Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1071596
  • 博文数量: 71
  • 博客积分: 3078
  • 博客等级: 少校
  • 技术积分: 945
  • 用 户 组: 普通用户
  • 注册时间: 2009-09-16 20:10
个人简介

此博客已停用 个人博客: Mangogeek.com

文章分类
文章存档

2016年(1)

2015年(32)

2014年(25)

2011年(13)

分类: LINUX

2014-11-01 09:27:49

Linux中,分别使用bus_type,device_driver,device来描述总线,驱动和设备,在设备模型中,所有的设备都通过总线来连接。即使有些设备没有连接到一根物理总线上,Linux为其设置了一个内部的、虚拟的platform总线,来维持总线、驱动、设备的关系。

总线:


点击(此处)折叠或打开

  1. struct bus_type {
  2.     const char        * name;//总线名字
  3.     struct module        * owner;
  4.     struct kset        subsys;//子系统,连接到一个全局变量kset bus_subsys。这样每一根总线系统都会通过bus_subsys结构连接起来。
  5.     struct kset        drivers;//总线驱动
  6.     struct kset        devices;//插入总线的所有设备
  7.     struct bus_attribute    * bus_attrs;
  8.     struct device_attribute    * dev_attrs;
  9.     struct driver_attribute    * drv_attrs;
  10.     int        (*match)(struct device * dev, struct device_driver * drv);
  11.     int        (*uevent)(struct device *dev, char **envp,int num_envp, char *buffer, int buffer_size);//参数与kset里的uevent相同。
  12.     int        (*probe)(struct device * dev);
  13.     int        (*remove)(struct device * dev);
  14.     void        (*shutdown)(struct device * dev);
  15. ....
  16. }

总线注册:bus_register(struct bus_type *bus);

总线删除:bus_unregister(struct bus_type *bus);

总线属性:


点击(此处)折叠或打开

  1. struct bus_attribute {
  2.     struct attribute    attr;
  3.     ssize_t (*show)(struct bus_type *, char * buf);
  4.     ssize_t (*store)(struct bus_type *, const char * buf, size_t count);
  5. }

创建和初始化bus_attribute结构:

#define BUS_ATTR(_name,_mode,_show,_store)

创建总线属性:

int bus_create_file(struct bus_type *,struct bus_attribute *);

删除属性:

void bus_remove_file(struct bus_type *, struct bus_attribute *);


点击(此处)折叠或打开

  1. Bus.c
  2. #include <linux/device.h>
  3. #include <linux/module.h>
  4. #include <linux/kernel.h>
  5. #include <linux/init.h>
  6. #include <linux/string.h>
  7. #include <linux/sysfs.h>
  8. #include <linux/stat.h>
  9. #include <linux/mm.h>


  10. static ssize_t show_bus_author(struct bus_type *bus,char *buf) {
  11.         return snprintf(buf,PAGE_SIZE,"%s\n","show_bus_author");
  12.     }

  13. static int virtual_bus_match(struct device *dev,struct device_driver *drv) {
  14. Printk(KERN_DEBUG”\n!!!!!!match!!!!!!\n”);
  15.      return !strcmp(dev_name(dev),drv->name);
  16.     }

  17. void my_bus_release(struct device *dev) {
  18.         printk(KERN_DEBUG"my bus release\n");
  19.     }

  20. struct bus_type virtual_bus={
  21.         .name        =    "virtual_bus",
  22.         .match    =    virtual_bus_match,
  23.     };

  24. struct device my_busdev={
  25.         .init_name    =    "my_busdev",
  26.         .release    =    my_bus_release,
  27.     };
  28. EXPORT_SYMBOL(virtual_bus);
  29. EXPORT_SYMBOL(my_busdev);

  30. static BUS_ATTR(c,S_IRUGO,show_bus_author,NULL);

  31. static int __init bus_init(void) {
  32.     int ret;
  33.     ret=bus_register(&virtual_bus);    //register virtual_bus
  34.     if(ret){
  35.         return ret;
  36.     }
  37.     if(bus_create_file(&virtual_bus,&bus_attr_c)) { //创建总线属性文件
  38.         printk(KERN_NOTICE"unable to create bus attr\n");
  39.     }
  40.     
  41.     ret =    device_register(&my_busdev);
  42.     if(ret) {
  43.     printk(KERN_NOTICE"unable to register device\n");
  44.     }
  45.     printk("bus register success!\n");
  46.     return 0;
  47. }

  48. static void __exit bus_exit(void) {
  49.     bus_unregister(&virtual_bus);
  50.     device_unregister(&my_busdev);
  51. }

  52. module_init(bus_init);
  53. module_exit(bus_exit);
  54. MODULE_AUTHOR("MANGO");
  55. MODULE_LICENSE("Dual BSD/GPL")

