linux设备驱动模型一上层容器之device
2012-05-19 09:17
489 查看
系统中任一设备都有一个device对象描述,我们先来看一下它在内核中的表示:
可以看到device_private 的作用主要是把device链接入n个链表,以方便查找设备。
有关device,最重要的一个函数就是device_register,它的作用主要是注册设备驱动程序,搜寻驱动drv对应的设备,并与之关联。
接着调用device_add添加到驱动模型中去。
首先调用查看是否已经注册:
再调用 really_probe进行匹配
到这里,设备就已经匹配成功了,这样就把设备和相应的驱动挂钩上了。
最后看一下他们的关系图:
struct device { struct device *parent;//父设备 struct device_private *p;//设备的私有数据 struct kobject kobj;//表示该设备并把它链接到设备模型中的kobject const char *init_name;//初始化名字 struct device_type *type;//设备的类型 struct mutex mutex; //用于互斥访问 struct bus_type *bus; // 标识了该设备链接在哪一个总线上 struct device_driver *driver; // 管理该设备的驱动程序,一个设备只能有一个驱动程序 void *platform_data; //平台的特定数据 struct dev_pm_info power; #ifdef CONFIG_NUMA int numa_node; /* NUMA node this device is close to */ #endif u64 *dma_mask; //指向设备DMA屏蔽字 u64 coherent_dma_mask;//设备一致性DMA的屏蔽字 struct device_dma_parameters *dma_parms; struct list_head dma_pools; //聚集的DMA缓冲池 struct dma_coherent_mem *dma_mem; //指向设备所使用的一致性DMA存储器描述符的指针 struct dev_archdata archdata; #ifdef CONFIG_OF struct device_node *of_node; #endif dev_t devt; /* dev_t, creates the sysfs "dev" */ spinlock_t devres_lock;//用于互斥访问设备 struct list_head devres_head; struct klist_node knode_class; struct class *class;//指向属于的类 const struct attribute_group **groups; /* optional groups */ void (*release)(struct device *dev);//释放设备描述符的回调函数 };
struct device_private { struct klist klist_children;//该设备的子设备链表 struct klist_node knode_parent;//此结点将device链入device的parent的children链表 struct klist_node knode_driver;//此结点将device链入device对应的driver的devices链表 struct klist_node knode_bus;//此结点将device链入到对应的bus的devices链表 void *driver_data;//设备驱动程序使用的私有数据 struct device *device;//指向与之相关的device };
可以看到device_private 的作用主要是把device链接入n个链表,以方便查找设备。
有关device,最重要的一个函数就是device_register,它的作用主要是注册设备驱动程序,搜寻驱动drv对应的设备,并与之关联。
int device_register(struct device *dev) { device_initialize(dev);//初始化dev return device_add(dev); //添加dev }这个函数比较简单,主要是调用另外两个函数进行设备的初始化和添加操作,首先看下device_initialize
void device_initialize(struct device *dev) { dev->kobj.kset = devices_kset;//设置设备的kobject所属集合,devices_kset其实在第一层,sys/devices/ kobject_init(&dev->kobj, &device_ktype); //初始化设备的kobject INIT_LIST_HEAD(&dev->dma_pools); //初始化设备的DMA池,用于传递大数据 mutex_init(&dev->mutex); //初始化互斥锁 lockdep_set_novalidate_class(&dev->mutex); spin_lock_init(&dev->devres_lock);//初始化自旋锁,用于同步子设备链表 INIT_LIST_HEAD(&dev->devres_head); //初始化子设备链表头 device_pm_init(dev);// 此函数初始化device的power域 set_dev_node(dev, -1); }devices_kset是所有dev的kset,也就是所有dev都被链接在该kset下,这个kset是在设备初始化的时候创建的
int __init devices_init(void) { devices_kset = kset_create_and_add("devices", &device_uevent_ops, NULL); ...... char_kobj_err: kobject_put(sysfs_dev_block_kobj); block_kobj_err: kobject_put(dev_kobj); dev_kobj_err: kset_unregister(devices_kset); return -ENOMEM; }parent=NULL,所以生成/sys/devices目录
void device_initialize(struct device *dev) { dev->kobj.kset = devices_kset;//设置设备的kobject所属集合,devices_kset其实在第一层,sys/devices/ kobject_init(&dev->kobj, &device_ktype); //初始化设备的kobject INIT_LIST_HEAD(&dev->dma_pools); //初始化设备的DMA池,用于传递大数据 mutex_init(&dev->mutex); //初始化互斥锁 lockdep_set_novalidate_class(&dev->mutex); spin_lock_init(&dev->devres_lock);//初始化自旋锁,用于同步子设备链表 INIT_LIST_HEAD(&dev->devres_head); //初始化子设备链表头 device_pm_init(dev);// 此函数初始化device的power域 set_dev_node(dev, -1); }device_initialize对设备结构进行初始化,这里的ktype是device_ktype,kset是devices_kset
接着调用device_add添加到驱动模型中去。
int device_add(struct device *dev) { struct device *parent = NULL; struct class_interface *class_intf; int error = -EINVAL; dev = get_device(dev);//增加设备的kobject的引用计数 if (!dev) goto done; if (!dev->p) { error = device_private_init(dev);//初始化dev的私有成员,及其链表操作函数 if (error) goto done; } /* * for statically allocated devices, which should all be converted * some day, we need to initialize the name. We prevent reading back * the name, and force the use of dev_name() */ if (dev->init_name) { //保存设备名,以后需要获取时使用dev_name函数获取 dev_set_name(dev, "%s", dev->init_name); dev->init_name = NULL; } if (!dev_name(dev)) { error = -EINVAL; goto name_error; } pr_debug("device: '%s': %s\n", dev_name(dev), __func__); parent = get_device(dev->parent);//返回父节点,增加父节点引用计数,如果有返回,没有返回NULL setup_parent(dev, parent);//以上层devices为准重设dev->kobj.parent /* use parent numa_node */ if (parent) set_dev_node(dev, dev_to_node(parent)); /* first, register with generic layer. */ /* we require the name to be set before, and pass NULL */ error = kobject_add(&dev->kobj, dev->kobj.parent, NULL); //设置dev->kobj的名字和父对象,并建立相应目录 if (error) goto Error; /* notify platform of device entry */ if (platform_notify) platform_notify(dev); error = device_create_file(dev, &uevent_attr); //建立uevent属性文件 if (error) goto attrError; if (MAJOR(dev->devt)) { error = device_create_file(dev, &devt_attr);//在sys下产生dev属性文件 if (error) goto ueventattrError; error = device_create_sys_dev_entry(dev); if (error) goto devtattrError; devtmpfs_create_node(dev); } //建立subsystem链接文件连接到所属class error = device_add_class_symlinks(dev); if (error) goto SymlinkError; //添加dev的属性描述文件 error = device_add_attrs(dev); if (error) goto AttrsError; error = bus_add_device(dev); //添加链接文件至所属bus if (error) goto BusError; error = dpm_sysfs_add(dev); //添加power文件 if (error) goto DPMError; device_pm_add(dev); /* Notify clients of device addition. This call must come * after dpm_sysf_add() and before kobject_uevent(). */ if (dev->bus) blocking_notifier_call_chain(&dev->bus->p->bus_notifier, BUS_NOTIFY_ADD_DEVICE, dev); kobject_uevent(&dev->kobj, KOBJ_ADD);//向用户空间发出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->class_mutex); /* tie the class to the device */ klist_add_tail(&dev->knode_class, &dev->class->p->class_devices); /* notify any interfaces that the device is here */ list_for_each_entry(class_intf, &dev->class->p->class_interfaces, node) if (class_intf->add_dev) class_intf->add_dev(dev, class_intf); mutex_unlock(&dev->class->p->class_mutex); } done: put_device(dev); return error; DPMError: bus_remove_device(dev); BusError: device_remove_attrs(dev); AttrsError: device_remove_class_symlinks(dev); SymlinkError: if (MAJOR(dev->devt)) devtmpfs_delete_node(dev); if (MAJOR(dev->devt)) device_remove_sys_dev_entry(dev); devtattrError: if (MAJOR(dev->devt)) device_remove_file(dev, &devt_attr); ueventattrError: device_remove_file(dev, &uevent_attr); attrError: kobject_uevent(&dev->kobj, KOBJ_REMOVE); kobject_del(&dev->kobj); Error: cleanup_device_parent(dev); if (parent) put_device(parent); name_error: kfree(dev->p); dev->p = NULL; goto done; }这里看一下设备匹配:
void bus_probe_device(struct device *dev)//匹配driver以及初始化过程 { struct bus_type *bus = dev->bus; int ret; if (bus && bus->p->drivers_autoprobe) {//设置了自动匹配初始化那么就开始匹配 ret = device_attach(dev); WARN_ON(ret < 0); } }device_attach进行匹配操作。
int device_attach(struct device *dev) { int ret = 0; device_lock(dev); if (dev->driver) {//默认指定了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; }device_bind_driver进行驱动的绑定。
int device_bind_driver(struct device *dev) { int ret; //将driver和dev使用link,链接到一起,使他们真正相关 ret = driver_sysfs_add(dev); if (!ret) driver_bound(dev);//将私有成员的driver节点挂到了driver的设备链表 return ret; }driver_sysfs_add建立软链,它会在驱动目录下建立一个到设备的同名链接,并且在设备目录下建立一个名为 driver.到驱动的链接
static int driver_sysfs_add(struct device *dev) { int ret; ret = sysfs_create_link(&dev->driver->p->kobj, &dev->kobj,//驱动目录下dev->kobj目录链接到dev->kobj kobject_name(&dev->kobj)); if (ret == 0) { ret = sysfs_create_link(&dev->kobj, &dev->driver->p->kobj,//在dev->kobj目录下的driver目录链接到其驱动目录 "driver"); if (ret) sysfs_remove_link(&dev->driver->p->kobj, kobject_name(&dev->kobj)); } return ret; }driver_bound将私有成员的driver节点挂到了driver的设备链表
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); //将设备添加到driver的链表 if (dev->bus) blocking_notifier_call_chain(&dev->bus->p->bus_notifier, BUS_NOTIFY_BOUND_DRIVER, dev);//通知bus上所有设备bound消息 }回到device_attach,如果没有指定就进行遍历匹配
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,//和driver遍历device类似,从头开始遍历bus的driver链表 start ? &start->p->knode_bus : NULL); //发现一个driver就调用fn即__device_attach进行匹配 while ((drv = next_driver(&i)) && !error) error = fn(drv, data); klist_iter_exit(&i); return error; }再来看下__device_attach
static int __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);//进行真正的匹配操作 }看下driver_match_device
static inline int driver_match_device(struct device_driver *drv, struct device *dev)//bus的match存在就用bus的否则就直接匹配成功.match通常实现为首先扫描driver支持的id设备表,如果为NULL就用名字进行匹配 { return drv->bus->match ? drv->bus->match(dev, drv) : 1; }再来看下driver_probe_device,进行匹配操作
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);//调用really_probe pm_runtime_put_sync(dev); return ret; }
首先调用查看是否已经注册:
static inline int device_is_registered(struct device *dev) { return dev->kobj.state_in_sysfs; //在sysfs中表示已经注册 }
再调用 really_probe进行匹配
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; //device的driver初始化成该driver if (driver_sysfs_add(dev)) {//驱动目录下建立一个到设备的同名链接,并且在设备目录下建立一个名为 driver.到驱动的链接 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); //如果bus的probe存在就用bus的, if (ret) goto probe_failed; } else if (drv->probe) {//如果bus的不存在driver的存在 ret = drv->probe(dev);//再用driver的 if (ret) goto probe_failed; } driver_bound(dev);//调用driver_bound进行绑定 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); } /* * Ignore errors returned by ->probe so that the next driver can try * its luck. */ ret = 0; done: atomic_dec(&probe_count); wake_up(&probe_waitqueue); return ret; }再看下driver_bound
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); //将设备添加到driver的链表 if (dev->bus) blocking_notifier_call_chain(&dev->bus->p->bus_notifier, BUS_NOTIFY_BOUND_DRIVER, dev);//通知bus上所有设备bound消息 }
到这里,设备就已经匹配成功了,这样就把设备和相应的驱动挂钩上了。
最后看一下他们的关系图:
相关文章推荐
- linux设备驱动模型一上层容器之driver
- linux设备驱动模型一上层容器之class
- Linux设备驱动模型之上层容器
- Linux设备驱动编程模型之上层容器篇
- Linux设备驱动编程模型之上层容器篇
- linux设备驱动模型一上层容器之class
- linux设备驱动模型一上层容器之bus概述
- linux设备驱动模型一上层容器之关系
- linux设备驱动模型一上层容器之bus
- Linux设备驱动编程模型之上层容器篇
- Linux设备驱动模型之上层容器
- 阅读Linux设备驱动模型源码之 device结构体成员详解
- Linux设备驱动模型探究--3(device)
- Linux设备驱动工程师之路——设备模型(下)上层模型
- LINUX设备驱动之设备模型四--device&driver&bus
- linux设备驱动模型之device-driver
- Linux设备驱动模型框架分析(三)——LDDM的实体bus_type、device和device_driver
- Linux 设备模型(中)之上层容器
- Linux那些事儿之我是Sysfs(3)设备模型上层容器
- Linux 设备模型(中)之上层容器