Rev 1867 | Only display areas with differences | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 1867 | Rev 9499 | ||
---|---|---|---|
1 | #include |
1 | #include |
2 | #include |
2 | #include |
3 | #include |
3 | #include |
4 | #include |
4 | #include |
5 | #include |
5 | #include |
6 | 6 | ||
7 | #include "acpi.h" |
7 | #include "acpi.h" |
8 | #include "acpi_bus.h" |
8 | #include "acpi_bus.h" |
9 | 9 | ||
10 | 10 | ||
11 | #define PREFIX "ACPI: " |
11 | #define PREFIX "ACPI: " |
12 | 12 | ||
13 | #define ACPI_BUS_CLASS "system_bus" |
13 | #define ACPI_BUS_CLASS "system_bus" |
14 | #define ACPI_BUS_HID "KLBSYBUS" |
14 | #define ACPI_BUS_HID "KLBSYBUS" |
15 | #define ACPI_BUS_DEVICE_NAME "System Bus" |
15 | #define ACPI_BUS_DEVICE_NAME "System Bus" |
16 | 16 | ||
17 | 17 | ||
18 | #define ACPI_IS_ROOT_DEVICE(device) (!(device)->parent) |
18 | #define ACPI_IS_ROOT_DEVICE(device) (!(device)->parent) |
19 | 19 | ||
20 | #define STRUCT_TO_INT(s) (*((int*)&s)) |
20 | #define STRUCT_TO_INT(s) (*((int*)&s)) |
21 | 21 | ||
22 | 22 | ||
23 | extern struct acpi_device *acpi_root; |
23 | extern struct acpi_device *acpi_root; |
24 | 24 | ||
25 | extern struct list_head acpi_device_list; |
25 | extern struct list_head acpi_device_list; |
26 | extern struct list_head acpi_bus_id_list; |
26 | extern struct list_head acpi_bus_id_list; |
27 | 27 | ||
28 | DEFINE_MUTEX(acpi_device_lock); |
28 | DEFINE_MUTEX(acpi_device_lock); |
29 | 29 | ||
30 | 30 | ||
31 | struct acpi_device_bus_id{ |
31 | struct acpi_device_bus_id{ |
32 | char bus_id[15]; |
32 | char bus_id[15]; |
33 | unsigned int instance_no; |
33 | unsigned int instance_no; |
34 | struct list_head node; |
34 | struct list_head node; |
35 | }; |
35 | }; |
36 | 36 | ||
37 | 37 | ||
38 | struct acpi_hardware_id { |
38 | struct acpi_hardware_id { |
39 | struct list_head list; |
39 | struct list_head list; |
40 | char *id; |
40 | char *id; |
41 | }; |
41 | }; |
42 | 42 | ||
43 | #define acpi_device_name(d) ((d)->pnp.device_name) |
43 | #define acpi_device_name(d) ((d)->pnp.device_name) |
44 | #define acpi_device_class(d) ((d)->pnp.device_class) |
44 | #define acpi_device_class(d) ((d)->pnp.device_class) |
45 | 45 | ||
46 | 46 | ||
47 | static void |
47 | static void |
48 | acpi_util_eval_error(ACPI_HANDLE h, ACPI_STRING p, ACPI_STATUS s) |
48 | acpi_util_eval_error(ACPI_HANDLE h, ACPI_STRING p, ACPI_STATUS s) |
49 | { |
49 | { |
50 | #ifdef ACPI_DEBUG_OUTPUT |
50 | #ifdef ACPI_DEBUG_OUTPUT |
51 | char prefix[80] = {'\0'}; |
51 | char prefix[80] = {'\0'}; |
52 | ACPI_BUFFER buffer = {sizeof(prefix), prefix}; |
52 | ACPI_BUFFER buffer = {sizeof(prefix), prefix}; |
53 | AcpiGetName(h, ACPI_FULL_PATHNAME, &buffer); |
53 | AcpiGetName(h, ACPI_FULL_PATHNAME, &buffer); |
54 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Evaluate [%s.%s]: %s\n", |
54 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Evaluate [%s.%s]: %s\n", |
55 | (char *) prefix, p, AcpiFormatException(s))); |
55 | (char *) prefix, p, AcpiFormatException(s))); |
56 | #else |
56 | #else |
57 | return; |
57 | return; |
58 | #endif |
58 | #endif |
59 | } |
59 | } |
60 | 60 | ||
61 | ACPI_STATUS |
61 | ACPI_STATUS |
62 | acpi_evaluate_integer(ACPI_HANDLE handle, ACPI_STRING pathname, |
62 | acpi_evaluate_integer(ACPI_HANDLE handle, ACPI_STRING pathname, |
63 | ACPI_OBJECT_LIST *arguments, unsigned long long *data) |
63 | ACPI_OBJECT_LIST *arguments, unsigned long long *data) |
64 | { |
64 | { |
65 | ACPI_STATUS status = AE_OK; |
65 | ACPI_STATUS status = AE_OK; |
66 | ACPI_OBJECT element; |
66 | ACPI_OBJECT element; |
67 | ACPI_BUFFER buffer = { 0, NULL }; |
67 | ACPI_BUFFER buffer = { 0, NULL }; |
68 | 68 | ||
69 | if (!data) |
69 | if (!data) |
70 | return AE_BAD_PARAMETER; |
70 | return AE_BAD_PARAMETER; |
71 | 71 | ||
72 | buffer.Length = sizeof(ACPI_OBJECT); |
72 | buffer.Length = sizeof(ACPI_OBJECT); |
73 | buffer.Pointer = &element; |
73 | buffer.Pointer = &element; |
74 | status = AcpiEvaluateObject(handle, pathname, arguments, &buffer); |
74 | status = AcpiEvaluateObject(handle, pathname, arguments, &buffer); |
75 | if (ACPI_FAILURE(status)) { |
75 | if (ACPI_FAILURE(status)) { |
76 | acpi_util_eval_error(handle, pathname, status); |
76 | acpi_util_eval_error(handle, pathname, status); |
77 | return status; |
77 | return status; |
78 | } |
78 | } |
79 | 79 | ||
80 | if (element.Type != ACPI_TYPE_INTEGER) { |
80 | if (element.Type != ACPI_TYPE_INTEGER) { |
81 | acpi_util_eval_error(handle, pathname, AE_BAD_DATA); |
81 | acpi_util_eval_error(handle, pathname, AE_BAD_DATA); |
82 | return AE_BAD_DATA; |
82 | return AE_BAD_DATA; |
83 | } |
83 | } |
84 | 84 | ||
85 | *data = element.Integer.Value; |
85 | *data = element.Integer.Value; |
86 | 86 | ||
87 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Return value [%llu]\n", *data)); |
87 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Return value [%llu]\n", *data)); |
88 | 88 | ||
89 | return AE_OK; |
89 | return AE_OK; |
90 | } |
90 | } |
91 | 91 | ||
92 | 92 | ||
93 | void acpi_bus_data_handler(ACPI_HANDLE handle, void *context) |
93 | void acpi_bus_data_handler(ACPI_HANDLE handle, void *context) |
94 | { |
94 | { |
95 | 95 | ||
96 | /* TBD */ |
96 | /* TBD */ |
97 | 97 | ||
98 | return; |
98 | return; |
99 | } |
99 | } |
100 | 100 | ||
101 | int acpi_bus_get_device(ACPI_HANDLE handle, struct acpi_device **device) |
101 | int acpi_bus_get_device(ACPI_HANDLE handle, struct acpi_device **device) |
102 | { |
102 | { |
103 | ACPI_STATUS status = AE_OK; |
103 | ACPI_STATUS status = AE_OK; |
104 | 104 | ||
105 | if (!device) |
105 | if (!device) |
106 | { |
106 | { |
107 | return -EINVAL; |
107 | return -EINVAL; |
108 | }; |
108 | }; |
109 | 109 | ||
110 | /* TBD: Support fixed-feature devices */ |
110 | /* TBD: Support fixed-feature devices */ |
111 | 111 | ||
112 | status = AcpiGetData(handle, acpi_bus_data_handler, (void **)device); |
112 | status = AcpiGetData(handle, acpi_bus_data_handler, (void **)device); |
113 | if (ACPI_FAILURE(status) || !*device) { |
113 | if (ACPI_FAILURE(status) || !*device) { |
114 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No context for object [%p]\n", |
114 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No context for object [%p]\n", |
115 | handle)); |
115 | handle)); |
116 | return -ENODEV; |
116 | return -ENODEV; |
117 | } |
117 | } |
118 | return 0; |
118 | return 0; |
119 | } |
119 | } |
120 | 120 | ||
121 | 121 | ||
122 | ACPI_STATUS acpi_bus_get_status_handle(ACPI_HANDLE handle, |
122 | ACPI_STATUS acpi_bus_get_status_handle(ACPI_HANDLE handle, |
123 | unsigned long long *sta) |
123 | unsigned long long *sta) |
124 | { |
124 | { |
125 | ACPI_STATUS status; |
125 | ACPI_STATUS status; |
126 | 126 | ||
127 | status = acpi_evaluate_integer(handle, "_STA", NULL, sta); |
127 | status = acpi_evaluate_integer(handle, "_STA", NULL, sta); |
128 | if (ACPI_SUCCESS(status)) |
128 | if (ACPI_SUCCESS(status)) |
129 | { |
129 | { |
130 | return AE_OK; |
130 | return AE_OK; |
131 | }; |
131 | }; |
132 | 132 | ||
133 | if (status == AE_NOT_FOUND) |
133 | if (status == AE_NOT_FOUND) |
134 | { |
134 | { |
135 | *sta = ACPI_STA_DEVICE_PRESENT | ACPI_STA_DEVICE_ENABLED | |
135 | *sta = ACPI_STA_DEVICE_PRESENT | ACPI_STA_DEVICE_ENABLED | |
136 | ACPI_STA_DEVICE_UI | ACPI_STA_DEVICE_FUNCTIONING; |
136 | ACPI_STA_DEVICE_UI | ACPI_STA_DEVICE_FUNCTIONING; |
137 | return AE_OK; |
137 | return AE_OK; |
138 | } |
138 | } |
139 | return status; |
139 | return status; |
140 | } |
140 | } |
141 | 141 | ||
142 | 142 | ||
143 | 143 | ||
144 | /* -------------------------------------------------------------------------- |
144 | /* -------------------------------------------------------------------------- |
145 | ACPI Bus operations |
145 | ACPI Bus operations |
146 | -------------------------------------------------------------------------- */ |
146 | -------------------------------------------------------------------------- */ |
147 | 147 | ||
148 | int acpi_match_device_ids(struct acpi_device *device, |
148 | int acpi_match_device_ids(struct acpi_device *device, |
149 | const struct acpi_device_ids *ids) |
149 | const struct acpi_device_ids *ids) |
150 | { |
150 | { |
151 | const struct acpi_device_ids *id; |
151 | const struct acpi_device_ids *id; |
152 | struct acpi_hardware_id *hwid; |
152 | struct acpi_hardware_id *hwid; |
153 | 153 | ||
154 | /* |
154 | /* |
155 | * If the device is not present, it is unnecessary to load device |
155 | * If the device is not present, it is unnecessary to load device |
156 | * driver for it. |
156 | * driver for it. |
157 | */ |
157 | */ |
158 | // if (!device->status.present) |
158 | // if (!device->status.present) |
159 | // return -ENODEV; |
159 | // return -ENODEV; |
160 | 160 | ||
161 | for (id = ids; id->id[0]; id++) |
161 | for (id = ids; id->id[0]; id++) |
162 | list_for_each_entry(hwid, &device->pnp.ids, list) |
162 | list_for_each_entry(hwid, &device->pnp.ids, list) |
163 | if (!strcmp((char *) id->id, hwid->id)) |
163 | if (!strcmp((char *) id->id, hwid->id)) |
164 | return 0; |
164 | return 0; |
165 | 165 | ||
166 | return -ENOENT; |
166 | return -ENOENT; |
167 | } |
167 | } |
168 | 168 | ||
169 | 169 | ||
170 | static int acpi_device_register(struct acpi_device *device) |
170 | static int acpi_device_register(struct acpi_device *device) |
171 | { |
171 | { |
172 | int result; |
172 | int result; |
173 | struct acpi_device_bus_id *acpi_device_bus_id, *new_bus_id; |
173 | struct acpi_device_bus_id *acpi_device_bus_id, *new_bus_id; |
174 | int found = 0; |
174 | int found = 0; |
175 | 175 | ||
176 | /* |
176 | /* |
177 | * Linkage |
177 | * Linkage |
178 | * ------- |
178 | * ------- |
179 | * Link this device to its parent and siblings. |
179 | * Link this device to its parent and siblings. |
180 | */ |
180 | */ |
181 | INIT_LIST_HEAD(&device->children); |
181 | INIT_LIST_HEAD(&device->children); |
182 | INIT_LIST_HEAD(&device->node); |
182 | INIT_LIST_HEAD(&device->node); |
183 | 183 | ||
184 | new_bus_id = kzalloc(sizeof(struct acpi_device_bus_id), GFP_KERNEL); |
184 | new_bus_id = kzalloc(sizeof(struct acpi_device_bus_id), GFP_KERNEL); |
185 | if (!new_bus_id) { |
185 | if (!new_bus_id) { |
186 | printk(KERN_ERR PREFIX "Memory allocation error\n"); |
186 | printk(KERN_ERR PREFIX "Memory allocation error\n"); |
187 | return -ENOMEM; |
187 | return -ENOMEM; |
188 | } |
188 | } |
189 | 189 | ||
190 | mutex_lock(&acpi_device_lock); |
190 | mutex_lock(&acpi_device_lock); |
191 | /* |
191 | /* |
192 | * Find suitable bus_id and instance number in acpi_bus_id_list |
192 | * Find suitable bus_id and instance number in acpi_bus_id_list |
193 | * If failed, create one and link it into acpi_bus_id_list |
193 | * If failed, create one and link it into acpi_bus_id_list |
194 | */ |
194 | */ |
195 | list_for_each_entry(acpi_device_bus_id, &acpi_bus_id_list, node) |
195 | list_for_each_entry(acpi_device_bus_id, &acpi_bus_id_list, node) |
196 | { |
196 | { |
197 | if (!strcmp(acpi_device_bus_id->bus_id, |
197 | if (!strcmp(acpi_device_bus_id->bus_id, |
198 | acpi_device_hid(device))) |
198 | acpi_device_hid(device))) |
199 | { |
199 | { |
200 | acpi_device_bus_id->instance_no++; |
200 | acpi_device_bus_id->instance_no++; |
201 | found = 1; |
201 | found = 1; |
202 | kfree(new_bus_id); |
202 | kfree(new_bus_id); |
203 | break; |
203 | break; |
204 | } |
204 | } |
205 | }; |
205 | }; |
206 | 206 | ||
207 | if (!found) |
207 | if (!found) |
208 | { |
208 | { |
209 | acpi_device_bus_id = new_bus_id; |
209 | acpi_device_bus_id = new_bus_id; |
210 | strcpy(acpi_device_bus_id->bus_id, acpi_device_hid(device)); |
210 | strcpy(acpi_device_bus_id->bus_id, acpi_device_hid(device)); |
211 | acpi_device_bus_id->instance_no = 0; |
211 | acpi_device_bus_id->instance_no = 0; |
212 | list_add_tail(&acpi_device_bus_id->node, &acpi_bus_id_list); |
212 | list_add_tail(&acpi_device_bus_id->node, &acpi_bus_id_list); |
213 | } |
213 | } |
214 | 214 | ||
215 | // dev_set_name(&device->dev, "%s:%02x", acpi_device_bus_id->bus_id, acpi_device_bus_id->instance_no); |
215 | // dev_set_name(&device->dev, "%s:%02x", acpi_device_bus_id->bus_id, acpi_device_bus_id->instance_no); |
216 | 216 | ||
217 | if (device->parent) |
217 | if (device->parent) |
218 | list_add_tail(&device->node, &device->parent->children); |
218 | list_add_tail(&device->node, &device->parent->children); |
219 | 219 | ||
220 | mutex_unlock(&acpi_device_lock); |
220 | mutex_unlock(&acpi_device_lock); |
221 | 221 | ||
222 | // device->dev.bus = &acpi_bus_type; |
222 | // device->dev.bus = &acpi_bus_type; |
223 | // device->dev.release = &acpi_device_release; |
223 | // device->dev.release = &acpi_device_release; |
224 | // result = device_register(&device->dev); |
224 | // result = device_register(&device->dev); |
225 | // if (result) { |
225 | // if (result) { |
226 | // dev_err(&device->dev, "Error registering device\n"); |
226 | // dev_err(&device->dev, "Error registering device\n"); |
227 | // goto end; |
227 | // goto end; |
228 | // } |
228 | // } |
229 | 229 | ||
230 | 230 | ||
231 | // device->removal_type = ACPI_BUS_REMOVAL_NORMAL; |
231 | // device->removal_type = ACPI_BUS_REMOVAL_NORMAL; |
232 | return 0; |
232 | return 0; |
233 | end: |
233 | end: |
234 | mutex_lock(&acpi_device_lock); |
234 | mutex_lock(&acpi_device_lock); |
235 | if (device->parent) |
235 | if (device->parent) |
236 | list_del(&device->node); |
236 | list_del(&device->node); |
237 | mutex_unlock(&acpi_device_lock); |
237 | mutex_unlock(&acpi_device_lock); |
238 | return result; |
238 | return result; |
239 | } |
239 | } |
240 | 240 | ||
241 | 241 | ||
242 | static struct acpi_device *acpi_bus_get_parent(ACPI_HANDLE handle) |
242 | static struct acpi_device *acpi_bus_get_parent(ACPI_HANDLE handle) |
243 | { |
243 | { |
244 | ACPI_STATUS status; |
244 | ACPI_STATUS status; |
245 | struct acpi_device *device; |
245 | struct acpi_device *device; |
246 | int ret; |
246 | int ret; |
247 | 247 | ||
248 | /* |
248 | /* |
249 | * Fixed hardware devices do not appear in the namespace and do not |
249 | * Fixed hardware devices do not appear in the namespace and do not |
250 | * have handles, but we fabricate acpi_devices for them, so we have |
250 | * have handles, but we fabricate acpi_devices for them, so we have |
251 | * to deal with them specially. |
251 | * to deal with them specially. |
252 | */ |
252 | */ |
253 | if (handle == NULL) |
253 | if (handle == NULL) |
254 | return acpi_root; |
254 | return acpi_root; |
255 | 255 | ||
256 | do { |
256 | do { |
257 | status = AcpiGetParent(handle, &handle); |
257 | status = AcpiGetParent(handle, &handle); |
258 | if (status == AE_NULL_ENTRY) |
258 | if (status == AE_NULL_ENTRY) |
259 | return NULL; |
259 | return NULL; |
260 | if (ACPI_FAILURE(status)) |
260 | if (ACPI_FAILURE(status)) |
261 | return acpi_root; |
261 | return acpi_root; |
262 | 262 | ||
263 | ret = acpi_bus_get_device(handle, &device); |
263 | ret = acpi_bus_get_device(handle, &device); |
264 | if (ret == 0) |
264 | if (ret == 0) |
265 | return device; |
265 | return device; |
266 | } while (1); |
266 | } while (1); |
267 | } |
267 | } |
268 | 268 | ||
269 | 269 | ||
270 | static int acpi_bus_get_flags(struct acpi_device *device) |
270 | static int acpi_bus_get_flags(struct acpi_device *device) |
271 | { |
271 | { |
272 | ACPI_STATUS status = AE_OK; |
272 | ACPI_STATUS status = AE_OK; |
273 | ACPI_HANDLE temp = NULL; |
273 | ACPI_HANDLE temp = NULL; |
274 | 274 | ||
275 | /* Presence of _STA indicates 'dynamic_status' */ |
275 | /* Presence of _STA indicates 'dynamic_status' */ |
276 | status = AcpiGetHandle(device->handle, "_STA", &temp); |
276 | status = AcpiGetHandle(device->handle, "_STA", &temp); |
277 | if (ACPI_SUCCESS(status)) |
277 | if (ACPI_SUCCESS(status)) |
278 | device->flags.dynamic_status = 1; |
278 | device->flags.dynamic_status = 1; |
279 | 279 | ||
280 | /* Presence of _RMV indicates 'removable' */ |
280 | /* Presence of _RMV indicates 'removable' */ |
281 | status = AcpiGetHandle(device->handle, "_RMV", &temp); |
281 | status = AcpiGetHandle(device->handle, "_RMV", &temp); |
282 | if (ACPI_SUCCESS(status)) |
282 | if (ACPI_SUCCESS(status)) |
283 | device->flags.removable = 1; |
283 | device->flags.removable = 1; |
284 | 284 | ||
285 | /* Presence of _EJD|_EJ0 indicates 'ejectable' */ |
285 | /* Presence of _EJD|_EJ0 indicates 'ejectable' */ |
286 | status = AcpiGetHandle(device->handle, "_EJD", &temp); |
286 | status = AcpiGetHandle(device->handle, "_EJD", &temp); |
287 | if (ACPI_SUCCESS(status)) |
287 | if (ACPI_SUCCESS(status)) |
288 | device->flags.ejectable = 1; |
288 | device->flags.ejectable = 1; |
289 | else { |
289 | else { |
290 | status = AcpiGetHandle(device->handle, "_EJ0", &temp); |
290 | status = AcpiGetHandle(device->handle, "_EJ0", &temp); |
291 | if (ACPI_SUCCESS(status)) |
291 | if (ACPI_SUCCESS(status)) |
292 | device->flags.ejectable = 1; |
292 | device->flags.ejectable = 1; |
293 | } |
293 | } |
294 | 294 | ||
295 | /* Presence of _LCK indicates 'lockable' */ |
295 | /* Presence of _LCK indicates 'lockable' */ |
296 | status = AcpiGetHandle(device->handle, "_LCK", &temp); |
296 | status = AcpiGetHandle(device->handle, "_LCK", &temp); |
297 | if (ACPI_SUCCESS(status)) |
297 | if (ACPI_SUCCESS(status)) |
298 | device->flags.lockable = 1; |
298 | device->flags.lockable = 1; |
299 | 299 | ||
300 | /* Presence of _PS0|_PR0 indicates 'power manageable' */ |
300 | /* Presence of _PS0|_PR0 indicates 'power manageable' */ |
301 | status = AcpiGetHandle(device->handle, "_PS0", &temp); |
301 | status = AcpiGetHandle(device->handle, "_PS0", &temp); |
302 | if (ACPI_FAILURE(status)) |
302 | if (ACPI_FAILURE(status)) |
303 | status = AcpiGetHandle(device->handle, "_PR0", &temp); |
303 | status = AcpiGetHandle(device->handle, "_PR0", &temp); |
304 | if (ACPI_SUCCESS(status)) |
304 | if (ACPI_SUCCESS(status)) |
305 | device->flags.power_manageable = 1; |
305 | device->flags.power_manageable = 1; |
306 | 306 | ||
307 | /* Presence of _PRW indicates wake capable */ |
307 | /* Presence of _PRW indicates wake capable */ |
308 | status = AcpiGetHandle(device->handle, "_PRW", &temp); |
308 | status = AcpiGetHandle(device->handle, "_PRW", &temp); |
309 | if (ACPI_SUCCESS(status)) |
309 | if (ACPI_SUCCESS(status)) |
310 | device->flags.wake_capable = 1; |
310 | device->flags.wake_capable = 1; |
311 | 311 | ||
312 | /* TBD: Performance management */ |
312 | /* TBD: Performance management */ |
313 | 313 | ||
314 | return 0; |
314 | return 0; |
315 | } |
315 | } |
316 | 316 | ||
317 | static void acpi_device_get_busid(struct acpi_device *device) |
317 | static void acpi_device_get_busid(struct acpi_device *device) |
318 | { |
318 | { |
319 | char bus_id[5] = { '?', 0 }; |
319 | char bus_id[5] = { '?', 0 }; |
320 | struct acpi_buffer buffer = { sizeof(bus_id), bus_id }; |
320 | struct acpi_buffer buffer = { sizeof(bus_id), bus_id }; |
321 | int i = 0; |
321 | int i = 0; |
322 | 322 | ||
323 | /* |
323 | /* |
324 | * Bus ID |
324 | * Bus ID |
325 | * ------ |
325 | * ------ |
326 | * The device's Bus ID is simply the object name. |
326 | * The device's Bus ID is simply the object name. |
327 | * TBD: Shouldn't this value be unique (within the ACPI namespace)? |
327 | * TBD: Shouldn't this value be unique (within the ACPI namespace)? |
328 | */ |
328 | */ |
329 | if (ACPI_IS_ROOT_DEVICE(device)) { |
329 | if (ACPI_IS_ROOT_DEVICE(device)) { |
330 | strcpy(device->pnp.bus_id, "ACPI"); |
330 | strcpy(device->pnp.bus_id, "ACPI"); |
331 | return; |
331 | return; |
332 | } |
332 | } |
333 | 333 | ||
334 | switch (device->device_type) |
334 | switch (device->device_type) |
335 | { |
335 | { |
336 | case ACPI_BUS_TYPE_POWER_BUTTON: |
336 | case ACPI_BUS_TYPE_POWER_BUTTON: |
337 | strcpy(device->pnp.bus_id, "PWRF"); |
337 | strcpy(device->pnp.bus_id, "PWRF"); |
338 | break; |
338 | break; |
339 | case ACPI_BUS_TYPE_SLEEP_BUTTON: |
339 | case ACPI_BUS_TYPE_SLEEP_BUTTON: |
340 | strcpy(device->pnp.bus_id, "SLPF"); |
340 | strcpy(device->pnp.bus_id, "SLPF"); |
341 | break; |
341 | break; |
342 | default: |
342 | default: |
343 | AcpiGetName(device->handle, ACPI_SINGLE_NAME, &buffer); |
343 | AcpiGetName(device->handle, ACPI_SINGLE_NAME, &buffer); |
344 | /* Clean up trailing underscores (if any) */ |
344 | /* Clean up trailing underscores (if any) */ |
345 | for (i = 3; i > 1; i--) { |
345 | for (i = 3; i > 1; i--) { |
346 | if (bus_id[i] == '_') |
346 | if (bus_id[i] == '_') |
347 | bus_id[i] = '\0'; |
347 | bus_id[i] = '\0'; |
348 | else |
348 | else |
349 | break; |
349 | break; |
350 | } |
350 | } |
351 | strcpy(device->pnp.bus_id, bus_id); |
351 | strcpy(device->pnp.bus_id, bus_id); |
352 | break; |
352 | break; |
353 | } |
353 | } |
354 | } |
354 | } |
355 | 355 | ||
356 | 356 | ||
357 | #define ACPI_VIDEO_OUTPUT_SWITCHING 0x0001 |
357 | #define ACPI_VIDEO_OUTPUT_SWITCHING 0x0001 |
358 | #define ACPI_VIDEO_DEVICE_POSTING 0x0002 |
358 | #define ACPI_VIDEO_DEVICE_POSTING 0x0002 |
359 | #define ACPI_VIDEO_ROM_AVAILABLE 0x0004 |
359 | #define ACPI_VIDEO_ROM_AVAILABLE 0x0004 |
360 | #define ACPI_VIDEO_BACKLIGHT 0x0008 |
360 | #define ACPI_VIDEO_BACKLIGHT 0x0008 |
361 | #define ACPI_VIDEO_BACKLIGHT_FORCE_VENDOR 0x0010 |
361 | #define ACPI_VIDEO_BACKLIGHT_FORCE_VENDOR 0x0010 |
362 | #define ACPI_VIDEO_BACKLIGHT_FORCE_VIDEO 0x0020 |
362 | #define ACPI_VIDEO_BACKLIGHT_FORCE_VIDEO 0x0020 |
363 | #define ACPI_VIDEO_OUTPUT_SWITCHING_FORCE_VENDOR 0x0040 |
363 | #define ACPI_VIDEO_OUTPUT_SWITCHING_FORCE_VENDOR 0x0040 |
364 | #define ACPI_VIDEO_OUTPUT_SWITCHING_FORCE_VIDEO 0x0080 |
364 | #define ACPI_VIDEO_OUTPUT_SWITCHING_FORCE_VIDEO 0x0080 |
365 | #define ACPI_VIDEO_BACKLIGHT_DMI_VENDOR 0x0100 |
365 | #define ACPI_VIDEO_BACKLIGHT_DMI_VENDOR 0x0100 |
366 | #define ACPI_VIDEO_BACKLIGHT_DMI_VIDEO 0x0200 |
366 | #define ACPI_VIDEO_BACKLIGHT_DMI_VIDEO 0x0200 |
367 | #define ACPI_VIDEO_OUTPUT_SWITCHING_DMI_VENDOR 0x0400 |
367 | #define ACPI_VIDEO_OUTPUT_SWITCHING_DMI_VENDOR 0x0400 |
368 | #define ACPI_VIDEO_OUTPUT_SWITCHING_DMI_VIDEO 0x0800 |
368 | #define ACPI_VIDEO_OUTPUT_SWITCHING_DMI_VIDEO 0x0800 |
369 | 369 | ||
370 | 370 | ||
371 | long acpi_is_video_device(struct acpi_device *device) |
371 | long acpi_is_video_device(struct acpi_device *device) |
372 | { |
372 | { |
373 | ACPI_HANDLE h_dummy; |
373 | ACPI_HANDLE h_dummy; |
374 | long video_caps = 0; |
374 | long video_caps = 0; |
375 | 375 | ||
376 | if (!device) |
376 | if (!device) |
377 | return 0; |
377 | return 0; |
378 | 378 | ||
379 | /* Is this device able to support video switching ? */ |
379 | /* Is this device able to support video switching ? */ |
380 | if (ACPI_SUCCESS(AcpiGetHandle(device->handle, "_DOD", &h_dummy)) || |
380 | if (ACPI_SUCCESS(AcpiGetHandle(device->handle, "_DOD", &h_dummy)) || |
381 | ACPI_SUCCESS(AcpiGetHandle(device->handle, "_DOS", &h_dummy))) |
381 | ACPI_SUCCESS(AcpiGetHandle(device->handle, "_DOS", &h_dummy))) |
382 | video_caps |= ACPI_VIDEO_OUTPUT_SWITCHING; |
382 | video_caps |= ACPI_VIDEO_OUTPUT_SWITCHING; |
383 | 383 | ||
384 | /* Is this device able to retrieve a video ROM ? */ |
384 | /* Is this device able to retrieve a video ROM ? */ |
385 | if (ACPI_SUCCESS(AcpiGetHandle(device->handle, "_ROM", &h_dummy))) |
385 | if (ACPI_SUCCESS(AcpiGetHandle(device->handle, "_ROM", &h_dummy))) |
386 | video_caps |= ACPI_VIDEO_ROM_AVAILABLE; |
386 | video_caps |= ACPI_VIDEO_ROM_AVAILABLE; |
387 | 387 | ||
388 | /* Is this device able to configure which video head to be POSTed ? */ |
388 | /* Is this device able to configure which video head to be POSTed ? */ |
389 | if (ACPI_SUCCESS(AcpiGetHandle(device->handle, "_VPO", &h_dummy)) && |
389 | if (ACPI_SUCCESS(AcpiGetHandle(device->handle, "_VPO", &h_dummy)) && |
390 | ACPI_SUCCESS(AcpiGetHandle(device->handle, "_GPD", &h_dummy)) && |
390 | ACPI_SUCCESS(AcpiGetHandle(device->handle, "_GPD", &h_dummy)) && |
391 | ACPI_SUCCESS(AcpiGetHandle(device->handle, "_SPD", &h_dummy))) |
391 | ACPI_SUCCESS(AcpiGetHandle(device->handle, "_SPD", &h_dummy))) |
392 | video_caps |= ACPI_VIDEO_DEVICE_POSTING; |
392 | video_caps |= ACPI_VIDEO_DEVICE_POSTING; |
393 | 393 | ||
394 | return video_caps; |
394 | return video_caps; |
395 | } |
395 | } |
396 | 396 | ||
397 | /* |
397 | /* |
398 | * acpi_bay_match - see if a device is an ejectable driver bay |
398 | * acpi_bay_match - see if a device is an ejectable driver bay |
399 | * |
399 | * |
400 | * If an acpi object is ejectable and has one of the ACPI ATA methods defined, |
400 | * If an acpi object is ejectable and has one of the ACPI ATA methods defined, |
401 | * then we can safely call it an ejectable drive bay |
401 | * then we can safely call it an ejectable drive bay |
402 | */ |
402 | */ |
403 | static int acpi_bay_match(struct acpi_device *device){ |
403 | static int acpi_bay_match(struct acpi_device *device){ |
404 | ACPI_STATUS status; |
404 | ACPI_STATUS status; |
405 | ACPI_HANDLE handle; |
405 | ACPI_HANDLE handle; |
406 | ACPI_HANDLE tmp; |
406 | ACPI_HANDLE tmp; |
407 | ACPI_HANDLE phandle; |
407 | ACPI_HANDLE phandle; |
408 | 408 | ||
409 | handle = device->handle; |
409 | handle = device->handle; |
410 | 410 | ||
411 | status = AcpiGetHandle(handle, "_EJ0", &tmp); |
411 | status = AcpiGetHandle(handle, "_EJ0", &tmp); |
412 | if (ACPI_FAILURE(status)) |
412 | if (ACPI_FAILURE(status)) |
413 | return -ENODEV; |
413 | return -ENODEV; |
414 | 414 | ||
415 | if ((ACPI_SUCCESS(AcpiGetHandle(handle, "_GTF", &tmp))) || |
415 | if ((ACPI_SUCCESS(AcpiGetHandle(handle, "_GTF", &tmp))) || |
416 | (ACPI_SUCCESS(AcpiGetHandle(handle, "_GTM", &tmp))) || |
416 | (ACPI_SUCCESS(AcpiGetHandle(handle, "_GTM", &tmp))) || |
417 | (ACPI_SUCCESS(AcpiGetHandle(handle, "_STM", &tmp))) || |
417 | (ACPI_SUCCESS(AcpiGetHandle(handle, "_STM", &tmp))) || |
418 | (ACPI_SUCCESS(AcpiGetHandle(handle, "_SDD", &tmp)))) |
418 | (ACPI_SUCCESS(AcpiGetHandle(handle, "_SDD", &tmp)))) |
419 | return 0; |
419 | return 0; |
420 | 420 | ||
421 | if (AcpiGetParent(handle, &phandle)) |
421 | if (AcpiGetParent(handle, &phandle)) |
422 | return -ENODEV; |
422 | return -ENODEV; |
423 | 423 | ||
424 | if ((ACPI_SUCCESS(AcpiGetHandle(phandle, "_GTF", &tmp))) || |
424 | if ((ACPI_SUCCESS(AcpiGetHandle(phandle, "_GTF", &tmp))) || |
425 | (ACPI_SUCCESS(AcpiGetHandle(phandle, "_GTM", &tmp))) || |
425 | (ACPI_SUCCESS(AcpiGetHandle(phandle, "_GTM", &tmp))) || |
426 | (ACPI_SUCCESS(AcpiGetHandle(phandle, "_STM", &tmp))) || |
426 | (ACPI_SUCCESS(AcpiGetHandle(phandle, "_STM", &tmp))) || |
427 | (ACPI_SUCCESS(AcpiGetHandle(phandle, "_SDD", &tmp)))) |
427 | (ACPI_SUCCESS(AcpiGetHandle(phandle, "_SDD", &tmp)))) |
428 | return 0; |
428 | return 0; |
429 | 429 | ||
430 | return -ENODEV; |
430 | return -ENODEV; |
431 | } |
431 | } |
432 | 432 | ||
433 | /* |
433 | /* |
434 | * acpi_dock_match - see if a device has a _DCK method |
434 | * acpi_dock_match - see if a device has a _DCK method |
435 | */ |
435 | */ |
436 | static int acpi_dock_match(struct acpi_device *device) |
436 | static int acpi_dock_match(struct acpi_device *device) |
437 | { |
437 | { |
438 | ACPI_HANDLE tmp; |
438 | ACPI_HANDLE tmp; |
439 | return AcpiGetHandle(device->handle, "_DCK", &tmp); |
439 | return AcpiGetHandle(device->handle, "_DCK", &tmp); |
440 | } |
440 | } |
441 | 441 | ||
442 | char *acpi_device_hid(struct acpi_device *device) |
442 | char *acpi_device_hid(struct acpi_device *device) |
443 | { |
443 | { |
444 | struct acpi_hardware_id *hid; |
444 | struct acpi_hardware_id *hid; |
445 | 445 | ||
446 | hid = list_first_entry(&device->pnp.ids, struct acpi_hardware_id, list); |
446 | hid = list_first_entry(&device->pnp.ids, struct acpi_hardware_id, list); |
447 | return hid->id; |
447 | return hid->id; |
448 | } |
448 | } |
449 | 449 | ||
450 | static void acpi_add_id(struct acpi_device *device, const char *dev_id) |
450 | static void acpi_add_id(struct acpi_device *device, const char *dev_id) |
451 | { |
451 | { |
452 | struct acpi_hardware_id *id; |
452 | struct acpi_hardware_id *id; |
453 | 453 | ||
454 | id = kmalloc(sizeof(*id), GFP_KERNEL); |
454 | id = kmalloc(sizeof(*id), GFP_KERNEL); |
455 | if (!id) |
455 | if (!id) |
456 | return; |
456 | return; |
457 | 457 | ||
458 | INIT_LIST_HEAD(&id->list); |
458 | INIT_LIST_HEAD(&id->list); |
459 | 459 | ||
460 | id->id = kmalloc(strlen(dev_id) + 1, GFP_KERNEL); |
460 | id->id = kmalloc(strlen(dev_id) + 1, GFP_KERNEL); |
461 | if (!id->id) { |
461 | if (!id->id) { |
462 | kfree(id); |
462 | kfree(id); |
463 | return; |
463 | return; |
464 | } |
464 | } |
465 | 465 | ||
466 | strcpy(id->id, dev_id); |
466 | strcpy(id->id, dev_id); |
467 | list_add_tail(&id->list, &device->pnp.ids); |
467 | list_add_tail(&id->list, &device->pnp.ids); |
468 | } |
468 | } |
469 | 469 | ||
470 | 470 | ||
471 | 471 | ||
472 | static void acpi_device_set_id(struct acpi_device *device) |
472 | static void acpi_device_set_id(struct acpi_device *device) |
473 | { |
473 | { |
474 | ACPI_STATUS status; |
474 | ACPI_STATUS status; |
475 | ACPI_DEVICE_INFO *info; |
475 | ACPI_DEVICE_INFO *info; |
476 | ACPI_DEVICE_ID_LIST *cid_list; |
476 | ACPI_DEVICE_ID_LIST *cid_list; |
477 | int i; |
477 | int i; |
478 | 478 | ||
479 | switch (device->device_type) |
479 | switch (device->device_type) |
480 | { |
480 | { |
481 | case ACPI_BUS_TYPE_DEVICE: |
481 | case ACPI_BUS_TYPE_DEVICE: |
482 | if (ACPI_IS_ROOT_DEVICE(device)) { |
482 | if (ACPI_IS_ROOT_DEVICE(device)) { |
483 | acpi_add_id(device, ACPI_SYSTEM_HID); |
483 | acpi_add_id(device, ACPI_SYSTEM_HID); |
484 | break; |
484 | break; |
485 | } |
485 | } |
486 | 486 | ||
487 | status = AcpiGetObjectInfo(device->handle, &info); |
487 | status = AcpiGetObjectInfo(device->handle, &info); |
488 | if (ACPI_FAILURE(status)) { |
488 | if (ACPI_FAILURE(status)) { |
489 | printk(KERN_ERR PREFIX "%s: Error reading device info\n", __func__); |
489 | printk(KERN_ERR PREFIX "%s: Error reading device info\n", __func__); |
490 | return; |
490 | return; |
491 | } |
491 | } |
492 | 492 | ||
493 | if (info->Valid & ACPI_VALID_HID) |
493 | if (info->Valid & ACPI_VALID_HID) |
494 | acpi_add_id(device, info->HardwareId.String); |
494 | acpi_add_id(device, info->HardwareId.String); |
495 | if (info->Valid & ACPI_VALID_CID) |
495 | if (info->Valid & ACPI_VALID_CID) |
496 | { |
496 | { |
497 | cid_list = &info->CompatibleIdList; |
497 | cid_list = &info->CompatibleIdList; |
498 | for (i = 0; i < cid_list->Count; i++) |
498 | for (i = 0; i < cid_list->Count; i++) |
499 | acpi_add_id(device, cid_list->Ids[i].String); |
499 | acpi_add_id(device, cid_list->Ids[i].String); |
500 | } |
500 | } |
501 | if (info->Valid & ACPI_VALID_ADR) { |
501 | if (info->Valid & ACPI_VALID_ADR) { |
502 | device->pnp.bus_address = info->Address; |
502 | device->pnp.bus_address = info->Address; |
503 | device->flags.bus_address = 1; |
503 | device->flags.bus_address = 1; |
504 | } |
504 | } |
505 | 505 | ||
506 | kfree(info); |
506 | kfree(info); |
507 | 507 | ||
508 | /* |
508 | /* |
509 | * Some devices don't reliably have _HIDs & _CIDs, so add |
509 | * Some devices don't reliably have _HIDs & _CIDs, so add |
510 | * synthetic HIDs to make sure drivers can find them. |
510 | * synthetic HIDs to make sure drivers can find them. |
511 | */ |
511 | */ |
512 | if (acpi_is_video_device(device)) |
512 | if (acpi_is_video_device(device)) |
513 | acpi_add_id(device, ACPI_VIDEO_HID); |
513 | acpi_add_id(device, ACPI_VIDEO_HID); |
514 | else if (ACPI_SUCCESS(acpi_bay_match(device))) |
514 | else if (ACPI_SUCCESS(acpi_bay_match(device))) |
515 | acpi_add_id(device, ACPI_BAY_HID); |
515 | acpi_add_id(device, ACPI_BAY_HID); |
516 | else if (ACPI_SUCCESS(acpi_dock_match(device))) |
516 | else if (ACPI_SUCCESS(acpi_dock_match(device))) |
517 | acpi_add_id(device, ACPI_DOCK_HID); |
517 | acpi_add_id(device, ACPI_DOCK_HID); |
518 | else if (!acpi_device_hid(device) && |
518 | else if (!acpi_device_hid(device) && |
519 | ACPI_IS_ROOT_DEVICE(device->parent)) { |
519 | ACPI_IS_ROOT_DEVICE(device->parent)) { |
520 | acpi_add_id(device, ACPI_BUS_HID); /* \_SB, LNXSYBUS */ |
520 | acpi_add_id(device, ACPI_BUS_HID); /* \_SB, LNXSYBUS */ |
521 | strcpy(device->pnp.device_name, ACPI_BUS_DEVICE_NAME); |
521 | strcpy(device->pnp.device_name, ACPI_BUS_DEVICE_NAME); |
522 | strcpy(device->pnp.device_class, ACPI_BUS_CLASS); |
522 | strcpy(device->pnp.device_class, ACPI_BUS_CLASS); |
523 | } |
523 | } |
524 | 524 | ||
525 | break; |
525 | break; |
526 | case ACPI_BUS_TYPE_POWER: |
526 | case ACPI_BUS_TYPE_POWER: |
527 | acpi_add_id(device, ACPI_POWER_HID); |
527 | acpi_add_id(device, ACPI_POWER_HID); |
528 | break; |
528 | break; |
529 | case ACPI_BUS_TYPE_PROCESSOR: |
529 | case ACPI_BUS_TYPE_PROCESSOR: |
530 | acpi_add_id(device, ACPI_PROCESSOR_OBJECT_HID); |
530 | acpi_add_id(device, ACPI_PROCESSOR_OBJECT_HID); |
531 | break; |
531 | break; |
532 | case ACPI_BUS_TYPE_THERMAL: |
532 | case ACPI_BUS_TYPE_THERMAL: |
533 | acpi_add_id(device, ACPI_THERMAL_HID); |
533 | acpi_add_id(device, ACPI_THERMAL_HID); |
534 | break; |
534 | break; |
535 | case ACPI_BUS_TYPE_POWER_BUTTON: |
535 | case ACPI_BUS_TYPE_POWER_BUTTON: |
536 | acpi_add_id(device, ACPI_BUTTON_HID_POWERF); |
536 | acpi_add_id(device, ACPI_BUTTON_HID_POWERF); |
537 | break; |
537 | break; |
538 | case ACPI_BUS_TYPE_SLEEP_BUTTON: |
538 | case ACPI_BUS_TYPE_SLEEP_BUTTON: |
539 | acpi_add_id(device, ACPI_BUTTON_HID_SLEEPF); |
539 | acpi_add_id(device, ACPI_BUTTON_HID_SLEEPF); |
540 | break; |
540 | break; |
541 | } |
541 | } |
542 | 542 | ||
543 | /* |
543 | /* |
544 | * We build acpi_devices for some objects that don't have _HID or _CID, |
544 | * We build acpi_devices for some objects that don't have _HID or _CID, |
545 | * e.g., PCI bridges and slots. Drivers can't bind to these objects, |
545 | * e.g., PCI bridges and slots. Drivers can't bind to these objects, |
546 | * but we do use them indirectly by traversing the acpi_device tree. |
546 | * but we do use them indirectly by traversing the acpi_device tree. |
547 | * This generic ID isn't useful for driver binding, but it provides |
547 | * This generic ID isn't useful for driver binding, but it provides |
548 | * the useful property that "every acpi_device has an ID." |
548 | * the useful property that "every acpi_device has an ID." |
549 | */ |
549 | */ |
550 | if (list_empty(&device->pnp.ids)) |
550 | if (list_empty(&device->pnp.ids)) |
551 | acpi_add_id(device, "device"); |
551 | acpi_add_id(device, "device"); |
552 | } |
552 | } |
553 | 553 | ||
554 | static int acpi_device_set_context(struct acpi_device *device) |
554 | static int acpi_device_set_context(struct acpi_device *device) |
555 | { |
555 | { |
556 | ACPI_STATUS status; |
556 | ACPI_STATUS status; |
557 | 557 | ||
558 | /* |
558 | /* |
559 | * Context |
559 | * Context |
560 | * ------- |
560 | * ------- |
561 | * Attach this 'struct acpi_device' to the ACPI object. This makes |
561 | * Attach this 'struct acpi_device' to the ACPI object. This makes |
562 | * resolutions from handle->device very efficient. Fixed hardware |
562 | * resolutions from handle->device very efficient. Fixed hardware |
563 | * devices have no handles, so we skip them. |
563 | * devices have no handles, so we skip them. |
564 | */ |
564 | */ |
565 | if (!device->handle) |
565 | if (!device->handle) |
566 | return 0; |
566 | return 0; |
567 | 567 | ||
568 | status = AcpiAttachData(device->handle, |
568 | status = AcpiAttachData(device->handle, |
569 | acpi_bus_data_handler, device); |
569 | acpi_bus_data_handler, device); |
570 | if (ACPI_SUCCESS(status)) |
570 | if (ACPI_SUCCESS(status)) |
571 | return 0; |
571 | return 0; |
572 | 572 | ||
573 | printk(KERN_ERR PREFIX "Error attaching device data\n"); |
573 | printk(KERN_ERR PREFIX "Error attaching device data\n"); |
574 | return -ENODEV; |
574 | return -ENODEV; |
575 | } |
575 | } |
576 | 576 | ||
577 | 577 | ||
578 | static int acpi_add_single_object(struct acpi_device **child, |
578 | static int acpi_add_single_object(struct acpi_device **child, |
579 | ACPI_HANDLE handle, int type, |
579 | ACPI_HANDLE handle, int type, |
580 | unsigned long long sta, |
580 | unsigned long long sta, |
581 | struct acpi_bus_ops *ops) |
581 | struct acpi_bus_ops *ops) |
582 | { |
582 | { |
583 | int result; |
583 | int result; |
584 | struct acpi_device *device; |
584 | struct acpi_device *device; |
585 | ACPI_BUFFER buffer = { ACPI_ALLOCATE_BUFFER, NULL }; |
585 | ACPI_BUFFER buffer = { ACPI_ALLOCATE_BUFFER, NULL }; |
586 | ACPI_DEVICE_INFO *info = NULL; |
586 | ACPI_DEVICE_INFO *info = NULL; |
587 | ACPI_DEVICE_ID_LIST *cid_list; |
587 | ACPI_DEVICE_ID_LIST *cid_list; |
588 | int i; |
588 | int i; |
589 | 589 | ||
590 | 590 | ||
591 | device = kzalloc(sizeof(struct acpi_device), GFP_KERNEL); |
591 | device = kzalloc(sizeof(struct acpi_device), GFP_KERNEL); |
592 | if (!device) { |
592 | if (!device) { |
593 | printk(KERN_ERR PREFIX "Memory allocation error\n"); |
593 | printk(KERN_ERR PREFIX "Memory allocation error\n"); |
594 | return -ENOMEM; |
594 | return -ENOMEM; |
595 | } |
595 | } |
596 | 596 | ||
597 | INIT_LIST_HEAD(&device->pnp.ids); |
597 | INIT_LIST_HEAD(&device->pnp.ids); |
598 | device->device_type = type; |
598 | device->device_type = type; |
599 | device->handle = handle; |
599 | device->handle = handle; |
600 | device->parent = acpi_bus_get_parent(handle); |
600 | device->parent = acpi_bus_get_parent(handle); |
601 | device->bus_ops = *ops; /* workround for not call .start */ |
601 | device->bus_ops = *ops; /* workround for not call .start */ |
602 | STRUCT_TO_INT(device->status) = sta; |
602 | STRUCT_TO_INT(device->status) = sta; |
603 | 603 | ||
604 | acpi_device_get_busid(device); |
604 | acpi_device_get_busid(device); |
605 | 605 | ||
606 | /* |
606 | /* |
607 | * Flags |
607 | * Flags |
608 | * ----- |
608 | * ----- |
609 | * Note that we only look for object handles -- cannot evaluate objects |
609 | * Note that we only look for object handles -- cannot evaluate objects |
610 | * until we know the device is present and properly initialized. |
610 | * until we know the device is present and properly initialized. |
611 | */ |
611 | */ |
612 | result = acpi_bus_get_flags(device); |
612 | result = acpi_bus_get_flags(device); |
613 | if (result) |
613 | if (result) |
614 | goto end; |
614 | goto end; |
615 | 615 | ||
616 | /* |
616 | /* |
617 | * Initialize Device |
617 | * Initialize Device |
618 | * ----------------- |
618 | * ----------------- |
619 | * TBD: Synch with Core's enumeration/initialization process. |
619 | * TBD: Synch with Core's enumeration/initialization process. |
620 | */ |
620 | */ |
621 | acpi_device_set_id(device); |
621 | acpi_device_set_id(device); |
622 | 622 | ||
623 | 623 | ||
624 | if ((result = acpi_device_set_context(device))) |
624 | if ((result = acpi_device_set_context(device))) |
625 | goto end; |
625 | goto end; |
626 | 626 | ||
627 | result = acpi_device_register(device); |
627 | result = acpi_device_register(device); |
628 | 628 | ||
629 | /* |
629 | /* |
630 | * Bind _ADR-Based Devices when hot add |
630 | * Bind _ADR-Based Devices when hot add |
631 | */ |
631 | */ |
632 | if (device->flags.bus_address) { |
632 | if (device->flags.bus_address) { |
633 | if (device->parent && device->parent->ops.bind) |
633 | if (device->parent && device->parent->ops.bind) |
634 | device->parent->ops.bind(device); |
634 | device->parent->ops.bind(device); |
635 | } |
635 | } |
636 | 636 | ||
637 | end: |
637 | end: |
638 | 638 | ||
639 | AcpiGetName(handle, ACPI_FULL_PATHNAME, &buffer); |
639 | AcpiGetName(handle, ACPI_FULL_PATHNAME, &buffer); |
640 | dbgprintf(PREFIX "Adding [%s]", (char *)buffer.Pointer); |
640 | dbgprintf(PREFIX "Adding [%s]", (char *)buffer.Pointer); |
641 | kfree(buffer.Pointer); |
641 | kfree(buffer.Pointer); |
642 | 642 | ||
643 | AcpiGetObjectInfo(handle, &info); |
643 | AcpiGetObjectInfo(handle, &info); |
644 | if (info->Valid & ACPI_VALID_HID) |
644 | if (info->Valid & ACPI_VALID_HID) |
645 | dbgprintf (" HID: %s", info->HardwareId.String); |
645 | dbgprintf (" HID: %s", info->HardwareId.String); |
646 | 646 | ||
647 | if (info->Valid & ACPI_VALID_CID) |
647 | if (info->Valid & ACPI_VALID_CID) |
648 | { |
648 | { |
649 | cid_list = &info->CompatibleIdList; |
649 | cid_list = &info->CompatibleIdList; |
650 | for (i = 0; i < cid_list->Count; i++) |
650 | for (i = 0; i < cid_list->Count; i++) |
651 | dbgprintf(" CID: %s\n", cid_list->Ids[i].String); |
651 | dbgprintf(" CID: %s\n", cid_list->Ids[i].String); |
652 | } |
652 | } |
653 | dbgprintf("\n"); |
653 | dbgprintf("\n"); |
654 | 654 | ||
655 | kfree(info); |
655 | kfree(info); |
656 | 656 | ||
657 | if (!result) { |
657 | if (!result) { |
658 | *child = device; |
658 | *child = device; |
659 | }; |
659 | }; |
660 | return result; |
660 | return result; |
661 | } |
661 | } |
662 | 662 | ||
663 | #define ACPI_STA_DEFAULT (ACPI_STA_DEVICE_PRESENT | ACPI_STA_DEVICE_ENABLED | \ |
663 | #define ACPI_STA_DEFAULT (ACPI_STA_DEVICE_PRESENT | ACPI_STA_DEVICE_ENABLED | \ |
664 | ACPI_STA_DEVICE_UI | ACPI_STA_DEVICE_FUNCTIONING) |
664 | ACPI_STA_DEVICE_UI | ACPI_STA_DEVICE_FUNCTIONING) |
665 | 665 | ||
666 | static int acpi_bus_type_and_status(ACPI_HANDLE handle, int *type, |
666 | static int acpi_bus_type_and_status(ACPI_HANDLE handle, int *type, |
667 | unsigned long long *sta) |
667 | unsigned long long *sta) |
668 | { |
668 | { |
669 | ACPI_STATUS status; |
669 | ACPI_STATUS status; |
670 | ACPI_OBJECT_TYPE acpi_type; |
670 | ACPI_OBJECT_TYPE acpi_type; |
671 | 671 | ||
672 | status = AcpiGetType(handle, &acpi_type); |
672 | status = AcpiGetType(handle, &acpi_type); |
673 | if (ACPI_FAILURE(status)) |
673 | if (ACPI_FAILURE(status)) |
674 | return -ENODEV; |
674 | return -ENODEV; |
675 | 675 | ||
676 | switch (acpi_type) |
676 | switch (acpi_type) |
677 | { |
677 | { |
678 | case ACPI_TYPE_ANY: /* for ACPI_ROOT_OBJECT */ |
678 | case ACPI_TYPE_ANY: /* for ACPI_ROOT_OBJECT */ |
679 | case ACPI_TYPE_DEVICE: |
679 | case ACPI_TYPE_DEVICE: |
680 | *type = ACPI_BUS_TYPE_DEVICE; |
680 | *type = ACPI_BUS_TYPE_DEVICE; |
681 | status = acpi_bus_get_status_handle(handle, sta); |
681 | status = acpi_bus_get_status_handle(handle, sta); |
682 | if (ACPI_FAILURE(status)) |
682 | if (ACPI_FAILURE(status)) |
683 | return -ENODEV; |
683 | return -ENODEV; |
684 | break; |
684 | break; |
685 | case ACPI_TYPE_PROCESSOR: |
685 | case ACPI_TYPE_PROCESSOR: |
686 | *type = ACPI_BUS_TYPE_PROCESSOR; |
686 | *type = ACPI_BUS_TYPE_PROCESSOR; |
687 | status = acpi_bus_get_status_handle(handle, sta); |
687 | status = acpi_bus_get_status_handle(handle, sta); |
688 | if (ACPI_FAILURE(status)) |
688 | if (ACPI_FAILURE(status)) |
689 | return -ENODEV; |
689 | return -ENODEV; |
690 | break; |
690 | break; |
691 | case ACPI_TYPE_THERMAL: |
691 | case ACPI_TYPE_THERMAL: |
692 | *type = ACPI_BUS_TYPE_THERMAL; |
692 | *type = ACPI_BUS_TYPE_THERMAL; |
693 | *sta = ACPI_STA_DEFAULT; |
693 | *sta = ACPI_STA_DEFAULT; |
694 | break; |
694 | break; |
695 | case ACPI_TYPE_POWER: |
695 | case ACPI_TYPE_POWER: |
696 | *type = ACPI_BUS_TYPE_POWER; |
696 | *type = ACPI_BUS_TYPE_POWER; |
697 | *sta = ACPI_STA_DEFAULT; |
697 | *sta = ACPI_STA_DEFAULT; |
698 | break; |
698 | break; |
699 | default: |
699 | default: |
700 | return -ENODEV; |
700 | return -ENODEV; |
701 | } |
701 | } |
702 | 702 | ||
703 | return 0; |
703 | return 0; |
704 | } |
704 | } |
705 | 705 | ||
706 | 706 | ||
707 | static ACPI_STATUS acpi_bus_check_add(ACPI_HANDLE handle, u32 lvl, |
707 | static ACPI_STATUS acpi_bus_check_add(ACPI_HANDLE handle, u32 lvl, |
708 | void *context, void **return_value) |
708 | void *context, void **return_value) |
709 | { |
709 | { |
710 | struct acpi_bus_ops *ops = context; |
710 | struct acpi_bus_ops *ops = context; |
711 | int type; |
711 | int type; |
712 | unsigned long long sta; |
712 | unsigned long long sta; |
713 | struct acpi_device *device; |
713 | struct acpi_device *device; |
714 | ACPI_STATUS status; |
714 | ACPI_STATUS status; |
715 | int result; |
715 | int result; |
716 | 716 | ||
717 | result = acpi_bus_type_and_status(handle, &type, &sta); |
717 | result = acpi_bus_type_and_status(handle, &type, &sta); |
718 | if (result) |
718 | if (result) |
719 | return AE_OK; |
719 | return AE_OK; |
720 | 720 | ||
721 | if (!(sta & ACPI_STA_DEVICE_PRESENT) && |
721 | if (!(sta & ACPI_STA_DEVICE_PRESENT) && |
722 | !(sta & ACPI_STA_DEVICE_FUNCTIONING)) |
722 | !(sta & ACPI_STA_DEVICE_FUNCTIONING)) |
723 | return AE_CTRL_DEPTH; |
723 | return AE_CTRL_DEPTH; |
724 | 724 | ||
725 | /* |
725 | /* |
726 | * We may already have an acpi_device from a previous enumeration. If |
726 | * We may already have an acpi_device from a previous enumeration. If |
727 | * so, we needn't add it again, but we may still have to start it. |
727 | * so, we needn't add it again, but we may still have to start it. |
728 | */ |
728 | */ |
729 | device = NULL; |
729 | device = NULL; |
730 | acpi_bus_get_device(handle, &device); |
730 | acpi_bus_get_device(handle, &device); |
731 | if (ops->acpi_op_add && !device) |
731 | if (ops->acpi_op_add && !device) |
732 | acpi_add_single_object(&device, handle, type, sta, ops); |
732 | acpi_add_single_object(&device, handle, type, sta, ops); |
733 | 733 | ||
734 | if (!device) |
734 | if (!device) |
735 | return AE_CTRL_DEPTH; |
735 | return AE_CTRL_DEPTH; |
736 | 736 | ||
737 | /* |
737 | /* |
738 | if (ops->acpi_op_start && !(ops->acpi_op_add)) { |
738 | if (ops->acpi_op_start && !(ops->acpi_op_add)) { |
739 | status = acpi_start_single_object(device); |
739 | status = acpi_start_single_object(device); |
740 | if (ACPI_FAILURE(status)) |
740 | if (ACPI_FAILURE(status)) |
741 | return AE_CTRL_DEPTH; |
741 | return AE_CTRL_DEPTH; |
742 | } |
742 | } |
743 | */ |
743 | */ |
744 | 744 | ||
745 | if (!*return_value) |
745 | if (!*return_value) |
746 | *return_value = device; |
746 | *return_value = device; |
747 | return AE_OK; |
747 | return AE_OK; |
748 | } |
748 | } |
749 | 749 | ||
750 | 750 | ||
751 | static int acpi_bus_scan(ACPI_HANDLE handle, struct acpi_bus_ops *ops, |
751 | static int acpi_bus_scan(ACPI_HANDLE handle, struct acpi_bus_ops *ops, |
752 | struct acpi_device **child) |
752 | struct acpi_device **child) |
753 | { |
753 | { |
754 | ACPI_STATUS status; |
754 | ACPI_STATUS status; |
755 | void *device = NULL; |
755 | void *device = NULL; |
756 | 756 | ||
757 | status = acpi_bus_check_add(handle, 0, ops, &device); |
757 | status = acpi_bus_check_add(handle, 0, ops, &device); |
758 | if (ACPI_SUCCESS(status)) |
758 | if (ACPI_SUCCESS(status)) |
759 | AcpiWalkNamespace(ACPI_TYPE_ANY, handle, ACPI_UINT32_MAX, |
759 | AcpiWalkNamespace(ACPI_TYPE_ANY, handle, ACPI_UINT32_MAX, |
760 | acpi_bus_check_add, NULL, ops, &device); |
760 | acpi_bus_check_add, NULL, ops, &device); |
761 | 761 | ||
762 | if (child) |
762 | if (child) |
763 | *child = device; |
763 | *child = device; |
764 | 764 | ||
765 | if (device) |
765 | if (device) |
766 | return 0; |
766 | return 0; |
767 | else |
767 | else |
768 | return -ENODEV; |
768 | return -ENODEV; |
769 | } |
769 | } |
770 | 770 | ||
771 | 771 | ||
772 | int acpi_scan() |
772 | int acpi_scan() |
773 | { |
773 | { |
774 | int err; |
774 | int err; |
775 | struct acpi_bus_ops ops; |
775 | struct acpi_bus_ops ops; |
776 | 776 | ||
777 | memset(&ops, 0, sizeof(ops)); |
777 | memset(&ops, 0, sizeof(ops)); |
778 | ops.acpi_op_add = 1; |
778 | ops.acpi_op_add = 1; |
779 | ops.acpi_op_start = 1; |
779 | ops.acpi_op_start = 1; |
780 | 780 | ||
781 | err = acpi_bus_scan(ACPI_ROOT_OBJECT, &ops, &acpi_root); |
781 | err = acpi_bus_scan(ACPI_ROOT_OBJECT, &ops, &acpi_root); |
782 | 782 | ||
783 | return err; |
783 | return err; |
784 | };>> |
784 | };>> |
785 | 785 | ||
786 | 786 | ||
787 | - |