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