~ubuntu-branches/ubuntu/precise/linux-lowlatency/precise

« back to all changes in this revision

Viewing changes to drivers/acpi/container.c

  • Committer: Package Import Robot
  • Author(s): Alessio Igor Bogani
  • Date: 2011-10-26 11:13:05 UTC
  • Revision ID: package-import@ubuntu.com-20111026111305-tz023xykf0i6eosh
Tags: upstream-3.2.0
ImportĀ upstreamĀ versionĀ 3.2.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * acpi_container.c  - ACPI Generic Container Driver
 
3
 * ($Revision: )
 
4
 *
 
5
 * Copyright (C) 2004 Anil S Keshavamurthy (anil.s.keshavamurthy@intel.com)
 
6
 * Copyright (C) 2004 Keiichiro Tokunaga (tokunaga.keiich@jp.fujitsu.com)
 
7
 * Copyright (C) 2004 Motoyuki Ito (motoyuki@soft.fujitsu.com)
 
8
 * Copyright (C) 2004 Intel Corp.
 
9
 * Copyright (C) 2004 FUJITSU LIMITED
 
10
 *
 
11
 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
12
 *
 
13
 *  This program is free software; you can redistribute it and/or modify
 
14
 *  it under the terms of the GNU General Public License as published by
 
15
 *  the Free Software Foundation; either version 2 of the License, or (at
 
16
 *  your option) any later version.
 
17
 *
 
18
 *  This program is distributed in the hope that it will be useful, but
 
19
 *  WITHOUT ANY WARRANTY; without even the implied warranty of
 
20
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
21
 *  General Public License for more details.
 
22
 *
 
23
 *  You should have received a copy of the GNU General Public License along
 
24
 *  with this program; if not, write to the Free Software Foundation, Inc.,
 
25
 *  59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
 
26
 *
 
27
 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
28
 */
 
29
#include <linux/kernel.h>
 
30
#include <linux/module.h>
 
31
#include <linux/init.h>
 
32
#include <linux/slab.h>
 
33
#include <linux/types.h>
 
34
#include <linux/acpi.h>
 
35
#include <acpi/acpi_bus.h>
 
36
#include <acpi/acpi_drivers.h>
 
37
#include <acpi/container.h>
 
38
 
 
39
#define PREFIX "ACPI: "
 
40
 
 
41
#define ACPI_CONTAINER_DEVICE_NAME      "ACPI container device"
 
42
#define ACPI_CONTAINER_CLASS            "container"
 
43
 
 
44
#define INSTALL_NOTIFY_HANDLER          1
 
45
#define UNINSTALL_NOTIFY_HANDLER        2
 
46
 
 
47
#define _COMPONENT                      ACPI_CONTAINER_COMPONENT
 
48
ACPI_MODULE_NAME("container");
 
49
 
 
50
MODULE_AUTHOR("Anil S Keshavamurthy");
 
51
MODULE_DESCRIPTION("ACPI container driver");
 
52
MODULE_LICENSE("GPL");
 
53
 
 
54
static int acpi_container_add(struct acpi_device *device);
 
55
static int acpi_container_remove(struct acpi_device *device, int type);
 
56
 
 
57
static const struct acpi_device_id container_device_ids[] = {
 
58
        {"ACPI0004", 0},
 
59
        {"PNP0A05", 0},
 
60
        {"PNP0A06", 0},
 
61
        {"", 0},
 
62
};
 
63
MODULE_DEVICE_TABLE(acpi, container_device_ids);
 
64
 
 
65
static struct acpi_driver acpi_container_driver = {
 
66
        .name = "container",
 
67
        .class = ACPI_CONTAINER_CLASS,
 
68
        .ids = container_device_ids,
 
69
        .ops = {
 
70
                .add = acpi_container_add,
 
71
                .remove = acpi_container_remove,
 
72
                },
 
73
};
 
74
 
 
75
/*******************************************************************/
 
76
 
 
77
static int is_device_present(acpi_handle handle)
 
