使用哪个引脚,怎么操作引脚,都写死在代码中。最简单,不考虑扩展性,可以快速实现功能。但是修改引脚时,需要重新编译。
利用面向对象的设计思想,对驱动进行分层、分离等操作,将驱动整体依据通用性上下分层,上层注册驱动,下层实现硬件操作,如图所示
这样我们在更换硬件时,只需要更改board_xxx.c函数即可,提高了代码的复用性,而在下层的硬件操作中,我们可以再做细分,将硬件资源与引脚选取、初始化进行“分离”这一操作,如图所示
图中led_resource实现led资源的定义,board_xxx实现引脚的选用,chip_gpio实现了对led资源的init和ctrl函数
这里直接构建了一个总的device结构体platform_device,把整个板子上所有的硬件资源和初始化模板都塞进去,构建成一个庞大又臃肿的资源结合体。
struct bus_type platform_bus_type = {
.name = "platform",
.dev_groups = platform_dev_groups,
.match = platform_match, //bind platform device to platform driver.
.uevent = platform_uevent,
.dma_configure = platform_dma_configure,
.pm = &platform_dev_pm_ops,
};
这个结构体里面有个platform_match
成员,在外部有该成员函数的定义,负责为BUS比较Device和Driver是否匹配,在注册驱动时,整个driver_match_device(drv, dev)
函数把platform_match(drv, dev)
塞进去,比较的顺序如下。
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);
}
总体的递归调用流程就是这样的,一层一层的追溯到最底层就是一个probe
int platform_device_register(struct platform_device *pdev)
platform_device_add(pdev);
device_add(&pdev->dev); //struct device
error = bus_add_device(dev); //放入链表
bus_probe_device(dev); //probe drivers for a new device
device_initial_probe(dev);
__device_attach(dev, true);
bus_for_each_drv(dev->bus, NULL, &data,__device_attach_driver); //在drv链表中, bus_type->subsys_private->klist_drivers
__device_attach_driver //attempt to bind device & driver together. struct device_driver和struct device
driver_match_device(drv, dev); //查看drv和dev是否匹配,drv->bus->match ? drv->bus->match(dev, drv) : 1;在这里会调用bus里面的match函数,指向了platform_match
driver_probe_device(drv, dev); //attempt to bind device & driver together,调用drv的probe函数
really_probe(dev, drv);
dev->driver = drv; //dev里面的driver = drv。将两者联系起来了。
dev->bus->probe(dev); //在platform_bus_type中没有定义probe函数,所以会调用drv->probe(dev)函数
//或者
drv->probe(dev);
platform_driver_register(drv)
int __platform_driver_register(struct platform_driver *drv, struct module *owner)
drv->driver.owner = owner;
drv->driver.bus = &platform_bus_type;
drv->driver.probe = platform_drv_probe;
drv->driver.remove = platform_drv_remove;
drv->driver.shutdown = platform_drv_shutdown;
driver_register(&drv->driver); //register driver with bus
bus_add_driver(drv); //放入链表,这种bus type的驱动列表
driver_attach(drv); //try to bind driver to devices.
bus_for_each_dev(drv->bus, NULL, drv, __driver_attach);
__driver_attach
driver_match_device(drv, dev); //查看drv和dev是否匹配,drv->bus->match ? drv->bus->match(dev, drv) : 1;在这里会调用bus里面的match函数,指向了platform_match
device_driver_attach(drv, dev); //attach a specific driver to a specific device
driver_probe_device(drv, dev);
really_probe(dev, drv);
dev->driver = drv; //dev里面的driver = drv。将两者联系起来了。
dev->bus->probe(dev); //在platform_bus_type中没有定义probe函数,所以会调用drv->probe(dev)函数
//或者
drv->probe(dev);
注册/注销
platform_device_register/ platform_device_unregister
platform_driver_register/ platform_driver_unregister
platform_add_devices // 注册多个 device
查询函数
返回该 dev 中某类型(type)资源中的第 n 个
struct resource *platform_get_resource(struct platform_device *dev, unsigned int type,unsigned int n)
返回该 dev 所用的第 n 个中断
int platform_get_irq(struct platform_device *dev, unsigned int n)
通过名字(name)返回该 dev 的某类型(type)资源
struct resource *platform_get_resource_byname(struct platform_device *dev, unsigned int type, const char *name)
通过名字(name)返回该 dev 的中断号
int platform_get_irq_byname(struct platform_device *dev, const char *name)