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