当前位置:首页 > 嵌入式 > 嵌入式软件
[导读]Linux设备驱动的难点在于复杂的,庞大的结构。理清楚结构和一个结构与另外结构的关系,以及linux设备驱动的层次性和层次封装抽象性。对于linux设备驱动的结构有点像C++中的类,而层次与抽象有点像继承的关系。

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

本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除。
换一批
延伸阅读

为了满足日益增长的数据处理需求,铁威马NAS推出了全新的性能巅峰2024年旗舰之作F4-424 Pro,并搭载了最新的操作系统--TOS 6。这款高效办公神器的问世,无疑将为企业和专业人士带来前所未有的便捷与效率。

关键字: 存储 Linux 服务器

为增进大家对鼠标的认识,本文将对鼠标左键单击变双击的维修方法以及鼠标单击异常的解决方法予以介绍。

关键字: 鼠标 指数 驱动

往复泵是一种重要的流体输送设备,广泛应用于化工、石油、制药、冶金等领域。其工作原理基于活塞在泵缸内的往复运动,通过改变泵缸内的容积来实现液体的吸入和排出。本文将详细阐述往复泵的工作原理、结构特点、性能参数以及应用领域,以...

关键字: 往复泵 泵缸 设备

以下内容中,小编将对显卡驱动的相关内容进行着重介绍和阐述,希望本文能帮您增进对显卡驱动的了解,和小编一起来看看吧。

关键字: 显卡 驱动 显卡驱动

双系统将是下述内容的主要介绍对象,通过这篇文章,小编希望大家可以对双系统的相关情况以及信息有所认识和了解,详细内容如下。

关键字: 双系统 Windows Linux

液相色谱法是一种高效、快速的分离分析技术,广泛应用于化学、生物、医药等领域。液相色谱仪作为实现液相色谱分析的设备,具有高效、高分辨率、高灵敏度等特点。本文将详细介绍液相色谱仪的操作步骤、原理以及应用。

关键字: 液相色谱法 分离分析技术 设备

安装Linux操作系统并不复杂,下面是一个大致的步骤指南,以帮助您完成安装。1. 下载Linux发行版:首先,您需要从Linux发行版官方网站下载最新的ISO镜像文件。

关键字: Linux 操作系统 ISO镜像

计算机是由一堆硬件组成的,为了有限的控制这些硬件资源,于是就有了操作系统的产生,操作系统是软件子系统的一部分,是硬件基础上的第一层软件。

关键字: Linux 操作系统 计算机

漏电保护器是一种用于检测和切断漏电电流的设备,它对于保护人身安全和防止电气火灾具有重要作用。然而,在现实生活中,一些电工并不愿意安装漏电保护器,这背后有着多种原因。本文将探讨电工不愿意安装漏电保护的原因,并分析其背后的因...

关键字: 漏电保护器 检测 设备

Linux操作系统是一套免费使用和自由传播的类Unix操作系统,通常被称为GNU/Linux。它是由林纳斯·托瓦兹在1991年首次发布的,并基于POSIX和UNIX的多用户、多任务、支持多线程和多CPU的操作系统。Lin...

关键字: Linux 操作系统
关闭
关闭