赞
踩
做Linux做么多年,虽然说看了很多,还没有写过这边方便的博客,今天接学习的机会,来记录下同时复习下
关于linux设备驱动模型应该有很多文章和博客已经记录和阐述了,至于为什么linux要设计这么一个设备驱动的软件架构,可以看看宋宝华老师的《Linux驱动设备开发详解》第十二章
设备驱动模型有三个重要组件,分别是总线(bus type)、设备(device)和驱动(driver)
在不使用设备驱动模型是,一个外设的驱动在特定的CPU上运行需要一套特定的驱动,那么在多个不同的CPU上就需要多个驱动,按照这种逻辑,N个同类型的外设在M个不同的CPU上就需要N*M份驱动,这种是典型的强耦合,不符合软件工程的基本原则,引用宋宝华老师书上的图片如下
使用了设备驱动模型后只需要N+M个驱动
典型的设备驱动模型有platform设备驱动、i2c/spi驱动、块设备、input设备、tty、usb等诸多设备驱动,下面我们具体分析从platform驱动设备来理清bus、driver、device之前的关系
汇编代码.S文件调用
kernel-5.10/init/main.c start_kernel ---->arch_call_rest_init----->rest_init---->kernel_init ---->kernel_init_freeable ---->do_basic_setup ---->driver_init ---->platform_bus_init---->bus_register
struct bus_type platform_bus_type = { .name = "platform", .dev_groups = platform_dev_groups, .match = platform_match, .uevent = platform_uevent, .dma_configure = platform_dma_configure, .pm = &platform_dev_pm_ops, }; struct bus_type { const char *name; const char *dev_name; struct device *dev_root; const struct attribute_group **bus_groups; const struct attribute_group **dev_groups; const struct attribute_group **drv_groups; int (*match)(struct device *dev, struct device_driver *drv); int (*uevent)(struct device *dev, struct kobj_uevent_env *env); int (*probe)(struct device *dev); void (*sync_state)(struct device *dev); int (*remove)(struct device *dev); void (*shutdown)(struct device *dev); int (*online)(struct device *dev); int (*offline)(struct device *dev); int (*suspend)(struct device *dev, pm_message_t state); int (*resume)(struct device *dev); int (*num_vf)(struct device *dev); int (*dma_configure)(struct device *dev); const struct dev_pm_ops *pm; const struct iommu_ops *iommu_ops; struct subsys_private *p; struct lock_class_key lock_key; bool need_parent_lock; ANDROID_KABI_RESERVE(1); ANDROID_KABI_RESERVE(2); ANDROID_KABI_RESERVE(3); ANDROID_KABI_RESERVE(4); }; 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); }
上面是bus_register时注册的platform_bus_type,其中需要注意的是.match函数,当挂在platform总线上的driver和device匹配时会调用,会根据of_match_table、acpi、id_table、drv_name来匹配,至于bus_register函数中的其他调用有兴趣的可以自行去了解kobject/kset,这里不再赘述
相关也可以看看博客linux驱动 平台设备驱动模型,我看看写的比较详细,注意这篇博客的kernel版本和我的不一样,我这是kernel5.10
这里已display中的panel注册为例
static struct mipi_dsi_driver panel_simple_dsi_driver = { .driver = { .name = "panel-simple-dsi", .of_match_table = dsi_of_match, }, .probe = panel_simple_dsi_probe, .remove = panel_simple_dsi_remove, .shutdown = panel_simple_dsi_shutdown, }; static int __init panel_simple_init(void) { int err; //注册platform设备 err = platform_driver_register(&panel_simple_platform_driver); if (err < 0) return err; if (IS_ENABLED(CONFIG_DRM_MIPI_DSI)) { err = mipi_dsi_driver_register(&panel_simple_dsi_driver); if (err < 0) return err; } return 0; } module_init(panel_simple_init);
在kernel开始运行时会调用运行.init.text代码段的函数,而运行module_init宏定义的内容,关于module_init、late_initcall、subsys_init等可以查看kernel-5.10/include/linux/module.h、init.h
platform_driver_register
#define platform_driver_register(drv) \ __platform_driver_register(drv, THIS_MODULE) 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; return driver_register(&drv->driver); } int driver_register(struct device_driver *drv) { int ret; struct device_driver *other; if (!drv->bus->p) { pr_err("Driver '%s' was unable to register with bus_type '%s' because the bus was not initialized.\n", drv->name, drv->bus->name); return -EINVAL; } if ((drv->bus->probe && drv->probe) || (drv->bus->remove && drv->remove) || (drv->bus->shutdown && drv->shutdown)) pr_warn("Driver '%s' needs updating - please use " "bus_type methods\n", drv->name); //检查driver是否已经注册在bus上 other = driver_find(drv->name, drv->bus); if (other) { pr_err("Error: Driver '%s' is already registered, " "aborting...\n", drv->name); return -EBUSY; } //这个函数下面分析 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; } EXPORT_SYMBOL_GPL(driver_register); 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; error = kobject_init_and_add(&priv->kobj, &driver_ktype, NULL, "%s", drv->name); if (error) goto out_unregister; //将knode_bus加入到bus的klist_drivers链表中 klist_add_tail(&priv->knode_bus, &bus->p->klist_drivers); if (drv->bus->p->drivers_autoprobe) { //调用bus中的match函数 error = driver_attach(drv); if (error) goto out_unregister; } 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); /* drv->p is freed in driver_release() */ drv->p = NULL; out_put_bus: bus_put(bus); return error; } int driver_attach(struct device_driver *drv) { return bus_for_each_dev(drv->bus, NULL, drv, __driver_attach); } EXPORT_SYMBOL_GPL(driver_attach); static int __driver_attach(struct device *dev, void *data) { struct device_driver *drv = data; int ret; /* * 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_type中的match函数 ret = driver_match_device(drv, dev); if (ret == 0) { /* no match */ return 0; } else if (ret == -EPROBE_DEFER) { dev_dbg(dev, "Device match requests probe deferral\n"); driver_deferred_probe_add(dev); } else if (ret < 0) { dev_dbg(dev, "Bus failed to match device: %d\n", ret); return ret; } /* ret > 0 means positive match */ if (driver_allows_async_probing(drv)) { /* * Instead of probing the device synchronously we will * probe it asynchronously to allow for more parallelism. * * We only take the device lock here in order to guarantee * that the dev->driver and async_driver fields are protected */ dev_dbg(dev, "probing driver %s asynchronously\n", drv->name); device_lock(dev); if (!dev->driver) { get_device(dev); dev->p->async_driver = drv; async_schedule_dev(__driver_attach_async_helper, dev); } device_unlock(dev); return 0; } //driver和device匹配完成,调用driver中的probe函数完成注册 device_driver_attach(drv, dev); return 0; } static inline int driver_match_device(struct device_driver *drv, struct device *dev) { return drv->bus->match ? drv->bus->match(dev, drv) : 1; }
在kernel未引入dts之前和引入dts之后的device注册时不同的
具体可参考platform_device的生成过程
总之引入设备驱动模型后,隔离了bsp和驱动,使得驱动有更好的可扩展性和跨平台性,另外一个驱动可以支持多个设备
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。