Linux设备模型提取了设备操作的共有属性,进行抽象,并将这部分抽象的共有属性在内核中实现,而为需要添加设备和驱动的操作提供了统一的接口,简化了驱动开发过程,只需要熟悉这些统一的接口就可以进行驱动开发;
目录
[TOC]
内核中有个用的比较多的驱动模型,platform平台总线模型,是一条虚拟的总线;在platform总线中,设备用platform_device表示,驱动用platform_driver表示;platform由内核统一管理,在驱动中使用资源,安全性和可移植性高;在硬件部分修改时,只需要修改硬件部分的设备platform_device代码,即可完成硬件适配;
总线、设备、驱动模型
graph TB
Bus(Bus)-->Dev(Dev)
Bus-->Drv(Drv)
Dev-->platform_device(platform_device)
Drv-->platform_driver(platform_driver)
Dev:指定硬件资源
Drv:
1)分配、设置、注册file_operations
2)根据Dev的硬件资源操作硬件
Drv:
probe,分配、设置、注册file_operations
2. 重要的结构体
struct bus_type
struct platform_device
struct platform_driver
platform_match函数用来比对Dev和Drv是否匹配,如果匹配成功,则调用Drv里的probe函数;
bus_type
1 2 3 4 5 6 7 8 9 10 11 12
| struct bus_type { const char *name; const char *dev_name; ...... int (*match)(struct device *dev, struct device_driver *drv); int (*uevent)(struct device *dev, struct kobj_uevent_env *env); int (*probe)(struct device *dev); int (*remove)(struct device *dev); void (*shutdown)(struct device *dev); ...... };
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| struct platform_device { const char *name; int id; bool id_auto; struct device dev; u32 num_resources; struct resource *resource;
const struct platform_device_id *id_entry; char *driver_override;
struct mfd_cell *mfd_cell;
struct pdev_archdata archdata; };
|
1 2 3 4 5 6 7 8 9 10 11
| 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; bool prevent_deferred_probe; };
|
1 2 3 4 5
| struct platform_device_id { char name[PLATFORM_NAME_SIZE]; kernel_ulong_t driver_data; };
|
id_table是一个数组,可以支持一个或多个设备名;数组的最后一个成员应该为空;
platform的初始化操作在内核启动时完成,不需要驱动开发者修改;
graph LR
do_basic_setup(do_basic_setup)-->
driver_init(driver_init)-->
platform_bus_init(platform_bus_init)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| int __init platform_bus_init(void) { int error;
early_platform_cleanup();
error = device_register(&platform_bus); if (error) return error; error = bus_register(&platform_bus_type); if (error) device_unregister(&platform_bus); of_platform_register_reconfig_notifier(); return error; }
|
bus_register()
可在sysfs下看到/sys/bus/platform;
1 2 3 4 5
| struct device platform_bus = { .init_name = "platform", }; EXPORT_SYMBOL_GPL(platform_bus);
|
1 2 3 4 5 6 7 8 9
| struct bus_type platform_bus_type = { .name = "platform", .dev_groups = platform_dev_groups, .match = platform_match, .uevent = platform_uevent, .pm = &platform_dev_pm_ops, }; EXPORT_SYMBOL_GPL(platform_bus_type);
|
1 2 3 4 5 6 7 8
| int platform_device_register(struct platform_device *pdev) { device_initialize(&pdev->dev); arch_setup_pdev_archdata(pdev); return platform_device_add(pdev); } EXPORT_SYMBOL_GPL(platform_device_register);
|
1 2 3 4 5 6 7
| void platform_device_unregister(struct platform_device *pdev) { platform_device_del(pdev); platform_device_put(pdev); } EXPORT_SYMBOL_GPL(platform_device_unregister);
|
1 2 3
| #define platform_driver_register(drv) \ __platform_driver_register(drv, THIS_MODULE)
|
1 2 3 4 5 6 7 8 9 10 11 12 13
| 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); } EXPORT_SYMBOL_GPL(__platform_driver_register);
|
1 2 3 4 5 6
| void platform_driver_unregister(struct platform_driver *drv) { driver_unregister(&drv->driver); } EXPORT_SYMBOL_GPL(platform_driver_unregister);
|
或者直接使用一个宏代替:
1 2 3 4
| #define module_platform_driver(__platform_driver) \ module_driver(__platform_driver, platform_driver_register, \ platform_driver_unregister)
|
1 2 3 4 5 6 7 8 9 10 11 12
| #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);
|
graph TB
bus_add_driver(bus_add_driver)-->
driver_attach(driver_attach)--bus_for_each_dev-->
__driver_attach(__driver_attach)-->
driver_match_device(driver_match_device)-->
bus_match(drv->bus->match)
__driver_attach-->driver_probe_device(driver_probe_device)-->
really_probe(really_probe)-->
dev_bus_probe(dev->bus->probe)
really_probe-->drv_probe(drv->probe)
5. match匹配
driver_match_device()函数中的drv->bus->match,就是指向platform_bus_type的match函数指针,即platform_match()函数,用来完成Dev和Drv的匹配;通过Dev中的name和Drv中的id_table->name进行匹配,匹配成功后就会调用Drv中的probe函数;
1
| int (*match)(struct device *dev, struct device_driver *drv);
|
platform_bus_type的match函数指针,被初始化指向platform_match()函数;
1 2 3 4 5 6
| struct bus_type platform_bus_type = { ...... .match = platform_match, ...... };
|
当一个新设备或新驱动添加到总线时,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 25
| 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);
if (pdev->driver_override) return !strcmp(pdev->driver_override, drv->name);
if (of_driver_match_device(dev, drv)) return 1;
if (acpi_driver_match_device(dev, drv)) return 1;
if (pdrv->id_table) return platform_match_id(pdrv->id_table, pdev) != NULL;
return (strcmp(pdev->name, drv->name) == 0); }
|
如果platform_driver中存在id_table,就通过platform_match_id()函数来比较id_table进行匹配;
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| static const struct platform_device_id *platform_match_id( const struct platform_device_id *id, struct platform_device *pdev) { while (id->name[0]) { if (strcmp(pdev->name, id->name) == 0) { pdev->id_entry = id; return id; } id++; } return NULL; }
|
如果platform_driver中有id_table,用platform_device中的const char *name和platform_driver中的id_table->name比较;
1
| strcmp(pdev->name, id->name);
|
如果platform_driver中没有id_table,用platform_device中的const char *name和platform_driver中的struct device_driver driver中的name比较;
1
| strcmp(pdev->name, drv->name);
|
优先比较id_table->name
其次比较struct device_driver driver中的name;
如果比较的两个name相同,match就匹配成功,就会调用driver中的probe函数;
6. probe
driver_probe_device()函数通过really_probe()函数,调用drv->bus->probe,就是指向platform_bus_type的probe函数指针,即platform_probe()函数,
graph TB
driver_probe_device(driver_probe_device)-->
really_probe(really_probe)-->
dev_bus_probe(dev->bus->probe)-->
platform_drv_probe(platform_drv_probe)-->
drv_probe(drv->probe)
really_probe-->drv_probe2(drv->probe)
1 2 3 4 5 6 7 8 9
| struct resource { resource_size_t start; resource_size_t end; const char *name; unsigned long flags; unsigned long desc; struct resource *parent, *sibling, *child; };
|
获取资源
1 2
| struct resource *platform_get_resource(struct platform_device *dev, unsigned int type, unsigned int num);
|
资源类型
1 2 3 4 5 6 7 8
| #define IORESOURCE_TYPE_BITS 0x00001f00 #define IORESOURCE_IO 0x00000100 #define IORESOURCE_MEM 0x00000200 #define IORESOURCE_REG 0x00000300 #define IORESOURCE_IRQ 0x00000400 #define IORESOURCE_DMA 0x00000800 #define IORESOURCE_BUS 0x00001000
|
用法
1 2 3
| struct platform_device *dev; struct resource *res; res = platform_get_resource(dev, IORESOURCE_MEM, 0);
|
8. 实例
1 2
| platform_device_register(); platform_device_unregister();
|
1 2
| platform_driver_register(); platform_driver_unregister();
|
1 2
| struct resource *res; res = platform_get_resource();
|
使用设备树
graph TB
Bus(Bus)-->Dts(DTS中构造节点)
Bus-->Drv(Drv)
Dev:在DTS中构造设备节点,指定硬件资源
Drv:
1)分配、设置、注册file_operations
2)根据Dev的硬件资源操作硬件
Drv:
probe,分配、设置、注册file_operations
dts–>dtb–>
内核解析dtb文件,得到device_node结构体,生成platform_device结构体,其中包含硬件资源,硬件资源来源于DTS文件;
设备树中节点的compatible,用来
reg是寄存器,和内存基本一样
1 2 3 4 5 6 7
| struct resource *res; res = platform_get_resource if (res) { led_pin = ; } else { of_property_read_s32(platform_device->dev.of_node, "pin", &ledpin); }
|
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 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);
if (pdev->driver_override) return !strcmp(pdev->driver_override, drv->name);
if (of_driver_match_device(dev, drv)) return 1;
if (acpi_driver_match_device(dev, drv)) return 1;
if (pdrv->id_table) return platform_match_id(pdrv->id_table, pdev) != NULL;
return (strcmp(pdev->name, drv->name) == 0); }
|
1 2 3 4 5
| 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; }
|
1 2 3 4 5 6
| struct device_driver { const char *name; struct bus_type *bus; ...... const struct of_device_id *of_match_table; };
|
1 2 3 4 5 6 7
| struct of_device_id { char name[32]; char type[32]; char compatible[128]; const void *data; };
|
1 2 3 4 5 6 7 8 9
| const struct of_device_id *of_match_device(const struct of_device_id *matches, const struct device *dev) { if ((!matches) || (!dev->of_node)) return NULL; return of_match_node(matches, dev->of_node); } EXPORT_SYMBOL(of_match_device);
|
1 2 3 4 5 6 7 8 9 10 11 12 13
| const struct of_device_id *of_match_node(const struct of_device_id *matches, const struct device_node *node) { const struct of_device_id *match; unsigned long flags;
raw_spin_lock_irqsave(&devtree_lock, flags); match = __of_match_node(matches, node); raw_spin_unlock_irqrestore(&devtree_lock, flags); return match; } EXPORT_SYMBOL(of_match_node);
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| const struct of_device_id *__of_match_node(const struct of_device_id *matches, const struct device_node *node) { const struct of_device_id *best_match = NULL; int score, best_score = 0;
if (!matches) return NULL;
for (; matches->name[0] || matches->type[0] || matches->compatible[0]; matches++) { score = __of_device_is_compatible(node, matches->compatible, matches->type, matches->name); if (score > best_score) { best_match = matches; best_score = score; } }
return best_match; }
|
设备树和驱动的匹配过程如下:
graph TB
of_driver_match_device(of_driver_match_device)-->
of_match_device(of_match_device)-->
of_match_node(of_match_node)-->
__of_match_node(__of_match_node)-->
__of_device_is_compatible(__of_device_is_compatible)
__of_device_is_compatible--compatible-->of_compat_cmp(of_compat_cmp)
__of_device_is_compatible--type-->of_compat_cmp
__of_device_is_compatible--name-->of_compat_cmp
of_compat_cmp-->
strcasecmp(strcasecmp)
__of_match_node()函数,把device_driver的of_match_table(struct of_device_id)和device里的of_node(struct device_node)进行匹配;
匹配方式是,在__of_device_is_compatible()函数里,分别调用of_compat_cmp()函数对两者的compatible、type、name字符串进行对比,compatible、type、name字符串要同时相同;一般情况下,name、type为空,只比较compatible字符串;比较compatible字符串时是比较整个字符串;这里的比较不是单纯的比较,是采用的加分制;
platform_device
struct device dev;
of_node
对于dts生成的platform_device,dev中含有of_node;
of_node中含有的属性,取决于设备树;比如:compatible、reg、pin属性;
compatible属性和of_match_table中的compatible进行比对;
优先比较:compatible,
参考资料
https://www.jianshu.com/p/6325f723509b
回到目录