0%

device和driver匹配过程分析

工作中编写驱动的时候,经常会使用到platform_driver_register向内核注册一个driver,使用platform_device_register向内核注册一个device,并且也会听到其他人说不管是driver先注册还是device先注册,内核都会去寻找对应的匹配项。本文就是针对platform device和platform driver的注册和匹配过程进行详细的分析,对注册和匹配的一些机制深入理解,方便对工作中驱动调试出现的一些问题快速的理清思路。

平台:ARM + IMX6UL Linux内核版本:4.1.15 代码阅读:Vscode

为什么需要platform device和platform driver?

首先需要知道的是不管是driver还是device,都是与bus有关的,platform_device和platform_driver都是platform bus下的两个接口(interface),而platform是一个伪总线也可以称之为虚拟总线,platform是用来解决如下问题:真实世界的 Linux 设备和驱动程序通常需要挂在总线上,对于挂在PCI、USB、I2C、SPI上的设备来说自然不是问题,但是在嵌入式系统中,SOC系统中集成了独立的外设控制器,SOC内存空间的外设不包含在这个class bus中。基于此背景,Linux 发明了一种称为平台总线的虚拟总线。如SOC 系统中集成的独立外部单元(I2C、LCD、SPI、RTC 等)被视为平台设备。 从Linux2.6开始引入一套新的驱动管理和注册机制:platform_device和platform_driver。大多数Linux都可以使用这种机制,设备用platform_Device表示;驱动程序注册到 platform_Driver。

platform_driver注册流程分析

先看看platform_driver的表示形式:

1
2
3
4
5
6
7
8
9
10
11
//include\linux\platform_device.h
struct platform_driver {
int (*probe)(struct platform_device *);
int (*remove)(struct platform_device *);
void (*shutdown)(struct platform_device *);
int (*suspend)(struct platform_device *, pm_message_t state);
int (*resume)(struct platform_device *);
struct device_driver driver;
const struct platform_device_id *id_table;//idtable用来匹配的
bool prevent_deferred_probe;
};

驱动开发时,使用platform_driver_register向linux内核注册一个驱动,platform_driver_register会调用__platform_driver_register

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//drivers\base\platform.c
int __platform_driver_register(struct platform_driver *drv,
struct module *owner)
{
drv->driver.owner = owner;
drv->driver.bus = &platform_bus_type;// 设置driver的bus的类型为platform_bus_type
if (drv->probe) // 如果drv含有probe(device_driver类型)则driver上的probe指向总线的probe函数
drv->driver.probe = platform_drv_probe;
if (drv->remove)
drv->driver.remove = platform_drv_remove;
if (drv->shutdown)
drv->driver.shutdown = platform_drv_shutdown;

//调用driver_register函数将驱动添加到总线的drv链表
return driver_register(&drv->driver);
}

__platform_driver_register里首先会设置driver的bus类型为platform_bus_type,然后判断platform_driver是否实现了probe函数,如果实现了,那么用platform_driver的driver里的probe指向bus的probe函数,最后调用driver_register将driver添加到bus的driver链表。继续往下走,看driver_register的实现。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
//drivers\base\driver.c
int driver_register(struct device_driver *drv)
{
int ret;
struct device_driver *other;

BUG_ON(!drv->bus->p);

if ((drv->bus->probe && drv->probe) ||
(drv->bus->remove && drv->remove) ||
(drv->bus->shutdown && drv->shutdown))
printk(KERN_WARNING "Driver '%s' needs updating - please use "
"bus_type methods\n", drv->name);

//查找是否此driver是否已经注册过了?
other = driver_find(drv->name, drv->bus);
if (other) {
printk(KERN_ERR "Error: Driver '%s' is already registered, "
"aborting...\n", drv->name);
return -EBUSY;
}

//添加driver到bus的drv链表上
ret = bus_add_driver(drv);
if (ret)
return ret;
ret = driver_add_groups(drv, drv->groups);
if (ret) {
bus_remove_driver(drv);
return ret;
}
kobject_uevent(&drv->p->kobj, KOBJ_ADD);

return ret;
}

