Chinaunix首页 | 论坛 | 博客
  • 博客访问: 716278
  • 博文数量: 94
  • 博客积分: 2812
  • 博客等级: 少校
  • 技术积分: 1555
  • 用 户 组: 普通用户
  • 注册时间: 2009-11-08 21:28
文章分类

全部博文(94)

文章存档

2012年(23)

2011年(39)

2010年(14)

2009年(18)

分类: LINUX

2011-11-25 16:04:26

Linux设备模型是由总线(bus_type),设备(device),驱动(device_driver)这三个数据结构来描述的。在设备模型中,所有的设备都通过总线来连接。即使有些设备没有连接到一根物理上的总线,Linux为其设置了一个内部的,虚拟的platform总线,来维持总线,驱动,设备的关系。总线是处理器与一个或者多个设备之间的通道。比如一个USB控制器通常是一个PCI设备,设备模型展示了总线和他们所控制的设备之间的连接。
一般来说可以这么理解,整个的设备模型是一个OO的体系结构,总线,设备,驱动都是其中鲜活存在的对象,kobject是他们的基类,所实现的只是一些公共的接口,kset是同种类型的kobject对象的集合,也可以说是对象的容器。只是因为C语言里不可能会有C++语言里类的class继承等概念,只有通过kobject嵌入到对象结构中来实现。这样,内核使用kobject将各个对象连接起来组成一个分层的体系结构。kobject结构中包含了parent成员,指向了另一个kobject结构,也就是这个分层结构的上一层结点。而kset是通过链表来实现的。

kobject是Linux在2.6中新引进的统一的设备管理模型,目的是对Linux的2.6系统所有的设备进行统一的管理。kobject是组成设备模型的基本结构。kobject是驱动程序模型中的一个核心数据结构,与sysfs文件系统自然的绑定在一起:——每个kobject对应sysfs文件系统中的一个目录。kobject往往被嵌入到设备驱动程序模型中的组件中,如总线,设备和驱动程序的描述符。kobject的作用是,为所属“容器”提供
.引用计数器
.维持容器的层次列表或组
.为容器的属性提供一种用户态查看的视图
kset是同类型kobject结构的一个集合体,通过kset数据结构可将kobjects组成一棵层次树。

  1. struct bus_type {  
  2.     const char      *name;       //总线类型的名称  
  3.     struct bus_attribute    *bus_attrs;  //总线属性  
  4.     struct device_attribute *dev_attrs;  //设备属性  
  5.     struct driver_attribute *drv_attrs;  //驱动属性  
  6.     int (*match)(struct device *dev, struct device_driver *drv);  
  7.     int (*uevent)(struct device *dev, struct kobj_uevent_env *env);  
  8.     int (*probe)(struct device *dev);  
  9.     int (*remove)(struct device *dev);  
  10.     void (*shutdown)(struct device *dev);  
  11.     int (*suspend)(struct device *dev, pm_message_t state);  
  12.     int (*suspend_late)(struct device *dev, pm_message_t state);  
  13.     int (*resume_early)(struct device *dev);  
  14.     int (*resume)(struct device *dev);  
  15.     struct dev_pm_ops *pm;  
  16.     struct bus_type_private *p;  
  17. };  
  18. struct bus_type_private {  
  19.     struct kset subsys;                  //该总线的subsystem  
  20.     struct kset *drivers_kset;           //所有与该总线相关的驱动集合  
  21.     struct kset *devices_kset;           //所有挂接在该总线上的设备集合  
  22.     struct klist klist_devices;  
  23.     struct klist klist_drivers;  
  24.     struct blocking_notifier_head bus_notifier;  
  25.     unsigned int drivers_autoprobe:1;  
  26.     struct bus_type *bus;  
  27. };  
  28. struct bus_attribute {  
  29.     struct attribute    attr;  
  30.     ssize_t (*show)(struct bus_type *bus, char *buf);  
  31.     ssize_t (*store)(struct bus_type *bus, const char *buf, size_t count);  
  32. };  

