Chinaunix首页 | 论坛 | 博客
  • 博客访问: 287658
  • 博文数量: 68
  • 博客积分: 1121
  • 博客等级: 少尉
  • 技术积分: 634
  • 用 户 组: 普通用户
  • 注册时间: 2011-04-01 09:43
文章分类
文章存档

2014年(1)

2013年(8)

2012年(37)

2011年(22)

分类: 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公社网站()  原文链接:

阅读(2033) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~