1 | /* $NetBSD: acpi_util.c,v 1.8 2011/06/21 03:37:21 jruoho Exp $ */ |
2 | |
3 | /*- |
4 | * Copyright (c) 2003, 2007 The NetBSD Foundation, Inc. |
5 | * All rights reserved. |
6 | * |
7 | * This code is derived from software contributed to The NetBSD Foundation |
8 | * by Charles M. Hannum of By Noon Software, Inc. |
9 | * |
10 | * Redistribution and use in source and binary forms, with or without |
11 | * modification, are permitted provided that the following conditions |
12 | * are met: |
13 | * 1. Redistributions of source code must retain the above copyright |
14 | * notice, this list of conditions and the following disclaimer. |
15 | * 2. Redistributions in binary form must reproduce the above copyright |
16 | * notice, this list of conditions and the following disclaimer in the |
17 | * documentation and/or other materials provided with the distribution. |
18 | * |
19 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS |
20 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
21 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
22 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS |
23 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
29 | * POSSIBILITY OF SUCH DAMAGE. |
30 | */ |
31 | |
32 | /* |
33 | * Copyright 2001, 2003 Wasabi Systems, Inc. |
34 | * All rights reserved. |
35 | * |
36 | * Written by Jason R. Thorpe for Wasabi Systems, Inc. |
37 | * |
38 | * Redistribution and use in source and binary forms, with or without |
39 | * modification, are permitted provided that the following conditions |
40 | * are met: |
41 | * 1. Redistributions of source code must retain the above copyright |
42 | * notice, this list of conditions and the following disclaimer. |
43 | * 2. Redistributions in binary form must reproduce the above copyright |
44 | * notice, this list of conditions and the following disclaimer in the |
45 | * documentation and/or other materials provided with the distribution. |
46 | * 3. All advertising materials mentioning features or use of this software |
47 | * must display the following acknowledgement: |
48 | * This product includes software developed for the NetBSD Project by |
49 | * Wasabi Systems, Inc. |
50 | * 4. The name of Wasabi Systems, Inc. may not be used to endorse |
51 | * or promote products derived from this software without specific prior |
52 | * written permission. |
53 | * |
54 | * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND |
55 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
56 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
57 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC |
58 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
59 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
60 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
61 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
62 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
63 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
64 | * POSSIBILITY OF SUCH DAMAGE. |
65 | */ |
66 | |
67 | #include <sys/cdefs.h> |
68 | __KERNEL_RCSID(0, "$NetBSD: acpi_util.c,v 1.8 2011/06/21 03:37:21 jruoho Exp $" ); |
69 | |
70 | #include <sys/param.h> |
71 | |
72 | #include <dev/acpi/acpireg.h> |
73 | #include <dev/acpi/acpivar.h> |
74 | |
75 | #define _COMPONENT ACPI_BUS_COMPONENT |
76 | ACPI_MODULE_NAME ("acpi_util" ) |
77 | |
78 | static void acpi_clean_node(ACPI_HANDLE, void *); |
79 | |
80 | static const char * const acpicpu_ids[] = { |
81 | "ACPI0007" , |
82 | NULL |
83 | }; |
84 | |
85 | /* |
86 | * Evaluate an integer object. |
87 | */ |
88 | ACPI_STATUS |
89 | acpi_eval_integer(ACPI_HANDLE handle, const char *path, ACPI_INTEGER *valp) |
90 | { |
91 | ACPI_OBJECT obj; |
92 | ACPI_BUFFER buf; |
93 | ACPI_STATUS rv; |
94 | |
95 | if (handle == NULL) |
96 | handle = ACPI_ROOT_OBJECT; |
97 | |
98 | (void)memset(&obj, 0, sizeof(obj)); |
99 | buf.Pointer = &obj; |
100 | buf.Length = sizeof(obj); |
101 | |
102 | rv = AcpiEvaluateObject(handle, path, NULL, &buf); |
103 | |
104 | if (ACPI_FAILURE(rv)) |
105 | return rv; |
106 | |
107 | /* Check that evaluation produced a return value. */ |
108 | if (buf.Length == 0) |
109 | return AE_NULL_OBJECT; |
110 | |
111 | if (obj.Type != ACPI_TYPE_INTEGER) |
112 | return AE_TYPE; |
113 | |
114 | if (valp != NULL) |
115 | *valp = obj.Integer.Value; |
116 | |
117 | return AE_OK; |
118 | } |
119 | |
120 | /* |
121 | * Evaluate an integer object with a single integer input parameter. |
122 | */ |
123 | ACPI_STATUS |
124 | acpi_eval_set_integer(ACPI_HANDLE handle, const char *path, ACPI_INTEGER val) |
125 | { |
126 | ACPI_OBJECT_LIST arg; |
127 | ACPI_OBJECT obj; |
128 | |
129 | if (handle == NULL) |
130 | handle = ACPI_ROOT_OBJECT; |
131 | |
132 | obj.Type = ACPI_TYPE_INTEGER; |
133 | obj.Integer.Value = val; |
134 | |
135 | arg.Count = 1; |
136 | arg.Pointer = &obj; |
137 | |
138 | return AcpiEvaluateObject(handle, path, &arg, NULL); |
139 | } |
140 | |
141 | /* |
142 | * Evaluate a (Unicode) string object. |
143 | */ |
144 | ACPI_STATUS |
145 | acpi_eval_string(ACPI_HANDLE handle, const char *path, char **stringp) |
146 | { |
147 | ACPI_OBJECT *obj; |
148 | ACPI_BUFFER buf; |
149 | ACPI_STATUS rv; |
150 | |
151 | rv = acpi_eval_struct(handle, path, &buf); |
152 | |
153 | if (ACPI_FAILURE(rv)) |
154 | return rv; |
155 | |
156 | obj = buf.Pointer; |
157 | |
158 | if (obj->Type != ACPI_TYPE_STRING) { |
159 | rv = AE_TYPE; |
160 | goto out; |
161 | } |
162 | |
163 | if (obj->String.Length == 0) { |
164 | rv = AE_BAD_DATA; |
165 | goto out; |
166 | } |
167 | |
168 | *stringp = ACPI_ALLOCATE(obj->String.Length + 1); |
169 | |
170 | if (*stringp == NULL) { |
171 | rv = AE_NO_MEMORY; |
172 | goto out; |
173 | } |
174 | |
175 | (void)memcpy(*stringp, obj->String.Pointer, obj->String.Length); |
176 | |
177 | (*stringp)[obj->String.Length] = '\0'; |
178 | |
179 | out: |
180 | ACPI_FREE(buf.Pointer); |
181 | |
182 | return rv; |
183 | } |
184 | |
185 | /* |
186 | * Evaluate a structure. Caller must free buf.Pointer by ACPI_FREE(). |
187 | */ |
188 | ACPI_STATUS |
189 | acpi_eval_struct(ACPI_HANDLE handle, const char *path, ACPI_BUFFER *buf) |
190 | { |
191 | |
192 | if (handle == NULL) |
193 | handle = ACPI_ROOT_OBJECT; |
194 | |
195 | buf->Pointer = NULL; |
196 | buf->Length = ACPI_ALLOCATE_LOCAL_BUFFER; |
197 | |
198 | return AcpiEvaluateObject(handle, path, NULL, buf); |
199 | } |
200 | |
201 | /* |
202 | * Evaluate a reference handle from an element in a package. |
203 | */ |
204 | ACPI_STATUS |
205 | acpi_eval_reference_handle(ACPI_OBJECT *elm, ACPI_HANDLE *handle) |
206 | { |
207 | |
208 | if (elm == NULL || handle == NULL) |
209 | return AE_BAD_PARAMETER; |
210 | |
211 | switch (elm->Type) { |
212 | |
213 | case ACPI_TYPE_ANY: |
214 | case ACPI_TYPE_LOCAL_REFERENCE: |
215 | |
216 | if (elm->Reference.Handle == NULL) |
217 | return AE_NULL_ENTRY; |
218 | |
219 | *handle = elm->Reference.Handle; |
220 | |
221 | return AE_OK; |
222 | |
223 | case ACPI_TYPE_STRING: |
224 | return AcpiGetHandle(NULL, elm->String.Pointer, handle); |
225 | |
226 | default: |
227 | return AE_TYPE; |
228 | } |
229 | } |
230 | |
231 | /* |
232 | * Iterate over all objects in a package, and pass them all |
233 | * to a function. If the called function returns non-AE_OK, |
234 | * the iteration is stopped and that value is returned. |
235 | */ |
236 | ACPI_STATUS |
237 | acpi_foreach_package_object(ACPI_OBJECT *pkg, |
238 | ACPI_STATUS (*func)(ACPI_OBJECT *, void *), void *arg) |
239 | { |
240 | ACPI_STATUS rv = AE_OK; |
241 | uint32_t i; |
242 | |
243 | if (pkg == NULL) |
244 | return AE_BAD_PARAMETER; |
245 | |
246 | if (pkg->Type != ACPI_TYPE_PACKAGE) |
247 | return AE_TYPE; |
248 | |
249 | for (i = 0; i < pkg->Package.Count; i++) { |
250 | |
251 | rv = (*func)(&pkg->Package.Elements[i], arg); |
252 | |
253 | if (ACPI_FAILURE(rv)) |
254 | break; |
255 | } |
256 | |
257 | return rv; |
258 | } |
259 | |
260 | /* |
261 | * Fetch data info the specified (empty) ACPI buffer. |
262 | * Caller must free buf.Pointer by ACPI_FREE(). |
263 | */ |
264 | ACPI_STATUS |
265 | acpi_get(ACPI_HANDLE handle, ACPI_BUFFER *buf, |
266 | ACPI_STATUS (*getit)(ACPI_HANDLE, ACPI_BUFFER *)) |
267 | { |
268 | |
269 | buf->Pointer = NULL; |
270 | buf->Length = ACPI_ALLOCATE_LOCAL_BUFFER; |
271 | |
272 | return (*getit)(handle, buf); |
273 | } |
274 | |
275 | /* |
276 | * Return a complete pathname from a handle. |
277 | * |
278 | * Note that the function uses static data storage; |
279 | * if the data is needed for future use, it should be |
280 | * copied before any subsequent calls overwrite it. |
281 | */ |
282 | const char * |
283 | acpi_name(ACPI_HANDLE handle) |
284 | { |
285 | static char name[80]; |
286 | ACPI_BUFFER buf; |
287 | ACPI_STATUS rv; |
288 | |
289 | if (handle == NULL) |
290 | handle = ACPI_ROOT_OBJECT; |
291 | |
292 | buf.Pointer = name; |
293 | buf.Length = sizeof(name); |
294 | |
295 | rv = AcpiGetName(handle, ACPI_FULL_PATHNAME, &buf); |
296 | |
297 | if (ACPI_FAILURE(rv)) |
298 | return "UNKNOWN" ; |
299 | |
300 | return name; |
301 | } |
302 | |
303 | /* |
304 | * Match given IDs against _HID and _CIDs. |
305 | */ |
306 | int |
307 | acpi_match_hid(ACPI_DEVICE_INFO *ad, const char * const *ids) |
308 | { |
309 | uint32_t i, n; |
310 | char *id; |
311 | |
312 | while (*ids) { |
313 | |
314 | if ((ad->Valid & ACPI_VALID_HID) != 0) { |
315 | |
316 | if (pmatch(ad->HardwareId.String, *ids, NULL) == 2) |
317 | return 1; |
318 | } |
319 | |
320 | if ((ad->Valid & ACPI_VALID_CID) != 0) { |
321 | |
322 | n = ad->CompatibleIdList.Count; |
323 | |
324 | for (i = 0; i < n; i++) { |
325 | |
326 | id = ad->CompatibleIdList.Ids[i].String; |
327 | |
328 | if (pmatch(id, *ids, NULL) == 2) |
329 | return 1; |
330 | } |
331 | } |
332 | |
333 | ids++; |
334 | } |
335 | |
336 | return 0; |
337 | } |
338 | |
339 | /* |
340 | * Match a device node from a handle. |
341 | */ |
342 | struct acpi_devnode * |
343 | acpi_match_node(ACPI_HANDLE handle) |
344 | { |
345 | struct acpi_devnode *ad; |
346 | ACPI_STATUS rv; |
347 | |
348 | if (handle == NULL) |
349 | return NULL; |
350 | |
351 | rv = AcpiGetData(handle, acpi_clean_node, (void **)&ad); |
352 | |
353 | if (ACPI_FAILURE(rv)) |
354 | return NULL; |
355 | |
356 | return ad; |
357 | } |
358 | |
359 | /* |
360 | * Permanently associate a device node with a handle. |
361 | */ |
362 | void |
363 | acpi_match_node_init(struct acpi_devnode *ad) |
364 | { |
365 | (void)AcpiAttachData(ad->ad_handle, acpi_clean_node, ad); |
366 | } |
367 | |
368 | static void |
369 | acpi_clean_node(ACPI_HANDLE handle, void *aux) |
370 | { |
371 | /* Nothing. */ |
372 | } |
373 | |
374 | /* |
375 | * Match a handle from a cpu_info. Returns NULL on failure. |
376 | * |
377 | * Note that acpi_match_node() can be used if the device node |
378 | * is also required. |
379 | */ |
380 | ACPI_HANDLE |
381 | acpi_match_cpu_info(struct cpu_info *ci) |
382 | { |
383 | struct acpi_softc *sc = acpi_softc; |
384 | struct acpi_devnode *ad; |
385 | ACPI_INTEGER val; |
386 | ACPI_OBJECT *obj; |
387 | ACPI_BUFFER buf; |
388 | ACPI_HANDLE hdl; |
389 | ACPI_STATUS rv; |
390 | |
391 | if (sc == NULL || acpi_active == 0) |
392 | return NULL; |
393 | |
394 | /* |
395 | * CPUs are declared in the ACPI namespace |
396 | * either as a Processor() or as a Device(). |
397 | * In both cases the MADT entries are used |
398 | * for the match (see ACPI 4.0, section 8.4). |
399 | */ |
400 | SIMPLEQ_FOREACH(ad, &sc->ad_head, ad_list) { |
401 | |
402 | hdl = ad->ad_handle; |
403 | |
404 | switch (ad->ad_type) { |
405 | |
406 | case ACPI_TYPE_DEVICE: |
407 | |
408 | if (acpi_match_hid(ad->ad_devinfo, acpicpu_ids) == 0) |
409 | break; |
410 | |
411 | rv = acpi_eval_integer(hdl, "_UID" , &val); |
412 | |
413 | if (ACPI_SUCCESS(rv) && val == ci->ci_acpiid) |
414 | return hdl; |
415 | |
416 | break; |
417 | |
418 | case ACPI_TYPE_PROCESSOR: |
419 | |
420 | rv = acpi_eval_struct(hdl, NULL, &buf); |
421 | |
422 | if (ACPI_FAILURE(rv)) |
423 | break; |
424 | |
425 | obj = buf.Pointer; |
426 | |
427 | if (obj->Processor.ProcId == ci->ci_acpiid) { |
428 | ACPI_FREE(buf.Pointer); |
429 | return hdl; |
430 | } |
431 | |
432 | ACPI_FREE(buf.Pointer); |
433 | break; |
434 | } |
435 | } |
436 | |
437 | return NULL; |
438 | } |
439 | |
440 | /* |
441 | * Match a CPU from a handle. Returns NULL on failure. |
442 | */ |
443 | struct cpu_info * |
444 | acpi_match_cpu_handle(ACPI_HANDLE hdl) |
445 | { |
446 | struct cpu_info *ci; |
447 | ACPI_DEVICE_INFO *di; |
448 | CPU_INFO_ITERATOR cii; |
449 | ACPI_INTEGER val; |
450 | ACPI_OBJECT *obj; |
451 | ACPI_BUFFER buf; |
452 | ACPI_STATUS rv; |
453 | |
454 | ci = NULL; |
455 | di = NULL; |
456 | buf.Pointer = NULL; |
457 | |
458 | rv = AcpiGetObjectInfo(hdl, &di); |
459 | |
460 | if (ACPI_FAILURE(rv)) |
461 | return NULL; |
462 | |
463 | switch (di->Type) { |
464 | |
465 | case ACPI_TYPE_DEVICE: |
466 | |
467 | if (acpi_match_hid(di, acpicpu_ids) == 0) |
468 | goto out; |
469 | |
470 | rv = acpi_eval_integer(hdl, "_UID" , &val); |
471 | |
472 | if (ACPI_FAILURE(rv)) |
473 | goto out; |
474 | |
475 | break; |
476 | |
477 | case ACPI_TYPE_PROCESSOR: |
478 | |
479 | rv = acpi_eval_struct(hdl, NULL, &buf); |
480 | |
481 | if (ACPI_FAILURE(rv)) |
482 | goto out; |
483 | |
484 | obj = buf.Pointer; |
485 | val = obj->Processor.ProcId; |
486 | break; |
487 | |
488 | default: |
489 | goto out; |
490 | } |
491 | |
492 | for (CPU_INFO_FOREACH(cii, ci)) { |
493 | |
494 | if (ci->ci_acpiid == val) |
495 | goto out; |
496 | } |
497 | |
498 | ci = NULL; |
499 | |
500 | out: |
501 | if (di != NULL) |
502 | ACPI_FREE(di); |
503 | |
504 | if (buf.Pointer != NULL) |
505 | ACPI_FREE(buf.Pointer); |
506 | |
507 | return ci; |
508 | } |
509 | |