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