xref: /illumos-gate/usr/src/uts/intel/io/acpica/acpi_enum.c (revision d4039345c8fe6e54a31d17d91e86e393fdcf401b)
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 /*
22aa2aa9a6SDana Myers  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23ae115bc7Smrj  * Use is subject to license terms.
241f9b2f1bSJason King  *
25*d4039345SRichard Lowe  * Copyright (c) 2012 Gary Mills
26*d4039345SRichard Lowe  * Copyright 2018, Joyent, Inc.
271f9b2f1bSJason King  * Copyright 2021 Racktop Systems, Inc.
28ae115bc7Smrj  */
29ae115bc7Smrj 
30ae115bc7Smrj /*
31ae115bc7Smrj  * ACPI enumerator
32ae115bc7Smrj  */
33ae115bc7Smrj 
34ae115bc7Smrj #include <sys/ddi.h>
35ae115bc7Smrj #include <sys/sunddi.h>
36ae115bc7Smrj #include <sys/sunndi.h>
37ae115bc7Smrj #include <sys/note.h>
38aa2aa9a6SDana Myers #include <sys/acpi/acpi.h>
39ae115bc7Smrj #include <sys/acpica.h>
40aa2aa9a6SDana Myers #include <util/sscanf.h>
411f9b2f1bSJason King #include <util/qsort.h>
42ae115bc7Smrj 
431f9b2f1bSJason King /*
441f9b2f1bSJason King  * Used to track the interrupts used by a resource, as well as the set of
451f9b2f1bSJason King  * interrupts used overall. The IRQ values are ints for historical purposes
461f9b2f1bSJason King  * (the "interrupts" property has traditionally been an array of ints) even
471f9b2f1bSJason King  * though negative IRQ values do not make much sense.
481f9b2f1bSJason King  */
491f9b2f1bSJason King typedef struct intrs {
501f9b2f1bSJason King 	int	*i_intrs;
511f9b2f1bSJason King 	uint_t	i_num;
521f9b2f1bSJason King 	uint_t	i_alloc;
531f9b2f1bSJason King } intrs_t;
54ae115bc7Smrj 
55*d4039345SRichard Lowe static uint32_t acpi_enum_debug = 0x00;
56ae115bc7Smrj #define	PARSE_RESOURCES_DEBUG	0x0001
57*d4039345SRichard Lowe #define	ISAPNP_LOOKUP_DEBUG	0x0002
58ae115bc7Smrj #define	DEVICES_NOT_ENUMED	0x0004
59ae115bc7Smrj #define	PARSE_RES_IRQ		0x0008
60ae115bc7Smrj #define	PARSE_RES_DMA		0x0010
61ae115bc7Smrj #define	PARSE_RES_MEMORY	0x0020
62ae115bc7Smrj #define	PARSE_RES_IO		0x0040
63ae115bc7Smrj #define	PARSE_RES_ADDRESS	0x0080
64ae115bc7Smrj #define	ISA_DEVICE_ENUM		0x1000
65ae115bc7Smrj #define	PROCESS_CIDS		0x2000
66ae115bc7Smrj 
67ae115bc7Smrj static dev_info_t *usedrdip = NULL;
681f9b2f1bSJason King static intrs_t used_interrupts;
69ae115bc7Smrj static unsigned short used_dmas = 0;
70ae115bc7Smrj typedef struct used_io_mem {
71ae115bc7Smrj 	unsigned int start_addr;
72ae115bc7Smrj 	unsigned int length;
73ae115bc7Smrj 	struct used_io_mem *next;
74ae115bc7Smrj } used_io_mem_t;
75ae115bc7Smrj static used_io_mem_t *used_io_head = NULL;
76ae115bc7Smrj static used_io_mem_t *used_mem_head = NULL;
77ae115bc7Smrj static int used_io_count = 0;
78ae115bc7Smrj static int used_mem_count = 0;
79ae115bc7Smrj 
80ae115bc7Smrj #define	MAX_PARSED_ACPI_RESOURCES	255
81ae115bc7Smrj #define	ACPI_ISA_LIMIT	16
821f9b2f1bSJason King static int dma[ACPI_ISA_LIMIT];
83ae115bc7Smrj #define	ACPI_ELEMENT_PACKAGE_LIMIT	32
84ae115bc7Smrj #define	EISA_ID_SIZE	7
85ae115bc7Smrj 
861f9b2f1bSJason King static void
add_interrupt(intrs_t * intrs,int irq)871f9b2f1bSJason King add_interrupt(intrs_t *intrs, int irq)
881f9b2f1bSJason King {
891f9b2f1bSJason King 	/* We only want to add the value once */
901f9b2f1bSJason King 	for (uint_t i = 0; i < intrs->i_num; i++) {
911f9b2f1bSJason King 		if (intrs->i_intrs[i] == irq)
921f9b2f1bSJason King 			return;
931f9b2f1bSJason King 	}
941f9b2f1bSJason King 
951f9b2f1bSJason King 	/*
961f9b2f1bSJason King 	 * Initially, i_num and i_alloc will be 0, and we allocate
971f9b2f1bSJason King 	 * i_intrs to hold ACPI_ISA_LIMIT values on the initial add attempt.
981f9b2f1bSJason King 	 * Since ISA buses could only use at most ACPI_ISA_LIMIT (16)
991f9b2f1bSJason King 	 * interrupts, this seems like a reasonable size. The extended IRQ
1001f9b2f1bSJason King 	 * resource however exists explicitly to support IRQ values beyond
1011f9b2f1bSJason King 	 * 16. That suggests it may be possible on some hardware to exceed
1021f9b2f1bSJason King 	 * the initial allocation. If we do exceed the initial allocation, we
1031f9b2f1bSJason King 	 * grow i_intrs in chunks of ACPI_ISA_LIMIT since that's as good an
1041f9b2f1bSJason King 	 * amount as any.
1051f9b2f1bSJason King 	 */
1061f9b2f1bSJason King 	if (intrs->i_num == intrs->i_alloc) {
1071f9b2f1bSJason King 		uint_t newlen = intrs->i_alloc + ACPI_ISA_LIMIT;
1081f9b2f1bSJason King 		size_t newsz = newlen * sizeof (int);
1091f9b2f1bSJason King 		size_t oldsz = intrs->i_alloc * sizeof (int);
1101f9b2f1bSJason King 		int *newar = kmem_alloc(newsz, KM_SLEEP);
1111f9b2f1bSJason King 
1121f9b2f1bSJason King 		if (intrs->i_num > 0) {
1131f9b2f1bSJason King 			bcopy(intrs->i_intrs, newar, oldsz);
1141f9b2f1bSJason King 			kmem_free(intrs->i_intrs, oldsz);
1151f9b2f1bSJason King 		}
1161f9b2f1bSJason King 
1171f9b2f1bSJason King 		intrs->i_intrs = newar;
1181f9b2f1bSJason King 		intrs->i_alloc = newlen;
1191f9b2f1bSJason King 	}
1201f9b2f1bSJason King 
1211f9b2f1bSJason King 	intrs->i_intrs[intrs->i_num++] = irq;
1221f9b2f1bSJason King }
1231f9b2f1bSJason King 
124ae115bc7Smrj /*
125ae115bc7Smrj  * insert used io/mem in increasing order
126ae115bc7Smrj  */
127ae115bc7Smrj static void
insert_used_resource(used_io_mem_t * used,int * used_count,used_io_mem_t ** head)128ae115bc7Smrj insert_used_resource(used_io_mem_t *used, int *used_count, used_io_mem_t **head)
129ae115bc7Smrj {
130ae115bc7Smrj 	used_io_mem_t *curr, *prev;
131ae115bc7Smrj 
132ae115bc7Smrj 	(*used_count)++;
133ae115bc7Smrj 	if (*head == NULL) {
134ae115bc7Smrj 		*head = used;
135ae115bc7Smrj 		return;
136ae115bc7Smrj 	}
137ae115bc7Smrj 	curr = prev = *head;
138ae115bc7Smrj 	/* find a place to insert */
139ae115bc7Smrj 	while ((curr != NULL) &&
140ae115bc7Smrj 	    (curr->start_addr < used->start_addr)) {
141ae115bc7Smrj 		prev = curr;
142ae115bc7Smrj 		curr = curr->next;
143ae115bc7Smrj 	}
144ae115bc7Smrj 	if (prev == curr) {
145ae115bc7Smrj 		/* head */
146ae115bc7Smrj 		*head = used;
147ae115bc7Smrj 		used->next = curr;
148ae115bc7Smrj 		return;
149ae115bc7Smrj 	} else {
150ae115bc7Smrj 		prev->next = used;
151ae115bc7Smrj 	}
152ae115bc7Smrj 	used->next = curr;
153ae115bc7Smrj }
154ae115bc7Smrj 
155ae115bc7Smrj static void
add_used_io_mem(struct regspec * io,int io_count)156ae115bc7Smrj add_used_io_mem(struct regspec *io, int io_count)
157ae115bc7Smrj {
158ae115bc7Smrj 	int i;
159ae115bc7Smrj 	used_io_mem_t *used;
160ae115bc7Smrj 
161ae115bc7Smrj 	for (i = 0; i < io_count; i++) {
162*d4039345SRichard Lowe 		used = kmem_zalloc(sizeof (used_io_mem_t),
163ae115bc7Smrj 		    KM_SLEEP);
164ae115bc7Smrj 		used->start_addr = io[i].regspec_addr;
165ae115bc7Smrj 		used->length = io[i].regspec_size;
166ae115bc7Smrj 		if (io[i].regspec_bustype == 1) {
167ae115bc7Smrj 			insert_used_resource(used, &used_io_count,
168ae115bc7Smrj 			    &used_io_head);
169ae115bc7Smrj 		} else {
170ae115bc7Smrj 			insert_used_resource(used, &used_mem_count,
171ae115bc7Smrj 			    &used_mem_head);
172ae115bc7Smrj 		}
173ae115bc7Smrj 	}
174ae115bc7Smrj }
175ae115bc7Smrj 
176ae115bc7Smrj static void
parse_resources_irq(ACPI_RESOURCE * resource_ptr,intrs_t * intrs)1771f9b2f1bSJason King parse_resources_irq(ACPI_RESOURCE *resource_ptr, intrs_t *intrs)
178ae115bc7Smrj {
1791f9b2f1bSJason King 	uint_t i;
180ae115bc7Smrj 
181a4a4d28eSSeth Goldberg 	for (i = 0; i < resource_ptr->Data.Irq.InterruptCount; i++) {
1821f9b2f1bSJason King 		uint8_t irq = resource_ptr->Data.Irq.Interrupts[i];
1831f9b2f1bSJason King 
1841f9b2f1bSJason King 		add_interrupt(intrs, irq);
1851f9b2f1bSJason King 		add_interrupt(&used_interrupts, irq);
1861f9b2f1bSJason King 
187ae115bc7Smrj 		if (acpi_enum_debug & PARSE_RES_IRQ) {
1881f9b2f1bSJason King 			cmn_err(CE_NOTE, "!%s() IRQ num %u, intr # = %u",
1891f9b2f1bSJason King 			    __func__, i, irq);
1901f9b2f1bSJason King 		}
1911f9b2f1bSJason King 	}
1921f9b2f1bSJason King }
1931f9b2f1bSJason King 
1941f9b2f1bSJason King static void
parse_resources_extended_irq(ACPI_RESOURCE * resource_ptr,intrs_t * intrs)1951f9b2f1bSJason King parse_resources_extended_irq(ACPI_RESOURCE *resource_ptr, intrs_t *intrs)
1961f9b2f1bSJason King {
1971f9b2f1bSJason King 	uint_t i;
1981f9b2f1bSJason King 
1991f9b2f1bSJason King 	for (i = 0; i < resource_ptr->Data.ExtendedIrq.InterruptCount; i++) {
2001f9b2f1bSJason King 		uint32_t irq = resource_ptr->Data.ExtendedIrq.Interrupts[i];
2011f9b2f1bSJason King 
2021f9b2f1bSJason King 		/*
2031f9b2f1bSJason King 		 * As noted in the definition of intrs_t above, traditionally
2041f9b2f1bSJason King 		 * the "interrupts" property is an array of ints. This is
2051f9b2f1bSJason King 		 * more precautionary than anything since it seems unlikely
2061f9b2f1bSJason King 		 * that anything will have an irq value > 2^31 anytime soon.
2071f9b2f1bSJason King 		 */
2081f9b2f1bSJason King 		if (irq > INT32_MAX) {
2091f9b2f1bSJason King 			if (acpi_enum_debug & PARSE_RES_IRQ) {
2101f9b2f1bSJason King 				cmn_err(CE_NOTE,
2111f9b2f1bSJason King 				    "!%s() intr # = %u out of range",
2121f9b2f1bSJason King 				    __func__, irq);
2131f9b2f1bSJason King 			}
2141f9b2f1bSJason King 			continue;
2151f9b2f1bSJason King 		}
2161f9b2f1bSJason King 
2171f9b2f1bSJason King 		add_interrupt(intrs, irq);
2181f9b2f1bSJason King 		add_interrupt(&used_interrupts, irq);
2191f9b2f1bSJason King 
2201f9b2f1bSJason King 		if (acpi_enum_debug & PARSE_RES_IRQ) {
2211f9b2f1bSJason King 			cmn_err(CE_NOTE, "!%s() IRQ num %u, intr # = %u",
2221f9b2f1bSJason King 			    __func__, i, irq);
223ae115bc7Smrj 		}
224ae115bc7Smrj 	}
225ae115bc7Smrj }
226ae115bc7Smrj 
227ae115bc7Smrj static void
parse_resources_dma(ACPI_RESOURCE * resource_ptr,int * dma_count)228ae115bc7Smrj parse_resources_dma(ACPI_RESOURCE *resource_ptr, int *dma_count)
229ae115bc7Smrj {
230ae115bc7Smrj 	int i;
231ae115bc7Smrj 
232a4a4d28eSSeth Goldberg 	for (i = 0; i < resource_ptr->Data.Dma.ChannelCount; i++) {
233a4a4d28eSSeth Goldberg 		dma[(*dma_count)++] = resource_ptr->Data.Dma.Channels[i];
234a4a4d28eSSeth Goldberg 		used_dmas |= 1 << resource_ptr->Data.Dma.Channels[i];
235ae115bc7Smrj 		if (acpi_enum_debug & PARSE_RES_DMA) {
2367b1019a6SJerry Jelinek 			cmn_err(CE_NOTE, "!parse_resources() "\
237ae115bc7Smrj 			    "DMA num %u, channel # = %u",
238a4a4d28eSSeth Goldberg 			    i, resource_ptr->Data.Dma.Channels[i]);
239ae115bc7Smrj 		}
240ae115bc7Smrj 	}
241ae115bc7Smrj }
242ae115bc7Smrj 
243ae115bc7Smrj static void
parse_resources_io(ACPI_RESOURCE * resource_ptr,struct regspec * io,int * io_count)244ae115bc7Smrj parse_resources_io(ACPI_RESOURCE *resource_ptr, struct regspec *io,
245ae115bc7Smrj     int *io_count)
246ae115bc7Smrj {
247ae115bc7Smrj 	ACPI_RESOURCE_IO acpi_io = resource_ptr->Data.Io;
248ae115bc7Smrj 
2498fc7923fSDana Myers 	if (acpi_io.AddressLength == 0)
2508fc7923fSDana Myers 		return;
2518fc7923fSDana Myers 
252ae115bc7Smrj 	io[*io_count].regspec_bustype = 1; /* io */
253ae115bc7Smrj 	io[*io_count].regspec_size = acpi_io.AddressLength;
254ae115bc7Smrj 	io[*io_count].regspec_addr = acpi_io.Minimum;
255ae115bc7Smrj 	if (acpi_enum_debug & PARSE_RES_IO) {
2567b1019a6SJerry Jelinek 		cmn_err(CE_NOTE, "!parse_resources() "\
257ae115bc7Smrj 		    "IO min 0x%X, max 0x%X, length: 0x%X",
258ae115bc7Smrj 		    acpi_io.Minimum,
259ae115bc7Smrj 		    acpi_io.Maximum,
260ae115bc7Smrj 		    acpi_io.AddressLength);
261ae115bc7Smrj 	}
262ae115bc7Smrj 	(*io_count)++;
263ae115bc7Smrj }
264ae115bc7Smrj 
265ae115bc7Smrj static void
parse_resources_fixed_io(ACPI_RESOURCE * resource_ptr,struct regspec * io,int * io_count)266ae115bc7Smrj parse_resources_fixed_io(ACPI_RESOURCE *resource_ptr, struct regspec *io,
267ae115bc7Smrj     int *io_count)
268ae115bc7Smrj {
269ae115bc7Smrj 	ACPI_RESOURCE_FIXED_IO fixed_io = resource_ptr->Data.FixedIo;
270ae115bc7Smrj 
2718fc7923fSDana Myers 	if (fixed_io.AddressLength == 0)
2728fc7923fSDana Myers 		return;
2738fc7923fSDana Myers 
274ae115bc7Smrj 	io[*io_count].regspec_bustype = 1; /* io */
275ae115bc7Smrj 	io[*io_count].regspec_addr = fixed_io.Address;
276ae115bc7Smrj 	io[*io_count].regspec_size = fixed_io.AddressLength;
277ae115bc7Smrj 	if (acpi_enum_debug & PARSE_RES_IO) {
2787b1019a6SJerry Jelinek 		cmn_err(CE_NOTE, "!parse_resources() "\
279ae115bc7Smrj 		    "Fixed IO 0x%X, length: 0x%X",
280ae115bc7Smrj 		    fixed_io.Address, fixed_io.AddressLength);
281ae115bc7Smrj 	}
282ae115bc7Smrj 	(*io_count)++;
283ae115bc7Smrj }
284ae115bc7Smrj 
285ae115bc7Smrj static void
parse_resources_fixed_mem32(ACPI_RESOURCE * resource_ptr,struct regspec * io,int * io_count)286ae115bc7Smrj parse_resources_fixed_mem32(ACPI_RESOURCE *resource_ptr, struct regspec *io,
287ae115bc7Smrj     int *io_count)
288ae115bc7Smrj {
289ae115bc7Smrj 	ACPI_RESOURCE_FIXED_MEMORY32 fixed_mem32 =
290ae115bc7Smrj 	    resource_ptr->Data.FixedMemory32;
291ae115bc7Smrj 
2928fc7923fSDana Myers 	if (fixed_mem32.AddressLength == 0)
2938fc7923fSDana Myers 		return;
2948fc7923fSDana Myers 
295ae115bc7Smrj 	io[*io_count].regspec_bustype = 0; /* memory */
296ae115bc7Smrj 	io[*io_count].regspec_addr = fixed_mem32.Address;
297ae115bc7Smrj 	io[*io_count].regspec_size = fixed_mem32.AddressLength;
298ae115bc7Smrj 	if (acpi_enum_debug & PARSE_RES_MEMORY) {
2997b1019a6SJerry Jelinek 		cmn_err(CE_NOTE, "!parse_resources() "\
300ae115bc7Smrj 		    "Fixed Mem 32 %ul, length: %ul",
301ae115bc7Smrj 		    fixed_mem32.Address, fixed_mem32.AddressLength);
302ae115bc7Smrj 	}
303ae115bc7Smrj 	(*io_count)++;
304ae115bc7Smrj }
305ae115bc7Smrj 
306ae115bc7Smrj static void
parse_resources_mem32(ACPI_RESOURCE * resource_ptr,struct regspec * io,int * io_count)307ae115bc7Smrj parse_resources_mem32(ACPI_RESOURCE *resource_ptr, struct regspec *io,
308ae115bc7Smrj     int *io_count)
309ae115bc7Smrj {
310ae115bc7Smrj 	ACPI_RESOURCE_MEMORY32 mem32 = resource_ptr->Data.Memory32;
311ae115bc7Smrj 
3128fc7923fSDana Myers 	if (mem32.AddressLength == 0)
3138fc7923fSDana Myers 		return;
3148fc7923fSDana Myers 
315ae115bc7Smrj 	if (resource_ptr->Data.Memory32.Minimum ==
316ae115bc7Smrj 	    resource_ptr->Data.Memory32.Maximum) {
317ae115bc7Smrj 		io[*io_count].regspec_bustype = 0; /* memory */
318ae115bc7Smrj 		io[*io_count].regspec_addr = mem32.Minimum;
319ae115bc7Smrj 		io[*io_count].regspec_size = mem32.AddressLength;
320ae115bc7Smrj 		(*io_count)++;
321ae115bc7Smrj 		if (acpi_enum_debug & PARSE_RES_MEMORY) {
3227b1019a6SJerry Jelinek 			cmn_err(CE_NOTE, "!parse_resources() "\
323ae115bc7Smrj 			    "Mem 32 0x%X, length: 0x%X",
324ae115bc7Smrj 			    mem32.Minimum, mem32.AddressLength);
325ae115bc7Smrj 		}
326ae115bc7Smrj 		return;
327ae115bc7Smrj 	}
328ae115bc7Smrj 	if (acpi_enum_debug & PARSE_RES_MEMORY) {
3297b1019a6SJerry Jelinek 		cmn_err(CE_NOTE, "!parse_resources() "\
330ae115bc7Smrj 		    "MEM32 Min Max not equal!");
3317b1019a6SJerry Jelinek 		cmn_err(CE_NOTE, "!parse_resources() "\
332ae115bc7Smrj 		    "Mem 32 Minimum 0x%X, Maximum: 0x%X",
333ae115bc7Smrj 		    mem32.Minimum, mem32.Maximum);
334ae115bc7Smrj 	}
335ae115bc7Smrj }
336ae115bc7Smrj 
337ae115bc7Smrj static void
parse_resources_addr16(ACPI_RESOURCE * resource_ptr,struct regspec * io,int * io_count)338ae115bc7Smrj parse_resources_addr16(ACPI_RESOURCE *resource_ptr, struct regspec *io,
339ae115bc7Smrj     int *io_count)
340ae115bc7Smrj {
341ae115bc7Smrj 	ACPI_RESOURCE_ADDRESS16 addr16 =
342ae115bc7Smrj 	    resource_ptr->Data.Address16;
3438fc7923fSDana Myers 
3447b1019a6SJerry Jelinek 	if (addr16.Address.AddressLength == 0)
3458fc7923fSDana Myers 		return;
3468fc7923fSDana Myers 
347ae115bc7Smrj 	if (acpi_enum_debug & PARSE_RES_ADDRESS) {
348ae115bc7Smrj 		if (addr16.ResourceType == ACPI_MEMORY_RANGE) {
3497b1019a6SJerry Jelinek 			cmn_err(CE_NOTE, "!parse_resources() "\
350ae115bc7Smrj 			    "ADDRESS 16 MEMORY RANGE");
351ae115bc7Smrj 		} else
352ae115bc7Smrj 		if (addr16.ResourceType == ACPI_IO_RANGE) {
3537b1019a6SJerry Jelinek 			cmn_err(CE_NOTE, "!parse_resources() "\
354ae115bc7Smrj 			    "ADDRESS 16 IO RANGE");
355ae115bc7Smrj 		} else {
3567b1019a6SJerry Jelinek 			cmn_err(CE_NOTE, "!parse_resources() "\
357ae115bc7Smrj 			    "ADDRESS 16 OTHER");
358ae115bc7Smrj 		}
3597b1019a6SJerry Jelinek 		cmn_err(CE_NOTE, "!parse_resources() "\
360ae115bc7Smrj 		    "%s "\
361ae115bc7Smrj 		    "MinAddressFixed 0x%X, "\
362ae115bc7Smrj 		    "MaxAddressFixed 0x%X, "\
363ae115bc7Smrj 		    "Minimum 0x%X, "\
364ae115bc7Smrj 		    "Maximum 0x%X, "\
365ae115bc7Smrj 		    "length: 0x%X\n",
366ae115bc7Smrj 		    addr16.ProducerConsumer == ACPI_CONSUMER ?
367ae115bc7Smrj 		    "CONSUMER" : "PRODUCER",
368ae115bc7Smrj 		    addr16.MinAddressFixed,
369ae115bc7Smrj 		    addr16.MaxAddressFixed,
3707b1019a6SJerry Jelinek 		    addr16.Address.Minimum,
3717b1019a6SJerry Jelinek 		    addr16.Address.Maximum,
3727b1019a6SJerry Jelinek 		    addr16.Address.AddressLength);
373ae115bc7Smrj 	}
374ae115bc7Smrj 	if (addr16.ProducerConsumer == ACPI_PRODUCER ||
375ae115bc7Smrj 	    (addr16.ResourceType != ACPI_MEMORY_RANGE &&
376ae115bc7Smrj 	    addr16.ResourceType != ACPI_IO_RANGE)) {
377ae115bc7Smrj 		return;
378ae115bc7Smrj 	}
3797b1019a6SJerry Jelinek 	if (addr16.Address.AddressLength > 0) {
380ae115bc7Smrj 		if (addr16.ResourceType == ACPI_MEMORY_RANGE) {
381ae115bc7Smrj 			/* memory */
382ae115bc7Smrj 			io[*io_count].regspec_bustype = 0;
383ae115bc7Smrj 		} else {
384ae115bc7Smrj 			/* io */
385ae115bc7Smrj 			io[*io_count].regspec_bustype = 1;
386ae115bc7Smrj 		}
3877b1019a6SJerry Jelinek 		io[*io_count].regspec_addr = addr16.Address.Minimum;
3887b1019a6SJerry Jelinek 		io[*io_count].regspec_size = addr16.Address.AddressLength;
389ae115bc7Smrj 		(*io_count)++;
390ae115bc7Smrj 	}
391ae115bc7Smrj }
392ae115bc7Smrj 
393ae115bc7Smrj static void
parse_resources_addr32(ACPI_RESOURCE * resource_ptr,struct regspec * io,int * io_count)394ae115bc7Smrj parse_resources_addr32(ACPI_RESOURCE *resource_ptr, struct regspec *io,
395ae115bc7Smrj     int *io_count)
396ae115bc7Smrj {
397ae115bc7Smrj 	ACPI_RESOURCE_ADDRESS32 addr32 =
398ae115bc7Smrj 	    resource_ptr->Data.Address32;
3998fc7923fSDana Myers 
4007b1019a6SJerry Jelinek 	if (addr32.Address.AddressLength == 0)
4018fc7923fSDana Myers 		return;
4028fc7923fSDana Myers 
403ae115bc7Smrj 	if (acpi_enum_debug & PARSE_RES_ADDRESS) {
404ae115bc7Smrj 		if (addr32.ResourceType == ACPI_MEMORY_RANGE) {
4057b1019a6SJerry Jelinek 			cmn_err(CE_NOTE, "!parse_resources() "\
406ae115bc7Smrj 			    "ADDRESS 32 MEMORY RANGE");
407ae115bc7Smrj 		} else
408ae115bc7Smrj 		if (addr32.ResourceType == ACPI_IO_RANGE) {
4097b1019a6SJerry Jelinek 			cmn_err(CE_NOTE, "!parse_resources() "\
410ae115bc7Smrj 			    "ADDRESS 32 IO RANGE");
411ae115bc7Smrj 		} else {
4127b1019a6SJerry Jelinek 			cmn_err(CE_NOTE, "!parse_resources() "\
413ae115bc7Smrj 			    "ADDRESS 32 OTHER");
414ae115bc7Smrj 		}
4157b1019a6SJerry Jelinek 		cmn_err(CE_NOTE, "!parse_resources() "\
416ae115bc7Smrj 		    "%s "\
417ae115bc7Smrj 		    "MinAddressFixed 0x%X, "\
418ae115bc7Smrj 		    "MaxAddressFixed 0x%X, "\
419ae115bc7Smrj 		    "Minimum 0x%X, "\
420ae115bc7Smrj 		    "Maximum 0x%X, "\
421ae115bc7Smrj 		    "length: 0x%X\n",
422ae115bc7Smrj 		    addr32.ProducerConsumer == ACPI_CONSUMER ?
423ae115bc7Smrj 		    "CONSUMER" : "PRODUCER",
424ae115bc7Smrj 		    addr32.MinAddressFixed,
425ae115bc7Smrj 		    addr32.MaxAddressFixed,
4267b1019a6SJerry Jelinek 		    addr32.Address.Minimum,
4277b1019a6SJerry Jelinek 		    addr32.Address.Maximum,
4287b1019a6SJerry Jelinek 		    addr32.Address.AddressLength);
429ae115bc7Smrj 	}
430ae115bc7Smrj 	if (addr32.ProducerConsumer == ACPI_PRODUCER ||
431ae115bc7Smrj 	    (addr32.ResourceType != ACPI_MEMORY_RANGE &&
432ae115bc7Smrj 	    addr32.ResourceType != ACPI_IO_RANGE)) {
433ae115bc7Smrj 		return;
434ae115bc7Smrj 	}
4357b1019a6SJerry Jelinek 	if (addr32.Address.AddressLength > 0) {
436ae115bc7Smrj 		if (addr32.ResourceType == ACPI_MEMORY_RANGE) {
437ae115bc7Smrj 			/* memory */
438ae115bc7Smrj 			io[*io_count].regspec_bustype = 0;
439ae115bc7Smrj 		} else {
440ae115bc7Smrj 			/* io */
441ae115bc7Smrj 			io[*io_count].regspec_bustype = 1;
442ae115bc7Smrj 		}
4437b1019a6SJerry Jelinek 		io[*io_count].regspec_addr = addr32.Address.Minimum;
4447b1019a6SJerry Jelinek 		io[*io_count].regspec_size = addr32.Address.AddressLength;
445ae115bc7Smrj 		(*io_count)++;
446ae115bc7Smrj 	}
447ae115bc7Smrj }
448ae115bc7Smrj 
449ae115bc7Smrj static void
parse_resources_addr64(ACPI_RESOURCE * resource_ptr,struct regspec * io,int * io_count)450ae115bc7Smrj parse_resources_addr64(ACPI_RESOURCE *resource_ptr, struct regspec *io,
451ae115bc7Smrj     int *io_count)
452ae115bc7Smrj {
453ae115bc7Smrj 	ACPI_RESOURCE_ADDRESS64 addr64 =
454ae115bc7Smrj 	    resource_ptr->Data.Address64;
4558fc7923fSDana Myers 
4567b1019a6SJerry Jelinek 	if (addr64.Address.AddressLength == 0)
4578fc7923fSDana Myers 		return;
4588fc7923fSDana Myers 
459ae115bc7Smrj 	if (acpi_enum_debug & PARSE_RES_ADDRESS) {
460ae115bc7Smrj 		if (addr64.ResourceType == ACPI_MEMORY_RANGE) {
4617b1019a6SJerry Jelinek 			cmn_err(CE_NOTE, "!parse_resources() "\
462ae115bc7Smrj 			    "ADDRESS 64 MEMORY RANGE");
463ae115bc7Smrj 		} else
464ae115bc7Smrj 		if (addr64.ResourceType == ACPI_IO_RANGE) {
4657b1019a6SJerry Jelinek 			cmn_err(CE_NOTE, "!parse_resources() "\
466ae115bc7Smrj 			    "ADDRESS 64 IO RANGE");
467ae115bc7Smrj 		} else {
4687b1019a6SJerry Jelinek 			cmn_err(CE_NOTE, "!parse_resources() "\
469ae115bc7Smrj 			    "ADDRESS 64 OTHER");
470ae115bc7Smrj 		}
471ae115bc7Smrj #ifdef _LP64
4727b1019a6SJerry Jelinek 		cmn_err(CE_NOTE, "!parse_resources() "\
473ae115bc7Smrj 		    "%s "\
474ae115bc7Smrj 		    "MinAddressFixed 0x%X, "\
475ae115bc7Smrj 		    "MaxAddressFixed 0x%X, "\
476ae115bc7Smrj 		    "Minimum 0x%lX, "\
477ae115bc7Smrj 		    "Maximum 0x%lX, "\
478ae115bc7Smrj 		    "length: 0x%lX\n",
479a4a4d28eSSeth Goldberg 		    addr64.ProducerConsumer == ACPI_CONSUMER ?
480a4a4d28eSSeth Goldberg 		    "CONSUMER" : "PRODUCER",
481a4a4d28eSSeth Goldberg 		    addr64.MinAddressFixed,
482a4a4d28eSSeth Goldberg 		    addr64.MaxAddressFixed,
4837b1019a6SJerry Jelinek 		    addr64.Address.Minimum,
4847b1019a6SJerry Jelinek 		    addr64.Address.Maximum,
4857b1019a6SJerry Jelinek 		    addr64.Address.AddressLength);
486ae115bc7Smrj #else
4877b1019a6SJerry Jelinek 		cmn_err(CE_NOTE, "!parse_resources() "\
488ae115bc7Smrj 		    "%s "\
489ae115bc7Smrj 		    "MinAddressFixed 0x%X, "\
490ae115bc7Smrj 		    "MaxAddressFixed 0x%X, "\
491ae115bc7Smrj 		    "Minimum 0x%llX, "\
492ae115bc7Smrj 		    "Maximum 0x%llX, "\
493ae115bc7Smrj 		    "length: 0x%llX\n",
494ae115bc7Smrj 		    addr64.ProducerConsumer == ACPI_CONSUMER ?
495ae115bc7Smrj 		    "CONSUMER" : "PRODUCER",
496ae115bc7Smrj 		    addr64.MinAddressFixed,
497ae115bc7Smrj 		    addr64.MaxAddressFixed,
4987b1019a6SJerry Jelinek 		    addr64.Address.Minimum,
4997b1019a6SJerry Jelinek 		    addr64.Address.Maximum,
5007b1019a6SJerry Jelinek 		    addr64.Address.AddressLength);
501a4a4d28eSSeth Goldberg #endif
502ae115bc7Smrj 	}
503ae115bc7Smrj 	if (addr64.ProducerConsumer == ACPI_PRODUCER ||
504ae115bc7Smrj 	    (addr64.ResourceType != ACPI_MEMORY_RANGE &&
505ae115bc7Smrj 	    addr64.ResourceType != ACPI_IO_RANGE)) {
506ae115bc7Smrj 		return;
507ae115bc7Smrj 	}
5087b1019a6SJerry Jelinek 	if (addr64.Address.AddressLength > 0) {
509ae115bc7Smrj 		if (addr64.ResourceType == ACPI_MEMORY_RANGE) {
510ae115bc7Smrj 			/* memory */
511ae115bc7Smrj 			io[*io_count].regspec_bustype = 0;
512ae115bc7Smrj 		} else {
513ae115bc7Smrj 			/* io */
514ae115bc7Smrj 			io[*io_count].regspec_bustype = 1;
515ae115bc7Smrj 		}
5167b1019a6SJerry Jelinek 		io[*io_count].regspec_addr = addr64.Address.Minimum;
5177b1019a6SJerry Jelinek 		io[*io_count].regspec_size = addr64.Address.AddressLength;
518ae115bc7Smrj 		(*io_count)++;
519ae115bc7Smrj 	}
520ae115bc7Smrj }
521ae115bc7Smrj 
522ae115bc7Smrj static ACPI_STATUS
parse_resources(ACPI_HANDLE handle,dev_info_t * xdip,char * path)52312f7d0bdSGary Mills parse_resources(ACPI_HANDLE handle, dev_info_t *xdip, char *path)
524ae115bc7Smrj {
525ae115bc7Smrj 	ACPI_BUFFER	buf;
526ae115bc7Smrj 	ACPI_RESOURCE	*resource_ptr;
527ae115bc7Smrj 	ACPI_STATUS	status;
528ae115bc7Smrj 	char		*current_ptr, *last_ptr;
529ae115bc7Smrj 	struct		regspec *io;
5301f9b2f1bSJason King 	intrs_t		intrs = { 0 };
5311f9b2f1bSJason King 	int		io_count = 0, dma_count = 0;
532ae115bc7Smrj 	int		i;
533ae115bc7Smrj 
534ae115bc7Smrj 	buf.Length = ACPI_ALLOCATE_BUFFER;
535ae115bc7Smrj 	status = AcpiGetCurrentResources(handle, &buf);
53612f7d0bdSGary Mills 	switch (status) {
53712f7d0bdSGary Mills 	case AE_OK:
53812f7d0bdSGary Mills 		break;
53912f7d0bdSGary Mills 	case AE_NOT_FOUND:
54012f7d0bdSGary Mills 		/*
54112f7d0bdSGary Mills 		 * Workaround for faulty DSDT tables that omit the _CRS
54212f7d0bdSGary Mills 		 * method for the UAR3 device but have a valid _PRS method
54312f7d0bdSGary Mills 		 * for that device.
54412f7d0bdSGary Mills 		 */
54512f7d0bdSGary Mills 		status = AcpiGetPossibleResources(handle, &buf);
546ae115bc7Smrj 		if (status != AE_OK) {
547ae115bc7Smrj 			return (status);
548ae115bc7Smrj 		}
54912f7d0bdSGary Mills 		break;
55012f7d0bdSGary Mills 	default:
55112f7d0bdSGary Mills 		cmn_err(CE_WARN,
55212f7d0bdSGary Mills 		    "!AcpiGetCurrentResources failed for %s, exception: %s",
55312f7d0bdSGary Mills 		    path, AcpiFormatException(status));
55412f7d0bdSGary Mills 		return (status);
55512f7d0bdSGary Mills 		break;
55612f7d0bdSGary Mills 	}
557*d4039345SRichard Lowe 	io = kmem_zalloc(sizeof (struct regspec) *
558ae115bc7Smrj 	    MAX_PARSED_ACPI_RESOURCES, KM_SLEEP);
559ae115bc7Smrj 	current_ptr = buf.Pointer;
560ae115bc7Smrj 	last_ptr = (char *)buf.Pointer + buf.Length;
561ae115bc7Smrj 	while (current_ptr < last_ptr) {
562ae115bc7Smrj 		if (io_count >= MAX_PARSED_ACPI_RESOURCES) {
563ae115bc7Smrj 			break;
564ae115bc7Smrj 		}
565ae115bc7Smrj 		resource_ptr = (ACPI_RESOURCE *)current_ptr;
566ae115bc7Smrj 		current_ptr += resource_ptr->Length;
567ae115bc7Smrj 		switch (resource_ptr->Type) {
568ae115bc7Smrj 		case ACPI_RESOURCE_TYPE_END_TAG:
569ae115bc7Smrj 			current_ptr = last_ptr;
570ae115bc7Smrj 			break;
571ae115bc7Smrj 		case ACPI_RESOURCE_TYPE_IO:
572ae115bc7Smrj 			parse_resources_io(resource_ptr, io, &io_count);
573ae115bc7Smrj 			break;
574ae115bc7Smrj 		case ACPI_RESOURCE_TYPE_FIXED_IO:
575ae115bc7Smrj 			parse_resources_fixed_io(resource_ptr, io, &io_count);
576ae115bc7Smrj 			break;
577ae115bc7Smrj 		case ACPI_RESOURCE_TYPE_FIXED_MEMORY32:
578ae115bc7Smrj 			parse_resources_fixed_mem32(resource_ptr, io,
579ae115bc7Smrj 			    &io_count);
580ae115bc7Smrj 			break;
581ae115bc7Smrj 		case ACPI_RESOURCE_TYPE_MEMORY32:
582ae115bc7Smrj 			parse_resources_mem32(resource_ptr, io, &io_count);
583ae115bc7Smrj 			break;
584ae115bc7Smrj 		case ACPI_RESOURCE_TYPE_ADDRESS16:
585ae115bc7Smrj 			parse_resources_addr16(resource_ptr, io, &io_count);
586ae115bc7Smrj 			break;
587ae115bc7Smrj 		case ACPI_RESOURCE_TYPE_ADDRESS32:
588ae115bc7Smrj 			parse_resources_addr32(resource_ptr, io, &io_count);
589ae115bc7Smrj 			break;
590ae115bc7Smrj 		case ACPI_RESOURCE_TYPE_ADDRESS64:
591ae115bc7Smrj 			parse_resources_addr64(resource_ptr, io, &io_count);
592ae115bc7Smrj 			break;
593ae115bc7Smrj 		case ACPI_RESOURCE_TYPE_IRQ:
5941f9b2f1bSJason King 			parse_resources_irq(resource_ptr, &intrs);
595ae115bc7Smrj 			break;
596ae115bc7Smrj 		case ACPI_RESOURCE_TYPE_DMA:
597ae115bc7Smrj 			parse_resources_dma(resource_ptr, &dma_count);
598ae115bc7Smrj 			break;
599ae115bc7Smrj 		case ACPI_RESOURCE_TYPE_START_DEPENDENT:
600ae115bc7Smrj 			cmn_err(CE_NOTE,
601ae115bc7Smrj 			    "!ACPI source type"
602ae115bc7Smrj 			    " ACPI_RESOURCE_TYPE_START_DEPENDENT"
603ae115bc7Smrj 			    " not supported");
604ae115bc7Smrj 			break;
605ae115bc7Smrj 		case ACPI_RESOURCE_TYPE_END_DEPENDENT:
606ae115bc7Smrj 			cmn_err(CE_NOTE,
607ae115bc7Smrj 			    "!ACPI source type"
608ae115bc7Smrj 			    " ACPI_RESOURCE_TYPE_END_DEPENDENT"
609ae115bc7Smrj 			    " not supported");
610ae115bc7Smrj 			break;
611ae115bc7Smrj 		case ACPI_RESOURCE_TYPE_VENDOR:
612ae115bc7Smrj 			cmn_err(CE_NOTE,
613ae115bc7Smrj 			    "!ACPI source type"
614ae115bc7Smrj 			    " ACPI_RESOURCE_TYPE_VENDOR"
615ae115bc7Smrj 			    " not supported");
616ae115bc7Smrj 			break;
617ae115bc7Smrj 		case ACPI_RESOURCE_TYPE_MEMORY24:
618ae115bc7Smrj 			cmn_err(CE_NOTE,
619ae115bc7Smrj 			    "!ACPI source type"
620ae115bc7Smrj 			    " ACPI_RESOURCE_TYPE_MEMORY24"
621ae115bc7Smrj 			    " not supported");
622ae115bc7Smrj 			break;
623ae115bc7Smrj 		case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
6241f9b2f1bSJason King 			parse_resources_extended_irq(resource_ptr, &intrs);
625ae115bc7Smrj 			break;
626ae115bc7Smrj 		default:
627ae115bc7Smrj 		/* Some types are not yet implemented (See CA 6.4) */
628ae115bc7Smrj 			cmn_err(CE_NOTE,
629ae115bc7Smrj 			    "!ACPI resource type (0X%X) not yet supported",
630ae115bc7Smrj 			    resource_ptr->Type);
631ae115bc7Smrj 			break;
632ae115bc7Smrj 		}
633ae115bc7Smrj 	}
634ae115bc7Smrj 
635ae115bc7Smrj 	if (io_count) {
636ae115bc7Smrj 		/*
637ae115bc7Smrj 		 * on LX50, you get interrupts of mouse and keyboard
638ae115bc7Smrj 		 * from separate PNP id...
639ae115bc7Smrj 		 */
640ae115bc7Smrj 		if (io_count == 2) {
641ae115bc7Smrj 			if ((io[0].regspec_addr == 0x60 &&
642ae115bc7Smrj 			    io[1].regspec_addr == 0x64) ||
643ae115bc7Smrj 			    (io[0].regspec_addr == 0x64 &&
644ae115bc7Smrj 			    io[1].regspec_addr == 0x60)) {
6451f9b2f1bSJason King 				intrs.i_num = 0;
6461f9b2f1bSJason King 				add_interrupt(&intrs, 0x1);
6471f9b2f1bSJason King 				add_interrupt(&intrs, 0xc);
6481f9b2f1bSJason King 				add_interrupt(&used_interrupts, 0x1);
6491f9b2f1bSJason King 				add_interrupt(&used_interrupts, 0xc);
650ae115bc7Smrj 			}
651ae115bc7Smrj 		}
652ae115bc7Smrj 		add_used_io_mem(io, io_count);
653ae115bc7Smrj 		if (xdip != NULL) {
654ae115bc7Smrj 			(void) ndi_prop_update_int_array(DDI_DEV_T_NONE, xdip,
655ae115bc7Smrj 			    "reg", (int *)io, 3*io_count);
656ae115bc7Smrj 		}
657ae115bc7Smrj 	}
6581f9b2f1bSJason King 	if (intrs.i_num > 0) {
6591f9b2f1bSJason King 		if (xdip != NULL) {
660ae115bc7Smrj 			(void) ndi_prop_update_int_array(DDI_DEV_T_NONE, xdip,
6611f9b2f1bSJason King 			    "interrupts", intrs.i_intrs, intrs.i_num);
6621f9b2f1bSJason King 		}
6631f9b2f1bSJason King 		kmem_free(intrs.i_intrs, intrs.i_alloc * sizeof (int));
664ae115bc7Smrj 	}
665ae115bc7Smrj 	if (dma_count && (xdip != NULL)) {
666ae115bc7Smrj 		(void) ndi_prop_update_int_array(DDI_DEV_T_NONE, xdip,
667ae115bc7Smrj 		    "dma-channels", (int *)dma, dma_count);
668ae115bc7Smrj 	}
669ae115bc7Smrj 	AcpiOsFree(buf.Pointer);
670ae115bc7Smrj 	kmem_free(io, sizeof (struct regspec) * MAX_PARSED_ACPI_RESOURCES);
671ae115bc7Smrj 	return (status);
672ae115bc7Smrj }
673ae115bc7Smrj 
674ae115bc7Smrj /* keyboard mouse is under i8042, everything else under isa */
675ae115bc7Smrj static dev_info_t *
get_bus_dip(const char * nodename,dev_info_t * isa_dip)676*d4039345SRichard Lowe get_bus_dip(const char *nodename, dev_info_t *isa_dip)
677ae115bc7Smrj {
678ae115bc7Smrj 	static dev_info_t *i8042_dip = NULL;
679ae115bc7Smrj 	struct regspec i8042_regs[] = {
680ae115bc7Smrj 		{1, 0x60, 0x1},
681ae115bc7Smrj 		{1, 0x64, 0x1}
682ae115bc7Smrj 	};
683ae115bc7Smrj 	int i8042_intrs[] = {0x1, 0xc};
684ae115bc7Smrj 
685*d4039345SRichard Lowe 	if (strcmp(nodename, "keyboard") != 0 &&
686*d4039345SRichard Lowe 	    strcmp(nodename, "mouse") != 0)
687ae115bc7Smrj 		return (isa_dip);
688ae115bc7Smrj 
689ae115bc7Smrj 	if (i8042_dip)
690ae115bc7Smrj 		return (i8042_dip);
691ae115bc7Smrj 
692ae115bc7Smrj 	ndi_devi_alloc_sleep(isa_dip, "i8042", (pnode_t)DEVI_SID_NODEID,
693ae115bc7Smrj 	    &i8042_dip);
694ae115bc7Smrj 	(void) ndi_prop_update_int_array(DDI_DEV_T_NONE, i8042_dip,
695ae115bc7Smrj 	    "reg", (int *)i8042_regs, 6);
696ae115bc7Smrj 	(void) ndi_prop_update_int_array(DDI_DEV_T_NONE, i8042_dip,
697ae115bc7Smrj 	    "interrupts", (int *)i8042_intrs, 2);
698ae115bc7Smrj 	(void) ndi_prop_update_string(DDI_DEV_T_NONE, i8042_dip,
699ae115bc7Smrj 	    "unit-address", "1,60");
700ae115bc7Smrj 	(void) ndi_devi_bind_driver(i8042_dip, 0);
701ae115bc7Smrj 	return (i8042_dip);
702ae115bc7Smrj }
703ae115bc7Smrj 
704ae115bc7Smrj void
eisa_to_str(ACPI_INTEGER id,char * np)705ae115bc7Smrj eisa_to_str(ACPI_INTEGER id, char *np)
706ae115bc7Smrj {
707ae115bc7Smrj 	static const char hextab[] = "0123456789ABCDEF";
708ae115bc7Smrj 
709ae115bc7Smrj 	/*
710ae115bc7Smrj 	 *  Expand an EISA device name:
711ae115bc7Smrj 	 *
712aa2aa9a6SDana Myers 	 * This routine converts a 32-bit EISA device "id" to a
713aa2aa9a6SDana Myers 	 * 7-byte ASCII device name, which is stored at "np".
714ae115bc7Smrj 	 */
715ae115bc7Smrj 
716ae115bc7Smrj 	*np++ = '@' + ((id >> 2)  & 0x1F);
717ae115bc7Smrj 	*np++ = '@' + ((id << 3)  & 0x18) + ((id >> 13) & 0x07);
718ae115bc7Smrj 	*np++ = '@' + ((id >> 8)  & 0x1F);
719ae115bc7Smrj 	*np++ = hextab[(id >> 20) & 0x0F];
720ae115bc7Smrj 	*np++ = hextab[(id >> 16) & 0x0F];
721ae115bc7Smrj 	*np++ = hextab[(id >> 28) & 0x0F];
722ae115bc7Smrj 	*np++ = hextab[(id >> 24) & 0x0F];
723ae115bc7Smrj 	*np = 0;
724ae115bc7Smrj }
725ae115bc7Smrj 
726ae115bc7Smrj /*
727ae115bc7Smrj  * process_cids() -- process multiple CIDs in a package
728ae115bc7Smrj  */
729ae115bc7Smrj static void
process_cids(ACPI_OBJECT * rv,device_id_t ** dd)730aa2aa9a6SDana Myers process_cids(ACPI_OBJECT *rv, device_id_t **dd)
731ae115bc7Smrj {
732aa2aa9a6SDana Myers 	device_id_t *d;
733aa2aa9a6SDana Myers 	char tmp_cidstr[8];	/* 7-character EISA ID */
734ae115bc7Smrj 	int i;
735ae115bc7Smrj 
736aa2aa9a6SDana Myers 	if ((rv->Package.Count == 0) || rv->Package.Elements == NULL)
737ae115bc7Smrj 		return; /* empty package */
738ae115bc7Smrj 
739aa2aa9a6SDana Myers 	/*
740aa2aa9a6SDana Myers 	 * Work the package 'backwards' so the resulting list is
741aa2aa9a6SDana Myers 	 * in original order of preference.
742aa2aa9a6SDana Myers 	 */
743aa2aa9a6SDana Myers 	for (i = rv->Package.Count - 1; i >= 0; i--) {
744ae115bc7Smrj 		/* get the actual acpi_object */
745ae115bc7Smrj 		ACPI_OBJECT obj = rv->Package.Elements[i];
746ae115bc7Smrj 		switch (obj.Type) {
747ae115bc7Smrj 		case ACPI_TYPE_INTEGER:
748ae115bc7Smrj 			eisa_to_str(obj.Integer.Value, tmp_cidstr);
749*d4039345SRichard Lowe 			d = kmem_zalloc(sizeof (device_id_t), KM_SLEEP);
750aa2aa9a6SDana Myers 			d->id = strdup(tmp_cidstr);
751aa2aa9a6SDana Myers 			d->next = *dd;
752aa2aa9a6SDana Myers 			*dd = d;
753ae115bc7Smrj 			break;
754ae115bc7Smrj 		case ACPI_TYPE_STRING:
755*d4039345SRichard Lowe 			d = kmem_zalloc(sizeof (device_id_t), KM_SLEEP);
756aa2aa9a6SDana Myers 			d->id = strdup(obj.String.Pointer);
757aa2aa9a6SDana Myers 			d->next = *dd;
758aa2aa9a6SDana Myers 			*dd = d;
759ae115bc7Smrj 			break;
760ae115bc7Smrj 		default:
761ae115bc7Smrj 			if (acpi_enum_debug & PROCESS_CIDS) {
7627b1019a6SJerry Jelinek 				cmn_err(CE_NOTE, "!unexpected CID type: %d",
763ae115bc7Smrj 				    obj.Type);
764ae115bc7Smrj 			}
765ae115bc7Smrj 			break;
766ae115bc7Smrj 		}
767ae115bc7Smrj 	}
768ae115bc7Smrj }
769aa2aa9a6SDana Myers 
770aa2aa9a6SDana Myers /*
771aa2aa9a6SDana Myers  * Convert "raw" PNP and ACPI IDs to IEEE 1275-compliant form.
772aa2aa9a6SDana Myers  * Some liberty is taken here, treating "ACPI" as a special form
773aa2aa9a6SDana Myers  * of PNP vendor ID.  strsize specifies size of buffer.
774aa2aa9a6SDana Myers  */
775aa2aa9a6SDana Myers static void
convert_to_pnp1275(char * pnpid,char * str,int strsize)776aa2aa9a6SDana Myers convert_to_pnp1275(char *pnpid, char *str, int strsize)
777aa2aa9a6SDana Myers {
778aa2aa9a6SDana Myers 	char	vendor[5];
779aa2aa9a6SDana Myers 	uint_t	id;
780aa2aa9a6SDana Myers 
781aa2aa9a6SDana Myers 	if (strncmp(pnpid, "ACPI", 4) == 0) {
782aa2aa9a6SDana Myers 		/* Assume ACPI ID: ACPIxxxx */
783aa2aa9a6SDana Myers 		sscanf(pnpid, "%4s%x", vendor, &id);
784aa2aa9a6SDana Myers 	} else {
785aa2aa9a6SDana Myers 		/* Assume PNP ID: aaaxxxx */
786aa2aa9a6SDana Myers 		sscanf(pnpid, "%3s%x", vendor, &id);
787aa2aa9a6SDana Myers 	}
788aa2aa9a6SDana Myers 
789aa2aa9a6SDana Myers 	snprintf(str, strsize, "pnp%s,%x", vendor, id);
790aa2aa9a6SDana Myers }
791aa2aa9a6SDana Myers 
792aa2aa9a6SDana Myers /*
793aa2aa9a6SDana Myers  * Given a list of device ID elements in most-to-least-specific
794aa2aa9a6SDana Myers  * order, create a "compatible" property.
795aa2aa9a6SDana Myers  */
796aa2aa9a6SDana Myers static void
create_compatible_property(dev_info_t * dip,device_id_t * ids)797aa2aa9a6SDana Myers create_compatible_property(dev_info_t *dip, device_id_t *ids)
798aa2aa9a6SDana Myers {
799aa2aa9a6SDana Myers 	char		**strs;
800aa2aa9a6SDana Myers 	int		list_len, i;
801aa2aa9a6SDana Myers 	device_id_t	*d;
802aa2aa9a6SDana Myers 
803aa2aa9a6SDana Myers 	/* count list length */
804aa2aa9a6SDana Myers 	list_len = 0;
805aa2aa9a6SDana Myers 	d = ids;
806aa2aa9a6SDana Myers 	while (d != NULL) {
807aa2aa9a6SDana Myers 		list_len++;
808aa2aa9a6SDana Myers 		d = d->next;
809aa2aa9a6SDana Myers 	}
810aa2aa9a6SDana Myers 
811*d4039345SRichard Lowe 	strs = kmem_zalloc(list_len * sizeof (char *), KM_SLEEP);
812aa2aa9a6SDana Myers 	i = 0;
813aa2aa9a6SDana Myers 	d = ids;
814aa2aa9a6SDana Myers 	while (d != NULL) {
815aa2aa9a6SDana Myers 		/* strlen("pnpXXXX,xxxx") + 1 = 13 */
816aa2aa9a6SDana Myers 		strs[i] = kmem_zalloc(13, KM_SLEEP);
817aa2aa9a6SDana Myers 		convert_to_pnp1275(d->id, strs[i++], 13);
818aa2aa9a6SDana Myers 		d = d->next;
819aa2aa9a6SDana Myers 	}
820aa2aa9a6SDana Myers 
821aa2aa9a6SDana Myers 	/* update property */
822aa2aa9a6SDana Myers 	(void) ndi_prop_update_string_array(DDI_DEV_T_NONE, dip,
823aa2aa9a6SDana Myers 	    "compatible", strs, list_len);
824aa2aa9a6SDana Myers 
825aa2aa9a6SDana Myers 
826aa2aa9a6SDana Myers 	/* free memory */
827aa2aa9a6SDana Myers 	for (i = 0; i < list_len; i++)
828aa2aa9a6SDana Myers 		kmem_free(strs[i], 13);
829aa2aa9a6SDana Myers 
830aa2aa9a6SDana Myers 	kmem_free(strs, list_len * sizeof (char *));
831ae115bc7Smrj }
832ae115bc7Smrj 
833ae115bc7Smrj /*
834ae115bc7Smrj  * isa_acpi_callback()
835ae115bc7Smrj  */
836ae115bc7Smrj static ACPI_STATUS
isa_acpi_callback(ACPI_HANDLE ObjHandle,uint32_t NestingLevel,void * a,void ** b)837ae115bc7Smrj isa_acpi_callback(ACPI_HANDLE ObjHandle, uint32_t NestingLevel, void *a,
838ae115bc7Smrj     void **b)
839ae115bc7Smrj {
840ae115bc7Smrj 	_NOTE(ARGUNUSED(NestingLevel, b))
841ae115bc7Smrj 
842ae115bc7Smrj 	ACPI_BUFFER		rb;
843ae115bc7Smrj 	ACPI_DEVICE_INFO	*info = NULL;
844ae115bc7Smrj 	char			*path = NULL;
845ae115bc7Smrj 	char			*hidstr = NULL;
846aa2aa9a6SDana Myers 	char			tmp_cidstr[8];	/* EISAID size */
847ae115bc7Smrj 	dev_info_t		*dip = (dev_info_t *)a;
848ae115bc7Smrj 	dev_info_t		*xdip = NULL;
849aa2aa9a6SDana Myers 	device_id_t		*d, *device_ids = NULL;
850*d4039345SRichard Lowe 	const isapnp_desc_t	*m;
85135786f68SRobert Mustacchi 	int			status;
852ae115bc7Smrj 
853ae115bc7Smrj 	/*
854ae115bc7Smrj 	 * get full ACPI pathname for object
855ae115bc7Smrj 	 */
856ae115bc7Smrj 	rb.Length = ACPI_ALLOCATE_BUFFER;
857ae115bc7Smrj 	rb.Pointer = NULL;
858ae115bc7Smrj 	if (AcpiGetName(ObjHandle, ACPI_FULL_PATHNAME, &rb) != AE_OK) {
859ae115bc7Smrj 		cmn_err(CE_WARN, "!acpi_enum: could not get pathname");
860ae115bc7Smrj 		goto done;
861ae115bc7Smrj 	}
862ae115bc7Smrj 	path = (char *)rb.Pointer;
863ae115bc7Smrj 
864ae115bc7Smrj 	/*
865ae115bc7Smrj 	 * Get device info object
866ae115bc7Smrj 	 */
86757190917SDana Myers 	if (AcpiGetObjectInfo(ObjHandle, &info) != AE_OK) {
868ae115bc7Smrj 		cmn_err(CE_WARN, "!acpi_enum: could not get device"
869ae115bc7Smrj 		    " info for %s", path);
870ae115bc7Smrj 		goto done;
871ae115bc7Smrj 	}
872ae115bc7Smrj 
873ae115bc7Smrj 	/*
874ae115bc7Smrj 	 * If device isn't present, we don't enumerate
875ae115bc7Smrj 	 * NEEDSWORK: what about docking bays and the like?
876ae115bc7Smrj 	 */
87735786f68SRobert Mustacchi 	if (ACPI_FAILURE(acpica_get_object_status(ObjHandle, &status))) {
87835786f68SRobert Mustacchi 		cmn_err(CE_WARN, "!acpi_enum: no _STA for %s", path);
87935786f68SRobert Mustacchi 		goto done;
88035786f68SRobert Mustacchi 	}
88135786f68SRobert Mustacchi 
882ae115bc7Smrj 	/*
883ae115bc7Smrj 	 * CA 6.3.6 _STA method
884ae115bc7Smrj 	 * Bit 0 -- device is present
885ae115bc7Smrj 	 * Bit 1 -- device is enabled
886ae115bc7Smrj 	 * Bit 2 -- device is shown in UI
887ae115bc7Smrj 	 */
88835786f68SRobert Mustacchi 	if ((status & 0x7) != 0x7) {
88912f7d0bdSGary Mills 		if (acpi_enum_debug & DEVICES_NOT_ENUMED) {
8907b1019a6SJerry Jelinek 			cmn_err(CE_NOTE, "!parse_resources() "
89112f7d0bdSGary Mills 			    "Bad status 0x%x for %s",
89235786f68SRobert Mustacchi 			    status, path);
89312f7d0bdSGary Mills 		}
894ae115bc7Smrj 		goto done;
895ae115bc7Smrj 	}
896ae115bc7Smrj 
897ae115bc7Smrj 	/*
898ae115bc7Smrj 	 * Keep track of _HID value
899ae115bc7Smrj 	 */
900ae115bc7Smrj 	if (!(info->Valid & ACPI_VALID_HID)) {
901ae115bc7Smrj 		/* No _HID, we skip this node */
90212f7d0bdSGary Mills 		if (acpi_enum_debug & DEVICES_NOT_ENUMED) {
9037b1019a6SJerry Jelinek 			cmn_err(CE_NOTE, "!parse_resources() "
90412f7d0bdSGary Mills 			    "No _HID for %s", path);
90512f7d0bdSGary Mills 		}
906ae115bc7Smrj 		goto done;
907ae115bc7Smrj 	}
90857190917SDana Myers 	hidstr = info->HardwareId.String;
909ae115bc7Smrj 
910ae115bc7Smrj 	/*
911ae115bc7Smrj 	 * Attempt to get _CID value
912ae115bc7Smrj 	 */
913ae115bc7Smrj 	rb.Length = ACPI_ALLOCATE_BUFFER;
914ae115bc7Smrj 	rb.Pointer = NULL;
915db2bae30SDana Myers 	if (AcpiEvaluateObject(ObjHandle, "_CID", NULL, &rb) == AE_OK &&
916db2bae30SDana Myers 	    rb.Length != 0) {
917ae115bc7Smrj 		ACPI_OBJECT *rv = rb.Pointer;
918ae115bc7Smrj 
919ae115bc7Smrj 		switch (rv->Type) {
920ae115bc7Smrj 		case ACPI_TYPE_INTEGER:
921aa2aa9a6SDana Myers 			eisa_to_str(rv->Integer.Value, tmp_cidstr);
922*d4039345SRichard Lowe 			d = kmem_zalloc(sizeof (device_id_t), KM_SLEEP);
923aa2aa9a6SDana Myers 			d->id = strdup(tmp_cidstr);
924aa2aa9a6SDana Myers 			d->next = device_ids;
925aa2aa9a6SDana Myers 			device_ids = d;
926ae115bc7Smrj 			break;
927ae115bc7Smrj 		case ACPI_TYPE_STRING:
928*d4039345SRichard Lowe 			d = kmem_zalloc(sizeof (device_id_t), KM_SLEEP);
929aa2aa9a6SDana Myers 			d->id = strdup(rv->String.Pointer);
930aa2aa9a6SDana Myers 			d->next = device_ids;
931aa2aa9a6SDana Myers 			device_ids = d;
932ae115bc7Smrj 			break;
933ae115bc7Smrj 		case ACPI_TYPE_PACKAGE:
934aa2aa9a6SDana Myers 			process_cids(rv, &device_ids);
935ae115bc7Smrj 			break;
936ae115bc7Smrj 		default:
937ae115bc7Smrj 			break;
938ae115bc7Smrj 		}
939ae115bc7Smrj 		AcpiOsFree(rb.Pointer);
940ae115bc7Smrj 	}
941ae115bc7Smrj 
942aa2aa9a6SDana Myers 	/*
943aa2aa9a6SDana Myers 	 * Add _HID last so it's at the head of the list
944aa2aa9a6SDana Myers 	 */
945*d4039345SRichard Lowe 	d = kmem_zalloc(sizeof (device_id_t), KM_SLEEP);
946aa2aa9a6SDana Myers 	d->id = strdup(hidstr);
947aa2aa9a6SDana Myers 	d->next = device_ids;
948aa2aa9a6SDana Myers 	device_ids = d;
949ae115bc7Smrj 
950ae115bc7Smrj 	/*
951*d4039345SRichard Lowe 	 * isapnp_desc_lookup() expects _HID first in device_ids
952ae115bc7Smrj 	 */
953*d4039345SRichard Lowe 	if ((m = isapnp_desc_lookup(device_ids)) !=  NULL) {
954*d4039345SRichard Lowe 		/* PNP description found in isapnp table */
955ae115bc7Smrj 		if (!(strncmp(hidstr, "ACPI", 4))) {
956ae115bc7Smrj 			dip = ddi_root_node();
957ae115bc7Smrj 		} else {
958*d4039345SRichard Lowe 			dip = get_bus_dip(m->ipnp_name, dip);
959ae115bc7Smrj 		}
960*d4039345SRichard Lowe 		ndi_devi_alloc_sleep(dip, m->ipnp_name,
961ae115bc7Smrj 		    (pnode_t)DEVI_SID_NODEID, &xdip);
962ae115bc7Smrj 		(void) ndi_prop_update_string(DDI_DEV_T_NONE, xdip,
963*d4039345SRichard Lowe 		    "model", (char *)m->ipnp_model);
964*d4039345SRichard Lowe 
965*d4039345SRichard Lowe 		if (m->ipnp_compat != NULL) {
966ae115bc7Smrj 			(void) ndi_prop_update_string(DDI_DEV_T_NONE, xdip,
967*d4039345SRichard Lowe 			    "compatible", (char *)m->ipnp_compat);
968*d4039345SRichard Lowe 		}
969ae115bc7Smrj 	} else {
97012f7d0bdSGary Mills 		(void) parse_resources(ObjHandle, xdip, path);
971ae115bc7Smrj 		goto done;
972ae115bc7Smrj 	}
973aa2aa9a6SDana Myers 
974ae115bc7Smrj 	(void) ndi_prop_update_string(DDI_DEV_T_NONE, xdip, "acpi-namespace",
975ae115bc7Smrj 	    path);
976ae115bc7Smrj 
97712f7d0bdSGary Mills 	(void) parse_resources(ObjHandle, xdip, path);
978ae115bc7Smrj 
979ae115bc7Smrj 	/* Special processing for mouse and keyboard devices per IEEE 1275 */
980*d4039345SRichard Lowe 	if (strcmp(m->ipnp_name, "keyboard") == 0) {
981ae115bc7Smrj 		(void) ndi_prop_update_int(DDI_DEV_T_NONE, xdip, "reg", 0);
982ae115bc7Smrj 		(void) ndi_prop_update_string(DDI_DEV_T_NONE, xdip,
983*d4039345SRichard Lowe 		    "device-type", "keyboard");
984*d4039345SRichard Lowe 	} else if (strcmp(m->ipnp_name, "mouse") == 0) {
985ae115bc7Smrj 		(void) ndi_prop_update_int(DDI_DEV_T_NONE, xdip, "reg", 1);
986ae115bc7Smrj 		(void) ndi_prop_update_string(DDI_DEV_T_NONE, xdip,
987*d4039345SRichard Lowe 		    "device-type", "mouse");
988ae115bc7Smrj 	}
989aa2aa9a6SDana Myers 
990aa2aa9a6SDana Myers 	/*
991aa2aa9a6SDana Myers 	 * Create default "compatible" property if required
992aa2aa9a6SDana Myers 	 */
993aa2aa9a6SDana Myers 	if (!ddi_prop_exists(DDI_DEV_T_ANY, xdip,
994aa2aa9a6SDana Myers 	    DDI_PROP_DONTPASS, "compatible"))
995aa2aa9a6SDana Myers 		create_compatible_property(xdip, device_ids);
996ae115bc7Smrj 
997ae115bc7Smrj 	(void) ndi_devi_bind_driver(xdip, 0);
998ae115bc7Smrj 
999ae115bc7Smrj done:
1000aa2aa9a6SDana Myers 	/* discard _HID/_CID list */
1001aa2aa9a6SDana Myers 	d = device_ids;
1002aa2aa9a6SDana Myers 	while (d != NULL) {
1003aa2aa9a6SDana Myers 		device_id_t *next;
1004aa2aa9a6SDana Myers 
1005aa2aa9a6SDana Myers 		next = d->next;
1006*d4039345SRichard Lowe 		if (d->id != NULL)
1007*d4039345SRichard Lowe 			strfree(d->id);
1008*d4039345SRichard Lowe 
1009*d4039345SRichard Lowe 		kmem_free(d, sizeof (device_id_t));
1010aa2aa9a6SDana Myers 		d = next;
1011aa2aa9a6SDana Myers 	}
1012aa2aa9a6SDana Myers 
1013ae115bc7Smrj 	if (path != NULL)
1014ae115bc7Smrj 		AcpiOsFree(path);
1015ae115bc7Smrj 	if (info != NULL)
1016ae115bc7Smrj 		AcpiOsFree(info);
1017ae115bc7Smrj 
1018ae115bc7Smrj 	return (AE_OK);
1019ae115bc7Smrj }
1020ae115bc7Smrj 
10211f9b2f1bSJason King static int
irq_cmp(const void * a,const void * b)10221f9b2f1bSJason King irq_cmp(const void *a, const void *b)
10231f9b2f1bSJason King {
10241f9b2f1bSJason King 	const int *l = a;
10251f9b2f1bSJason King 	const int *r = b;
10261f9b2f1bSJason King 
10271f9b2f1bSJason King 	if (*l < *r)
10281f9b2f1bSJason King 		return (-1);
10291f9b2f1bSJason King 	if (*l > *r)
10301f9b2f1bSJason King 		return (1);
10311f9b2f1bSJason King 	return (0);
10321f9b2f1bSJason King }
10331f9b2f1bSJason King 
1034ae115bc7Smrj static void
used_res_interrupts(void)1035ae115bc7Smrj used_res_interrupts(void)
1036ae115bc7Smrj {
10371f9b2f1bSJason King 	if (used_interrupts.i_num == 0)
10381f9b2f1bSJason King 		return;
1039ae115bc7Smrj 
10401f9b2f1bSJason King 	/*
10411f9b2f1bSJason King 	 * add_known_used_resources() in usr/src/uts/i86pc.io/isa.c (used
10421f9b2f1bSJason King 	 * when ACPI enumeration is disabled) states that the interrupt values
10431f9b2f1bSJason King 	 * in the interrupts property of usedrdip should be in increasing order.
10441f9b2f1bSJason King 	 * It does not state the reason for the requirement, however out of
10451f9b2f1bSJason King 	 * an abundance of caution, we ensure the interrupt values are also
10461f9b2f1bSJason King 	 * stored in the interrupts property in increasing order.
10471f9b2f1bSJason King 	 */
10481f9b2f1bSJason King 	qsort(used_interrupts.i_intrs, used_interrupts.i_num, sizeof (int),
10491f9b2f1bSJason King 	    irq_cmp);
10501f9b2f1bSJason King 
1051ae115bc7Smrj 	(void) ndi_prop_update_int_array(DDI_DEV_T_NONE, usedrdip,
10521f9b2f1bSJason King 	    "interrupts", used_interrupts.i_intrs, used_interrupts.i_num);
10531f9b2f1bSJason King 
10541f9b2f1bSJason King 	kmem_free(used_interrupts.i_intrs,
10551f9b2f1bSJason King 	    used_interrupts.i_alloc * sizeof (int));
10561f9b2f1bSJason King 	bzero(&used_interrupts, sizeof (used_interrupts));
1057ae115bc7Smrj }
1058ae115bc7Smrj 
1059ae115bc7Smrj static void
used_res_dmas(void)1060ae115bc7Smrj used_res_dmas(void)
1061ae115bc7Smrj {
1062ae115bc7Smrj 	int dma[ACPI_ISA_LIMIT];
1063ae115bc7Smrj 	int count = 0;
1064ae115bc7Smrj 	int i;
1065ae115bc7Smrj 
1066ae115bc7Smrj 	for (i = 0; i < ACPI_ISA_LIMIT; i++) {
1067ae115bc7Smrj 		if ((used_dmas >> i) & 1) {
1068ae115bc7Smrj 			dma[count++] = i;
1069ae115bc7Smrj 		}
1070ae115bc7Smrj 	}
1071ae115bc7Smrj 	(void) ndi_prop_update_int_array(DDI_DEV_T_NONE, usedrdip,
1072ae115bc7Smrj 	    "dma-channels", (int *)dma, count);
1073ae115bc7Smrj }
1074ae115bc7Smrj 
1075ae115bc7Smrj static void
used_res_io_mem(char * nodename,int * count,used_io_mem_t ** head)1076ae115bc7Smrj used_res_io_mem(char *nodename, int *count, used_io_mem_t **head)
1077ae115bc7Smrj {
1078ae115bc7Smrj 	int *io;
1079ae115bc7Smrj 	used_io_mem_t *used = *head;
1080ae115bc7Smrj 	int i;
1081ae115bc7Smrj 
1082ae115bc7Smrj 	*count *= 2;
1083*d4039345SRichard Lowe 	io = kmem_zalloc(sizeof (int)*(*count), KM_SLEEP);
1084ae115bc7Smrj 	for (i = 0; i < *count; i += 2) {
1085ae115bc7Smrj 		used_io_mem_t *prev;
1086ae115bc7Smrj 		if (used != NULL) {
1087ae115bc7Smrj 			io[i] = used->start_addr;
1088ae115bc7Smrj 			io[i+1] = used->length;
1089ae115bc7Smrj 			prev = used;
1090ae115bc7Smrj 			used = used->next;
1091ae115bc7Smrj 			kmem_free(prev, sizeof (used_io_mem_t));
1092ae115bc7Smrj 		}
1093ae115bc7Smrj 	}
1094ae115bc7Smrj 	(void) ndi_prop_update_int_array(DDI_DEV_T_NONE, usedrdip,
1095ae115bc7Smrj 	    nodename, (int *)io, *count);
1096ae115bc7Smrj 	kmem_free(io, sizeof (int) * (*count));
1097ae115bc7Smrj 	*head = NULL;
1098ae115bc7Smrj }
1099ae115bc7Smrj 
1100ae115bc7Smrj /*
1101ae115bc7Smrj  * acpi_isa_device_enum() -- call from isa nexus driver
1102ae115bc7Smrj  * returns 1 if deviced enumeration is successful
1103ae115bc7Smrj  *         0 if deviced enumeration fails
1104ae115bc7Smrj  */
1105ae115bc7Smrj int
acpi_isa_device_enum(dev_info_t * isa_dip)1106ae115bc7Smrj acpi_isa_device_enum(dev_info_t *isa_dip)
1107ae115bc7Smrj {
1108ae115bc7Smrj 	char *acpi_prop;
1109ae115bc7Smrj 
1110ae115bc7Smrj 	if (ddi_prop_lookup_string(DDI_DEV_T_ANY, ddi_root_node(),
1111*d4039345SRichard Lowe 	    DDI_PROP_DONTPASS, "acpi_enum_debug", &acpi_prop) ==
1112ae115bc7Smrj 	    DDI_PROP_SUCCESS) {
1113*d4039345SRichard Lowe 		unsigned long data;
1114*d4039345SRichard Lowe 		if (ddi_strtoul(acpi_prop, NULL, 0, &data) == 0) {
1115*d4039345SRichard Lowe 			acpi_enum_debug = (uint32_t)data;
1116ae115bc7Smrj 			e_ddi_prop_remove(DDI_DEV_T_NONE, ddi_root_node(),
1117*d4039345SRichard Lowe 			    "acpi_enum_debug");
1118ae115bc7Smrj 			e_ddi_prop_update_int(DDI_DEV_T_NONE,
1119*d4039345SRichard Lowe 			    ddi_root_node(), "acpi_enum_debug", data);
1120ae115bc7Smrj 		}
1121ae115bc7Smrj 		ddi_prop_free(acpi_prop);
1122ae115bc7Smrj 	}
1123ae115bc7Smrj 
1124ae115bc7Smrj 	if (acpi_enum_debug & ISA_DEVICE_ENUM) {
11257b1019a6SJerry Jelinek 		cmn_err(CE_NOTE, "!acpi_isa_device_enum() called");
1126ae115bc7Smrj 	}
1127ae115bc7Smrj 
1128ae115bc7Smrj 	if (acpica_init() != AE_OK) {
1129*d4039345SRichard Lowe 		cmn_err(CE_WARN, "!acpi_isa_device_enum: init failed");
1130*d4039345SRichard Lowe 		/*
1131*d4039345SRichard Lowe 		 * Note: `acpi-enum` is a private boolean property that is
1132*d4039345SRichard Lowe 		 * respected both as a user-set property (by the isa nexus
1133*d4039345SRichard Lowe 		 * which calls us), and set by us on failure (here) to
1134*d4039345SRichard Lowe 		 * communicate to the i8042 nexus that ACPI enumeration has
1135*d4039345SRichard Lowe 		 * not taken place and that it must enumerate.
1136*d4039345SRichard Lowe 		 */
1137ae115bc7Smrj 		(void) e_ddi_prop_update_string(DDI_DEV_T_NONE,
1138ae115bc7Smrj 		    ddi_root_node(), "acpi-enum", "off");
1139ae115bc7Smrj 		return (0);
1140ae115bc7Smrj 	}
1141ae115bc7Smrj 
1142*d4039345SRichard Lowe 	usedrdip = ddi_find_devinfo("used-resources", -1, 0);
1143ae115bc7Smrj 	if (usedrdip == NULL) {
1144*d4039345SRichard Lowe 		ndi_devi_alloc_sleep(ddi_root_node(), "used-resources",
1145ae115bc7Smrj 		    (pnode_t)DEVI_SID_NODEID, &usedrdip);
1146ae115bc7Smrj 
1147ae115bc7Smrj 	}
1148ae115bc7Smrj 
1149ae115bc7Smrj 	/*
115012f7d0bdSGary Mills 	 * Do the actual enumeration.  Avoid AcpiGetDevices because it
115112f7d0bdSGary Mills 	 * has an unnecessary internal callback that duplicates
115212f7d0bdSGary Mills 	 * determining if the device is present.
1153ae115bc7Smrj 	 */
115412f7d0bdSGary Mills 	(void) AcpiWalkNamespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
115512f7d0bdSGary Mills 	    UINT32_MAX, isa_acpi_callback, NULL, isa_dip, NULL);
1156ae115bc7Smrj 
1157ae115bc7Smrj 	used_res_interrupts();
1158ae115bc7Smrj 	used_res_dmas();
1159ae115bc7Smrj 	used_res_io_mem("device-memory", &used_mem_count, &used_mem_head);
1160ae115bc7Smrj 	used_res_io_mem("io-space", &used_io_count, &used_io_head);
1161ae115bc7Smrj 	(void) ndi_devi_bind_driver(usedrdip, 0);
1162ae115bc7Smrj 
1163ae115bc7Smrj 	return (1);
1164ae115bc7Smrj }
1165