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