编译后,会在/sys/bus下建立virtual_bus文件夹。


执行cat c,得到如下输出:



设备驱动程序:


点击(此处)折叠或打开

  1. struct device_driver {
  2.     const char        * name;
  3.     struct bus_type        * bus;
  4.     struct kobject        kobj;
  5.     struct klist        klist_devices;
  6.     struct klist_node    knode_bus;
  7.     struct module        * owner;
  8.     const char         * mod_name;    /* used for built-in modules */
  9.     struct module_kobject    * mkobj;
  10.     int    (*probe)    (struct device * dev);
  11.     int    (*remove)    (struct device * dev);
  12.     void    (*shutdown)    (struct device * dev);
  13.     int    (*suspend)    (struct device * dev, pm_message_t state);
  14.     int    (*resume)    (struct device * dev);
  15. }

Driver.c


点击(此处)折叠或打开

  1. #include <linux/device.h>
  2. #include <linux/module.h>
  3. #include <linux/kernel.h>
  4. #include <linux/init.h>
  5. #include <linux/string.h>
  6. #include <linux/sysfs.h>
  7. #include <linux/stat.h>
  8. #include <linux/mm.h>

  9. extern struct device my_busdev;
  10. extern struct bus_type virtual_bus;
  11. extern struct device virtual_device;

  12. static ssize_t show_driver_author(struct device_driver *driver,char *buf) {
  13.     return snprintf(buf,PAGE_SIZE,"%s\n","mango");
  14. }

  15. int my_driver_remove(struct device *dev) {
  16.     printk("my_driver_remove\n");
  17.     return 0;
  18. }

  19. int my_driver_probe(struct device *dev) {
  20.     printk("my_driver_probe\n");
  21.     return 0;
  22. }

  23. struct device_driver virtual_driver={
  24.         .name        =    "mytest",
  25.         .bus        =    &virtual_bus,
  26.         .probe    =        my_driver_probe,
  27.         .remove    =        my_driver_remove,
  28.     };

  29. static DRIVER_ATTR(c,S_IRUGO,show_driver_author,NULL);

  30. static int __init my_driver_init(void) {
  31.         int ret;
  32.         ret    =    driver_register(&virtual_driver);
  33.         if(ret)
  34.             return ret;
  35.         if(driver_create_file(&virtual_driver,&driver_attr_c))
  36.             printk(KERN_NOTICE"unable to create author attr\n");
  37.         printk("driver register success\n");
  38.         return ret;
  39.     }

  40. static void __exit my_driver_exit(void) {
  41.         driver_unregister(&virtual_driver);
  42.         printk("driver unregister success\n");
  43. }

  44. module_init(my_driver_init);
  45. module_exit(my_driver_exit);
  46. MODULE_AUTHOR("MANGO");
  47. MODULE_LICENSE("Dual BSD/GPL")
编译后driver.ko

设备:



点击(此处)折叠或打开

  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;//设备的父设备,大多数情况下,一个父设备是某种总线的宿主控制器。如果是NULL,则表示该设备是顶层设备。
  7.     struct kobject kobj;//device->kobj->parent与&device->parent->kobj是相同的。
  8.     char    bus_id[BUS_ID_SIZE];    /* position on parent bus */
  9.     struct device_type    *type;
  10. ......
  11.     struct bus_type    * bus;        /* type of bus device is on */
  12.     struct device_driver *driver;    /* which driver has allocated this
  13.                      device */
  14.     void        *driver_data;    /* data private to the driver */
  15. ......
  16.     void    (*release)(struct device * dev);//当指向设备的最后一个引用被删除时,内核调用该方法。
  17. }

