linux kernel之platform driver&device

在驱动程序的模型分层有一层总线基础层(PCI总线,I2C总线,USB总线等),总线层对应实际上的总线,然而,对于嵌入式开发领域而言,有很多SOC芯片内置了各种外设,并比如LCDUARTaudio、摄像头口等等,并没有总线。

为了统一驱动架构抽象,所以引入了platform bus这个虚拟的总线模型

本文简要介绍一下platform driver&device怎么工作的,主要是如何发现并注册设备(probe)。

在系统上电后,start_kernel() -> rest_init() -> kernel_init() -> kernel_init_freeable() -> do_basic_setup() -> driver_init() -> platform_bus_init()

platform_bus_init()就是初始化虚拟的总线模型:

Linux/init/main.c

 

 

 

Linux/drivers/base/init.c

Linux/drivers/base/platform.c

944行注册第一个总线设备platform_bus,我们来看看device_register()做了些什么。

Linux/drivers/base/core.c

这里将dev的kobj.kset设置为devices_kset, 将dev的kobj.ktype设置为device_ktype.

其中,devices_kset在driver_init() -> devices_init()时初始化。

Kset是挂载sysfs文件系统下的,这部分不在本文范畴,请参考sysfs&kobject文章。

这里简单说明一下:

devices_kset关联目录/sys/devices

dev_kobj关联目录/sys/dev

sysfs_dev_block_jobj关联目录/sys/block

sysfs_dev_char_kobj关联目录/sys/char

 

linux/lib/kobject.c

 

我们接着看device_register().

再调用device_initialize()初始化dev后,调用device_add(dev)。我们来看看device_add()的实现。

Linux/drivers/base/core.c

990行给device分配private内存。

1001行设置dev->kobj->name,这里这只为platform.

1027行,向系统注册(新增加)kobject。这个kobject对应的目录platform在哪呢?

kobject_add() -> kobject_add_varg() -> kobject_add_internal()

linux/lib/kobject.c

我们的platform device的parent是空,故219行将parent设置为kobj->kset->kobj, 即devices_kset,然后229行创建该dev->kobj对用的目录,即在/sys/devices/下创建platform目录。

1035行,device_file_create() 定义在 linux/drivers/base/core.c

Linux/include/linux/sysfs.h

Linux/fs/sysfs/file.c

我们的platform device的kobject设置了ktype为device_ktype(在device_initialize()), 这个device_ktype定义了show&store.

Linux/drivers/base/core.c

所以在__kernfs_create_file()中首先在当前platform device kobject对应的目录下创建kn文件attr->name, 同时将kn-attr->ops设置为sysfs_file_kfops_rw.

这个attr为1035行的dev_attr_uevent. 下面是它的定义:

Linux/drivers/base/core.c

Linux/include/linux/device.h

Linux/include/linux/sysfs.h

故,1035行在/sys/devices/platform/目录下创建了kernfs文件uevent.

1040行,如果当前的设备的主设备号不为0,则还将创建dev文件。(platfor_bus无设备号(虚拟设备),故不创建这个dev文件)。

1057行,bus_add_device()如果又bus_type,则将当前device添加到bus_type的device list中, 同时还将创建bus_type有关文件。

Linux/drivers/base/bus.c

1073行,bus_probe_device()查找deivce关联的platform driver,通过bus_type->probe()间接调用platform driver的probe函数(对于MAC设备,就是会去创建net_device)

Linux/drivers/base/bus.c

Linux/drivers/base/dd.c

Linux/drivers/base/bus.c

Linux/drivers/base/dd.c

所以当platform_driver已经注册了,当前设备关联这个platform_driver,则会出发这个platform_driver的probe()调用。

到此,device_register()基本结束,我们回到platform_bus_init()。

Linux/drivers/base/platform.c

接下去就是947行bus_register(),即注册platform_bus_type。

Linux/drivers/base/bus.c

首先分配bus_type的private内存(877行), 然后设置bus_type的kobj->name为platform(886行), kobj.kset为bus_kset, kobj.ktype为bus_ktype(890&891行),接着调用kset_register()注册kobj, 注册kobj会创建目录platform,该目录在bus_kset对应的目录下。bus_kset定义在linux/drivers/base/bus.c中

从上述代码snip中可见,bus_kset对应目录/sys/bus/

所以894行会在/sys/bus/目录下创建目录platform.

898-909行,会在/sys/bus/platform/目录下创建文件uevent,创建目录devices, drivers。

最后919行,清空bus_type的klist_drivers, 表示当前bus_type上没有任何的platform_driver注册。

Platform device的注册通过platform_device_register()来进行。

Platform driver的注册通过module_platform_driver() -> platform_driver_register() -> __platform_driver_register() 来进行。

Linux/include/linux/platform_device.h

我们先来看platform_device_register()。

Linux/drivers/base/platform.c

Linux/drivers/base/core.c

首先调用device_initialize()将platform_device的dev->kobj.kset设置为devices_kset, dev->kboj.ktype设置为device_ktype,即当platform_device没有设置parent时,这个devices_kset就是它的parent.

之后调用platform_device_add().

Linux/drivers/base/platform.c

platform_device_add首先将platform device的parent设置为platform_bus,即platform device的kobj对应的目录都在platform_bus的kobj对应的目录/sys/devices/platform/下。

且设置platform device的bus_type为platform_bus_type(kobj对应目录/sys/bus/platform/), 之后调用device_add(dev)注册设备到bus_type的klist_devices上。如果这个bus_type(platform_bus_type)已经又platform driver注册了,则会调用platform driver的probe()函数,这一部分,之前的已经介绍过了,跳过。

 

我们来看另外一个函数: __platform_driver_register ()

Linux/drivers/base/platform.c

__platform_driver_register()设置platform driver的bus_type为platform_bus_type(kobj对应目录/sys/bus/platform/), 设置device_driver的probe为platform_drv_probe(), 还设置了remove, shutdown,最后调用driver_register()注册device_driver.

Linux/drivers/base/driver.c

Driver_register检查bus_type的drivers_kset中所有注册的platform_driver是否存在当前请求注册的platform driver(比较的是name),检查通过后,调用bus_add_driver()注册。

Linux/drivers/base/bus.c

Bus_add_driver首先给driver申请private内存,然后通过kobject_init_and_add()在/sys/bus/platform/下创建platform_driver的name对应的目录(684 & 685行),并在690行将请求的platform_driver添加到bus_type的klist_drivers上。

691行,如果bus_type的drivers_autoprobe是enable的,则条用driver_attach去将bus_type上的platform_device  attach上,具体过程就是调用match函数匹配,匹配通过后,最终调用platform_driver的probe()函数。

 

下图是关于bus_type, platform_driver, platform_device的关系描述:(下面更新于2021.04.21,对于嵌入式系统中各总线和platform总线之间的关系,有一些新的认识,摘录于下面的ppt截图)

 

 

https://www.cnblogs.com/embInn/p/13034307.html

 

 

 

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值