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 2016, 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() "\
391 cmn_err(CE_NOTE
, "!parse_resources() "\
393 "MinAddressFixed 0x%X, "\
394 "MaxAddressFixed 0x%X, "\
398 addr64
.ProducerConsumer
== ACPI_CONSUMER
?
399 "CONSUMER" : "PRODUCER",
400 addr64
.MinAddressFixed
,
401 addr64
.MaxAddressFixed
,
402 addr64
.Address
.Minimum
,
403 addr64
.Address
.Maximum
,
404 addr64
.Address
.AddressLength
);
406 cmn_err(CE_NOTE
, "!parse_resources() "\
408 "MinAddressFixed 0x%X, "\
409 "MaxAddressFixed 0x%X, "\
413 addr64
.ProducerConsumer
== ACPI_CONSUMER
?
414 "CONSUMER" : "PRODUCER",
415 addr64
.MinAddressFixed
,
416 addr64
.MaxAddressFixed
,
417 addr64
.Address
.Minimum
,
418 addr64
.Address
.Maximum
,
419 addr64
.Address
.AddressLength
);
422 if (addr64
.ProducerConsumer
== ACPI_PRODUCER
||
423 (addr64
.ResourceType
!= ACPI_MEMORY_RANGE
&&
424 addr64
.ResourceType
!= ACPI_IO_RANGE
)) {
427 if (addr64
.Address
.AddressLength
> 0) {
428 if (addr64
.ResourceType
== ACPI_MEMORY_RANGE
) {
430 io
[*io_count
].regspec_bustype
= 0;
433 io
[*io_count
].regspec_bustype
= 1;
435 io
[*io_count
].regspec_addr
= addr64
.Address
.Minimum
;
436 io
[*io_count
].regspec_size
= addr64
.Address
.AddressLength
;
442 parse_resources(ACPI_HANDLE handle
, dev_info_t
*xdip
, char *path
)
445 ACPI_RESOURCE
*resource_ptr
;
447 char *current_ptr
, *last_ptr
;
449 int io_count
= 0, interrupt_count
= 0, dma_count
= 0;
452 buf
.Length
= ACPI_ALLOCATE_BUFFER
;
453 status
= AcpiGetCurrentResources(handle
, &buf
);
459 * Workaround for faulty DSDT tables that omit the _CRS
460 * method for the UAR3 device but have a valid _PRS method
463 status
= AcpiGetPossibleResources(handle
, &buf
);
464 if (status
!= AE_OK
) {
470 "!AcpiGetCurrentResources failed for %s, exception: %s",
471 path
, AcpiFormatException(status
));
475 io
= (struct regspec
*)kmem_zalloc(sizeof (struct regspec
) *
476 MAX_PARSED_ACPI_RESOURCES
, KM_SLEEP
);
477 current_ptr
= buf
.Pointer
;
478 last_ptr
= (char *)buf
.Pointer
+ buf
.Length
;
479 while (current_ptr
< last_ptr
) {
480 if (io_count
>= MAX_PARSED_ACPI_RESOURCES
) {
483 resource_ptr
= (ACPI_RESOURCE
*)current_ptr
;
484 current_ptr
+= resource_ptr
->Length
;
485 switch (resource_ptr
->Type
) {
486 case ACPI_RESOURCE_TYPE_END_TAG
:
487 current_ptr
= last_ptr
;
489 case ACPI_RESOURCE_TYPE_IO
:
490 parse_resources_io(resource_ptr
, io
, &io_count
);
492 case ACPI_RESOURCE_TYPE_FIXED_IO
:
493 parse_resources_fixed_io(resource_ptr
, io
, &io_count
);
495 case ACPI_RESOURCE_TYPE_FIXED_MEMORY32
:
496 parse_resources_fixed_mem32(resource_ptr
, io
,
499 case ACPI_RESOURCE_TYPE_MEMORY32
:
500 parse_resources_mem32(resource_ptr
, io
, &io_count
);
502 case ACPI_RESOURCE_TYPE_ADDRESS16
:
503 parse_resources_addr16(resource_ptr
, io
, &io_count
);
505 case ACPI_RESOURCE_TYPE_ADDRESS32
:
506 parse_resources_addr32(resource_ptr
, io
, &io_count
);
508 case ACPI_RESOURCE_TYPE_ADDRESS64
:
509 parse_resources_addr64(resource_ptr
, io
, &io_count
);
511 case ACPI_RESOURCE_TYPE_IRQ
:
512 parse_resources_irq(resource_ptr
, &interrupt_count
);
514 case ACPI_RESOURCE_TYPE_DMA
:
515 parse_resources_dma(resource_ptr
, &dma_count
);
517 case ACPI_RESOURCE_TYPE_START_DEPENDENT
:
520 " ACPI_RESOURCE_TYPE_START_DEPENDENT"
523 case ACPI_RESOURCE_TYPE_END_DEPENDENT
:
526 " ACPI_RESOURCE_TYPE_END_DEPENDENT"
529 case ACPI_RESOURCE_TYPE_VENDOR
:
532 " ACPI_RESOURCE_TYPE_VENDOR"
535 case ACPI_RESOURCE_TYPE_MEMORY24
:
538 " ACPI_RESOURCE_TYPE_MEMORY24"
541 case ACPI_RESOURCE_TYPE_EXTENDED_IRQ
:
544 " ACPI_RESOURCE_TYPE_EXT_IRQ"
548 /* Some types are not yet implemented (See CA 6.4) */
550 "!ACPI resource type (0X%X) not yet supported",
558 * on LX50, you get interrupts of mouse and keyboard
559 * from separate PNP id...
562 if ((io
[0].regspec_addr
== 0x60 &&
563 io
[1].regspec_addr
== 0x64) ||
564 (io
[0].regspec_addr
== 0x64 &&
565 io
[1].regspec_addr
== 0x60)) {
575 add_used_io_mem(io
, io_count
);
577 (void) ndi_prop_update_int_array(DDI_DEV_T_NONE
, xdip
,
578 "reg", (int *)io
, 3*io_count
);
581 if (interrupt_count
&& (xdip
!= NULL
)) {
582 (void) ndi_prop_update_int_array(DDI_DEV_T_NONE
, xdip
,
583 "interrupts", (int *)interrupt
, interrupt_count
);
585 if (dma_count
&& (xdip
!= NULL
)) {
586 (void) ndi_prop_update_int_array(DDI_DEV_T_NONE
, xdip
,
587 "dma-channels", (int *)dma
, dma_count
);
589 AcpiOsFree(buf
.Pointer
);
590 kmem_free(io
, sizeof (struct regspec
) * MAX_PARSED_ACPI_RESOURCES
);
594 /* keyboard mouse is under i8042, everything else under isa */
596 get_bus_dip(char *nodename
, dev_info_t
*isa_dip
)
598 static dev_info_t
*i8042_dip
= NULL
;
599 struct regspec i8042_regs
[] = {
603 int i8042_intrs
[] = {0x1, 0xc};
605 if (strcmp(nodename
, keyboard_alias
) != 0 &&
606 strcmp(nodename
, mouse_alias
) != 0)
612 ndi_devi_alloc_sleep(isa_dip
, "i8042", (pnode_t
)DEVI_SID_NODEID
,
614 (void) ndi_prop_update_int_array(DDI_DEV_T_NONE
, i8042_dip
,
615 "reg", (int *)i8042_regs
, 6);
616 (void) ndi_prop_update_int_array(DDI_DEV_T_NONE
, i8042_dip
,
617 "interrupts", (int *)i8042_intrs
, 2);
618 (void) ndi_prop_update_string(DDI_DEV_T_NONE
, i8042_dip
,
619 "unit-address", "1,60");
620 (void) ndi_devi_bind_driver(i8042_dip
, 0);
625 * put content of properties (if any) to dev info tree at branch xdip
626 * return non-zero if a "compatible" property was processed, zero otherwise
630 process_properties(dev_info_t
*xdip
, property_t
*properties
)
634 while (properties
!= NULL
) {
635 (void) ndi_prop_update_string(DDI_DEV_T_NONE
, xdip
,
636 properties
->name
, properties
->value
);
637 if (strcmp(properties
->name
, "compatible") == 0)
639 properties
= properties
->next
;
646 eisa_to_str(ACPI_INTEGER id
, char *np
)
648 static const char hextab
[] = "0123456789ABCDEF";
651 * Expand an EISA device name:
653 * This routine converts a 32-bit EISA device "id" to a
654 * 7-byte ASCII device name, which is stored at "np".
657 *np
++ = '@' + ((id
>> 2) & 0x1F);
658 *np
++ = '@' + ((id
<< 3) & 0x18) + ((id
>> 13) & 0x07);
659 *np
++ = '@' + ((id
>> 8) & 0x1F);
660 *np
++ = hextab
[(id
>> 20) & 0x0F];
661 *np
++ = hextab
[(id
>> 16) & 0x0F];
662 *np
++ = hextab
[(id
>> 28) & 0x0F];
663 *np
++ = hextab
[(id
>> 24) & 0x0F];
668 * process_cids() -- process multiple CIDs in a package
671 process_cids(ACPI_OBJECT
*rv
, device_id_t
**dd
)
674 char tmp_cidstr
[8]; /* 7-character EISA ID */
677 if ((rv
->Package
.Count
== 0) || rv
->Package
.Elements
== NULL
)
678 return; /* empty package */
681 * Work the package 'backwards' so the resulting list is
682 * in original order of preference.
684 for (i
= rv
->Package
.Count
- 1; i
>= 0; i
--) {
685 /* get the actual acpi_object */
686 ACPI_OBJECT obj
= rv
->Package
.Elements
[i
];
688 case ACPI_TYPE_INTEGER
:
689 eisa_to_str(obj
.Integer
.Value
, tmp_cidstr
);
690 d
= mf_alloc_device_id();
691 d
->id
= strdup(tmp_cidstr
);
695 case ACPI_TYPE_STRING
:
696 d
= mf_alloc_device_id();
697 d
->id
= strdup(obj
.String
.Pointer
);
702 if (acpi_enum_debug
& PROCESS_CIDS
) {
703 cmn_err(CE_NOTE
, "!unexpected CID type: %d",
712 * Convert "raw" PNP and ACPI IDs to IEEE 1275-compliant form.
713 * Some liberty is taken here, treating "ACPI" as a special form
714 * of PNP vendor ID. strsize specifies size of buffer.
717 convert_to_pnp1275(char *pnpid
, char *str
, int strsize
)
722 if (strncmp(pnpid
, "ACPI", 4) == 0) {
723 /* Assume ACPI ID: ACPIxxxx */
724 sscanf(pnpid
, "%4s%x", vendor
, &id
);
726 /* Assume PNP ID: aaaxxxx */
727 sscanf(pnpid
, "%3s%x", vendor
, &id
);
730 snprintf(str
, strsize
, "pnp%s,%x", vendor
, id
);
734 * Given a list of device ID elements in most-to-least-specific
735 * order, create a "compatible" property.
738 create_compatible_property(dev_info_t
*dip
, device_id_t
*ids
)
744 /* count list length */
752 /* create string array */
753 strs
= (char **)kmem_zalloc(list_len
* sizeof (char *), KM_SLEEP
);
757 /* strlen("pnpXXXX,xxxx") + 1 = 13 */
758 strs
[i
] = kmem_zalloc(13, KM_SLEEP
);
759 convert_to_pnp1275(d
->id
, strs
[i
++], 13);
763 /* update property */
764 (void) ndi_prop_update_string_array(DDI_DEV_T_NONE
, dip
,
765 "compatible", strs
, list_len
);
769 for (i
= 0; i
< list_len
; i
++)
770 kmem_free(strs
[i
], 13);
772 kmem_free(strs
, list_len
* sizeof (char *));
776 * isa_acpi_callback()
779 isa_acpi_callback(ACPI_HANDLE ObjHandle
, uint32_t NestingLevel
, void *a
,
782 _NOTE(ARGUNUSED(NestingLevel
, b
))
785 ACPI_DEVICE_INFO
*info
= NULL
;
788 char tmp_cidstr
[8]; /* EISAID size */
789 dev_info_t
*dip
= (dev_info_t
*)a
;
790 dev_info_t
*xdip
= NULL
;
791 device_id_t
*d
, *device_ids
= NULL
;
792 const master_rec_t
*m
;
793 int compatible_present
= 0;
796 * get full ACPI pathname for object
798 rb
.Length
= ACPI_ALLOCATE_BUFFER
;
800 if (AcpiGetName(ObjHandle
, ACPI_FULL_PATHNAME
, &rb
) != AE_OK
) {
801 cmn_err(CE_WARN
, "!acpi_enum: could not get pathname");
804 path
= (char *)rb
.Pointer
;
807 * Get device info object
809 if (AcpiGetObjectInfo(ObjHandle
, &info
) != AE_OK
) {
810 cmn_err(CE_WARN
, "!acpi_enum: could not get device"
811 " info for %s", path
);
816 * If device isn't present, we don't enumerate
817 * NEEDSWORK: what about docking bays and the like?
819 if (info
->Valid
& ACPI_VALID_STA
) {
821 * CA 6.3.6 _STA method
822 * Bit 0 -- device is present
823 * Bit 1 -- device is enabled
824 * Bit 2 -- device is shown in UI
826 if (!((info
->CurrentStatus
& 0x7) == 7)) {
827 if (acpi_enum_debug
& DEVICES_NOT_ENUMED
) {
828 cmn_err(CE_NOTE
, "!parse_resources() "
829 "Bad status 0x%x for %s",
830 info
->CurrentStatus
, path
);
835 cmn_err(CE_WARN
, "!acpi_enum: no _STA for %s", path
);
840 * Keep track of _HID value
842 if (!(info
->Valid
& ACPI_VALID_HID
)) {
843 /* No _HID, we skip this node */
844 if (acpi_enum_debug
& DEVICES_NOT_ENUMED
) {
845 cmn_err(CE_NOTE
, "!parse_resources() "
846 "No _HID for %s", path
);
850 hidstr
= info
->HardwareId
.String
;
853 * Attempt to get _CID value
855 rb
.Length
= ACPI_ALLOCATE_BUFFER
;
857 if (AcpiEvaluateObject(ObjHandle
, "_CID", NULL
, &rb
) == AE_OK
&&
859 ACPI_OBJECT
*rv
= rb
.Pointer
;
862 case ACPI_TYPE_INTEGER
:
863 eisa_to_str(rv
->Integer
.Value
, tmp_cidstr
);
864 d
= mf_alloc_device_id();
865 d
->id
= strdup(tmp_cidstr
);
866 d
->next
= device_ids
;
869 case ACPI_TYPE_STRING
:
870 d
= mf_alloc_device_id();
871 d
->id
= strdup(rv
->String
.Pointer
);
872 d
->next
= device_ids
;
875 case ACPI_TYPE_PACKAGE
:
876 process_cids(rv
, &device_ids
);
881 AcpiOsFree(rb
.Pointer
);
885 * Add _HID last so it's at the head of the list
887 d
= mf_alloc_device_id();
888 d
->id
= strdup(hidstr
);
889 d
->next
= device_ids
;
893 * master_file_lookup() expects _HID first in device_ids
895 if ((m
= master_file_lookup(device_ids
)) != NULL
) {
896 /* PNP description found in master table */
897 if (!(strncmp(hidstr
, "ACPI", 4))) {
898 dip
= ddi_root_node();
900 dip
= get_bus_dip(m
->name
, dip
);
902 ndi_devi_alloc_sleep(dip
, m
->name
,
903 (pnode_t
)DEVI_SID_NODEID
, &xdip
);
904 (void) ndi_prop_update_string(DDI_DEV_T_NONE
, xdip
,
905 "model", m
->description
);
906 compatible_present
= process_properties(xdip
, m
->properties
);
908 /* for ISA devices not known to the master file */
909 if (!(strncmp(hidstr
, "PNP03", 5))) {
910 /* a keyboard device includes PNP03xx */
911 dip
= get_bus_dip(keyboard_alias
, dip
);
912 ndi_devi_alloc_sleep(dip
, keyboard_alias
,
913 (pnode_t
)DEVI_SID_NODEID
, &xdip
);
914 (void) ndi_prop_update_string(DDI_DEV_T_NONE
, xdip
,
915 "compatible", "pnpPNP,303");
916 (void) ndi_prop_update_string(DDI_DEV_T_NONE
, xdip
,
917 "model", "PNP03xx keyboard");
919 if (!(strncmp(hidstr
, "PNP0F", 5))) {
920 /* a mouse device include PNP0Fxx */
921 dip
= get_bus_dip(mouse_alias
, dip
);
922 ndi_devi_alloc_sleep(dip
, mouse_alias
,
923 (pnode_t
)DEVI_SID_NODEID
, &xdip
);
924 (void) ndi_prop_update_string(DDI_DEV_T_NONE
,
925 xdip
, "compatible", "pnpPNP,f03");
926 (void) ndi_prop_update_string(DDI_DEV_T_NONE
,
927 xdip
, "model", "PNP0Fxx mouse");
929 (void) parse_resources(ObjHandle
, xdip
, path
);
935 (void) ndi_prop_update_string(DDI_DEV_T_NONE
, xdip
, "acpi-namespace",
938 (void) parse_resources(ObjHandle
, xdip
, path
);
940 /* Special processing for mouse and keyboard devices per IEEE 1275 */
941 /* if master entry doesn't contain "compatible" then we add default */
942 if (strcmp(m
->name
, keyboard_alias
) == 0) {
943 (void) ndi_prop_update_int(DDI_DEV_T_NONE
, xdip
, "reg", 0);
944 (void) ndi_prop_update_string(DDI_DEV_T_NONE
, xdip
,
945 "device-type", keyboard_alias
);
946 if (!compatible_present
)
947 (void) ndi_prop_update_string(DDI_DEV_T_NONE
, xdip
,
948 "compatible", "pnpPNP,303");
949 } else if (strcmp(m
->name
, mouse_alias
) == 0) {
950 (void) ndi_prop_update_int(DDI_DEV_T_NONE
, xdip
, "reg", 1);
951 (void) ndi_prop_update_string(DDI_DEV_T_NONE
, xdip
,
952 "device-type", mouse_alias
);
953 if (!compatible_present
)
954 (void) ndi_prop_update_string(DDI_DEV_T_NONE
, xdip
,
955 "compatible", "pnpPNP,f03");
959 * Create default "compatible" property if required
961 if (!ddi_prop_exists(DDI_DEV_T_ANY
, xdip
,
962 DDI_PROP_DONTPASS
, "compatible"))
963 create_compatible_property(xdip
, device_ids
);
965 (void) ndi_devi_bind_driver(xdip
, 0);
968 /* discard _HID/_CID list */
974 mf_free_device_id(d
);
987 used_res_interrupts(void)
989 int intr
[ACPI_ISA_LIMIT
];
993 for (i
= 0; i
< ACPI_ISA_LIMIT
; i
++) {
994 if ((used_interrupts
>> i
) & 1) {
998 (void) ndi_prop_update_int_array(DDI_DEV_T_NONE
, usedrdip
,
999 "interrupts", (int *)intr
, count
);
1005 int dma
[ACPI_ISA_LIMIT
];
1009 for (i
= 0; i
< ACPI_ISA_LIMIT
; i
++) {
1010 if ((used_dmas
>> i
) & 1) {
1014 (void) ndi_prop_update_int_array(DDI_DEV_T_NONE
, usedrdip
,
1015 "dma-channels", (int *)dma
, count
);
1019 used_res_io_mem(char *nodename
, int *count
, used_io_mem_t
**head
)
1022 used_io_mem_t
*used
= *head
;
1026 io
= (int *)kmem_zalloc(sizeof (int)*(*count
), KM_SLEEP
);
1027 for (i
= 0; i
< *count
; i
+= 2) {
1028 used_io_mem_t
*prev
;
1030 io
[i
] = used
->start_addr
;
1031 io
[i
+1] = used
->length
;
1034 kmem_free(prev
, sizeof (used_io_mem_t
));
1037 (void) ndi_prop_update_int_array(DDI_DEV_T_NONE
, usedrdip
,
1038 nodename
, (int *)io
, *count
);
1039 kmem_free(io
, sizeof (int)*(*count
));
1044 * acpi_isa_device_enum() -- call from isa nexus driver
1045 * returns 1 if deviced enumeration is successful
1046 * 0 if deviced enumeration fails
1049 acpi_isa_device_enum(dev_info_t
*isa_dip
)
1053 if (ddi_prop_lookup_string(DDI_DEV_T_ANY
, ddi_root_node(),
1054 DDI_PROP_DONTPASS
, ACPI_ENUM_DEBUG
, &acpi_prop
) ==
1057 if (ddi_strtol(acpi_prop
, NULL
, 0, &data
) == 0) {
1058 acpi_enum_debug
= (unsigned long)data
;
1059 e_ddi_prop_remove(DDI_DEV_T_NONE
, ddi_root_node(),
1061 e_ddi_prop_update_int(DDI_DEV_T_NONE
,
1062 ddi_root_node(), ACPI_ENUM_DEBUG
, data
);
1064 ddi_prop_free(acpi_prop
);
1067 if (acpi_enum_debug
& ISA_DEVICE_ENUM
) {
1068 cmn_err(CE_NOTE
, "!acpi_isa_device_enum() called");
1071 if (acpica_init() != AE_OK
) {
1072 cmn_err(CE_WARN
, "!isa_enum: init failed");
1073 /* Note, pickup by i8042 nexus */
1074 (void) e_ddi_prop_update_string(DDI_DEV_T_NONE
,
1075 ddi_root_node(), "acpi-enum", "off");
1079 usedrdip
= ddi_find_devinfo(USED_RESOURCES
, -1, 0);
1080 if (usedrdip
== NULL
) {
1081 ndi_devi_alloc_sleep(ddi_root_node(), USED_RESOURCES
,
1082 (pnode_t
)DEVI_SID_NODEID
, &usedrdip
);
1086 process_master_file();
1089 * Do the actual enumeration. Avoid AcpiGetDevices because it
1090 * has an unnecessary internal callback that duplicates
1091 * determining if the device is present.
1093 (void) AcpiWalkNamespace(ACPI_TYPE_DEVICE
, ACPI_ROOT_OBJECT
,
1094 UINT32_MAX
, isa_acpi_callback
, NULL
, isa_dip
, NULL
);
1097 used_res_interrupts();
1099 used_res_io_mem("device-memory", &used_mem_count
, &used_mem_head
);
1100 used_res_io_mem("io-space", &used_io_count
, &used_io_head
);
1101 (void) ndi_devi_bind_driver(usedrdip
, 0);