78
{
 
79
        acpi_handle temp;
 
80
        acpi_status status;
 
81
        unsigned long long sta;
 
82
 
 
83
 
 
84
        status = acpi_get_handle(handle, "_STA", &temp);
 
85
        if (ACPI_FAILURE(status))
 
86
                return 1;       /* _STA not found, assume device present */
 
87
 
 
88
        status = acpi_evaluate_integer(handle, "_STA", NULL, &sta);
 
89
        if (ACPI_FAILURE(status))
 
90
                return 0;       /* Firmware error */
 
91
 
 
92
        return ((sta & ACPI_STA_DEVICE_PRESENT) == ACPI_STA_DEVICE_PRESENT);
 
93
}
 
94
 
 
95
/*******************************************************************/
 
96
static int acpi_container_add(struct acpi_device *device)
 
97
{
 
98
        struct acpi_container *container;
 
99
 
 
100
 
 
101
        if (!device) {
 
102
                printk(KERN_ERR PREFIX "device is NULL\n");
 
103
                return -EINVAL;
 
104
        }
 
105
 
 
106
        container = kzalloc(sizeof(struct acpi_container), GFP_KERNEL);
 
107
        if (!container)
 
108
                return -ENOMEM;
 
109
 
 
110
        container->handle = device->handle;
 
111
        strcpy(acpi_device_name(device), ACPI_CONTAINER_DEVICE_NAME);
 
112
        strcpy(acpi_device_class(device), ACPI_CONTAINER_CLASS);
 
113
        device->driver_data = container;
 
114
 
 
115
        ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device <%s> bid <%s>\n",
 
116
                          acpi_device_name(device), acpi_device_bid(device)));
 
117
 
 
118
        return 0;
 
119
}
 
120
 
 
121
static int acpi_container_remove(struct acpi_device *device, int type)
 
122
{
 
123
        acpi_status status = AE_OK;
 
124
        struct acpi_container *pc = NULL;
 
125
 
 
126
        pc = acpi_driver_data(device);
 
127
        kfree(pc);
 
128
        return status;
 
129
}
 
130
 
 
131
static int container_device_add(struct acpi_device **device, acpi_handle handle)
 
132
{
 
133
        acpi_handle phandle;
 
134
        struct acpi_device *pdev;
 
135
        int result;
 
136
 
 
137
 
 
138
        if (acpi_get_parent(handle, &phandle)) {
 
139
                return -ENODEV;
 
140
        }
 
141
 
 
142
        if (acpi_bus_get_device(phandle, &pdev)) {
 
143
                return -ENODEV;
 
144
        }
 
145
 
 
146
        if (acpi_bus_add(device, pdev, handle, ACPI_BUS_TYPE_DEVICE)) {
 
147
                return -ENODEV;
 
148
        }
 
149
 
 
150
        result = acpi_bus_start(*device);
 
151
 
 
152
        return result;
 
153
}
 
154
 
 
155
static void container_notify_cb(acpi_handle handle, u32 type, void *context)
 
156
{
 
157
        struct acpi_device *device = NULL;
 
158
        int result;
 
159
        int present;
 
160
        acpi_status status;
 
161
 
 
162
 
 
163
        present = is_device_present(handle);
 
164
 
 
165
        switch (type) {
 
166
        case ACPI_NOTIFY_BUS_CHECK:
 
167
                /* Fall through */
 
168
        case ACPI_NOTIFY_DEVICE_CHECK:
 
169
                printk(KERN_WARNING "Container driver received %s event\n",
 
170
                       (type == ACPI_NOTIFY_BUS_CHECK) ?
 
171
                       "ACPI_NOTIFY_BUS_CHECK" : "ACPI_NOTIFY_DEVICE_CHECK");
 
172
                status = acpi_bus_get_device(handle, &device);
 
173
                if (present) {
 
174
                        if (ACPI_FAILURE(status) || !device) {
 
175
                                result = container_device_add(&device, handle);
 
176
                                if (!result)
 
177
                                        kobject_uevent(&device->dev.kobj,
 
178
                                                       KOBJ_ONLINE);
 
179
                                else
 
180
                                        printk(KERN_WARNING
 
181
                                               "Failed to add container\n");
 
182
                        }
 
183
                } else {
 
184
                        if (ACPI_SUCCESS(status)) {
 
185
                                /* device exist and this is a remove request */
 
186
                                kobject_uevent(&device->dev.kobj, KOBJ_OFFLINE);
 
187
                        }
 
188
                }
 
189
                break;
 
190
        case ACPI_NOTIFY_EJECT_REQUEST:
 
191
                if (!acpi_bus_get_device(handle, &device) && device) {
 
192
                        kobject_uevent(&device->dev.kobj, KOBJ_OFFLINE);
 
193
                }
 
194
                break;
 
195
        default:
 
196
                break;
 
197
        }
 
198
        return;
 
199
}
 
