linux设备驱动模型之device
来源:互联网 发布:android 打开移动网络 编辑:程序博客网 时间:2024/06/05 22:35
系统中任一设备都有一个device对象描述,我们先来看一下它在内核中的表示:
[cpp] view plain copy print?
- 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);//释放设备描述符的回调函数
- };
[cpp] view plain copy print?
- 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对应的设备,并与之关联。
[cpp] view plain copy print?
- int device_register(struct device *dev)
- {
- device_initialize(dev);//初始化dev
- return device_add(dev); //添加dev
- }
[cpp] view plain copy print?
- 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);
- }
[cpp] view plain copy print?
- 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;
- }
[cpp] view plain copy print?
- 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_add添加到驱动模型中去。
[cpp] view plain copy print?
- 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;
- }
[cpp] view plain copy print?
- 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);
- }
- }
[cpp] view plain copy print?
- 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;
- }
[cpp] view plain copy print?
- 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;
- }
[cpp] view plain copy print?
- 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;
- }
[cpp] view plain copy print?
- 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消息
- }
[cpp] view plain copy print?
- 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;
- }
[cpp] view plain copy print?
- 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);//进行真正的匹配操作
- }
[cpp] view plain copy print?
- 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;
- }
[cpp] view plain copy print?
- 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;
- }
首先调用查看是否已经注册:
[cpp] view plain copy print?
- static inline int device_is_registered(struct device *dev)
- {
- return dev->kobj.state_in_sysfs; //在sysfs中表示已经注册
- }
[cpp] view plain copy print?
- 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;
- }
[cpp] view plain copy print?
- 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消息
- }
到这里,设备就已经匹配成功了,这样就把设备和相应的驱动挂钩上了。
最后看一下他们的关系图:
原文:http://blog.csdn.net/new_abc/article/details/7582215
阅读全文
0 0
- linux设备驱动模型之device
- linux设备驱动模型之device-driver
- Linux设备驱动模型-Device
- LINUX设备驱动之设备模型三--device&driver&bus
- LINUX设备驱动之设备模型四--device&driver&bus
- LINUX设备驱动之设备模型五--device&driver&bus
- 设备驱动模型之device
- 设备驱动模型之device
- linux内核部件分析之----设备驱动模型之device
- linux内核组件之---设备驱动模型之device-driver
- linux内核部件分析之----设备驱动模型之device
- linux设备驱动模型一上层容器之device
- Linux内核部件分析--设备驱动模型之device
- Linux内核部件分析--设备驱动模型之device-driver
- Linux内核部件分析<6> 设备驱动模型之device
- Linux内核部件分析--设备驱动模型之device
- Linux内核部件分析--设备驱动模型之device-driver
- linux ------ 设备驱动模型之二(bus, device, driver)
- Android 异常容错处理
- hdoj--2003
- 单行、多行文字超出用省略号表示
- 三点顺序 【南阳 oj 题目68 】
- WPS for Linux(ubuntu)字体配置(字体缺失解决办法)
- linux设备驱动模型之device
- 原根的一些理解与题目
- 卷积神经网络CNN(8)—— Pix2Pix Application -- Aerialmap Lane Line Detection (Pix2Pix应用:航拍图车道线检测)
- ES6基础--import和export
- Android 同步与加锁
- hdu 2094 拓扑排序
- Java集合类详解
- (三)读取本地音乐文件
- [LeetCode]41. First Missing Positive