在driver_register里,首先会调用driver_find在bus上根据driver name查找是否已有driver注册,如果没有注册的话就调用bus_add_driver把driver添加到bus的driver链表上。我们看看bus_add_driver的实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
//drivers\base\bus.c
int bus_add_driver(struct device_driver *drv)
{
struct bus_type *bus;
struct driver_private *priv;
int error = 0;

//获取总线类型
bus = bus_get(drv->bus);
if (!bus)
return -EINVAL;

pr_debug("bus: '%s': add driver %s\n", bus->name, drv->name);

priv = kzalloc(sizeof(*priv), GFP_KERNEL);
if (!priv) {
error = -ENOMEM;
goto out_put_bus;
}
klist_init(&priv->klist_devices, NULL, NULL);
priv->driver = drv;
drv->p = priv;
priv->kobj.kset = bus->p->drivers_kset;
//将drv加入sysfs
error = kobject_init_and_add(&priv->kobj, &driver_ktype, NULL,
"%s", drv->name);
if (error)
goto out_unregister;

//将drv挂入到总线的链表中
klist_add_tail(&priv->knode_bus, &bus->p->klist_drivers);
if (drv->bus->p->drivers_autoprobe) {
//如果总线可以自动的probe,就会调用匹配函数
error = driver_attach(drv);
if (error)
goto out_unregister;
}
//创建driver相关的模块
module_add_driver(drv->owner, drv);

error = driver_create_file(drv, &driver_attr_uevent);
if (error) {
printk(KERN_ERR "%s: uevent attr (%s) failed\n",
__func__, drv->name);
}
error = driver_add_groups(drv, bus->drv_groups);
if (error) {
/* How the hell do we get out of this pickle? Give up */
printk(KERN_ERR "%s: driver_create_groups(%s) failed\n",
__func__, drv->name);
}

if (!drv->suppress_bind_attrs) {
error = add_bind_files(drv);
if (error) {
/* Ditto */
printk(KERN_ERR "%s: add_bind_files(%s) failed\n",
__func__, drv->name);
}
}

return 0;

out_unregister:
kobject_put(&priv->kobj);
kfree(drv->p);
drv->p = NULL;
out_put_bus:
bus_put(bus);
return error;
}

在bus_add_driver函数里,我们首先调用bus_get获取driver所在的bus类型,然后为该driver的private data分配内存。不妨看看driver_private的定义:

1
2
3
4
5
6
7
8
//drivers\base\base.h
struct driver_private {
struct kobject kobj;//在sysfs中代表目录本身
struct klist klist_devices;// 管理的设备列表,列表里的设备都是匹配本驱动的
struct klist_node knode_bus;// 一个knode节点,会连接到所属的bus的driver列表上(bus挂接点,用于将自身挂接到对应bus(每个driver只属于一条总线))
struct module_kobject *mkobj;// driver与相关的module之间的联系
struct device_driver *driver;//driver实体本身
};

分配完driver_private内存之后,由于一个driver可能对应着多个设备,因此在driver_private里就用一个链表来挂载所有的devic,那就调用klist_init来初始化klist_devices,然后让要操作的driver的drivate_private指向刚分配的priv,然后再调用kobject_init_and_add把driver加入到sysfs里。接下来继续调用klist_add_tail把driver挂到bus的链表上,knode_bus就是挂载点,klist_drivers就是bus下挂的多个driver。然后判断driver所在的bus是否支持autoprobe,这个autoprobe在bus init的时候会默认设置为1,具体可见bus_register,那就可以调用driver_attach来把driver绑定到device。

1
2
3
4
int driver_attach(struct device_driver *drv)
{
return bus_for_each_dev(drv->bus, NULL, drv, __driver_attach);
}

在driver_attach函数里,调用bus_for_each_dev对bus上的driver,如果有相应匹配的device,就调用__driver_attach来进行绑定。我们还是先看看bus_for_each_dev函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
int bus_for_each_dev(struct bus_type *bus, struct device *start,
void *data, int (*fn)(struct device *, void *))
{
struct klist_iter i;
struct device *dev;
int error = 0;

if (!bus || !bus->p)
return -EINVAL;

klist_iter_init_node(&bus->p->klist_devices, &i,
(start ? &start->p->knode_bus : NULL));
while ((dev = next_device(&i)) && !error)// 遍历总线dev链表中的所有设备
error = fn(dev, data);// 判断驱动与设备是否匹配,若匹配则将二者绑定
klist_iter_exit(&i);
return error;
}

