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

【Linux开发】linux设备驱动归纳总结(八):3.设备管理的分层与面向对象思想的更多相关文章

  1. linux设备驱动归纳总结(八):3.设备管理的分层与面向对象思想【转】

    本文转载自:http://blog.chinaunix.net/uid-25014876-id-110738.html linux设备驱动归纳总结(八):3.设备管理的分层与面向对象思想 xxxxxx ...

  2. 【Linux开发】linux设备驱动归纳总结(九):1.platform总线的设备和驱动

    linux设备驱动归纳总结(九):1.platform总线的设备和驱动 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx ...

  3. linux设备驱动归纳总结

    前言: (总结已经基本写完,这段时间我会从新排版和修正.错误总会有的,望能指正!) 前段时间学习了嵌入式驱动,趁着没开始找工作,这段时间我会每天抽出时间来复习. 我的总结是根据学习时的笔记(李杨老师授 ...

  4. 【Linux】linux设备驱动归纳总结

    前言: (总结已经基本写完,这段时间我会从新排版和修正.错误总会有的,望能指正!) 前段时间学习了嵌入式驱动,趁着没开始找工作,这段时间我会每天抽出时间来复习. 我的总结是根据学习时的笔记(李杨老师授 ...

  5. linux设备驱动归纳总结(九):1.platform总线的设备和驱动【转】

    本文转载自:http://blog.chinaunix.net/uid-25014876-id-111745.html linux设备驱动归纳总结(九):1.platform总线的设备和驱动 xxxx ...

  6. 【Linux开发】linux设备驱动归纳总结(八):2.总线、设备和驱动的关系

    linux设备驱动归纳总结(八):2.总线.设备和驱动的关系 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx ...

  7. 【Linux开发】linux设备驱动归纳总结(八):4.总线热插拔

    linux设备驱动归纳总结(八):4.总线热插拔 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx ...

  8. 【Linux开发】linux设备驱动归纳总结(八):1.总线、设备和驱动

    linux设备驱动归纳总结(八):1.总线.设备和驱动 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx ...

  9. 【Linux开发】linux设备驱动归纳总结(五):1.在内核空间分配内存

    linux设备驱动归纳总结(五):1.在内核空间分配内存 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx ...

随机推荐

  1. Python之阿姆斯特朗数

    # Python 检测用户输入的数字是否为阿姆斯特朗数 # 如果一个n位正整数等于其各位数字的n次方之和,则称该数为阿阿姆斯特朗数 while True: # 获取用户输入的数字 num = int( ...

  2. vscode安装eslint插件,代码统一自动修复

    ESlint:是用来统一JavaScript代码风格的工具,不包含css.html等. 方法和步骤: 通常情况下vue项目都会添加eslint组件,我们可以查看webpack的配置文件package. ...

  3. java 项目 文件关系 扫描 注释注入(2)

    https://www.cnblogs.com/daimajun/p/7152970.html(copy) 先提一嘴 @RequestMapping(“url”),这里的 url写的是请求路径的一部分 ...

  4. 玩转git和github

    1.概念 git---工具,版本控制 github----网站,社交平台,开源项目,远程仓库 2.下载 msysgit是Windows版的Git,从http://msysgit.github.io/下 ...

  5. Topics(主题模式)

    引言 topic exchange和direct exchange类似,都是通过routing key和binding key进行匹配,不同的是topic exchange可以为routing key ...

  6. Mybatis内置的日志工厂提供日志功能

    Mybatis内置的日志工厂提供日志功能,具体的日志实现有以下几种工具: SLF4J Apache Commons Logging Log4j 2 Log4j JDK logging 具体选择哪个日志 ...

  7. TCP层recvmsg系统调用的实现分析

    概述 recvmsg系统调用在tcp层的实现是tcp_recvmsg函数,该函数完成从接收队列中读取数据复制到用户空间的任务:函数在执行过程中会锁定控制块,避免软中断在tcp层的影响:函数会涉及从接收 ...

  8. oracle性能诊断sql

    --1.阻塞及等待事件信息查询-- 查询所有会话的状态.等待类型及当前正在执行的SQL脚本select t.SID, t.SERIAL#, t.Status, t.Action, t.Event, t ...

  9. koa 基础(十二)koa-static 静态资源中间件 静态web服务

    1.目录 2.app.js /** * koa-static 静态资源中间件 静态web服务 * 1.npm install --save koa-static * 2.const static = ...

  10. Mysql 纪录用户操作日志

    有时,我们想追踪某个数据库操作记录,如想找出是谁操作了某个表(比如谁将字段名改了). 二进制日志记录了操作记录,线程号等信息,但是却没有记录用户信息,因此需要结合init-connect来实现追踪. ...