标签:
之前接触到的字符设备驱动是非常单纯的Linux字符设备驱动,他不具备工程中Linux驱动中的设备与驱动分离思想和设备驱动的分层思想,不具备“总线-设备-驱动”模型的概念。接下来通过分析platform设备驱动模型的搭建过程来看看Linux的设备驱动模型究竟是怎样的?
platform驱动模型搭建:(1)platform核心层:为设备层和驱动层提供注册接口、为设备层和驱动层的匹配提供标准
①搭建总线框架:struct bus_type { const char *name; struct bus_attribute *bus_attrs; struct device_attribute *dev_attrs; struct driver_attribute *drv_attrs; 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); int (*suspend)(struct device *dev, pm_message_t state); int (*suspend_late)(struct device *dev, pm_message_t state); int (*resume_early)(struct device *dev); int (*resume)(struct device *dev); struct dev_pm_ops *pm; struct bus_type_private *p; //看到这个private就有点C++类中的限定域关键字了,这个类的私有成员 };总线类实例化:platform总线
struct bus_type platform_bus_type = { .name = "platform", .dev_attrs = platform_dev_attrs, .match = platform_match, //关键成员 .uevent = platform_uevent, .pm = PLATFORM_PM_OPS_PTR, };注册platform总线过程:
platform_bus_init() { ..... error = bus_register(&platform_bus_type);//注册platform总线的核心工作 ..... } bus_register(struct bus_type *bus) { //创建bus的属性文件 retval = bus_create_file(bus, &bus_attr_uevent); ...... //在/sys/bus/bus->name目录下创建devices目录 priv->devices_kset = kset_create_and_add("devices", NULL,&priv->subsys.kobj); .... //在/sys/bus/bus->name目录下创建drivers目录 priv->drivers_kset = kset_create_and_add("drivers", NULL,&priv->subsys.kobj); //初始化总线设备\总线驱动链表 klist_init(&priv->klist_devices, klist_devices_get, klist_devices_put); klist_init(&priv->klist_drivers, NULL, NULL); }核心层的功绩:初始化了klist_devices和klist_drivers两个链表,没有谈到如何判断设备和驱动匹配?“.match=platform_match”有初始化,但是什么时候被调用?
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); /* match against the id table first */ if (pdrv->id_table) //看看drv的id_table中是否有现成匹配的设备记录 return platform_match_id(pdrv->id_table, pdev) != NULL; /* fall-back to driver name match */ return (strcmp(pdev->name, drv->name) == 0); /* match成功,strcmp返回0,语句逻辑返回1 */ }②为设备层提供注册API、提供自动匹配接口函数
struct device { struct device *parent; struct device_private *p; struct kobject kobj; const char *init_name; /* initial name of the device 这个就是传统的bus_id,具体到每一个设备之后当做默认值 */ struct device_type *type; ...... struct bus_type *bus; /* type of bus device is on */ struct device_driver *driver; /* which driver has allocated this device */ void *driver_data; /* data private to the driver */ void *platform_data; /* Platform specific data, device core doesn't touch it */ ...... void (*release)(struct device *dev); };派生类:platform设备
struct platform_device { const char *name; int id; // 硬件设备的象征/代表 struct device dev; // 由此继承基类 u32 num_resources; struct resource * resource;//这个驱动使用的资源 struct platform_device_id *id_entry; };注册platform设备函数调用关系:
platform_device_add(struct platform_device *pdev)
pdev->dev.bus = &platform_bus_type;
device_add(&pdev->dev);
bus_attach_device(struct device *dev)
device_attach(dev);
bus_for_each_drv()函数的实现:bus_for_each_drv(dev->bus, NULL, dev, __device_attach);
bus_for_each_drv(struct bus_type *bus, struct device_driver *start, void *data, int (*fn)(struct device_driver *, void *)) { ...... while ((drv = next_driver(&i)) && !error) error = fn(drv, data); ...... }分析:
__device_attach(struct device_driver *drv, void *data) { struct device *dev = data; if (!driver_match_device(drv, dev)) return 0; return driver_probe_device(drv, dev); //match成功就执行这个函数,他最终调用really_probe()函数 } driver_match_device(struct device_driver *drv,struct device *dev) { return drv->bus->match ? drv->bus->match(dev, drv) : 1; //看到这一句,上面留下的疑问就解决了:原来核心层留下的匹配判断标准match接口就是在这里被调用的!!!好爽!^_^ } really_probe(struct device *dev, struct device_driver *drv) { ...... if (dev->bus->probe) //如果bus_type结构里边的probe成员有定义就优先调用他的 { ret = dev->bus->probe(dev); if (ret) goto probe_failed; } else if (drv->probe) //没有就调用匹配到的drv结构里边的probe成员函数 { ret = drv->probe(dev); if (ret) goto probe_failed; } driver_bound(dev);//bound是绑定的意思,即将match成功的设备加入驱动的设备链表 ...... }③为驱动层提供API、提供自动匹配接口函数
struct device_driver { const char *name; struct bus_type *bus; struct module *owner; const char *mod_name; /* used for built-in modules */ int (*probe) (struct device *dev); int (*remove) (struct device *dev); void (*shutdown) (struct device *dev); int (*suspend) (struct device *dev, pm_message_t state); int (*resume) (struct device *dev); struct attribute_group **groups; struct dev_pm_ops *pm; struct driver_private *p; };驱动派生类:
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 (*suspend_late)(struct platform_device *, pm_message_t state); int (*resume_early)(struct platform_device *); int (*resume)(struct platform_device *); struct device_driver driver; //继承基类 struct platform_device_id *id_table; };注册platform_driver驱动结构体函数执行流程:
platform_driver_register(struct platform_driver *drv) { /*下面进行一系列的判断,如果派生的platform_driver中没有对特有成员进行初始化,设置成默认的 */ drv->driver.bus = &platform_bus_type; //指向这个驱动所属的bus类型:platform if (drv->probe) //有重定向 drv->driver.probe = platform_drv_probe; if (drv->remove) //有重定向 drv->driver.remove = platform_drv_remove; ...... return driver_register(&drv->driver); 【进入分析】 //注册的关键材料是platform_driver->driver->bus:关键是为了注册总线的类型platform_bus_type } driver_register(struct device_driver *drv) { ...... struct device_driver *other; ...... other = driver_find(drv->name, drv->bus); //在该总线上查找是否有该设备驱动名对应的驱动 if (other) { //如果设备已经存在对应的驱动就:出错,驱动已经存在 put_driver(other); printk(KERN_ERR "Error: Driver '%s' is already registered, " "aborting...\n", drv->name); return -EEXIST; } bus_add_driver(drv); /* 在总线上添加这个驱动,成功的话最终结果:在bus/platform/drivers目录下面生成“name”对应的目录 ,并且会生成 bind module uevent unbind 四个文件*/ ...... }继续深入分析:
driver_attach(drv); /* 试图将驱动和设备绑定起来 */
bus_for_each_dev(drv->bus, NULL, drv, __driver_attach);//到这里可以非常明显的发现和设备层做的事情非常相似,几乎是对称出现
/* 对总线上的每一个设备都会拿来执行__driver_attach,他在这里被用作回调函数,看看是否匹配,这个函数和__device_attach函数做的事情基本一样这里就不再累述了*/
2.通过platform_device_register()把这个结构体链入核心层的klist_devices链表
标签:
原文地址:http://blog.csdn.net/clb1609158506/article/details/45153067