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