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