bus_for_each_dev函数里,我们遍历总线devices链表(klist_devices)中的所有device,判断driver与device是否匹配,如果匹配日就调用__driver_attach进行绑定。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
static int __driver_attach(struct device *dev, void *data)
{
struct device_driver *drv = data;

/*
* Lock device and try to bind to it. We drop the error
* here and always return 0, because we need to keep trying
* to bind to devices and some drivers will return an error
* simply if it didn't support the device.
*
* driver_probe_device() will spit a warning if there
* is an error.
*/

// 调用bus的match函数对设备和驱动进行匹配,若匹配driver_match_device函数的返回值为1,则程序立即返回,若匹配则继续向下执行
if (!driver_match_device(drv, dev))
return 0;

if (dev->parent) /* Needed for USB */
device_lock(dev->parent);
device_lock(dev);
if (!dev->driver)
driver_probe_device(drv, dev);// 若设备和驱动匹配且设备的驱动程序为空,则将该驱动程序绑定到该设备(调用驱动程序的probe函数)
device_unlock(dev);
if (dev->parent)
device_unlock(dev->parent);

return 0;
}

__driver_attach里,调用driver_match_device把driver和device进行匹配。

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

可以看到driver_match_device的实现就是看driver所在的bus是否有match函数,如果有,就调用bus所在的match函数进行匹配,我们之前已经讲过了在__platform_driver_register函数里,我们先drv->driver.bus = &platform_bus_type,也就是说driver所在的bus为platform_bus。

1
2
3
4
5
6
7
struct bus_type platform_bus_type = {
.name = "platform",
.dev_groups = platform_dev_groups,
.match = platform_match,
.uevent = platform_uevent,
.pm = &platform_dev_pm_ops,
};

platform_bus_type默认的match函数为platform_match,我们看看其实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
static int platform_match(struct device *dev, struct device_driver *drv)
{
struct platform_device *pdev = to_platform_device(dev);
struct platform_driver *pdrv = to_platform_driver(drv);

//设备完全可以自由地宣布她喜欢的第三者driver,哪怕这个第三者driver和她本身完全没有任何的匹配因子,操作的 //入口就是driver_override sysfs文件
if (pdev->driver_override)
return !strcmp(pdev->driver_override, drv->name);

/* Attempt an OF style match first */
if (of_driver_match_device(dev, drv))
return 1;

/* Then try ACPI style match */
if (acpi_driver_match_device(dev, drv))
return 1;

/* Then try to match against the id table */
if (pdrv->id_table)
return platform_match_id(pdrv->id_table, pdev) != NULL;

/* fall-back to driver name match */
return (strcmp(pdev->name, drv->name) == 0);
}

我们的需求是调用driver_match_device看driver所在的bus上是否有匹配的device。在platform_match函数里,有四种匹配的方式,优先级最高的是利用设备树里的compatible字段与驱动里的name字段进行匹配,如果匹配成功就返回。

1
2
3
4
5
6
//include\linux\of_device.h
static inline int of_driver_match_device(struct device *dev,
const struct device_driver *drv)
{
return of_match_device(drv->of_match_table, dev) != NULL;
}

