linux内核部件分析设备驱动模型之device.docx
- 文档编号:29597335
- 上传时间:2023-07-25
- 格式:DOCX
- 页数:61
- 大小:40.64KB
linux内核部件分析设备驱动模型之device.docx
《linux内核部件分析设备驱动模型之device.docx》由会员分享,可在线阅读,更多相关《linux内核部件分析设备驱动模型之device.docx(61页珍藏版)》请在冰豆网上搜索。
linux内核部件分析设备驱动模型之device
linux的设备驱动模型,是建立在sysfs和kobject之上的,由总线、设备、驱动、类所组成的关系结构。
从本节开始,我们将对linux这一设备驱动模型进行深入分析。
头文件是include/linux/device.h,实现在drivers/base目录中。
本节要分析的,是其中的设备,主要在core.c中。
[cpp] viewplaincopyprint?
1.struct device {
2. struct device *parent;
3.
4. struct device_private *p;
5.
6. struct kobject kobj;
7. const char *init_name; /* initial name of the device */
8. struct device_type *type;
9.
10. struct semaphore sem; /* semaphore to synchronize calls to
11. * its driver.
12. */
13.
14. struct bus_type *bus; /* type of bus device is on */
15. struct device_driver *driver; /* which driver has allocated this
16. device */
17. void *platform_data; /* Platform specific data, device
18. core doesn't touch it */
19. struct dev_pm_info power;
20.
21.#ifdef CONFIG_NUMA
22. int numa_node; /* NUMA node this device is close to */
23.#endif
24. u64 *dma_mask; /* dma mask (if dma'able device) */
25. u64 coherent_dma_mask;/* Like dma_mask, but for
26. alloc_coherent mappings as
27. not all hardware supports
28. 64 bit addresses for consistent
29. allocations such descriptors. */
30.
31. struct device_dma_parameters *dma_parms;
32.
33. struct list_head dma_pools; /* dma pools (if dma'ble) */
34.
35. struct dma_coherent_mem *dma_mem; /* internal for coherent mem
36. override */
37. /* arch specific additions */
38. struct dev_archdata archdata;
39.
40. dev_t devt; /* dev_t, creates the sysfs "dev" */
41.
42. spinlock_t devres_lock;
43. struct list_head devres_head;
44.
45. struct klist_node knode_class;
46. struct class *class;
47. const struct attribute_group **groups; /* optional groups */
48.
49. void (*release)(struct device *dev);
50.};
先来分析下structdevice的结构变量。
首先是指向父节点的指针parent,kobj是内嵌在device中的kobject,用于把它联系到sysfs中。
bus是对设备所在总线的指针,driver是对设备所用驱动的指针。
还有DMA需要的数据,表示设备号的devt,表示设备资源的devres_head和保护它的devres_lock。
指向类的指针class,knode_class是被连入class链表时所用的klist节点。
group是设备的属性集合。
release应该是设备释放时调用的函数。
[cpp] viewplaincopyprint?
1.struct device_private {
2. struct klist klist_children;
3. struct klist_node knode_parent;
4. struct klist_node knode_driver;
5. struct klist_node knode_bus;
6. void *driver_data;
7. struct device *device;
8.};
9.#define to_device_private_parent(obj) \
10. container_of(obj, struct device_private, knode_parent)
11.#define to_device_private_driver(obj) \
12. container_of(obj, struct device_private, knode_driver)
13.#define to_device_private_bus(obj) \
14. container_of(obj, struct device_private, knode_bus)
structdevice中有一部分不愿意让外界看到,所以做出structdevice_private结构,包括了设备驱动模型内部的链接。
klist_children是子设备的链表,knode_parent是连入父设备的klist_children时所用的节点,knode_driver是连入驱动的设备链表所用的节点,knode_bus是连入总线的设备链表时所用的节点。
driver_data用于在设备结构中存放相关的驱动信息,也许是驱动专门为设备建立的结构实例。
device则是指向structdevice_private所属的device。
下面还有一些宏,to_device_private_parent()是从父设备的klist_children上节点,获得相应的device_private。
to_device_private_driver()是从驱动的设备链表上节点,获得对应的device_private。
to_device_private_bus()是从总线的设备链表上节点,获得对应的device_private。
或许会奇怪,为什么knode_class没有被移入structdevice_private,或许有外部模块需要用到它。
[cpp] viewplaincopyprint?
1./*
2. * The type of device, "struct device" is embedded in. A class
3. * or bus can contain devices of different types
4. * like "partitions" and "disks", "mouse" and "event".
5. * This identifies the device type and carries type-specific
6. * information, equivalent to the kobj_type of a kobject.
7. * If "name" is specified, the uevent will contain it in
8. * the DEVTYPE variable.
9. */
10.struct device_type {
11. const char *name;
12. const struct attribute_group **groups;
13. int (*uevent)(struct device *dev, struct kobj_uevent_env *env);
14. char *(*devnode)(struct device *dev, mode_t *mode);
15. void (*release)(struct device *dev);
16.
17. const struct dev_pm_ops *pm;
18.};
device竟然有device_type,类似于与kobject相对的kobj_type,之后我们再看它怎么用。
[cpp] viewplaincopyprint?
1./* interface for exporting device attributes */
2.struct device_attribute {
3. struct attribute attr;
4. ssize_t (*show)(struct device *dev, struct device_attribute *attr,
5. char *buf);
6. ssize_t (*store)(struct device *dev, struct device_attribute *attr,
7. const char *buf, size_t count);
8.};
9.
10.#define DEVICE_ATTR(_name, _mode, _show, _store) \
11.struct device_attribute dev_attr_##_name = __ATTR(_name, _mode, _show, _store)
这个device_attribute显然就是device对structattribute的封装,新加的show()、store()函数都是以与设备相关的结构调用的。
至于device中其它的archdata、dma、devres,都是作为设备特有的,我们现在主要关心设备驱动模型的建立,这些会尽量忽略。
下面就来看看device的实现,这主要在core.c中。
[cpp] viewplaincopyprint?
1.int __init devices_init(void)
2.{
3. devices_kset = kset_create_and_add("devices", &device_uevent_ops, NULL);
4. if (!
devices_kset)
5. return -ENOMEM;
6. dev_kobj = kobject_create_and_add("dev", NULL);
7. if (!
dev_kobj)
8. goto dev_kobj_err;
9. sysfs_dev_block_kobj = kobject_create_and_add("block", dev_kobj);
10. if (!
sysfs_dev_block_kobj)
11. goto block_kobj_err;
12. sysfs_dev_char_kobj = kobject_create_and_add("char", dev_kobj);
13. if (!
sysfs_dev_char_kobj)
14. goto char_kobj_err;
15.
16. return 0;
17.
18. char_kobj_err:
19. kobject_put(sysfs_dev_block_kobj);
20. block_kobj_err:
21. kobject_put(dev_kobj);
22. dev_kobj_err:
23. kset_unregister(devices_kset);
24. return -ENOMEM;
25.}
这是在设备驱动模型初始化时调用的device部分初始的函数devices_init()。
它干的事情我们都很熟悉,就是建立sysfs中的devices目录,和dev目录。
还在dev目录下又建立了block和char两个子目录。
因为dev目录只打算存放辅助的设备号,所以没必要使用kset。
[cpp] viewplaincopyprint?
1.static ssize_t dev_attr_show(struct kobject *kobj, struct attribute *attr,
2. char *buf)
3.{
4. struct device_attribute *dev_attr = to_dev_attr(attr);
5. struct device *dev = to_dev(kobj);
6. ssize_t ret = -EIO;
7.
8. if (dev_attr->show)
9. ret = dev_attr->show(dev, dev_attr, buf);
10. if (ret >= (ssize_t)PAGE_SIZE) {
11. print_symbol("dev_attr_show:
%s returned bad count\n",
12. (unsigned long)dev_attr->show);
13. }
14. return ret;
15.}
16.
17.static ssize_t dev_attr_store(struct kobject *kobj, struct attribute *attr,
18. const char *buf, size_t count)
19.{
20. struct device_attribute *dev_attr = to_dev_attr(attr);
21. struct device *dev = to_dev(kobj);
22. ssize_t ret = -EIO;
23.
24. if (dev_attr->store)
25. ret = dev_attr->store(dev, dev_attr, buf, count);
26. return ret;
27.}
28.
29.static struct sysfs_ops dev_sysfs_ops = {
30. .show = dev_attr_show,
31. .store = dev_attr_store,
32.};
看到这里是不是很熟悉,dev_sysfs_ops就是device准备注册到sysfs中的操作函数。
dev_attr_show()和dev_attr_store()都会再调用与属性相关的函数。
[cpp] viewplaincopyprint?
1.static void device_release(struct kobject *kobj)
2.{
3. struct device *dev = to_dev(kobj);
4. struct device_private *p = dev->p;
5.
6. if (dev->release)
7. dev->release(dev);
8. else if (dev->type && dev->type->release)
9. dev->type->release(dev);
10. else if (dev->class && dev->class->dev_release)
11. dev->class->dev_release(dev);
12. else
13. WARN(1, KERN_ERR "Device '%s' does not have a release() "
14. "function, it is broken and must be fixed.\n",
15. dev_name(dev));
16. kfree(p);
17.}
18.
19.static struct kobj_type device_ktype = {
20. .release = device_release,
21. .sysfs_ops = &dev_sysfs_ops,
22.};
使用的release函数是device_release。
在释放device时,会依次调用device结构中定义的release函数,device_type中定义的release函数,device所属的class中所定义的release函数,最后会吧device_private结构释放掉。
[cpp] viewplaincopyprint?
1.static int dev_uevent_filter(struct kset *kset, struct kobject *kobj)
2.{
3. struct kobj_type *ktype = get_ktype(kobj);
4.
5. if (ktype == &device_ktype) {
6. struct device *dev = to_dev(kobj);
7. if (dev->bus)
8. return 1;
9. if (dev->class)
10. return 1;
11. }
12. return 0;
13.}
14.
15.static const char *dev_uevent_name(struct kset *kset, struct kobject *kobj)
16.{
17. struct device *dev = to_dev(kobj);
18.
19. if (dev->bus)
20. return dev->bus->name;
21. if (dev->class)
22. return dev->class->name;
23. return NULL;
24.}
25.
26.static int dev_uevent(struct kset *kset, struct kobject *kobj,
27. struct kobj_uevent_env *env)
28.{
29. struct device *dev = to_dev(kobj);
30. int retval = 0;
31.
32. /* add device node properties if present */
33. if (MAJOR(dev->devt)) {
34. const char *tmp;
35. const char *name;
36. mode_t mode = 0;
37.
38. add_uevent_var(env, "MAJOR=%u", MAJOR(dev->devt));
39. add_uevent_var(env, "MINOR=%u", MINOR(dev->devt));
40. name = device_get_devnode(dev, &mode, &tmp);
41. if (name) {
42. add_uevent_var(env, "DEVNAME=%s", name);
43. kfree(tmp);
44. if (mode)
45.
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- linux 内核 部件 分析 设备 驱动 模型 device