200
 
 
201
static acpi_status
 
202
container_walk_namespace_cb(acpi_handle handle,
 
203
                            u32 lvl, void *context, void **rv)
 
204
{
 
205
        char *hid = NULL;
 
206
        struct acpi_device_info *info;
 
207
        acpi_status status;
 
208
        int *action = context;
 
209
 
 
210
        status = acpi_get_object_info(handle, &info);
 
211
        if (ACPI_FAILURE(status)) {
 
212
                return AE_OK;
 
213
        }
 
214
 
 
215
        if (info->valid & ACPI_VALID_HID)
 
216
                hid = info->hardware_id.string;
 
217
 
 
218
        if (hid == NULL) {
 
219
                goto end;
 
220
        }
 
221
 
 
222
        if (strcmp(hid, "ACPI0004") && strcmp(hid, "PNP0A05") &&
 
223
            strcmp(hid, "PNP0A06")) {
 
224
                goto end;
 
225
        }
 
226
 
 
227
        switch (*action) {
 
228
        case INSTALL_NOTIFY_HANDLER:
 
229
                acpi_install_notify_handler(handle,
 
230
                                            ACPI_SYSTEM_NOTIFY,
 
231
                                            container_notify_cb, NULL);
 
232
                break;
 
233
        case UNINSTALL_NOTIFY_HANDLER:
 
234
                acpi_remove_notify_handler(handle,
 
235
                                           ACPI_SYSTEM_NOTIFY,
 
236
                                           container_notify_cb);
 
237
                break;
 
238
        default:
 
239
                break;
 
240
        }
 
241
 
 
242
      end:
 
243
        kfree(info);
 
244
 
 
245
        return AE_OK;
 
246
}
 
247
 
 
248
static int __init acpi_container_init(void)
 
249
{
 
250
        int result = 0;
 
251
        int action = INSTALL_NOTIFY_HANDLER;
 
252
 
 
253
        result = acpi_bus_register_driver(&acpi_container_driver);
 
254
        if (result < 0) {
 
255
                return (result);
 
256
        }
 
257
 
 
258
        /* register notify handler to every container device */
 
259
        acpi_walk_namespace(ACPI_TYPE_DEVICE,
 
260
                            ACPI_ROOT_OBJECT,
 
261
                            ACPI_UINT32_MAX,
 
262
                            container_walk_namespace_cb, NULL, &action, NULL);
 
263
 
 
264
        return (0);
 
265
}
 
266
 
 
267
static void __exit acpi_container_exit(void)
 
268
{
 
269
        int action = UNINSTALL_NOTIFY_HANDLER;
 
270
 
 
271
 
 
272
        acpi_walk_namespace(ACPI_TYPE_DEVICE,
 
273
                            ACPI_ROOT_OBJECT,
 
274
                            ACPI_UINT32_MAX,
 
275
                            container_walk_namespace_cb, NULL, &action, NULL);
 
276
 
 
277
        acpi_bus_unregister_driver(&acpi_container_driver);
 
278
 
 
279
        return;
 
280
}
 
281
 
 
282
module_init(acpi_container_init);
 
283
module_exit(acpi_container_exit);