Linux驱动之设备模型(5)-设备

1. 设备,LDM中用device结构体来描述设备

  1. struct device {  
  2.  /* 父设备,通常是某种总线或者是宿主设备 */  
  3.          struct device             *parent;    
  4.  /* 私有数据指针:子设备链表,父设备链表节点,驱动程序链表节点,总线链表节点 */  
  5.          struct device_private       *p;    
  6.    
  7.          struct kobject kobj;          /* 连接到结构体系中的kobject */  
  8.          const char                  *init_name; /* initial name of the device */  
  9.          const struct device_type *type;  /* 设备类型 */  
  10.    
  11.          struct bus_type        *bus;    /* 依附的总线 */  
  12.          struct device_driver *driver;   /* 关联的驱动程序 */  
  13.          void           *platform_data;      /* Platform specific data*/  
  14.    
  15.          dev_t                           devt;         /* dev_t, creates the sysfs"dev" */  
  16.    
  17.          struct klist_node      knode_class;  /*  */  
  18.          struct class                *class;       /* 设备所属的类 */  
  19.          const struct attribute_group **groups; /* optional groups */  
  20.    
  21.          void  (*release)(structdevice *dev);  /* 当引用计数(kobject->kref)减为0时调用 */  
  22. };  

我们在注册一个设备时,通常要初始化parent,name,bus_id和bus这四个成员。


2. 设备的注册和注销

  1. int device_register(struct device *dev)  
  2. void device_unregister(struct device *dev)  

    注册函数分析,注册函数分为两个部分device_initialize和device_add,具体分析一下device_add

  1. int device_add(structdevice *dev)  
  2. {  
  3.          struct device *parent = NULL;  
  4.          struct class_interface *class_intf;  
  5.          int error = -EINVAL;  
  6.           
  7.          /* 引用计数加1 */  
  8.          dev = get_device(dev);  
  9.    
  10.          /* 
  11.           * for statically allocated devices, whichshould all be converted 
  12.           * some day, we need to initialize the name. We prevent reading back 
  13.           * the name, and force the use of dev_name() 
  14.           */  
  15.          if (dev->init_name) {  
  16.                    dev_set_name(dev,"%s", dev->init_name);  
  17.                    dev->init_name = NULL;  
  18.          }  
  19.    
  20.          /* 增加父设备的引用计数 */  
  21.          parent = get_device(dev->parent);  
  22.          setup_parent(dev, parent);  
  23.    
  24.          /* 把内嵌的kobject注册到设备模型中 */  
  25.          error = kobject_add(&dev->kobj,dev->kobj.parent, NULL);  
  26.    
  27.                    /*创建属性文件uevent */  
  28.          error = device_create_file(dev,&uevent_attr);  
  29.    
  30.          /* 如果定义了devt,则产生dev属性,并在/dev目录下产生设备节点文件 */  
  31.          if (MAJOR(dev->devt)) {  
  32.                    error = device_create_file(dev,&devt_attr);  
  33.                   }  
  34.    
  35.          /* 创建属性文件 */  
  36.          error = device_add_class_symlinks(dev);  
  37.          error = device_add_attrs(dev);  
  38.    
  39.          /* 把设备添加到总线上,这个是重点,稍后分析*/  
  40.          error = bus_add_device(dev);  
  41.    
  42.                    /*产生KOBJ_ADD uevent */  
  43.          kobject_uevent(&dev->kobj,KOBJ_ADD);  
  44.    
  45.          /* 给设备探测相应的驱动 */  
  46.          bus_probe_device(dev);  
  47.    
  48.          /* 如果设备有父设备,将它加入parent的子设备链中 */  
  49.          if (parent)  
  50.                    klist_add_tail(&dev->p->knode_parent,  
  51.                                    &parent->p->klist_children);  
  52.    
  53.          /* 如果设备附属于某个类,则需完成相应工作*/  
  54.          if (dev->class) {  
  55.                    /* 把设备添加到class的设备链表中,完成关联*/  
  56.                    klist_add_tail(&dev->knode_class,  
  57.                                   &dev->class->p->klist_devices);  
  58.    
  59.                    /* notify any interfaces thatthe device is here */  
  60.                    list_for_each_entry(class_intf,  
  61.                                         &dev->class->p->class_interfaces, node)  
  62.                             if(class_intf->add_dev)  
  63.                                      class_intf->add_dev(dev,class_intf);  
  64.          }  
  65. }  
