备驱动程序 使计算机系统可以与设备进行通信的一个软件组。在大多数情况下,驱动程序也会对硬件进行操作以便将数据传送给设备。有些设备,尤其是 PC 兼容机上的一些视频示配器,在系统中没有安装正确的设备驱动程序时,这些设备将无法正常工作.
首先还是看一下其结构:
struct device_driver { const char *name; //名字 struct bus_type *bus;//其所在的bus struct module *owner;//表示实现设备驱动程序的模块 const char *mod_name; //模块名 bool suppress_bind_attrs; /* disables bind/unbind via sysfs */ #if defined(CONFIG_OF) const struct of_device_id *of_match_table; #endif 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;//私有属性 };
struct driver_private { struct kobject kobj;//代表driver自身 struct klist klist_devices;//可以操控的设备链表 struct klist_node knode_bus;//挂接到bus的节点 struct module_kobject *mkobj; //模块相关 struct device_driver *driver; //回指该driver };driver_private存放kob相关的数据
结构中有五个回调函数,这五个回调函数用于处理热插拔、即插即用和电源管理。 当总线设备驱动程序发现一个可能有它处理的设备时就会调用probe方法,相应的函数将会探测硬件,从而对该设备进行更进一步的检查。如果该device_driver对象的pribe()方法的返回值是一个负数,那就意味这该驱动不能邦定到此设备上,那么就要释放所有为该device_driver对象分配的资源。 当移走一个可热插拔的设备时驱动程序会调用remove方法,而驱动程序本身被卸载时,它所处理的每个设备也会调用remove方法。
当内核必须更改设备的供电状态时,设备驱动会调用shutdown、suspend和resume三个方法。其中shutdown方法会停止对设备供电。suspend方法是将设备切换到低功耗状态,此方法中的state参数即要设置的状态,pm_message_t被定义在linux/include/linux/pm.h中,
typedef struct pm_message {
int event;
}pm_message_t;
可取的状态有:
#define PM_EVENT_ON 0
/*驱动器恢复工作,开始相应硬盘和软件请求*/
#define PM_EVENT_FREEZE 1
/*停止对设备的操作以便保存一致的映象,但是不能再进入低功耗状态,也不能发出唤醒事件*/
#define PM_EVENT_SUSPEND 2 /*为即将到来的系统状态进入低功耗状态,在适当的时候可以唤醒*/
#define PM_EVENT_PRETHAW 3 /*为系统从一个较早的PM_EVENT_FREEZE保存的映象中恢复过来 做准备*/
driver方面的主要函数也跟device一样,也是注册的函数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) || //driver和bus的同名操作函数如果同时存在,会出现警告 (drv->bus->remove && drv->remove) || //并且会优先选用bus的 (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); //进入bus的driver链表,确认该driver是否已经注册 if (other) { put_driver(other); //找到了再减少引用计数,并且报错退出 printk(KERN_ERR "Error: Driver '%s' is already registered, " "aborting...\n", drv->name); return -EBUSY; } ret = bus_add_driver(drv); //如果没有注册,那么把该driver加入所在bus,并生成文件夹和链接 if (ret) return ret; ret = driver_add_groups(drv, drv->groups);//添加attribute_group if (ret) bus_remove_driver(drv); return ret; }大部分工作在 bus_add_driver()例程中完成
driver_find()例程通过驱动所属bus 的driver 容器drivers_kset 来查找
struct device_driver *driver_find(const char *name, struct bus_type *bus) { struct kobject *k = kset_find_obj(bus->p->drivers_kset, name);//bus->p->drivers_kset代表bus下的driver目录,此处会遍历bus的driver链表,通过driver内嵌的kobj名字比较 struct driver_private *priv; if (k) { priv = to_driver(k); return priv->driver; //如果找到同名的kobj那么返回该driver } return NULL; }通过kset_find_obj(bus->p->drivers_kset, name)查找该driver 的kobj
struct kobject *kset_find_obj(struct kset *kset, const char *name) { struct kobject *k; struct kobject *ret = NULL; spin_lock(&kset->list_lock); list_for_each_entry(k, &kset->list, entry) {//遍历bus下的driver链表,获取kobj if (kobject_name(k) && !strcmp(kobject_name(k), name)) {// 比较name字符 ret = kobject_get(k);// 如果找到就增加引用并返回 break; } } spin_unlock(&kset->list_lock); return ret; }显然,所有同类型的driver 都注册到了 一个bus->p->drivers_kset->list 中,所以可通过其查找已经注册的driver
再来看下bus_add_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的指针经,增加对 bus 的引用 if (!bus) return -EINVAL; pr_debug("bus: '%s': add driver %s\n", bus->name, drv->name); priv = kzalloc(sizeof(*priv), GFP_KERNEL); //开始初始化这个driver的私有成员,这个结构体中存放着kobj相关的数据 if (!priv) { error = -ENOMEM; goto out_put_bus; } klist_init(&priv->klist_devices, NULL, NULL);//设备操作函数清空,设备链表初始化 priv->driver = drv;// 反向指向包含其的 drv,以便后续使用 drv->p = priv; // 将 priv保存到 device_driver priv->kobj.kset = bus->p->drivers_kset;//kset指定到bus下面drivers_kset容器 error = kobject_init_and_add(&priv->kobj, &driver_ktype, NULL, //建立层次结构和属性文件 "%s", drv->name); if (error) goto out_unregister; if (drv->bus->p->drivers_autoprobe) {//bus的自动匹配如果设置为真, error = driver_attach(drv); //那么到bus的devices上去匹配设备 if (error) goto out_unregister; } klist_add_tail(&priv->knode_bus, &bus->p->klist_drivers);//把driver挂接到bus的driver链表,方便后续快速查找 driver module_add_driver(drv->owner, drv);//将driver添加到module模块 error = driver_create_file(drv, &driver_attr_uevent);//以下添加该driver相关属性文件 if (error) { printk(KERN_ERR "%s: uevent attr (%s) failed\n", __func__, drv->name); } error = driver_add_attrs(bus, drv);//添加 bus 的公有属性文件 if (error) { /* How the hell do we get out of this pickle? Give up */ printk(KERN_ERR "%s: driver_add_attrs(%s) failed\n", __func__, drv->name); } /* 如果配置了”CONFIG_HOTPLUG",则生成“bind”和"unbind”属性文件,可用于手动匹 配和移除 device与driver 之间的关联 */ 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); } } kobject_uevent(&priv->kobj, KOBJ_ADD);// 通过 uevent 设置几个环境变量并通知用户空间,以便调用程序来完成相关设置 return 0; out_unregister: kobject_put(&priv->kobj); kfree(drv->p); drv->p = NULL; out_put_bus: bus_put(bus); return error; }bus_register()例程注册 bus(本例是platform_bus_type)的时候,除了生成该 bus的kset 容器 subsys,还生成 devices_kset和drivers_kset容器,都包含在struct bus_type_private 里。
driver_attach()例程从bus中查找匹配的 device
int driver_attach(struct device_driver *drv) { return bus_for_each_dev(drv->bus, NULL, drv, __driver_attach);//遍历bus的设备链表找到合适的设备就调用__driver_attachNULL表示从头开始遍历 }对比下前面device的时候是
ret = bus_for_each_drv(dev->bus, NULL, dev, __device_attach);是不一样的。
继续往下看bus_for_each_dev
int bus_for_each_dev(struct bus_type *bus, struct device *start, void *data, int (*fn)(struct device *, void *)) { struct klist_iter i; struct device *dev; int error = 0; if (!bus) return -EINVAL; klist_iter_init_node(&bus->p->klist_devices, &i, //进入bus的devices链表 (start ? &start->p->knode_bus : NULL)); while ((dev = next_device(&i)) && !error)//设备存在则调用fn即__driver_attach进行匹配 error = fn(dev, data); klist_iter_exit(&i); return error; }再来看下回调到的__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那么需要初始化匹配到的这个设备 driver_probe_device(drv, dev); device_unlock(dev); if (dev->parent) device_unlock(dev->parent); return 0; }
int driver_probe_device(struct device_driver *drv, struct device *dev) { int ret = 0; if (!device_is_registered(dev))//判断该设备是否已经注册 return -ENODEV; pr_debug("bus: '%s': %s: matched device %s with driver %s\n", drv->bus->name, __func__, dev_name(dev), drv->name); pm_runtime_get_noresume(dev); pm_runtime_barrier(dev); ret = really_probe(dev, drv);// 这里真正开始调用用户在 device_driver 中注册的 probe()例程 pm_runtime_put_sync(dev); return ret; }到really_probe后,就回到了前面的device注册的时候一样的了,这里可以回过去看看
最后 看下调用流程图: