xref: /illumos-gate/usr/src/uts/intel/io/acpica/acpi_enum.c (revision 46b592853d0f4f11781b6b0a7533f267c6aee132)
1 /*
2  * CDDL HEADER START
3  *
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.
7  *
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.
12  *
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]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 /*
27  * ACPI enumerator
28  */
29 
30 #include <sys/ddi.h>
31 #include <sys/sunddi.h>
32 #include <sys/sunndi.h>
33 #include <sys/note.h>
34 #include <sys/acpi/acpi.h>
35 #include <sys/acpica.h>
36 #include <util/sscanf.h>
37 
38 
39 static char keyboard_alias[] = "keyboard";
40 static char mouse_alias[] = "mouse";
41 #define	ACPI_ENUM_DEBUG		"acpi_enum_debug"
42 #define	PARSE_RESOURCES_DEBUG	0x0001
43 #define	MASTER_LOOKUP_DEBUG	0x0002
44 #define	DEVICES_NOT_ENUMED	0x0004
45 #define	PARSE_RES_IRQ		0x0008
46 #define	PARSE_RES_DMA		0x0010
47 #define	PARSE_RES_MEMORY	0x0020
48 #define	PARSE_RES_IO		0x0040
49 #define	PARSE_RES_ADDRESS	0x0080
50 #define	ISA_DEVICE_ENUM		0x1000
51 #define	PROCESS_CIDS		0x2000
52 static unsigned long acpi_enum_debug = 0x00;
53 
54 static char USED_RESOURCES[] = "used-resources";
55 static dev_info_t *usedrdip = NULL;
56 static unsigned short used_interrupts = 0;
57 static unsigned short used_dmas = 0;
58 typedef struct used_io_mem {
59 	unsigned int start_addr;
60 	unsigned int length;
61 	struct used_io_mem *next;
62 } used_io_mem_t;
63 static used_io_mem_t *used_io_head = NULL;
64 static used_io_mem_t *used_mem_head = NULL;
65 static int used_io_count = 0;
66 static int used_mem_count = 0;
67 
68 #define	MAX_PARSED_ACPI_RESOURCES	255
69 #define	ACPI_ISA_LIMIT	16
70 static int interrupt[ACPI_ISA_LIMIT], dma[ACPI_ISA_LIMIT];
71 #define	ACPI_ELEMENT_PACKAGE_LIMIT	32
72 #define	EISA_ID_SIZE	7
73 
74 /*
75  * insert used io/mem in increasing order
76  */
77 static void
78 insert_used_resource(used_io_mem_t *used, int *used_count, used_io_mem_t **head)
79 {
80 	used_io_mem_t *curr, *prev;
81 
82 	(*used_count)++;
83 	if (*head == NULL) {
84 		*head = used;
85 		return;
86 	}
87 	curr = prev = *head;
88 	/* find a place to insert */
89 	while ((curr != NULL) &&
90 	    (curr->start_addr < used->start_addr)) {
91 		prev = curr;
92 		curr = curr->next;
93 	}
94 	if (prev == curr) {
95 		/* head */
96 		*head = used;
97 		used->next = curr;
98 		return;
99 	} else {
100 		prev->next = used;
101 	}
102 	used->next = curr;
103 }
104 
105 static void
106 add_used_io_mem(struct regspec *io, int io_count)
107 {
108 	int i;
109 	used_io_mem_t *used;
110 
111 	for (i = 0; i < io_count; i++) {
112 		used = (used_io_mem_t *)kmem_zalloc(sizeof (used_io_mem_t),
113 		    KM_SLEEP);
114 		used->start_addr = io[i].regspec_addr;
115 		used->length = io[i].regspec_size;
116 		if (io[i].regspec_bustype == 1) {
117 			insert_used_resource(used, &used_io_count,
118 			    &used_io_head);
119 		} else {
120 			insert_used_resource(used, &used_mem_count,
121 			    &used_mem_head);
122 		}
123 	}
124 }
125 
126 static void
127 parse_resources_irq(ACPI_RESOURCE *resource_ptr, int *interrupt_count)
128 {
129 	int i;
130 
131 	for (i = 0; i < resource_ptr->Data.Irq.InterruptCount; i++) {
132 		interrupt[(*interrupt_count)++] =
133 		    resource_ptr->Data.Irq.Interrupts[i];
134 		used_interrupts |= 1 << resource_ptr->Data.Irq.Interrupts[i];
135 		if (acpi_enum_debug & PARSE_RES_IRQ) {
136 			cmn_err(CE_NOTE, "parse_resources() "\
137 			    "IRQ num %u, intr # = %u",
138 			    i, resource_ptr->Data.Irq.Interrupts[i]);
139 		}
140 	}
141 }
142 
143 static void
144 parse_resources_dma(ACPI_RESOURCE *resource_ptr, int *dma_count)
145 {
146 	int i;
147 
148 	for (i = 0; i < resource_ptr->Data.Dma.ChannelCount; i++) {
149 		dma[(*dma_count)++] = resource_ptr->Data.Dma.Channels[i];
150 		used_dmas |= 1 << resource_ptr->Data.Dma.Channels[i];
151 		if (acpi_enum_debug & PARSE_RES_DMA) {
152 			cmn_err(CE_NOTE, "parse_resources() "\
153 			    "DMA num %u, channel # = %u",
154 			    i, resource_ptr->Data.Dma.Channels[i]);
155 		}
156 	}
157 }
158 
159 static void
160 parse_resources_io(ACPI_RESOURCE *resource_ptr, struct regspec *io,
161     int *io_count)
162 {
163 	ACPI_RESOURCE_IO acpi_io = resource_ptr->Data.Io;
164 
165 	if (acpi_io.AddressLength == 0)
166 		return;
167 
168 	io[*io_count].regspec_bustype = 1; /* io */
169 	io[*io_count].regspec_size = acpi_io.AddressLength;
170 	io[*io_count].regspec_addr = acpi_io.Minimum;
171 	if (acpi_enum_debug & PARSE_RES_IO) {
172 		cmn_err(CE_NOTE, "parse_resources() "\
173 		    "IO min 0x%X, max 0x%X, length: 0x%X",
174 		    acpi_io.Minimum,
175 		    acpi_io.Maximum,
176 		    acpi_io.AddressLength);
177 	}
178 	(*io_count)++;
179 }
180 
181 static void
182 parse_resources_fixed_io(ACPI_RESOURCE *resource_ptr, struct regspec *io,
183     int *io_count)
184 {
185 	ACPI_RESOURCE_FIXED_IO fixed_io = resource_ptr->Data.FixedIo;
186 
187 	if (fixed_io.AddressLength == 0)
188 		return;
189 
190 	io[*io_count].regspec_bustype = 1; /* io */
191 	io[*io_count].regspec_addr = fixed_io.Address;
192 	io[*io_count].regspec_size = fixed_io.AddressLength;
193 	if (acpi_enum_debug & PARSE_RES_IO) {
194 		cmn_err(CE_NOTE, "parse_resources() "\
195 		    "Fixed IO 0x%X, length: 0x%X",
196 		    fixed_io.Address, fixed_io.AddressLength);
197 	}
198 	(*io_count)++;
199 }
200 
201 static void
202 parse_resources_fixed_mem32(ACPI_RESOURCE *resource_ptr, struct regspec *io,
203     int *io_count)
204 {
205 	ACPI_RESOURCE_FIXED_MEMORY32 fixed_mem32 =
206 	    resource_ptr->Data.FixedMemory32;
207 
208 	if (fixed_mem32.AddressLength == 0)
209 		return;
210 
211 	io[*io_count].regspec_bustype = 0; /* memory */
212 	io[*io_count].regspec_addr = fixed_mem32.Address;
213 	io[*io_count].regspec_size = fixed_mem32.AddressLength;
214 	if (acpi_enum_debug & PARSE_RES_MEMORY) {
215 		cmn_err(CE_NOTE, "parse_resources() "\
216 		    "Fixed Mem 32 %ul, length: %ul",
217 		    fixed_mem32.Address, fixed_mem32.AddressLength);
218 	}
219 	(*io_count)++;
220 }
221 
222 static void
223 parse_resources_mem32(ACPI_RESOURCE *resource_ptr, struct regspec *io,
224     int *io_count)
225 {
226 	ACPI_RESOURCE_MEMORY32 mem32 = resource_ptr->Data.Memory32;
227 
228 	if (mem32.AddressLength == 0)
229 		return;
230 
231 	if (resource_ptr->Data.Memory32.Minimum ==
232 	    resource_ptr->Data.Memory32.Maximum) {
233 		io[*io_count].regspec_bustype = 0; /* memory */
234 		io[*io_count].regspec_addr = mem32.Minimum;
235 		io[*io_count].regspec_size = mem32.AddressLength;
236 		(*io_count)++;
237 		if (acpi_enum_debug & PARSE_RES_MEMORY) {
238 			cmn_err(CE_NOTE, "parse_resources() "\
239 			    "Mem 32 0x%X, length: 0x%X",
240 			    mem32.Minimum, mem32.AddressLength);
241 		}
242 		return;
243 	}
244 	if (acpi_enum_debug & PARSE_RES_MEMORY) {
245 		cmn_err(CE_NOTE, "parse_resources() "\
246 		    "MEM32 Min Max not equal!");
247 		cmn_err(CE_NOTE, "parse_resources() "\
248 		    "Mem 32 Minimum 0x%X, Maximum: 0x%X",
249 		    mem32.Minimum, mem32.Maximum);
250 	}
251 }
252 
253 static void
254 parse_resources_addr16(ACPI_RESOURCE *resource_ptr, struct regspec *io,
255     int *io_count)
256 {
257 	ACPI_RESOURCE_ADDRESS16 addr16 =
258 	    resource_ptr->Data.Address16;
259 
260 	if (addr16.AddressLength == 0)
261 		return;
262 
263 	if (acpi_enum_debug & PARSE_RES_ADDRESS) {
264 		if (addr16.ResourceType == ACPI_MEMORY_RANGE) {
265 			cmn_err(CE_NOTE, "parse_resources() "\
266 			    "ADDRESS 16 MEMORY RANGE");
267 		} else
268 		if (addr16.ResourceType == ACPI_IO_RANGE) {
269 			cmn_err(CE_NOTE, "parse_resources() "\
270 			    "ADDRESS 16 IO RANGE");
271 		} else {
272 			cmn_err(CE_NOTE, "parse_resources() "\
273 			    "ADDRESS 16 OTHER");
274 		}
275 		cmn_err(CE_NOTE, "parse_resources() "\
276 		    "%s "\
277 		    "MinAddressFixed 0x%X, "\
278 		    "MaxAddressFixed 0x%X, "\
279 		    "Minimum 0x%X, "\
280 		    "Maximum 0x%X, "\
281 		    "length: 0x%X\n",
282 		    addr16.ProducerConsumer == ACPI_CONSUMER ?
283 		    "CONSUMER" : "PRODUCER",
284 		    addr16.MinAddressFixed,
285 		    addr16.MaxAddressFixed,
286 		    addr16.Minimum,
287 		    addr16.Maximum,
288 		    addr16.AddressLength);
289 	}
290 	if (addr16.ProducerConsumer == ACPI_PRODUCER ||
291 	    (addr16.ResourceType != ACPI_MEMORY_RANGE &&
292 	    addr16.ResourceType != ACPI_IO_RANGE)) {
293 		return;
294 	}
295 	if (addr16.AddressLength > 0) {
296 		if (addr16.ResourceType == ACPI_MEMORY_RANGE) {
297 			/* memory */
298 			io[*io_count].regspec_bustype = 0;
299 		} else {
300 			/* io */
301 			io[*io_count].regspec_bustype = 1;
302 		}
303 		io[*io_count].regspec_addr = addr16.Minimum;
304 		io[*io_count].regspec_size = addr16.AddressLength;
305 		(*io_count)++;
306 	}
307 }
308 
309 static void
310 parse_resources_addr32(ACPI_RESOURCE *resource_ptr, struct regspec *io,
311     int *io_count)
312 {
313 	ACPI_RESOURCE_ADDRESS32 addr32 =
314 	    resource_ptr->Data.Address32;
315 
316 	if (addr32.AddressLength == 0)
317 		return;
318 
319 	if (acpi_enum_debug & PARSE_RES_ADDRESS) {
320 		if (addr32.ResourceType == ACPI_MEMORY_RANGE) {
321 			cmn_err(CE_NOTE, "parse_resources() "\
322 			    "ADDRESS 32 MEMORY RANGE");
323 		} else
324 		if (addr32.ResourceType == ACPI_IO_RANGE) {
325 			cmn_err(CE_NOTE, "parse_resources() "\
326 			    "ADDRESS 32 IO RANGE");
327 		} else {
328 			cmn_err(CE_NOTE, "parse_resources() "\
329 			    "ADDRESS 32 OTHER");
330 		}
331 		cmn_err(CE_NOTE, "parse_resources() "\
332 		    "%s "\
333 		    "MinAddressFixed 0x%X, "\
334 		    "MaxAddressFixed 0x%X, "\
335 		    "Minimum 0x%X, "\
336 		    "Maximum 0x%X, "\
337 		    "length: 0x%X\n",
338 		    addr32.ProducerConsumer == ACPI_CONSUMER ?
339 		    "CONSUMER" : "PRODUCER",
340 		    addr32.MinAddressFixed,
341 		    addr32.MaxAddressFixed,
342 		    addr32.Minimum,
343 		    addr32.Maximum,
344 		    addr32.AddressLength);
345 	}
346 	if (addr32.ProducerConsumer == ACPI_PRODUCER ||
347 	    (addr32.ResourceType != ACPI_MEMORY_RANGE &&
348 	    addr32.ResourceType != ACPI_IO_RANGE)) {
349 		return;
350 	}
351 	if (addr32.AddressLength > 0) {
352 		if (addr32.ResourceType == ACPI_MEMORY_RANGE) {
353 			/* memory */
354 			io[*io_count].regspec_bustype = 0;
355 		} else {
356 			/* io */
357 			io[*io_count].regspec_bustype = 1;
358 		}
359 		io[*io_count].regspec_addr = addr32.Minimum;
360 		io[*io_count].regspec_size = addr32.AddressLength;
361 		(*io_count)++;
362 	}
363 }
364 
365 static void
366 parse_resources_addr64(ACPI_RESOURCE *resource_ptr, struct regspec *io,
367     int *io_count)
368 {
369 	ACPI_RESOURCE_ADDRESS64 addr64 =
370 	    resource_ptr->Data.Address64;
371 
372 	if (addr64.AddressLength == 0)
373 		return;
374 
375 	if (acpi_enum_debug & PARSE_RES_ADDRESS) {
376 		if (addr64.ResourceType == ACPI_MEMORY_RANGE) {
377 			cmn_err(CE_NOTE, "parse_resources() "\
378 			    "ADDRESS 64 MEMORY RANGE");
379 		} else
380 		if (addr64.ResourceType == ACPI_IO_RANGE) {
381 			cmn_err(CE_NOTE, "parse_resources() "\
382 			    "ADDRESS 64 IO RANGE");
383 		} else {
384 			cmn_err(CE_NOTE, "parse_resources() "\
385 			    "ADDRESS 64 OTHER");
386 		}
387 #ifdef _LP64
388 		cmn_err(CE_NOTE, "parse_resources() "\
389 		    "%s "\
390 		    "MinAddressFixed 0x%X, "\
391 		    "MaxAddressFixed 0x%X, "\
392 		    "Minimum 0x%lX, "\
393 		    "Maximum 0x%lX, "\
394 		    "length: 0x%lX\n",
395 		    addr64.ProducerConsumer == ACPI_CONSUMER ?
396 		    "CONSUMER" : "PRODUCER",
397 		    addr64.MinAddressFixed,
398 		    addr64.MaxAddressFixed,
399 		    addr64.Minimum,
400 		    addr64.Maximum,
401 		    addr64.AddressLength);
402 #else
403 		cmn_err(CE_NOTE, "parse_resources() "\
404 		    "%s "\
405 		    "MinAddressFixed 0x%X, "\
406 		    "MaxAddressFixed 0x%X, "\
407 		    "Minimum 0x%llX, "\
408 		    "Maximum 0x%llX, "\
409 		    "length: 0x%llX\n",
410 		    addr64.ProducerConsumer == ACPI_CONSUMER ?
411 		    "CONSUMER" : "PRODUCER",
412 		    addr64.MinAddressFixed,
413 		    addr64.MaxAddressFixed,
414 		    addr64.Minimum,
415 		    addr64.Maximum,
416 		    addr64.AddressLength);
417 #endif
418 	}
419 	if (addr64.ProducerConsumer == ACPI_PRODUCER ||
420 	    (addr64.ResourceType != ACPI_MEMORY_RANGE &&
421 	    addr64.ResourceType != ACPI_IO_RANGE)) {
422 		return;
423 	}
424 	if (addr64.AddressLength > 0) {
425 		if (addr64.ResourceType == ACPI_MEMORY_RANGE) {
426 			/* memory */
427 			io[*io_count].regspec_bustype = 0;
428 		} else {
429 			/* io */
430 			io[*io_count].regspec_bustype = 1;
431 		}
432 		io[*io_count].regspec_addr = addr64.Minimum;
433 		io[*io_count].regspec_size = addr64.AddressLength;
434 		(*io_count)++;
435 	}
436 }
437 
438 static ACPI_STATUS
439 parse_resources(ACPI_HANDLE handle, dev_info_t *xdip)
440 {
441 	ACPI_BUFFER	buf;
442 	ACPI_RESOURCE	*resource_ptr;
443 	ACPI_STATUS	status;
444 	char		*current_ptr, *last_ptr;
445 	struct		regspec *io;
446 	int		io_count = 0, interrupt_count = 0, dma_count = 0;
447 	int		i;
448 
449 	buf.Length = ACPI_ALLOCATE_BUFFER;
450 	status = AcpiGetCurrentResources(handle, &buf);
451 	if (status != AE_OK) {
452 		return (status);
453 	}
454 	io = (struct regspec *)kmem_zalloc(sizeof (struct regspec) *
455 	    MAX_PARSED_ACPI_RESOURCES, KM_SLEEP);
456 	current_ptr = buf.Pointer;
457 	last_ptr = (char *)buf.Pointer + buf.Length;
458 	while (current_ptr < last_ptr) {
459 		if (io_count >= MAX_PARSED_ACPI_RESOURCES) {
460 			break;
461 		}
462 		resource_ptr = (ACPI_RESOURCE *)current_ptr;
463 		current_ptr += resource_ptr->Length;
464 		switch (resource_ptr->Type) {
465 		case ACPI_RESOURCE_TYPE_END_TAG:
466 			current_ptr = last_ptr;
467 			break;
468 		case ACPI_RESOURCE_TYPE_IO:
469 			parse_resources_io(resource_ptr, io, &io_count);
470 			break;
471 		case ACPI_RESOURCE_TYPE_FIXED_IO:
472 			parse_resources_fixed_io(resource_ptr, io, &io_count);
473 			break;
474 		case ACPI_RESOURCE_TYPE_FIXED_MEMORY32:
475 			parse_resources_fixed_mem32(resource_ptr, io,
476 			    &io_count);
477 			break;
478 		case ACPI_RESOURCE_TYPE_MEMORY32:
479 			parse_resources_mem32(resource_ptr, io, &io_count);
480 			break;
481 		case ACPI_RESOURCE_TYPE_ADDRESS16:
482 			parse_resources_addr16(resource_ptr, io, &io_count);
483 			break;
484 		case ACPI_RESOURCE_TYPE_ADDRESS32:
485 			parse_resources_addr32(resource_ptr, io, &io_count);
486 			break;
487 		case ACPI_RESOURCE_TYPE_ADDRESS64:
488 			parse_resources_addr64(resource_ptr, io, &io_count);
489 			break;
490 		case ACPI_RESOURCE_TYPE_IRQ:
491 			parse_resources_irq(resource_ptr, &interrupt_count);
492 			break;
493 		case ACPI_RESOURCE_TYPE_DMA:
494 			parse_resources_dma(resource_ptr, &dma_count);
495 			break;
496 		case ACPI_RESOURCE_TYPE_START_DEPENDENT:
497 			cmn_err(CE_NOTE,
498 			    "!ACPI source type"
499 			    " ACPI_RESOURCE_TYPE_START_DEPENDENT"
500 			    " not supported");
501 			break;
502 		case ACPI_RESOURCE_TYPE_END_DEPENDENT:
503 			cmn_err(CE_NOTE,
504 			    "!ACPI source type"
505 			    " ACPI_RESOURCE_TYPE_END_DEPENDENT"
506 			    " not supported");
507 			break;
508 		case ACPI_RESOURCE_TYPE_VENDOR:
509 			cmn_err(CE_NOTE,
510 			    "!ACPI source type"
511 			    " ACPI_RESOURCE_TYPE_VENDOR"
512 			    " not supported");
513 			break;
514 		case ACPI_RESOURCE_TYPE_MEMORY24:
515 			cmn_err(CE_NOTE,
516 			    "!ACPI source type"
517 			    " ACPI_RESOURCE_TYPE_MEMORY24"
518 			    " not supported");
519 			break;
520 		case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
521 			cmn_err(CE_NOTE,
522 			    "!ACPI source type"
523 			    " ACPI_RESOURCE_TYPE_EXT_IRQ"
524 			    " not supported");
525 			break;
526 		default:
527 		/* Some types are not yet implemented (See CA 6.4) */
528 			cmn_err(CE_NOTE,
529 			    "!ACPI resource type (0X%X) not yet supported",
530 			    resource_ptr->Type);
531 			break;
532 		}
533 	}
534 
535 	if (io_count) {
536 		/*
537 		 * on LX50, you get interrupts of mouse and keyboard
538 		 * from separate PNP id...
539 		 */
540 		if (io_count == 2) {
541 			if ((io[0].regspec_addr == 0x60 &&
542 			    io[1].regspec_addr == 0x64) ||
543 			    (io[0].regspec_addr == 0x64 &&
544 			    io[1].regspec_addr == 0x60)) {
545 				interrupt[0] = 0x1;
546 				interrupt[1] = 0xc;
547 				interrupt_count = 2;
548 				used_interrupts |=
549 				    1 << interrupt[0];
550 				used_interrupts |=
551 				    1 << interrupt[1];
552 			}
553 		}
554 		add_used_io_mem(io, io_count);
555 		if (xdip != NULL) {
556 			(void) ndi_prop_update_int_array(DDI_DEV_T_NONE, xdip,
557 			    "reg", (int *)io, 3*io_count);
558 		}
559 	}
560 	if (interrupt_count && (xdip != NULL)) {
561 		(void) ndi_prop_update_int_array(DDI_DEV_T_NONE, xdip,
562 		    "interrupts", (int *)interrupt, interrupt_count);
563 	}
564 	if (dma_count && (xdip != NULL)) {
565 		(void) ndi_prop_update_int_array(DDI_DEV_T_NONE, xdip,
566 		    "dma-channels", (int *)dma, dma_count);
567 	}
568 	AcpiOsFree(buf.Pointer);
569 	kmem_free(io, sizeof (struct regspec) * MAX_PARSED_ACPI_RESOURCES);
570 	return (status);
571 }
572 
573 /* keyboard mouse is under i8042, everything else under isa */
574 static dev_info_t *
575 get_bus_dip(char *nodename, dev_info_t *isa_dip)
576 {
577 	static dev_info_t *i8042_dip = NULL;
578 	struct regspec i8042_regs[] = {
579 		{1, 0x60, 0x1},
580 		{1, 0x64, 0x1}
581 	};
582 	int i8042_intrs[] = {0x1, 0xc};
583 
584 	if (strcmp(nodename, keyboard_alias) != 0 &&
585 	    strcmp(nodename, mouse_alias) != 0)
586 		return (isa_dip);
587 
588 	if (i8042_dip)
589 		return (i8042_dip);
590 
591 	ndi_devi_alloc_sleep(isa_dip, "i8042", (pnode_t)DEVI_SID_NODEID,
592 	    &i8042_dip);
593 	(void) ndi_prop_update_int_array(DDI_DEV_T_NONE, i8042_dip,
594 	    "reg", (int *)i8042_regs, 6);
595 	(void) ndi_prop_update_int_array(DDI_DEV_T_NONE, i8042_dip,
596 	    "interrupts", (int *)i8042_intrs, 2);
597 	(void) ndi_prop_update_string(DDI_DEV_T_NONE, i8042_dip,
598 	    "unit-address", "1,60");
599 	(void) ndi_devi_bind_driver(i8042_dip, 0);
600 	return (i8042_dip);
601 }
602 
603 /*
604  * put content of properties (if any) to dev info tree at branch xdip
605  * return non-zero if a "compatible" property was processed, zero otherwise
606  *
607  */
608 static int
609 process_properties(dev_info_t *xdip, property_t *properties)
610 {
611 	int	rv = 0;
612 
613 	while (properties != NULL) {
614 		(void) ndi_prop_update_string(DDI_DEV_T_NONE, xdip,
615 		    properties->name, properties->value);
616 		if (strcmp(properties->name, "compatible") == 0)
617 			rv = 1;
618 		properties = properties->next;
619 	}
620 
621 	return (rv);
622 }
623 
624 void
625 eisa_to_str(ACPI_INTEGER id, char *np)
626 {
627 	static const char hextab[] = "0123456789ABCDEF";
628 
629 	/*
630 	 *  Expand an EISA device name:
631 	 *
632 	 * This routine converts a 32-bit EISA device "id" to a
633 	 * 7-byte ASCII device name, which is stored at "np".
634 	 */
635 
636 	*np++ = '@' + ((id >> 2)  & 0x1F);
637 	*np++ = '@' + ((id << 3)  & 0x18) + ((id >> 13) & 0x07);
638 	*np++ = '@' + ((id >> 8)  & 0x1F);
639 	*np++ = hextab[(id >> 20) & 0x0F];
640 	*np++ = hextab[(id >> 16) & 0x0F];
641 	*np++ = hextab[(id >> 28) & 0x0F];
642 	*np++ = hextab[(id >> 24) & 0x0F];
643 	*np = 0;
644 }
645 
646 /*
647  * process_cids() -- process multiple CIDs in a package
648  */
649 static void
650 process_cids(ACPI_OBJECT *rv, device_id_t **dd)
651 {
652 	device_id_t *d;
653 	char tmp_cidstr[8];	/* 7-character EISA ID */
654 	int i;
655 
656 	if ((rv->Package.Count == 0) || rv->Package.Elements == NULL)
657 		return; /* empty package */
658 
659 	/*
660 	 * Work the package 'backwards' so the resulting list is
661 	 * in original order of preference.
662 	 */
663 	for (i = rv->Package.Count - 1; i >= 0; i--) {
664 		/* get the actual acpi_object */
665 		ACPI_OBJECT obj = rv->Package.Elements[i];
666 		switch (obj.Type) {
667 		case ACPI_TYPE_INTEGER:
668 			eisa_to_str(obj.Integer.Value, tmp_cidstr);
669 			d = mf_alloc_device_id();
670 			d->id = strdup(tmp_cidstr);
671 			d->next = *dd;
672 			*dd = d;
673 			break;
674 		case ACPI_TYPE_STRING:
675 			d = mf_alloc_device_id();
676 			d->id = strdup(obj.String.Pointer);
677 			d->next = *dd;
678 			*dd = d;
679 			break;
680 		default:
681 			if (acpi_enum_debug & PROCESS_CIDS) {
682 				cmn_err(CE_NOTE, "unexpected CID type: %d",
683 				    obj.Type);
684 			}
685 			break;
686 		}
687 	}
688 }
689 
690 /*
691  * Convert "raw" PNP and ACPI IDs to IEEE 1275-compliant form.
692  * Some liberty is taken here, treating "ACPI" as a special form
693  * of PNP vendor ID.  strsize specifies size of buffer.
694  */
695 static void
696 convert_to_pnp1275(char *pnpid, char *str, int strsize)
697 {
698 	char	vendor[5];
699 	uint_t	id;
700 
701 	if (strncmp(pnpid, "ACPI", 4) == 0) {
702 		/* Assume ACPI ID: ACPIxxxx */
703 		sscanf(pnpid, "%4s%x", vendor, &id);
704 	} else {
705 		/* Assume PNP ID: aaaxxxx */
706 		sscanf(pnpid, "%3s%x", vendor, &id);
707 	}
708 
709 	snprintf(str, strsize, "pnp%s,%x", vendor, id);
710 }
711 
712 /*
713  * Given a list of device ID elements in most-to-least-specific
714  * order, create a "compatible" property.
715  */
716 static void
717 create_compatible_property(dev_info_t *dip, device_id_t *ids)
718 {
719 	char		**strs;
720 	int		list_len, i;
721 	device_id_t	*d;
722 
723 	/* count list length */
724 	list_len = 0;
725 	d = ids;
726 	while (d != NULL) {
727 		list_len++;
728 		d = d->next;
729 	}
730 
731 	/* create string array */
732 	strs = (char **)kmem_zalloc(list_len * sizeof (char *), KM_SLEEP);
733 	i = 0;
734 	d = ids;
735 	while (d != NULL) {
736 		/* strlen("pnpXXXX,xxxx") + 1 = 13 */
737 		strs[i] = kmem_zalloc(13, KM_SLEEP);
738 		convert_to_pnp1275(d->id, strs[i++], 13);
739 		d = d->next;
740 	}
741 
742 	/* update property */
743 	(void) ndi_prop_update_string_array(DDI_DEV_T_NONE, dip,
744 	    "compatible", strs, list_len);
745 
746 
747 	/* free memory */
748 	for (i = 0; i < list_len; i++)
749 		kmem_free(strs[i], 13);
750 
751 	kmem_free(strs, list_len * sizeof (char *));
752 }
753 
754 /*
755  * isa_acpi_callback()
756  */
757 static ACPI_STATUS
758 isa_acpi_callback(ACPI_HANDLE ObjHandle, uint32_t NestingLevel, void *a,
759     void **b)
760 {
761 	_NOTE(ARGUNUSED(NestingLevel, b))
762 
763 	ACPI_BUFFER	rb;
764 	ACPI_DEVICE_INFO *info = NULL;
765 	char		*path = NULL;
766 	char		*hidstr = NULL;
767 	char		tmp_cidstr[8];	/* EISAID size */
768 	dev_info_t	*dip = (dev_info_t *)a;
769 	dev_info_t	*xdip = NULL;
770 	device_id_t	*d, *device_ids = NULL;
771 	const master_rec_t	*m;
772 	int		compatible_present = 0;
773 
774 	/*
775 	 * get full ACPI pathname for object
776 	 */
777 	rb.Length = ACPI_ALLOCATE_BUFFER;
778 	rb.Pointer = NULL;
779 	if (AcpiGetName(ObjHandle, ACPI_FULL_PATHNAME, &rb) != AE_OK) {
780 		cmn_err(CE_WARN, "!acpi_enum: could not get pathname");
781 		goto done;
782 	}
783 	path = (char *)rb.Pointer;
784 
785 	/*
786 	 * Get device info object
787 	 */
788 	rb.Length = ACPI_ALLOCATE_BUFFER;
789 	rb.Pointer = NULL;
790 	if (AcpiGetObjectInfo(ObjHandle, &rb) != AE_OK) {
791 		cmn_err(CE_WARN, "!acpi_enum: could not get device"
792 		    " info for %s", path);
793 		goto done;
794 	}
795 	info = (ACPI_DEVICE_INFO *)rb.Pointer;
796 
797 	/*
798 	 * If device isn't present, we don't enumerate
799 	 * NEEDSWORK: what about docking bays and the like?
800 	 */
801 	if (info->Valid & ACPI_VALID_STA) {
802 		/*
803 		 * CA 6.3.6 _STA method
804 		 * Bit 0 -- device is present
805 		 * Bit 1 -- device is enabled
806 		 * Bit 2 -- device is shown in UI
807 		 */
808 		if (!((info->CurrentStatus & 0x7) == 7)) {
809 			goto done;
810 		}
811 	} else {
812 		cmn_err(CE_WARN, "!acpi_enum: no _STA for %s", path);
813 		goto done;
814 	}
815 
816 	/*
817 	 * Keep track of _HID value
818 	 */
819 	if (!(info->Valid & ACPI_VALID_HID)) {
820 		/* No _HID, we skip this node */
821 		goto done;
822 	}
823 	hidstr = info->HardwareId.Value;
824 
825 	/*
826 	 * Attempt to get _CID value
827 	 */
828 	rb.Length = ACPI_ALLOCATE_BUFFER;
829 	rb.Pointer = NULL;
830 	if (AcpiEvaluateObject(ObjHandle, "_CID", NULL, &rb) == AE_OK &&
831 	    rb.Length != 0) {
832 		ACPI_OBJECT *rv = rb.Pointer;
833 
834 		switch (rv->Type) {
835 		case ACPI_TYPE_INTEGER:
836 			eisa_to_str(rv->Integer.Value, tmp_cidstr);
837 			d = mf_alloc_device_id();
838 			d->id = strdup(tmp_cidstr);
839 			d->next = device_ids;
840 			device_ids = d;
841 			break;
842 		case ACPI_TYPE_STRING:
843 			d = mf_alloc_device_id();
844 			d->id = strdup(rv->String.Pointer);
845 			d->next = device_ids;
846 			device_ids = d;
847 			break;
848 		case ACPI_TYPE_PACKAGE:
849 			process_cids(rv, &device_ids);
850 			break;
851 		default:
852 			break;
853 		}
854 		AcpiOsFree(rb.Pointer);
855 	}
856 
857 	/*
858 	 * Add _HID last so it's at the head of the list
859 	 */
860 	d = mf_alloc_device_id();
861 	d->id = strdup(hidstr);
862 	d->next = device_ids;
863 	device_ids = d;
864 
865 	/*
866 	 * master_file_lookup() expects _HID first in device_ids
867 	 */
868 	if ((m = master_file_lookup(device_ids)) !=  NULL) {
869 		/* PNP description found in master table */
870 		if (!(strncmp(hidstr, "ACPI", 4))) {
871 			dip = ddi_root_node();
872 		} else {
873 			dip = get_bus_dip(m->name, dip);
874 		}
875 		ndi_devi_alloc_sleep(dip, m->name,
876 		    (pnode_t)DEVI_SID_NODEID, &xdip);
877 		(void) ndi_prop_update_string(DDI_DEV_T_NONE, xdip,
878 		    "model", m->description);
879 		compatible_present = process_properties(xdip, m->properties);
880 	} else {
881 		/* for ISA devices not known to the master file */
882 		if (!(strncmp(hidstr, "PNP03", 5))) {
883 			/* a keyboard device includes PNP03xx */
884 			dip = get_bus_dip(keyboard_alias, dip);
885 			ndi_devi_alloc_sleep(dip, keyboard_alias,
886 			    (pnode_t)DEVI_SID_NODEID, &xdip);
887 			(void) ndi_prop_update_string(DDI_DEV_T_NONE, xdip,
888 			    "compatible", "pnpPNP,303");
889 			(void) ndi_prop_update_string(DDI_DEV_T_NONE, xdip,
890 			    "model", "PNP03xx keyboard");
891 		} else {
892 			if (!(strncmp(hidstr, "PNP0F", 5))) {
893 				/* a mouse device include PNP0Fxx */
894 				dip = get_bus_dip(mouse_alias, dip);
895 				ndi_devi_alloc_sleep(dip, mouse_alias,
896 				    (pnode_t)DEVI_SID_NODEID, &xdip);
897 				(void) ndi_prop_update_string(DDI_DEV_T_NONE,
898 				    xdip, "compatible", "pnpPNP,f03");
899 				(void) ndi_prop_update_string(DDI_DEV_T_NONE,
900 				    xdip, "model", "PNP0Fxx mouse");
901 			} else {
902 				(void) parse_resources(ObjHandle, xdip);
903 				goto done;
904 			}
905 		}
906 	}
907 
908 	(void) ndi_prop_update_string(DDI_DEV_T_NONE, xdip, "acpi-namespace",
909 	    path);
910 
911 	(void) parse_resources(ObjHandle, xdip);
912 
913 	/* Special processing for mouse and keyboard devices per IEEE 1275 */
914 	/* if master entry doesn't contain "compatible" then we add default */
915 	if (strcmp(m->name, keyboard_alias) == 0) {
916 		(void) ndi_prop_update_int(DDI_DEV_T_NONE, xdip, "reg", 0);
917 		(void) ndi_prop_update_string(DDI_DEV_T_NONE, xdip,
918 		    "device-type", keyboard_alias);
919 		if (!compatible_present)
920 			(void) ndi_prop_update_string(DDI_DEV_T_NONE, xdip,
921 			    "compatible", "pnpPNP,303");
922 	} else if (strcmp(m->name, mouse_alias) == 0) {
923 		(void) ndi_prop_update_int(DDI_DEV_T_NONE, xdip, "reg", 1);
924 		(void) ndi_prop_update_string(DDI_DEV_T_NONE, xdip,
925 		    "device-type", mouse_alias);
926 		if (!compatible_present)
927 			(void) ndi_prop_update_string(DDI_DEV_T_NONE, xdip,
928 			    "compatible", "pnpPNP,f03");
929 	}
930 
931 	/*
932 	 * Create default "compatible" property if required
933 	 */
934 	if (!ddi_prop_exists(DDI_DEV_T_ANY, xdip,
935 	    DDI_PROP_DONTPASS, "compatible"))
936 		create_compatible_property(xdip, device_ids);
937 
938 	(void) ndi_devi_bind_driver(xdip, 0);
939 
940 done:
941 	/* discard _HID/_CID list */
942 	d = device_ids;
943 	while (d != NULL) {
944 		device_id_t *next;
945 
946 		next = d->next;
947 		mf_free_device_id(d);
948 		d = next;
949 	}
950 
951 	if (path != NULL)
952 		AcpiOsFree(path);
953 	if (info != NULL)
954 		AcpiOsFree(info);
955 
956 	return (AE_OK);
957 }
958 
959 static void
960 used_res_interrupts(void)
961 {
962 	int intr[ACPI_ISA_LIMIT];
963 	int count = 0;
964 	int i;
965 
966 	for (i = 0; i < ACPI_ISA_LIMIT; i++) {
967 		if ((used_interrupts >> i) & 1) {
968 			intr[count++] = i;
969 		}
970 	}
971 	(void) ndi_prop_update_int_array(DDI_DEV_T_NONE, usedrdip,
972 	    "interrupts", (int *)intr, count);
973 }
974 
975 static void
976 used_res_dmas(void)
977 {
978 	int dma[ACPI_ISA_LIMIT];
979 	int count = 0;
980 	int i;
981 
982 	for (i = 0; i < ACPI_ISA_LIMIT; i++) {
983 		if ((used_dmas >> i) & 1) {
984 			dma[count++] = i;
985 		}
986 	}
987 	(void) ndi_prop_update_int_array(DDI_DEV_T_NONE, usedrdip,
988 	    "dma-channels", (int *)dma, count);
989 }
990 
991 static void
992 used_res_io_mem(char *nodename, int *count, used_io_mem_t **head)
993 {
994 	int *io;
995 	used_io_mem_t *used = *head;
996 	int i;
997 
998 	*count *= 2;
999 	io = (int *)kmem_zalloc(sizeof (int)*(*count), KM_SLEEP);
1000 	for (i = 0; i < *count; i += 2) {
1001 		used_io_mem_t *prev;
1002 		if (used != NULL) {
1003 			io[i] = used->start_addr;
1004 			io[i+1] = used->length;
1005 			prev = used;
1006 			used = used->next;
1007 			kmem_free(prev, sizeof (used_io_mem_t));
1008 		}
1009 	}
1010 	(void) ndi_prop_update_int_array(DDI_DEV_T_NONE, usedrdip,
1011 	    nodename, (int *)io, *count);
1012 	kmem_free(io, sizeof (int)*(*count));
1013 	*head = NULL;
1014 }
1015 
1016 /*
1017  * acpi_isa_device_enum() -- call from isa nexus driver
1018  * returns 1 if deviced enumeration is successful
1019  *         0 if deviced enumeration fails
1020  */
1021 int
1022 acpi_isa_device_enum(dev_info_t *isa_dip)
1023 {
1024 	char *acpi_prop;
1025 
1026 	if (ddi_prop_lookup_string(DDI_DEV_T_ANY, ddi_root_node(),
1027 	    DDI_PROP_DONTPASS, ACPI_ENUM_DEBUG, &acpi_prop) ==
1028 	    DDI_PROP_SUCCESS) {
1029 		long data;
1030 		if (ddi_strtol(acpi_prop, NULL, 0, &data) == 0) {
1031 			acpi_enum_debug = (unsigned long)data;
1032 			e_ddi_prop_remove(DDI_DEV_T_NONE, ddi_root_node(),
1033 			    ACPI_ENUM_DEBUG);
1034 			e_ddi_prop_update_int(DDI_DEV_T_NONE,
1035 			    ddi_root_node(), ACPI_ENUM_DEBUG, data);
1036 		}
1037 		ddi_prop_free(acpi_prop);
1038 	}
1039 
1040 	if (acpi_enum_debug & ISA_DEVICE_ENUM) {
1041 		cmn_err(CE_NOTE, "acpi_isa_device_enum() called");
1042 	}
1043 
1044 	if (acpica_init() != AE_OK) {
1045 		cmn_err(CE_WARN, "!isa_enum: init failed");
1046 		/* Note, pickup by i8042 nexus */
1047 		(void) e_ddi_prop_update_string(DDI_DEV_T_NONE,
1048 		    ddi_root_node(), "acpi-enum", "off");
1049 		return (0);
1050 	}
1051 
1052 	usedrdip = ddi_find_devinfo(USED_RESOURCES, -1, 0);
1053 	if (usedrdip == NULL) {
1054 		ndi_devi_alloc_sleep(ddi_root_node(), USED_RESOURCES,
1055 		    (pnode_t)DEVI_SID_NODEID, &usedrdip);
1056 
1057 	}
1058 
1059 	process_master_file();
1060 
1061 	/*
1062 	 * Do the actual enumeration
1063 	 */
1064 	(void) AcpiGetDevices(NULL, isa_acpi_callback, isa_dip, 0);
1065 
1066 	free_master_data();
1067 	used_res_interrupts();
1068 	used_res_dmas();
1069 	used_res_io_mem("device-memory", &used_mem_count, &used_mem_head);
1070 	used_res_io_mem("io-space", &used_io_count, &used_io_head);
1071 	(void) ndi_devi_bind_driver(usedrdip, 0);
1072 
1073 	return (1);
1074 }
1075