前言
平时写驱动或者看一份驱动代码的时候,经常被各种注册接口函数搞晕,到底什么时候用哪一个呢?这个问题必须要在理解了Linux的设备模型后才能有个清晰的概念,本文只是在阅读了网上一些大神的博客后的一些小小的总结。不过本文暂时不会对Linux的设备模型有过多的深入,只是在自己的理解上,理清一下注册接口之间的关系。
正文
先来看一下我们在驱动开发过程中,最常接触到的两个结构体。
1、device和device_driver
这两个结构体是驱动开发的基础,顾名思义,device就是设备的抽象,device_driver就是驱动的抽象。结构体都比较复杂,但是好在注释比较清晰,具体可以参考:include\linux\device.h。驱动开发中接触最多的就是怎么使用这些接口,所以我们先看一下这些使用步骤。
下面以hid总线(bus)、uhid设备(device)、hid-generic驱动(device_driver)为例子,讲述一下流程,代码目录为:drivers\hid\。
1.1、bus
因为这一小节重点讲device和device_driver,所以bus的概念我们先放一边。注册hid总线的代码在:drivers\hid\hid-core.c
1.2、device
分配一个struct device类型的变量,填充必要的信息后,把它注册到内核中。
代码目录:
drivers\hid\uhid.c
函数调用关系:
uhid_char_open //分配了uhid_device结构体,其中就包含了struct device
->uhid_device_add_worker
->hid_add_device
->device_add //这个函数就是将分配到的device注册到内核中,并在这个过程中匹配合适的device_driver
->bus_probe_device //注册进总线
->device_attach
->__device_attach
->driver_match_device //最终会调用driver的match函数
1.3、device_driver
分配一个struct device_driver类型的变量,填充必要的信息后,把它注册到内核中
代码目录:
drivers\hid\hid-generic.c
函数调用关系:
module_hid_driver //分配的struct hid_driver就包含了struct device_driver
->__hid_register_driver
->driver_register
->bus_add_driver //将driver加到bus上
->driver_attach //匹配对应的device
1.4、小结
所以我们可以看到,注册device用的device_add接口(或者device_register、device_create_vargs和device_create,不过它们最终都是调用device_add);注册device_driver用的driver_register接口。不过实际开发中,除了直接用device和device_driver,也会用,在这两个结构体封装上的其他结构体,比如下一小节要讲的内容。
2、platform_device和platform_driver
系统中,每个设备都需要连接到一个bus上,这个bus可以是一个实际存在的内部bus、虚拟的bus或者是platform bus。这一小节我们主要关注platform bus。
那么连接到platform bus的platform device又有哪些呢?kernel在platform.txt中有相关的定义,总的来说就是,platform device包括:基于端口的设备(已不推荐使用,保留下来只为兼容旧设备,legacy);连接物理总线的桥设备;集成在SOC上的各种控制器;连接在其他bus上的设备等等。
platform bus基于底层的bus模块,抽象出来的一个虚拟的platform bus,用于platform设备的连接;platform device基于底层的device模块,用于表示platform设备;platform driver基于底层的driver模块,用于驱动platform设备。
其实从platform device和platform driver两个结构体的定义就可以看出,他们是和struct device和struct device_driver有着千丝万缕的关系。具体的定义可以参考:include\linux\platform_device.h。下面我们只是看一下怎么用系统提供的API。
2.1、struct platform_device
代码路径:
drivers\base\platform.c
函数调用关系:
platform_device_register
->platform_device_add
->device_add
从函数调用关系来看,最终还是走到了device_add,也进一步说明platform_device是在device上的一层封装而已。还有其它的注册接口可以参考include\linux\platform_device.h
2.2、struct platform_driver
代码路径:
linux\platform_device.h
函数调用关系:
platform_driver_register
->__platform_driver_register
->driver_register //类似于platform_device,最终也是调用到注册device_driver的函数
2.3、platform bus
想注册device和driver,当然需要有对应的bus,而platform bus的注册在drivers\base\platform.c的platform_bus_init实现。细节就不过多说了,有兴趣的同学可以自行查阅代码。
2.4、小结
上面只是提到了一些API,具体的驱动代码例子可以参考我以前写的文章:设备、驱动、总线模型简介。