可以看出of_driver_match_device其实就是把设备树里的compatible字段和驱动里的of_match_table里的.compatible字段进行匹配,以IMX6UL 的SPI驱动为例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
//drivers\spi\spi-imx.c
......
static const struct of_device_id spi_imx_dt_ids[] = {
{ .compatible = "fsl,imx1-cspi", .data = &imx1_cspi_devtype_data, },
{ .compatible = "fsl,imx21-cspi", .data = &imx21_cspi_devtype_data, },
{ .compatible = "fsl,imx27-cspi", .data = &imx27_cspi_devtype_data, },
{ .compatible = "fsl,imx31-cspi", .data = &imx31_cspi_devtype_data, },
{ .compatible = "fsl,imx35-cspi", .data = &imx35_cspi_devtype_data, },
{ .compatible = "fsl,imx51-ecspi", .data = &imx51_ecspi_devtype_data, },
{ .compatible = "fsl,imx6ul-ecspi", .data = &imx6ul_ecspi_devtype_data, },
{ /* sentinel */ }
};
......
static struct platform_driver spi_imx_driver = {
.driver = {
.name = DRIVER_NAME,
.of_match_table = spi_imx_dt_ids,
.pm = IMX_SPI_PM,
},
.id_table = spi_imx_devtype,
.probe = spi_imx_probe,
.remove = spi_imx_remove,
};
......
1
2
3
4
5
6
7
8
9
10
11
12
13
14
//arch\arm\boot\dts\imx6ul.dtsi
ecspi1: ecspi@02008000 {
#address-cells = <1>;
#size-cells = <0>;
compatible = "fsl,imx6ul-ecspi", "fsl,imx51-ecspi";
reg = <0x02008000 0x4000>;
interrupts = <GIC_SPI 31 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&clks IMX6UL_CLK_ECSPI1>,
<&clks IMX6UL_CLK_ECSPI1>;
clock-names = "ipg", "per";
dmas = <&sdma 3 7 1>, <&sdma 4 7 2>;
dma-names = "rx", "tx";
status = "disabled";
};

由上面IMX6UL的驱动和DTS文件不难看出,DTS里ecspi的compatible属性值是fsl,imx6ul-ecspi,驱动在调用platform_driver_register进行注册的时候会首先使用of_match_table来进行匹配,匹配成功就调用probe函数。如果OF style方式匹配不成功,就调用acpi_driver_match_device来进行匹配(没接触过这种匹配方式,暂不分析)。如果acpi_driver_match_device失败的话,就使用驱动里定义的id_table方式,也就是说设备的名字出现在驱动的ID表中,id_table的匹配方式可以简化成如下代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
static const struct platform_device_id xxx_ids[] = {
{
.name = "id_table matchxxxxx",
},
{}
};
MODULE_DEVICE_TABLE(platform, xxx_ids);


static struct platform_driver xxx_driver = {
.driver = {
.name = "xxx",
.owner = THIS_MODULE,
},
.id_table = xxx_ids,
.probe = xxx_probe,
.remove = xxx_remove,
};

那么platform_match_id就是利用strcmp(pdev->name, id->name)简单的比较驱动id_table里的.name字段与device的name字段,如果相同,则匹配成功。最后一种匹配方式很简单粗暴,直接把driver name和device name进行匹配,匹配成功就返回。
所以驱动和设备匹配的四种方式按照优先级排列如下:

  • 不讲理的方式,利用driver_override(工作中没用到)
  • OF STYLE:即利用设备树的cimpatiable字段
  • ACPI
  • id_table方式比较
  • 直接比较driver name和device name

好了好了,我们回到__driver_attach函数里,当匹配成功的时候返回1,然后判断如果要绑定到的device下面的driver是否为空(一个device只能有一个driver),如果为空那么就调用driver_probe_device把device和driver绑定到一起。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
int driver_probe_device(struct device_driver *drv, struct device *dev)
{
int ret = 0;

if (!device_is_registered(dev))
return -ENODEV;

pr_debug("bus: '%s': %s: matched device %s with driver %s\n",
drv->bus->name, __func__, dev_name(dev), drv->name);

pm_runtime_barrier(dev);
ret = really_probe(dev, drv);
pm_request_idle(dev);

return ret;
}

