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*cb565728SJerry 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
insert_used_resource(used_io_mem_t * used,int * used_count,used_io_mem_t ** head)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
add_used_io_mem(struct regspec * io,int io_count)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
parse_resources_irq(ACPI_RESOURCE * resource_ptr,int * interrupt_count)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*cb565728SJerry 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
parse_resources_dma(ACPI_RESOURCE * resource_ptr,int * dma_count)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*cb565728SJerry 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
parse_resources_io(ACPI_RESOURCE * resource_ptr,struct regspec * io,int * io_count)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*cb565728SJerry 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
parse_resources_fixed_io(ACPI_RESOURCE * resource_ptr,struct regspec * io,int * io_count)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*cb565728SJerry 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
parse_resources_fixed_mem32(ACPI_RESOURCE * resource_ptr,struct regspec * io,int * io_count)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*cb565728SJerry 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
parse_resources_mem32(ACPI_RESOURCE * resource_ptr,struct regspec * io,int * io_count)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*cb565728SJerry 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*cb565728SJerry Jelinek cmn_err(CE_NOTE, "!parse_resources() "\
249ae115bc7Smrj "MEM32 Min Max not equal!");
250*cb565728SJerry 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
parse_resources_addr16(ACPI_RESOURCE * resource_ptr,struct regspec * io,int * io_count)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*cb565728SJerry 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*cb565728SJerry Jelinek cmn_err(CE_NOTE, "!parse_resources() "\
269ae115bc7Smrj "ADDRESS 16 MEMORY RANGE");
270ae115bc7Smrj } else
271ae115bc7Smrj if (addr16.ResourceType == ACPI_IO_RANGE) {
272*cb565728SJerry Jelinek cmn_err(CE_NOTE, "!parse_resources() "\
273ae115bc7Smrj "ADDRESS 16 IO RANGE");
274ae115bc7Smrj } else {
275*cb565728SJerry Jelinek cmn_err(CE_NOTE, "!parse_resources() "\
276ae115bc7Smrj "ADDRESS 16 OTHER");
277ae115bc7Smrj }
278*cb565728SJerry 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*cb565728SJerry Jelinek addr16.Address.Minimum,
290*cb565728SJerry Jelinek addr16.Address.Maximum,
291*cb565728SJerry 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*cb565728SJerry 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*cb565728SJerry Jelinek io[*io_count].regspec_addr = addr16.Address.Minimum;
307*cb565728SJerry Jelinek io[*io_count].regspec_size = addr16.Address.AddressLength;
308ae115bc7Smrj (*io_count)++;
309ae115bc7Smrj }
310ae115bc7Smrj }
311ae115bc7Smrj
312ae115bc7Smrj static void
parse_resources_addr32(ACPI_RESOURCE * resource_ptr,struct regspec * io,int * io_count)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*cb565728SJerry 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*cb565728SJerry Jelinek cmn_err(CE_NOTE, "!parse_resources() "\
325ae115bc7Smrj "ADDRESS 32 MEMORY RANGE");
326ae115bc7Smrj } else
327ae115bc7Smrj if (addr32.ResourceType == ACPI_IO_RANGE) {
328*cb565728SJerry Jelinek cmn_err(CE_NOTE, "!parse_resources() "\
329ae115bc7Smrj "ADDRESS 32 IO RANGE");
330ae115bc7Smrj } else {
331*cb565728SJerry Jelinek cmn_err(CE_NOTE, "!parse_resources() "\
332ae115bc7Smrj "ADDRESS 32 OTHER");
333ae115bc7Smrj }
334*cb565728SJerry 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*cb565728SJerry Jelinek addr32.Address.Minimum,
346*cb565728SJerry Jelinek addr32.Address.Maximum,
347*cb565728SJerry 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*cb565728SJerry 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*cb565728SJerry Jelinek io[*io_count].regspec_addr = addr32.Address.Minimum;
363*cb565728SJerry Jelinek io[*io_count].regspec_size = addr32.Address.AddressLength;
364ae115bc7Smrj (*io_count)++;
365ae115bc7Smrj }
366ae115bc7Smrj }
367ae115bc7Smrj
368ae115bc7Smrj static void
parse_resources_addr64(ACPI_RESOURCE * resource_ptr,struct regspec * io,int * io_count)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*cb565728SJerry 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*cb565728SJerry Jelinek cmn_err(CE_NOTE, "!parse_resources() "\
381ae115bc7Smrj "ADDRESS 64 MEMORY RANGE");
382ae115bc7Smrj } else
383ae115bc7Smrj if (addr64.ResourceType == ACPI_IO_RANGE) {
384*cb565728SJerry Jelinek cmn_err(CE_NOTE, "!parse_resources() "\
385ae115bc7Smrj "ADDRESS 64 IO RANGE");
386ae115bc7Smrj } else {
387*cb565728SJerry Jelinek cmn_err(CE_NOTE, "!parse_resources() "\
388ae115bc7Smrj "ADDRESS 64 OTHER");
389ae115bc7Smrj }
390ae115bc7Smrj #ifdef _LP64
391*cb565728SJerry 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*cb565728SJerry Jelinek addr64.Address.Minimum,
403*cb565728SJerry Jelinek addr64.Address.Maximum,
404*cb565728SJerry Jelinek addr64.Address.AddressLength);
405ae115bc7Smrj #else
406*cb565728SJerry 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*cb565728SJerry Jelinek addr64.Address.Minimum,
418*cb565728SJerry Jelinek addr64.Address.Maximum,
419*cb565728SJerry 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*cb565728SJerry 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*cb565728SJerry Jelinek io[*io_count].regspec_addr = addr64.Address.Minimum;
436*cb565728SJerry Jelinek io[*io_count].regspec_size = addr64.Address.AddressLength;
437ae115bc7Smrj (*io_count)++;
438ae115bc7Smrj }
439ae115bc7Smrj }
440ae115bc7Smrj
441ae115bc7Smrj static ACPI_STATUS
parse_resources(ACPI_HANDLE handle,dev_info_t * xdip,char * path)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 *
get_bus_dip(char * nodename,dev_info_t * isa_dip)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
process_properties(dev_info_t * xdip,property_t * properties)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
eisa_to_str(ACPI_INTEGER id,char * np)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
process_cids(ACPI_OBJECT * rv,device_id_t ** dd)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*cb565728SJerry 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
convert_to_pnp1275(char * pnpid,char * str,int strsize)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
create_compatible_property(dev_info_t * dip,device_id_t * ids)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
isa_acpi_callback(ACPI_HANDLE ObjHandle,uint32_t NestingLevel,void * a,void ** b)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*cb565728SJerry 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*cb565728SJerry 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
used_res_interrupts(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
used_res_dmas(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
used_res_io_mem(char * nodename,int * count,used_io_mem_t ** head)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
acpi_isa_device_enum(dev_info_t * isa_dip)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*cb565728SJerry 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