1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 /* 27 * Copyright (c) 2009, Intel Corporation. 28 * All rights reserved. 29 */ 30 31 #include <sys/types.h> 32 #include <sys/cmn_err.h> 33 #include <sys/sysmacros.h> 34 #include <sys/sunddi.h> 35 #include <sys/sunndi.h> 36 #include <sys/acpi/acpi.h> 37 #include <sys/acpica.h> 38 #include <sys/acpidev.h> 39 #include <sys/acpidev_impl.h> 40 #include <util/sscanf.h> 41 42 /* Data structures used to extract the numeric unit address from string _UID. */ 43 static acpidev_pseudo_uid_head_t acpidev_uid_heads[ACPIDEV_CLASS_ID_MAX]; 44 static char *acpidev_uid_formats[] = { 45 "%u", 46 }; 47 48 static char *acpidev_unknown_object_name = "<unknown>"; 49 50 int 51 acpidev_query_device_status(ACPI_HANDLE hdl) 52 { 53 int status; 54 55 ASSERT(hdl != NULL); 56 if (hdl == NULL) { 57 ACPIDEV_DEBUG(CE_WARN, 58 "acpidev: hdl is NULL in acpidev_query_device_status()."); 59 return (0); 60 } 61 62 if (ACPI_FAILURE(acpica_eval_int(hdl, METHOD_NAME__STA, &status))) { 63 /* 64 * Set the default value according to ACPI3.0b sec 6.3.7: 65 * If a device object (including the processor object) does 66 * not have an _STA object, then OSPM assumes that all of the 67 * above bits are set (in other words, the device is present, 68 * enabled, shown in the UI, and functioning). 69 */ 70 status = 0xF; 71 } 72 73 return (status); 74 } 75 76 boolean_t 77 acpidev_check_device_present(int status) 78 { 79 /* 80 * According to ACPI3.0 Spec, if either the ACPI_STA_DEVICE_PRESENT bit 81 * or the ACPI_STA_DEVICE_FUNCTIONING bit is set, the device exists. 82 */ 83 if (status & (ACPI_STA_DEVICE_PRESENT | ACPI_STA_DEVICE_FUNCTIONING)) { 84 return (B_TRUE); 85 } 86 87 return (B_FALSE); 88 } 89 90 boolean_t 91 acpidev_check_device_enabled(int stat) 92 { 93 /* 94 * According to ACPI3.0 Spec, if either the ACPI_STA_DEVICE_PRESENT bit 95 * or the ACPI_STA_DEVICE_FUNCTIONING bit is set, the device exists. 96 * Return true if device exists and has been enabled. 97 */ 98 if ((stat & (ACPI_STA_DEVICE_PRESENT | ACPI_STA_DEVICE_FUNCTIONING)) && 99 (stat & ACPI_STA_DEVICE_ENABLED)) { 100 return (B_TRUE); 101 } 102 103 return (B_FALSE); 104 } 105 106 boolean_t 107 acpidev_match_device_id(ACPI_DEVICE_INFO *infop, char **ids, int count) 108 { 109 int i, j; 110 111 ASSERT(infop != NULL); 112 ASSERT(ids != NULL || count == 0); 113 /* Special case to match all devices if count is 0. */ 114 if (count == 0) { 115 return (B_TRUE); 116 } else if (infop == NULL || ids == NULL) { 117 ACPIDEV_DEBUG(CE_WARN, "acpidev: invalid parameters in " 118 "acpidev_match_device_id()."); 119 return (B_FALSE); 120 } 121 122 /* Match _HID first. */ 123 if (infop->Valid & ACPI_VALID_HID) { 124 for (i = 0; i < count; i++) { 125 if (strncmp(ids[i], infop->HardwareId.Value, 126 sizeof (infop->HardwareId.Value)) == 0) { 127 return (B_TRUE); 128 } 129 } 130 } 131 132 /* Match _CID next. */ 133 if (infop->Valid & ACPI_VALID_CID) { 134 for (i = 0; i < count; i++) { 135 for (j = 0; j < infop->CompatibilityId.Count; j++) { 136 if (strncmp(ids[i], 137 infop->CompatibilityId.Id[j].Value, 138 sizeof (ACPI_COMPATIBLE_ID)) == 0) { 139 return (B_TRUE); 140 } 141 } 142 } 143 } 144 145 return (B_FALSE); 146 } 147 148 struct acpidev_get_device_arg { 149 boolean_t skip_non_exist; 150 int id_count; 151 char **device_ids; 152 void *user_arg; 153 ACPI_WALK_CALLBACK user_func; 154 }; 155 156 static ACPI_STATUS 157 acpidev_get_device_callback(ACPI_HANDLE hdl, UINT32 level, void *arg, 158 void **retval) 159 { 160 ACPI_STATUS rc; 161 ACPI_BUFFER buf; 162 ACPI_DEVICE_INFO *infop; 163 struct acpidev_get_device_arg *argp; 164 165 argp = (struct acpidev_get_device_arg *)arg; 166 ASSERT(argp != NULL); 167 ASSERT(hdl != NULL); 168 169 /* Query object information. */ 170 buf.Length = ACPI_ALLOCATE_BUFFER; 171 rc = AcpiGetObjectInfo(hdl, &buf); 172 if (ACPI_FAILURE(rc)) { 173 cmn_err(CE_WARN, "!acpidev: failed to get ACPI object info " 174 "in acpidev_get_device_callback()."); 175 return (AE_CTRL_DEPTH); 176 } 177 infop = buf.Pointer; 178 179 /* 180 * Skip scanning of children if the device is neither PRESENT nor 181 * FUNCTIONING. 182 * Please refer to ACPI Spec3.0b Sec 6.3.1 and 6.5.1. 183 */ 184 if (argp->skip_non_exist && (infop->Valid & ACPI_VALID_STA) && 185 !acpidev_check_device_present(infop->CurrentStatus)) { 186 rc = AE_CTRL_DEPTH; 187 /* Call user callback if matched. */ 188 } else if (acpidev_match_device_id(infop, argp->device_ids, 189 argp->id_count)) { 190 rc = argp->user_func(hdl, level, argp->user_arg, retval); 191 } else { 192 rc = AE_OK; 193 } 194 195 /* Free ACPI object info buffer. */ 196 AcpiOsFree(infop); 197 198 return (rc); 199 } 200 201 ACPI_STATUS 202 acpidev_get_device_by_id(ACPI_HANDLE hdl, char **ids, int count, 203 int maxdepth, boolean_t skip_non_exist, 204 ACPI_WALK_CALLBACK userfunc, void *userarg, void **retval) 205 { 206 ACPI_STATUS rc; 207 struct acpidev_get_device_arg arg; 208 209 ASSERT(userfunc != NULL); 210 if (hdl == NULL || userfunc == NULL || (ids == NULL && count != 0)) { 211 ACPIDEV_DEBUG(CE_WARN, "acpidev: invalid parameters " 212 "in acpidev_get_device_by_id()."); 213 return (AE_BAD_PARAMETER); 214 } 215 216 /* Enumerate all descendant objects. */ 217 arg.skip_non_exist = skip_non_exist; 218 arg.device_ids = ids; 219 arg.id_count = count; 220 arg.user_arg = userarg; 221 arg.user_func = userfunc; 222 rc = AcpiWalkNamespace(ACPI_TYPE_DEVICE, hdl, maxdepth, 223 &acpidev_get_device_callback, &arg, retval); 224 225 return (rc); 226 } 227 228 ACPI_STATUS 229 acpidev_walk_apic(ACPI_BUFFER *bufp, ACPI_HANDLE hdl, char *method, 230 acpidev_apic_walker_t func, void *context) 231 { 232 ACPI_STATUS rc; 233 ssize_t len; 234 ACPI_BUFFER buf; 235 ACPI_OBJECT *obj; 236 ACPI_SUBTABLE_HEADER *ap; 237 ACPI_TABLE_MADT *mp = NULL; 238 239 ASSERT(func != NULL); 240 if (func == NULL) { 241 ACPIDEV_DEBUG(CE_WARN, 242 "acpidev: invalid parameters for acpidev_walk_apic()."); 243 return (AE_BAD_PARAMETER); 244 } 245 246 buf.Pointer = NULL; 247 buf.Length = ACPI_ALLOCATE_BUFFER; 248 249 /* A walk buffer was passed in if bufp isn't NULL. */ 250 if (bufp != NULL) { 251 ap = (ACPI_SUBTABLE_HEADER *)(bufp->Pointer); 252 len = bufp->Length; 253 } else if (method != NULL) { 254 /* 255 * Otherwise, if we have an evaluate method, we get the walk 256 * buffer from a successful invocation of 257 * AcpiEvaluateObjectTyped(). 258 */ 259 ASSERT(hdl != NULL); 260 rc = AcpiEvaluateObjectTyped(hdl, method, NULL, &buf, 261 ACPI_TYPE_BUFFER); 262 if (ACPI_SUCCESS(rc)) { 263 ASSERT(buf.Length >= sizeof (*obj)); 264 obj = buf.Pointer; 265 ap = (ACPI_SUBTABLE_HEADER *)obj->Buffer.Pointer; 266 len = obj->Buffer.Length; 267 } else { 268 if (rc != AE_NOT_FOUND) 269 cmn_err(CE_WARN, "!acpidev: failed to evaluate " 270 "%s in acpidev_walk_apic().", method); 271 return (rc); 272 } 273 } else { 274 /* As a last resort, walk the MADT table. */ 275 rc = AcpiGetTable(ACPI_SIG_MADT, 1, (ACPI_TABLE_HEADER **)&mp); 276 if (ACPI_FAILURE(rc)) { 277 cmn_err(CE_WARN, "!acpidev: failed to get MADT table " 278 "in acpidev_walk_apic()."); 279 return (rc); 280 } 281 ap = (ACPI_SUBTABLE_HEADER *)(mp + 1); 282 len = mp->Header.Length - sizeof (*mp); 283 } 284 285 ASSERT(len >= 0); 286 for (rc = AE_OK; len > 0 && ACPI_SUCCESS(rc); len -= ap->Length, 287 ap = (ACPI_SUBTABLE_HEADER *)(((char *)ap) + ap->Length)) { 288 ASSERT(len >= sizeof (ACPI_SUBTABLE_HEADER)); 289 if (len <= sizeof (ACPI_SUBTABLE_HEADER) || 290 ap->Length <= sizeof (ACPI_SUBTABLE_HEADER) || 291 len < ap->Length) { 292 cmn_err(CE_WARN, 293 "!acpidev: invalid APIC entry in MADT/_MAT."); 294 break; 295 } 296 rc = (*func)(ap, context); 297 } 298 299 if (buf.Pointer != NULL) { 300 AcpiOsFree(buf.Pointer); 301 } 302 303 return (rc); 304 } 305 306 char * 307 acpidev_get_object_name(ACPI_HANDLE hdl) 308 { 309 ACPI_BUFFER buf; 310 char *objname = acpidev_unknown_object_name; 311 312 buf.Length = ACPI_ALLOCATE_BUFFER; 313 buf.Pointer = NULL; 314 if (ACPI_SUCCESS(AcpiGetName(hdl, ACPI_FULL_PATHNAME, &buf))) { 315 ASSERT(buf.Pointer != NULL); 316 objname = (char *)buf.Pointer; 317 } 318 319 return (objname); 320 } 321 322 void 323 acpidev_free_object_name(char *objname) 324 { 325 if (objname != acpidev_unknown_object_name && objname != NULL) { 326 AcpiOsFree(objname); 327 } 328 } 329 330 acpidev_walk_info_t * 331 acpidev_alloc_walk_info(acpidev_op_type_t op_type, int lvl, ACPI_HANDLE hdl, 332 acpidev_class_list_t **listpp, acpidev_walk_info_t *pinfop) 333 { 334 ACPI_BUFFER buf; 335 acpidev_walk_info_t *infop = NULL; 336 acpidev_data_handle_t datap = NULL; 337 338 ASSERT(0 <= lvl && lvl < ACPIDEV_MAX_ENUM_LEVELS); 339 infop = kmem_zalloc(sizeof (*infop), KM_SLEEP); 340 infop->awi_op_type = op_type; 341 infop->awi_level = lvl; 342 infop->awi_parent = pinfop; 343 infop->awi_class_list = listpp; 344 infop->awi_hdl = hdl; 345 infop->awi_name = acpidev_get_object_name(hdl); 346 347 /* Cache ACPI device information. */ 348 buf.Length = ACPI_ALLOCATE_BUFFER; 349 if (ACPI_FAILURE(AcpiGetObjectInfo(hdl, &buf))) { 350 cmn_err(CE_WARN, "!acpidev: failed to get object info for %s " 351 "in acpidev_alloc_walk_info().", infop->awi_name); 352 acpidev_free_object_name(infop->awi_name); 353 kmem_free(infop, sizeof (*infop)); 354 return (NULL); 355 } 356 infop->awi_info = buf.Pointer; 357 358 /* 359 * Get or create an ACPI object data handle, which will be used to 360 * maintain object status information. 361 */ 362 if ((datap = acpidev_data_get_handle(hdl)) != NULL) { 363 ASSERT(datap->aod_hdl == hdl); 364 ASSERT(datap->aod_level == lvl); 365 } else if ((datap = acpidev_data_create_handle(hdl)) != NULL) { 366 datap->aod_level = lvl; 367 datap->aod_hdl = hdl; 368 } else { 369 ACPIDEV_DEBUG(CE_WARN, "acpidev: failed to create object " 370 "handle for %s in acpidev_alloc_walk_info().", 371 infop->awi_name); 372 AcpiOsFree(infop->awi_info); 373 acpidev_free_object_name(infop->awi_name); 374 kmem_free(infop, sizeof (*infop)); 375 return (NULL); 376 } 377 infop->awi_data = datap; 378 /* Sync DEVICE_CREATED flag. */ 379 if (datap->aod_iflag & ACPIDEV_ODF_DEVINFO_CREATED) { 380 ASSERT(datap->aod_dip != NULL); 381 ASSERT(datap->aod_class != NULL); 382 infop->awi_dip = datap->aod_dip; 383 infop->awi_flags |= ACPIDEV_WI_DEVICE_CREATED; 384 } 385 386 return (infop); 387 } 388 389 void 390 acpidev_free_walk_info(acpidev_walk_info_t *infop) 391 { 392 /* 393 * The ACPI object data handle will only be released when the 394 * corresponding object is going to be destroyed. 395 */ 396 if (infop != NULL) { 397 if (infop->awi_info != NULL) { 398 AcpiOsFree(infop->awi_info); 399 } 400 if (infop->awi_name != NULL) { 401 acpidev_free_object_name(infop->awi_name); 402 } 403 kmem_free(infop, sizeof (*infop)); 404 } 405 } 406 407 dev_info_t * 408 acpidev_walk_info_get_pdip(acpidev_walk_info_t *infop) 409 { 410 while (infop != NULL) { 411 if (infop->awi_dip != NULL) { 412 return (infop->awi_dip); 413 } 414 infop = infop->awi_parent; 415 } 416 417 return (NULL); 418 } 419 420 /* 421 * Called to release resources when the corresponding object is going 422 * to be destroyed. 423 */ 424 /*ARGSUSED*/ 425 static void 426 acpidev_get_object_handler(ACPI_HANDLE hdl, UINT32 func, void *data) 427 { 428 acpidev_data_handle_t objhdl = data; 429 430 kmem_free(objhdl, sizeof (acpidev_data_handle_t)); 431 } 432 433 acpidev_data_handle_t 434 acpidev_data_get_handle(ACPI_HANDLE hdl) 435 { 436 void *ptr; 437 acpidev_data_handle_t objhdl = NULL; 438 439 if (ACPI_SUCCESS(AcpiGetData(hdl, acpidev_get_object_handler, &ptr))) { 440 objhdl = (acpidev_data_handle_t)ptr; 441 } 442 443 return (objhdl); 444 } 445 446 acpidev_data_handle_t 447 acpidev_data_create_handle(ACPI_HANDLE hdl) 448 { 449 acpidev_data_handle_t objhdl; 450 451 objhdl = kmem_zalloc(sizeof (*objhdl), KM_SLEEP); 452 if (ACPI_FAILURE(AcpiAttachData(hdl, acpidev_get_object_handler, 453 (void *)objhdl))) { 454 cmn_err(CE_WARN, 455 "!acpidev: failed to attach handle data to object."); 456 kmem_free(objhdl, sizeof (*objhdl)); 457 return (NULL); 458 } 459 460 return (objhdl); 461 } 462 463 void 464 acpidev_data_destroy_handle(ACPI_HANDLE hdl) 465 { 466 void *ptr; 467 468 if (ACPI_SUCCESS(AcpiGetData(hdl, acpidev_get_object_handler, &ptr)) && 469 ACPI_SUCCESS(AcpiDetachData(hdl, acpidev_get_object_handler))) { 470 kmem_free(ptr, sizeof (acpidev_data_handle_t)); 471 } 472 } 473 474 ACPI_HANDLE 475 acpidev_data_get_object(acpidev_data_handle_t hdl) 476 { 477 ASSERT(hdl != NULL); 478 return ((hdl != NULL) ? hdl->aod_hdl : NULL); 479 } 480 481 dev_info_t * 482 acpidev_data_get_devinfo(acpidev_data_handle_t hdl) 483 { 484 ASSERT(hdl != NULL); 485 if (hdl == NULL || 486 (hdl->aod_iflag & ACPIDEV_ODF_DEVINFO_CREATED) == 0) { 487 return (NULL); 488 } else { 489 ASSERT(hdl->aod_dip != NULL); 490 return (hdl->aod_dip); 491 } 492 } 493 494 int 495 acpidev_data_get_status(acpidev_data_handle_t hdl) 496 { 497 ASSERT(hdl != NULL); 498 if (hdl == NULL || 499 (hdl->aod_iflag & ACPIDEV_ODF_STATUS_VALID) == 0) { 500 return (0); 501 } else { 502 return (hdl->aod_status); 503 } 504 } 505 506 void 507 acpidev_data_set_flag(acpidev_data_handle_t hdl, uint32_t flag) 508 { 509 ASSERT(hdl != NULL); 510 hdl->aod_eflag |= flag; 511 } 512 513 void 514 acpidev_data_clear_flag(acpidev_data_handle_t hdl, uint32_t flag) 515 { 516 ASSERT(hdl != NULL); 517 hdl->aod_eflag &= ~flag; 518 } 519 520 uint32_t 521 acpidev_data_get_flag(acpidev_data_handle_t hdl, uint32_t flag) 522 { 523 ASSERT(hdl != NULL); 524 return (hdl->aod_eflag & flag); 525 } 526 527 static char * 528 acpidev_generate_pseudo_unitaddr(char *uid, acpidev_class_id_t cid, 529 char *buf, size_t len) 530 { 531 acpidev_pseudo_uid_t *up, **pp; 532 533 ASSERT(len >= 64); 534 ASSERT(cid >= 0 && cid < ACPIDEV_CLASS_ID_MAX); 535 if (cid < 0 || cid >= ACPIDEV_CLASS_ID_MAX) { 536 return (NULL); 537 } 538 539 mutex_enter(&acpidev_uid_heads[cid].apuh_lock); 540 for (pp = &acpidev_uid_heads[cid].apuh_first; *pp != NULL; 541 pp = &(*pp)->apu_next) { 542 if (strcmp(uid, (*pp)->apu_uid) == 0 && 543 (*pp)->apu_cid == cid) { 544 break; 545 } 546 } 547 /* uid doesn't exist, create one and insert it into the list. */ 548 if (*pp == NULL) { 549 up = kmem_zalloc(sizeof (*up), KM_SLEEP); 550 up->apu_uid = ddi_strdup(uid, KM_SLEEP); 551 up->apu_cid = cid; 552 up->apu_nid = acpidev_uid_heads[cid].apuh_id++; 553 *pp = up; 554 } 555 ASSERT(*pp != NULL); 556 mutex_exit(&acpidev_uid_heads[cid].apuh_lock); 557 558 /* 559 * Generate a special format unit address with three fields to 560 * guarantee uniqueness. Normal unit addresses for ACPI devices have 561 * either one or two fields. 562 */ 563 if (snprintf(buf, len, "%u,%u,0", (*pp)->apu_nid, cid) > len) { 564 return (NULL); 565 } 566 567 return (buf); 568 } 569 570 static char * 571 acpidev_gen_unitaddr(char *uid, char *fmt, char *buf, size_t len) 572 { 573 size_t i, cnt; 574 uint_t id1, id2; 575 576 ASSERT(len >= 64); 577 if (fmt == NULL || strlen(fmt) == 0) { 578 return (NULL); 579 } 580 581 /* 582 * Count '%' in format string to protect sscanf(). 583 * Only support '%u' and '%x', and maximum 2 conversions. 584 */ 585 for (cnt = 0, i = 0; fmt[i] != 0 && cnt <= 2; i++) { 586 if (fmt[i] != '%') { 587 continue; 588 } else if (fmt[i + 1] == 'u' || fmt[i + 1] == 'x') { 589 /* Skip next character. */ 590 i++; 591 cnt++; 592 } else { 593 /* Invalid conversion, stop walking. */ 594 cnt = SIZE_MAX; 595 } 596 } 597 if (cnt != 1 && cnt != 2) { 598 ACPIDEV_DEBUG(CE_WARN, 599 "acpidev: invalid uid format string '%s'.", fmt); 600 return (NULL); 601 } 602 603 /* Scan uid and generate unitaddr. */ 604 if (sscanf(uid, fmt, &id1, &id2) != cnt) { 605 return (NULL); 606 } 607 /* 608 * Reverse the order of the two IDs to match the requirements of the 609 * hotplug driver. 610 */ 611 if (cnt == 2 && snprintf(buf, len, "%u,%u", id2, id1) >= len) { 612 ACPIDEV_DEBUG(CE_WARN, 613 "acpidev: generated unitaddr is too long."); 614 return (NULL); 615 } else if (cnt == 1 && snprintf(buf, len, "%u", id1) >= len) { 616 ACPIDEV_DEBUG(CE_WARN, 617 "acpidev: generated unitaddr is too long."); 618 return (NULL); 619 } 620 621 return (buf); 622 } 623 624 char * 625 acpidev_generate_unitaddr(char *uid, char **fmts, size_t nfmt, 626 char *buf, size_t len) 627 { 628 size_t i; 629 uint_t count = 0; 630 ulong_t val; 631 char **formats = NULL; 632 char *rbuf = NULL; 633 char *endp = NULL; 634 635 ASSERT(len >= 64); 636 637 /* Use _UID as unit address if it's a decimal integer. */ 638 if (ddi_strtoul(uid, &endp, 10, &val) == 0 && 639 (endp == NULL || *endp == 0)) { 640 if (snprintf(buf, len, "%s", uid) >= len) { 641 return (NULL); 642 } else { 643 return (buf); 644 } 645 } 646 647 /* First handle uid format strings from device property. */ 648 if (ddi_prop_lookup_string_array(DDI_DEV_T_ANY, ddi_root_node(), 649 DDI_PROP_DONTPASS, 650 ACPIDEV_PROP_NAME_UID_FORMAT, &formats, &count) == DDI_SUCCESS) { 651 /* Walk through format strings and try to generate unitaddr. */ 652 for (i = 0; i < count && rbuf == NULL; i++) { 653 rbuf = acpidev_gen_unitaddr(uid, formats[i], buf, len); 654 } 655 ddi_prop_free(formats); 656 } 657 658 /* Then handle embedded uid format strings. */ 659 if (fmts != NULL) { 660 for (i = 0; i < nfmt && rbuf == NULL; i++) { 661 rbuf = acpidev_gen_unitaddr(uid, fmts[i], buf, len); 662 } 663 } 664 665 return (rbuf); 666 } 667 668 /* 669 * The Solaris device "unit-address" property is composed of a comma-delimited 670 * list of hexadecimal values. According to the ACPI spec, the ACPI _UID method 671 * could return an integer or a string. If it returns an integer, it is used 672 * as the unit-address as is. If _UID returns a string, we try to extract some 673 * meaningful integers to compose the unit-address property. If we fail to 674 * extract any integers, a pseudo-sequential number will be generated for the 675 * unit-address. 676 */ 677 ACPI_STATUS 678 acpidev_set_unitaddr(acpidev_walk_info_t *infop, char **fmts, size_t nfmt, 679 char *unitaddr) 680 { 681 char unit[64]; 682 683 ASSERT(infop != NULL); 684 ASSERT(infop->awi_dip != NULL); 685 ASSERT(infop->awi_info != NULL); 686 if (infop == NULL || infop->awi_dip == NULL || 687 infop->awi_info == NULL) { 688 ACPIDEV_DEBUG(CE_WARN, 689 "acpidev: invalid parameters in acpidev_set_unitaddr()."); 690 return (AE_BAD_PARAMETER); 691 } 692 693 if (infop->awi_info->Valid & ACPI_VALID_UID) { 694 if (ndi_prop_update_string(DDI_DEV_T_NONE, infop->awi_dip, 695 ACPIDEV_PROP_NAME_ACPI_UID, infop->awi_info->UniqueId.Value) 696 != NDI_SUCCESS) { 697 cmn_err(CE_WARN, 698 "!acpidev: failed to set UID property for %s.", 699 infop->awi_name); 700 return (AE_ERROR); 701 } 702 } 703 704 if (unitaddr == NULL && (infop->awi_info->Valid & ACPI_VALID_UID)) { 705 /* Try to generate unit address from _UID. */ 706 if (fmts == NULL) { 707 fmts = acpidev_uid_formats; 708 nfmt = sizeof (acpidev_uid_formats) / sizeof (char *); 709 } 710 unitaddr = acpidev_generate_unitaddr( 711 infop->awi_info->UniqueId.Value, fmts, nfmt, 712 unit, sizeof (unit)); 713 /* Generate pseudo sequential unit address. */ 714 if (unitaddr == NULL) { 715 unitaddr = acpidev_generate_pseudo_unitaddr( 716 infop->awi_info->UniqueId.Value, 717 infop->awi_class_curr->adc_class_id, 718 unit, sizeof (unit)); 719 } 720 if (unitaddr == NULL) { 721 cmn_err(CE_WARN, "!acpidev: failed to generate unit " 722 "address from %s.", 723 infop->awi_info->UniqueId.Value); 724 return (AE_ERROR); 725 } 726 } 727 if (unitaddr == NULL) { 728 /* 729 * Some ACPI objects may have no _UID method available, so we 730 * can't generate the "unit-address" property for them. 731 * On the other hand, it's legal to support such a device 732 * without a unit address, so return success here. 733 */ 734 return (AE_OK); 735 } 736 737 if (ndi_prop_update_string(DDI_DEV_T_NONE, infop->awi_dip, 738 ACPIDEV_PROP_NAME_UNIT_ADDR, unitaddr) != NDI_SUCCESS) { 739 cmn_err(CE_WARN, "!acpidev: failed to set unitaddr for %s.", 740 infop->awi_name); 741 return (AE_ERROR); 742 } 743 744 return (AE_OK); 745 } 746 747 ACPI_STATUS 748 acpidev_set_compatible(acpidev_walk_info_t *infop, char **compat, int acount) 749 { 750 int count, i, j; 751 char **compatible = NULL; 752 ACPI_DEVICE_INFO *di; 753 754 /* 755 * Generate compatible list for device based on: 756 * * Device HID if available 757 * * Device CIDs if available 758 * * property array passed in 759 */ 760 ASSERT(infop != NULL); 761 ASSERT(infop->awi_dip != NULL); 762 ASSERT(infop->awi_info != NULL); 763 ASSERT(compat != NULL || acount == 0); 764 if (infop == NULL || infop->awi_dip == NULL || 765 infop->awi_info == NULL || (compat == NULL && acount != 0)) { 766 ACPIDEV_DEBUG(CE_WARN, "acpidev: invalid parameters " 767 "in acpidev_set_compatible()."); 768 return (AE_BAD_PARAMETER); 769 } 770 771 /* Compute string count. */ 772 count = acount; 773 di = infop->awi_info; 774 if (di->Valid & ACPI_VALID_HID) { 775 count++; 776 } 777 if (di->Valid & ACPI_VALID_CID) { 778 count += di->CompatibilityId.Count; 779 } 780 compatible = kmem_zalloc(sizeof (char *) * count, KM_SLEEP); 781 782 /* Generate string array. */ 783 i = 0; 784 if (di->Valid & ACPI_VALID_HID) { 785 compatible[i++] = di->HardwareId.Value; 786 } 787 if (di->Valid & ACPI_VALID_CID) { 788 for (j = 0; j < di->CompatibilityId.Count; j++) { 789 compatible[i++] = di->CompatibilityId.Id[j].Value; 790 } 791 } 792 for (j = 0; j < acount; j++) { 793 compatible[i++] = compat[j]; 794 } 795 ASSERT(i == count); 796 797 /* Set "compatible" property. */ 798 if (ndi_prop_update_string_array(DDI_DEV_T_NONE, infop->awi_dip, 799 OBP_COMPATIBLE, compatible, count) != NDI_SUCCESS) { 800 cmn_err(CE_WARN, "!acpidev: failed to set compatible " 801 "property for %s in acpidev_set_compatible().", 802 infop->awi_name); 803 kmem_free(compatible, count * sizeof (char *)); 804 return (AE_ERROR); 805 } 806 kmem_free(compatible, count * sizeof (char *)); 807 808 return (AE_OK); 809 } 810