subsys描述该总线的子系统,subsys是一个kset结构,他连接到一个全局变量kset bus_subsys中。这样,每一根总线系统都会通过bus_subsys结构连接起来。kset *devices_kset是指向该总线所有设备的集合的指针,kset *drivers_kset是指向该总线所有驱动的集合的指针。该总线上的设备和驱动分别用一个链表连接在一起,分别是klist_devices,klist_drivers。每次都用kset *drivers_kset,kset *devices_kset遍历所有设备/驱动很麻烦,用klist比较直接方便。

  1. struct device {  
  2.     struct klist        klist_children;  
  3.     struct klist_node   knode_parent;   /* node in sibling list */  
  4.     struct klist_node   knode_driver;  
  5.     struct klist_node   knode_bus;  
  6.     struct device       *parent;  
  7.     struct kobject kobj;  
  8.     char    bus_id[BUS_ID_SIZE];    /* position on parent bus */  
  9.     unsigned        uevent_suppress:1;  
  10.     const char      *init_name; /* initial name of the device */  
  11.     struct device_type  *type;  
  12.     struct semaphore    sem;    /* semaphore to synchronize calls to 
  13.                      * its driver. 
  14.                      */  
  15.     struct bus_type *bus;       /* type of bus device is on */  
  16.     struct device_driver *driver;   /* which driver has allocated this 
  17.                        device */  
  18.     void        *driver_data;   /* data private to the driver */  
  19.     void        *platform_data; /* Platform specific data, device 
  20.                        core doesn't touch it */  
  21.     struct dev_pm_info  power;  
  22. #ifdef CONFIG_NUMA  
  23.     int     numa_node;  /* NUMA node this device is close to */  
  24. #endif  
  25.     u64     *dma_mask;  /* dma mask (if dma'able device) */  
  26.     u64     coherent_dma_mask;/* Like dma_mask, but for 
  27.                          alloc_coherent mappings as 
  28.                          not all hardware supports 
  29.                          64 bit addresses for consistent 
  30.                          allocations such descriptors. */  
  31.     struct device_dma_parameters *dma_parms;  
  32.     struct list_head    dma_pools;  /* dma pools (if dma'ble) */  
  33.     struct dma_coherent_mem *dma_mem; /* internal for coherent mem 
  34.                          override */  
  35.     /* arch specific additions */  
  36.     struct dev_archdata archdata;  
  37.     dev_t           devt;   /* dev_t, creates the sysfs "dev" */  
  38.     spinlock_t      devres_lock;  
  39.     struct list_head    devres_head;  
  40.     struct klist_node   knode_class;  
  41.     struct class        *class;  
  42.     struct attribute_group  **groups;   /* optional groups */  
  43.     void    (*release)(struct device *dev);  
  44. };  
  45. struct device_private {  
  46.     struct klist klist_children;  
  47.     struct klist_node knode_parent;  
  48.     struct klist_node knode_driver;  
  49.     struct klist_node knode_bus;  
  50.     struct device *device;  
  51. };  
  52. struct device_attribute {  
  53.     struct attribute    attr;  
  54.     ssize_t (*show)(struct device *dev, struct device_attribute *attr,  
  55.             char *buf);  
  56.     ssize_t (*store)(struct device *dev, struct device_attribute *attr,  
  57.              const char *buf, size_t count);  
  58. };  

需要注意的是,总线也是设备,也必须按设备注册。这里的parent是指该设备所属的父设备,struct kobject kobj;表示该设备并把它连接到结构体系中的kobject。请注意,作为一个通用准则,device->kobj->parent与&device->parent->kobj是相同的。bus_id是在总线上唯一标识该设备的字符串。struct bus_type *bus;标识了该设备连接在何种类型的总线上。struct device_driver *driver;管理该设备的驱动。void (*release)(struct device *dev);当指向设备的最后一个引用被删除时,内核调用该方法。它将从内嵌的kobject的release方法中调用。device_private中的knode_parent,knode_driver,knode_bus分别是挂入parent,驱动,总线链表中的指针。

  1. struct device_driver {  
  2.     const char      *name;               //设备驱动程序的名称  
  3.     struct bus_type     *bus;                //该驱动所管理的设备挂接的总线类型  
  4.     struct module       *owner;  
  5.     const char      *mod_name;  /* used for built-in modules */  
  6.     int (*probe) (struct device *dev);  
  7.     int (*remove) (struct device *dev);  
  8.     void (*shutdown) (struct device *dev);  
  9.     int (*suspend) (struct device *dev, pm_message_t state);  
  10.     int (*resume) (struct device *dev);  
  11.     struct attribute_group **groups;  
  12.     struct dev_pm_ops *pm;  
  13.     struct driver_private *p;  
  14. };  
  15. struct driver_private {  
  16.     struct kobject kobj;  
  17.     struct klist klist_devices;               //该驱动所管理的设备链表头  
  18.     struct klist_node knode_bus;              //挂入总线链表中的指针  
  19.     struct module_kobject *mkobj;  
  20.     struct device_driver *driver;  
  21. };  
  22. struct driver_attribute {  
  23.     struct attribute attr;  
  24.     ssize_t (*show)(struct device_driver *driver, char *buf);  
  25.     ssize_t (*store)(struct device_driver *driver, const char *buf,  
  26.              size_t count);  
  27. };  

