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