良许Linux教程网 干货合集 深入探讨Linux设备驱动模型-Device的实现原理和相关技术

深入探讨Linux设备驱动模型-Device的实现原理和相关技术

Linux系统中,设备驱动模型是一种非常重要的模型。它负责管理设备驱动程序并向用户空间提供接口。在本文中,我们将深入探讨Linux设备驱动模型-Device的实现原理和相关技术。

前言

Linux将所有的设备统一抽象为struct device结构, 同时将所有的驱动统一抽象为struct device_driver结构。这样设计之后就方便驱动开发工程师编写驱动,只需要将具体的设备包含struct device结构,具体的驱动包含struct device_driver结构。最终会调用device_register和driver_register将驱动和设备注册到系统,表现出来就是在sys目录的device和driver目录下。本小节先分析device结构,以及相关API,以及如何注册到系统中,以及提供给上层的sys接口。

数据结构

Linux将所有的设备统一抽象为struct device结构。定义在

1. struct device { 
2.   struct device    *parent; 
3.  
4.   struct device_private  *p; 
5.  
6.   struct kobject kobj; 
7.   const char   *init_name; /* initial name of the device */ 
8.   const struct device_type *type; 
9.  
10.   struct mutex    mutex; /* mutex to synchronize calls to 
11. ​           \* its driver. 
12. ​           */ 
13.  
14.   struct bus_type *bus;    /* type of bus device is on */ 
15.   struct device_driver *driver;  /* which driver has allocated this 
16. ​            device */ 
17.   void    *platform_data; /* Platform specific data, device 
18. ​            core doesn't touch it */ 
19.   void    *driver_data;  /* Driver data, set and get with 
20. ​            dev_set/get_drvdata */ 
21.   struct dev_pm_info power; 
22.   struct dev_pm_domain  *pm_domain; 
23.  
24. \#ifdef CONFIG_PINCTRL 
25.   struct dev_pin_info *pins; 
26. \#endif 
27.  
28. \#ifdef CONFIG_NUMA 
29.   int   numa_node; /* NUMA node this device is close to */ 
30. \#endif 
31.   u64   *dma_mask; /* dma mask (if dma'able device) */ 
32.   u64   coherent_dma_mask;/* Like dma_mask, but for 
33. ​             alloc_coherent mappings as 
34. ​             not all hardware supports 
35. ​             64 bit addresses for consistent 
36. ​             allocations such descriptors. */ 
37.   unsigned long  dma_pfn_offset; 
38.  
39.   struct device_dma_parameters *dma_parms; 
40.  
41.   struct list_head  dma_pools; /* dma pools (if dma'ble) */ 
42.  
43.   struct dma_coherent_mem *dma_mem; /* internal for coherent mem 
44. ​             override */ 
45. \#ifdef CONFIG_DMA_CMA 
46.   struct cma *cma_area;    /* contiguous memory area for dma 
47. ​            allocations */ 
48. \#endif 
49.   /* arch specific additions */ 
50.   struct dev_archdata archdata; 
51.  
52.   struct device_node *of_node; /* associated device tree node */ 
53.   struct acpi_dev_node  acpi_node; /* associated ACPI device node */ 
54.  
55.   dev_t      devt;  /* dev_t, creates the sysfs "dev" */ 
56.   u32     id; /* device instance */ 
57.  
58.   spinlock_t   devres_lock; 
59.   struct list_head  devres_head; 
60.  
61.   struct klist_node  knode_class; 
62.   struct class    *class; 
63.   const struct attribute_group **groups; /* optional groups */ 
64.  
65.   void  (*release)(struct device *dev); 
66.   struct iommu_group *iommu_group; 
67.  
68.   bool      offline_disabled:1; 
69.   bool      offline:1; 
70. }; 

device结构体比较复杂,同时其中还包含了dma, numa, pintrl, pm相关的知识,本小节不做过多谈论。不过该结构体的注释是相当的详细,可以参考。

parent: 代表设备的parent节点,通常parent是bus或者controller。 如果此parent为NULL,则此设备就是顶层设备。

p: 代表device的私有数据的指针,指针类型为device_private。

