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