driver_probe_device里具体的绑定动作是在really_probe里进行的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
static int really_probe(struct device *dev, struct device_driver *drv)
{
int ret = 0;
int local_trigger_count = atomic_read(&deferred_trigger_count);

atomic_inc(&probe_count);
pr_debug("bus: '%s': %s: probing driver %s with device %s\n",
drv->bus->name, __func__, drv->name, dev_name(dev));
WARN_ON(!list_empty(&dev->devres_head));

//把待绑定的driver挂到device的driver上
dev->driver = drv;

/* If using pinctrl, bind pins now before probing */
ret = pinctrl_bind_pins(dev);
if (ret)
goto probe_failed;
//drivers_sysfs_add()负责创建sysfs中driver和device指向对方的软链接
if (driver_sysfs_add(dev)) {
printk(KERN_ERR "%s: driver_sysfs_add(%s) failed\n",
__func__, dev_name(dev));
goto probe_failed;
}

if (dev->pm_domain && dev->pm_domain->activate) {
ret = dev->pm_domain->activate(dev);
if (ret)
goto probe_failed;
}

if (dev->bus->probe) {//如果device attachd的bus本身就有probe函数,那么就调用device的probe函数
ret = dev->bus->probe(dev);
if (ret)
goto probe_failed;
} else if (drv->probe) {//如果device没有probe函数,那么就调用driver的probe函数
ret = drv->probe(dev);
if (ret)
goto probe_failed;
}

if (dev->pm_domain && dev->pm_domain->sync)
dev->pm_domain->sync(dev);

driver_bound(dev); //将device加入驱动的设备链表。
ret = 1;
pr_debug("bus: '%s': %s: bound device %s to driver %s\n",
drv->bus->name, __func__, dev_name(dev), drv->name);
goto done;

probe_failed:
devres_release_all(dev);
driver_sysfs_remove(dev);
dev->driver = NULL;
dev_set_drvdata(dev, NULL);
if (dev->pm_domain && dev->pm_domain->dismiss)
dev->pm_domain->dismiss(dev);

switch (ret) {
case -EPROBE_DEFER:
/* Driver requested deferred probing */
dev_dbg(dev, "Driver %s requests probe deferral\n", drv->name);
driver_deferred_probe_add(dev);
/* Did a trigger occur while probing? Need to re-trigger if yes */
if (local_trigger_count != atomic_read(&deferred_trigger_count))
driver_deferred_probe_trigger();
break;
case -ENODEV:
case -ENXIO:
pr_debug("%s: probe of %s rejects match %d\n",
drv->name, dev_name(dev), ret);
break;
default:
/* driver matched but the probe failed */
printk(KERN_WARNING
"%s: probe of %s failed with error %d\n",
drv->name, dev_name(dev), ret);
}
/*
* Ignore errors returned by ->probe so that the next driver can try
* its luck.
*/
ret = 0;
done:
atomic_dec(&probe_count);
wake_up(&probe_waitqueue);
return ret;
}

really_probe里,会判断dev->bus->probe是否为空,也就是判断device attach上的bus是否有probe函数,如果有就调用device的probe函数。如果没有,那就调用platform_driver.driver的probe函数,我们在__platform_driver_register已经把platform_driver.driver绑定到了platform_drv_probe

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
static int platform_drv_probe(struct device *_dev)
{
struct platform_driver *drv = to_platform_driver(_dev->driver);
struct platform_device *dev = to_platform_device(_dev);
int ret;

ret = of_clk_set_defaults(_dev->of_node, false);
if (ret < 0)
return ret;

ret = dev_pm_domain_attach(_dev, true);
if (ret != -EPROBE_DEFER) {
ret = drv->probe(dev);// 此处间接地调用了platform_driver提供的probe函数,如果是imx6ul,就调用相应的platform_driver
if (ret)
dev_pm_domain_detach(_dev, true);
}

if (drv->prevent_deferred_probe && ret == -EPROBE_DEFER) {
dev_warn(_dev, "probe deferral not supported\n");
ret = -ENXIO;
}

return ret;
}

platform_drv_probe函数里,间接地调用了platform_driver提供的probe函数,如果是IMX6UL,就调用相应的platform_driver,还是以IMX6UL SPI为例:

1
2
3
4
5
6
7
8
9
10
static struct platform_driver spi_imx_driver = {
.driver = {
.name = DRIVER_NAME,
.of_match_table = spi_imx_dt_ids,
.pm = IMX_SPI_PM,
},
.id_table = spi_imx_devtype,
.probe = spi_imx_probe,
.remove = spi_imx_remove,
};

really_probe里就会调用IMX的spi_imx_probe进行SPI配置的一些工作。好了,probe分析完毕,继续分析really_probe,具体的绑定动作在driver_bound函数里进行,我们看看其实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
static void driver_bound(struct device *dev)
{
if (klist_node_attached(&dev->p->knode_driver)) {//判断是否已经绑定
printk(KERN_WARNING "%s: device %s already bound\n",
__func__, kobject_name(&dev->kobj));
return;
}

pr_debug("driver: '%s': %s: bound to device '%s'\n", dev->driver->name,
__func__, dev_name(dev));

//将device添加到driver的链表上
klist_add_tail(&dev->p->knode_driver, &dev->driver->p->klist_devices);

/*
* Make sure the device is no longer in one of the deferred lists and
* kick off retrying all pending devices
*/
driver_deferred_probe_del(dev);
driver_deferred_probe_trigger();

if (dev->bus)
blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
BUS_NOTIFY_BOUND_DRIVER, dev);
}

