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.String, 126 infop->HardwareId.Length) == 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->CompatibleIdList.Count; j++) { 136 if (strncmp(ids[i], 137 infop->CompatibleIdList.Ids[j].String, 138 infop->CompatibleIdList.Ids[j].Length) 139 == 0) { 140 return (B_TRUE); 141 } 142 } 143 } 144 } 145 146 return (B_FALSE); 147 } 148 149 struct acpidev_get_device_arg { 150 boolean_t skip_non_exist; 151 int id_count; 152 char **device_ids; 153 void *user_arg; 154 ACPI_WALK_CALLBACK user_func; 155 }; 156 157 static ACPI_STATUS 158 acpidev_get_device_callback(ACPI_HANDLE hdl, UINT32 level, void *arg, 159 void **retval) 160 { 161 ACPI_STATUS rc; 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 rc = AcpiGetObjectInfo(hdl, &infop); 171 if (ACPI_FAILURE(rc)) { 172 cmn_err(CE_WARN, "!acpidev: failed to get ACPI object info " 173 "in acpidev_get_device_callback()."); 174 return (AE_CTRL_DEPTH); 175 } 176 177 /* 178 * Skip scanning of children if the device is neither PRESENT nor 179 * FUNCTIONING. 180 * Please refer to ACPI Spec3.0b Sec 6.3.1 and 6.5.1. 181 */ 182 if (argp->skip_non_exist && (infop->Valid & ACPI_VALID_STA) && 183 !acpidev_check_device_present(infop->CurrentStatus)) { 184 rc = AE_CTRL_DEPTH; 185 /* Call user callback if matched. */ 186 } else if (acpidev_match_device_id(infop, argp->device_ids, 187 argp->id_count)) { 188 rc = argp->user_func(hdl, level, argp->user_arg, retval); 189 } else { 190 rc = AE_OK; 191 } 192 193 /* Free ACPI object info buffer. */ 194 AcpiOsFree(infop); 195 196 return (rc); 197 } 198 199 ACPI_STATUS 200 acpidev_get_device_by_id(ACPI_HANDLE hdl, char **ids, int count, 201 int maxdepth, boolean_t skip_non_exist, 202 ACPI_WALK_CALLBACK userfunc, void *userarg, void **retval) 203 { 204 ACPI_STATUS rc; 205 struct acpidev_get_device_arg arg; 206 207 ASSERT(userfunc != NULL); 208 if (hdl == NULL || userfunc == NULL || (ids == NULL && count != 0)) { 209 ACPIDEV_DEBUG(CE_WARN, "acpidev: invalid parameters " 210 "in acpidev_get_device_by_id()."); 211 return (AE_BAD_PARAMETER); 212 } 213 214 /* Enumerate all descendant objects. */ 215 arg.skip_non_exist = skip_non_exist; 216 arg.device_ids = ids; 217 arg.id_count = count; 218 arg.user_arg = userarg; 219 arg.user_func = userfunc; 220 rc = AcpiWalkNamespace(ACPI_TYPE_DEVICE, hdl, maxdepth, 221 &acpidev_get_device_callback, NULL, &arg, retval); 222 223 return (rc); 224 } 225 226 ACPI_STATUS 227 acpidev_walk_apic(ACPI_BUFFER *bufp, ACPI_HANDLE hdl, char *method, 228 acpidev_apic_walker_t func, void *context) 229 { 230 ACPI_STATUS rc; 231 ssize_t len; 232 ACPI_BUFFER buf; 233 ACPI_OBJECT *obj; 234 ACPI_SUBTABLE_HEADER *ap; 235 ACPI_TABLE_MADT *mp = NULL; 236 237 ASSERT(func != NULL); 238 if (func == NULL) { 239 ACPIDEV_DEBUG(CE_WARN, 240 "acpidev: invalid parameters for acpidev_walk_apic()."); 241 return (AE_BAD_PARAMETER); 242 } 243 244 buf.Pointer = NULL; 245 buf.Length = ACPI_ALLOCATE_BUFFER; 246 247 /* A walk buffer was passed in if bufp isn't NULL. */ 248 if (bufp != NULL) { 249 ap = (ACPI_SUBTABLE_HEADER *)(bufp->Pointer); 250 len = bufp->Length; 251 } else if (method != NULL) { 252 /* 253 * Otherwise, if we have an evaluate method, we get the walk 254 * buffer from a successful invocation of 255 * AcpiEvaluateObjectTyped(). 256 */ 257 ASSERT(hdl != NULL); 258 rc = AcpiEvaluateObjectTyped(hdl, method, NULL, &buf, 259 ACPI_TYPE_BUFFER); 260 if (ACPI_SUCCESS(rc)) { 261 ASSERT(buf.Length >= sizeof (*obj)); 262 obj = buf.Pointer; 263 ap = (ACPI_SUBTABLE_HEADER *)obj->Buffer.Pointer; 264 len = obj->Buffer.Length; 265 } else { 266 if (rc != AE_NOT_FOUND) 267 cmn_err(CE_WARN, "!acpidev: failed to evaluate " 268 "%s in acpidev_walk_apic().", method); 269 return (rc); 270 } 271 } else { 272 /* As a last resort, walk the MADT table. */ 273 rc = AcpiGetTable(ACPI_SIG_MADT, 1, (ACPI_TABLE_HEADER **)&mp); 274 if (ACPI_FAILURE(rc)) { 275 cmn_err(CE_WARN, "!acpidev: failed to get MADT table " 276 "in acpidev_walk_apic()."); 277 return (rc); 278 } 279 ap = (ACPI_SUBTABLE_HEADER *)(mp + 1); 280 len = mp->Header.Length - sizeof (*mp); 281 } 282 283 ASSERT(len >= 0); 284 for (rc = AE_OK; len > 0 && ACPI_SUCCESS(rc); len -= ap->Length, 285 ap = (ACPI_SUBTABLE_HEADER *)(((char *)ap) + ap->Length)) { 286 ASSERT(len >= sizeof (ACPI_SUBTABLE_HEADER)); 287 if (len <= sizeof (ACPI_SUBTABLE_HEADER) || 288 ap->Length <= sizeof (ACPI_SUBTABLE_HEADER) || 289 len < ap->Length) { 290 cmn_err(CE_WARN, 291 "!acpidev: invalid APIC entry in MADT/_MAT."); 292 break; 293 } 294 rc = (*func)(ap, context); 295 } 296 297 if (buf.Pointer != NULL) { 298 AcpiOsFree(buf.Pointer); 299 } 300 301 return (rc); 302 } 303 304 char * 305 acpidev_get_object_name(ACPI_HANDLE hdl) 306 { 307 ACPI_BUFFER buf; 308 char *objname = acpidev_unknown_object_name; 309 310 buf.Length = ACPI_ALLOCATE_BUFFER; 311 buf.Pointer = NULL; 312 if (ACPI_SUCCESS(AcpiGetName(hdl, ACPI_FULL_PATHNAME, &buf))) { 313 ASSERT(buf.Pointer != NULL); 314 objname = (char *)buf.Pointer; 315 } 316 317 return (objname); 318 } 319 320 void 321 acpidev_free_object_name(char *objname) 322 { 323 if (objname != acpidev_unknown_object_name && objname != NULL) { 324 AcpiOsFree(objname); 325 } 326 } 327 328 acpidev_walk_info_t * 329 acpidev_alloc_walk_info(acpidev_op_type_t op_type, int lvl, ACPI_HANDLE hdl, 330 acpidev_class_list_t **listpp, acpidev_walk_info_t *pinfop) 331 { 332 acpidev_walk_info_t *infop = NULL; 333 acpidev_data_handle_t datap = NULL; 334 335 ASSERT(0 <= lvl && lvl < ACPIDEV_MAX_ENUM_LEVELS); 336 infop = kmem_zalloc(sizeof (*infop), KM_SLEEP); 337 infop->awi_op_type = op_type; 338 infop->awi_level = lvl; 339 infop->awi_parent = pinfop; 340 infop->awi_class_list = listpp; 341 infop->awi_hdl = hdl; 342 infop->awi_name = acpidev_get_object_name(hdl); 343 344 /* Cache ACPI device information. */ 345 if (ACPI_FAILURE(AcpiGetObjectInfo(hdl, &infop->awi_info))) { 346 cmn_err(CE_WARN, "!acpidev: failed to get object info for %s " 347 "in acpidev_alloc_walk_info().", infop->awi_name); 348 acpidev_free_object_name(infop->awi_name); 349 kmem_free(infop, sizeof (*infop)); 350 return (NULL); 351 } 352 353 /* 354 * Get or create an ACPI object data handle, which will be used to 355 * maintain object status information. 356 */ 357 if ((datap = acpidev_data_get_handle(hdl)) != NULL) { 358 ASSERT(datap->aod_hdl == hdl); 359 ASSERT(datap->aod_level == lvl); 360 } else if ((datap = acpidev_data_create_handle(hdl)) != NULL) { 361 datap->aod_level = lvl; 362 datap->aod_hdl = hdl; 363 } else { 364 ACPIDEV_DEBUG(CE_WARN, "acpidev: failed to create object " 365 "handle for %s in acpidev_alloc_walk_info().", 366 infop->awi_name); 367 AcpiOsFree(infop->awi_info); 368 acpidev_free_object_name(infop->awi_name); 369 kmem_free(infop, sizeof (*infop)); 370 return (NULL); 371 } 372 infop->awi_data = datap; 373 /* Sync DEVICE_CREATED flag. */ 374 if (datap->aod_iflag & ACPIDEV_ODF_DEVINFO_CREATED) { 375 ASSERT(datap->aod_dip != NULL); 376 ASSERT(datap->aod_class != NULL); 377 infop->awi_dip = datap->aod_dip; 378 infop->awi_flags |= ACPIDEV_WI_DEVICE_CREATED; 379 } 380 381 return (infop); 382 } 383 384 void 385 acpidev_free_walk_info(acpidev_walk_info_t *infop) 386 { 387 /* 388 * The ACPI object data handle will only be released when the 389 * corresponding object is going to be destroyed. 390 */ 391 if (infop != NULL) { 392 if (infop->awi_info != NULL) { 393 AcpiOsFree(infop->awi_info); 394 } 395 if (infop->awi_name != NULL) { 396 acpidev_free_object_name(infop->awi_name); 397 } 398 kmem_free(infop, sizeof (*infop)); 399 } 400 } 401 402 dev_info_t * 403 acpidev_walk_info_get_pdip(acpidev_walk_info_t *infop) 404 { 405 while (infop != NULL) { 406 if (infop->awi_dip != NULL) { 407 return (infop->awi_dip); 408 } 409 infop = infop->awi_parent; 410 } 411 412 return (NULL); 413 } 414 415 /* 416 * Called to release resources when the corresponding object is going 417 * to be destroyed. 418 */ 419 /*ARGSUSED*/ 420 static void 421 acpidev_get_object_handler(ACPI_HANDLE hdl, void *data) 422 { 423 acpidev_data_handle_t objhdl = data; 424 425 kmem_free(objhdl, sizeof (acpidev_data_handle_t)); 426 } 427 428 acpidev_data_handle_t 429 acpidev_data_get_handle(ACPI_HANDLE hdl) 430 { 431 void *ptr; 432 acpidev_data_handle_t objhdl = NULL; 433 434 if (ACPI_SUCCESS(AcpiGetData(hdl, acpidev_get_object_handler, &ptr))) { 435 objhdl = (acpidev_data_handle_t)ptr; 436 } 437 438 return (objhdl); 439 } 440 441 acpidev_data_handle_t 442 acpidev_data_create_handle(ACPI_HANDLE hdl) 443 { 444 acpidev_data_handle_t objhdl; 445 446 objhdl = kmem_zalloc(sizeof (*objhdl), KM_SLEEP); 447 if (ACPI_FAILURE(AcpiAttachData(hdl, acpidev_get_object_handler, 448 (void *)objhdl))) { 449 cmn_err(CE_WARN, 450 "!acpidev: failed to attach handle data to object."); 451 kmem_free(objhdl, sizeof (*objhdl)); 452 return (NULL); 453 } 454 455 return (objhdl); 456 } 457 458 void 459 acpidev_data_destroy_handle(ACPI_HANDLE hdl) 460 { 461 void *ptr; 462 463 if (ACPI_SUCCESS(AcpiGetData(hdl, acpidev_get_object_handler, &ptr)) && 464 ACPI_SUCCESS(AcpiDetachData(hdl, acpidev_get_object_handler))) { 465 kmem_free(ptr, sizeof (acpidev_data_handle_t)); 466 } 467 } 468 469 ACPI_HANDLE 470 acpidev_data_get_object(acpidev_data_handle_t hdl) 471 { 472 ASSERT(hdl != NULL); 473 return ((hdl != NULL) ? hdl->aod_hdl : NULL); 474 } 475 476 dev_info_t * 477 acpidev_data_get_devinfo(acpidev_data_handle_t hdl) 478 { 479 ASSERT(hdl != NULL); 480 if (hdl == NULL || 481 (hdl->aod_iflag & ACPIDEV_ODF_DEVINFO_CREATED) == 0) { 482 return (NULL); 483 } else { 484 ASSERT(hdl->aod_dip != NULL); 485 return (hdl->aod_dip); 486 } 487 } 488 489 int 490 acpidev_data_get_status(acpidev_data_handle_t hdl) 491 { 492 ASSERT(hdl != NULL); 493 if (hdl == NULL || 494 (hdl->aod_iflag & ACPIDEV_ODF_STATUS_VALID) == 0) { 495 return (0); 496 } else { 497 return (hdl->aod_status); 498 } 499 } 500 501 void 502 acpidev_data_set_flag(acpidev_data_handle_t hdl, uint32_t flag) 503 { 504 ASSERT(hdl != NULL); 505 hdl->aod_eflag |= flag; 506 } 507 508 void 509 acpidev_data_clear_flag(acpidev_data_handle_t hdl, uint32_t flag) 510 { 511 ASSERT(hdl != NULL); 512 hdl->aod_eflag &= ~flag; 513 } 514 515 uint32_t 516 acpidev_data_get_flag(acpidev_data_handle_t hdl, uint32_t flag) 517 { 518 ASSERT(hdl != NULL); 519 return (hdl->aod_eflag & flag); 520 } 521 522 static char * 523 acpidev_generate_pseudo_unitaddr(char *uid, acpidev_class_id_t cid, 524 char *buf, size_t len) 525 { 526 acpidev_pseudo_uid_t *up, **pp; 527 528 ASSERT(len >= 64); 529 ASSERT(cid >= 0 && cid < ACPIDEV_CLASS_ID_MAX); 530 if (cid < 0 || cid >= ACPIDEV_CLASS_ID_MAX) { 531 return (NULL); 532 } 533 534 mutex_enter(&acpidev_uid_heads[cid].apuh_lock); 535 for (pp = &acpidev_uid_heads[cid].apuh_first; *pp != NULL; 536 pp = &(*pp)->apu_next) { 537 if (strcmp(uid, (*pp)->apu_uid) == 0 && 538 (*pp)->apu_cid == cid) { 539 break; 540 } 541 } 542 /* uid doesn't exist, create one and insert it into the list. */ 543 if (*pp == NULL) { 544 up = kmem_zalloc(sizeof (*up), KM_SLEEP); 545 up->apu_uid = ddi_strdup(uid, KM_SLEEP); 546 up->apu_cid = cid; 547 up->apu_nid = acpidev_uid_heads[cid].apuh_id++; 548 *pp = up; 549 } 550 ASSERT(*pp != NULL); 551 mutex_exit(&acpidev_uid_heads[cid].apuh_lock); 552 553 /* 554 * Generate a special format unit address with three fields to 555 * guarantee uniqueness. Normal unit addresses for ACPI devices have 556 * either one or two fields. 557 */ 558 if (snprintf(buf, len, "%u,%u,0", (*pp)->apu_nid, cid) > len) { 559 return (NULL); 560 } 561 562 return (buf); 563 } 564 565 static char * 566 acpidev_gen_unitaddr(char *uid, char *fmt, char *buf, size_t len) 567 { 568 size_t i, cnt; 569 uint_t id1, id2; 570 571 ASSERT(len >= 64); 572 if (fmt == NULL || strlen(fmt) == 0) { 573 return (NULL); 574 } 575 576 /* 577 * Count '%' in format string to protect sscanf(). 578 * Only support '%u' and '%x', and maximum 2 conversions. 579 */ 580 for (cnt = 0, i = 0; fmt[i] != 0 && cnt <= 2; i++) { 581 if (fmt[i] != '%') { 582 continue; 583 } else if (fmt[i + 1] == 'u' || fmt[i + 1] == 'x') { 584 /* Skip next character. */ 585 i++; 586 cnt++; 587 } else { 588 /* Invalid conversion, stop walking. */ 589 cnt = SIZE_MAX; 590 } 591 } 592 if (cnt != 1 && cnt != 2) { 593 ACPIDEV_DEBUG(CE_WARN, 594 "acpidev: invalid uid format string '%s'.", fmt); 595 return (NULL); 596 } 597 598 /* Scan uid and generate unitaddr. */ 599 if (sscanf(uid, fmt, &id1, &id2) != cnt) { 600 return (NULL); 601 } 602 /* 603 * Reverse the order of the two IDs to match the requirements of the 604 * hotplug driver. 605 */ 606 if (cnt == 2 && snprintf(buf, len, "%u,%u", id2, id1) >= len) { 607 ACPIDEV_DEBUG(CE_WARN, 608 "acpidev: generated unitaddr is too long."); 609 return (NULL); 610 } else if (cnt == 1 && snprintf(buf, len, "%u", id1) >= len) { 611 ACPIDEV_DEBUG(CE_WARN, 612 "acpidev: generated unitaddr is too long."); 613 return (NULL); 614 } 615 616 return (buf); 617 } 618 619 char * 620 acpidev_generate_unitaddr(char *uid, char **fmts, size_t nfmt, 621 char *buf, size_t len) 622 { 623 size_t i; 624 uint_t count = 0; 625 ulong_t val; 626 char **formats = NULL; 627 char *rbuf = NULL; 628 char *endp = NULL; 629 630 ASSERT(len >= 64); 631 632 /* Use _UID as unit address if it's a decimal integer. */ 633 if (ddi_strtoul(uid, &endp, 10, &val) == 0 && 634 (endp == NULL || *endp == 0)) { 635 if (snprintf(buf, len, "%s", uid) >= len) { 636 return (NULL); 637 } else { 638 return (buf); 639 } 640 } 641 642 /* First handle uid format strings from device property. */ 643 if (ddi_prop_lookup_string_array(DDI_DEV_T_ANY, ddi_root_node(), 644 DDI_PROP_DONTPASS, 645 ACPIDEV_PROP_NAME_UID_FORMAT, &formats, &count) == DDI_SUCCESS) { 646 /* Walk through format strings and try to generate unitaddr. */ 647 for (i = 0; i < count && rbuf == NULL; i++) { 648 rbuf = acpidev_gen_unitaddr(uid, formats[i], buf, len); 649 } 650 ddi_prop_free(formats); 651 } 652 653 /* Then handle embedded uid format strings. */ 654 if (fmts != NULL) { 655 for (i = 0; i < nfmt && rbuf == NULL; i++) { 656 rbuf = acpidev_gen_unitaddr(uid, fmts[i], buf, len); 657 } 658 } 659 660 return (rbuf); 661 } 662 663 /* 664 * The Solaris device "unit-address" property is composed of a comma-delimited 665 * list of hexadecimal values. According to the ACPI spec, the ACPI _UID method 666 * could return an integer or a string. If it returns an integer, it is used 667 * as the unit-address as is. If _UID returns a string, we try to extract some 668 * meaningful integers to compose the unit-address property. If we fail to 669 * extract any integers, a pseudo-sequential number will be generated for the 670 * unit-address. 671 */ 672 ACPI_STATUS 673 acpidev_set_unitaddr(acpidev_walk_info_t *infop, char **fmts, size_t nfmt, 674 char *unitaddr) 675 { 676 char unit[64]; 677 678 ASSERT(infop != NULL); 679 ASSERT(infop->awi_dip != NULL); 680 ASSERT(infop->awi_info != NULL); 681 if (infop == NULL || infop->awi_dip == NULL || 682 infop->awi_info == NULL) { 683 ACPIDEV_DEBUG(CE_WARN, 684 "acpidev: invalid parameters in acpidev_set_unitaddr()."); 685 return (AE_BAD_PARAMETER); 686 } 687 688 if (infop->awi_info->Valid & ACPI_VALID_UID) { 689 if (ndi_prop_update_string(DDI_DEV_T_NONE, infop->awi_dip, 690 ACPIDEV_PROP_NAME_ACPI_UID, 691 infop->awi_info->UniqueId.String) != NDI_SUCCESS) { 692 cmn_err(CE_WARN, 693 "!acpidev: failed to set UID property for %s.", 694 infop->awi_name); 695 return (AE_ERROR); 696 } 697 } 698 699 if (unitaddr == NULL && (infop->awi_info->Valid & ACPI_VALID_UID)) { 700 /* Try to generate unit address from _UID. */ 701 if (fmts == NULL) { 702 fmts = acpidev_uid_formats; 703 nfmt = sizeof (acpidev_uid_formats) / sizeof (char *); 704 } 705 unitaddr = acpidev_generate_unitaddr( 706 infop->awi_info->UniqueId.String, fmts, nfmt, 707 unit, sizeof (unit)); 708 /* Generate pseudo sequential unit address. */ 709 if (unitaddr == NULL) { 710 unitaddr = acpidev_generate_pseudo_unitaddr( 711 infop->awi_info->UniqueId.String, 712 infop->awi_class_curr->adc_class_id, 713 unit, sizeof (unit)); 714 } 715 if (unitaddr == NULL) { 716 cmn_err(CE_WARN, "!acpidev: failed to generate unit " 717 "address from %s.", 718 infop->awi_info->UniqueId.String); 719 return (AE_ERROR); 720 } 721 } 722 if (unitaddr == NULL) { 723 /* 724 * Some ACPI objects may have no _UID method available, so we 725 * can't generate the "unit-address" property for them. 726 * On the other hand, it's legal to support such a device 727 * without a unit address, so return success here. 728 */ 729 return (AE_OK); 730 } 731 732 if (ndi_prop_update_string(DDI_DEV_T_NONE, infop->awi_dip, 733 ACPIDEV_PROP_NAME_UNIT_ADDR, unitaddr) != NDI_SUCCESS) { 734 cmn_err(CE_WARN, "!acpidev: failed to set unitaddr for %s.", 735 infop->awi_name); 736 return (AE_ERROR); 737 } 738 739 return (AE_OK); 740 } 741 742 ACPI_STATUS 743 acpidev_set_compatible(acpidev_walk_info_t *infop, char **compat, int acount) 744 { 745 int count, i, j; 746 char **compatible = NULL; 747 ACPI_DEVICE_INFO *di; 748 749 /* 750 * Generate compatible list for device based on: 751 * * Device HID if available 752 * * Device CIDs if available 753 * * property array passed in 754 */ 755 ASSERT(infop != NULL); 756 ASSERT(infop->awi_dip != NULL); 757 ASSERT(infop->awi_info != NULL); 758 ASSERT(compat != NULL || acount == 0); 759 if (infop == NULL || infop->awi_dip == NULL || 760 infop->awi_info == NULL || (compat == NULL && acount != 0)) { 761 ACPIDEV_DEBUG(CE_WARN, "acpidev: invalid parameters " 762 "in acpidev_set_compatible()."); 763 return (AE_BAD_PARAMETER); 764 } 765 766 /* Compute string count. */ 767 count = acount; 768 di = infop->awi_info; 769 if (di->Valid & ACPI_VALID_HID) { 770 count++; 771 } 772 if (di->Valid & ACPI_VALID_CID) { 773 count += di->CompatibleIdList.Count; 774 } 775 compatible = kmem_zalloc(sizeof (char *) * count, KM_SLEEP); 776 777 /* Generate string array. */ 778 i = 0; 779 if (di->Valid & ACPI_VALID_HID) { 780 compatible[i++] = di->HardwareId.String; 781 } 782 if (di->Valid & ACPI_VALID_CID) { 783 for (j = 0; j < di->CompatibleIdList.Count; j++) { 784 compatible[i++] = di->CompatibleIdList.Ids[j].String; 785 } 786 } 787 for (j = 0; j < acount; j++) { 788 compatible[i++] = compat[j]; 789 } 790 ASSERT(i == count); 791 792 /* Set "compatible" property. */ 793 if (ndi_prop_update_string_array(DDI_DEV_T_NONE, infop->awi_dip, 794 OBP_COMPATIBLE, compatible, count) != NDI_SUCCESS) { 795 cmn_err(CE_WARN, "!acpidev: failed to set compatible " 796 "property for %s in acpidev_set_compatible().", 797 infop->awi_name); 798 kmem_free(compatible, count * sizeof (char *)); 799 return (AE_ERROR); 800 } 801 kmem_free(compatible, count * sizeof (char *)); 802 803 return (AE_OK); 804 } 805