kobj: kobject结构,用于层级关系。

init_name: 设备对象的名称,出现在sys目录下。

type: 指向device_type结构,代表了设备的特殊的信息。

mutex: 同步操作。

bus: 设备所属的总线。

driver: 设备所对应的驱动。

platfrorm_data: 设备所对应的平台数据。

driver_data: 保存设备所对于驱动的数据,一般使用get/set函数。

power/pm_domain: 电源管理相关的内容。

of_node: 该设备对应的设备树结构。

devt: 设备号,由主设备号和次设备号组成。

id: 设备索引号。

devres_head: 设备资源管理的链表。用于将设备使用的资源用链表管理。

class: 设备所属的class。

group: 设备默认的属性。

设备相关函数

  • devices_init

此函数主要是初始化devices_kset,以及初始化所有的dev_kset

1. int __init devices_init(void) 
2. { 
3.   devices_kset = kset_create_and_add("devices", &device_uevent_ops, NULL);   
4.   if (!devices_kset) 
5. ​    return -ENOMEM; 
6.   dev_kobj = kobject_create_and_add("dev", NULL); 
7.   if (!dev_kobj) 
8. ​    goto dev_kobj_err; 
9.   sysfs_dev_block_kobj = kobject_create_and_add("block", dev_kobj); 
10.   if (!sysfs_dev_block_kobj) 
11. ​    goto block_kobj_err; 
12.   sysfs_dev_char_kobj = kobject_create_and_add("char", dev_kobj); 
13.   if (!sysfs_dev_char_kobj) 
14. ​    goto char_kobj_err; 
15.  
16.   return 0; 
17.  
18.  char_kobj_err: 
19.   kobject_put(sysfs_dev_block_kobj); 
20.  block_kobj_err: 
21.   kobject_put(dev_kobj); 
22.  dev_kobj_err: 
23.   kset_unregister(devices_kset); 
24.   return -ENOMEM; 
25. } 

内核中每一个设备都是struct device结构,同时内核将所有的设备使用devices_kset管理。同时为了统一方便管理又将设备分为block和char设备,生成的内核对象分别为sysfs_dev_block_kobj和sysfs_dev_char_kobj。当然这两个内核模块都是在dev内核模块之下的。

这个函数的操作实现最后表现到sys文件目录下,分别为/sys/devices, /sys/dev, /sys/dev/char, /sys/dev/block。

  • device_initialize(用于初始化一个device)
1. void device_initialize(struct device *dev) 
2. { 
3.   dev->kobj.kset = devices_kset; 
4.   kobject_init(&dev->kobj, &device_ktype); 
5.   INIT_LIST_HEAD(&dev->dma_pools); 
6.   mutex_init(&dev->mutex); 
7.   lockdep_set_novalidate_class(&dev->mutex); 
8.   spin_lock_init(&dev->devres_lock); 
9.   INIT_LIST_HEAD(&dev->devres_head); 
10.   device_pm_init(dev); 
11.   set_dev_node(dev, -1); 
12. } 

主要是设置设备所属的kset,设置设备所属kset的ktype,初始化设备资源管理的链表,以及设备电源管理初始化。

  • device_add(添加一个设备到系统中)
