linux内核总线驱动模型-驱动篇

tech2024-07-26  30

如果你了解了前面总线、设备模型,分析总线设备驱动模型的driver相对来说会轻松很多。开始也是看看其数据结构。

struct device_driver { const char *name; /*驱动的名字*/ struct bus_type *bus; /*驱动属于的总线类型*/ struct module *owner; const char *mod_name; /* used for built-in modules */ bool suppress_bind_attrs; /* disables bind/unbind via sysfs */ const struct of_device_id *of_match_table; const struct acpi_device_id *acpi_match_table; 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); const struct attribute_group **groups; const struct dev_pm_ops *pm; struct driver_private *p; };

与device类型相似,其中有一个指向driver_private的指针p,一些与其他的组件相关的联系都被移到这个结构变量中。不展开来看了,看完了关于驱动的一些重要的数据结构,那么开始重要的,如何向内核注册一个drv呢?我们使用driver_register。

int driver_register(struct device_driver *drv) { int ret; struct device_driver *other; BUG_ON(!drv->bus->p); if ((drv->bus->probe && drv->probe) || (drv->bus->remove && drv->remove) || (drv->bus->shutdown && drv->shutdown)) printk(KERN_WARNING "Driver '%s' needs updating - please use " "bus_type methods\n", drv->name); other = driver_find(drv->name, drv->bus); if (other) { printk(KERN_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; }

第6-19行,做一些必要的检查,并利用驱动的名字在bus的drv链表中查找是否已存在该驱动。接着,就进入这个函数的重点bus_add_driver,几乎注册所有的工作都是由它来完成。

/** * bus_add_driver - Add a driver to the bus. * @drv: driver. */ int bus_add_driver(struct device_driver *drv) { struct bus_type *bus; struct driver_private *priv; int error = 0; bus = bus_get(drv->bus); //增加总线的bus引用 if (!bus) return -EINVAL; pr_debug("bus: '%s': add driver %s\n", bus->name, drv->name); /*分别driver_private结构体空间,并进行初始化*/ 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);//将drv加入到sys中 if (error) goto out_unregister; /*将drv挂入到总线的链表中*/ klist_add_tail(&priv->knode_bus, &bus->p->klist_drivers); /*如果总线可以自动的probe,就会调用该匹配函数*/ if (drv->bus->p->drivers_autoprobe) { error = driver_attach(drv); if (error) goto out_unregister; } module_add_driver(drv->owner, drv); /*在drv目录下创建event属性文件*/ 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); kfree(drv->p); 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); } static int __driver_attach(struct device *dev, void *data) { struct device_driver *drv = data; /* * 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. */ if (!driver_match_device(drv, dev)) return 0; if (dev->parent) /* Needed for USB */ device_lock(dev->parent); device_lock(dev); if (!dev->driver) driver_probe_device(drv, dev); device_unlock(dev); if (dev->parent) device_unlock(dev->parent); 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; }

最终也是调用总线的match函数来完成设备与驱动的匹配的过程。

以上分析了总线、设备、驱动三种类型,主要是在注册上,其主要是在sysfs中创建目录和属性文件。在设备或者驱动注册到总线上,总线是如何为其找到对应的驱动的过程,下面一个图能很好的说明这一过程。

由图可以清楚的看出,bus的作用是向内核注册一条总线,并将drv一一加入到总线的drv链表,dev一一加入到总线的dev链表。当有设备或驱动注册的时候,在驱动或者设备链表一一取出,调用总线的match函数来完成匹配,匹配成功后调用总线的probe函数。

回顾下driver_register的作用,首先会将drv放入到bus得drv链表,从bus的dev链表取出每一个dev,用总线的match函数来判断能否支持drv

device_register的作用和driver一样,将dev放入到bus得dev链表,从bus的drv链表取出每一个drv,用总线的match函数来判断能否支持dev。

下面来看一个例子:

extern struct bus_type my_bus_type; static int my_probe(struct device *dev) { printk("Driver found device which my driver can handle!\n"); return 0; } static int my_remove(struct device *dev) { printk("Driver found device unpluged!\n"); return 0; } struct device_driver my_driver = { .name = "my_dev", .bus = &my_bus_type, .probe = my_probe, .remove = my_remove, }; /* * Export a simple attribute. */ static ssize_t mydriver_show(struct device_driver *driver, char *buf) { return sprintf(buf, "%s\n", "This is my driver!"); } static DRIVER_ATTR(drv, S_IRUGO, mydriver_show, NULL); static int __init my_driver_init(void) { int ret = 0; /*注册驱动*/ driver_register(&my_driver); /*创建属性文件*/ driver_create_file(&my_driver, &driver_attr_drv); return ret; } static void my_driver_exit(void) { driver_unregister(&my_driver); } module_init(my_driver_init); module_exit(my_driver_exit);
最新回复(0)