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