设备注册:int device_register(struct device *dev);

设备删除:int device_unregister(struct device *dev);

设备属性:


点击(此处)折叠或打开

  1. struct device_attribute {
  2.     struct attribute    attr;
  3.     ssize_t (*show)(struct device *dev, struct device_attribute *attr,
  4.             char *buf);
  5.     ssize_t (*store)(struct device *dev, struct device_attribute *attr,
  6.              const char *buf, size_t count);
  7. };

宏:#define DEVICE_ATTR(_name,_mode,_show,_store)

创建设备属性:

int device_create_file(struct device *device,struct device_attribute * entry);

删除设备属性:

void device_remove_file(struct device *dev,struct device_attribute *attr);

设置设备的名字:

dev_set_name(&dev, "name");

 

Device.c

点击(此处)折叠或打开
  1. #include <linux/device.h>
  2. #include <linux/module.h>
  3. #include <linux/kernel.h>
  4. #include <linux/init.h>
  5. #include <linux/string.h>
  6. #include <linux/sysfs.h>
  7. #include <linux/stat.h>
  8. #include <linux/mm.h>

  9. extern struct device my_bus;
  10. extern struct bus_type virtual_bus;
  11. extern struct device virtual_device;

  12. static ssize_t show_driver_author(struct device_driver *driver,char *buf) {
  13.     return snprintf(buf,PAGE_SIZE,"%s\n","mango");
  14. }

  15. int my_driver_remove(struct device *dev) {
  16.     printk("my_driver_remove\n");
  17.     return 0;
  18. }

  19. int my_driver_probe(struct device *dev) {
  20.     printk("my_driver_probe\n");
  21.     return 0;
  22. }

  23. struct device_driver virtual_driver={
  24.         .name        =    "mytest",
  25.         .bus        =    &virtual_bus,
  26.         .probe    =        my_driver_probe,
  27.         .remove    =        my_driver_remove,
  28.     };
  29. static char *c="mango_attr";

  30. static DRIVER_ATTR(c,S_IRUGO,show_driver_author,NULL);

  31. static int __init my_driver_init(void) {
  32.         int ret;
  33.         ret    =    driver_register(&virtual_driver);
  34.         if(ret)
  35.             return ret;
  36.         if(driver_create_file(&virtual_driver,&driver_attr_c))
  37.             printk(KERN_NOTICE"unable to create author attr\n");
  38.         printk("driver register success\n");
  39.         return ret;
  40.     }

  41. static void __exit my_driver_exit(void) {
  42.         driver_unregister(&virtual_driver);
  43.         printk("driver unregister success\n");
  44. }

  45. module_init(my_driver_init);
  46. module_exit(my_driver_exit);
  47. MODULE_AUTHOR("MANGO");
  48. MODULE_LICENSE("Dual BSD/GPL")

编译完后生成device.ko,加载后得到如下输出:


device指定的父设备是my_busdev,则应该对应目录为:/sys/devices/my_busdev/mytest

 

执行cat c,可以看到如下输出:


三个都加载,由于driverdevice名字一样,会匹配上,如下图:


此时再看bus下,文件结构如下:


会发现依附于virtual_bus总线的devicedriver通过总线match起来,且都建立了相应的连接文件。


device_driverdevice分别表示驱动和设备,这两者必须依附于一条总线,因此都包含了struct bus_type指针。在Linux内核中,设备和驱动程序是分开注册的。bus_typematch成员函数可以将两者捆绑在一起。

总线、驱动和设备最终会落实为sysfs中的1个目录,总线、设备和驱动中的各个attribute则直接落实为sysfs中的1个文件,attribute会伴随着showstore函数,分别用于读和写该attribute对应的sysfs文件结点。

事实上,udev规则中个信息的来源实际上就是bus_type,device_driver,device以及attribute等所对应的文件节点。

一个设备类描述了一种设备类型,类是一个设备的高层视图,几乎所有的类都显示在/sys/class目录中。一个例外是块设备。出于历史原因,它们出现在/sys/block下。

每个类都需要一个唯一的名字,它将显示在/sys/class中。

注册函数:int class_register(struct class *cls);

删除函数:void class_unregister(struct class *cls);




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