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