name指向驱动的名字,上边的device中也有一个名为bus_id的字符数组。查看一下,struct bus_type中有一个match,函数,这个是干什么用的呢。设备有了驱动才可以工作,只有驱动没有设备也是不行,驱动和设备需要关联上,这就需要这个match函数。驱动和设备是通过name来管理的,所以在match函数中要比较device的bus_id和driver中的name是否相等。如果相等,就说明驱动和设备互相找到了,这时device_driver中的probe函数被调用。我下边的例子中是这样实现的:

  1. static ssize_t show_driver_author(struct device_driver *driver, char *buf){  
  2.     return snprintf(buf, PAGE_SIZE, "%s/n", author);  
  3. }  

下面是一个测试程序:

BUS:

  1. #include   
  2. #include   
  3. #include   
  4. #include   
  5. #include   
  6.   
  7. static char *author = "LiWanPeng";  
  8.   
  9. static ssize_t show_bus_author(struct bus_type *bus, char *buf){  
  10.     return snprintf(buf, PAGE_SIZE, "%s/n", author);  
  11. }  
  12.   
  13. void my_bus_release(struct device *dev){  
  14.     printk(KERN_DEBUG "my bus release/n");    
  15. }     
  16.   
  17. static int virtual_bus_match(struct device *dev, struct device_driver *drv){  
  18.     return !strncmp(dev->bus_id, drv->name, strlen(drv->name));  
  19. }  
  20.   
  21. struct bus_type virtual_bus = {  
  22.     .name = "my_bus",  
  23.     .match = virtual_bus_match,  
  24. };  
  25.   
  26. struct device my_bus = {  
  27.     .init_name = "my_bus0",  
  28.     .release = my_bus_release,  
  29. };  
  30.   
  31. EXPORT_SYMBOL(my_bus);  
  32. EXPORT_SYMBOL(virtual_bus);  
  33.   
  34. static BUS_ATTR(author, S_IRUGO, show_bus_author, NULL);   
  35.   
  36. static int __init bus_init(void){  
  37.     int ret;  
  38.     ret = bus_register(&virtual_bus);  
  39.     if(ret)  
  40.         return ret;  
  41.     if(bus_create_file(&virtual_bus, &bus_attr_author))  
  42.         printk(KERN_NOTICE "Unable to create author attribute/n");  
  43.     ret = device_register(&my_bus);  
  44.     if(ret)  
  45.         printk(KERN_NOTICE "Fail to register device/n");  
  46.     printk("bus regiter success/n");  
  47.     return ret;  
  48. }  
  49.   
  50. static void __exit bus_exit(void){  
  51.     bus_unregister(&virtual_bus);  
  52.     device_unregister(&my_bus);  
  53. }  
  54.   
  55. module_init(bus_init);  
  56. module_exit(bus_exit);  
  57. MODULE_LICENSE("GPL");     

DEVICE:

  1. #include   
  2. #include   
  3. #include   
  4. #include   
  5.   
  6. char *author = "LiWanPeng";  
  7. extern struct bus_type virtual_bus;  
  8. extern struct device my_bus;  
  9.   
  10. static ssize_t show_device_author(struct device *dev, struct device_attribute *attr, char *buf){  
  11.     return snprintf(buf, PAGE_SIZE, "%s/n", author);  
  12. }  
  13.   
  14. void virtual_device_release(struct device *dev){  
  15.     printk("virtual_device is released/n");  
  16. }  
  17.   
  18. struct device virtual_device ={  
  19.     .bus_id = "my_dev",  
  20.     .bus = &virtual_bus,  
  21.     .parent = &my_bus,  
  22.     .release = virtual_device_release,  
  23. };  
  24.   
  25. static DEVICE_ATTR(author, S_IRUGO, show_device_author, NULL);   
  26.   
  27. static int __init device_init(void){  
  28.     int ret;  
  29.     ret = device_register(&virtual_device);  
  30.     if(ret)  
  31.         return ret;  
  32.     if(device_create_file(&virtual_device, &dev_attr_author))  
  33.         printk(KERN_NOTICE "Unable to create author attribute/n");  
  34.     printk("device register success/n");  
  35.     return ret;  
  36. }  
  37.   
  38. static void __exit device_exit(void){  
  39.     device_unregister(&virtual_device);  
  40. }  
  41.   
  42. module_init(device_init);  
  43. module_exit(device_exit);  
  44. MODULE_AUTHOR("liwanpeng");  
  45. MODULE_LICENSE("GPL");  

