18e56767dSsmall /*
28e56767dSsmall  * CDDL HEADER START
38e56767dSsmall  *
48e56767dSsmall  * The contents of this file are subject to the terms of the
5aaba6dfeSmyers  * Common Development and Distribution License (the "License").
6aaba6dfeSmyers  * You may not use this file except in compliance with the License.
78e56767dSsmall  *
88e56767dSsmall  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
98e56767dSsmall  * or http://www.opensolaris.org/os/licensing.
108e56767dSsmall  * See the License for the specific language governing permissions
118e56767dSsmall  * and limitations under the License.
128e56767dSsmall  *
138e56767dSsmall  * When distributing Covered Code, include this CDDL HEADER in each
148e56767dSsmall  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
158e56767dSsmall  * If applicable, add the following below this CDDL HEADER, with the
168e56767dSsmall  * fields enclosed by brackets "[]" replaced with your own identifying
178e56767dSsmall  * information: Portions Copyright [yyyy] [name of copyright owner]
188e56767dSsmall  *
198e56767dSsmall  * CDDL HEADER END
208e56767dSsmall  */
217c478bd9Sstevel@tonic-gate /*
22aa2aa9a6SDana Myers  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * 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.
287c478bd9Sstevel@tonic-gate  */
297c478bd9Sstevel@tonic-gate 
307c478bd9Sstevel@tonic-gate /*
317c478bd9Sstevel@tonic-gate  * ACPI enumerator
327c478bd9Sstevel@tonic-gate  */
337c478bd9Sstevel@tonic-gate 
347c478bd9Sstevel@tonic-gate #include <sys/ddi.h>
357c478bd9Sstevel@tonic-gate #include <sys/sunddi.h>
367c478bd9Sstevel@tonic-gate #include <sys/sunndi.h>
377c478bd9Sstevel@tonic-gate #include <sys/note.h>
38aa2aa9a6SDana Myers #include <sys/acpi/acpi.h>
397c478bd9Sstevel@tonic-gate #include <sys/acpica.h>
40aa2aa9a6SDana Myers #include <util/sscanf.h>
411f9b2f1bSJason King #include <util/qsort.h>
427c478bd9Sstevel@tonic-gate 
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;
547c478bd9Sstevel@tonic-gate 
55*d4039345SRichard Lowe static uint32_t acpi_enum_debug = 0x00;
567c478bd9Sstevel@tonic-gate #define	PARSE_RESOURCES_DEBUG	0x0001
57*d4039345SRichard Lowe #define	ISAPNP_LOOKUP_DEBUG	0x0002
587c478bd9Sstevel@tonic-gate #define	DEVICES_NOT_ENUMED	0x0004
597c478bd9Sstevel@tonic-gate #define	PARSE_RES_IRQ		0x0008
607c478bd9Sstevel@tonic-gate #define	PARSE_RES_DMA		0x0010
617c478bd9Sstevel@tonic-gate #define	PARSE_RES_MEMORY	0x0020
627c478bd9Sstevel@tonic-gate #define	PARSE_RES_IO		0x0040
637c478bd9Sstevel@tonic-gate #define	PARSE_RES_ADDRESS	0x0080
647c478bd9Sstevel@tonic-gate #define	ISA_DEVICE_ENUM		0x1000
657c478bd9Sstevel@tonic-gate #define	PROCESS_CIDS		0x2000
667c478bd9Sstevel@tonic-gate 
677c478bd9Sstevel@tonic-gate static dev_info_t *usedrdip = NULL;
681f9b2f1bSJason King static intrs_t used_interrupts;
697c478bd9Sstevel@tonic-gate static unsigned short used_dmas = 0;
707c478bd9Sstevel@tonic-gate typedef struct used_io_mem {
717c478bd9Sstevel@tonic-gate 	unsigned int start_addr;
727c478bd9Sstevel@tonic-gate 	unsigned int length;
737c478bd9Sstevel@tonic-gate 	struct used_io_mem *next;
747c478bd9Sstevel@tonic-gate } used_io_mem_t;
757c478bd9Sstevel@tonic-gate static used_io_mem_t *used_io_head = NULL;
767c478bd9Sstevel@tonic-gate static used_io_mem_t *used_mem_head = NULL;
777c478bd9Sstevel@tonic-gate static int used_io_count = 0;
787c478bd9Sstevel@tonic-gate static int used_mem_count = 0;
797c478bd9Sstevel@tonic-gate 
807c478bd9Sstevel@tonic-gate #define	MAX_PARSED_ACPI_RESOURCES	255
817c478bd9Sstevel@tonic-gate #define	ACPI_ISA_LIMIT	16
821f9b2f1bSJason King static int dma[ACPI_ISA_LIMIT];
837c478bd9Sstevel@tonic-gate #define	ACPI_ELEMENT_PACKAGE_LIMIT	32
84ac0f75d7Sdchieu #define	EISA_ID_SIZE	7
857c478bd9Sstevel@tonic-gate 
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 
1247c478bd9Sstevel@tonic-gate /*
1257c478bd9Sstevel@tonic-gate  * insert used io/mem in increasing order
1267c478bd9Sstevel@tonic-gate  */
1277c478bd9Sstevel@tonic-gate static void
insert_used_resource(used_io_mem_t * used,int * used_count,used_io_mem_t ** head)1287c478bd9Sstevel@tonic-gate insert_used_resource(used_io_mem_t *used, int *used_count, used_io_mem_t **head)
1297c478bd9Sstevel@tonic-gate {
1307c478bd9Sstevel@tonic-gate 	used_io_mem_t *curr, *prev;
1317c478bd9Sstevel@tonic-gate 
1327c478bd9Sstevel@tonic-gate 	(*used_count)++;
1337c478bd9Sstevel@tonic-gate 	if (*head == NULL) {
1347c478bd9Sstevel@tonic-gate 		*head = used;
1357c478bd9Sstevel@tonic-gate 		return;
1367c478bd9Sstevel@tonic-gate 	}
1377c478bd9Sstevel@tonic-gate 	curr = prev = *head;
1387c478bd9Sstevel@tonic-gate 	/* find a place to insert */
1397c478bd9Sstevel@tonic-gate 	while ((curr != NULL) &&
1407c478bd9Sstevel@tonic-gate 	    (curr->start_addr < used->start_addr)) {
1417c478bd9Sstevel@tonic-gate 		prev = curr;
1427c478bd9Sstevel@tonic-gate 		curr = curr->next;
1437c478bd9Sstevel@tonic-gate 	}
1447c478bd9Sstevel@tonic-gate 	if (prev == curr) {
1457c478bd9Sstevel@tonic-gate 		/* head */
1467c478bd9Sstevel@tonic-gate 		*head = used;
1477c478bd9Sstevel@tonic-gate 		used->next = curr;
1487c478bd9Sstevel@tonic-gate 		return;
1497c478bd9Sstevel@tonic-gate 	} else {
1507c478bd9Sstevel@tonic-gate 		prev->next = used;
1517c478bd9Sstevel@tonic-gate 	}
1527c478bd9Sstevel@tonic-gate 	used->next = curr;
1537c478bd9Sstevel@tonic-gate }
1547c478bd9Sstevel@tonic-gate 
1557c478bd9Sstevel@tonic-gate static void
add_used_io_mem(struct regspec * io,int io_count)1567c478bd9Sstevel@tonic-gate add_used_io_mem(struct regspec *io, int io_count)
1577c478bd9Sstevel@tonic-gate {
1587c478bd9Sstevel@tonic-gate 	int i;
1597c478bd9Sstevel@tonic-gate 	used_io_mem_t *used;
1607c478bd9Sstevel@tonic-gate 
1617c478bd9Sstevel@tonic-gate 	for (i = 0; i < io_count; i++) {
162*d4039345SRichard Lowe 		used = kmem_zalloc(sizeof (used_io_mem_t),
1637c478bd9Sstevel@tonic-gate 		    KM_SLEEP);
1647c478bd9Sstevel@tonic-gate 		used->start_addr = io[i].regspec_addr;
1657c478bd9Sstevel@tonic-gate 		used->length = io[i].regspec_size;
1667c478bd9Sstevel@tonic-gate 		if (io[i].regspec_bustype == 1) {
1677c478bd9Sstevel@tonic-gate 			insert_used_resource(used, &used_io_count,
1687c478bd9Sstevel@tonic-gate 			    &used_io_head);
1697c478bd9Sstevel@tonic-gate 		} else {
1707c478bd9Sstevel@tonic-gate 			insert_used_resource(used, &used_mem_count,
1717c478bd9Sstevel@tonic-gate 			    &used_mem_head);
1727c478bd9Sstevel@tonic-gate 		}
1737c478bd9Sstevel@tonic-gate 	}
1747c478bd9Sstevel@tonic-gate }
1757c478bd9Sstevel@tonic-gate 
1767c478bd9Sstevel@tonic-gate static void
parse_resources_irq(ACPI_RESOURCE * resource_ptr,intrs_t * intrs)1771f9b2f1bSJason King parse_resources_irq(ACPI_RESOURCE *resource_ptr, intrs_t *intrs)
1787c478bd9Sstevel@tonic-gate {
1791f9b2f1bSJason King 	uint_t i;
1807c478bd9Sstevel@tonic-gate 
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 
1877c478bd9Sstevel@tonic-gate 		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);
2237c478bd9Sstevel@tonic-gate 		}
2247c478bd9Sstevel@tonic-gate 	}
2257c478bd9Sstevel@tonic-gate }
2267c478bd9Sstevel@tonic-gate 
2277c478bd9Sstevel@tonic-gate static void
parse_resources_dma(ACPI_RESOURCE * resource_ptr,int * dma_count)2287c478bd9Sstevel@tonic-gate parse_resources_dma(ACPI_RESOURCE *resource_ptr, int *dma_count)
2297c478bd9Sstevel@tonic-gate {
2307c478bd9Sstevel@tonic-gate 	int i;
2317c478bd9Sstevel@tonic-gate 
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];
2357c478bd9Sstevel@tonic-gate 		if (acpi_enum_debug & PARSE_RES_DMA) {
2367b1019a6SJerry Jelinek 			cmn_err(CE_NOTE, "!parse_resources() "\
2377c478bd9Sstevel@tonic-gate 			    "DMA num %u, channel # = %u",
238a4a4d28eSSeth Goldberg 			    i, resource_ptr->Data.Dma.Channels[i]);
2397c478bd9Sstevel@tonic-gate 		}
2407c478bd9Sstevel@tonic-gate 	}
2417c478bd9Sstevel@tonic-gate }
2427c478bd9Sstevel@tonic-gate 
2437c478bd9Sstevel@tonic-gate static void
parse_resources_io(ACPI_RESOURCE * resource_ptr,struct regspec * io,int * io_count)2447c478bd9Sstevel@tonic-gate parse_resources_io(ACPI_RESOURCE *resource_ptr, struct regspec *io,
2457c478bd9Sstevel@tonic-gate     int *io_count)
2467c478bd9Sstevel@tonic-gate {
2477c478bd9Sstevel@tonic-gate 	ACPI_RESOURCE_IO acpi_io = resource_ptr->Data.Io;
2487c478bd9Sstevel@tonic-gate 
2498fc7923fSDana Myers 	if (acpi_io.AddressLength == 0)
2508fc7923fSDana Myers 		return;
2518fc7923fSDana Myers 
2527c478bd9Sstevel@tonic-gate 	io[*io_count].regspec_bustype = 1; /* io */
253186507a7Smyers 	io[*io_count].regspec_size = acpi_io.AddressLength;
254c960c1feSmyers 	io[*io_count].regspec_addr = acpi_io.Minimum;
2557c478bd9Sstevel@tonic-gate 	if (acpi_enum_debug & PARSE_RES_IO) {
2567b1019a6SJerry Jelinek 		cmn_err(CE_NOTE, "!parse_resources() "\
2577c478bd9Sstevel@tonic-gate 		    "IO min 0x%X, max 0x%X, length: 0x%X",
258186507a7Smyers 		    acpi_io.Minimum,
259186507a7Smyers 		    acpi_io.Maximum,
260186507a7Smyers 		    acpi_io.AddressLength);
2617c478bd9Sstevel@tonic-gate 	}
2627c478bd9Sstevel@tonic-gate 	(*io_count)++;
2637c478bd9Sstevel@tonic-gate }
2647c478bd9Sstevel@tonic-gate 
2657c478bd9Sstevel@tonic-gate static void
parse_resources_fixed_io(ACPI_RESOURCE * resource_ptr,struct regspec * io,int * io_count)2667c478bd9Sstevel@tonic-gate parse_resources_fixed_io(ACPI_RESOURCE *resource_ptr, struct regspec *io,
2677c478bd9Sstevel@tonic-gate     int *io_count)
2687c478bd9Sstevel@tonic-gate {
2697c478bd9Sstevel@tonic-gate 	ACPI_RESOURCE_FIXED_IO fixed_io = resource_ptr->Data.FixedIo;
2707c478bd9Sstevel@tonic-gate 
2718fc7923fSDana Myers 	if (fixed_io.AddressLength == 0)
2728fc7923fSDana Myers 		return;
2738fc7923fSDana Myers 
2747c478bd9Sstevel@tonic-gate 	io[*io_count].regspec_bustype = 1; /* io */
275186507a7Smyers 	io[*io_count].regspec_addr = fixed_io.Address;
276186507a7Smyers 	io[*io_count].regspec_size = fixed_io.AddressLength;
2777c478bd9Sstevel@tonic-gate 	if (acpi_enum_debug & PARSE_RES_IO) {
2787b1019a6SJerry Jelinek 		cmn_err(CE_NOTE, "!parse_resources() "\
2797c478bd9Sstevel@tonic-gate 		    "Fixed IO 0x%X, length: 0x%X",
280186507a7Smyers 		    fixed_io.Address, fixed_io.AddressLength);
2817c478bd9Sstevel@tonic-gate 	}
2827c478bd9Sstevel@tonic-gate 	(*io_count)++;
2837c478bd9Sstevel@tonic-gate }
2847c478bd9Sstevel@tonic-gate 
2857c478bd9Sstevel@tonic-gate static void
parse_resources_fixed_mem32(ACPI_RESOURCE * resource_ptr,struct regspec * io,int * io_count)2867c478bd9Sstevel@tonic-gate parse_resources_fixed_mem32(ACPI_RESOURCE *resource_ptr, struct regspec *io,
2877c478bd9Sstevel@tonic-gate     int *io_count)
2887c478bd9Sstevel@tonic-gate {
289186507a7Smyers 	ACPI_RESOURCE_FIXED_MEMORY32 fixed_mem32 =
2907c478bd9Sstevel@tonic-gate 	    resource_ptr->Data.FixedMemory32;
2917c478bd9Sstevel@tonic-gate 
2928fc7923fSDana Myers 	if (fixed_mem32.AddressLength == 0)
2938fc7923fSDana Myers 		return;
2948fc7923fSDana Myers 
2957c478bd9Sstevel@tonic-gate 	io[*io_count].regspec_bustype = 0; /* memory */
296186507a7Smyers 	io[*io_count].regspec_addr = fixed_mem32.Address;
297186507a7Smyers 	io[*io_count].regspec_size = fixed_mem32.AddressLength;
2987c478bd9Sstevel@tonic-gate 	if (acpi_enum_debug & PARSE_RES_MEMORY) {
2997b1019a6SJerry Jelinek 		cmn_err(CE_NOTE, "!parse_resources() "\
3007c478bd9Sstevel@tonic-gate 		    "Fixed Mem 32 %ul, length: %ul",
301186507a7Smyers 		    fixed_mem32.Address, fixed_mem32.AddressLength);
3027c478bd9Sstevel@tonic-gate 	}
3037c478bd9Sstevel@tonic-gate 	(*io_count)++;
3047c478bd9Sstevel@tonic-gate }
3057c478bd9Sstevel@tonic-gate 
3067c478bd9Sstevel@tonic-gate static void
parse_resources_mem32(ACPI_RESOURCE * resource_ptr,struct regspec * io,int * io_count)3077c478bd9Sstevel@tonic-gate parse_resources_mem32(ACPI_RESOURCE *resource_ptr, struct regspec *io,
3087c478bd9Sstevel@tonic-gate     int *io_count)
3097c478bd9Sstevel@tonic-gate {
310186507a7Smyers 	ACPI_RESOURCE_MEMORY32 mem32 = resource_ptr->Data.Memory32;
3117c478bd9Sstevel@tonic-gate 
3128fc7923fSDana Myers 	if (mem32.AddressLength == 0)
3138fc7923fSDana Myers 		return;
3148fc7923fSDana Myers 
315186507a7Smyers 	if (resource_ptr->Data.Memory32.Minimum ==
316186507a7Smyers 	    resource_ptr->Data.Memory32.Maximum) {
3177c478bd9Sstevel@tonic-gate 		io[*io_count].regspec_bustype = 0; /* memory */
318186507a7Smyers 		io[*io_count].regspec_addr = mem32.Minimum;
319186507a7Smyers 		io[*io_count].regspec_size = mem32.AddressLength;
3207c478bd9Sstevel@tonic-gate 		(*io_count)++;
3217c478bd9Sstevel@tonic-gate 		if (acpi_enum_debug & PARSE_RES_MEMORY) {
3227b1019a6SJerry Jelinek 			cmn_err(CE_NOTE, "!parse_resources() "\
3237c478bd9Sstevel@tonic-gate 			    "Mem 32 0x%X, length: 0x%X",
324186507a7Smyers 			    mem32.Minimum, mem32.AddressLength);
3257c478bd9Sstevel@tonic-gate 		}
3267c478bd9Sstevel@tonic-gate 		return;
3277c478bd9Sstevel@tonic-gate 	}
3287c478bd9Sstevel@tonic-gate 	if (acpi_enum_debug & PARSE_RES_MEMORY) {
3297b1019a6SJerry Jelinek 		cmn_err(CE_NOTE, "!parse_resources() "\
3307c478bd9Sstevel@tonic-gate 		    "MEM32 Min Max not equal!");
3317b1019a6SJerry Jelinek 		cmn_err(CE_NOTE, "!parse_resources() "\
332186507a7Smyers 		    "Mem 32 Minimum 0x%X, Maximum: 0x%X",
333186507a7Smyers 		    mem32.Minimum, mem32.Maximum);
3347c478bd9Sstevel@tonic-gate 	}
3357c478bd9Sstevel@tonic-gate }
3367c478bd9Sstevel@tonic-gate 
3377c478bd9Sstevel@tonic-gate static void
parse_resources_addr16(ACPI_RESOURCE * resource_ptr,struct regspec * io,int * io_count)3387c478bd9Sstevel@tonic-gate parse_resources_addr16(ACPI_RESOURCE *resource_ptr, struct regspec *io,
3397c478bd9Sstevel@tonic-gate     int *io_count)
3407c478bd9Sstevel@tonic-gate {
3417c478bd9Sstevel@tonic-gate 	ACPI_RESOURCE_ADDRESS16 addr16 =
3427c478bd9Sstevel@tonic-gate 	    resource_ptr->Data.Address16;
3438fc7923fSDana Myers 
3447b1019a6SJerry Jelinek 	if (addr16.Address.AddressLength == 0)
3458fc7923fSDana Myers 		return;
3468fc7923fSDana Myers 
3477c478bd9Sstevel@tonic-gate 	if (acpi_enum_debug & PARSE_RES_ADDRESS) {
3487c478bd9Sstevel@tonic-gate 		if (addr16.ResourceType == ACPI_MEMORY_RANGE) {
3497b1019a6SJerry Jelinek 			cmn_err(CE_NOTE, "!parse_resources() "\
3507c478bd9Sstevel@tonic-gate 			    "ADDRESS 16 MEMORY RANGE");
3517c478bd9Sstevel@tonic-gate 		} else
3527c478bd9Sstevel@tonic-gate 		if (addr16.ResourceType == ACPI_IO_RANGE) {
3537b1019a6SJerry Jelinek 			cmn_err(CE_NOTE, "!parse_resources() "\
3547c478bd9Sstevel@tonic-gate 			    "ADDRESS 16 IO RANGE");
3557c478bd9Sstevel@tonic-gate 		} else {
3567b1019a6SJerry Jelinek 			cmn_err(CE_NOTE, "!parse_resources() "\
3577c478bd9Sstevel@tonic-gate 			    "ADDRESS 16 OTHER");
3587c478bd9Sstevel@tonic-gate 		}
3597b1019a6SJerry Jelinek 		cmn_err(CE_NOTE, "!parse_resources() "\
3607c478bd9Sstevel@tonic-gate 		    "%s "\
3617c478bd9Sstevel@tonic-gate 		    "MinAddressFixed 0x%X, "\
3627c478bd9Sstevel@tonic-gate 		    "MaxAddressFixed 0x%X, "\
363186507a7Smyers 		    "Minimum 0x%X, "\
364186507a7Smyers 		    "Maximum 0x%X, "\
3657c478bd9Sstevel@tonic-gate 		    "length: 0x%X\n",
3667c478bd9Sstevel@tonic-gate 		    addr16.ProducerConsumer == ACPI_CONSUMER ?
3677c478bd9Sstevel@tonic-gate 		    "CONSUMER" : "PRODUCER",
3687c478bd9Sstevel@tonic-gate 		    addr16.MinAddressFixed,
3697c478bd9Sstevel@tonic-gate 		    addr16.MaxAddressFixed,
3707b1019a6SJerry Jelinek 		    addr16.Address.Minimum,
3717b1019a6SJerry Jelinek 		    addr16.Address.Maximum,
3727b1019a6SJerry Jelinek 		    addr16.Address.AddressLength);
3737c478bd9Sstevel@tonic-gate 	}
374aaba6dfeSmyers 	if (addr16.ProducerConsumer == ACPI_PRODUCER ||
375aaba6dfeSmyers 	    (addr16.ResourceType != ACPI_MEMORY_RANGE &&
376aaba6dfeSmyers 	    addr16.ResourceType != ACPI_IO_RANGE)) {
3777c478bd9Sstevel@tonic-gate 		return;
3787c478bd9Sstevel@tonic-gate 	}
3797b1019a6SJerry Jelinek 	if (addr16.Address.AddressLength > 0) {
3807c478bd9Sstevel@tonic-gate 		if (addr16.ResourceType == ACPI_MEMORY_RANGE) {
3817c478bd9Sstevel@tonic-gate 			/* memory */
3827c478bd9Sstevel@tonic-gate 			io[*io_count].regspec_bustype = 0;
3837c478bd9Sstevel@tonic-gate 		} else {
3847c478bd9Sstevel@tonic-gate 			/* io */
3857c478bd9Sstevel@tonic-gate 			io[*io_count].regspec_bustype = 1;
3867c478bd9Sstevel@tonic-gate 		}
3877b1019a6SJerry Jelinek 		io[*io_count].regspec_addr = addr16.Address.Minimum;
3887b1019a6SJerry Jelinek 		io[*io_count].regspec_size = addr16.Address.AddressLength;
3897c478bd9Sstevel@tonic-gate 		(*io_count)++;
3907c478bd9Sstevel@tonic-gate 	}
3917c478bd9Sstevel@tonic-gate }
3927c478bd9Sstevel@tonic-gate 
3937c478bd9Sstevel@tonic-gate static void
parse_resources_addr32(ACPI_RESOURCE * resource_ptr,struct regspec * io,int * io_count)3947c478bd9Sstevel@tonic-gate parse_resources_addr32(ACPI_RESOURCE *resource_ptr, struct regspec *io,
3957c478bd9Sstevel@tonic-gate     int *io_count)
3967c478bd9Sstevel@tonic-gate {
3977c478bd9Sstevel@tonic-gate 	ACPI_RESOURCE_ADDRESS32 addr32 =
3987c478bd9Sstevel@tonic-gate 	    resource_ptr->Data.Address32;
3998fc7923fSDana Myers 
4007b1019a6SJerry Jelinek 	if (addr32.Address.AddressLength == 0)
4018fc7923fSDana Myers 		return;
4028fc7923fSDana Myers 
4037c478bd9Sstevel@tonic-gate 	if (acpi_enum_debug & PARSE_RES_ADDRESS) {
4047c478bd9Sstevel@tonic-gate 		if (addr32.ResourceType == ACPI_MEMORY_RANGE) {
4057b1019a6SJerry Jelinek 			cmn_err(CE_NOTE, "!parse_resources() "\
4067c478bd9Sstevel@tonic-gate 			    "ADDRESS 32 MEMORY RANGE");
4077c478bd9Sstevel@tonic-gate 		} else
4087c478bd9Sstevel@tonic-gate 		if (addr32.ResourceType == ACPI_IO_RANGE) {
4097b1019a6SJerry Jelinek 			cmn_err(CE_NOTE, "!parse_resources() "\
4107c478bd9Sstevel@tonic-gate 			    "ADDRESS 32 IO RANGE");
4117c478bd9Sstevel@tonic-gate 		} else {
4127b1019a6SJerry Jelinek 			cmn_err(CE_NOTE, "!parse_resources() "\
4137c478bd9Sstevel@tonic-gate 			    "ADDRESS 32 OTHER");
4147c478bd9Sstevel@tonic-gate 		}
4157b1019a6SJerry Jelinek 		cmn_err(CE_NOTE, "!parse_resources() "\
4167c478bd9Sstevel@tonic-gate 		    "%s "\
4177c478bd9Sstevel@tonic-gate 		    "MinAddressFixed 0x%X, "\
4187c478bd9Sstevel@tonic-gate 		    "MaxAddressFixed 0x%X, "\
419186507a7Smyers 		    "Minimum 0x%X, "\
420186507a7Smyers 		    "Maximum 0x%X, "\
4217c478bd9Sstevel@tonic-gate 		    "length: 0x%X\n",
4227c478bd9Sstevel@tonic-gate 		    addr32.ProducerConsumer == ACPI_CONSUMER ?
4237c478bd9Sstevel@tonic-gate 		    "CONSUMER" : "PRODUCER",
4247c478bd9Sstevel@tonic-gate 		    addr32.MinAddressFixed,
4257c478bd9Sstevel@tonic-gate 		    addr32.MaxAddressFixed,
4267b1019a6SJerry Jelinek 		    addr32.Address.Minimum,
4277b1019a6SJerry Jelinek 		    addr32.Address.Maximum,
4287b1019a6SJerry Jelinek 		    addr32.Address.AddressLength);
4297c478bd9Sstevel@tonic-gate 	}
430aaba6dfeSmyers 	if (addr32.ProducerConsumer == ACPI_PRODUCER ||
431aaba6dfeSmyers 	    (addr32.ResourceType != ACPI_MEMORY_RANGE &&
432aaba6dfeSmyers 	    addr32.ResourceType != ACPI_IO_RANGE)) {
4337c478bd9Sstevel@tonic-gate 		return;
4347c478bd9Sstevel@tonic-gate 	}
4357b1019a6SJerry Jelinek 	if (addr32.Address.AddressLength > 0) {
4367c478bd9Sstevel@tonic-gate 		if (addr32.ResourceType == ACPI_MEMORY_RANGE) {
4377c478bd9Sstevel@tonic-gate 			/* memory */
4387c478bd9Sstevel@tonic-gate 			io[*io_count].regspec_bustype = 0;
4397c478bd9Sstevel@tonic-gate 		} else {
4407c478bd9Sstevel@tonic-gate 			/* io */
4417c478bd9Sstevel@tonic-gate 			io[*io_count].regspec_bustype = 1;
4427c478bd9Sstevel@tonic-gate 		}
4437b1019a6SJerry Jelinek 		io[*io_count].regspec_addr = addr32.Address.Minimum;
4447b1019a6SJerry Jelinek 		io[*io_count].regspec_size = addr32.Address.AddressLength;
4457c478bd9Sstevel@tonic-gate 		(*io_count)++;
4467c478bd9Sstevel@tonic-gate 	}
4477c478bd9Sstevel@tonic-gate }
4487c478bd9Sstevel@tonic-gate 
4497c478bd9Sstevel@tonic-gate static void
parse_resources_addr64(ACPI_RESOURCE * resource_ptr,struct regspec * io,int * io_count)4507c478bd9Sstevel@tonic-gate parse_resources_addr64(ACPI_RESOURCE *resource_ptr, struct regspec *io,
4517c478bd9Sstevel@tonic-gate     int *io_count)
4527c478bd9Sstevel@tonic-gate {
4537c478bd9Sstevel@tonic-gate 	ACPI_RESOURCE_ADDRESS64 addr64 =
4547c478bd9Sstevel@tonic-gate 	    resource_ptr->Data.Address64;
4558fc7923fSDana Myers 
4567b1019a6SJerry Jelinek 	if (addr64.Address.AddressLength == 0)
4578fc7923fSDana Myers 		return;
4588fc7923fSDana Myers 
4597c478bd9Sstevel@tonic-gate 	if (acpi_enum_debug & PARSE_RES_ADDRESS) {
4607c478bd9Sstevel@tonic-gate 		if (addr64.ResourceType == ACPI_MEMORY_RANGE) {
4617b1019a6SJerry Jelinek 			cmn_err(CE_NOTE, "!parse_resources() "\
4627c478bd9Sstevel@tonic-gate 			    "ADDRESS 64 MEMORY RANGE");
4637c478bd9Sstevel@tonic-gate 		} else
4647c478bd9Sstevel@tonic-gate 		if (addr64.ResourceType == ACPI_IO_RANGE) {
4657b1019a6SJerry Jelinek 			cmn_err(CE_NOTE, "!parse_resources() "\
4667c478bd9Sstevel@tonic-gate 			    "ADDRESS 64 IO RANGE");
4677c478bd9Sstevel@tonic-gate 		} else {
4687b1019a6SJerry Jelinek 			cmn_err(CE_NOTE, "!parse_resources() "\
4697c478bd9Sstevel@tonic-gate 			    "ADDRESS 64 OTHER");
4707c478bd9Sstevel@tonic-gate 		}
4717c478bd9Sstevel@tonic-gate #ifdef _LP64
4727b1019a6SJerry Jelinek 		cmn_err(CE_NOTE, "!parse_resources() "\
4737c478bd9Sstevel@tonic-gate 		    "%s "\
4747c478bd9Sstevel@tonic-gate 		    "MinAddressFixed 0x%X, "\
4757c478bd9Sstevel@tonic-gate 		    "MaxAddressFixed 0x%X, "\
476186507a7Smyers 		    "Minimum 0x%lX, "\
477186507a7Smyers 		    "Maximum 0x%lX, "\
4787c478bd9Sstevel@tonic-gate 		    "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);
4867c478bd9Sstevel@tonic-gate #else
4877b1019a6SJerry Jelinek 		cmn_err(CE_NOTE, "!parse_resources() "\
4887c478bd9Sstevel@tonic-gate 		    "%s "\
4897c478bd9Sstevel@tonic-gate 		    "MinAddressFixed 0x%X, "\
4907c478bd9Sstevel@tonic-gate 		    "MaxAddressFixed 0x%X, "\
491186507a7Smyers 		    "Minimum 0x%llX, "\
492186507a7Smyers 		    "Maximum 0x%llX, "\
4937c478bd9Sstevel@tonic-gate 		    "length: 0x%llX\n",
4947c478bd9Sstevel@tonic-gate 		    addr64.ProducerConsumer == ACPI_CONSUMER ?
4957c478bd9Sstevel@tonic-gate 		    "CONSUMER" : "PRODUCER",
4967c478bd9Sstevel@tonic-gate 		    addr64.MinAddressFixed,
4977c478bd9Sstevel@tonic-gate 		    addr64.MaxAddressFixed,
4987b1019a6SJerry Jelinek 		    addr64.Address.Minimum,
4997b1019a6SJerry Jelinek 		    addr64.Address.Maximum,
5007b1019a6SJerry Jelinek 		    addr64.Address.AddressLength);
501a4a4d28eSSeth Goldberg #endif
5027c478bd9Sstevel@tonic-gate 	}
503aaba6dfeSmyers 	if (addr64.ProducerConsumer == ACPI_PRODUCER ||
504aaba6dfeSmyers 	    (addr64.ResourceType != ACPI_MEMORY_RANGE &&
505aaba6dfeSmyers 	    addr64.ResourceType != ACPI_IO_RANGE)) {
5067c478bd9Sstevel@tonic-gate 		return;
5077c478bd9Sstevel@tonic-gate 	}
5087b1019a6SJerry Jelinek 	if (addr64.Address.AddressLength > 0) {
5097c478bd9Sstevel@tonic-gate 		if (addr64.ResourceType == ACPI_MEMORY_RANGE) {
5107c478bd9Sstevel@tonic-gate 			/* memory */
5117c478bd9Sstevel@tonic-gate 			io[*io_count].regspec_bustype = 0;
5127c478bd9Sstevel@tonic-gate 		} else {
5137c478bd9Sstevel@tonic-gate 			/* io */
5147c478bd9Sstevel@tonic-gate 			io[*io_count].regspec_bustype = 1;
5157c478bd9Sstevel@tonic-gate 		}
5167b1019a6SJerry Jelinek 		io[*io_count].regspec_addr = addr64.Address.Minimum;
5177b1019a6SJerry Jelinek 		io[*io_count].regspec_size = addr64.Address.AddressLength;
5187c478bd9Sstevel@tonic-gate 		(*io_count)++;
5197c478bd9Sstevel@tonic-gate 	}
5207c478bd9Sstevel@tonic-gate }
5217c478bd9Sstevel@tonic-gate 
5227c478bd9Sstevel@tonic-gate 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)
5247c478bd9Sstevel@tonic-gate {
5257c478bd9Sstevel@tonic-gate 	ACPI_BUFFER	buf;
5267c478bd9Sstevel@tonic-gate 	ACPI_RESOURCE	*resource_ptr;
5277c478bd9Sstevel@tonic-gate 	ACPI_STATUS	status;
5287c478bd9Sstevel@tonic-gate 	char		*current_ptr, *last_ptr;
5297c478bd9Sstevel@tonic-gate 	struct		regspec *io;
5301f9b2f1bSJason King 	intrs_t		intrs = { 0 };
5311f9b2f1bSJason King 	int		io_count = 0, dma_count = 0;
5327c478bd9Sstevel@tonic-gate 	int		i;
5337c478bd9Sstevel@tonic-gate 
5347c478bd9Sstevel@tonic-gate 	buf.Length = ACPI_ALLOCATE_BUFFER;
5357c478bd9Sstevel@tonic-gate 	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);
54612f7d0bdSGary Mills 		if (status != AE_OK) {
54712f7d0bdSGary Mills 			return (status);
54812f7d0bdSGary Mills 		}
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));
5547c478bd9Sstevel@tonic-gate 		return (status);
55512f7d0bdSGary Mills 		break;
5567c478bd9Sstevel@tonic-gate 	}
557*d4039345SRichard Lowe 	io = kmem_zalloc(sizeof (struct regspec) *
5587c478bd9Sstevel@tonic-gate 	    MAX_PARSED_ACPI_RESOURCES, KM_SLEEP);
5597c478bd9Sstevel@tonic-gate 	current_ptr = buf.Pointer;
5607c478bd9Sstevel@tonic-gate 	last_ptr = (char *)buf.Pointer + buf.Length;
5617c478bd9Sstevel@tonic-gate 	while (current_ptr < last_ptr) {
5627c478bd9Sstevel@tonic-gate 		if (io_count >= MAX_PARSED_ACPI_RESOURCES) {
5637c478bd9Sstevel@tonic-gate 			break;
5647c478bd9Sstevel@tonic-gate 		}
5657c478bd9Sstevel@tonic-gate 		resource_ptr = (ACPI_RESOURCE *)current_ptr;
5667c478bd9Sstevel@tonic-gate 		current_ptr += resource_ptr->Length;
567186507a7Smyers 		switch (resource_ptr->Type) {
568186507a7Smyers 		case ACPI_RESOURCE_TYPE_END_TAG:
5697c478bd9Sstevel@tonic-gate 			current_ptr = last_ptr;
5707c478bd9Sstevel@tonic-gate 			break;
571186507a7Smyers 		case ACPI_RESOURCE_TYPE_IO:
5727c478bd9Sstevel@tonic-gate 			parse_resources_io(resource_ptr, io, &io_count);
5737c478bd9Sstevel@tonic-gate 			break;
574186507a7Smyers 		case ACPI_RESOURCE_TYPE_FIXED_IO:
5757c478bd9Sstevel@tonic-gate 			parse_resources_fixed_io(resource_ptr, io, &io_count);
5767c478bd9Sstevel@tonic-gate 			break;
577186507a7Smyers 		case ACPI_RESOURCE_TYPE_FIXED_MEMORY32:
5787c478bd9Sstevel@tonic-gate 			parse_resources_fixed_mem32(resource_ptr, io,
5797c478bd9Sstevel@tonic-gate 			    &io_count);
5807c478bd9Sstevel@tonic-gate 			break;
581186507a7Smyers 		case ACPI_RESOURCE_TYPE_MEMORY32:
5827c478bd9Sstevel@tonic-gate 			parse_resources_mem32(resource_ptr, io, &io_count);
5837c478bd9Sstevel@tonic-gate 			break;
584186507a7Smyers 		case ACPI_RESOURCE_TYPE_ADDRESS16:
5857c478bd9Sstevel@tonic-gate 			parse_resources_addr16(resource_ptr, io, &io_count);
5867c478bd9Sstevel@tonic-gate 			break;
587186507a7Smyers 		case ACPI_RESOURCE_TYPE_ADDRESS32:
5887c478bd9Sstevel@tonic-gate 			parse_resources_addr32(resource_ptr, io, &io_count);
5897c478bd9Sstevel@tonic-gate 			break;
590186507a7Smyers 		case ACPI_RESOURCE_TYPE_ADDRESS64:
5917c478bd9Sstevel@tonic-gate 			parse_resources_addr64(resource_ptr, io, &io_count);
5927c478bd9Sstevel@tonic-gate 			break;
593186507a7Smyers 		case ACPI_RESOURCE_TYPE_IRQ:
5941f9b2f1bSJason King 			parse_resources_irq(resource_ptr, &intrs);
5957c478bd9Sstevel@tonic-gate 			break;
596186507a7Smyers 		case ACPI_RESOURCE_TYPE_DMA:
5977c478bd9Sstevel@tonic-gate 			parse_resources_dma(resource_ptr, &dma_count);
5987c478bd9Sstevel@tonic-gate 			break;
599186507a7Smyers 		case ACPI_RESOURCE_TYPE_START_DEPENDENT:
6007c478bd9Sstevel@tonic-gate 			cmn_err(CE_NOTE,
601186507a7Smyers 			    "!ACPI source type"
602186507a7Smyers 			    " ACPI_RESOURCE_TYPE_START_DEPENDENT"
603186507a7Smyers 			    " not supported");
6047c478bd9Sstevel@tonic-gate 			break;
605186507a7Smyers 		case ACPI_RESOURCE_TYPE_END_DEPENDENT:
6067c478bd9Sstevel@tonic-gate 			cmn_err(CE_NOTE,
607186507a7Smyers 			    "!ACPI source type"
608186507a7Smyers 			    " ACPI_RESOURCE_TYPE_END_DEPENDENT"
609186507a7Smyers 			    " not supported");
6107c478bd9Sstevel@tonic-gate 			break;
611186507a7Smyers 		case ACPI_RESOURCE_TYPE_VENDOR:
6127c478bd9Sstevel@tonic-gate 			cmn_err(CE_NOTE,
613186507a7Smyers 			    "!ACPI source type"
614186507a7Smyers 			    " ACPI_RESOURCE_TYPE_VENDOR"
615186507a7Smyers 			    " not supported");
6167c478bd9Sstevel@tonic-gate 			break;
617186507a7Smyers 		case ACPI_RESOURCE_TYPE_MEMORY24:
6187c478bd9Sstevel@tonic-gate 			cmn_err(CE_NOTE,
619186507a7Smyers 			    "!ACPI source type"
620186507a7Smyers 			    " ACPI_RESOURCE_TYPE_MEMORY24"
621186507a7Smyers 			    " not supported");
6227c478bd9Sstevel@tonic-gate 			break;
623186507a7Smyers 		case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
6241f9b2f1bSJason King 			parse_resources_extended_irq(resource_ptr, &intrs);
6257c478bd9Sstevel@tonic-gate 			break;
6267c478bd9Sstevel@tonic-gate 		default:
6277c478bd9Sstevel@tonic-gate 		/* Some types are not yet implemented (See CA 6.4) */
6287c478bd9Sstevel@tonic-gate 			cmn_err(CE_NOTE,
6297c478bd9Sstevel@tonic-gate 			    "!ACPI resource type (0X%X) not yet supported",
630186507a7Smyers 			    resource_ptr->Type);
6317c478bd9Sstevel@tonic-gate 			break;
6327c478bd9Sstevel@tonic-gate 		}
6337c478bd9Sstevel@tonic-gate 	}
6347c478bd9Sstevel@tonic-gate 
6357c478bd9Sstevel@tonic-gate 	if (io_count) {
6367c478bd9Sstevel@tonic-gate 		/*
6377c478bd9Sstevel@tonic-gate 		 * on LX50, you get interrupts of mouse and keyboard
6387c478bd9Sstevel@tonic-gate 		 * from separate PNP id...
6397c478bd9Sstevel@tonic-gate 		 */
6407c478bd9Sstevel@tonic-gate 		if (io_count == 2) {
6417c478bd9Sstevel@tonic-gate 			if ((io[0].regspec_addr == 0x60 &&
6427c478bd9Sstevel@tonic-gate 			    io[1].regspec_addr == 0x64) ||
6437c478bd9Sstevel@tonic-gate 			    (io[0].regspec_addr == 0x64 &&
6447c478bd9Sstevel@tonic-gate 			    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);
6507c478bd9Sstevel@tonic-gate 			}
6517c478bd9Sstevel@tonic-gate 		}
6527c478bd9Sstevel@tonic-gate 		add_used_io_mem(io, io_count);
6537c478bd9Sstevel@tonic-gate 		if (xdip != NULL) {
6547c478bd9Sstevel@tonic-gate 			(void) ndi_prop_update_int_array(DDI_DEV_T_NONE, xdip,
6557c478bd9Sstevel@tonic-gate 			    "reg", (int *)io, 3*io_count);
6567c478bd9Sstevel@tonic-gate 		}
6577c478bd9Sstevel@tonic-gate 	}
6581f9b2f1bSJason King 	if (intrs.i_num > 0) {
6591f9b2f1bSJason King 		if (xdip != NULL) {
6601f9b2f1bSJason King 			(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));
6647c478bd9Sstevel@tonic-gate 	}
6657c478bd9Sstevel@tonic-gate 	if (dma_count && (xdip != NULL)) {
6667c478bd9Sstevel@tonic-gate 		(void) ndi_prop_update_int_array(DDI_DEV_T_NONE, xdip,
6677c478bd9Sstevel@tonic-gate 		    "dma-channels", (int *)dma, dma_count);
6687c478bd9Sstevel@tonic-gate 	}
6697c478bd9Sstevel@tonic-gate 	AcpiOsFree(buf.Pointer);
6707c478bd9Sstevel@tonic-gate 	kmem_free(io, sizeof (struct regspec) * MAX_PARSED_ACPI_RESOURCES);
6717c478bd9Sstevel@tonic-gate 	return (status);
6727c478bd9Sstevel@tonic-gate }
6737c478bd9Sstevel@tonic-gate 
6747c478bd9Sstevel@tonic-gate /* keyboard mouse is under i8042, everything else under isa */
6757c478bd9Sstevel@tonic-gate 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)
6777c478bd9Sstevel@tonic-gate {
6787c478bd9Sstevel@tonic-gate 	static dev_info_t *i8042_dip = NULL;
6797c478bd9Sstevel@tonic-gate 	struct regspec i8042_regs[] = {
6807c478bd9Sstevel@tonic-gate 		{1, 0x60, 0x1},
6817c478bd9Sstevel@tonic-gate 		{1, 0x64, 0x1}
6827c478bd9Sstevel@tonic-gate 	};
6837c478bd9Sstevel@tonic-gate 	int i8042_intrs[] = {0x1, 0xc};
6847c478bd9Sstevel@tonic-gate 
685*d4039345SRichard Lowe 	if (strcmp(nodename, "keyboard") != 0 &&
686*d4039345SRichard Lowe 	    strcmp(nodename, "mouse") != 0)
6877c478bd9Sstevel@tonic-gate 		return (isa_dip);
6887c478bd9Sstevel@tonic-gate 
6897c478bd9Sstevel@tonic-gate 	if (i8042_dip)
6907c478bd9Sstevel@tonic-gate 		return (i8042_dip);
6917c478bd9Sstevel@tonic-gate 
692fa9e4066Sahrens 	ndi_devi_alloc_sleep(isa_dip, "i8042", (pnode_t)DEVI_SID_NODEID,
6937c478bd9Sstevel@tonic-gate 	    &i8042_dip);
6947c478bd9Sstevel@tonic-gate 	(void) ndi_prop_update_int_array(DDI_DEV_T_NONE, i8042_dip,
6957c478bd9Sstevel@tonic-gate 	    "reg", (int *)i8042_regs, 6);
6967c478bd9Sstevel@tonic-gate 	(void) ndi_prop_update_int_array(DDI_DEV_T_NONE, i8042_dip,
6977c478bd9Sstevel@tonic-gate 	    "interrupts", (int *)i8042_intrs, 2);
6987c478bd9Sstevel@tonic-gate 	(void) ndi_prop_update_string(DDI_DEV_T_NONE, i8042_dip,
6997c478bd9Sstevel@tonic-gate 	    "unit-address", "1,60");
7007c478bd9Sstevel@tonic-gate 	(void) ndi_devi_bind_driver(i8042_dip, 0);
7017c478bd9Sstevel@tonic-gate 	return (i8042_dip);
7027c478bd9Sstevel@tonic-gate }
7037c478bd9Sstevel@tonic-gate 
7047c478bd9Sstevel@tonic-gate void
eisa_to_str(ACPI_INTEGER id,char * np)7057c478bd9Sstevel@tonic-gate eisa_to_str(ACPI_INTEGER id, char *np)
7067c478bd9Sstevel@tonic-gate {
7077c478bd9Sstevel@tonic-gate 	static const char hextab[] = "0123456789ABCDEF";
7087c478bd9Sstevel@tonic-gate 
7097c478bd9Sstevel@tonic-gate 	/*
7107c478bd9Sstevel@tonic-gate 	 *  Expand an EISA device name:
7117c478bd9Sstevel@tonic-gate 	 *
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".
7147c478bd9Sstevel@tonic-gate 	 */
7157c478bd9Sstevel@tonic-gate 
7167c478bd9Sstevel@tonic-gate 	*np++ = '@' + ((id >> 2)  & 0x1F);
7177c478bd9Sstevel@tonic-gate 	*np++ = '@' + ((id << 3)  & 0x18) + ((id >> 13) & 0x07);
7187c478bd9Sstevel@tonic-gate 	*np++ = '@' + ((id >> 8)  & 0x1F);
7197c478bd9Sstevel@tonic-gate 	*np++ = hextab[(id >> 20) & 0x0F];
7207c478bd9Sstevel@tonic-gate 	*np++ = hextab[(id >> 16) & 0x0F];
7217c478bd9Sstevel@tonic-gate 	*np++ = hextab[(id >> 28) & 0x0F];
7227c478bd9Sstevel@tonic-gate 	*np++ = hextab[(id >> 24) & 0x0F];
7237c478bd9Sstevel@tonic-gate 	*np = 0;
7247c478bd9Sstevel@tonic-gate }
7257c478bd9Sstevel@tonic-gate 
7267c478bd9Sstevel@tonic-gate /*
7277c478bd9Sstevel@tonic-gate  * process_cids() -- process multiple CIDs in a package
7287c478bd9Sstevel@tonic-gate  */
7297c478bd9Sstevel@tonic-gate static void
process_cids(ACPI_OBJECT * rv,device_id_t ** dd)730aa2aa9a6SDana Myers process_cids(ACPI_OBJECT *rv, device_id_t **dd)
7317c478bd9Sstevel@tonic-gate {
732aa2aa9a6SDana Myers 	device_id_t *d;
733aa2aa9a6SDana Myers 	char tmp_cidstr[8];	/* 7-character EISA ID */
7347c478bd9Sstevel@tonic-gate 	int i;
7357c478bd9Sstevel@tonic-gate 
736aa2aa9a6SDana Myers 	if ((rv->Package.Count == 0) || rv->Package.Elements == NULL)
7377c478bd9Sstevel@tonic-gate 		return; /* empty package */
7387c478bd9Sstevel@tonic-gate 
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--) {
7447c478bd9Sstevel@tonic-gate 		/* get the actual acpi_object */
7457c478bd9Sstevel@tonic-gate 		ACPI_OBJECT obj = rv->Package.Elements[i];
7467c478bd9Sstevel@tonic-gate 		switch (obj.Type) {
7477c478bd9Sstevel@tonic-gate 		case ACPI_TYPE_INTEGER:
7487c478bd9Sstevel@tonic-gate 			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;
7537c478bd9Sstevel@tonic-gate 			break;
7547c478bd9Sstevel@tonic-gate 		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;
7597c478bd9Sstevel@tonic-gate 			break;
7607c478bd9Sstevel@tonic-gate 		default:
761ac0f75d7Sdchieu 			if (acpi_enum_debug & PROCESS_CIDS) {
7627b1019a6SJerry Jelinek 				cmn_err(CE_NOTE, "!unexpected CID type: %d",
763ac0f75d7Sdchieu 				    obj.Type);
764ac0f75d7Sdchieu 			}
7657c478bd9Sstevel@tonic-gate 			break;
7667c478bd9Sstevel@tonic-gate 		}
7677c478bd9Sstevel@tonic-gate 	}
768aa2aa9a6SDana Myers }
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;
8197c478bd9Sstevel@tonic-gate 	}
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 *));
8317c478bd9Sstevel@tonic-gate }
8327c478bd9Sstevel@tonic-gate 
8337c478bd9Sstevel@tonic-gate /*
8347c478bd9Sstevel@tonic-gate  * isa_acpi_callback()
8357c478bd9Sstevel@tonic-gate  */
8367c478bd9Sstevel@tonic-gate static ACPI_STATUS
isa_acpi_callback(ACPI_HANDLE ObjHandle,uint32_t NestingLevel,void * a,void ** b)8377c478bd9Sstevel@tonic-gate isa_acpi_callback(ACPI_HANDLE ObjHandle, uint32_t NestingLevel, void *a,
8387c478bd9Sstevel@tonic-gate     void **b)
8397c478bd9Sstevel@tonic-gate {
8407c478bd9Sstevel@tonic-gate 	_NOTE(ARGUNUSED(NestingLevel, b))
8417c478bd9Sstevel@tonic-gate 
842*d4039345SRichard Lowe 	ACPI_BUFFER		rb;
843*d4039345SRichard Lowe 	ACPI_DEVICE_INFO	*info = NULL;
844*d4039345SRichard Lowe 	char			*path = NULL;
845*d4039345SRichard Lowe 	char			*hidstr = NULL;
846*d4039345SRichard Lowe 	char			tmp_cidstr[8];	/* EISAID size */
847*d4039345SRichard Lowe 	dev_info_t		*dip = (dev_info_t *)a;
848*d4039345SRichard Lowe 	dev_info_t		*xdip = NULL;
849*d4039345SRichard Lowe 	device_id_t		*d, *device_ids = NULL;
850*d4039345SRichard Lowe 	const isapnp_desc_t	*m;
851*d4039345SRichard Lowe 	int			status;
8527c478bd9Sstevel@tonic-gate 
8537c478bd9Sstevel@tonic-gate 	/*
8547c478bd9Sstevel@tonic-gate 	 * get full ACPI pathname for object
8557c478bd9Sstevel@tonic-gate 	 */
8567c478bd9Sstevel@tonic-gate 	rb.Length = ACPI_ALLOCATE_BUFFER;
8577c478bd9Sstevel@tonic-gate 	rb.Pointer = NULL;
8587c478bd9Sstevel@tonic-gate 	if (AcpiGetName(ObjHandle, ACPI_FULL_PATHNAME, &rb) != AE_OK) {
8597c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "!acpi_enum: could not get pathname");
8607c478bd9Sstevel@tonic-gate 		goto done;
8617c478bd9Sstevel@tonic-gate 	}
8627c478bd9Sstevel@tonic-gate 	path = (char *)rb.Pointer;
8637c478bd9Sstevel@tonic-gate 
8647c478bd9Sstevel@tonic-gate 	/*
8657c478bd9Sstevel@tonic-gate 	 * Get device info object
8667c478bd9Sstevel@tonic-gate 	 */
86757190917SDana Myers 	if (AcpiGetObjectInfo(ObjHandle, &info) != AE_OK) {
8687c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "!acpi_enum: could not get device"
869a4a4d28eSSeth Goldberg 		    " info for %s", path);
8707c478bd9Sstevel@tonic-gate 		goto done;
8717c478bd9Sstevel@tonic-gate 	}
8727c478bd9Sstevel@tonic-gate 
8737c478bd9Sstevel@tonic-gate 	/*
8747c478bd9Sstevel@tonic-gate 	 * If device isn't present, we don't enumerate
8757c478bd9Sstevel@tonic-gate 	 * NEEDSWORK: what about docking bays and the like?
8767c478bd9Sstevel@tonic-gate 	 */
87735786f68SRobert Mustacchi 	if (ACPI_FAILURE(acpica_get_object_status(ObjHandle, &status))) {
8787c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "!acpi_enum: no _STA for %s", path);
8797c478bd9Sstevel@tonic-gate 		goto done;
8807c478bd9Sstevel@tonic-gate 	}
8817c478bd9Sstevel@tonic-gate 
88235786f68SRobert Mustacchi 	/*
88335786f68SRobert Mustacchi 	 * CA 6.3.6 _STA method
88435786f68SRobert Mustacchi 	 * Bit 0 -- device is present
88535786f68SRobert Mustacchi 	 * Bit 1 -- device is enabled
88635786f68SRobert Mustacchi 	 * Bit 2 -- device is shown in UI
88735786f68SRobert Mustacchi 	 */
88835786f68SRobert Mustacchi 	if ((status & 0x7) != 0x7) {
88935786f68SRobert Mustacchi 		if (acpi_enum_debug & DEVICES_NOT_ENUMED) {
89035786f68SRobert Mustacchi 			cmn_err(CE_NOTE, "!parse_resources() "
89135786f68SRobert Mustacchi 			    "Bad status 0x%x for %s",
89235786f68SRobert Mustacchi 			    status, path);
89335786f68SRobert Mustacchi 		}
89435786f68SRobert Mustacchi 		goto done;
89535786f68SRobert Mustacchi 	}
89635786f68SRobert Mustacchi 
8977c478bd9Sstevel@tonic-gate 	/*
8987c478bd9Sstevel@tonic-gate 	 * Keep track of _HID value
8997c478bd9Sstevel@tonic-gate 	 */
9007c478bd9Sstevel@tonic-gate 	if (!(info->Valid & ACPI_VALID_HID)) {
9017c478bd9Sstevel@tonic-gate 		/* 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 		}
9067c478bd9Sstevel@tonic-gate 		goto done;
9077c478bd9Sstevel@tonic-gate 	}
90857190917SDana Myers 	hidstr = info->HardwareId.String;
9097c478bd9Sstevel@tonic-gate 
9107c478bd9Sstevel@tonic-gate 	/*
9117c478bd9Sstevel@tonic-gate 	 * Attempt to get _CID value
9127c478bd9Sstevel@tonic-gate 	 */
9137c478bd9Sstevel@tonic-gate 	rb.Length = ACPI_ALLOCATE_BUFFER;
9147c478bd9Sstevel@tonic-gate 	rb.Pointer = NULL;
915db2bae30SDana Myers 	if (AcpiEvaluateObject(ObjHandle, "_CID", NULL, &rb) == AE_OK &&
916db2bae30SDana Myers 	    rb.Length != 0) {
9177c478bd9Sstevel@tonic-gate 		ACPI_OBJECT *rv = rb.Pointer;
9187c478bd9Sstevel@tonic-gate 
9197c478bd9Sstevel@tonic-gate 		switch (rv->Type) {
9207c478bd9Sstevel@tonic-gate 		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;
9267c478bd9Sstevel@tonic-gate 			break;
9277c478bd9Sstevel@tonic-gate 		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;
9327c478bd9Sstevel@tonic-gate 			break;
9337c478bd9Sstevel@tonic-gate 		case ACPI_TYPE_PACKAGE:
934aa2aa9a6SDana Myers 			process_cids(rv, &device_ids);
9357c478bd9Sstevel@tonic-gate 			break;
9367c478bd9Sstevel@tonic-gate 		default:
9377c478bd9Sstevel@tonic-gate 			break;
9387c478bd9Sstevel@tonic-gate 		}
9397c478bd9Sstevel@tonic-gate 		AcpiOsFree(rb.Pointer);
9407c478bd9Sstevel@tonic-gate 	}
9417c478bd9Sstevel@tonic-gate 
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;
9497c478bd9Sstevel@tonic-gate 
9507c478bd9Sstevel@tonic-gate 	/*
951*d4039345SRichard Lowe 	 * isapnp_desc_lookup() expects _HID first in device_ids
9527c478bd9Sstevel@tonic-gate 	 */
953*d4039345SRichard Lowe 	if ((m = isapnp_desc_lookup(device_ids)) !=  NULL) {
954*d4039345SRichard Lowe 		/* PNP description found in isapnp table */
9557c478bd9Sstevel@tonic-gate 		if (!(strncmp(hidstr, "ACPI", 4))) {
9567c478bd9Sstevel@tonic-gate 			dip = ddi_root_node();
9577c478bd9Sstevel@tonic-gate 		} else {
958*d4039345SRichard Lowe 			dip = get_bus_dip(m->ipnp_name, dip);
9597c478bd9Sstevel@tonic-gate 		}
960*d4039345SRichard Lowe 		ndi_devi_alloc_sleep(dip, m->ipnp_name,
961fa9e4066Sahrens 		    (pnode_t)DEVI_SID_NODEID, &xdip);
9627c478bd9Sstevel@tonic-gate 		(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) {
9667c478bd9Sstevel@tonic-gate 			(void) ndi_prop_update_string(DDI_DEV_T_NONE, xdip,
967*d4039345SRichard Lowe 			    "compatible", (char *)m->ipnp_compat);
9687c478bd9Sstevel@tonic-gate 		}
969*d4039345SRichard Lowe 	} else {
970*d4039345SRichard Lowe 		(void) parse_resources(ObjHandle, xdip, path);
971*d4039345SRichard Lowe 		goto done;
9727c478bd9Sstevel@tonic-gate 	}
973aa2aa9a6SDana Myers 
9747c478bd9Sstevel@tonic-gate 	(void) ndi_prop_update_string(DDI_DEV_T_NONE, xdip, "acpi-namespace",
9757c478bd9Sstevel@tonic-gate 	    path);
9767c478bd9Sstevel@tonic-gate 
97712f7d0bdSGary Mills 	(void) parse_resources(ObjHandle, xdip, path);
9787c478bd9Sstevel@tonic-gate 
9797c478bd9Sstevel@tonic-gate 	/* Special processing for mouse and keyboard devices per IEEE 1275 */
980*d4039345SRichard Lowe 	if (strcmp(m->ipnp_name, "keyboard") == 0) {
9817c478bd9Sstevel@tonic-gate 		(void) ndi_prop_update_int(DDI_DEV_T_NONE, xdip, "reg", 0);
9827c478bd9Sstevel@tonic-gate 		(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) {
9857c478bd9Sstevel@tonic-gate 		(void) ndi_prop_update_int(DDI_DEV_T_NONE, xdip, "reg", 1);
9867c478bd9Sstevel@tonic-gate 		(void) ndi_prop_update_string(DDI_DEV_T_NONE, xdip,
987*d4039345SRichard Lowe 		    "device-type", "mouse");
9887c478bd9Sstevel@tonic-gate 	}
9897c478bd9Sstevel@tonic-gate 
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);
996aa2aa9a6SDana Myers 
9977c478bd9Sstevel@tonic-gate 	(void) ndi_devi_bind_driver(xdip, 0);
9987c478bd9Sstevel@tonic-gate 
9997c478bd9Sstevel@tonic-gate 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 
10137c478bd9Sstevel@tonic-gate 	if (path != NULL)
10147c478bd9Sstevel@tonic-gate 		AcpiOsFree(path);
10157c478bd9Sstevel@tonic-gate 	if (info != NULL)
10167c478bd9Sstevel@tonic-gate 		AcpiOsFree(info);
10177c478bd9Sstevel@tonic-gate 
10187c478bd9Sstevel@tonic-gate 	return (AE_OK);
10197c478bd9Sstevel@tonic-gate }
10207c478bd9Sstevel@tonic-gate 
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 
10347c478bd9Sstevel@tonic-gate static void
used_res_interrupts(void)10357c478bd9Sstevel@tonic-gate used_res_interrupts(void)
10367c478bd9Sstevel@tonic-gate {
10371f9b2f1bSJason King 	if (used_interrupts.i_num == 0)
10381f9b2f1bSJason King 		return;
10391f9b2f1bSJason King 
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);
10507c478bd9Sstevel@tonic-gate 
10517c478bd9Sstevel@tonic-gate 	(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));
10577c478bd9Sstevel@tonic-gate }
10587c478bd9Sstevel@tonic-gate 
10597c478bd9Sstevel@tonic-gate static void
used_res_dmas(void)10607c478bd9Sstevel@tonic-gate used_res_dmas(void)
10617c478bd9Sstevel@tonic-gate {
10627c478bd9Sstevel@tonic-gate 	int dma[ACPI_ISA_LIMIT];
10637c478bd9Sstevel@tonic-gate 	int count = 0;
10647c478bd9Sstevel@tonic-gate 	int i;
10657c478bd9Sstevel@tonic-gate 
10667c478bd9Sstevel@tonic-gate 	for (i = 0; i < ACPI_ISA_LIMIT; i++) {
10677c478bd9Sstevel@tonic-gate 		if ((used_dmas >> i) & 1) {
10687c478bd9Sstevel@tonic-gate 			dma[count++] = i;
10697c478bd9Sstevel@tonic-gate 		}
10707c478bd9Sstevel@tonic-gate 	}
10717c478bd9Sstevel@tonic-gate 	(void) ndi_prop_update_int_array(DDI_DEV_T_NONE, usedrdip,
10727c478bd9Sstevel@tonic-gate 	    "dma-channels", (int *)dma, count);
10737c478bd9Sstevel@tonic-gate }
10747c478bd9Sstevel@tonic-gate 
10757c478bd9Sstevel@tonic-gate static void
used_res_io_mem(char * nodename,int * count,used_io_mem_t ** head)10767c478bd9Sstevel@tonic-gate used_res_io_mem(char *nodename, int *count, used_io_mem_t **head)
10777c478bd9Sstevel@tonic-gate {
10787c478bd9Sstevel@tonic-gate 	int *io;
10797c478bd9Sstevel@tonic-gate 	used_io_mem_t *used = *head;
10807c478bd9Sstevel@tonic-gate 	int i;
10817c478bd9Sstevel@tonic-gate 
10827c478bd9Sstevel@tonic-gate 	*count *= 2;
1083*d4039345SRichard Lowe 	io = kmem_zalloc(sizeof (int)*(*count), KM_SLEEP);
10847c478bd9Sstevel@tonic-gate 	for (i = 0; i < *count; i += 2) {
10857c478bd9Sstevel@tonic-gate 		used_io_mem_t *prev;
10867c478bd9Sstevel@tonic-gate 		if (used != NULL) {
10877c478bd9Sstevel@tonic-gate 			io[i] = used->start_addr;
10887c478bd9Sstevel@tonic-gate 			io[i+1] = used->length;
10897c478bd9Sstevel@tonic-gate 			prev = used;
10907c478bd9Sstevel@tonic-gate 			used = used->next;
10917c478bd9Sstevel@tonic-gate 			kmem_free(prev, sizeof (used_io_mem_t));
10927c478bd9Sstevel@tonic-gate 		}
10937c478bd9Sstevel@tonic-gate 	}
10947c478bd9Sstevel@tonic-gate 	(void) ndi_prop_update_int_array(DDI_DEV_T_NONE, usedrdip,
10957c478bd9Sstevel@tonic-gate 	    nodename, (int *)io, *count);
1096*d4039345SRichard Lowe 	kmem_free(io, sizeof (int) * (*count));
10977c478bd9Sstevel@tonic-gate 	*head = NULL;
10987c478bd9Sstevel@tonic-gate }
10997c478bd9Sstevel@tonic-gate 
11007c478bd9Sstevel@tonic-gate /*
11017c478bd9Sstevel@tonic-gate  * acpi_isa_device_enum() -- call from isa nexus driver
11027c478bd9Sstevel@tonic-gate  * returns 1 if deviced enumeration is successful
11037c478bd9Sstevel@tonic-gate  *         0 if deviced enumeration fails
11047c478bd9Sstevel@tonic-gate  */
11057c478bd9Sstevel@tonic-gate int
acpi_isa_device_enum(dev_info_t * isa_dip)11067c478bd9Sstevel@tonic-gate acpi_isa_device_enum(dev_info_t *isa_dip)
11077c478bd9Sstevel@tonic-gate {
11087c478bd9Sstevel@tonic-gate 	char *acpi_prop;
11097c478bd9Sstevel@tonic-gate 
11107c478bd9Sstevel@tonic-gate 	if (ddi_prop_lookup_string(DDI_DEV_T_ANY, ddi_root_node(),
1111*d4039345SRichard Lowe 	    DDI_PROP_DONTPASS, "acpi_enum_debug", &acpi_prop) ==
11127c478bd9Sstevel@tonic-gate 	    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;
11167c478bd9Sstevel@tonic-gate 			e_ddi_prop_remove(DDI_DEV_T_NONE, ddi_root_node(),
1117*d4039345SRichard Lowe 			    "acpi_enum_debug");
1118f7534bc1Ssmall 			e_ddi_prop_update_int(DDI_DEV_T_NONE,
1119*d4039345SRichard Lowe 			    ddi_root_node(), "acpi_enum_debug", data);
11207c478bd9Sstevel@tonic-gate 		}
11217c478bd9Sstevel@tonic-gate 		ddi_prop_free(acpi_prop);
11227c478bd9Sstevel@tonic-gate 	}
11237c478bd9Sstevel@tonic-gate 
11247c478bd9Sstevel@tonic-gate 	if (acpi_enum_debug & ISA_DEVICE_ENUM) {
11257b1019a6SJerry Jelinek 		cmn_err(CE_NOTE, "!acpi_isa_device_enum() called");
11267c478bd9Sstevel@tonic-gate 	}
11277c478bd9Sstevel@tonic-gate 
11287c478bd9Sstevel@tonic-gate 	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 		 */
1137f7534bc1Ssmall 		(void) e_ddi_prop_update_string(DDI_DEV_T_NONE,
11387c478bd9Sstevel@tonic-gate 		    ddi_root_node(), "acpi-enum", "off");
11397c478bd9Sstevel@tonic-gate 		return (0);
11407c478bd9Sstevel@tonic-gate 	}
11417c478bd9Sstevel@tonic-gate 
1142*d4039345SRichard Lowe 	usedrdip = ddi_find_devinfo("used-resources", -1, 0);
11437c478bd9Sstevel@tonic-gate 	if (usedrdip == NULL) {
1144*d4039345SRichard Lowe 		ndi_devi_alloc_sleep(ddi_root_node(), "used-resources",
1145fa9e4066Sahrens 		    (pnode_t)DEVI_SID_NODEID, &usedrdip);
11467c478bd9Sstevel@tonic-gate 
11477c478bd9Sstevel@tonic-gate 	}
11487c478bd9Sstevel@tonic-gate 
11497c478bd9Sstevel@tonic-gate 	/*
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.
11537c478bd9Sstevel@tonic-gate 	 */
115412f7d0bdSGary Mills 	(void) AcpiWalkNamespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
115512f7d0bdSGary Mills 	    UINT32_MAX, isa_acpi_callback, NULL, isa_dip, NULL);
11567c478bd9Sstevel@tonic-gate 
11577c478bd9Sstevel@tonic-gate 	used_res_interrupts();
11587c478bd9Sstevel@tonic-gate 	used_res_dmas();
11597c478bd9Sstevel@tonic-gate 	used_res_io_mem("device-memory", &used_mem_count, &used_mem_head);
11607c478bd9Sstevel@tonic-gate 	used_res_io_mem("io-space", &used_io_count, &used_io_head);
11617c478bd9Sstevel@tonic-gate 	(void) ndi_devi_bind_driver(usedrdip, 0);
11627c478bd9Sstevel@tonic-gate 
11637c478bd9Sstevel@tonic-gate 	return (1);
11647c478bd9Sstevel@tonic-gate }
1165