分类: LINUX
2012-07-08 01:18:02
内核中Device添加:
1.注册:函数调用
以音频设备注册为例,音频声卡初始化
代码目录:kernel/sound/soc/xxxx.c
1.static int __init audio_card_init(void)
2.{
3. int ret =0;
4. xxxx_snd_device = platform_device_alloc("soc-audio", -1);
5. if (!xxxx_snd_device) {
6. ret = -ENOMEM;
7. return ret;
8. }
9. platform_set_drvdata(xxxx_snd_device, &xxxx_snd_devdata);
10. xxxx_snd_devdata.dev = &xxxx_snd_device->dev;
11. ret = platform_device_add(xxxx_snd_device);
12. if (ret) {
13. platform_device_put(rk2818_snd_device);
14. }
15. return ret;
16.}
2.平台注册
代码目录:kernel/drivers/base/platform.c
1./**
2. * platform_device_add - add a platform device to device hierarchy
3. * @pdev: platform device we're adding
4. *
5. * This is part 2 of platform_device_register(), though may be called
6. * separately _iff_ pdev was allocated by platform_device_alloc().
7. */
8.int platform_device_add(struct platform_device *pdev)
9.{
10. int i, ret = 0;
11.
12. if (!pdev)
13. return -EINVAL;
14.
15. if (!pdev->dev.parent)
16. pdev->dev.parent = &platform_bus;
17.
18. pdev->dev.bus = &platform_bus_type;
19.
20. if (pdev->id != -1)
21. dev_set_name(&pdev->dev, "%s.%d", pdev->name, pdev->id);
22. else
23. dev_set_name(&pdev->dev, "%s", pdev->name);
24.
25. for (i = 0; i < pdev->num_resources; i++) {
26. struct resource *p, *r = &pdev->resource[i];
27.
28. if (r->name == NULL)
29. r->name = dev_name(&pdev->dev);
30.
31. p = r->parent;
32. if (!p) {
33. if (resource_type(r) == IORESOURCE_MEM)
34. p = &iomem_resource;
35. else if (resource_type(r) == IORESOURCE_IO)
36. p = &ioport_resource;
37. }
38.
39. if (p && insert_resource(p, r)) {
40. printk(KERN_ERR
41. "%s: failed to claim resource %d\n",
42. dev_name(&pdev->dev), i);
43. ret = -EBUSY;
44. goto failed;
45. }
46. }
47.
48. pr_debug("Registering platform device '%s'. Parent at %s\n",
49. dev_name(&pdev->dev), dev_name(pdev->dev.parent));
50.
51. ret = device_add(&pdev->dev);
52. if (ret == 0)
53. return ret;
54.
55. failed:
56. while (--i >= 0) {
57. struct resource *r = &pdev->resource[i];
58. unsigned long type = resource_type(r);
59.
60. if (type == IORESOURCE_MEM || type == IORESOURCE_IO)
61. release_resource(r);
62. }
63.
64. return ret;
65.}
66.EXPORT_SYMBOL_GPL(platform_device_add);
3.设备添加
代码目录:kernel/drivers/base/core.c
1./**
2. * device_add - add device to device hierarchy.
3. * @dev: device.
4. *
5. * This is part 2 of device_register(), though may be called
6. * separately _iff_ device_initialize() has been called separately.
7. *
8. * This adds @dev to the kobject hierarchy via kobject_add(), adds it
9. * to the global and sibling lists for the device, then
10. * adds it to the other relevant subsystems of the driver model.
11. *
12. * NOTE: _Never_ directly free @dev after calling this function, even
13. * if it returned an error! Always use put_device() to give up your
14. * reference instead.
15. */
16.int device_add(struct device *dev)
17.{
18. struct device *parent = NULL;
19. struct class_interface *class_intf;
20. int error = -EINVAL;
21.
22. dev = get_device(dev);
23. if (!dev)
24. goto done;
25.
26. if (!dev->p) {
27. error = device_private_init(dev);
28. if (error)
29. goto done;
30. }
31.
32. /*
33. * for statically allocated devices, which should all be converted
34. * some day, we need to initialize the name. We prevent reading back
35. * the name, and force the use of dev_name()
36. */
37. if (dev->init_name) {
38. dev_set_name(dev, "%s", dev->init_name);
39. dev->init_name = NULL;
40. }
41.
42. if (!dev_name(dev))
43. goto name_error;
44.
45. pr_debug("device: '%s': %s\n", dev_name(dev), __func__);
46.
47. parent = get_device(dev->parent);
48. setup_parent(dev, parent);
49.
50. /* use parent numa_node */
51. if (parent)
52. set_dev_node(dev, dev_to_node(parent));
53.
54. /* first, register with generic layer. */
55. /* we require the name to be set before, and pass NULL */
56. error = kobject_add(&dev->kobj, dev->kobj.parent, NULL);
57. if (error)
58. goto Error;
59.
60. /* notify platform of device entry */
61. if (platform_notify)
62. platform_notify(dev);
63.
64. error = device_create_file(dev, &uevent_attr);
65. if (error)
66. goto attrError;
67.
68. if (MAJOR(dev->devt)) {
69. error = device_create_file(dev, &devt_attr);
70. if (error)
71. goto ueventattrError;
72.
73. error = device_create_sys_dev_entry(dev);
74. if (error)
75. goto devtattrError;
76.
77. devtmpfs_create_node(dev);
78. }
79.
80. error = device_add_class_symlinks(dev);
81. if (error)
82. goto SymlinkError;
83. error = device_add_attrs(dev);
84. if (error)
85. goto AttrsError;
86. error = bus_add_device(dev);
87. if (error)
88. goto BusError;
89. error = dpm_sysfs_add(dev);
90. if (error)
91. goto DPMError;
92. device_pm_add(dev);
93.
94. /* Notify clients of device addition. This call must come
95. * after dpm_sysf_add() and before kobject_uevent().
96. */
97. if (dev->bus)
98. blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
99. BUS_NOTIFY_ADD_DEVICE, dev);
100.
101. kobject_uevent(&dev->kobj, KOBJ_ADD);
102. bus_probe_device(dev);
103. if (parent)
104. klist_add_tail(&dev->p->knode_parent,
105. &parent->p->klist_children);
106.
107. if (dev->class) {
108. mutex_lock(&dev->class->p->class_mutex);
109. /* tie the class to the device */
110. klist_add_tail(&dev->knode_class,
111. &dev->class->p->class_devices);
112.
113. /* notify any interfaces that the device is here */
114. list_for_each_entry(class_intf,
115. &dev->class->p->class_interfaces, node)
116. if (class_intf->add_dev)
117. class_intf->add_dev(dev, class_intf);
118. mutex_unlock(&dev->class->p->class_mutex);
119. }
120.done:
121. put_device(dev);
122. return error;
123. DPMError:
124. bus_remove_device(dev);
125. BusError:
126. device_remove_attrs(dev);
127. AttrsError:
128. device_remove_class_symlinks(dev);
129. SymlinkError:
130. if (MAJOR(dev->devt))
131. device_remove_sys_dev_entry(dev);
132. devtattrError:
133. if (MAJOR(dev->devt))
134. device_remove_file(dev, &devt_attr);
135. ueventattrError:
136. device_remove_file(dev, &uevent_attr);
137. attrError:
138. kobject_uevent(&dev->kobj, KOBJ_REMOVE);
139. kobject_del(&dev->kobj);
140. Error:
141. cleanup_device_parent(dev);
142. if (parent)
143. put_device(parent);
144.name_error:
145. kfree(dev->p);
146. dev->p = NULL;
147. goto done;
148.}
4.设备添加到电源管理链表中
代码目录:kernel/drivers/base/main.c
1./**
2. * device_pm_add - Add a device to the PM core's list of active devices.
3. * @dev: Device to add to the list.
4. */
5.void device_pm_add(struct device *dev)
6.{
7. pr_debug("PM: Adding info for %s:%s\n",
8. dev->bus ? dev->bus->name : "No Bus",
9. kobject_name(&dev->kobj));
10. mutex_lock(&dpm_list_mtx);
11. if (dev->parent) {
12. if (dev->parent->power.status >= DPM_SUSPENDING)
13. dev_warn(dev, "parent %s should not be sleeping\n",
14. dev_name(dev->parent));
15. } else if (transition_started) {
16. /*
17. * We refuse to register parentless devices while a PM
18. * transition is in progress in order to avoid leaving them
19. * unhandled down the road
20. */
21. dev_WARN(dev, "Parentless device registered during a PM transaction\n");
22. }
23.
24. list_add_tail(&dev->power.entry, &dpm_list);
25. mutex_unlock(&dpm_list_mtx);
26.}
综上,设备挂到电源管理的函数调用关系是(依次往下调用)
audio_card_init (函数类型包含__init 初始化调用)
platform_device_add
device_add
device_pm_add
list_add_tail(最直接的链表添加操作)
应用:Android休眠
1、state_store 调用 request_suspend_state,
2、然后request_suspend_state 调用early_suspend_work,完成一级休眠工作,
实际操作就是调用使用register_early_suspend注册的设备的suspend handle
比如触摸屏、按键、背光、重力感应等
3、early_suspend完成以后,
在函数末尾调用 wake_unlock(&main_wake_lock),释放掉非超时锁main_wake_lock,
如果应用程序没有不释放的锁了,就会调用到二级睡眠入口函数suspend
4、suspend调用pm_suspend,再调用enter_state,
这里才是真正二级待机的入口了
5、在函数suspend_prepare完成冻结进程成功后,就到了关于非系统设备的suspend函数,
就是suspend_devices_and_enter
6、suspend_devices_and_enter进来以后先关掉控制器,
如果开发人员,此时就不能打出log了,为调试方便可以不关闭控制器;
dpm_suspend_start(PMSG_SUSPEND)就是和本文有关的函数入口了,
它要完成的工作是关闭所有(源代码是全部)非系统设备(non-sysdev),
里面的管理就是用到前面注册添加好的链表了
7、dpm_prepare和dpm_suspend类似,
只是前者是遍历链表置状态位标志status为prepare,调用设备的prepare函数;
后者是遍历链表置状态位标志status为suspend,调用设备的suspend函数
本篇文章来源于 Linux公社网站() 原文链接: