linux内核 bus driver device
来源:互联网 发布:风险指数矩阵 编辑:程序博客网 时间:2024/05/01 22:08
一、总线、设备和驱动函数在/sys/中的框架
首先要写三个函数,bus.c、device.c和driver.c。这几个函数其实就是上一节函数的精简版,去掉属性文件的创建,仅仅保留创建和注销操作。
第一个函数是bus.c,加载模块会创建了一条名叫usb的总线,总线目录放在/sys/bus/目录下:
/*8th_devModule_2/1st/bus.c*/
6 struct bus_type usb_bus = {
7 .name = "usb", //注册成功后将在/sys/bus目录下看到目录usb
8 };
9
10 static int __init usb_bus_init(void)
11 {
12 int ret;
13 /*总线注册,必须检测返回值*/
14 ret = bus_register(&usb_bus);
15 if(ret){
16 printk("bus register failed!\n");
17 return ret;
18 }
19
20 printk("usb bus init\n");
21 return 0;
22 }
23
24 static void __exit usb_bus_exit(void)
25 {
26 bus_unregister(&usb_bus);
27 printk("usb bus bye!\n");
28 }
第二个函数是device.c,加载模块会创建目录/sys/device/usb_device来管理这个usb设备。
由于该设备指定了所属的总线是usb_bus,所有会在/sys/bus/usb/device目录下创建一了指向usb_device的软连接。
同时,在卸载模块时,usb_deivce被删除,内核自动调用release函数,现实当中release函数应该做一些卸载设备的相关操作,但是我的usb设备是我虚拟出来的,所以release函数只是打印了一句话。
/*8th_devModule_2/1st/device.c*/
5 extern struct bus_type usb_bus;
6
7 void usb_dev_release(struct device *dev) //卸载函数没有干具体的事情
8 {
9 printk("<kernel> release\n");
10 }
11
12 struct device usb_device = {
13 .bus_id = "usb_device",
14 .bus = &usb_bus, //指定该设备的总线,在/sys/bus/usb
15 .release = usb_dev_release, //必须要都有release函数,不然卸载时会出错
16 };
17
18 static int __init usb_device_init(void)
19 {
20 int ret;
21 /*设备注册,注册成功后在/sys/device目录下创建目录usb_device并在指定总线
22 * usb_bus的目录/sys/bus/usb/device创建/sys/device/usb_device的软连接*/
23 ret = device_register(&usb_device);
24 if(ret){
25 printk("device register failed!\n");
26 return ret;
27 }
28
29 printk("usb device init\n");
30 return 0;
31 }
32
33 static void __exit usb_device_exit(void)
34 {
35 device_unregister(&usb_device);
36 printk("usb device bye!\n");
37 }
第三个函数是driver.c,加载模块后会在指定的总线目录的driver目录,即/sys/bus/usb/driver目录下创建一个名叫usb_driver的目录来管理这个驱动函数。
/*8th_devModule_2/1st/driver.c*/
6 extern struct bus_type usb_bus;
7
8 struct device_driver usb_driver = {
9 .name = "usb_driver", //在/sys/中的驱动目录名字
10 .bus = &usb_bus, //必须指定驱动函数所属总线,不然不能注册。
11 };
12
13 static int __init usb_driver_init(void)
14 {
15 int ret;
16 /*驱动注册,注册成功后在/sys/bus/usb/driver目录下创建目录usb_driver*/
17 ret = driver_register(&usb_driver);
18 if(ret){
19 printk("driver register failed!\n");
20 return ret;
21 }
22 printk("usb driver init\n");
23 return 0;
24 }
25
26 static void __exit usb_driver_exit(void)
27 {
28 driver_unregister(&usb_driver);
29 printk("usb driver bye!\n");
30 }
接下来看看效果,因为设备和驱动的都指定了所属总线,所以必须先加载总线的模块。同样的,在卸载总线的模块前,必须先把设备和驱动的模块先卸载。
二、配对函数(match)、探测函数(probe)和卸载函数(remove)
现在讲一下三个函数:
第一个是配对函数(match),它是总线结构体bus_type的其中一个成员:
57 int (*match)(struct device *dev, struct device_driver *drv);
当总线上添加了新设备或者新驱动函数的时候,内核会调用一次或者多次这个函数。
举例,如果我现在添加了一个新的驱动函数,内核就会调用所属总线的match函数,配对总线上所有的设备,如果驱动能够处理其中一个设备,函数返回0,告诉内核配对成功。
一般的,match函数是判断设备的结构体成员device->bus_id和驱动函数的结构体成员device_driver->name是否一致,如果一致,那就表明配对成功。
所以,bus.c修改如下,贴上修改的代码:
/*8th_devModule_2/2nd/bus.c*/
6 int usb_bus_match(struct device *dev, struct device_driver *drv)
7 {
8 if(!strcmp(dev->bus_id, drv->name)){
9 printk("match success\n"); //为了配对成功,设备的bus_id和驱动的name我都更改为
10 return 1; //usb_mouse,详细的可以查看device.c和driver.c
11 }else{
12 printk("match failed\n");
13 return 0;
14 }
15 }
16
17 struct bus_type usb_bus = {
18 .name = "usb", //注册成功后将在/sys/bus目录下看到目录usb
19 .match = usb_bus_match,
20 };
第二个是探测函数(probe),它是驱动函数结构体中的一个成员:
129 int (*probe) (struct device *dev);
当配对(match)成功后,内核就会调用指定驱动中的probe函数来查询设备能否被该驱动操作,如果可以,驱动就会对该设备进行相应的操作,如初始化。所以说,真正的驱动函数入口是在probe函数中。
所以,driver.c修改如下:
/*8th_devModule_2/2nd/driver.c*/
8 void init_mouse(void)
9 {
10 printk("init usb mouse\n");
11 }
12
13 int usb_driver_probe(struct device *dev)
14 {//查询特定设备是否存在,以及是否能够才操作该设备,然后再进行设备操作。
15 //check_mouse(); //自己假设一下检查设备
16 init_mouse(); //usb鼠标驱动的真正入口
17 return 0;
18 }
。。。。。
26 struct device_driver usb_driver = {
27 .name = "usb_mouse", //在/sys/中的驱动目录名字,为了配对成功,修改为usb_mouse
28 .bus = &usb_bus, //必须指定驱动函数所属总线,不然不能注册。
29 .probe = usb_driver_probe,
30 。。。。。
31 };
第三个是卸载函数(remove),它是驱动函数结构体中的一个成员:
130 int (*remove) (struct device *dev);
当该驱动函数或者驱动函数正在操作的设备被移除时,内核会调用驱动函数中的remove函数调用,进行一些设备卸载相应的操作。
所以,driver.c修改如下:
/*8th_devModule_2/2nd/driver.c*/
20 int usb_driver_remove(struct device *dev)
21 {
22 printk("remove mouse driver\n");
23 return 0;
24 }
25
26 struct device_driver usb_driver = {
27 .name = "usb_mouse", //在/sys/中的驱动目录名字
28 .bus = &usb_bus, //必须指定驱动函数所属总线,不然不能注册。
29 .probe = usb_driver_probe,
30 .remove = usb_driver_remove,
31 };
match 执行地方:从driver_register看起:
int driver_register(struct device_driver * drv){ klist_init(&drv->klist_devices, klist_devices_get, klist_devices_put); init_completion(&drv->unloaded); return bus_add_driver(drv);}
klist_init与init_completion没去管它,可能是2.6的这个设备模型要做的一些工作。直觉告诉我要去bus_add_driver。
bus_add_driver中:
都是些Kobject 与 klist 、attr等。还是与设备模型有关的。但是其中有一句:
driver_attach(drv);
单听名字就很像:
void driver_attach(struct device_driver * drv){ bus_for_each_dev(drv->bus, NULL, drv, __driver_attach);}
在__driver_attach中又主要是这样:
driver_probe_device(drv, dev);
跑到driver_probe_device中去看看:
有一段很重要:
if (drv->bus->match && !drv->bus->match(dev, drv))
goto Done;
明显,是调用的驱动的总线上的match函数。如果返回1,则可以继续,否则就Done了。
继承执行的话:
if (drv->probe) {
ret = drv->probe(dev);
if (ret) {
dev->driver = NULL;
goto ProbeFailed;
}
只要probe存在则调用之。至此就完成了probe的调用。
1、多个设备对应一个驱动:
下面要讲的情况是,如果多个设备与内核中的一个驱动函数配对成功时,内核会进行怎么样的操作,先看实例。
为了能够让多个设备配对成功,我将bus.c的配对条件修改了一下:
/*8th_devModule_2/3th/bus.c */
6 int usb_bus_match(struct device *dev, struct device_driver *drv)
7 { //仅仅配对名字的前9个字母是否相同
8 if(!strncmp(dev->bus_id, drv->name, 9)){
9 printk("match success\n");
10 return 1;
11 }else{
12 printk("match failed\n");
13 return 0;
14 }
15 }
同时在device.c的基础上拷贝了device1.c和device2.c,三个程序都差不多,可以自己看看。接下来直接看效果:
[root: /]# cd /review_driver/8th_devModule/8th_devModule_2/3th
[root: 3th]# insmod bus.ko //先加载总线
usb bus init
[root: 3th]# insmod driver.ko //再加载驱动
usb driver init
[root: 3th]# insmod device.ko //当加载device.ko时,配对成功
match success
init usb mouse //内核调用驱动中的probe
usb device init
[root: 3th]# insmod device1.ko //再加载device1.ko,也配对成功
match success
init usb mouse //内核有调用驱动中的probe
usb device1 init
[root: 3th]# insmod device2.ko //加载device2.ko,配对不成功
match failed
usb device2 init
上面的验证表明,一个驱动可以对应多个设备。在联想起我举得男人女人——一个男人可以配对多个女人,哈哈。
2、一个设备对应多个驱动
这个例子中我将driver.c拷贝多了一个driver1.c,两个程序基本相同,都能配对成功,但看看效果:
[root: 3th]# insmod bus.ko //先加载总线
usb bus init
[root: 3th]# insmod device.ko //再加载设备
usb device init
[root: 3th]# insmod driver.ko //加载driver.ko
match success //配对成功
match success
init usb mouse //并且调用了probe
usb driver init
[root: 3th]# insmod driver1.ko //再加载driver1.ko
match success //因为名字的前9个字母一样,所以也会配对成功
usb driver1 init //但不会调用probe,因为已经有一个驱动跟该设备配对了。
上面的验证表明,一个设备只能对应一个驱动。
- linux内核 bus driver device
- linux bus driver device
- linux-bus,device,driver,class
- linux-bus,device,driver,class
- linux设备模型bus,device,driver
- linux设备模型bus,device,driver
- linux 驱动 device,driver ,bus 关系
- LINUX设备模型BUS,DEVICE,DRIVER
- LINUX设备模型BUS,DEVICE,DRIVER
- linux设备模型bus,device,driver
- linux设备模型bus,device,driver
- LINUX设备模型BUS,DEVICE,DRIVER
- linux bus driver device 三者关系
- bus,device和driver
- bus device driver
- 2.the linux device model--bus device driver
- linux设备模型之bus,device,driver分析一
- linux设备模型之bus,device,driver分析二
- java 九九乘法表
- HashMap简介
- JS 数字,金额 用逗号 隔开(数字格式化)
- hdu1253(胜利大逃亡)
- 北京小姐
- linux内核 bus driver device
- Java重载与覆盖
- struts2和servlet共存的几种方法
- 互联网大型应用软件架构设想与推荐
- 给定一个存放整数的数组,重新排列数组使得数组左边为奇数,右边为偶数
- 基于TestNG 与Selenium 的自动化测试设计与实施
- linux问题总结
- c语言中的转义字符
- smarty 定界符与js冲突的问题