【Linux开发】linux设备驱动归纳总结(八):3.设备管理的分层与面向对象思想
linux设备驱动归纳总结(八):3.设备管理的分层与面向对象思想
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
前面的内容介绍了总线、设备和驱动函数的关系和操作。从这节开始,介绍设备管理中的分层思想和面向对象思想(名字是我自己瞎编的,《LDD》上指的是结构体内嵌)。可以理解是平台类设备(platform)的一个过度。
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
一、设备管理的分层
回想一下之前的设备和驱动函数注册时,它们是自己指定所属的总线。但是,内核开发人员觉得,这样的方法不好,应该由总线来提供设备和驱动的注册函数。当设备和驱动需要注册到指定总线时,那就必须使用该总线为设备和驱动提供的注册函数。
所以,将上一节的bus.c修改如下:
/*8th_devModule_3/1st/bus.c*/
21 /*总线提供的设备注册函数*/
22 int usb_device_register(struct device *dev)
23 {
24 dev->bus = &usb_bus; //设备device的总线为usb_bus
25 return device_register(dev); //注册此device
26 }
27 void usb_device_unregister(struct device *dev)
28 {
29 device_unregister(dev);
30 }
31 EXPORT_SYMBOL(usb_device_register);
32 EXPORT_SYMBOL(usb_device_unregister);
33 /*总线提供的驱动注册函数*/
34 int usb_driver_register(struct device_driver *drv)
35 {
36 drv->bus = &usb_bus; //设置driver的总线为usb_bus
37 return driver_register(drv); //注册此driver
38 }
39 void usb_driver_unregister(struct device_driver *drv)
40 {
41 driver_unregister(drv);
42 }
43 EXPORT_SYMBOL(usb_driver_register);
44 EXPORT_SYMBOL(usb_driver_unregister);
再写一个bus.h,让设备和驱动函数包含该头文件后能够使用总线提供的驱动函数。
/*8th_devModule_3/1st/bus.h*/
1 #ifndef _BUS_H
2 #define _BUS_H
3
4 int usb_device_register(struct device *dev);
5 void usb_device_unregister(struct device *dev);
6
7 int usb_driver_register(struct device_driver *drv);
8 void usb_driver_unregister(struct device_driver *drv);
9 #endif /* _BUS_H */
上面的程序可以看到,其实也没干什么事情,只是由总线来封装并且向设备和驱动函数提供注册函数,便于管理。而不像以前,设备和驱动只要知道总线的名字,就能注册到指定的总线中。
再修改一下设备和驱动函数的代码:
/*8th_devModule_3/1st/device.c*/
11 /*结构体中不需要指定总线的成员,交由usb_device_register来完成*/
12 struct device usb_device = {
13 .bus_id = "usb_mouse",
14 .release = usb_dev_release, //必须要都有release函数,不然卸载时会出错
15 };
16
17 static int __init usb_device_init(void)
18 {
19 int ret;
20
21 ret = usb_device_register(&usb_device);
22 if(ret){
23 printk("device register failed!\n");
24 return ret;
25 }
26
27 printk("usb device init\n");
28 return 0;
29 }
30
31 static void __exit usb_device_exit(void)
32 {
33 usb_device_unregister(&usb_device);
34 printk("usb device bye!\n");
35 }
/*8th_devModule_3/1st/driver.c*/
24 /*结构体中不需要指定总线的成员,交由usb_device_register来完成*/
25 struct device_driver usb_driver = {
26 .name = "usb_mouse", //在/sys/中的驱动目录名字
27 .probe = usb_driver_probe,
28 .remove = usb_driver_remove,
29 };
30
31 static int __init usb_driver_init(void)
32 {
33 int ret;
34 /*驱动注册,注册成功后在/sys/bus/usb/driver目录下创建目录usb_mouse*/
35 ret = usb_driver_register(&usb_driver);
36 if(ret){
37 printk("driver register failed!\n");
38 return ret;
39 }
40 printk("usb driver init\n");
41 return 0;
42 }
43
44 static void __exit usb_driver_exit(void)
45 {
46 usb_driver_unregister(&usb_driver);
47 printk("usb driver bye!\n");
48 }
修改完毕,验证一下,效果和之前的一样,我也不详细解释:
[root: 1st]# insmod bus.ko
usb bus init
[root: 1st]# insmod device.ko
usb device init
[root: 1st]# insmod driver.ko
match success
match success
init usb mouse
usb driver init
[root: 1st]# rmmod device
remove mouse driver
release
usb device bye!
[root: 1st]# rmmod driver
usb driver bye!
[root: 1st]# rmmod bus
usb bus bye!
二、面向对象思想——结构内嵌
device结构体分别包含了设备模型的基本信息。然后,大多数的子系统还会记录该结构体以外但与设备相关的信息。因此,单纯用一个device结构来表示设备是很少见的,而是把device结构体内嵌到其他的结构体中。当然,device_driver也是一样。
接下来,我封装一下设备和驱动函数的结构体:
/*8th_devModule_3/2nd/bus.h*/
4 struct usb_device{ //在usb_device中包含device结构体
5 unsigned long phys, virt; //存放设备和物理地址和对应的虚拟地址
6 int irq; //存放设备的中断号
7 int VendorID, DeviceID; //存放设备的生产厂商编号和设备编号
8
9 struct device dev;
10 };
11
12 struct usb_driver{ //在usb_driver中包含device_driver结构体
13 int VendorID, DeviceID;
14
15 struct device_driver drv;
16 };
17
18 int usb_device_register(struct usb_device *usb_dev);
19 void usb_device_unregister(struct usb_device *usb_dev);
20
21 int usb_driver_register(struct usb_driver *usb_drv);
22 void usb_driver_unregister(struct usb_driver *usb_drv);
23 #endif /* _BUS_H */
在上面,我将设备结构体device内嵌到usb_device结构体中,该结构体中还有成员生产厂商编号和设备编号,在match函数会用来配对,成员irq、phys和virt在接下来的章节会用到。
同样的,驱动函数结构体device_driver被内嵌到usb_driver结构体中,该结构体中还有成员生产厂商编号和设备编号,在match函数中会用来匹配。
因为我定义了新的结构体,三个函数都的传参都有了稍稍的改变。
首先是bus.c:
/*8th_devModule_3/2nd/bus.c*/
7 int usb_bus_match(struct device *dev, struct device_driver *drv)
8 { /*使用container_of找出总线自己定义的结构体*/
9       struct usb_device *usb_dev = container_of(dev,
 struct usb_device, dev);
10     struct usb_driver *usb_drv = container_of(drv,
 struct usb_driver, drv);
11 /*配对函数判断驱动和设备的生产厂商编号和设备编号是否一致*/
12     if((usb_dev->VendorID
 == usb_drv->VendorID) &&
13                 (usb_dev->DeviceID
 == usb_drv->DeviceID)){
14         printk("match
 success\n");
15         return
 1;
16 }else{
17         printk("match
 failed\n");
18         return
 0;
19 }
20 }
bus.c中的配对函数被我修改了两部分:
1、通过container_of来获得usb_device和usb_driver结构体。
2、修改了配对了方法,通过判断两者生产厂商编号与设备号是否都一致。
因为定义了新的结构体,所以我将注册函数的参数也修改了。
/*8th_devModule_3/2nd/bus.c*/
26 /*总线提供的设备注册函数*/
27 int usb_device_register(struct usb_device *usb_dev)
28 {
29 usb_dev->dev.bus = &usb_bus; //设备device的总线为usb_bus
30     return device_register(&usb_dev->dev);
 //注册此device
31 }
32 void usb_device_unregister(struct usb_device *usb_dev)
33 {
34 device_unregister(&usb_dev->dev);
35 }
36 EXPORT_SYMBOL(usb_device_register);
37 EXPORT_SYMBOL(usb_device_unregister);
38 /*总线提供的驱动注册函数*/
39 int usb_driver_register(struct usb_driver *usb_drv)
40 {
41 usb_drv->drv.bus = &usb_bus; //设置driver的总线为usb_bus
42     return driver_register(&usb_drv->drv);
 //注册此driver
43 }
44 void usb_driver_unregister(struct usb_driver *usb_drv)
45 {
46 driver_unregister(&usb_drv->drv);
47 }
48 EXPORT_SYMBOL(usb_driver_register);
49 EXPORT_SYMBOL(usb_driver_unregister);
接着是device.c:
/*8th_evModule_3/2nd/device.c*/
12 struct usb_device mouse_dev = {
13     .VendorID
 = 0x1122,
14     .DeviceID
 = 0x3344,
15     .dev
 = {
16         .bus_id
 = "usb_mouse",
17         .release
 = usb_dev_release,
18 },
19 };
20
21 static int __init usb_device_init(void)
22 {
23 int ret;
24
25 ret = usb_device_register(&mouse_dev);
26 if(ret){
27         printk("device
 register failed!\n");
28         return
 ret;
29 }
30
31 printk("usb device init\n");
32 return 0;
33 }
34
35 static void __exit usb_device_exit(void)
36 {
37 usb_device_unregister(&mouse_dev);
38 printk("usb device bye!\n");
39 }
最后再看看driver.c:
/*8th_devModule_3/2nd/driver.c*/
25 struct usb_driver mouse_drv = {
26     .VendorID
 = 0x1122,
27     .DeviceID
 = 0x3344,
28     .drv
 = {
29         .name
 = "usb_mouse", //在/sys/中的驱动目录名字
30         .probe
 = usb_driver_probe,
31         .remove
 = usb_driver_remove,
32 },
33 };
34
35 static int __init usb_driver_init(void)
36 {
37 int ret;
38 /*驱动注册,注册成功后在/sys/bus/usb/driver目录下创建目录usb_mouse*/
39 ret = usb_driver_register(&mouse_drv);
40 if(ret){
41         printk("driver
 register failed!\n");
42         return
 ret;
43 }
44 printk("usb driver init\n");
45 return 0;
46 }
47
48 static void __exit usb_driver_exit(void)
49 {
50 usb_driver_unregister(&mouse_drv);
51 printk("usb driver bye!\n");
52 }
修改完毕,看看效果,其实就是和之前一模一样。
[root: /]# cd review_driver/8th_devModule/8th_devModule_3/2nd/
[root: 2nd]# insmod bus.ko
usb bus init
[root: 2nd]# insmod device.ko
usb device init
[root: 2nd]# insmod driver.ko
match success
match success
init usb mouse
usb driver init
[root: 2nd]# rmmod device
remove mouse driver
release
usb device bye!
[root: 2nd]# rmmod driver
usb driver bye!
[root: 2nd]# rmmod bus
usb bus bye!
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
三、总结
这节内容并不多,其实就是修改修改一下原来的代码,等到我介绍平台类设备的时候你就会发现,其实平台类就是这样一步步封装起来的(当然比我的复杂)。
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
源代码: 8th_devModule_3.rar
 8th_devModule_3.rar
【Linux开发】linux设备驱动归纳总结(八):3.设备管理的分层与面向对象思想的更多相关文章
- linux设备驱动归纳总结(八):3.设备管理的分层与面向对象思想【转】
		本文转载自:http://blog.chinaunix.net/uid-25014876-id-110738.html linux设备驱动归纳总结(八):3.设备管理的分层与面向对象思想 xxxxxx ... 
- 【Linux开发】linux设备驱动归纳总结(九):1.platform总线的设备和驱动
		linux设备驱动归纳总结(九):1.platform总线的设备和驱动 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx ... 
- linux设备驱动归纳总结
		前言: (总结已经基本写完,这段时间我会从新排版和修正.错误总会有的,望能指正!) 前段时间学习了嵌入式驱动,趁着没开始找工作,这段时间我会每天抽出时间来复习. 我的总结是根据学习时的笔记(李杨老师授 ... 
- 【Linux】linux设备驱动归纳总结
		前言: (总结已经基本写完,这段时间我会从新排版和修正.错误总会有的,望能指正!) 前段时间学习了嵌入式驱动,趁着没开始找工作,这段时间我会每天抽出时间来复习. 我的总结是根据学习时的笔记(李杨老师授 ... 
- linux设备驱动归纳总结(九):1.platform总线的设备和驱动【转】
		本文转载自:http://blog.chinaunix.net/uid-25014876-id-111745.html linux设备驱动归纳总结(九):1.platform总线的设备和驱动 xxxx ... 
- 【Linux开发】linux设备驱动归纳总结(八):2.总线、设备和驱动的关系
		linux设备驱动归纳总结(八):2.总线.设备和驱动的关系 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx ... 
- 【Linux开发】linux设备驱动归纳总结(八):4.总线热插拔
		linux设备驱动归纳总结(八):4.总线热插拔 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx ... 
- 【Linux开发】linux设备驱动归纳总结(八):1.总线、设备和驱动
		linux设备驱动归纳总结(八):1.总线.设备和驱动 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx ... 
- 【Linux开发】linux设备驱动归纳总结(五):1.在内核空间分配内存
		linux设备驱动归纳总结(五):1.在内核空间分配内存 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx ... 
随机推荐
- 5 LAMP配置管理:模块(state、file、pkg、service)、jinja模板、job管理、redis主从
			1. 配置管理:state和file https://docs.saltstack.com/en/latest/topics/states/index.html Full list of states ... 
- Error from server (NotFound): the server could not find the requested resource (get services http:heapster:)
			kubectl top pod --all-namespaces Error from server (NotFound): the server could not find the request ... 
- 51Nod 1055 最长等差数列 (dp+哈希)
			1055 最长等差数列 基准时间限制:2 秒 空间限制:262144 KB 分值: 80 难度:5级算法题 收藏 关注 N个不同的正整数,找出由这些数组成的最长的等差数列. 例如:1 3 5 6 ... 
- AcWing:142. 前缀统计(字典树)
			给定N个字符串S1,S2…SNS1,S2…SN,接下来进行M次询问,每次询问给定一个字符串T,求S1S1-SNSN中有多少个字符串是T的前缀. 输入字符串的总长度不超过106106,仅包含小写字母. ... 
- css基础(css书写 背景设置 标签分类 css特性)
			css书写位置 行内式写法 <p style="color:red;" font-size:12px;></p> 外联式写法 <link re ... 
- 使用yum安装nginx
			在CentOS 7中安装Nginx. 当使用以下命令安装Nginx时,发现无法安装成功. 1 yum install -y nginx 需要做一点处理. 安装Nginx源 执行以下命令: 1 rpm ... 
- 如何卸载zabbix且删除
			1.彻底卸载zabbix和删除残留文件 1 2 [root@localhost etc]# service zabbix stop //这个命令是停止服务 [root@localhost et ... 
- python-线性回归预测
			导入包 # Required Packages import matplotlib.pyplot as plt import numpy as np import pandas as pd from ... 
- 使用conda进行本地安装
			1. 由于安装源被墙转换为本地安装 例如要安装 boost-1.59版本,因为在默认源中没有,我们指定了特定源进行安装 conda install -c menpo dlib=boost-1.59 然 ... 
- Java多线程深入理解
			在java中要想实现多线程,有两种手段,一种是继续Thread类,另外一种是实现Runable接口. 对于直接继承Thread的类来说,代码大致框架是: ? 1 2 3 4 5 6 7 8 9 10 ... 