bus_add_device()
  1. int bus_add_device(struct device *dev)  
  2. {  
  3.          /* 引用计数加一 */  
  4.          struct bus_type *bus =bus_get(dev->bus);  
  5.    
  6.          if (bus) {  
  7.                    /* 创建相应的属性文件 */  
  8.                    error = device_add_attrs(bus,dev);  
  9.                    error =sysfs_create_link(&bus->p->devices_kset->kobj,  
  10.                                                         &dev->kobj,dev_name(dev));  
  11.                    error =sysfs_create_link(&dev->kobj,  
  12.                                      &dev->bus->p->subsys.kobj,"subsystem");  
  13.                    /* 把设备加入到总线的设备链中,这步才是重点*/  
  14.                    klist_add_tail(&dev->p->knode_bus,&bus->p->klist_devices);  
  15.          }  
  16. }  

bus_probe_device()->device_attach()

  1. int device_attach(struct device *dev)  
  2. {  
  3.          if (dev->driver) {  
  4.                    /* 如果设备已经依附于某个驱动,进行绑定 */  
  5.                    ret =device_bind_driver(dev);  
  6.          } else {  
  7.                    /* 遍历bus->p->klist_drivers寻找匹配的驱动,然后执行回调函数__device_attach */  
  8.                    ret = bus_for_each_drv(dev->bus, NULL, dev,__device_attach);  
  9.          }  
  10. out_unlock:  
  11.          device_unlock(dev);  
  12.          return ret;  
  13. }  

__device_attach()->driver_probe_device()->really_probe()->bus->probe()->drv->probe()  总线中定义的probe函数会优先执行,如果总线中没有定义probe才会执行驱动中定义的probe


3. 设备属性

   设备属性由device_attribute来表示

  1. structdevice_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. };  

初始化设备属性:

  1. DEVICE_ATTR(_name,_mode, _show, _store)  

 在sysfs目录下产生和移除属性文件
  1. int device_create_file(struct device *device,  
  2.                                                conststruct device_attribute *entry);  
  3. void device_remove_file(struct device *dev,  
  4.                                                 const struct device_attribute*attr);  

 

4. 实例解析

创建一个设备和它的属性version,并将此设备挂接到之前创建的总线上

  1. /* 
  2. * for learn device 
  3. */  
  4. #include <linux/init.h>  
  5. #include <linux/module.h>  
  6. #include <linux/kernel.h>  
  7. #include <linux/device.h>  
  8.    
  9. extern struct bus_type scbus_type;  
  10. extern struct device scbus;  
  11.    
  12. static char *Version = "revision1.0";  
  13.    
  14. /* 析构函数,引用计数减为0时调用 */  
  15. void screlease(struct device *dev)  
  16. {  
  17.          printk("scbusrelease\n");  
  18. }  
  19.    
  20. struct device scdevice = {  
  21.          .parent     = &scbus,           /* 父设备,此处为依附的总线 */  
  22.          .init_name        = "scdevice0",   
  23.          .bus = &scbus_type,        /* 依附的总线类型 */  
  24.          .release   = screlease,  
  25. };  
  26.    
  27. /* 
  28. * export device attribute 
  29. */  
  30. static ssize_t show_device_version(structdevice *dev,  
  31.                             structdevice_attribute *attr, char *buf)  
  32. {  
  33.          returnsprintf(buf, "%s\n", Version);  
  34. }  
  35. DEVICE_ATTR(version, 0666,show_device_version, NULL);  
  36.    
  37.    
  38. static int __init scdevice_init(void)  
  39. {  
  40.          intret;  
  41.    
  42.          /*注册设备 */  
  43.          ret= device_register(&scdevice);  
  44.          if(ret)  
  45.                    returnret;  
  46.    
  47.          /*创建属性 */  
  48.          ret= device_create_file(&scdevice, &dev_attr_version);  
  49.          if(ret)  
  50.                    gotoerr_create;  
  51.    
  52.          printk("Createa scdevice");  
  53.          return0;  
  54.    
  55. err_create:  
  56.          device_unregister(&scdevice);  
  57.          returnret;  
  58. }  
  59.    
  60. static void __exit scdevice_exit(void)  
  61. {  
  62.          device_remove_file(&scdevice,&dev_attr_version);  
  63.          device_unregister(&scdevice);  
  64.          printk("Removea scdevice");  
  65. }  
  66.    
  67. module_init(scdevice_init);  
  68. module_exit(scdevice_exit);  
  69.    
  70. MODULE_LICENSE("Dual BSD/GPL");  
  71. MODULE_AUTHOR("CJOK<cjok.liao@gmail.com>");  
  72.    

试验结果:



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值