DRIVER:

  1. #include   
  2. #include   
  3. #include   
  4. #include   
  5. #include   
  6.   
  7. extern struct bus_type virtual_bus;  
  8. char *author = "LiWanPeng";  
  9.   
  10. static ssize_t show_driver_author(struct device_driver *driver, char *buf){  
  11.     return snprintf(buf, PAGE_SIZE, "%s/n", author);  
  12. }  
  13.   
  14. int my_driver_remove(struct device *dev){  
  15.     printk("driver is removed/n");  
  16.     return 0;  
  17. }     
  18.   
  19. int my_driver_probe(struct device *dev){  
  20.     printk("driver can handle the device/n");     
  21.     return 0;  
  22. }  
  23.   
  24. struct device_driver virtual_driver = {  
  25.     .name = "my_dev",  
  26.     .bus = &virtual_bus,  
  27.     .probe = my_driver_probe,  
  28.     .remove = my_driver_remove,  
  29. };    
  30.   
  31. static DRIVER_ATTR(author, S_IRUGO, show_driver_author, NULL);   
  32.   
  33. static int __init my_driver_init(void){  
  34.     int ret;  
  35.     ret = driver_register(&virtual_driver);  
  36.     if(ret)  
  37.         return ret;  
  38.     if(driver_create_file(&virtual_driver, &driver_attr_author))  
  39.         printk(KERN_NOTICE "Unable to create author attribute/n");  
  40.     printk("driver register success/n");  
  41.     return ret;  
  42. }  
  43.   
  44. static void __exit my_driver_exit(void){  
  45.     driver_unregister(&virtual_driver);  
  46. }  
  47.   
  48. module_init(my_driver_init);  
  49. module_exit(my_driver_exit);  
  50. MODULE_LICENSE("GPL");  
  51. MODULE_AUTHOR("liwanpeng");  

Makefile:

  1. ifneq ($(KERNELRELEASE),)  
  2.     obj-m:= driver.o bus.o device.o  
  3. else  
  4.     KERNELDIR ?= /lib/modules/$(shell uname -r)/build  
  5.     PWD := $(shell pwd)  
  6. modules:  
  7.     $(MAKE) -C $(KERNELDIR) M=$(PWD) modules  
  8. clear:  
  9.     rm -rf *.o  
  10. endif  

测试:

  1. root@hacker:/home/hacker/program# dmesg  
  2. [  500.120888] bus regiter success  
  3. [  503.635832] device register success  
  4. [  515.237701] driver can handle the device  
  5. [  515.237772] driver register success  
  6.   
  7.   
  8. root@hacker:/home/hacker/program# dmesg  
  9. [  627.552494] bus regiter success  
  10. [  631.652273] driver register success  
  11. [  641.867854] driver can handle the device  
  12. [  641.867861] device register success  
  13.   
  14. root@hacker:/sys/bus/my_bus/drivers/my_dev# ls -l  
  15. total 0  
  16. -r--r--r-- 1 root root 4096 2011-05-06 22:46 author  
  17. --w------- 1 root root 4096 2011-05-06 22:46 bind  
  18. lrwxrwxrwx 1 root root    0 2011-05-06 22:46 my_dev -> ../../../../devices/my_bus0/my_dev  
  19. --w------- 1 root root 4096 2011-05-06 22:46 uevent  
  20. --w------- 1 root root 4096 2011-05-06 22:46 unbind  
  21. root@hacker:/sys/bus/my_bus/drivers/my_dev# cat author   
  22. LiWanPeng  

阅读(3051) | 评论(0) | 转发(3) |
给主人留下些什么吧!~~