1. int device_add(struct device *dev) 
2. { 
3.   struct device *parent = NULL; 
4.   struct kobject *kobj; 
5.   struct class_interface *class_intf; 
6.   int error = -EINVAL; 
7.  
8.   dev = get_device(dev);                 //增加此设备的引用计数 
9.   if (!dev) 
10. ​    goto done; 
11.  
12.   if (!dev->p) { 
13. ​    error = device_private_init(dev);      ---------------A 
14. ​    if (error) 
15. ​      goto done; 
16.   } 
17.  
18.   /* 
19.    \* for statically allocated devices, which should all be converted 
20.    \* some day, we need to initialize the name. We prevent reading back 
21.    \* the name, and force the use of dev_name() 
22.    */ 
23.   if (dev->init_name) { 
24. ​    dev_set_name(dev, "%s", dev->init_name); 
25. ​    dev->init_name = NULL; 
26.   } 
27.  
28.   /* subsystems can specify simple device enumeration */ 
29.   if (!dev_name(dev) && dev->bus && dev->bus->dev_name) 
30. ​    dev_set_name(dev, "%s%u", dev->bus->dev_name, dev->id); 
31.  
32.   if (!dev_name(dev)) {                         //设置device的name域,如果设置失败退出。 
33. ​    error = -EINVAL;                           
34. ​    goto name_error; 
35.   }                        
36.  
37.   pr_debug("device: '%s': %s\n", dev_name(dev), __func__); 
38.  
39.   parent = get_device(dev->parent);                   //增加设备parent的引用计数 
40.   kobj = get_device_parent(dev, parent);                 //设置设备parent的内核对象,建立设备在sys下的层次结构。 
41.   if (kobj) 
42. ​    dev->kobj.parent = kobj; 
43.  
44.   /* use parent numa_node */ 
45.   if (parent) 
46. ​    set_dev_node(dev, dev_to_node(parent)); 
47.  
48.   /* first, register with generic layer. */ 
49.   /* we require the name to be set before, and pass NULL */ 
50.   error = kobject_add(&dev->kobj, dev->kobj.parent, NULL);       //调用kobject_add将设备添加到sys中 
51.   if (error) 
52. ​    goto Error; 
53.  
54.   /* notify platform of device entry */ 
55.   if (platform_notify)                          
56. ​    platform_notify(dev);  
57.  
58.   error = device_create_file(dev, &dev_attr_uevent);         //创建设备的uevent属性 
59.   if (error) 
60. ​    goto attrError; 
61.  
62.   if (MAJOR(dev->devt)) { 
63. ​    error = device_create_file(dev, &dev_attr_dev);       //如果主设备号存在,创建dev属性 
64. ​    if (error) 
65. ​      goto ueventattrError; 
66.  
67. ​    error = device_create_sys_dev_entry(dev); 
68. ​    if (error) 
69. ​      goto devtattrError; 
70.  
71. ​    devtmpfs_create_node(dev);                 //调用devtmpfs,自动创建设备节点 
72.   } 
73.  
74.   error = device_add_class_symlinks(dev);               //创建链接文件 
75.   if (error) 
76. ​    goto SymlinkError; 
77.   error = device_add_attrs(dev);                   //添加设备的属性 
78.   if (error) 
79. ​    goto AttrsError; 
80.   error = bus_add_device(dev);                    //将此设备添加到一条总线上 
81.   if (error) 
82. ​    goto BusError; 
83.   error = dpm_sysfs_add(dev); 
84.   if (error) 
85. ​    goto DPMError; 
86.   device_pm_add(dev);                         //将设备添加到pm core链表中,会在suspend中使用到 
87.  
88.   /* Notify clients of device addition. This call must come 
89.    \* after dpm_sysfs_add() and before kobject_uevent(). 
90.    */ 
91.   if (dev->bus) 
92. ​    blocking_notifier_call_chain(&dev->bus->p->bus_notifier,  //使用通知链同时有新设备添加到bus中 
93. ​             BUS_NOTIFY_ADD_DEVICE, dev); 
94.  
95.   kobject_uevent(&dev->kobj, KOBJ_ADD);           //使用uevent通知上层,这时候就会使用到device_uevent_ops中的函数 
96.   bus_probe_device(dev);                  //匹配bus下的设备与驱动 
97.   if (parent) 
98. ​    klist_add_tail(&dev->p->knode_parent,       //如果parent存在,将dev添加到parent链表中 
99. ​          &parent->p->klist_children); 
100.  
101.   if (dev->class) {                     //如果class存在,则将dev添加到class链表中 
102. ​    mutex_lock(&dev->class->p->mutex); 
103. ​    /* tie the class to the device */ 
104. ​    klist_add_tail(&dev->knode_class, 
105. ​          &dev->class->p->klist_devices); 
106.  
107. ​    /* notify any interfaces that the device is here */ 
108. ​    list_for_each_entry(class_intf, 
109. ​          &dev->class->p->interfaces, node) 
110. ​      if (class_intf->add_dev) 
111. ​        class_intf->add_dev(dev, class_intf); 
112. ​    mutex_unlock(&dev->class->p->mutex); 
113.   } 
114. } 

