1 /* $NetBSD: acpi_util.c,v 1.7 2011/06/20 15:31:52 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.7 2011/06/20 15:31:52 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 * Get a device node from a handle. 277 */ 278 struct acpi_devnode * 279 acpi_get_node(ACPI_HANDLE handle) 280 { 281 struct acpi_devnode *ad; 282 ACPI_STATUS rv; 283 284 if (handle == NULL) 285 return NULL; 286 287 rv = AcpiGetData(handle, acpi_clean_node, (void **)&ad); 288 289 if (ACPI_FAILURE(rv)) 290 return NULL; 291 292 return ad; 293 } 294 295 /* 296 * Associate a device node with a handle. 297 */ 298 void 299 acpi_set_node(struct acpi_devnode *ad) 300 { 301 302 (void)AcpiAttachData(ad->ad_handle, acpi_clean_node, ad); 303 } 304 305 static void 306 acpi_clean_node(ACPI_HANDLE handle, void *aux) 307 { 308 /* Nothing. */ 309 } 310 311 /* 312 * Return a complete pathname from a handle. 313 * 314 * Note that the function uses static data storage; 315 * if the data is needed for future use, it should be 316 * copied before any subsequent calls overwrite it. 317 */ 318 const char * 319 acpi_name(ACPI_HANDLE handle) 320 { 321 static char name[80]; 322 ACPI_BUFFER buf; 323 ACPI_STATUS rv; 324 325 if (handle == NULL) 326 handle = ACPI_ROOT_OBJECT; 327 328 buf.Pointer = name; 329 buf.Length = sizeof(name); 330 331 rv = AcpiGetName(handle, ACPI_FULL_PATHNAME, &buf); 332 333 if (ACPI_FAILURE(rv)) 334 return "UNKNOWN"; 335 336 return name; 337 } 338 339 /* 340 * Match given IDs against _HID and _CIDs. 341 */ 342 int 343 acpi_match_hid(ACPI_DEVICE_INFO *ad, const char * const *ids) 344 { 345 uint32_t i, n; 346 char *id; 347 348 while (*ids) { 349 350 if ((ad->Valid & ACPI_VALID_HID) != 0) { 351 352 if (pmatch(ad->HardwareId.String, *ids, NULL) == 2) 353 return 1; 354 } 355 356 if ((ad->Valid & ACPI_VALID_CID) != 0) { 357 358 n = ad->CompatibleIdList.Count; 359 360 for (i = 0; i < n; i++) { 361 362 id = ad->CompatibleIdList.Ids[i].String; 363 364 if (pmatch(id, *ids, NULL) == 2) 365 return 1; 366 } 367 } 368 369 ids++; 370 } 371 372 return 0; 373 } 374 375 /* 376 * Match a handle from a cpu_info. Returns NULL on failure. 377 * 378 * Note that if also acpi_devnode is needed, a subsequent 379 * call to acpi_get_node() will work. 380 */ 381 ACPI_HANDLE 382 acpi_match_cpu_info(struct cpu_info *ci) 383 { 384 struct acpi_softc *sc = acpi_softc; 385 struct acpi_devnode *ad; 386 ACPI_INTEGER val; 387 ACPI_OBJECT *obj; 388 ACPI_BUFFER buf; 389 ACPI_HANDLE hdl; 390 ACPI_STATUS rv; 391 392 if (sc == NULL || acpi_active == 0) 393 return NULL; 394 395 /* 396 * CPUs are declared in the ACPI namespace 397 * either as a Processor() or as a Device(). 398 * In both cases the MADT entries are used 399 * for the match (see ACPI 4.0, section 8.4). 400 */ 401 SIMPLEQ_FOREACH(ad, &sc->ad_head, ad_list) { 402 403 hdl = ad->ad_handle; 404 405 switch (ad->ad_type) { 406 407 case ACPI_TYPE_DEVICE: 408 409 if (acpi_match_hid(ad->ad_devinfo, acpicpu_ids) == 0) 410 break; 411 412 rv = acpi_eval_integer(hdl, "_UID", &val); 413 414 if (ACPI_SUCCESS(rv) && val == ci->ci_acpiid) 415 return hdl; 416 417 break; 418 419 case ACPI_TYPE_PROCESSOR: 420 421 rv = acpi_eval_struct(hdl, NULL, &buf); 422 423 if (ACPI_FAILURE(rv)) 424 break; 425 426 obj = buf.Pointer; 427 428 if (obj->Processor.ProcId == ci->ci_acpiid) { 429 ACPI_FREE(buf.Pointer); 430 return hdl; 431 } 432 433 ACPI_FREE(buf.Pointer); 434 break; 435 } 436 } 437 438 return NULL; 439 } 440 441 /* 442 * Match a CPU from a handle. Returns NULL on failure. 443 */ 444 struct cpu_info * 445 acpi_match_cpu_handle(ACPI_HANDLE hdl) 446 { 447 struct cpu_info *ci; 448 ACPI_DEVICE_INFO *di; 449 CPU_INFO_ITERATOR cii; 450 ACPI_INTEGER val; 451 ACPI_OBJECT *obj; 452 ACPI_BUFFER buf; 453 ACPI_STATUS rv; 454 455 ci = NULL; 456 di = NULL; 457 buf.Pointer = NULL; 458 459 rv = AcpiGetObjectInfo(hdl, &di); 460 461 if (ACPI_FAILURE(rv)) 462 return NULL; 463 464 switch (di->Type) { 465 466 case ACPI_TYPE_DEVICE: 467 468 if (acpi_match_hid(di, acpicpu_ids) == 0) 469 goto out; 470 471 rv = acpi_eval_integer(hdl, "_UID", &val); 472 473 if (ACPI_FAILURE(rv)) 474 goto out; 475 476 break; 477 478 case ACPI_TYPE_PROCESSOR: 479 480 rv = acpi_eval_struct(hdl, NULL, &buf); 481 482 if (ACPI_FAILURE(rv)) 483 goto out; 484 485 obj = buf.Pointer; 486 val = obj->Processor.ProcId; 487 break; 488 489 default: 490 goto out; 491 } 492 493 for (CPU_INFO_FOREACH(cii, ci)) { 494 495 if (ci->ci_acpiid == val) 496 goto out; 497 } 498 499 ci = NULL; 500 501 out: 502 if (di != NULL) 503 ACPI_FREE(di); 504 505 if (buf.Pointer != NULL) 506 ACPI_FREE(buf.Pointer); 507 508 return ci; 509 } 510