嵌入式Linux设备驱动之总线、设备、驱动之间有何关系?
扫描二维码
随时随地手机看文章
Linux设备驱动的难点在于复杂的,庞大的结构。理清楚结构和一个结构与另外结构的关系,以及linux设备驱动的层次性和层次封装抽象性。对于linux设备驱动的结构有点像C++中的类,而层次与抽象有点像继承的关系。
一、总线、设备、驱动的主要三个结构关系
structbus_type
---------------------------------
struct bus_type中为devices和drivers准备了两个链表:
struct klist klist_devices
struct klist klist_drivers
struct device
---------------------------------
struct device有两个成员
struct bus_type *bus 记录的是这个设备连在哪条总线上
struct device_driver *driver 记录的是这个设备用的是哪个驱动
struct device_driver
---------------------------------
struct device_driver同样有两个成员
struct bus_type *bus 代表的是这个驱动属于哪条总线
struct klist klist_devices 记录的是这个驱动支持的那些设备,没错,是devices(复数),因为一个驱动程序可以支持一个或多个设备,反过来一个设备则只会绑定给一个驱动程序.
二、总线,设备,驱动的关联
总线将设备和驱动绑定。在系统每注册一个设备的时候,会寻找与之匹配的驱动;相反的,在系统每 注册一个驱动的时候,会寻找与之匹配的设备,而匹配由总线完成。一个现实的Linux设备和驱动通常都需要挂接在一种总线上。设备与驱动的关联通过总线的match()方法进行匹配,驱动挂载总线时与所有设备进行匹配,设备挂载总线时与所有的驱动进行匹配,所以驱动和设备的挂载无先后之分。匹配成功后会通过调用驱动的probo()方法来初始化设备。
三、总线,设备,驱动的注册
设备与驱动需要挂载在总线上,需要指明驱动与设备是属于哪条总线的,所以设备与驱动需要注册。而总线在linux系统中也是属于设备,所以总线也要注册,同时要先有总线而后才能注册设备和驱动,所以总线要先注册。
总线在linux系统中有俩种,一是实际存在的总线 pci usb 等等,还有一类是虚拟存在的总线 platform ,platform总线主要是用于集成在SoC系统的设备,使得每一个设备都属于一条总线,相应的设备称为platform_device,而驱动成为 platform_driver。linux驱动中platform总线用的非常多,以platform总线说明总线,设备,驱动的注册顺序,注意这里是以先调加设备为例。
1. platform_bus_type -- 总线 先被kenrel 注册。
2. 系统初始化过程中调用platform_add_devices 或者platform_device_register ,将平台设备(platform devices) 注册到平台总线中( platform_bus_type )
3. 平台驱动(platform driver) 与平台设备(platform device) 的关联是在platform_driver_register 或者driver_register 中实现,一般这个函数在驱动的初始化过程调用。
通过这三步,就将平台总线,设备,驱动关联起来。
1. platform bus 先被kenrel 注册。
------------------------------------------------------
do_basic_setup() --> - driver_init() --> - platform_bus_init() -->bus_register()
2. 系统初始化过程中调用platform_add_devices 或者platform_device_register ,将平台设备(platform devices) 注册到平台总线中( platform_bus_type )
------------------------------------------------------
系统启动阶段,总线的驱动链表还是空的,所以启动阶段的platform_add_devices() 只负责将设备添加到总线的设备链表上。
linux 2.6.26/drivers/base/platform.c
int platform_add_devices(struct platform_device **devs, int num)
{
...
ret = platform_device_register (devs[i]);
...
}
int platform_device_register(struct platform_device *pdev)
{
device_initialize(&pdev >dev);
return platform_device_add (pdev);
}
int platform_device_add (struct platform_device *pdev)
{
...
pdev >dev.bus = &platform_bus_type;
...
ret = device_add (&pdev >dev);
...
}
device_add() > bus_attach_device()
void bus_attach_device(struct device *dev)
{
struct bus_type *bus = dev >bus;
int ret = 0;
if (bus) {
if (bus >p >drivers_autoprobe)
ret = device_attach (dev);
WARN_ON(ret < 0);
if (ret >= 0)
klist_add_tail (&dev >knode_bus, &bus >p >klist_devices);
}
}
device_attach() 的返回值:
1 设备和驱动匹配成功
0 设备已经注册,但是总线上没有与之相匹配的驱动( 系统启动阶段,由于总线上还没有驱动,所以设备在此匹配不到与之对应的驱动,只是将其添加到总线的设备链表)
-ENODEV 设备没有注册(registered) -- 设备在哪里注册?
如果设备和驱动匹配成功; 或者设备已经注册,但是总线上没有与之相匹配的驱动 ,bus_attach_device() 将调用klist_add_tail() 将设备添加到总线的设备链表尾部。
四、附录linux内核中的platform的几个结构源代码
[cpp] view plain copy
1. // 所在目录:kernel/include/linux/platform_device.h
2. struct platform_device
3. {
4. const char * name;/* 设备名 */
5. u32 id;
6. struct device dev;
7. u32 num_resources;/* 设备所使用各类资源数量 */
8. struct resource * resource;/* 资源 */
9. };
10. // 所在目录:include/linux/ioport.h
11. struct resource
12. {
13. resource_size_t start; /* 资源的开始值 */
14. resource_size_t end; /* 资源的结束值 */
15. const char *name; /* 资源的名字 */
16. unsigned long flags; /* 资源的类型值,如可以是:mem,io,irq,dma等等 */
17. struct resource *parent, *sibling, *child;
18. };
19. // 所在目录:kernel/include/linux/ioport.h
20. struct platform_driver
21. {
22. int (*probe)(struct platform_device *);
23. int (*remove)(struct platform_device *);
24. void (*shutdown)(struct platform_device *);
25. int (*suspend)(struct platform_device *, pm_message_t state);
26. int (*suspend_late)(struct platform_device *, pm_message_t state);
27. int (*resume_early)(struct platform_device *);
28. int (*resume)(struct platform_device *);
29. struct pm_ext_ops *pm;
30. struct device_driver driver;
31. };
32. // 所在目录:include/linux/device.h
33. struct device_driver
34. {
35. char * name;
36. struct bus_type * bus;
37. rwlock_t lock;
38. atomic_t refcount;
39. list_t bus_list;
40. list_t devices;
41. struct driver_dir_entry dir;
42. int (*probe) (struct device * dev);
43. int (*remove) (struct device * dev);
44. int (*suspend) (struct device * dev, u32 state, u32 level);
45. int (*resume) (struct device * dev, u32 level);
46. void (*release) (struct device_driver * drv);
47. };