A: 如果设备的device_private不存在,就重现分配一个

  1. 1. int device_private_init(struct device *dev) 
    2. { 
    3.   dev->p = kzalloc(sizeof(*dev->p), GFP_KERNEL);             //分配一个device_private结构 
    4.   if (!dev->p) 
    5. ​    return -ENOMEM; 
    6.   dev->p->device = dev;                         //设置device_private的device结构 
    7.   klist_init(&dev->p->klist_children, klist_children_get,      
    8. ​      klist_children_put);                    //初始化设备下所有children链表 
    9.   INIT_LIST_HEAD(&dev->p->deferred_probe); 
    10.   return 0; 
    11. } 
    

B: 主要分析下如何将设备添加到一条总线上,这是核心。

1. int bus_add_device(struct device *dev) 
2. { 
3.   struct bus_type *bus = bus_get(dev->bus); 
4.   int error = 0; 
5.  
6.   if (bus) { 
7. ​    pr_debug("bus: '%s': add device %s\n", bus->name, dev_name(dev)); 
8. ​    error = device_add_attrs(bus, dev); 
9. ​    if (error) 
10. ​      goto out_put; 
11. ​    error = device_add_groups(dev, bus->dev_groups); 
12. ​    if (error) 
13. ​      goto out_groups; 
14. ​    error = sysfs_create_link(&bus->p->devices_kset->kobj, 
15. ​            &dev->kobj, dev_name(dev)); 
16. ​    if (error) 
17. ​      goto out_id; 
18. ​    error = sysfs_create_link(&dev->kobj, 
19. ​        &dev->bus->p->subsys.kobj, "subsystem"); 
20. ​    if (error) 
21. ​      goto out_subsys; 
22. ​    klist_add_tail(&dev->p->knode_bus, &bus->p->klist_devices); 
23.   } 
24.   return 0; 
25. } 

如果此设备不属于任何总线,直接就返回,否则添加设备属性,创建链接文件,将此bus下的设备添加到klist_devices链表中。

C: 关于总线先设备与驱动的匹配是设备驱动模型的核心

