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