二、linux设备模型层次关系:bus_type,device,device_driver 驱动核心可以注册多种类型的总线。 每种总线下面可以挂载许多设备。(通过kset devices) 每种总线下可以用很多设备驱动。(通过包含一个kset drivers)} 每个驱动可以处理一组设备。按照我的理解就是所有的设备都挂载到总线上,当加载驱动时,驱动就从总线上找到自己对应的设备。或者先把驱动加载上,来了一个设备就去总线找驱动。 这种基本关系的建立源于实际系统中各种总线,设备,驱动结构的抽象。 1.首先是总线,bus_type. 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; }; //bus_type的bus_type_private 成员 struct bus_type_private { struct kset subsys; struct kset *drivers_kset; struct kset *devices_kset; struct klist klist_devices; struct klist klist_drivers; struct blocking_notifier_head bus_notifier; unsigned int drivers_autoprobe:1; struct bus_type *bus; }; (1)总线的删除 void bus_unregister(struct bus_type *bus); (2)总线的match方法 int (*match)(struct device *dev, struct device_driver *drv); //当一个新设备或者驱动被添加到这个总线时,该方法被调用,用于判断指定的驱动程序是否能处理指定的设备。若可以,则返回非0值。下面的测试程序采用匹配设备的dev->bus_id字符串和驱动的drv->name字符串是否相同来判断驱动是否能处理该设备。 (3)总线uevent方法 int (*uevent)(structdevice *dev, char **envp, int num_envp)//在为用户产生热插拔事件之前,这个方法允许总线添加环境变量。 (4)总线属性由结构bus_attribute描述: struct bus_attribute { struct attribute attr; ssize_t (*show)(struct bus_type *bus,char *buf); ssize_t (*store)(struct bus_type *bus,const char *buf, size_t count); }; BUS_ATTR(name,mode, show, store)//在编译时创建和初始化bus_attribute结构,它将bus_attr_作为给定前缀来创建总线的真正名称。 如:static BUS_ATTR(version, S_IRUGO, show_bus_version, NULL);//将创建一个bus_attr_version结构体对象。 (5)创建\删除属性文件 int bus_create_file(struct bus_type *bus, struct bus_attribute *attr) void bus_remove_file(struct bus_type *bus, struct bus_attribute *attr) (6)可以看出该结构体中包含了有device和dirver的kset对象。 总线的注册:int bus_register(structbus_type *bus);如果成功,新的总线将被添加到系统,在/sys/bus目录下可以看到。 int bus_register(struct bus_type *bus) { int retval; struct bus_type_private *priv; priv = kzalloc(sizeof(struct bus_type_private), GFP_KERNEL); //分配空间 if (!priv) return -ENOMEM; priv->bus = bus; bus->p = priv;//建立bus_type和bus_type_private的关系 BLOCKING_INIT_NOTIFIER_HEAD(&priv->bus_notifier); //设置总线子系统kobject的名称 retval = kobject_set_name(&priv->subsys.kobj, "%s", bus->name);//给总线的kset结构里的kobject结构设置name,在/sys/bus目录下出现时就是这个bus名 if (retval) goto out; priv->subsys.kobj.kset = bus_kset;//设置总线子系统kobject的所属集合,其实对应sys/bus/ 目录 priv->subsys.kobj.ktype = &bus_ktype;//kobj_type类型变量,和sysfs有关 priv->drivers_autoprobe = 1; //这个变量如果置位,则会执行一个函数,在驱动注册会看到它的运用 //注册kset,就是建立/sys/bus/bus->name的目录 retval = kset_register(&priv->subsys); if (retval) goto out; //创建bus的属性文件 retval = bus_create_file(bus, &bus_attr_uevent);//调用sysfs_create_file(&bus->p->subsys.kobj, &attr->attr); if (retval) goto bus_uevent_fail; //在/sys/bus/bus->name目录下创建devices目录,父目录就是priv->subsys.kobj,即/sys/bus/bus->name的目录 priv->devices_kset = kset_create_and_add("devices", NULL,&priv->subsys.kobj); if (!priv->devices_kset) { retval = -ENOMEM; goto bus_devices_fail; } //在/sys/bus/bus->name目录下创建drivers目录,父目录就是priv->subsys.kobj,即/sys/bus/bus->name的目录 priv->drivers_kset = kset_create_and_add("drivers", NULL,&priv->subsys.kobj); if (!priv->drivers_kset) { retval = -ENOMEM; goto bus_drivers_fail; } // //初始化总线设备\总线驱动链表 klist_init(&priv->klist_devices, klist_devices_get, klist_devices_put); klist_init(&priv->klist_drivers, NULL, NULL); retval = add_probe_files(bus);//添加探测属性retval = bus_create_file(bus, &bus_attr_drivers_probe); retval = bus_create_file(bus, &bus_attr_drivers_autoprobe); if (retval) goto bus_probe_files_fail; retval = bus_add_attrs(bus);// 添加其他属性,bus_create_file(bus, &bus->bus_attrs[i]); if (retval) goto bus_attrs_fail; pr_debug("bus: '%s': registered\n", bus->name); return 0; bus_attrs_fail: remove_probe_files(bus); bus_probe_files_fail: kset_unregister(bus->p->drivers_kset); bus_drivers_fail: kset_unregister(bus->p->devices_kset); bus_devices_fail: bus_remove_file(bus, &bus_attr_uevent); bus_uevent_fail: kset_unregister(&bus->p->subsys); kfree(bus->p); out: return retval; } 2.下面是设备device的定义: struct device { struct klist klist_children; struct klist_nodeknode_parent;/* node in sibling list */ struct klist_nodeknode_driver; struct klist_nodeknode_bus; struct device *parent;//父设备,一般一个bus也对应一个设备。 struct kobject kobj; //代表自身 char bus_id[BUS_ID_SIZE];/* position on parent bus */ unsigned uevent_suppress:1; const char *init_name; /*设备初始名 */ struct device_type*type; struct semaphoresem;/* semaphore to synchronize calls to its driver. */ struct bus_type*bus;/* 所属的总线 */ struct device_driver *driver; /* 匹配的驱动*/ void *driver_data;/* data private to the driver */ void *platform_data;/* 由驱动定义并使用 */ struct dev_pm_infopower; u64 *dma_mask;/* dma mask (if dma'able device) */ u64 coherent_dma_mask; struct device_dma_parameters *dma_parms; struct list_headdma_pools;/* dma pools (if dma'ble) */ struct dma_coherent_mem*dma_mem; /* internal for coherent mem override */ struct dev_archdataarchdata; /* arch specific additions */ dev_t devt;/* dev_t, creates the sysfs "dev" */ spinlock_t devres_lock; struct list_headdevres_head; struct klist_nodeknode_class; struct class *class; struct attribute_group**groups;/* optional groups */ void (*release)(struct device *dev); }; //可以看出device结构体中也包含了一个kobject对象 (1)注册设备 int device_register(struct device *dev); (2)注销设备 viod device_unregister(struct device *dev) (3)设备属性由struct device_attribute描述 structdevice_attribute { struct attribute attr; ssize_t (*show)(struct device *dev,struct device_attribute *attr,char *buf); ssize_t (*store)(struct device *dev,struct device_attribute *attr,const char *buf, size_t count); }; (4)创建属性文件 int device_create_file(struct device *dev, struct device_attibute *entry) (5)删除属性文件 void device_remove_file(struct device *dev, struct device_attibute *entry) (6)device_register代码 int device_register(struct device *dev) { device_initialize(dev);//初始化设备各个字段 return device_add(dev); } void device_initialize(struct device *dev) { kobj_set_kset_s(dev, devices_subsys); //所有的dev属于devices_subsys这个集合 kobject_init(&dev->kobj); //初始kobj klist_init(&dev->klist_children, klist_children_get,klist_children_put);//初始化子设备链表 INIT_LIST_HEAD(&dev->dma_pools); INIT_LIST_HEAD(&dev->node); init_MUTEX(&dev->sem); device_init_wakeup(dev, 0); } int device_add(struct device *dev) { struct device *parent = NULL; struct kobject *kobj; struct class_interface *class_intf; int error = -EINVAL; dev = get_device(dev);//增加使用计数 if (!dev) goto done; if (!dev->p) { /*int device_private_init(struct device *dev) { dev->p = kzalloc(sizeof(*dev->p), GFP_KERNEL); if (!dev->p) return -ENOMEM; dev->p->device = dev;//指向设备自己 klist_init(&dev->p->klist_children, klist_children_get,klist_children_put);//初始化设备私有成员的子设备链表,还有两个函数,关于增加和减少子设备引用计数的 return 0; } */ error = device_private_init(dev); if (error) goto done; } if (dev->init_name) {//设备初始名存在 /* int dev_set_name(struct device *dev, const char *fmt, ...) { va_list vargs; int err; va_start(vargs, fmt); err = kobject_set_name_vargs(&dev->kobj, fmt, vargs); va_end(vargs); return err; } */ dev_set_name(dev, "%s", dev->init_name);//赋值给设备本身的kobject结构的name dev->init_name = NULL; } /*检查设备名是否存在,否则使用dev->bus->dev_name, dev->id生成设备本身的kobject结构的name*/ if (!dev_name(dev) && dev->bus && dev->bus->dev_name) dev_set_name(dev, "%s%u", dev->bus->dev_name, dev->id); if (!dev_name(dev)) {//再次检查name error = -EINVAL; goto name_error; } pr_debug("device: '%s': %s\n", dev_name(dev), __func__); parent = get_device(dev->parent);//增加父设备计数,并返回父设备结构 kobj = get_device_parent(dev, parent);//找到父设备对应的kobject结构 if (kobj) dev->kobj.parent = kobj;//将本设备的kobj的parent字段指向父设备的kobject结构 /* use parent numa_node */ if (parent) set_dev_node(dev, dev_to_node(parent));// dev->numa_node = node; //将Kobject对象注册到linux系统,即在dev->kobj.parent的目录下创建前边设置过的name的本设备的目录 error = kobject_add(&dev->kobj, dev->kobj.parent, NULL); if (error) goto Error; /* notify platform of device entry */ if (platform_notify) platform_notify(dev); //为sysfs文件系统创建设备的属性文件 error = device_create_file(dev, &uevent_attr); if (error) goto attrError; if (MAJOR(dev->devt)) {//如果存在设备号则添加dev_t属性,这样udev就能读取设备号属性从而在/dev/目录下创建设备节点,这样kobj和cdev也关联了 error = device_create_file(dev, &devt_attr);//创建属性文件static struct device_attribute devt_attr =__ATTR(dev, S_IRUGO, show_dev, NULL); if (error) goto ueventattrError; //创建一些符号链接 error = device_create_sys_dev_entry(dev); if (error) goto devtattrError; devtmpfs_create_node(dev);//在/dev下动态创建设备节点 } //建立类的sysfs符号连接 error = device_add_class_symlinks(dev); if (error) goto SymlinkError; error = device_add_attrs(dev);//调用device_create_file(dev, &bus->dev_attrs[i])为sysfs文件系统创建属性文件 if (error) goto AttrsError; error = bus_add_device(dev);//创建bus的一些符号链接,将设备添加进总线中 if (error) goto BusError; error = dpm_sysfs_add(dev);//电源管理 if (error) goto DPMError; device_pm_add(dev);//电源管理 if (dev->bus)//调用注册bus通知链上的所有函数 blocking_notifier_call_chain(&dev->bus->p->bus_notifier,BUS_NOTIFY_ADD_DEVICE, dev); //主要是向用户空间发送消息,实现热插拔 kobject_uevent(&dev->kobj, KOBJ_ADD); bus_probe_device(dev); //现在该为设备在总线上寻找合适的驱动了 if (parent)//如果父设备存在 klist_add_tail(&dev->p->knode_parent,&parent->p->klist_children);//将子设备添加到父设备的链表中 if (dev->class) { mutex_lock(&dev->class->p->mutex); klist_add_tail(&dev->knode_class,&dev->class->p->klist_devices); /* tie the class to the device */ /* notify any interfaces that the device is here */ list_for_each_entry(class_intf,&dev->class->p->interfaces, node) if (class_intf->add_dev) class_intf->add_dev(dev, class_intf); mutex_unlock(&dev->class->p->mutex); } done: put_device(dev); return error; .......//出错处理 } int bus_add_device(struct device *dev) { struct bus_type *bus = bus_get(dev->bus); int error = 0; if (bus) { pr_debug("bus: '%s': add device %s\n", bus->name, dev_name(dev)); error = device_add_attrs(bus, dev);//创建属性文件 if (error) goto out_put; error = sysfs_create_link(&bus->p->devices_kset->kobj,&dev->kobj, dev_name(dev));//创建设备所在bus目录下的设备链接 if (error) goto out_id; error = sysfs_create_link(&dev->kobj,&dev->bus->p->subsys.kobj, "subsystem");//创建链接 if (error) goto out_subsys; klist_add_tail(&dev->p->knode_bus, &bus->p->klist_devices);//将设备添加到所在bus总线下的链表中,将设备添加进总线的设备链表 } return 0; out_subsys: sysfs_remove_link(&bus->p->devices_kset->kobj, dev_name(dev)); out_id: device_remove_attrs(bus, dev); out_put: bus_put(dev->bus); return error; } void bus_probe_device(struct device *dev) { struct bus_type *bus = dev->bus;//找到设备所在的总线 int ret; if (bus && bus->p->drivers_autoprobe) {//drivers_autoprobe标志设为1,表明要自动匹配驱动 ret = device_attach(dev); //为设备寻找驱动 WARN_ON(ret < 0); } } int device_attach(struct device *dev) { int ret = 0; device_lock(dev);//锁住设备 if (dev->driver) {//如果设备有驱动 ret = device_bind_driver(dev);//那么将设备和驱动绑定 if (ret == 0) ret = 1; else { dev->driver = NULL; ret = 0; } } else {//如果设备没有驱动 pm_runtime_get_noresume(dev); ret = bus_for_each_drv(dev->bus, NULL, dev, __device_attach); //在总线上寻找驱动与该设备进行匹配 pm_runtime_put_sync(dev); } device_unlock(dev); return ret; } int device_bind_driver(struct device *dev) { int ret; ret = driver_sysfs_add(dev);//主要是添加driver和dev之间的连接文件 if (!ret) driver_bound(dev);//驱动绑定设备 return ret; } static int driver_sysfs_add(struct device *dev) { int ret; //1:在驱动目录下建立一个到设备的同名链接 //2:在设备目录下建立一个名为driver。到驱动的链接 ret = sysfs_create_link(&dev->driver->p->kobj, &dev->kobj,kobject_name(&dev->kobj)); //在driver目录下添加以dev->kobj名字的连接文件,连接到device if (ret == 0) { ret = sysfs_create_link(&dev->kobj, &dev->driver->p->kobj,"driver"); //同样在device目录下添加‘driver’为名字的连接文件连接到drvier if (ret) sysfs_remove_link(&dev->driver->p->kobj,kobject_name(&dev->kobj)); } return ret; } static void driver_bound(struct device *dev) { if (klist_node_attached(&dev->p->knode_driver)) { printk(KERN_WARNING "%s: device %s already bound\n",__func__, kobject_name(&dev->kobj)); return; } pr_debug("driver: '%s': %s: bound to device '%s'\n", dev_name(dev),__func__, dev->driver->name); //实现将驱动程序和设备联系起来。 klist_add_tail(&dev->p->knode_driver, &dev->driver->p->klist_devices); if (dev->bus)//调用注册bus通知链上的所有函数 blocking_notifier_call_chain(&dev->bus->p->bus_notifier,BUS_NOTIFY_BOUND_DRIVER, dev); } int bus_for_each_drv(struct bus_type *bus, struct device_driver *start,void *data, int (*fn)(struct device_driver *, void *)) { struct klist_iter i; struct device_driver *drv; int error = 0; if (!bus) return -EINVAL; klist_iter_init_node(&bus->p->klist_drivers, &i,start ? &start->p->knode_bus : NULL); //初始化i结构体 while ((drv = next_driver(&i)) && !error)//遍历总线上的驱动 error = fn(drv, data);//将驱动和设备进行匹配,这里的fn=__device_attach klist_iter_exit(&i); return error; } static int __device_attach(struct device_driver *drv, void *data) { struct device *dev = data; if (!driver_match_device(drv, dev))//现用总线上的match匹配函数进行低级匹配 return 0; return driver_probe_device(drv, dev); //再来高级匹配 } static inline int driver_match_device(struct device_driver *drv, struct device *dev) { return drv->bus->match ? drv->bus->match(dev, drv) : 1;//看到没,这里要调用总线上定义的match函数,实际就是比较设备名和驱动名是否一样 } int driver_probe_device(struct device_driver *drv, struct device *dev) { int ret = 0; if (!device_is_registered(dev)) //设备是否注册,返回 return dev->kobj.state_in_sysfs 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);//调用真正的匹配 pm_runtime_put_sync(dev); return ret; } static int really_probe(struct device *dev, struct device_driver *drv) { int ret = 0; atomic_inc(&probe_count); pr_debug("bus: '%s': %s: probing driver %s with device %s/n",drv->bus->name, __func__, drv->name, dev_name(dev)); WARN_ON(!list_empty(&dev->devres_head)); dev->driver = drv; if (driver_sysfs_add(dev)) {//主要是添加driver和dev之间的连接文件,见上 printk(KERN_ERR "%s: driver_sysfs_add(%s) failed/n",__func__, dev_name(dev)); goto probe_failed; } if (dev->bus->probe) {//现用总线上定义的probe函数尝试一下 ret = dev->bus->probe(dev); if (ret) goto probe_failed; } else if (drv->probe) {//如果不行,在用驱动上的probe尝试 ret = drv->probe(dev); if (ret) goto probe_failed; } driver_bound(dev);//驱动绑定设备 ret = 1; pr_debug("bus: '%s': %s: bound device %s to driver %s/n",drv->bus->name, __func__, dev_name(dev), drv->name); goto done; probe_failed: devres_release_all(dev); driver_sysfs_remove(dev); dev->driver = NULL; if (ret != -ENODEV && ret != -ENXIO) {/* driver matched but the probe failed */ printk(KERN_WARNING"%s: probe of %s failed with error %d/n",drv->name, dev_name(dev), ret); } ret = 0; done: atomic_dec(&probe_count); wake_up(&probe_waitqueue); return ret; } 3.下面是设备驱动定义: 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 driver_private { struct kobject kobj;//代表自身 struct klist klist_devices;//设备列表 struct klist_node knode_bus; struct module_kobject *mkobj; struct device_driver *driver; }; (1)当总线的match返回非0值,也就是总线找到与驱动相匹配的设备时,驱动的probe的函数将被调用。 (2)当设备从系统总删除是remove被调用。 (3)当系统关机的时候shutdown被调用。 (4)创建属性文件 int dirver_create_file(struct device_driver *drv, struct driver_attribute *attr); (5)删除属性文件 void driver_remove_file struct device_driver *drv, struct driver_attribute *attr); (6)驱动的属性使用structdriver_attribute来描述 structdriver_attribute{ structattribue attr; ssize_t(*show)(struct device_driver *drv, const char *buf); ssize_t(*store)(struct device_driver *drv, const char *buf, size_t count); } (7)卸载总线上注销驱动 int driver_register(structdevice_driver *drv) (8)在总线上注册驱动 void driver_unregister(struct device_driver *drv) (9)代码分析 int driver_register(struct device_driver *drv) { int ret; struct device_driver *other; BUG_ON(!drv->bus->p); //判断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); //在注册在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); //经过上面的验证后,将驱动添加注册到bus上 if (ret) return ret; ret = driver_add_groups(drv, drv->groups); //如果grop不为空的话,将在驱动文件夹下创建以group名字的子文件夹,然后在子文件夹下添加group的属性文件 if (ret) bus_remove_driver(drv); return ret; } int bus_add_driver(struct device_driver *drv) { struct bus_type *bus; struct driver_private *priv; int error = 0; bus = bus_get(drv->bus);//找到该drv所属的bus,其实就是增加该bus->p->subsys->kobject->kref的引用计数 if (!bus) return -EINVAL; pr_debug("bus: '%s': add driver %s\n", bus->name, drv->name); priv = kzalloc(sizeof(*priv), GFP_KERNEL);//分配driver_private结构 if (!priv) { error = -ENOMEM; goto out_put_bus; } klist_init(&priv->klist_devices, NULL, NULL);//初始化priv->klist_devices priv->driver = drv; //将该drv赋值给priv->driver drv->p = priv; //而drv的drv->p又等于priv priv->kobj.kset = bus->p->drivers_kset; //指向bus的drvier容器 //在sysfs文件系统下在总线所在的drivers_kset目录下添加该驱动的目录 error = kobject_init_and_add(&priv->kobj, &driver_ktype, NULL,"%s", drv->name); //驱动的kobject初始化和添加dir到sysfs中 if (error) goto out_unregister; if (drv->bus->p->drivers_autoprobe) { //这个变量默认是为1的 error = driver_attach(drv); //匹配相应的设备 if (error) goto out_unregister; } klist_add_tail(&priv->knode_bus, &bus->p->klist_drivers); //将priv->knode_bus添加到bus->p->klist_drivers,即添加到总线上 module_add_driver(drv->owner, drv); //添加drv的module error = driver_create_file(drv, &driver_attr_uevent); //在sysfs的目录下创建文件uevent属性文件 if (error) { printk(KERN_ERR "%s: uevent attr (%s) failed\n",__func__, drv->name); } error = driver_add_attrs(bus, drv);//给driver添加bus上的所有属性 if (error) { printk(KERN_ERR "%s: driver_add_attrs(%s) failed\n",__func__, drv->name); } error = add_bind_files(drv); //添加绑定文件,driver_attr_bind 和 driver_attr_unbind if (error) { printk(KERN_ERR "%s: add_bind_files(%s) failed\n", __func__, drv->name); } kobject_uevent(&priv->kobj, KOBJ_ADD); //产生一个KOBJ_ADD uevent return 0; out_unregister: kfree(drv->p); drv->p = NULL; kobject_put(&priv->kobj); 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); } //该函数将调用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,(start ? &start->p->knode_bus : NULL)); //将bus中的已注册的device列表放到迭代器中,方便索引 while ((dev = next_device(&i)) && !error) //将驱动逐个地与列表中每一个的device匹配,可能一个驱动匹配好几个设备 error = fn(dev, data); //这个fn就是上面传下来的__driver_attach klist_iter_exit(&i); return error; } static int __driver_attach(struct device *dev, void *data) { struct device_driver *drv = data; if (!driver_match_device(drv, dev)) //跟名字的意思一样,driver跟device尝试匹配 return 0; if (dev->parent) /* Needed for USB */ down(&dev->parent->sem); down(&dev->sem); if (!dev->driver) driver_probe_device(drv, dev);//再来高级匹配 up(&dev->sem); if (dev->parent) up(&dev->parent->sem); 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函数 } int driver_probe_device(struct device_driver *drv, struct device *dev) { int ret = 0; if (!device_is_registered(dev)) //首先判断这个device是否已经注册 return -ENODEV; pr_debug("bus: '%s': %s: matched device %s with driver %s\n",drv->bus->name, __func__, dev_name(dev), drv->name); ret = really_probe(dev, drv); //转而调用really_probe(),同以上的device_register()里调用的 return ret; } void module_add_driver(struct module *mod, struct device_driver *drv) { char *driver_name; int no_warn; struct module_kobject *mk = NULL; if (!drv) return; if (mod)//一般情况下为THIS_MODULE mk = &mod->mkobj; else if (drv->mod_name) {//如果没模块,则检查驱动的模块名 struct kobject *mkobj; mkobj = kset_find_obj(module_kset, drv->mod_name); //根据驱动模块的名字去module_kset集合中找 if (mkobj) { mk = container_of(mkobj, struct module_kobject, kobj); //用container_of方法通过kobj转换成module_kobject drv->p->mkobj = mk; //赋值给驱动的mkobj kobject_put(mkobj); } } if (!mk) //mk如果为null则返回 return; no_warn = sysfs_create_link(&drv->p->kobj, &mk->kobj, "module"); //在驱动文件夹下创建名为‘module’的链接文件,链接到module文件夹 driver_name = make_driver_name(drv); //生成driver_name,给module用 if (driver_name) { module_create_drivers_dir(mk); //在具体的module文件夹下创建driver目录 no_warn = sysfs_create_link(mk->drivers_dir, &drv->p->kobj,make_driver_name()); //在上面创建的driver目录下,生成一个名为driver_name指定的链接文件,链接到驱动的文件夹 kfree(driver_name); } } 总体来说,驱动的注册比较复杂,但是我们可以简单概况一下。 1、在总线上找找该驱动有没有被注册过 2、若没有注册过,则将驱动加入到总线驱动集合中 3、在总线上找能匹配驱动的设备 1、将总线上每个设备进行匹配 2、首先用总线的match 函数进行低级匹配 3、然后在用总线的probe函数进行高级匹配,若失败,则用驱动上的probe寒酸进行高级匹配 4、如果匹配成功,则将设备绑定到驱动链表中 4、如果匹配成功,则将驱动加入到总线的驱动链表中 4、结束语 系统初始化时,会扫描连接那些设备,并为扫描到的设备建立一个struct device的变量,接下来就是驱动,每次扫描有一个驱动程序,就要为其分配一个struct device_driver结构变量,并把这些变量加入相应的链表中,device插入devices、driver插入drivers中去,这样总线伤的两条链表变这样诞生了。在以前的系统中都是先有设备后又驱动的,因为设备都是先插好了再商店开机的。这样devices链表会先被创建,而后就是drivers链表,然后驱动程序就开始初始化,开始注册其struct devicr_driver结构,然后他就去总线的devices链表中去寻找(遍历)还没有绑定driver的设备,即struct device中的struct device_driver指针乃为空的设备。然后去观察该设备的特征,若匹配就会调用device_bind_driver的函数结合在一起,换句话说,把struct device中的struct devicr_drive driver指向这个driver,而struct device_driver drivers加入他的那张struct klist *klist_devices链表中来,这样 bus、device、driver就建立起关系并联系起来了。 三、测试模块 1.BUS [html] view plaincopy #include <linux/device.h> #include <linux/module.h> #include <linux/kernel.h> #include <linux/init.h> #include <linux/string.h> MODULE_AUTHOR("David Xie"); MODULE_LICENSE("Dual BSD/GPL"); static char *Version = "$Revision: 1.9 {1}quot;; static int my_match(struct device *dev, struct device_driver *driver) { return !strncmp(dev->bus_id, driver->name, strlen(driver->name)); } static void my_bus_release(struct device *dev) { printk(KERN_DEBUG "my bus release\n"); } struct device my_bus = { .bus_id = "my_bus0", .release = my_bus_release }; struct bus_type my_bus_type = { .name = "my_bus", .match = my_match, }; EXPORT_SYMBOL(my_bus); EXPORT_SYMBOL(my_bus_type); /* * Export a simple attribute. */ static ssize_t show_bus_version(struct bus_type *bus, char *buf) { return snprintf(buf, PAGE_SIZE, "%s\n", Version); } static BUS_ATTR(version, S_IRUGO, show_bus_version, NULL); static int __init my_bus_init(void) { int ret; /*注册总线*/ ret = bus_register(&my_bus_type); if (ret) return ret; /*创建属性文件*/ if (bus_create_file(&my_bus_type, &bus_attr_version)) printk(KERN_NOTICE "Fail to create version attribute!\n"); /*注册总线设备*/ ret = device_register(&my_bus); if (ret) printk(KERN_NOTICE "Fail to register device:my_bus!\n"); return ret; } static void my_bus_exit(void) { device_unregister(&my_bus); bus_unregister(&my_bus_type); } module_init(my_bus_init); module_exit(my_bus_exit); 创建一条名为my_bus_type的总线和一个名为my_bus的总线设备,注意总线也是一个设备,也需要注册。 测试结果: 2.DEVICE [html] view plaincopy #include <linux/device.h> #include <linux/module.h> #include <linux/kernel.h> #include <linux/init.h> #include <linux/string.h> MODULE_AUTHOR("David Xie"); MODULE_LICENSE("Dual BSD/GPL"); extern struct device my_bus; extern struct bus_type my_bus_type; /* Why need this ?*/ static void my_dev_release(struct device *dev) { } struct device my_dev = { .bus = &my_bus_type, .parent = &my_bus, .release = my_dev_release, }; /* * Export a simple attribute. */ static ssize_t mydev_show(struct device *dev, char *buf) { return sprintf(buf, "%s\n", "This is my device!"); } static DEVICE_ATTR(dev, S_IRUGO, mydev_show, NULL); static int __init my_device_init(void) { int ret = 0; /* 初始化设备 */ strncpy(my_dev.bus_id, "my_dev", BUS_ID_SIZE); /*注册设备*/ device_register(&my_dev); /*创建属性文件*/ device_create_file(&my_dev, &dev_attr_dev); return ret; } static void my_device_exit(void) { device_unregister(&my_dev); } module_init(my_device_init); module_exit(my_device_exit); 注册一个bus_id即名字为my_dev的设备,该设备的bus成员指向上一步创建的my_bus_type总线,parent成员指向上一步创建的my_bus总线设备。 测试结果: 3.DRIVER [html] view plaincopy #include <linux/device.h> #include <linux/module.h> #include <linux/kernel.h> #include <linux/init.h> #include <linux/string.h> MODULE_AUTHOR("David Xie"); MODULE_LICENSE("Dual BSD/GPL"); 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); 创建一个名为“bus_dev”的驱动,并将bus成员指向第一步创建的my_bus_type总线