linux内核部件分析设备驱动模型之driver.docx
- 文档编号:25960887
- 上传时间:2023-06-16
- 格式:DOCX
- 页数:28
- 大小:26.01KB
linux内核部件分析设备驱动模型之driver.docx
《linux内核部件分析设备驱动模型之driver.docx》由会员分享,可在线阅读,更多相关《linux内核部件分析设备驱动模型之driver.docx(28页珍藏版)》请在冰豆网上搜索。
linux内核部件分析设备驱动模型之driver
上节我们分析设备驱动模型中的device,主要是drivers/base/core.c,可以说是代码量最大的一个文件。
本节要分析的驱动driver,就要相对简单很多。
原因也很简单,对于driver,我们能定义的公共部分实在不多,能再sysfs中表达的也很少。
本节的分析将围绕drivers/base/driver.c,但头文件仍然是include/linux/device.h和drivers/base/base.h。
先让我们来看看driver的结构。
[cpp] viewplaincopyprint?
1.struct device_driver {
2. const char *name;
3. struct bus_type *bus;
4.
5. struct module *owner;
6. const char *mod_name; /* used for built-in modules */
7.
8. bool suppress_bind_attrs; /* disables bind/unbind via sysfs */
9.
10. int (*probe) (struct device *dev);
11. int (*remove) (struct device *dev);
12. void (*shutdown) (struct device *dev);
13. int (*suspend) (struct device *dev, pm_message_t state);
14. int (*resume) (struct device *dev);
15. const struct attribute_group **groups;
16.
17. const struct dev_pm_ops *pm;
18.
19. struct driver_private *p;
20.};
structdevice_driver就是模型定义的通用驱动结构。
name是驱动名称,但这个name也只是在静态定义的初始名称,实际使用的名称还是由kobject中保管的。
bus执行驱动所在的总线,owner是驱动所在的模块,还有一个所在模块名称mod_name,suppress_bind_attrs定义是否允许驱动通过sysfs决定挂载还是卸载设备。
下面是一系列函数指针,probe是在驱动刚与设备挂接时调用的,remove是在设备卸载时调用的,shutdown是在设备关闭时调用的(说实话我现在还不知道remove和shutdown的区别),suspend是设备休眠时调用的,resume是设备恢复时调用的。
group是属性集合,pm是电源管理的函数集合,p是指向driver_private的指针。
[cpp] viewplaincopyprint?
1.struct driver_private {
2. struct kobject kobj;
3. struct klist klist_devices;
4. struct klist_node knode_bus;
5. struct module_kobject *mkobj;
6. struct device_driver *driver;
7.};
8.#define to_driver(obj) container_of(obj, struct driver_private, kobj)
与device类似,device_driver把与其它组件联系的大部分结构变量移到structdriver_private中来。
首先是kobj,在sysfs中代表driver目录本身。
klist_devices是驱动下的设备链表,knode_bus是要挂载在总线的驱动链表上的节点。
mkobj是driver与相关module的联系,之前在device_driver结构中已经有指向module的指针,但这还不够,在/sys下你能发现一个module目录,所以驱动所属的模块在sysfs中也有显示,具体留到代码中再看。
driver指针自然是从driver_private指回structdevice_driver的。
[cpp] viewplaincopyprint?
1.struct driver_attribute {
2. struct attribute attr;
3. ssize_t (*show)(struct device_driver *driver, char *buf);
4. ssize_t (*store)(struct device_driver *driver, const char *buf,
5. size_t count);
6.};
7.
8.#define DRIVER_ATTR(_name, _mode, _show, _store) \
9.struct driver_attribute driver_attr_##_name = \
10. __ATTR(_name, _mode, _show, _store)
除了以上两个结构,还有structdriver_attribute。
driver_attribute是driver对structattribute的封装,添加了两个特用于device_driver的读写函数。
这种封装看似简单重复,工作量很小,但在使用时却会造成巨大的便利。
好,结构介绍完毕,下面看driver.c中的实现。
[cpp] viewplaincopyprint?
1.static struct device *next_device(struct klist_iter *i)
2.{
3. struct klist_node *n = klist_next(i);
4. struct device *dev = NULL;
5. struct device_private *dev_prv;
6.
7. if (n) {
8. dev_prv = to_device_private_driver(n);
9. dev = dev_prv->device;
10. }
11. return dev;
12.}
13.
14.int driver_for_each_device(struct device_driver *drv, struct device *start,
15. void *data, int (*fn)(struct device *, void *))
16.{
17. struct klist_iter i;
18. struct device *dev;
19. int error = 0;
20.
21. if (!
drv)
22. return -EINVAL;
23.
24. klist_iter_init_node(&drv->p->klist_devices, &i,
25. start ?
&start->p->knode_driver :
NULL);
26. while ((dev = next_device(&i)) && !
error)
27. error = fn(dev, data);
28. klist_iter_exit(&i);
29. return error;
30.}
31.struct device *driver_find_device(struct device_driver *drv,
32. struct device *start, void *data,
33. int (*match)(struct device *dev, void *data))
34.{
35. struct klist_iter i;
36. struct device *dev;
37.
38. if (!
drv)
39. return NULL;
40.
41. klist_iter_init_node(&drv->p->klist_devices, &i,
42. (start ?
&start->p->knode_driver :
NULL));
43. while ((dev = next_device(&i)))
44. if (match(dev, data) && get_device(dev))
45. break;
46. klist_iter_exit(&i);
47. return dev;
48.}
driver_for_each_device()是对drv的设备链表中的每个设备调用一次指定函数。
driver_find_device()是在drv的设备链表中寻找一个设备,寻找使用指定的匹配函数。
这两个函数都不陌生,在之前分析device的core.c中已经见到与它们很类似的函数,只不过那里是遍历设备的子设备链表,这里是遍历驱动的设备链表。
next_device()同样是辅助用的内部函数。
[cpp] viewplaincopyprint?
1.int driver_create_file(struct device_driver *drv,
2. struct driver_attribute *attr)
3.{
4. int error;
5. if (drv)
6. error = sysfs_create_file(&drv->p->kobj, &attr->attr);
7. else
8. error = -EINVAL;
9. return error;
10.}
11.
12.void driver_remove_file(struct device_driver *drv,
13. struct driver_attribute *attr)
14.{
15. if (drv)
16. sysfs_remove_file(&drv->p->kobj, &attr->attr);
17.}
driver_create_file()创建drv下的属性文件,调用sysfs_create_file()实现。
driver_remove_file()删除drv下的属性文件,调用sysfs_remove_file()实现。
[cpp] viewplaincopyprint?
1.static int driver_add_groups(struct device_driver *drv,
2. const struct attribute_group **groups)
3.{
4. int error = 0;
5. int i;
6.
7. if (groups) {
8. for (i = 0; groups[i]; i++) {
9. error = sysfs_create_group(&drv->p->kobj, groups[i]);
10. if (error) {
11. while (--i >= 0)
12. sysfs_remove_group(&drv->p->kobj,
13. groups[i]);
14. break;
15. }
16. }
17. }
18. return error;
19.}
20.
21.static void driver_remove_groups(struct device_driver *drv,
22. const struct attribute_group **groups)
23.{
24. int i;
25.
26. if (groups)
27. for (i = 0; groups[i]; i++)
28. sysfs_remove_group(&drv->p->kobj, groups[i]);
29.}
driver_add_groups()在drv目录下添加属性集合,调用sysfs_create_groups()实现。
driver_remove_groups()在drv目录下删除属性集合,调用sysfs_remove_groups()实现。
发现两点问题:
第一,是不是觉得driver_add_groups()不太合适,最好改为driver_create_groups()才搭调。
但不只是driver用driver_add_groups(),device也使用device_add_groups(),不知一处这样做。
第二,有没有发现driver_create_file()是外部函数,driver_add_groups()就是内部函数,也就是说driver只对外提供添加属性的接口,却不提供添加属性集合的接口。
理由吗?
在structdevice_driver()已经专门定义了一个groups变量来添加属性集合,后面就不易再重复提供接口,而且创建属性集合需要的操作远比创建属性费时。
在device中也是这样做的。
另外,driver中只提供管理属性文件的方法,却不提供管理二进制属性文件的方法,这是因为驱动本身没有这种需求,只有部分设备才要求二进制文件表示。
[cpp] viewplaincopyprint?
1.struct device_driver *get_driver(struct device_driver *drv)
2.{
3. if (drv) {
4. struct driver_private *priv;
5. struct kobject *kobj;
6.
7. kobj = kobject_get(&drv->p->kobj);
8. priv = to_driver(kobj);
9. return priv->driver;
10. }
11. return NULL;
12.}
13.
14.void put_driver(struct device_driver *drv)
15.{
16. kobject_put(&drv->p->kobj);
17.}
get_driver()增加drv的引用计数,put_driver()减少drv的引用计数。
这都是通过drv->p->kobj来做的。
[cpp] viewplaincopyprint?
1.struct device_driver *driver_find(const char *name, struct bus_type *bus)
2.{
3. struct kobject *k = kset_find_obj(bus->p->drivers_kset, name);
4. struct driver_private *priv;
5.
6. if (k) {
7. priv = to_driver(k);
8. return priv->driver;
9. }
10. return NULL;
11.}
driver_find()从bus的驱动链表中寻找特定名称的driver。
[cpp] viewplaincopyprint?
1./**
2. * driver_register - register driver with bus
3. * @drv:
driver to register
4. *
5. * We pass off most of the work to the bus_add_driver() call,
6. * since most of the things we have to do deal with the bus
7. * structures.
8. */
9.int driver_register(struct device_driver *drv)
10.{
11. int ret;
12. struct device_driver *other;
13.
14. BUG_ON(!
drv->bus->p);
15.
16. if ((drv->bus->probe && drv->probe) ||
17. (drv->bus->remove && drv->remove) ||
18. (drv->bus->shutdown && drv->shutdown))
19. printk(KERN_WARNING "Driver '%s' needs updating - please use "
20. "bus_type methods\n", drv->name);
21.
22. other = driver_find(drv->name, drv->bus);
23. if (other) {
24. put_driver(other);
25. printk(KERN_ERR "Error:
Driver '%s' is already registered, "
26. "aborting...\n", drv->name);
27. return -EBUSY;
28. }
29.
30. ret = bus_add_driver(drv);
31. if (ret)
32. return ret;
33. ret = driver_add_groups(drv, drv->groups);
34. if (ret)
35. bus_remove_driver(drv);
36. return ret;
37.}
driver_register()将drv注册到系统中。
它真是做得难以预料地简单,所有的工作几乎完全是由bus_add_driver()代为完成的。
但你要注意,在调用driver_register()前,drv->bus一定要预先设置。
device可以不绑定bus,但driver一定要绑定到bus上。
[cpp] viewplaincopyprint?
1.void driver_unregister(struct device_driver *drv)
2.{
3. if (!
drv || !
drv->p) {
4. WARN(1, "Unexpected driver unregister!
\n");
5. return;
6. }
7. driver_remove_groups(drv, drv->groups);
8. bus_remove_driver(drv);
9.}
driver_unregister()将drv从系统中撤销。
大部分工作是调用bus_remove_driver()完成的。
可以看出bus_add_driver()与bus_remove_driver()相对。
driver和bus的联系如此紧密,以至于driver的注册和撤销工作都可以由bus代劳了。
我们需要更进一步的分析。
经过调查,我们发现很有一部分driver的代码被移动到了bus.c中。
我们本节是以driver为主,所以接下来会尽量在不惊动bus的情况下,分析存在于bus.c中的driver代码。
[cpp] viewplaincopyprint?
1.static ssize_t drv_attr_show(struct kobject *kobj, struct attribute *attr,
2. char *buf)
3.{
4. struct driver_attribute *drv_attr = to_drv_attr(attr);
5. struct driver_private *drv_priv = to_driver(kobj);
6. ssize_t ret = -EIO;
7.
8. if (drv_attr->show)
9. ret = drv_attr->show(drv_priv->driver, buf);
10.
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- linux 内核 部件 分析 设备 驱动 模型 driver