4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright 2018, Joyent, Inc.
23 * Copyright (c) 2012 Gary Mills
25 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
26 * Use is subject to license terms.
34 #include <sys/sunddi.h>
35 #include <sys/sunndi.h>
37 #include <sys/acpi/acpi.h>
38 #include <sys/acpica.h>
39 #include <util/sscanf.h>
42 static char keyboard_alias
[] = "keyboard";
43 static char mouse_alias
[] = "mouse";
44 #define ACPI_ENUM_DEBUG "acpi_enum_debug"
45 #define PARSE_RESOURCES_DEBUG 0x0001
46 #define MASTER_LOOKUP_DEBUG 0x0002
47 #define DEVICES_NOT_ENUMED 0x0004
48 #define PARSE_RES_IRQ 0x0008
49 #define PARSE_RES_DMA 0x0010
50 #define PARSE_RES_MEMORY 0x0020
51 #define PARSE_RES_IO 0x0040
52 #define PARSE_RES_ADDRESS 0x0080
53 #define ISA_DEVICE_ENUM 0x1000
54 #define PROCESS_CIDS 0x2000
55 static unsigned long acpi_enum_debug
= 0x00;
57 static char USED_RESOURCES
[] = "used-resources";
58 static dev_info_t
*usedrdip
= NULL
;
59 static unsigned short used_interrupts
= 0;
60 static unsigned short used_dmas
= 0;
61 typedef struct used_io_mem
{
62 unsigned int start_addr
;
64 struct used_io_mem
*next
;
66 static used_io_mem_t
*used_io_head
= NULL
;
67 static used_io_mem_t
*used_mem_head
= NULL
;
68 static int used_io_count
= 0;
69 static int used_mem_count
= 0;
71 #define MAX_PARSED_ACPI_RESOURCES 255
72 #define ACPI_ISA_LIMIT 16
73 static int interrupt
[ACPI_ISA_LIMIT
], dma
[ACPI_ISA_LIMIT
];
74 #define ACPI_ELEMENT_PACKAGE_LIMIT 32
75 #define EISA_ID_SIZE 7
78 * insert used io/mem in increasing order
81 insert_used_resource(used_io_mem_t
*used
, int *used_count
, used_io_mem_t
**head
)
83 used_io_mem_t
*curr
, *prev
;
91 /* find a place to insert */
92 while ((curr
!= NULL
) &&
93 (curr
->start_addr
< used
->start_addr
)) {
109 add_used_io_mem(struct regspec
*io
, int io_count
)
114 for (i
= 0; i
< io_count
; i
++) {
115 used
= (used_io_mem_t
*)kmem_zalloc(sizeof (used_io_mem_t
),
117 used
->start_addr
= io
[i
].regspec_addr
;
118 used
->length
= io
[i
].regspec_size
;
119 if (io
[i
].regspec_bustype
== 1) {
120 insert_used_resource(used
, &used_io_count
,
123 insert_used_resource(used
, &used_mem_count
,
130 parse_resources_irq(ACPI_RESOURCE
*resource_ptr
, int *interrupt_count
)
134 for (i
= 0; i
< resource_ptr
->Data
.Irq
.InterruptCount
; i
++) {
135 interrupt
[(*interrupt_count
)++] =
136 resource_ptr
->Data
.Irq
.Interrupts
[i
];
137 used_interrupts
|= 1 << resource_ptr
->Data
.Irq
.Interrupts
[i
];
138 if (acpi_enum_debug
& PARSE_RES_IRQ
) {
139 cmn_err(CE_NOTE
, "!parse_resources() "\
140 "IRQ num %u, intr # = %u",
141 i
, resource_ptr
->Data
.Irq
.Interrupts
[i
]);
147 parse_resources_dma(ACPI_RESOURCE
*resource_ptr
, int *dma_count
)
151 for (i
= 0; i
< resource_ptr
->Data
.Dma
.ChannelCount
; i
++) {
152 dma
[(*dma_count
)++] = resource_ptr
->Data
.Dma
.Channels
[i
];
153 used_dmas
|= 1 << resource_ptr
->Data
.Dma
.Channels
[i
];
154 if (acpi_enum_debug
& PARSE_RES_DMA
) {
155 cmn_err(CE_NOTE
, "!parse_resources() "\
156 "DMA num %u, channel # = %u",
157 i
, resource_ptr
->Data
.Dma
.Channels
[i
]);
163 parse_resources_io(ACPI_RESOURCE
*resource_ptr
, struct regspec
*io
,
166 ACPI_RESOURCE_IO acpi_io
= resource_ptr
->Data
.Io
;
168 if (acpi_io
.AddressLength
== 0)
171 io
[*io_count
].regspec_bustype
= 1; /* io */
172 io
[*io_count
].regspec_size
= acpi_io
.AddressLength
;
173 io
[*io_count
].regspec_addr
= acpi_io
.Minimum
;
174 if (acpi_enum_debug
& PARSE_RES_IO
) {
175 cmn_err(CE_NOTE
, "!parse_resources() "\
176 "IO min 0x%X, max 0x%X, length: 0x%X",
179 acpi_io
.AddressLength
);
185 parse_resources_fixed_io(ACPI_RESOURCE
*resource_ptr
, struct regspec
*io
,
188 ACPI_RESOURCE_FIXED_IO fixed_io
= resource_ptr
->Data
.FixedIo
;
190 if (fixed_io
.AddressLength
== 0)
193 io
[*io_count
].regspec_bustype
= 1; /* io */
194 io
[*io_count
].regspec_addr
= fixed_io
.Address
;
195 io
[*io_count
].regspec_size
= fixed_io
.AddressLength
;
196 if (acpi_enum_debug
& PARSE_RES_IO
) {
197 cmn_err(CE_NOTE
, "!parse_resources() "\
198 "Fixed IO 0x%X, length: 0x%X",
199 fixed_io
.Address
, fixed_io
.AddressLength
);
205 parse_resources_fixed_mem32(ACPI_RESOURCE
*resource_ptr
, struct regspec
*io
,
208 ACPI_RESOURCE_FIXED_MEMORY32 fixed_mem32
=
209 resource_ptr
->Data
.FixedMemory32
;
211 if (fixed_mem32
.AddressLength
== 0)
214 io
[*io_count
].regspec_bustype
= 0; /* memory */
215 io
[*io_count
].regspec_addr
= fixed_mem32
.Address
;
216 io
[*io_count
].regspec_size
= fixed_mem32
.AddressLength
;
217 if (acpi_enum_debug
& PARSE_RES_MEMORY
) {
218 cmn_err(CE_NOTE
, "!parse_resources() "\
219 "Fixed Mem 32 %ul, length: %ul",
220 fixed_mem32
.Address
, fixed_mem32
.AddressLength
);
226 parse_resources_mem32(ACPI_RESOURCE
*resource_ptr
, struct regspec
*io
,
229 ACPI_RESOURCE_MEMORY32 mem32
= resource_ptr
->Data
.Memory32
;
231 if (mem32
.AddressLength
== 0)
234 if (resource_ptr
->Data
.Memory32
.Minimum
==
235 resource_ptr
->Data
.Memory32
.Maximum
) {
236 io
[*io_count
].regspec_bustype
= 0; /* memory */
237 io
[*io_count
].regspec_addr
= mem32
.Minimum
;
238 io
[*io_count
].regspec_size
= mem32
.AddressLength
;
240 if (acpi_enum_debug
& PARSE_RES_MEMORY
) {
241 cmn_err(CE_NOTE
, "!parse_resources() "\
242 "Mem 32 0x%X, length: 0x%X",
243 mem32
.Minimum
, mem32
.AddressLength
);
247 if (acpi_enum_debug
& PARSE_RES_MEMORY
) {
248 cmn_err(CE_NOTE
, "!parse_resources() "\
249 "MEM32 Min Max not equal!");
250 cmn_err(CE_NOTE
, "!parse_resources() "\
251 "Mem 32 Minimum 0x%X, Maximum: 0x%X",
252 mem32
.Minimum
, mem32
.Maximum
);
257 parse_resources_addr16(ACPI_RESOURCE
*resource_ptr
, struct regspec
*io
,
260 ACPI_RESOURCE_ADDRESS16 addr16
=
261 resource_ptr
->Data
.Address16
;
263 if (addr16
.Address
.AddressLength
== 0)
266 if (acpi_enum_debug
& PARSE_RES_ADDRESS
) {
267 if (addr16
.ResourceType
== ACPI_MEMORY_RANGE
) {
268 cmn_err(CE_NOTE
, "!parse_resources() "\
269 "ADDRESS 16 MEMORY RANGE");
271 if (addr16
.ResourceType
== ACPI_IO_RANGE
) {
272 cmn_err(CE_NOTE
, "!parse_resources() "\
273 "ADDRESS 16 IO RANGE");
275 cmn_err(CE_NOTE
, "!parse_resources() "\
278 cmn_err(CE_NOTE
, "!parse_resources() "\
280 "MinAddressFixed 0x%X, "\
281 "MaxAddressFixed 0x%X, "\
285 addr16
.ProducerConsumer
== ACPI_CONSUMER
?
286 "CONSUMER" : "PRODUCER",
287 addr16
.MinAddressFixed
,
288 addr16
.MaxAddressFixed
,
289 addr16
.Address
.Minimum
,
290 addr16
.Address
.Maximum
,
291 addr16
.Address
.AddressLength
);
293 if (addr16
.ProducerConsumer
== ACPI_PRODUCER
||
294 (addr16
.ResourceType
!= ACPI_MEMORY_RANGE
&&
295 addr16
.ResourceType
!= ACPI_IO_RANGE
)) {
298 if (addr16
.Address
.AddressLength
> 0) {
299 if (addr16
.ResourceType
== ACPI_MEMORY_RANGE
) {
301 io
[*io_count
].regspec_bustype
= 0;
304 io
[*io_count
].regspec_bustype
= 1;
306 io
[*io_count
].regspec_addr
= addr16
.Address
.Minimum
;
307 io
[*io_count
].regspec_size
= addr16
.Address
.AddressLength
;
313 parse_resources_addr32(ACPI_RESOURCE
*resource_ptr
, struct regspec
*io
,
316 ACPI_RESOURCE_ADDRESS32 addr32
=
317 resource_ptr
->Data
.Address32
;
319 if (addr32
.Address
.AddressLength
== 0)
322 if (acpi_enum_debug
& PARSE_RES_ADDRESS
) {
323 if (addr32
.ResourceType
== ACPI_MEMORY_RANGE
) {
324 cmn_err(CE_NOTE
, "!parse_resources() "\
325 "ADDRESS 32 MEMORY RANGE");
327 if (addr32
.ResourceType
== ACPI_IO_RANGE
) {
328 cmn_err(CE_NOTE
, "!parse_resources() "\
329 "ADDRESS 32 IO RANGE");
331 cmn_err(CE_NOTE
, "!parse_resources() "\
334 cmn_err(CE_NOTE
, "!parse_resources() "\
336 "MinAddressFixed 0x%X, "\
337 "MaxAddressFixed 0x%X, "\
341 addr32
.ProducerConsumer
== ACPI_CONSUMER
?
342 "CONSUMER" : "PRODUCER",
343 addr32
.MinAddressFixed
,
344 addr32
.MaxAddressFixed
,
345 addr32
.Address
.Minimum
,
346 addr32
.Address
.Maximum
,
347 addr32
.Address
.AddressLength
);
349 if (addr32
.ProducerConsumer
== ACPI_PRODUCER
||
350 (addr32
.ResourceType
!= ACPI_MEMORY_RANGE
&&
351 addr32
.ResourceType
!= ACPI_IO_RANGE
)) {
354 if (addr32
.Address
.AddressLength
> 0) {
355 if (addr32
.ResourceType
== ACPI_MEMORY_RANGE
) {
357 io
[*io_count
].regspec_bustype
= 0;
360 io
[*io_count
].regspec_bustype
= 1;
362 io
[*io_count
].regspec_addr
= addr32
.Address
.Minimum
;
363 io
[*io_count
].regspec_size
= addr32
.Address
.AddressLength
;
369 parse_resources_addr64(ACPI_RESOURCE
*resource_ptr
, struct regspec
*io
,
372 ACPI_RESOURCE_ADDRESS64 addr64
=
373 resource_ptr
->Data
.Address64
;
375 if (addr64
.Address
.AddressLength
== 0)
378 if (acpi_enum_debug
& PARSE_RES_ADDRESS
) {
379 if (addr64
.ResourceType
== ACPI_MEMORY_RANGE
) {
380 cmn_err(CE_NOTE
, "!parse_resources() "\
381 "ADDRESS 64 MEMORY RANGE");
383 if (addr64
.ResourceType
== ACPI_IO_RANGE
) {
384 cmn_err(CE_NOTE
, "!parse_resources() "\
385 "ADDRESS 64 IO RANGE");
387 cmn_err(CE_NOTE
, "!parse_resources() "\
390 cmn_err(CE_NOTE
, "!parse_resources() "\
392 "MinAddressFixed 0x%X, "\
393 "MaxAddressFixed 0x%X, "\
397 addr64
.ProducerConsumer
== ACPI_CONSUMER
?
398 "CONSUMER" : "PRODUCER",
399 addr64
.MinAddressFixed
,
400 addr64
.MaxAddressFixed
,
401 addr64
.Address
.Minimum
,
402 addr64
.Address
.Maximum
,
403 addr64
.Address
.AddressLength
);
405 if (addr64
.ProducerConsumer
== ACPI_PRODUCER
||
406 (addr64
.ResourceType
!= ACPI_MEMORY_RANGE
&&
407 addr64
.ResourceType
!= ACPI_IO_RANGE
)) {
410 if (addr64
.Address
.AddressLength
> 0) {
411 if (addr64
.ResourceType
== ACPI_MEMORY_RANGE
) {
413 io
[*io_count
].regspec_bustype
= 0;
416 io
[*io_count
].regspec_bustype
= 1;
418 io
[*io_count
].regspec_addr
= addr64
.Address
.Minimum
;
419 io
[*io_count
].regspec_size
= addr64
.Address
.AddressLength
;
425 parse_resources(ACPI_HANDLE handle
, dev_info_t
*xdip
, char *path
)
428 ACPI_RESOURCE
*resource_ptr
;
430 char *current_ptr
, *last_ptr
;
432 int io_count
= 0, interrupt_count
= 0, dma_count
= 0;
435 buf
.Length
= ACPI_ALLOCATE_BUFFER
;
436 status
= AcpiGetCurrentResources(handle
, &buf
);
442 * Workaround for faulty DSDT tables that omit the _CRS
443 * method for the UAR3 device but have a valid _PRS method
446 status
= AcpiGetPossibleResources(handle
, &buf
);
447 if (status
!= AE_OK
) {
453 "!AcpiGetCurrentResources failed for %s, exception: %s",
454 path
, AcpiFormatException(status
));
458 io
= kmem_zalloc(sizeof (struct regspec
) *
459 MAX_PARSED_ACPI_RESOURCES
, KM_SLEEP
);
460 current_ptr
= buf
.Pointer
;
461 last_ptr
= (char *)buf
.Pointer
+ buf
.Length
;
462 while (current_ptr
< last_ptr
) {
463 if (io_count
>= MAX_PARSED_ACPI_RESOURCES
) {
466 resource_ptr
= (ACPI_RESOURCE
*)current_ptr
;
467 current_ptr
+= resource_ptr
->Length
;
468 switch (resource_ptr
->Type
) {
469 case ACPI_RESOURCE_TYPE_END_TAG
:
470 current_ptr
= last_ptr
;
472 case ACPI_RESOURCE_TYPE_IO
:
473 parse_resources_io(resource_ptr
, io
, &io_count
);
475 case ACPI_RESOURCE_TYPE_FIXED_IO
:
476 parse_resources_fixed_io(resource_ptr
, io
, &io_count
);
478 case ACPI_RESOURCE_TYPE_FIXED_MEMORY32
:
479 parse_resources_fixed_mem32(resource_ptr
, io
,
482 case ACPI_RESOURCE_TYPE_MEMORY32
:
483 parse_resources_mem32(resource_ptr
, io
, &io_count
);
485 case ACPI_RESOURCE_TYPE_ADDRESS16
:
486 parse_resources_addr16(resource_ptr
, io
, &io_count
);
488 case ACPI_RESOURCE_TYPE_ADDRESS32
:
489 parse_resources_addr32(resource_ptr
, io
, &io_count
);
491 case ACPI_RESOURCE_TYPE_ADDRESS64
:
492 parse_resources_addr64(resource_ptr
, io
, &io_count
);
494 case ACPI_RESOURCE_TYPE_IRQ
:
495 parse_resources_irq(resource_ptr
, &interrupt_count
);
497 case ACPI_RESOURCE_TYPE_DMA
:
498 parse_resources_dma(resource_ptr
, &dma_count
);
500 case ACPI_RESOURCE_TYPE_START_DEPENDENT
:
503 " ACPI_RESOURCE_TYPE_START_DEPENDENT"
506 case ACPI_RESOURCE_TYPE_END_DEPENDENT
:
509 " ACPI_RESOURCE_TYPE_END_DEPENDENT"
512 case ACPI_RESOURCE_TYPE_VENDOR
:
515 " ACPI_RESOURCE_TYPE_VENDOR"
518 case ACPI_RESOURCE_TYPE_MEMORY24
:
521 " ACPI_RESOURCE_TYPE_MEMORY24"
524 case ACPI_RESOURCE_TYPE_EXTENDED_IRQ
:
527 " ACPI_RESOURCE_TYPE_EXT_IRQ"
531 /* Some types are not yet implemented (See CA 6.4) */
533 "!ACPI resource type (0X%X) not yet supported",
541 * on LX50, you get interrupts of mouse and keyboard
542 * from separate PNP id...
545 if ((io
[0].regspec_addr
== 0x60 &&
546 io
[1].regspec_addr
== 0x64) ||
547 (io
[0].regspec_addr
== 0x64 &&
548 io
[1].regspec_addr
== 0x60)) {
558 add_used_io_mem(io
, io_count
);
560 (void) ndi_prop_update_int_array(DDI_DEV_T_NONE
, xdip
,
561 "reg", (int *)io
, 3*io_count
);
564 if (interrupt_count
&& (xdip
!= NULL
)) {
565 (void) ndi_prop_update_int_array(DDI_DEV_T_NONE
, xdip
,
566 "interrupts", (int *)interrupt
, interrupt_count
);
568 if (dma_count
&& (xdip
!= NULL
)) {
569 (void) ndi_prop_update_int_array(DDI_DEV_T_NONE
, xdip
,
570 "dma-channels", (int *)dma
, dma_count
);
572 AcpiOsFree(buf
.Pointer
);
573 kmem_free(io
, sizeof (struct regspec
) * MAX_PARSED_ACPI_RESOURCES
);
577 /* keyboard mouse is under i8042, everything else under isa */
579 get_bus_dip(char *nodename
, dev_info_t
*isa_dip
)
581 static dev_info_t
*i8042_dip
= NULL
;
582 struct regspec i8042_regs
[] = {
586 int i8042_intrs
[] = {0x1, 0xc};
588 if (strcmp(nodename
, keyboard_alias
) != 0 &&
589 strcmp(nodename
, mouse_alias
) != 0)
595 ndi_devi_alloc_sleep(isa_dip
, "i8042", (pnode_t
)DEVI_SID_NODEID
,
597 (void) ndi_prop_update_int_array(DDI_DEV_T_NONE
, i8042_dip
,
598 "reg", (int *)i8042_regs
, 6);
599 (void) ndi_prop_update_int_array(DDI_DEV_T_NONE
, i8042_dip
,
600 "interrupts", (int *)i8042_intrs
, 2);
601 (void) ndi_prop_update_string(DDI_DEV_T_NONE
, i8042_dip
,
602 "unit-address", "1,60");
603 (void) ndi_devi_bind_driver(i8042_dip
, 0);
608 * put content of properties (if any) to dev info tree at branch xdip
609 * return non-zero if a "compatible" property was processed, zero otherwise
613 process_properties(dev_info_t
*xdip
, property_t
*properties
)
617 while (properties
!= NULL
) {
618 (void) ndi_prop_update_string(DDI_DEV_T_NONE
, xdip
,
619 properties
->name
, properties
->value
);
620 if (strcmp(properties
->name
, "compatible") == 0)
622 properties
= properties
->next
;
629 eisa_to_str(ACPI_INTEGER id
, char *np
)
631 static const char hextab
[] = "0123456789ABCDEF";
634 * Expand an EISA device name:
636 * This routine converts a 32-bit EISA device "id" to a
637 * 7-byte ASCII device name, which is stored at "np".
640 *np
++ = '@' + ((id
>> 2) & 0x1F);
641 *np
++ = '@' + ((id
<< 3) & 0x18) + ((id
>> 13) & 0x07);
642 *np
++ = '@' + ((id
>> 8) & 0x1F);
643 *np
++ = hextab
[(id
>> 20) & 0x0F];
644 *np
++ = hextab
[(id
>> 16) & 0x0F];
645 *np
++ = hextab
[(id
>> 28) & 0x0F];
646 *np
++ = hextab
[(id
>> 24) & 0x0F];
651 * process_cids() -- process multiple CIDs in a package
654 process_cids(ACPI_OBJECT
*rv
, device_id_t
**dd
)
657 char tmp_cidstr
[8]; /* 7-character EISA ID */
660 if ((rv
->Package
.Count
== 0) || rv
->Package
.Elements
== NULL
)
661 return; /* empty package */
664 * Work the package 'backwards' so the resulting list is
665 * in original order of preference.
667 for (i
= rv
->Package
.Count
- 1; i
>= 0; i
--) {
668 /* get the actual acpi_object */
669 ACPI_OBJECT obj
= rv
->Package
.Elements
[i
];
671 case ACPI_TYPE_INTEGER
:
672 eisa_to_str(obj
.Integer
.Value
, tmp_cidstr
);
673 d
= mf_alloc_device_id();
674 d
->id
= strdup(tmp_cidstr
);
678 case ACPI_TYPE_STRING
:
679 d
= mf_alloc_device_id();
680 d
->id
= strdup(obj
.String
.Pointer
);
685 if (acpi_enum_debug
& PROCESS_CIDS
) {
686 cmn_err(CE_NOTE
, "!unexpected CID type: %d",
695 * Convert "raw" PNP and ACPI IDs to IEEE 1275-compliant form.
696 * Some liberty is taken here, treating "ACPI" as a special form
697 * of PNP vendor ID. strsize specifies size of buffer.
700 convert_to_pnp1275(char *pnpid
, char *str
, int strsize
)
705 if (strncmp(pnpid
, "ACPI", 4) == 0) {
706 /* Assume ACPI ID: ACPIxxxx */
707 sscanf(pnpid
, "%4s%x", vendor
, &id
);
709 /* Assume PNP ID: aaaxxxx */
710 sscanf(pnpid
, "%3s%x", vendor
, &id
);
713 snprintf(str
, strsize
, "pnp%s,%x", vendor
, id
);
717 * Given a list of device ID elements in most-to-least-specific
718 * order, create a "compatible" property.
721 create_compatible_property(dev_info_t
*dip
, device_id_t
*ids
)
727 /* count list length */
735 /* create string array */
736 strs
= (char **)kmem_zalloc(list_len
* sizeof (char *), KM_SLEEP
);
740 /* strlen("pnpXXXX,xxxx") + 1 = 13 */
741 strs
[i
] = kmem_zalloc(13, KM_SLEEP
);
742 convert_to_pnp1275(d
->id
, strs
[i
++], 13);
746 /* update property */
747 (void) ndi_prop_update_string_array(DDI_DEV_T_NONE
, dip
,
748 "compatible", strs
, list_len
);
752 for (i
= 0; i
< list_len
; i
++)
753 kmem_free(strs
[i
], 13);
755 kmem_free(strs
, list_len
* sizeof (char *));
759 * isa_acpi_callback()
762 isa_acpi_callback(ACPI_HANDLE ObjHandle
, uint32_t NestingLevel
, void *a
,
765 _NOTE(ARGUNUSED(NestingLevel
, b
))
768 ACPI_DEVICE_INFO
*info
= NULL
;
771 char tmp_cidstr
[8]; /* EISAID size */
772 dev_info_t
*dip
= (dev_info_t
*)a
;
773 dev_info_t
*xdip
= NULL
;
774 device_id_t
*d
, *device_ids
= NULL
;
775 const master_rec_t
*m
;
776 int compatible_present
= 0;
780 * get full ACPI pathname for object
782 rb
.Length
= ACPI_ALLOCATE_BUFFER
;
784 if (AcpiGetName(ObjHandle
, ACPI_FULL_PATHNAME
, &rb
) != AE_OK
) {
785 cmn_err(CE_WARN
, "!acpi_enum: could not get pathname");
788 path
= (char *)rb
.Pointer
;
791 * Get device info object
793 if (AcpiGetObjectInfo(ObjHandle
, &info
) != AE_OK
) {
794 cmn_err(CE_WARN
, "!acpi_enum: could not get device"
795 " info for %s", path
);
800 * If device isn't present, we don't enumerate
801 * NEEDSWORK: what about docking bays and the like?
803 if (ACPI_FAILURE(acpica_get_object_status(ObjHandle
, &status
))) {
804 cmn_err(CE_WARN
, "!acpi_enum: no _STA for %s", path
);
809 * CA 6.3.6 _STA method
810 * Bit 0 -- device is present
811 * Bit 1 -- device is enabled
812 * Bit 2 -- device is shown in UI
814 if ((status
& 0x7) != 0x7) {
815 if (acpi_enum_debug
& DEVICES_NOT_ENUMED
) {
816 cmn_err(CE_NOTE
, "!parse_resources() "
817 "Bad status 0x%x for %s",
824 * Keep track of _HID value
826 if (!(info
->Valid
& ACPI_VALID_HID
)) {
827 /* No _HID, we skip this node */
828 if (acpi_enum_debug
& DEVICES_NOT_ENUMED
) {
829 cmn_err(CE_NOTE
, "!parse_resources() "
830 "No _HID for %s", path
);
834 hidstr
= info
->HardwareId
.String
;
837 * Attempt to get _CID value
839 rb
.Length
= ACPI_ALLOCATE_BUFFER
;
841 if (AcpiEvaluateObject(ObjHandle
, "_CID", NULL
, &rb
) == AE_OK
&&
843 ACPI_OBJECT
*rv
= rb
.Pointer
;
846 case ACPI_TYPE_INTEGER
:
847 eisa_to_str(rv
->Integer
.Value
, tmp_cidstr
);
848 d
= mf_alloc_device_id();
849 d
->id
= strdup(tmp_cidstr
);
850 d
->next
= device_ids
;
853 case ACPI_TYPE_STRING
:
854 d
= mf_alloc_device_id();
855 d
->id
= strdup(rv
->String
.Pointer
);
856 d
->next
= device_ids
;
859 case ACPI_TYPE_PACKAGE
:
860 process_cids(rv
, &device_ids
);
865 AcpiOsFree(rb
.Pointer
);
869 * Add _HID last so it's at the head of the list
871 d
= mf_alloc_device_id();
872 d
->id
= strdup(hidstr
);
873 d
->next
= device_ids
;
877 * master_file_lookup() expects _HID first in device_ids
879 if ((m
= master_file_lookup(device_ids
)) != NULL
) {
880 /* PNP description found in master table */
881 if (!(strncmp(hidstr
, "ACPI", 4))) {
882 dip
= ddi_root_node();
884 dip
= get_bus_dip(m
->name
, dip
);
886 ndi_devi_alloc_sleep(dip
, m
->name
,
887 (pnode_t
)DEVI_SID_NODEID
, &xdip
);
888 (void) ndi_prop_update_string(DDI_DEV_T_NONE
, xdip
,
889 "model", m
->description
);
890 compatible_present
= process_properties(xdip
, m
->properties
);
892 /* for ISA devices not known to the master file */
893 if (!(strncmp(hidstr
, "PNP03", 5))) {
894 /* a keyboard device includes PNP03xx */
895 dip
= get_bus_dip(keyboard_alias
, dip
);
896 ndi_devi_alloc_sleep(dip
, keyboard_alias
,
897 (pnode_t
)DEVI_SID_NODEID
, &xdip
);
898 (void) ndi_prop_update_string(DDI_DEV_T_NONE
, xdip
,
899 "compatible", "pnpPNP,303");
900 (void) ndi_prop_update_string(DDI_DEV_T_NONE
, xdip
,
901 "model", "PNP03xx keyboard");
903 if (!(strncmp(hidstr
, "PNP0F", 5))) {
904 /* a mouse device include PNP0Fxx */
905 dip
= get_bus_dip(mouse_alias
, dip
);
906 ndi_devi_alloc_sleep(dip
, mouse_alias
,
907 (pnode_t
)DEVI_SID_NODEID
, &xdip
);
908 (void) ndi_prop_update_string(DDI_DEV_T_NONE
,
909 xdip
, "compatible", "pnpPNP,f03");
910 (void) ndi_prop_update_string(DDI_DEV_T_NONE
,
911 xdip
, "model", "PNP0Fxx mouse");
913 (void) parse_resources(ObjHandle
, xdip
, path
);
919 (void) ndi_prop_update_string(DDI_DEV_T_NONE
, xdip
, "acpi-namespace",
922 (void) parse_resources(ObjHandle
, xdip
, path
);
924 /* Special processing for mouse and keyboard devices per IEEE 1275 */
925 /* if master entry doesn't contain "compatible" then we add default */
926 if (strcmp(m
->name
, keyboard_alias
) == 0) {
927 (void) ndi_prop_update_int(DDI_DEV_T_NONE
, xdip
, "reg", 0);
928 (void) ndi_prop_update_string(DDI_DEV_T_NONE
, xdip
,
929 "device-type", keyboard_alias
);
930 if (!compatible_present
)
931 (void) ndi_prop_update_string(DDI_DEV_T_NONE
, xdip
,
932 "compatible", "pnpPNP,303");
933 } else if (strcmp(m
->name
, mouse_alias
) == 0) {
934 (void) ndi_prop_update_int(DDI_DEV_T_NONE
, xdip
, "reg", 1);
935 (void) ndi_prop_update_string(DDI_DEV_T_NONE
, xdip
,
936 "device-type", mouse_alias
);
937 if (!compatible_present
)
938 (void) ndi_prop_update_string(DDI_DEV_T_NONE
, xdip
,
939 "compatible", "pnpPNP,f03");
943 * Create default "compatible" property if required
945 if (!ddi_prop_exists(DDI_DEV_T_ANY
, xdip
,
946 DDI_PROP_DONTPASS
, "compatible"))
947 create_compatible_property(xdip
, device_ids
);
949 (void) ndi_devi_bind_driver(xdip
, 0);
952 /* discard _HID/_CID list */
958 mf_free_device_id(d
);
971 used_res_interrupts(void)
973 int intr
[ACPI_ISA_LIMIT
];
977 for (i
= 0; i
< ACPI_ISA_LIMIT
; i
++) {
978 if ((used_interrupts
>> i
) & 1) {
982 (void) ndi_prop_update_int_array(DDI_DEV_T_NONE
, usedrdip
,
983 "interrupts", (int *)intr
, count
);
989 int dma
[ACPI_ISA_LIMIT
];
993 for (i
= 0; i
< ACPI_ISA_LIMIT
; i
++) {
994 if ((used_dmas
>> i
) & 1) {
998 (void) ndi_prop_update_int_array(DDI_DEV_T_NONE
, usedrdip
,
999 "dma-channels", (int *)dma
, count
);
1003 used_res_io_mem(char *nodename
, int *count
, used_io_mem_t
**head
)
1006 used_io_mem_t
*used
= *head
;
1010 io
= (int *)kmem_zalloc(sizeof (int)*(*count
), KM_SLEEP
);
1011 for (i
= 0; i
< *count
; i
+= 2) {
1012 used_io_mem_t
*prev
;
1014 io
[i
] = used
->start_addr
;
1015 io
[i
+1] = used
->length
;
1018 kmem_free(prev
, sizeof (used_io_mem_t
));
1021 (void) ndi_prop_update_int_array(DDI_DEV_T_NONE
, usedrdip
,
1022 nodename
, (int *)io
, *count
);
1023 kmem_free(io
, sizeof (int)*(*count
));
1028 * acpi_isa_device_enum() -- call from isa nexus driver
1029 * returns 1 if deviced enumeration is successful
1030 * 0 if deviced enumeration fails
1033 acpi_isa_device_enum(dev_info_t
*isa_dip
)
1037 if (ddi_prop_lookup_string(DDI_DEV_T_ANY
, ddi_root_node(),
1038 DDI_PROP_DONTPASS
, ACPI_ENUM_DEBUG
, &acpi_prop
) ==
1041 if (ddi_strtol(acpi_prop
, NULL
, 0, &data
) == 0) {
1042 acpi_enum_debug
= (unsigned long)data
;
1043 e_ddi_prop_remove(DDI_DEV_T_NONE
, ddi_root_node(),
1045 e_ddi_prop_update_int(DDI_DEV_T_NONE
,
1046 ddi_root_node(), ACPI_ENUM_DEBUG
, data
);
1048 ddi_prop_free(acpi_prop
);
1051 if (acpi_enum_debug
& ISA_DEVICE_ENUM
) {
1052 cmn_err(CE_NOTE
, "!acpi_isa_device_enum() called");
1055 if (acpica_init() != AE_OK
) {
1056 cmn_err(CE_WARN
, "!isa_enum: init failed");
1057 /* Note, pickup by i8042 nexus */
1058 (void) e_ddi_prop_update_string(DDI_DEV_T_NONE
,
1059 ddi_root_node(), "acpi-enum", "off");
1063 usedrdip
= ddi_find_devinfo(USED_RESOURCES
, -1, 0);
1064 if (usedrdip
== NULL
) {
1065 ndi_devi_alloc_sleep(ddi_root_node(), USED_RESOURCES
,
1066 (pnode_t
)DEVI_SID_NODEID
, &usedrdip
);
1070 process_master_file();
1073 * Do the actual enumeration. Avoid AcpiGetDevices because it
1074 * has an unnecessary internal callback that duplicates
1075 * determining if the device is present.
1077 (void) AcpiWalkNamespace(ACPI_TYPE_DEVICE
, ACPI_ROOT_OBJECT
,
1078 UINT32_MAX
, isa_acpi_callback
, NULL
, isa_dip
, NULL
);
1081 used_res_interrupts();
1083 used_res_io_mem("device-memory", &used_mem_count
, &used_mem_head
);
1084 used_res_io_mem("io-space", &used_io_count
, &used_io_head
);
1085 (void) ndi_devi_bind_driver(usedrdip
, 0);