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 * Copyright (c) 2012 Gary Mills 23 * 24 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 25 * Use is subject to license terms. 26 */ 27 28 /* 29 * ACPI enumerator 30 */ 31 32 #include <sys/ddi.h> 33 #include <sys/sunddi.h> 34 #include <sys/sunndi.h> 35 #include <sys/note.h> 36 #include <sys/acpi/acpi.h> 37 #include <sys/acpica.h> 38 #include <util/sscanf.h> 39 40 41 static char keyboard_alias[] = "keyboard"; 42 static char mouse_alias[] = "mouse"; 43 #define ACPI_ENUM_DEBUG "acpi_enum_debug" 44 #define PARSE_RESOURCES_DEBUG 0x0001 45 #define MASTER_LOOKUP_DEBUG 0x0002 46 #define DEVICES_NOT_ENUMED 0x0004 47 #define PARSE_RES_IRQ 0x0008 48 #define PARSE_RES_DMA 0x0010 49 #define PARSE_RES_MEMORY 0x0020 50 #define PARSE_RES_IO 0x0040 51 #define PARSE_RES_ADDRESS 0x0080 52 #define ISA_DEVICE_ENUM 0x1000 53 #define PROCESS_CIDS 0x2000 54 static unsigned long acpi_enum_debug = 0x00; 55 56 static char USED_RESOURCES[] = "used-resources"; 57 static dev_info_t *usedrdip = NULL; 58 static unsigned short used_interrupts = 0; 59 static unsigned short used_dmas = 0; 60 typedef struct used_io_mem { 61 unsigned int start_addr; 62 unsigned int length; 63 struct used_io_mem *next; 64 } used_io_mem_t; 65 static used_io_mem_t *used_io_head = NULL; 66 static used_io_mem_t *used_mem_head = NULL; 67 static int used_io_count = 0; 68 static int used_mem_count = 0; 69 70 #define MAX_PARSED_ACPI_RESOURCES 255 71 #define ACPI_ISA_LIMIT 16 72 static int interrupt[ACPI_ISA_LIMIT], dma[ACPI_ISA_LIMIT]; 73 #define ACPI_ELEMENT_PACKAGE_LIMIT 32 74 #define EISA_ID_SIZE 7 75 76 /* 77 * insert used io/mem in increasing order 78 */ 79 static void 80 insert_used_resource(used_io_mem_t *used, int *used_count, used_io_mem_t **head) 81 { 82 used_io_mem_t *curr, *prev; 83 84 (*used_count)++; 85 if (*head == NULL) { 86 *head = used; 87 return; 88 } 89 curr = prev = *head; 90 /* find a place to insert */ 91 while ((curr != NULL) && 92 (curr->start_addr < used->start_addr)) { 93 prev = curr; 94 curr = curr->next; 95 } 96 if (prev == curr) { 97 /* head */ 98 *head = used; 99 used->next = curr; 100 return; 101 } else { 102 prev->next = used; 103 } 104 used->next = curr; 105 } 106 107 static void 108 add_used_io_mem(struct regspec *io, int io_count) 109 { 110 int i; 111 used_io_mem_t *used; 112 113 for (i = 0; i < io_count; i++) { 114 used = (used_io_mem_t *)kmem_zalloc(sizeof (used_io_mem_t), 115 KM_SLEEP); 116 used->start_addr = io[i].regspec_addr; 117 used->length = io[i].regspec_size; 118 if (io[i].regspec_bustype == 1) { 119 insert_used_resource(used, &used_io_count, 120 &used_io_head); 121 } else { 122 insert_used_resource(used, &used_mem_count, 123 &used_mem_head); 124 } 125 } 126 } 127 128 static void 129 parse_resources_irq(ACPI_RESOURCE *resource_ptr, int *interrupt_count) 130 { 131 int i; 132 133 for (i = 0; i < resource_ptr->Data.Irq.InterruptCount; i++) { 134 interrupt[(*interrupt_count)++] = 135 resource_ptr->Data.Irq.Interrupts[i]; 136 used_interrupts |= 1 << resource_ptr->Data.Irq.Interrupts[i]; 137 if (acpi_enum_debug & PARSE_RES_IRQ) { 138 cmn_err(CE_NOTE, "parse_resources() "\ 139 "IRQ num %u, intr # = %u", 140 i, resource_ptr->Data.Irq.Interrupts[i]); 141 } 142 } 143 } 144 145 static void 146 parse_resources_dma(ACPI_RESOURCE *resource_ptr, int *dma_count) 147 { 148 int i; 149 150 for (i = 0; i < resource_ptr->Data.Dma.ChannelCount; i++) { 151 dma[(*dma_count)++] = resource_ptr->Data.Dma.Channels[i]; 152 used_dmas |= 1 << resource_ptr->Data.Dma.Channels[i]; 153 if (acpi_enum_debug & PARSE_RES_DMA) { 154 cmn_err(CE_NOTE, "parse_resources() "\ 155 "DMA num %u, channel # = %u", 156 i, resource_ptr->Data.Dma.Channels[i]); 157 } 158 } 159 } 160 161 static void 162 parse_resources_io(ACPI_RESOURCE *resource_ptr, struct regspec *io, 163 int *io_count) 164 { 165 ACPI_RESOURCE_IO acpi_io = resource_ptr->Data.Io; 166 167 if (acpi_io.AddressLength == 0) 168 return; 169 170 io[*io_count].regspec_bustype = 1; /* io */ 171 io[*io_count].regspec_size = acpi_io.AddressLength; 172 io[*io_count].regspec_addr = acpi_io.Minimum; 173 if (acpi_enum_debug & PARSE_RES_IO) { 174 cmn_err(CE_NOTE, "parse_resources() "\ 175 "IO min 0x%X, max 0x%X, length: 0x%X", 176 acpi_io.Minimum, 177 acpi_io.Maximum, 178 acpi_io.AddressLength); 179 } 180 (*io_count)++; 181 } 182 183 static void 184 parse_resources_fixed_io(ACPI_RESOURCE *resource_ptr, struct regspec *io, 185 int *io_count) 186 { 187 ACPI_RESOURCE_FIXED_IO fixed_io = resource_ptr->Data.FixedIo; 188 189 if (fixed_io.AddressLength == 0) 190 return; 191 192 io[*io_count].regspec_bustype = 1; /* io */ 193 io[*io_count].regspec_addr = fixed_io.Address; 194 io[*io_count].regspec_size = fixed_io.AddressLength; 195 if (acpi_enum_debug & PARSE_RES_IO) { 196 cmn_err(CE_NOTE, "parse_resources() "\ 197 "Fixed IO 0x%X, length: 0x%X", 198 fixed_io.Address, fixed_io.AddressLength); 199 } 200 (*io_count)++; 201 } 202 203 static void 204 parse_resources_fixed_mem32(ACPI_RESOURCE *resource_ptr, struct regspec *io, 205 int *io_count) 206 { 207 ACPI_RESOURCE_FIXED_MEMORY32 fixed_mem32 = 208 resource_ptr->Data.FixedMemory32; 209 210 if (fixed_mem32.AddressLength == 0) 211 return; 212 213 io[*io_count].regspec_bustype = 0; /* memory */ 214 io[*io_count].regspec_addr = fixed_mem32.Address; 215 io[*io_count].regspec_size = fixed_mem32.AddressLength; 216 if (acpi_enum_debug & PARSE_RES_MEMORY) { 217 cmn_err(CE_NOTE, "parse_resources() "\ 218 "Fixed Mem 32 %ul, length: %ul", 219 fixed_mem32.Address, fixed_mem32.AddressLength); 220 } 221 (*io_count)++; 222 } 223 224 static void 225 parse_resources_mem32(ACPI_RESOURCE *resource_ptr, struct regspec *io, 226 int *io_count) 227 { 228 ACPI_RESOURCE_MEMORY32 mem32 = resource_ptr->Data.Memory32; 229 230 if (mem32.AddressLength == 0) 231 return; 232 233 if (resource_ptr->Data.Memory32.Minimum == 234 resource_ptr->Data.Memory32.Maximum) { 235 io[*io_count].regspec_bustype = 0; /* memory */ 236 io[*io_count].regspec_addr = mem32.Minimum; 237 io[*io_count].regspec_size = mem32.AddressLength; 238 (*io_count)++; 239 if (acpi_enum_debug & PARSE_RES_MEMORY) { 240 cmn_err(CE_NOTE, "parse_resources() "\ 241 "Mem 32 0x%X, length: 0x%X", 242 mem32.Minimum, mem32.AddressLength); 243 } 244 return; 245 } 246 if (acpi_enum_debug & PARSE_RES_MEMORY) { 247 cmn_err(CE_NOTE, "parse_resources() "\ 248 "MEM32 Min Max not equal!"); 249 cmn_err(CE_NOTE, "parse_resources() "\ 250 "Mem 32 Minimum 0x%X, Maximum: 0x%X", 251 mem32.Minimum, mem32.Maximum); 252 } 253 } 254 255 static void 256 parse_resources_addr16(ACPI_RESOURCE *resource_ptr, struct regspec *io, 257 int *io_count) 258 { 259 ACPI_RESOURCE_ADDRESS16 addr16 = 260 resource_ptr->Data.Address16; 261 262 if (addr16.AddressLength == 0) 263 return; 264 265 if (acpi_enum_debug & PARSE_RES_ADDRESS) { 266 if (addr16.ResourceType == ACPI_MEMORY_RANGE) { 267 cmn_err(CE_NOTE, "parse_resources() "\ 268 "ADDRESS 16 MEMORY RANGE"); 269 } else 270 if (addr16.ResourceType == ACPI_IO_RANGE) { 271 cmn_err(CE_NOTE, "parse_resources() "\ 272 "ADDRESS 16 IO RANGE"); 273 } else { 274 cmn_err(CE_NOTE, "parse_resources() "\ 275 "ADDRESS 16 OTHER"); 276 } 277 cmn_err(CE_NOTE, "parse_resources() "\ 278 "%s "\ 279 "MinAddressFixed 0x%X, "\ 280 "MaxAddressFixed 0x%X, "\ 281 "Minimum 0x%X, "\ 282 "Maximum 0x%X, "\ 283 "length: 0x%X\n", 284 addr16.ProducerConsumer == ACPI_CONSUMER ? 285 "CONSUMER" : "PRODUCER", 286 addr16.MinAddressFixed, 287 addr16.MaxAddressFixed, 288 addr16.Minimum, 289 addr16.Maximum, 290 addr16.AddressLength); 291 } 292 if (addr16.ProducerConsumer == ACPI_PRODUCER || 293 (addr16.ResourceType != ACPI_MEMORY_RANGE && 294 addr16.ResourceType != ACPI_IO_RANGE)) { 295 return; 296 } 297 if (addr16.AddressLength > 0) { 298 if (addr16.ResourceType == ACPI_MEMORY_RANGE) { 299 /* memory */ 300 io[*io_count].regspec_bustype = 0; 301 } else { 302 /* io */ 303 io[*io_count].regspec_bustype = 1; 304 } 305 io[*io_count].regspec_addr = addr16.Minimum; 306 io[*io_count].regspec_size = addr16.AddressLength; 307 (*io_count)++; 308 } 309 } 310 311 static void 312 parse_resources_addr32(ACPI_RESOURCE *resource_ptr, struct regspec *io, 313 int *io_count) 314 { 315 ACPI_RESOURCE_ADDRESS32 addr32 = 316 resource_ptr->Data.Address32; 317 318 if (addr32.AddressLength == 0) 319 return; 320 321 if (acpi_enum_debug & PARSE_RES_ADDRESS) { 322 if (addr32.ResourceType == ACPI_MEMORY_RANGE) { 323 cmn_err(CE_NOTE, "parse_resources() "\ 324 "ADDRESS 32 MEMORY RANGE"); 325 } else 326 if (addr32.ResourceType == ACPI_IO_RANGE) { 327 cmn_err(CE_NOTE, "parse_resources() "\ 328 "ADDRESS 32 IO RANGE"); 329 } else { 330 cmn_err(CE_NOTE, "parse_resources() "\ 331 "ADDRESS 32 OTHER"); 332 } 333 cmn_err(CE_NOTE, "parse_resources() "\ 334 "%s "\ 335 "MinAddressFixed 0x%X, "\ 336 "MaxAddressFixed 0x%X, "\ 337 "Minimum 0x%X, "\ 338 "Maximum 0x%X, "\ 339 "length: 0x%X\n", 340 addr32.ProducerConsumer == ACPI_CONSUMER ? 341 "CONSUMER" : "PRODUCER", 342 addr32.MinAddressFixed, 343 addr32.MaxAddressFixed, 344 addr32.Minimum, 345 addr32.Maximum, 346 addr32.AddressLength); 347 } 348 if (addr32.ProducerConsumer == ACPI_PRODUCER || 349 (addr32.ResourceType != ACPI_MEMORY_RANGE && 350 addr32.ResourceType != ACPI_IO_RANGE)) { 351 return; 352 } 353 if (addr32.AddressLength > 0) { 354 if (addr32.ResourceType == ACPI_MEMORY_RANGE) { 355 /* memory */ 356 io[*io_count].regspec_bustype = 0; 357 } else { 358 /* io */ 359 io[*io_count].regspec_bustype = 1; 360 } 361 io[*io_count].regspec_addr = addr32.Minimum; 362 io[*io_count].regspec_size = addr32.AddressLength; 363 (*io_count)++; 364 } 365 } 366 367 static void 368 parse_resources_addr64(ACPI_RESOURCE *resource_ptr, struct regspec *io, 369 int *io_count) 370 { 371 ACPI_RESOURCE_ADDRESS64 addr64 = 372 resource_ptr->Data.Address64; 373 374 if (addr64.AddressLength == 0) 375 return; 376 377 if (acpi_enum_debug & PARSE_RES_ADDRESS) { 378 if (addr64.ResourceType == ACPI_MEMORY_RANGE) { 379 cmn_err(CE_NOTE, "parse_resources() "\ 380 "ADDRESS 64 MEMORY RANGE"); 381 } else 382 if (addr64.ResourceType == ACPI_IO_RANGE) { 383 cmn_err(CE_NOTE, "parse_resources() "\ 384 "ADDRESS 64 IO RANGE"); 385 } else { 386 cmn_err(CE_NOTE, "parse_resources() "\ 387 "ADDRESS 64 OTHER"); 388 } 389 #ifdef _LP64 390 cmn_err(CE_NOTE, "parse_resources() "\ 391 "%s "\ 392 "MinAddressFixed 0x%X, "\ 393 "MaxAddressFixed 0x%X, "\ 394 "Minimum 0x%lX, "\ 395 "Maximum 0x%lX, "\ 396 "length: 0x%lX\n", 397 addr64.ProducerConsumer == ACPI_CONSUMER ? 398 "CONSUMER" : "PRODUCER", 399 addr64.MinAddressFixed, 400 addr64.MaxAddressFixed, 401 addr64.Minimum, 402 addr64.Maximum, 403 addr64.AddressLength); 404 #else 405 cmn_err(CE_NOTE, "parse_resources() "\ 406 "%s "\ 407 "MinAddressFixed 0x%X, "\ 408 "MaxAddressFixed 0x%X, "\ 409 "Minimum 0x%llX, "\ 410 "Maximum 0x%llX, "\ 411 "length: 0x%llX\n", 412 addr64.ProducerConsumer == ACPI_CONSUMER ? 413 "CONSUMER" : "PRODUCER", 414 addr64.MinAddressFixed, 415 addr64.MaxAddressFixed, 416 addr64.Minimum, 417 addr64.Maximum, 418 addr64.AddressLength); 419 #endif 420 } 421 if (addr64.ProducerConsumer == ACPI_PRODUCER || 422 (addr64.ResourceType != ACPI_MEMORY_RANGE && 423 addr64.ResourceType != ACPI_IO_RANGE)) { 424 return; 425 } 426 if (addr64.AddressLength > 0) { 427 if (addr64.ResourceType == ACPI_MEMORY_RANGE) { 428 /* memory */ 429 io[*io_count].regspec_bustype = 0; 430 } else { 431 /* io */ 432 io[*io_count].regspec_bustype = 1; 433 } 434 io[*io_count].regspec_addr = addr64.Minimum; 435 io[*io_count].regspec_size = addr64.AddressLength; 436 (*io_count)++; 437 } 438 } 439 440 static ACPI_STATUS 441 parse_resources(ACPI_HANDLE handle, dev_info_t *xdip, char *path) 442 { 443 ACPI_BUFFER buf; 444 ACPI_RESOURCE *resource_ptr; 445 ACPI_STATUS status; 446 char *current_ptr, *last_ptr; 447 struct regspec *io; 448 int io_count = 0, interrupt_count = 0, dma_count = 0; 449 int i; 450 451 buf.Length = ACPI_ALLOCATE_BUFFER; 452 status = AcpiGetCurrentResources(handle, &buf); 453 switch (status) { 454 case AE_OK: 455 break; 456 case AE_NOT_FOUND: 457 /* 458 * Workaround for faulty DSDT tables that omit the _CRS 459 * method for the UAR3 device but have a valid _PRS method 460 * for that device. 461 */ 462 status = AcpiGetPossibleResources(handle, &buf); 463 if (status != AE_OK) { 464 return (status); 465 } 466 break; 467 default: 468 cmn_err(CE_WARN, 469 "!AcpiGetCurrentResources failed for %s, exception: %s", 470 path, AcpiFormatException(status)); 471 return (status); 472 break; 473 } 474 io = (struct regspec *)kmem_zalloc(sizeof (struct regspec) * 475 MAX_PARSED_ACPI_RESOURCES, KM_SLEEP); 476 current_ptr = buf.Pointer; 477 last_ptr = (char *)buf.Pointer + buf.Length; 478 while (current_ptr < last_ptr) { 479 if (io_count >= MAX_PARSED_ACPI_RESOURCES) { 480 break; 481 } 482 resource_ptr = (ACPI_RESOURCE *)current_ptr; 483 current_ptr += resource_ptr->Length; 484 switch (resource_ptr->Type) { 485 case ACPI_RESOURCE_TYPE_END_TAG: 486 current_ptr = last_ptr; 487 break; 488 case ACPI_RESOURCE_TYPE_IO: 489 parse_resources_io(resource_ptr, io, &io_count); 490 break; 491 case ACPI_RESOURCE_TYPE_FIXED_IO: 492 parse_resources_fixed_io(resource_ptr, io, &io_count); 493 break; 494 case ACPI_RESOURCE_TYPE_FIXED_MEMORY32: 495 parse_resources_fixed_mem32(resource_ptr, io, 496 &io_count); 497 break; 498 case ACPI_RESOURCE_TYPE_MEMORY32: 499 parse_resources_mem32(resource_ptr, io, &io_count); 500 break; 501 case ACPI_RESOURCE_TYPE_ADDRESS16: 502 parse_resources_addr16(resource_ptr, io, &io_count); 503 break; 504 case ACPI_RESOURCE_TYPE_ADDRESS32: 505 parse_resources_addr32(resource_ptr, io, &io_count); 506 break; 507 case ACPI_RESOURCE_TYPE_ADDRESS64: 508 parse_resources_addr64(resource_ptr, io, &io_count); 509 break; 510 case ACPI_RESOURCE_TYPE_IRQ: 511 parse_resources_irq(resource_ptr, &interrupt_count); 512 break; 513 case ACPI_RESOURCE_TYPE_DMA: 514 parse_resources_dma(resource_ptr, &dma_count); 515 break; 516 case ACPI_RESOURCE_TYPE_START_DEPENDENT: 517 cmn_err(CE_NOTE, 518 "!ACPI source type" 519 " ACPI_RESOURCE_TYPE_START_DEPENDENT" 520 " not supported"); 521 break; 522 case ACPI_RESOURCE_TYPE_END_DEPENDENT: 523 cmn_err(CE_NOTE, 524 "!ACPI source type" 525 " ACPI_RESOURCE_TYPE_END_DEPENDENT" 526 " not supported"); 527 break; 528 case ACPI_RESOURCE_TYPE_VENDOR: 529 cmn_err(CE_NOTE, 530 "!ACPI source type" 531 " ACPI_RESOURCE_TYPE_VENDOR" 532 " not supported"); 533 break; 534 case ACPI_RESOURCE_TYPE_MEMORY24: 535 cmn_err(CE_NOTE, 536 "!ACPI source type" 537 " ACPI_RESOURCE_TYPE_MEMORY24" 538 " not supported"); 539 break; 540 case ACPI_RESOURCE_TYPE_EXTENDED_IRQ: 541 cmn_err(CE_NOTE, 542 "!ACPI source type" 543 " ACPI_RESOURCE_TYPE_EXT_IRQ" 544 " not supported"); 545 break; 546 default: 547 /* Some types are not yet implemented (See CA 6.4) */ 548 cmn_err(CE_NOTE, 549 "!ACPI resource type (0X%X) not yet supported", 550 resource_ptr->Type); 551 break; 552 } 553 } 554 555 if (io_count) { 556 /* 557 * on LX50, you get interrupts of mouse and keyboard 558 * from separate PNP id... 559 */ 560 if (io_count == 2) { 561 if ((io[0].regspec_addr == 0x60 && 562 io[1].regspec_addr == 0x64) || 563 (io[0].regspec_addr == 0x64 && 564 io[1].regspec_addr == 0x60)) { 565 interrupt[0] = 0x1; 566 interrupt[1] = 0xc; 567 interrupt_count = 2; 568 used_interrupts |= 569 1 << interrupt[0]; 570 used_interrupts |= 571 1 << interrupt[1]; 572 } 573 } 574 add_used_io_mem(io, io_count); 575 if (xdip != NULL) { 576 (void) ndi_prop_update_int_array(DDI_DEV_T_NONE, xdip, 577 "reg", (int *)io, 3*io_count); 578 } 579 } 580 if (interrupt_count && (xdip != NULL)) { 581 (void) ndi_prop_update_int_array(DDI_DEV_T_NONE, xdip, 582 "interrupts", (int *)interrupt, interrupt_count); 583 } 584 if (dma_count && (xdip != NULL)) { 585 (void) ndi_prop_update_int_array(DDI_DEV_T_NONE, xdip, 586 "dma-channels", (int *)dma, dma_count); 587 } 588 AcpiOsFree(buf.Pointer); 589 kmem_free(io, sizeof (struct regspec) * MAX_PARSED_ACPI_RESOURCES); 590 return (status); 591 } 592 593 /* keyboard mouse is under i8042, everything else under isa */ 594 static dev_info_t * 595 get_bus_dip(char *nodename, dev_info_t *isa_dip) 596 { 597 static dev_info_t *i8042_dip = NULL; 598 struct regspec i8042_regs[] = { 599 {1, 0x60, 0x1}, 600 {1, 0x64, 0x1} 601 }; 602 int i8042_intrs[] = {0x1, 0xc}; 603 604 if (strcmp(nodename, keyboard_alias) != 0 && 605 strcmp(nodename, mouse_alias) != 0) 606 return (isa_dip); 607 608 if (i8042_dip) 609 return (i8042_dip); 610 611 ndi_devi_alloc_sleep(isa_dip, "i8042", (pnode_t)DEVI_SID_NODEID, 612 &i8042_dip); 613 (void) ndi_prop_update_int_array(DDI_DEV_T_NONE, i8042_dip, 614 "reg", (int *)i8042_regs, 6); 615 (void) ndi_prop_update_int_array(DDI_DEV_T_NONE, i8042_dip, 616 "interrupts", (int *)i8042_intrs, 2); 617 (void) ndi_prop_update_string(DDI_DEV_T_NONE, i8042_dip, 618 "unit-address", "1,60"); 619 (void) ndi_devi_bind_driver(i8042_dip, 0); 620 return (i8042_dip); 621 } 622 623 /* 624 * put content of properties (if any) to dev info tree at branch xdip 625 * return non-zero if a "compatible" property was processed, zero otherwise 626 * 627 */ 628 static int 629 process_properties(dev_info_t *xdip, property_t *properties) 630 { 631 int rv = 0; 632 633 while (properties != NULL) { 634 (void) ndi_prop_update_string(DDI_DEV_T_NONE, xdip, 635 properties->name, properties->value); 636 if (strcmp(properties->name, "compatible") == 0) 637 rv = 1; 638 properties = properties->next; 639 } 640 641 return (rv); 642 } 643 644 void 645 eisa_to_str(ACPI_INTEGER id, char *np) 646 { 647 static const char hextab[] = "0123456789ABCDEF"; 648 649 /* 650 * Expand an EISA device name: 651 * 652 * This routine converts a 32-bit EISA device "id" to a 653 * 7-byte ASCII device name, which is stored at "np". 654 */ 655 656 *np++ = '@' + ((id >> 2) & 0x1F); 657 *np++ = '@' + ((id << 3) & 0x18) + ((id >> 13) & 0x07); 658 *np++ = '@' + ((id >> 8) & 0x1F); 659 *np++ = hextab[(id >> 20) & 0x0F]; 660 *np++ = hextab[(id >> 16) & 0x0F]; 661 *np++ = hextab[(id >> 28) & 0x0F]; 662 *np++ = hextab[(id >> 24) & 0x0F]; 663 *np = 0; 664 } 665 666 /* 667 * process_cids() -- process multiple CIDs in a package 668 */ 669 static void 670 process_cids(ACPI_OBJECT *rv, device_id_t **dd) 671 { 672 device_id_t *d; 673 char tmp_cidstr[8]; /* 7-character EISA ID */ 674 int i; 675 676 if ((rv->Package.Count == 0) || rv->Package.Elements == NULL) 677 return; /* empty package */ 678 679 /* 680 * Work the package 'backwards' so the resulting list is 681 * in original order of preference. 682 */ 683 for (i = rv->Package.Count - 1; i >= 0; i--) { 684 /* get the actual acpi_object */ 685 ACPI_OBJECT obj = rv->Package.Elements[i]; 686 switch (obj.Type) { 687 case ACPI_TYPE_INTEGER: 688 eisa_to_str(obj.Integer.Value, tmp_cidstr); 689 d = mf_alloc_device_id(); 690 d->id = strdup(tmp_cidstr); 691 d->next = *dd; 692 *dd = d; 693 break; 694 case ACPI_TYPE_STRING: 695 d = mf_alloc_device_id(); 696 d->id = strdup(obj.String.Pointer); 697 d->next = *dd; 698 *dd = d; 699 break; 700 default: 701 if (acpi_enum_debug & PROCESS_CIDS) { 702 cmn_err(CE_NOTE, "unexpected CID type: %d", 703 obj.Type); 704 } 705 break; 706 } 707 } 708 } 709 710 /* 711 * Convert "raw" PNP and ACPI IDs to IEEE 1275-compliant form. 712 * Some liberty is taken here, treating "ACPI" as a special form 713 * of PNP vendor ID. strsize specifies size of buffer. 714 */ 715 static void 716 convert_to_pnp1275(char *pnpid, char *str, int strsize) 717 { 718 char vendor[5]; 719 uint_t id; 720 721 if (strncmp(pnpid, "ACPI", 4) == 0) { 722 /* Assume ACPI ID: ACPIxxxx */ 723 sscanf(pnpid, "%4s%x", vendor, &id); 724 } else { 725 /* Assume PNP ID: aaaxxxx */ 726 sscanf(pnpid, "%3s%x", vendor, &id); 727 } 728 729 snprintf(str, strsize, "pnp%s,%x", vendor, id); 730 } 731 732 /* 733 * Given a list of device ID elements in most-to-least-specific 734 * order, create a "compatible" property. 735 */ 736 static void 737 create_compatible_property(dev_info_t *dip, device_id_t *ids) 738 { 739 char **strs; 740 int list_len, i; 741 device_id_t *d; 742 743 /* count list length */ 744 list_len = 0; 745 d = ids; 746 while (d != NULL) { 747 list_len++; 748 d = d->next; 749 } 750 751 /* create string array */ 752 strs = (char **)kmem_zalloc(list_len * sizeof (char *), KM_SLEEP); 753 i = 0; 754 d = ids; 755 while (d != NULL) { 756 /* strlen("pnpXXXX,xxxx") + 1 = 13 */ 757 strs[i] = kmem_zalloc(13, KM_SLEEP); 758 convert_to_pnp1275(d->id, strs[i++], 13); 759 d = d->next; 760 } 761 762 /* update property */ 763 (void) ndi_prop_update_string_array(DDI_DEV_T_NONE, dip, 764 "compatible", strs, list_len); 765 766 767 /* free memory */ 768 for (i = 0; i < list_len; i++) 769 kmem_free(strs[i], 13); 770 771 kmem_free(strs, list_len * sizeof (char *)); 772 } 773 774 /* 775 * isa_acpi_callback() 776 */ 777 static ACPI_STATUS 778 isa_acpi_callback(ACPI_HANDLE ObjHandle, uint32_t NestingLevel, void *a, 779 void **b) 780 { 781 _NOTE(ARGUNUSED(NestingLevel, b)) 782 783 ACPI_BUFFER rb; 784 ACPI_DEVICE_INFO *info = NULL; 785 char *path = NULL; 786 char *hidstr = NULL; 787 char tmp_cidstr[8]; /* EISAID size */ 788 dev_info_t *dip = (dev_info_t *)a; 789 dev_info_t *xdip = NULL; 790 device_id_t *d, *device_ids = NULL; 791 const master_rec_t *m; 792 int compatible_present = 0; 793 794 /* 795 * get full ACPI pathname for object 796 */ 797 rb.Length = ACPI_ALLOCATE_BUFFER; 798 rb.Pointer = NULL; 799 if (AcpiGetName(ObjHandle, ACPI_FULL_PATHNAME, &rb) != AE_OK) { 800 cmn_err(CE_WARN, "!acpi_enum: could not get pathname"); 801 goto done; 802 } 803 path = (char *)rb.Pointer; 804 805 /* 806 * Get device info object 807 */ 808 if (AcpiGetObjectInfo(ObjHandle, &info) != AE_OK) { 809 cmn_err(CE_WARN, "!acpi_enum: could not get device" 810 " info for %s", path); 811 goto done; 812 } 813 814 /* 815 * If device isn't present, we don't enumerate 816 * NEEDSWORK: what about docking bays and the like? 817 */ 818 if (info->Valid & ACPI_VALID_STA) { 819 /* 820 * CA 6.3.6 _STA method 821 * Bit 0 -- device is present 822 * Bit 1 -- device is enabled 823 * Bit 2 -- device is shown in UI 824 */ 825 if (!((info->CurrentStatus & 0x7) == 7)) { 826 if (acpi_enum_debug & DEVICES_NOT_ENUMED) { 827 cmn_err(CE_NOTE, "parse_resources() " 828 "Bad status 0x%x for %s", 829 info->CurrentStatus, path); 830 } 831 goto done; 832 } 833 } else { 834 cmn_err(CE_WARN, "!acpi_enum: no _STA for %s", path); 835 goto done; 836 } 837 838 /* 839 * Keep track of _HID value 840 */ 841 if (!(info->Valid & ACPI_VALID_HID)) { 842 /* No _HID, we skip this node */ 843 if (acpi_enum_debug & DEVICES_NOT_ENUMED) { 844 cmn_err(CE_NOTE, "parse_resources() " 845 "No _HID for %s", path); 846 } 847 goto done; 848 } 849 hidstr = info->HardwareId.String; 850 851 /* 852 * Attempt to get _CID value 853 */ 854 rb.Length = ACPI_ALLOCATE_BUFFER; 855 rb.Pointer = NULL; 856 if (AcpiEvaluateObject(ObjHandle, "_CID", NULL, &rb) == AE_OK && 857 rb.Length != 0) { 858 ACPI_OBJECT *rv = rb.Pointer; 859 860 switch (rv->Type) { 861 case ACPI_TYPE_INTEGER: 862 eisa_to_str(rv->Integer.Value, tmp_cidstr); 863 d = mf_alloc_device_id(); 864 d->id = strdup(tmp_cidstr); 865 d->next = device_ids; 866 device_ids = d; 867 break; 868 case ACPI_TYPE_STRING: 869 d = mf_alloc_device_id(); 870 d->id = strdup(rv->String.Pointer); 871 d->next = device_ids; 872 device_ids = d; 873 break; 874 case ACPI_TYPE_PACKAGE: 875 process_cids(rv, &device_ids); 876 break; 877 default: 878 break; 879 } 880 AcpiOsFree(rb.Pointer); 881 } 882 883 /* 884 * Add _HID last so it's at the head of the list 885 */ 886 d = mf_alloc_device_id(); 887 d->id = strdup(hidstr); 888 d->next = device_ids; 889 device_ids = d; 890 891 /* 892 * master_file_lookup() expects _HID first in device_ids 893 */ 894 if ((m = master_file_lookup(device_ids)) != NULL) { 895 /* PNP description found in master table */ 896 if (!(strncmp(hidstr, "ACPI", 4))) { 897 dip = ddi_root_node(); 898 } else { 899 dip = get_bus_dip(m->name, dip); 900 } 901 ndi_devi_alloc_sleep(dip, m->name, 902 (pnode_t)DEVI_SID_NODEID, &xdip); 903 (void) ndi_prop_update_string(DDI_DEV_T_NONE, xdip, 904 "model", m->description); 905 compatible_present = process_properties(xdip, m->properties); 906 } else { 907 /* for ISA devices not known to the master file */ 908 if (!(strncmp(hidstr, "PNP03", 5))) { 909 /* a keyboard device includes PNP03xx */ 910 dip = get_bus_dip(keyboard_alias, dip); 911 ndi_devi_alloc_sleep(dip, keyboard_alias, 912 (pnode_t)DEVI_SID_NODEID, &xdip); 913 (void) ndi_prop_update_string(DDI_DEV_T_NONE, xdip, 914 "compatible", "pnpPNP,303"); 915 (void) ndi_prop_update_string(DDI_DEV_T_NONE, xdip, 916 "model", "PNP03xx keyboard"); 917 } else { 918 if (!(strncmp(hidstr, "PNP0F", 5))) { 919 /* a mouse device include PNP0Fxx */ 920 dip = get_bus_dip(mouse_alias, dip); 921 ndi_devi_alloc_sleep(dip, mouse_alias, 922 (pnode_t)DEVI_SID_NODEID, &xdip); 923 (void) ndi_prop_update_string(DDI_DEV_T_NONE, 924 xdip, "compatible", "pnpPNP,f03"); 925 (void) ndi_prop_update_string(DDI_DEV_T_NONE, 926 xdip, "model", "PNP0Fxx mouse"); 927 } else { 928 (void) parse_resources(ObjHandle, xdip, path); 929 goto done; 930 } 931 } 932 } 933 934 (void) ndi_prop_update_string(DDI_DEV_T_NONE, xdip, "acpi-namespace", 935 path); 936 937 (void) parse_resources(ObjHandle, xdip, path); 938 939 /* Special processing for mouse and keyboard devices per IEEE 1275 */ 940 /* if master entry doesn't contain "compatible" then we add default */ 941 if (strcmp(m->name, keyboard_alias) == 0) { 942 (void) ndi_prop_update_int(DDI_DEV_T_NONE, xdip, "reg", 0); 943 (void) ndi_prop_update_string(DDI_DEV_T_NONE, xdip, 944 "device-type", keyboard_alias); 945 if (!compatible_present) 946 (void) ndi_prop_update_string(DDI_DEV_T_NONE, xdip, 947 "compatible", "pnpPNP,303"); 948 } else if (strcmp(m->name, mouse_alias) == 0) { 949 (void) ndi_prop_update_int(DDI_DEV_T_NONE, xdip, "reg", 1); 950 (void) ndi_prop_update_string(DDI_DEV_T_NONE, xdip, 951 "device-type", mouse_alias); 952 if (!compatible_present) 953 (void) ndi_prop_update_string(DDI_DEV_T_NONE, xdip, 954 "compatible", "pnpPNP,f03"); 955 } 956 957 /* 958 * Create default "compatible" property if required 959 */ 960 if (!ddi_prop_exists(DDI_DEV_T_ANY, xdip, 961 DDI_PROP_DONTPASS, "compatible")) 962 create_compatible_property(xdip, device_ids); 963 964 (void) ndi_devi_bind_driver(xdip, 0); 965 966 done: 967 /* discard _HID/_CID list */ 968 d = device_ids; 969 while (d != NULL) { 970 device_id_t *next; 971 972 next = d->next; 973 mf_free_device_id(d); 974 d = next; 975 } 976 977 if (path != NULL) 978 AcpiOsFree(path); 979 if (info != NULL) 980 AcpiOsFree(info); 981 982 return (AE_OK); 983 } 984 985 static void 986 used_res_interrupts(void) 987 { 988 int intr[ACPI_ISA_LIMIT]; 989 int count = 0; 990 int i; 991 992 for (i = 0; i < ACPI_ISA_LIMIT; i++) { 993 if ((used_interrupts >> i) & 1) { 994 intr[count++] = i; 995 } 996 } 997 (void) ndi_prop_update_int_array(DDI_DEV_T_NONE, usedrdip, 998 "interrupts", (int *)intr, count); 999 } 1000 1001 static void 1002 used_res_dmas(void) 1003 { 1004 int dma[ACPI_ISA_LIMIT]; 1005 int count = 0; 1006 int i; 1007 1008 for (i = 0; i < ACPI_ISA_LIMIT; i++) { 1009 if ((used_dmas >> i) & 1) { 1010 dma[count++] = i; 1011 } 1012 } 1013 (void) ndi_prop_update_int_array(DDI_DEV_T_NONE, usedrdip, 1014 "dma-channels", (int *)dma, count); 1015 } 1016 1017 static void 1018 used_res_io_mem(char *nodename, int *count, used_io_mem_t **head) 1019 { 1020 int *io; 1021 used_io_mem_t *used = *head; 1022 int i; 1023 1024 *count *= 2; 1025 io = (int *)kmem_zalloc(sizeof (int)*(*count), KM_SLEEP); 1026 for (i = 0; i < *count; i += 2) { 1027 used_io_mem_t *prev; 1028 if (used != NULL) { 1029 io[i] = used->start_addr; 1030 io[i+1] = used->length; 1031 prev = used; 1032 used = used->next; 1033 kmem_free(prev, sizeof (used_io_mem_t)); 1034 } 1035 } 1036 (void) ndi_prop_update_int_array(DDI_DEV_T_NONE, usedrdip, 1037 nodename, (int *)io, *count); 1038 kmem_free(io, sizeof (int)*(*count)); 1039 *head = NULL; 1040 } 1041 1042 /* 1043 * acpi_isa_device_enum() -- call from isa nexus driver 1044 * returns 1 if deviced enumeration is successful 1045 * 0 if deviced enumeration fails 1046 */ 1047 int 1048 acpi_isa_device_enum(dev_info_t *isa_dip) 1049 { 1050 char *acpi_prop; 1051 1052 if (ddi_prop_lookup_string(DDI_DEV_T_ANY, ddi_root_node(), 1053 DDI_PROP_DONTPASS, ACPI_ENUM_DEBUG, &acpi_prop) == 1054 DDI_PROP_SUCCESS) { 1055 long data; 1056 if (ddi_strtol(acpi_prop, NULL, 0, &data) == 0) { 1057 acpi_enum_debug = (unsigned long)data; 1058 e_ddi_prop_remove(DDI_DEV_T_NONE, ddi_root_node(), 1059 ACPI_ENUM_DEBUG); 1060 e_ddi_prop_update_int(DDI_DEV_T_NONE, 1061 ddi_root_node(), ACPI_ENUM_DEBUG, data); 1062 } 1063 ddi_prop_free(acpi_prop); 1064 } 1065 1066 if (acpi_enum_debug & ISA_DEVICE_ENUM) { 1067 cmn_err(CE_NOTE, "acpi_isa_device_enum() called"); 1068 } 1069 1070 if (acpica_init() != AE_OK) { 1071 cmn_err(CE_WARN, "!isa_enum: init failed"); 1072 /* Note, pickup by i8042 nexus */ 1073 (void) e_ddi_prop_update_string(DDI_DEV_T_NONE, 1074 ddi_root_node(), "acpi-enum", "off"); 1075 return (0); 1076 } 1077 1078 usedrdip = ddi_find_devinfo(USED_RESOURCES, -1, 0); 1079 if (usedrdip == NULL) { 1080 ndi_devi_alloc_sleep(ddi_root_node(), USED_RESOURCES, 1081 (pnode_t)DEVI_SID_NODEID, &usedrdip); 1082 1083 } 1084 1085 process_master_file(); 1086 1087 /* 1088 * Do the actual enumeration. Avoid AcpiGetDevices because it 1089 * has an unnecessary internal callback that duplicates 1090 * determining if the device is present. 1091 */ 1092 (void) AcpiWalkNamespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, 1093 UINT32_MAX, isa_acpi_callback, NULL, isa_dip, NULL); 1094 1095 free_master_data(); 1096 used_res_interrupts(); 1097 used_res_dmas(); 1098 used_res_io_mem("device-memory", &used_mem_count, &used_mem_head); 1099 used_res_io_mem("io-space", &used_io_count, &used_io_head); 1100 (void) ndi_devi_bind_driver(usedrdip, 0); 1101 1102 return (1); 1103 }