1. void bus_probe_device(struct device *dev) 
2. { 
3.   struct bus_type *bus = dev->bus; 
4.   struct subsys_interface *sif; 
5.   int ret; 
6.  
7.   if (!bus)                //如果不存在总线,直接返回 
8. ​    return; 
9.  
10.   if (bus->p->drivers_autoprobe) {    //是否总线支持自动匹配 
11. ​    ret = device_attach(dev); 
12. ​    WARN_ON(ret p->mutex);       
16.   list_for_each_entry(sif, &bus->p->interfaces, node) 
17. ​    if (sif->add_dev) 
18. ​      sif->add_dev(dev, sif);       
19.   mutex_unlock(&bus->p->mutex); 
20. } 

一般总线都会支持自动匹配,当然可以修改driver_autoprobe的值,然后调用device_attach进行匹配。

1. int device_attach(struct device *dev) 
2. { 
3.   int ret = 0; 
4.  
5.   device_lock(dev);           //因为此操作只能运行一个dev进行,需要互斥保护。 
6.   if (dev->driver) {           //如果设备存在对应的driver,说明已经进行了匹配,只需要调用device_bind_driver在sys中建立关系。 
7. ​    if (klist_node_attached(&dev->p->knode_driver)) { 
8. ​      ret = 1; 
9. ​      goto out_unlock; 
10. ​    } 
11. ​    ret = device_bind_driver(dev); 
12. ​    if (ret == 0) 
13. ​      ret = 1; 
14. ​    else { 
15. ​      dev->driver = NULL; 
16. ​      ret = 0; 
17. ​    } 
18.   } else { 
19. ​    ret = bus_for_each_drv(dev->bus, NULL, dev, __device_attach);   //如果driver不存在,则需要遍历dev所在bus下的所有driver 
20. ​    pm_request_idle(dev); 
21.   } 
22. out_unlock: 
23.   device_unlock(dev); 
24.   return ret; 
25. 

}

当遍历driver下过程中,最终会调用到__device_attach函数。

1. static int __device_attach(struct device_driver *drv, void *data) 
2. { 
3.   struct device *dev = data; 
4.  
5.   if (!driver_match_device(drv, dev)) 
6. ​    return 0; 
7.  
8.   return driver_probe_device(drv, dev); 
9. } 

函数match最终使用的匹配是

 ![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)

1. static inline int driver_match_device(struct device_driver *drv, 
2. ​           struct device *dev) 
3. { 
4.   return drv->bus->match ? drv->bus->match(dev, drv) : 1; 
5. } 

根据bus是否存在match函数,如果存在调用bus的match函数,如果不存在,直接返回1。如果匹配成功之后就会调用driver_probe_device进行绑定,最终会调用really_probe函数。

1. static int really_probe(struct device *dev, struct device_driver *drv) 
2. { 
3.   int ret = 0; 
4.   int local_trigger_count = atomic_read(&deferred_trigger_count); 
5.  
6.   atomic_inc(&probe_count); 
7.   pr_debug("bus: '%s': %s: probing driver %s with device %s\n", 
8. ​     drv->bus->name, __func__, drv->name, dev_name(dev)); 
9.   WARN_ON(!list_empty(&dev->devres_head)); 
10.  
11.   dev->driver = drv;                         //设置设备的driver变量 
12.  
13.   /* If using pinctrl, bind pins now before probing */ 
14.   ret = pinctrl_bind_pins(dev); 
15.   if (ret) 
16. ​    goto probe_failed; 
17.  
18.   if (driver_sysfs_add(dev)) {                     
19. ​    printk(KERN_ERR "%s: driver_sysfs_add(%s) failed\n", 
20. ​      __func__, dev_name(dev)); 
21. ​    goto probe_failed; 
22.   } 
23.  
24.   if (dev->bus->probe) { 
25. ​    ret = dev->bus->probe(dev);          //如果bus的probe存在,则调用bus的probe函数 
26. ​    if (ret) 
27. ​      goto probe_failed; 
28.   } else if (drv->probe) {                //否则调用驱动的probe,这下知道驱动的probe函数是如何调用的。 
29. ​    ret = drv->probe(dev); 
30. ​    if (ret) 
31. ​      goto probe_failed; 
32.   } 
33.  
34.   driver_bound(dev);                   //将设备所属的驱动加入到驱动链表中,使用通知链发出BOUND信息。 
35.   ret = 1; 
36.   pr_debug("bus: '%s': %s: bound device %s to driver %s\n", 
37. ​     drv->bus->name, __func__, dev_name(dev), drv->name); 
38.   goto done; 
39.  
40. probe_failed:        //probe失败之后,就会清空设备资源,设备driver设置为NULL,从sys中移除dev建立的driver链接。 
41.   devres_release_all(dev); 
42.   driver_sysfs_remove(dev); 
43.   dev->driver = NULL; 
44.   dev_set_drvdata(dev, NULL); 
45.  
46.   if (ret == -EPROBE_DEFER) { 
47. ​    /* Driver requested deferred probing */ 
48. ​    dev_info(dev, "Driver %s requests probe deferral\n", drv->name); 
49. ​    driver_deferred_probe_add(dev); 
50. ​    /* Did a trigger occur while probing? Need to re-trigger if yes */ 
51. ​    if (local_trigger_count != atomic_read(&deferred_trigger_count)) 
52. ​      driver_deferred_probe_trigger(); 
53.   } else if (ret != -ENODEV && ret != -ENXIO) { 
54. ​    /* driver matched but the probe failed */ 
55. ​    printk(KERN_WARNING 
56. ​        "%s: probe of %s failed with error %d\n", 
57. ​        drv->name, dev_name(dev), ret); 
58.   } else { 
59. ​    pr_debug("%s: probe of %s rejects match %d\n", 
60. ​        drv->name, dev_name(dev), ret); 
61.   } 
62.   /* 
63.    \* Ignore errors returned by ->probe so that the next driver can try 
64.    \* its luck. 
65.    */ 
66.   ret = 0; 
67. } 
  • device_register(注册一个设备到系统中是上述两个函数的结合体)
  • device_unregister(将一个设备从系统中注销)
1. void device_unregister(struct device *dev) 
2. { 
3.   pr_debug("device: '%s': %s\n", dev_name(dev), __func__); 
4.   device_del(dev); 
5.   put_device(dev); 
6. } 

此函数分为两步走,第一步从系统中移除此设备,第二步将设备的引用计数减去1。主要的注销操作在device_del中实现,也就是register的反操作。

1. void device_del(struct device *dev) 
2. { 
3.   struct device *parent = dev->parent; 
4.   struct class_interface *class_intf; 
5.  
6.   /* Notify clients of device removal. This call must come 
7.    \* before dpm_sysfs_remove(). 
8.    */ 
9.   if (dev->bus)   //如果bus总线存在,调用通知链删除设备 
10. ​    blocking_notifier_call_chain(&dev->bus->p->bus_notifier, 
11. ​             BUS_NOTIFY_DEL_DEVICE, dev); 
12.   dpm_sysfs_remove(dev); //电源管理函数,关掉设备电源 
13.   if (parent)      //如果有父设备,将当前设备从父设备所属链表删除 
14. ​    klist_del(&dev->p->knode_parent); 
15.   if (MAJOR(dev->devt)) {   //如果主设备号存在, 动态删除设备节点,移除设备的属性 
16. ​    devtmpfs_delete_node(dev); 
17. ​    device_remove_sys_dev_entry(dev); 
18. ​    device_remove_file(dev, &dev_attr_dev); 
19.   } 
20.   if (dev->class) {  //如果设备所属的class存在,移除设备的链接,调用remove_dev做移除,从class链表中删除该设备 
21. ​    device_remove_class_symlinks(dev); 
22.  
23. ​    mutex_lock(&dev->class->p->mutex); 
24. ​    /* notify any interfaces that the device is now gone */ 
25. ​    list_for_each_entry(class_intf, 
26. ​          &dev->class->p->interfaces, node) 
27. ​      if (class_intf->remove_dev) 
28. ​        class_intf->remove_dev(dev, class_intf); 
29. ​    /* remove the device from the class list */ 
30. ​    klist_del(&dev->knode_class); 
31. ​    mutex_unlock(&dev->class->p->mutex); 
32.   } 
33.   device_remove_file(dev, &dev_attr_uevent);  //移除设备的uevent属性 
34.   device_remove_attrs(dev);       
35.   bus_remove_device(dev);            //从总线中移除设备,以及电源管理等。 
36.   device_pm_remove(dev); 
37.   driver_deferred_probe_del(dev); 
38.  
39.   /* Notify the platform of the removal, in case they 
40.    \* need to do anything... 
41.    */ 
42.   if (platform_notify_remove) 
43. ​    platform_notify_remove(dev); 
44.   if (dev->bus) 
45. ​    blocking_notifier_call_chain(&dev->bus->p->bus_notifier, 
46. ​             BUS_NOTIFY_REMOVED_DEVICE, dev); 
47.   kobject_uevent(&dev->kobj, KOBJ_REMOVE); 
48.   cleanup_device_parent(dev); 
49.   kobject_del(&dev->kobj);       //删除设备的内核模块 
50.   put_device(parent); 
51. } 

设备属性

linux中使用device_attribute结构体表示一个设备的属性

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

通常使用to_dev_attr宏定义得到device_attribute对象

\#define to_dev_attr(_attr) container_of(_attr, struct device_attribute, attr) 

同时为了方便定义设备的属性,内核提供了一系列相关的宏定义,用于初始化设备的属性。

1. \#define DEVICE_ATTR(_name, _mode, _show, _store) \ 
2.   struct device_attribute dev_attr_##_name = __ATTR(_name, _mode, _show, _store) 
3. \#define DEVICE_ATTR_RW(_name) \ 
4.   struct device_attribute dev_attr_##_name = __ATTR_RW(_name) 
5. \#define DEVICE_ATTR_RO(_name) \ 
6.   struct device_attribute dev_attr_##_name = __ATTR_RO(_name) 
7. \#define DEVICE_ATTR_WO(_name) \ 
8.   struct device_attribute dev_attr_##_name = __ATTR_WO(_name) 

关于设备属性的调用过程,最终会调用到设备的show和store函数中,具体的流程分析可见Linux设备驱动模型-Ktype

  1. 1. static ssize_t dev_attr_show(struct kobject *kobj, struct attribute *attr, 
    2. ​         char *buf) 
    3. { 
    4.   struct device_attribute *dev_attr = to_dev_attr(attr); 
    5.   struct device *dev = kobj_to_dev(kobj); 
    6.   ssize_t ret = -EIO; 
    7.  
    8.   if (dev_attr->show) 
    9. ​    ret = dev_attr->show(dev, dev_attr, buf); 
    10.   if (ret >= (ssize_t)PAGE_SIZE) { 
    11. ​    print_symbol("dev_attr_show: %s returned bad count\n", 
    12. ​        (unsigned long)dev_attr->show); 
    13.   } 
    14.   return ret; 
    15. } 
    16.  
    17. static ssize_t dev_attr_store(struct kobject *kobj, struct attribute *attr, 
    18. ​         const char *buf, size_t count) 
    19. { 
    20.   struct device_attribute *dev_attr = to_dev_attr(attr); 
    21.   struct device *dev = kobj_to_dev(kobj); 
    22.   ssize_t ret = -EIO; 
    23.  
    24.   if (dev_attr->store) 
    25. ​    ret = dev_attr->store(dev, dev_attr, buf, count); 
    26.   return ret; 
    27. } 
    28.  
    29. static const struct sysfs_ops dev_sysfs_ops = { 
    30.   .show  = dev_attr_show, 
    31.   .store = dev_attr_store, 
    32. }; 
    

设备类型

在include/linux/device.h文件存在这样的结构体:

1. struct device_type { 
2.   const char *name; 
3.   const struct attribute_group **groups; 
4.   int (*uevent)(struct device *dev, struct kobj_uevent_env *env); 
5.   char *(*devnode)(struct device *dev, umode_t *mode, 
6. ​       kuid_t *uid, kgid_t *gid); 
7.   void (*release)(struct device *dev); 
8.  
9.   const struct dev_pm_ops *pm; 
10. }; 

此结构代表设备类型。通常一个Bus下会存在各种设备的,比如:disks, mouse, event等。而此结构就表明此设备是何种类型的设备。

name: 代表设备的名称,在上报event的时候,会通过DEVTYPE设置设备的类型名称。

groups: 代码设备的属性,在添加设备的属性的时候,如果存在设备类型,也会添加设备类型的属性。

uevent: 在新增一个设备时,通过该函数上报设备类型的uevent。

devnode: 在创建一个设备节点的时候会使用到,获取设备的信息。

release: 在设备释放时候,如果存在设备类型会调用到。

总之,设备驱动模型是Linux系统中不可或缺的一部分。它负责管理设备驱动程序并向用户空间提供接口。希望本文能够帮助读者更好地理解Linux设备驱动模型-Device的实现原理和相关技术。

以上就是良许教程网为各位朋友分享的Linu系统相关内容。想要了解更多Linux相关知识记得关注公众号“良许Linux”,或扫描下方二维码进行关注,更多干货等着你 !

137e00002230ad9f26e78-265x300
本文由 良许Linux教程网 发布,可自由转载、引用,但需署名作者且注明文章出处。如转载至微信公众号,请在文末添加作者公众号二维码。
良许

作者: 良许

良许,世界500强企业Linux开发工程师,公众号【良许Linux】的作者,全网拥有超30W粉丝。个人标签:创业者,CSDN学院讲师,副业达人,流量玩家,摄影爱好者。
上一篇
下一篇

发表评论

联系我们

联系我们

公众号:良许Linux

在线咨询: QQ交谈

邮箱: yychuyu@163.com

关注微信
微信扫一扫关注我们

微信扫一扫关注我们

关注微博
返回顶部