内核版本:linux-4.19.63
Allwinner H3 SPI驱动为例:
spi-sun6i.c
static struct platform_driver sun6i_spi_driver = {
.probe = sun6i_spi_probe,
.remove = sun6i_spi_remove,
.driver = {
.name = "sun6i-spi",
.of_match_table = sun6i_spi_match,
.pm = &sun6i_spi_pm_ops,
},
};
module_platform_driver(sun6i_spi_driver);
module_platform_driver 是一个宏,展开来看:
#define platform_driver_register(drv) \
__platform_driver_register(drv, THIS_MODULE)
extern void platform_driver_unregister(struct platform_driver *);
#define module_platform_driver(__platform_driver) \
module_driver(__platform_driver, platform_driver_register, \
platform_driver_unregister)
#define module_driver(__driver, __register, __unregister, ...) \
static int __init __driver##_init(void) \
{ \
return __register(&(__driver) , ##__VA_ARGS__); \
} \
module_init(__driver##_init); \
static void __exit __driver##_exit(void) \
{ \
__unregister(&(__driver) , ##__VA_ARGS__); \
} \
module_exit(__driver##_exit);
其实module_platform_driver(xxx) 简化了代码;就是填充了 module_init ,module_exit 代码
直接看平台驱动注册函数:
/**
* __platform_driver_register - register a driver for platform-level devices
* @drv: platform driver structure
* @owner: owning module/driver
*/
int __platform_driver_register(struct platform_driver *drv,
struct module *owner)
{
drv->driver.owner = owner;
drv->driver.bus = &platform_bus_type; //bus 类型为 platform_bus_type
drv->driver.probe = platform_drv_probe;
drv->driver.remove = platform_drv_remove;
drv->driver.shutdown = platform_drv_shutdown;
return driver_register(&drv->driver); //往下会调用总线的match函数匹配成功后调用 platform_drv_probe
platform_drv_probe
xxx_probe //最终调用具体实现的probe 如:sun6i_spi_probe
}
其实就是在 platform_bus 上注册了一个 driver 。
linux 下的驱动框架是总线、驱动、设备。驱动只有在有对应的设备的时候才会调用probe函数。另外总线也是要注册的。
问题1:platform_bus 总线是何时注册的?
问题2:platform_device 是何时注册的?
1:platform_bus 总线是何时注册的?
platform_bus_type
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 注册过程:内核启动时调用了do_basic_setup() 最终 bus_register(&platform_bus_type);
do_basic_setup(); //内核启动时会调用
driver_init();
platform_bus_init();
bus_register(&platform_bus_type); //注册总线
priv->subsys.kobj.kset = bus_kset;
priv->subsys.kobj.ktype = &bus_ktype;
priv->drivers_autoprobe = 1; //总是为1
2:platform_device 是何时注册的?
platform device 的注册:
#define __define_initcall(fn, id) \
static initcall_t __initcall_##fn##id __used \
__attribute__((__section__(".initcall" #id ".init"))) = fn;
#define arch_initcall_sync(fn) __define_initcall(fn, 3s)
arch_initcall_sync(of_platform_default_populate_init); //内核启动时由do_initcalls 调用
of_platform_default_populate_init
of_platform_default_populate
of_platform_populate
dev = of_platform_device_create_pdata(bus, bus_id, platform_data, parent);
if (!of_device_is_available(np) ||
of_node_test_and_set_flag(np, OF_POPULATED))
return NULL; // of_device_is_available 里判断dts设备节点的status是否等于"okay"
dev = of_device_alloc(np, bus_id, parent);
dev->dev.bus = &platform_bus_type; //bus 类型为 platform_bus_type
dev->dev.platform_data = platform_data;
of_device_add(dev)
return device_add(&ofdev->dev);
内核启动时会解析设备树文件,将各设备节点(status = “okay” 的节点)注册到platform总线下。
问题3:设备与驱动如何匹配?
driver_register 和 device_add 这两个函数最终都会试图去调用 bus 里的match函数。
在平台设备里就是platform_match
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);
/* When driver_override is set, only bind to the matching driver */
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);
}
of_driver_match_device
of_match_device
of_match_node
__of_match_node(matches, node);
__of_device_is_compatible
static int __of_device_is_compatible(const struct device_node *device,
const char *compat, const char *type, const char *name)
{
struct property *prop;
const char *cp;
int index = 0, score = 0;
/* Compatible match has highest priority */
if (compat && compat[0]) {
prop = __of_find_property(device, "compatible", NULL); //一般通过比较compatible来进行匹配
for (cp = of_prop_next_string(prop, NULL); cp;
cp = of_prop_next_string(prop, cp), index++) {
if (of_compat_cmp(cp, compat, strlen(compat)) == 0) {
score = INT_MAX/2 - (index << 2);
break;
}
}
if (!score)
return 0;
}
/* Matching type is better than matching name */
if (type && type[0]) {
if (!device->type || of_node_cmp(type, device->type))
return 0;
score += 2;
}
/* Matching name is a bit better than not */
if (name && name[0]) {
if (!device->name || of_node_cmp(name, device->name))
return 0;
score++;
}
return score;
}
可以看出优先是使用compatible来进行匹配的。
问题5:匹配成功后做了什么?
match函数匹配成功会后调用platform_bus里的 platform_drv_probe,最终调用driver里的 probe,以sun6i_spi 为例就是 sun6i_spi_probe
sun6i_spi_probe
master = spi_alloc_master(&pdev->dev, sizeof(struct sun6i_spi));
master->set_cs = sun6i_spi_set_cs;
master->transfer_one = sun6i_spi_transfer_one;
devm_spi_register_master(&pdev->dev, master)
devm_spi_register_controller
spi_register_controller
of_register_spi_devices
for_each_available_child_of_node
of_register_spi_device
spi_alloc_device
of_modalias_node
of_spi_parse_dt
spi_add_device(spi);
spi_dev_set_name(spi);
spi_setup(spi);
device_add(&spi->dev);
总结梳理:
linux 下平台驱动一般流程是
1.注册总线(bus)
2.注册设备(device)
3.注册驱动(driver)
4.设备与匹配成功后,调用 probe