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