driver_bound函数里,我们首先调用klist_node_attached判断device上是否已经绑定有driver了。如果没有,就调用klist_add_tail把device添加到driver的klist_devices链表上,至此就完成了platform_driver的注册流程,接下来分析platform_device的注册流程。

platform_device注册流程分析

首先看看platform_device的定义:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
struct platform_device {
const char *name;// 设备的名字,这个名字会代替device->dev_id,用作sys/device下显示的目录名
int id;// 设备id,用于给插入给该总线并且具有相同name的设备编号,如果只有一个设备的话填-1
bool id_auto;
struct device dev;// 内嵌device结构
u32 num_resources;// 资源的数目
struct resource *resource; // 资源

const struct platform_device_id *id_entry;
char *driver_override; /* Driver name to force a match */

/* MFD cell pointer */
struct mfd_cell *mfd_cell;

/* arch specific additions */
struct pdev_archdata archdata;
};

platform_device的注册调用platform_device_register实现,具体的注册工作在platform_device_add里进行。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
int platform_device_add_data(struct platform_device *pdev, const void *data,
size_t size)
{
void *d = NULL;

if (data) {
d = kmemdup(data, size, GFP_KERNEL);
if (!d)
return -ENOMEM;
}

kfree(pdev->dev.platform_data);
pdev->dev.platform_data = d;
return 0;
}
EXPORT_SYMBOL_GPL(platform_device_add_data);

/**
* platform_device_add - add a platform device to device hierarchy
* @pdev: platform device we're adding
*
* This is part 2 of platform_device_register(), though may be called
* separately _iff_ pdev was allocated by platform_device_alloc().
*/
int platform_device_add(struct platform_device *pdev)
{
int i, ret;

if (!pdev)
return -EINVAL;

if (!pdev->dev.parent)
pdev->dev.parent = &platform_bus;

pdev->dev.bus = &platform_bus_type;

switch (pdev->id) {
default:
dev_set_name(&pdev->dev, "%s.%d", pdev->name, pdev->id);
break;
case PLATFORM_DEVID_NONE:
dev_set_name(&pdev->dev, "%s", pdev->name);
break;
case PLATFORM_DEVID_AUTO:
/*
* Automatically allocated device ID. We mark it as such so
* that we remember it must be freed, and we append a suffix
* to avoid namespace collision with explicit IDs.
*/
ret = ida_simple_get(&platform_devid_ida, 0, 0, GFP_KERNEL);
if (ret < 0)
goto err_out;
pdev->id = ret;
pdev->id_auto = true;
dev_set_name(&pdev->dev, "%s.%d.auto", pdev->name, pdev->id);
break;
}

for (i = 0; i < pdev->num_resources; i++) {//获取资源
struct resource *p, *r = &pdev->resource[i];

if (r->name == NULL)
r->name = dev_name(&pdev->dev);

p = r->parent;
if (!p) {//设置资源类型
if (resource_type(r) == IORESOURCE_MEM)
p = &iomem_resource;
else if (resource_type(r) == IORESOURCE_IO)
p = &ioport_resource;
}

if (p && insert_resource(p, r)) {
dev_err(&pdev->dev, "failed to claim resource %d\n", i);
ret = -EBUSY;
goto failed;
}
}

pr_debug("Registering platform device '%s'. Parent at %s\n",
dev_name(&pdev->dev), dev_name(pdev->dev.parent));

ret = device_add(&pdev->dev);
if (ret == 0)
return ret;

failed:
if (pdev->id_auto) {
ida_simple_remove(&platform_devid_ida, pdev->id);
pdev->id = PLATFORM_DEVID_AUTO;
}

while (--i >= 0) {
struct resource *r = &pdev->resource[i];
if (r->parent)
release_resource(r);
}

err_out:
return ret;
}

首先把device所在的bus设置为platform_bus_type,然后为其设置名字(pdev->id是在platform_device_alloc里初始化的),platform device生成的时候,对于DTS里相同bus的node,使用id来对其进行编号,如果bus下只有一个device,那么id就为-1。接下来就是获取资源和设置资源类型,比如IO资源还是MEM资源。最后调用device_add把device添加到device hierarchy。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
int device_add(struct device *dev)
{
struct device *parent = NULL;
struct kobject *kobj;
struct class_interface *class_intf;
int error = -EINVAL;

dev = get_device(dev);//增加device的引用计数
if (!dev)
goto done;

if (!dev->p) {
error = device_private_init(dev);//初始化device的私有成员p
if (error)
goto done;
}

/*
* for statically allocated devices, which should all be converted
* some day, we need to initialize the name. We prevent reading back
* the name, and force the use of dev_name()
*/
if (dev->init_name) {
dev_set_name(dev, "%s", dev->init_name);//初始化device内部的kobject
dev->init_name = NULL;
}

/* subsystems can specify simple device enumeration */
if (!dev_name(dev) && dev->bus && dev->bus->dev_name)//如果bus存在,使用bus以及设备id来初始化设备内部kobject名字
dev_set_name(dev, "%s%u", dev->bus->dev_name, dev->id);

if (!dev_name(dev)) {//获得设备的名字

error = -EINVAL;
goto name_error;
}

pr_debug("device: '%s': %s\n", dev_name(dev), __func__);

parent = get_device(dev->parent);//增加device parent device引用计数
kobj = get_device_parent(dev, parent);
if (kobj)
dev->kobj.parent = kobj;//在kobject层实现设备父子关系

/* use parent numa_node */
if (parent)
set_dev_node(dev, dev_to_node(parent));

/* first, register with generic layer. */
/* we require the name to be set before, and pass NULL */
error = kobject_add(&dev->kobj, dev->kobj.parent, NULL);//将设备加入到kobject模型中,创建sys相关目录
if (error)
goto Error;

/* notify platform of device entry */
if (platform_notify)
platform_notify(dev);

error = device_create_file(dev, &dev_attr_uevent);//创建sys目录下设备的uevent属性文件,通过它可以查看设备的uevent事件
if (error)
goto attrError;

error = device_add_class_symlinks(dev);//dev与class创建软链接
if (error)
goto SymlinkError;
error = device_add_attrs(dev);//创建sys目录下设备其他属性文件,即添加device/type/class定义的属性集合
if (error)
goto AttrsError;
error = bus_add_device(dev);//将设备加入到管理它的bus总线的设备连表上
if (error)
goto BusError;
error = dpm_sysfs_add(dev);//电源管理相关
if (error)
goto DPMError;
device_pm_add(dev);

if (MAJOR(dev->devt)) {
error = device_create_file(dev, &dev_attr_dev);//如果没有设备号,就创建dev属性
if (error)
goto DevAttrError;

error = device_create_sys_dev_entry(dev);//创建软链接
if (error)
goto SysEntryError;

devtmpfs_create_node(dev);//在dev下创建设备文件
}

/* Notify clients of device addition. This call must come
* after dpm_sysfs_add() and before kobject_uevent().
*/
if (dev->bus)
blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
BUS_NOTIFY_ADD_DEVICE, dev);//通知注册监听该总线的设备,有新设备加入

kobject_uevent(&dev->kobj, KOBJ_ADD);//产生一个内核uevent事件,该事件可以被内核以及应用层捕获,属于linux设备模型中热插拔机制
// 为总线上的设备寻找驱动
bus_probe_device(dev);
if (parent)
klist_add_tail(&dev->p->knode_parent,
&parent->p->klist_children);

if (dev->class) {
mutex_lock(&dev->class->p->mutex);
/* tie the class to the device */
klist_add_tail(&dev->knode_class,
&dev->class->p->klist_devices);//将设备挂接在其设备class上面

/* notify any interfaces that the device is here */
list_for_each_entry(class_intf,
&dev->class->p->interfaces, node)
if (class_intf->add_dev)
class_intf->add_dev(dev, class_intf);//通知有新设备加入
mutex_unlock(&dev->class->p->mutex);
}
......
}

device_add函数里,为bus上的device寻找驱动的函数是bus_probe_device,我们看看其实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
void bus_probe_device(struct device *dev)
{
struct bus_type *bus = dev->bus;
struct subsys_interface *sif;
int ret;

if (!bus)
return;
//bus_type里的drivers_autoprobe默认为1,即开启自动probe
if (bus->p->drivers_autoprobe) {
ret = device_attach(dev);
WARN_ON(ret < 0);
}

mutex_lock(&bus->p->mutex);
list_for_each_entry(sif, &bus->p->interfaces, node)
if (sif->add_dev)
sif->add_dev(dev, sif);
mutex_unlock(&bus->p->mutex);
}

类似platform_driver,platform_device调用了device_attach来进行device和driver的绑定。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
int device_attach(struct device *dev)
{
int ret = 0;

device_lock(dev);
if (dev->driver) {
if (klist_node_attached(&dev->p->knode_driver)) {
ret = 1;
goto out_unlock;
}
ret = device_bind_driver(dev);
if (ret == 0)
ret = 1;
else {
dev->driver = NULL;
ret = 0;
}
} else {
ret = bus_for_each_drv(dev->bus, NULL, dev, __device_attach);// 遍历bus的drv链表为设备寻找驱动
pm_request_idle(dev);
}
out_unlock:
device_unlock(dev);
return ret;
}

device_attach可以看到,首先判断该device下是否有driver,如果已经有了driver,则调用device_bind_driver进行绑定。否则,就调用bus_for_each_drv,遍历bus上的klist_drivers链表,查找是否有匹配的driver,如果有,则调用__device_attach进行绑定。先看看bus_for_each_drv

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
int bus_for_each_drv(struct bus_type *bus, struct device_driver *start,
void *data, int (*fn)(struct device_driver *, void *))
{
struct klist_iter i;
struct device_driver *drv;
int error = 0;

if (!bus)
return -EINVAL;

klist_iter_init_node(&bus->p->klist_drivers, &i,
start ? &start->p->knode_bus : NULL);
while ((drv = next_driver(&i)) && !error)// 遍历整个drv链表
error = fn(drv, data);// 寻找该设备匹配的驱动程序,若匹配则将二者绑定
klist_iter_exit(&i);
return error;
}

可以看出bus_for_each_drv和bus_for_each_dev很类似,都是遍历整个链表,如果有匹配项,就调用相应的回调函数进行绑定。接下来我们看看具体的绑定函数__device_attach

1
2
3
4
5
6
7
8
9
static int __device_attach(struct device_driver *drv, void *data)
{
struct device *dev = data;
// 调用bus的match函数对设备和驱动进行匹配,若不匹配driver_match_device函数的返回值为1,则程序立即返回,若匹配则继续向下执行
if (!driver_match_device(drv, dev))
return 0;

return driver_probe_device(drv, dev);// 若设备和驱动匹配,则将该驱动程序绑定到该设备
}

哈哈,__device_attach首先会调用driver_match_device函数进行匹配,这个匹配函数我们在分析platform_driver注册流程时已经分析过了。如果在相应的bus下找到了device的driver,那么就调用driver_probe_device进行绑定工作,driver_probe_device相关分析可以参考platform_driver的注册流程分析,此处不再赘述。

总结

分析了platform_driver和platform_device的详细注册流程之后,我们总结一下整个注册过程中重要的函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
platform_driver_register
--->driver_register
--->driver_find
--->bus_add_driver
--->klist_init
--->kobject_init_and_add
--->klist_add_tail
--->driver_attach
--->bus_for_each_dev
--->klist_iter_init_node
--->fn(具体的绑定函数)
--->__driver_attach
--->driver_match_device
--->platform_bus_type.match
--->driver_probe_device
--->really_probe
--->driver_bound
1
2
3
4
5
6
7
8
9
10
11
platform_device_register
--->platform_device_add
--->device_add
--->bus_probe_device
--->device_attach
--->bus_for_each_drv
--->__device_attach
--->driver_match_device
--->driver_probe_device
--->really_probe
--->driver_bound

综上所述,不管是platform_driver还是platform_device向内核注册的时候,都会在bus上去寻找对方,如果匹配就调用相应的probe函数,并且把彼此绑定。