xref: /illumos-gate/usr/src/uts/intel/io/acpica/acpi_enum.c (revision bde334a8dbd66dfa70ce4d7fc9dcad6e1ae45fe4)
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 2018, Joyent, Inc.
23  * Copyright (c) 2012 Gary Mills
24  *
25  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
26  * Use is subject to license terms.
27  */
28 
29 /*
30  * ACPI enumerator
31  */
32 
33 #include <sys/ddi.h>
34 #include <sys/sunddi.h>
35 #include <sys/sunndi.h>
36 #include <sys/note.h>
37 #include <sys/acpi/acpi.h>
38 #include <sys/acpica.h>
39 #include <util/sscanf.h>
40 
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 	if (acpi_io.AddressLength == 0)
169 		return;
170 
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",
177 		    acpi_io.Minimum,
178 		    acpi_io.Maximum,
179 		    acpi_io.AddressLength);
180 	}
181 	(*io_count)++;
182 }
183 
184 static void
185 parse_resources_fixed_io(ACPI_RESOURCE *resource_ptr, struct regspec *io,
186     int *io_count)
187 {
188 	ACPI_RESOURCE_FIXED_IO fixed_io = resource_ptr->Data.FixedIo;
189 
190 	if (fixed_io.AddressLength == 0)
191 		return;
192 
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);
200 	}
201 	(*io_count)++;
202 }
203 
204 static void
205 parse_resources_fixed_mem32(ACPI_RESOURCE *resource_ptr, struct regspec *io,
206     int *io_count)
207 {
208 	ACPI_RESOURCE_FIXED_MEMORY32 fixed_mem32 =
209 	    resource_ptr->Data.FixedMemory32;
210 
211 	if (fixed_mem32.AddressLength == 0)
212 		return;
213 
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);
221 	}
222 	(*io_count)++;
223 }
224 
225 static void
226 parse_resources_mem32(ACPI_RESOURCE *resource_ptr, struct regspec *io,
227     int *io_count)
228 {
229 	ACPI_RESOURCE_MEMORY32 mem32 = resource_ptr->Data.Memory32;
230 
231 	if (mem32.AddressLength == 0)
232 		return;
233 
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;
239 		(*io_count)++;
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);
244 		}
245 		return;
246 	}
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);
253 	}
254 }
255 
256 static void
257 parse_resources_addr16(ACPI_RESOURCE *resource_ptr, struct regspec *io,
258     int *io_count)
259 {
260 	ACPI_RESOURCE_ADDRESS16 addr16 =
261 	    resource_ptr->Data.Address16;
262 
263 	if (addr16.Address.AddressLength == 0)
264 		return;
265 
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");
270 		} else
271 		if (addr16.ResourceType == ACPI_IO_RANGE) {
272 			cmn_err(CE_NOTE, "!parse_resources() "\
273 			    "ADDRESS 16 IO RANGE");
274 		} else {
275 			cmn_err(CE_NOTE, "!parse_resources() "\
276 			    "ADDRESS 16 OTHER");
277 		}
278 		cmn_err(CE_NOTE, "!parse_resources() "\
279 		    "%s "\
280 		    "MinAddressFixed 0x%X, "\
281 		    "MaxAddressFixed 0x%X, "\
282 		    "Minimum 0x%X, "\
283 		    "Maximum 0x%X, "\
284 		    "length: 0x%X\n",
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);
292 	}
293 	if (addr16.ProducerConsumer == ACPI_PRODUCER ||
294 	    (addr16.ResourceType != ACPI_MEMORY_RANGE &&
295 	    addr16.ResourceType != ACPI_IO_RANGE)) {
296 		return;
297 	}
298 	if (addr16.Address.AddressLength > 0) {
299 		if (addr16.ResourceType == ACPI_MEMORY_RANGE) {
300 			/* memory */
301 			io[*io_count].regspec_bustype = 0;
302 		} else {
303 			/* io */
304 			io[*io_count].regspec_bustype = 1;
305 		}
306 		io[*io_count].regspec_addr = addr16.Address.Minimum;
307 		io[*io_count].regspec_size = addr16.Address.AddressLength;
308 		(*io_count)++;
309 	}
310 }
311 
312 static void
313 parse_resources_addr32(ACPI_RESOURCE *resource_ptr, struct regspec *io,
314     int *io_count)
315 {
316 	ACPI_RESOURCE_ADDRESS32 addr32 =
317 	    resource_ptr->Data.Address32;
318 
319 	if (addr32.Address.AddressLength == 0)
320 		return;
321 
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");
326 		} else
327 		if (addr32.ResourceType == ACPI_IO_RANGE) {
328 			cmn_err(CE_NOTE, "!parse_resources() "\
329 			    "ADDRESS 32 IO RANGE");
330 		} else {
331 			cmn_err(CE_NOTE, "!parse_resources() "\
332 			    "ADDRESS 32 OTHER");
333 		}
334 		cmn_err(CE_NOTE, "!parse_resources() "\
335 		    "%s "\
336 		    "MinAddressFixed 0x%X, "\
337 		    "MaxAddressFixed 0x%X, "\
338 		    "Minimum 0x%X, "\
339 		    "Maximum 0x%X, "\
340 		    "length: 0x%X\n",
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);
348 	}
349 	if (addr32.ProducerConsumer == ACPI_PRODUCER ||
350 	    (addr32.ResourceType != ACPI_MEMORY_RANGE &&
351 	    addr32.ResourceType != ACPI_IO_RANGE)) {
352 		return;
353 	}
354 	if (addr32.Address.AddressLength > 0) {
355 		if (addr32.ResourceType == ACPI_MEMORY_RANGE) {
356 			/* memory */
357 			io[*io_count].regspec_bustype = 0;
358 		} else {
359 			/* io */
360 			io[*io_count].regspec_bustype = 1;
361 		}
362 		io[*io_count].regspec_addr = addr32.Address.Minimum;
363 		io[*io_count].regspec_size = addr32.Address.AddressLength;
364 		(*io_count)++;
365 	}
366 }
367 
368 static void
369 parse_resources_addr64(ACPI_RESOURCE *resource_ptr, struct regspec *io,
370     int *io_count)
371 {
372 	ACPI_RESOURCE_ADDRESS64 addr64 =
373 	    resource_ptr->Data.Address64;
374 
375 	if (addr64.Address.AddressLength == 0)
376 		return;
377 
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");
382 		} else
383 		if (addr64.ResourceType == ACPI_IO_RANGE) {
384 			cmn_err(CE_NOTE, "!parse_resources() "\
385 			    "ADDRESS 64 IO RANGE");
386 		} else {
387 			cmn_err(CE_NOTE, "!parse_resources() "\
388 			    "ADDRESS 64 OTHER");
389 		}
390 #ifdef _LP64
391 		cmn_err(CE_NOTE, "!parse_resources() "\
392 		    "%s "\
393 		    "MinAddressFixed 0x%X, "\
394 		    "MaxAddressFixed 0x%X, "\
395 		    "Minimum 0x%lX, "\
396 		    "Maximum 0x%lX, "\
397 		    "length: 0x%lX\n",
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);
405 #else
406 		cmn_err(CE_NOTE, "!parse_resources() "\
407 		    "%s "\
408 		    "MinAddressFixed 0x%X, "\
409 		    "MaxAddressFixed 0x%X, "\
410 		    "Minimum 0x%llX, "\
411 		    "Maximum 0x%llX, "\
412 		    "length: 0x%llX\n",
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);
420 #endif
421 	}
422 	if (addr64.ProducerConsumer == ACPI_PRODUCER ||
423 	    (addr64.ResourceType != ACPI_MEMORY_RANGE &&
424 	    addr64.ResourceType != ACPI_IO_RANGE)) {
425 		return;
426 	}
427 	if (addr64.Address.AddressLength > 0) {
428 		if (addr64.ResourceType == ACPI_MEMORY_RANGE) {
429 			/* memory */
430 			io[*io_count].regspec_bustype = 0;
431 		} else {
432 			/* io */
433 			io[*io_count].regspec_bustype = 1;
434 		}
435 		io[*io_count].regspec_addr = addr64.Address.Minimum;
436 		io[*io_count].regspec_size = addr64.Address.AddressLength;
437 		(*io_count)++;
438 	}
439 }
440 
441 static ACPI_STATUS
442 parse_resources(ACPI_HANDLE handle, dev_info_t *xdip, char *path)
443 {
444 	ACPI_BUFFER	buf;
445 	ACPI_RESOURCE	*resource_ptr;
446 	ACPI_STATUS	status;
447 	char		*current_ptr, *last_ptr;
448 	struct		regspec *io;
449 	int		io_count = 0, interrupt_count = 0, dma_count = 0;
450 	int		i;
451 
452 	buf.Length = ACPI_ALLOCATE_BUFFER;
453 	status = AcpiGetCurrentResources(handle, &buf);
454 	switch (status) {
455 	case AE_OK:
456 		break;
457 	case AE_NOT_FOUND:
458 		/*
459 		 * Workaround for faulty DSDT tables that omit the _CRS
460 		 * method for the UAR3 device but have a valid _PRS method
461 		 * for that device.
462 		 */
463 		status = AcpiGetPossibleResources(handle, &buf);
464 		if (status != AE_OK) {
465 			return (status);
466 		}
467 		break;
468 	default:
469 		cmn_err(CE_WARN,
470 		    "!AcpiGetCurrentResources failed for %s, exception: %s",
471 		    path, AcpiFormatException(status));
472 		return (status);
473 		break;
474 	}
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) {
481 			break;
482 		}
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;
488 			break;
489 		case ACPI_RESOURCE_TYPE_IO:
490 			parse_resources_io(resource_ptr, io, &io_count);
491 			break;
492 		case ACPI_RESOURCE_TYPE_FIXED_IO:
493 			parse_resources_fixed_io(resource_ptr, io, &io_count);
494 			break;
495 		case ACPI_RESOURCE_TYPE_FIXED_MEMORY32:
496 			parse_resources_fixed_mem32(resource_ptr, io,
497 			    &io_count);
498 			break;
499 		case ACPI_RESOURCE_TYPE_MEMORY32:
500 			parse_resources_mem32(resource_ptr, io, &io_count);
501 			break;
502 		case ACPI_RESOURCE_TYPE_ADDRESS16:
503 			parse_resources_addr16(resource_ptr, io, &io_count);
504 			break;
505 		case ACPI_RESOURCE_TYPE_ADDRESS32:
506 			parse_resources_addr32(resource_ptr, io, &io_count);
507 			break;
508 		case ACPI_RESOURCE_TYPE_ADDRESS64:
509 			parse_resources_addr64(resource_ptr, io, &io_count);
510 			break;
511 		case ACPI_RESOURCE_TYPE_IRQ:
512 			parse_resources_irq(resource_ptr, &interrupt_count);
513 			break;
514 		case ACPI_RESOURCE_TYPE_DMA:
515 			parse_resources_dma(resource_ptr, &dma_count);
516 			break;
517 		case ACPI_RESOURCE_TYPE_START_DEPENDENT:
518 			cmn_err(CE_NOTE,
519 			    "!ACPI source type"
520 			    " ACPI_RESOURCE_TYPE_START_DEPENDENT"
521 			    " not supported");
522 			break;
523 		case ACPI_RESOURCE_TYPE_END_DEPENDENT:
524 			cmn_err(CE_NOTE,
525 			    "!ACPI source type"
526 			    " ACPI_RESOURCE_TYPE_END_DEPENDENT"
527 			    " not supported");
528 			break;
529 		case ACPI_RESOURCE_TYPE_VENDOR:
530 			cmn_err(CE_NOTE,
531 			    "!ACPI source type"
532 			    " ACPI_RESOURCE_TYPE_VENDOR"
533 			    " not supported");
534 			break;
535 		case ACPI_RESOURCE_TYPE_MEMORY24:
536 			cmn_err(CE_NOTE,
537 			    "!ACPI source type"
538 			    " ACPI_RESOURCE_TYPE_MEMORY24"
539 			    " not supported");
540 			break;
541 		case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
542 			cmn_err(CE_NOTE,
543 			    "!ACPI source type"
544 			    " ACPI_RESOURCE_TYPE_EXT_IRQ"
545 			    " not supported");
546 			break;
547 		default:
548 		/* Some types are not yet implemented (See CA 6.4) */
549 			cmn_err(CE_NOTE,
550 			    "!ACPI resource type (0X%X) not yet supported",
551 			    resource_ptr->Type);
552 			break;
553 		}
554 	}
555 
556 	if (io_count) {
557 		/*
558 		 * on LX50, you get interrupts of mouse and keyboard
559 		 * from separate PNP id...
560 		 */
561 		if (io_count == 2) {
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)) {
566 				interrupt[0] = 0x1;
567 				interrupt[1] = 0xc;
568 				interrupt_count = 2;
569 				used_interrupts |=
570 				    1 << interrupt[0];
571 				used_interrupts |=
572 				    1 << interrupt[1];
573 			}
574 		}
575 		add_used_io_mem(io, io_count);
576 		if (xdip != NULL) {
577 			(void) ndi_prop_update_int_array(DDI_DEV_T_NONE, xdip,
578 			    "reg", (int *)io, 3*io_count);
579 		}
580 	}
581 	if (interrupt_count && (xdip != NULL)) {
582 		(void) ndi_prop_update_int_array(DDI_DEV_T_NONE, xdip,
583 		    "interrupts", (int *)interrupt, interrupt_count);
584 	}
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);
588 	}
589 	AcpiOsFree(buf.Pointer);
590 	kmem_free(io, sizeof (struct regspec) * MAX_PARSED_ACPI_RESOURCES);
591 	return (status);
592 }
593 
594 /* keyboard mouse is under i8042, everything else under isa */
595 static dev_info_t *
596 get_bus_dip(char *nodename, dev_info_t *isa_dip)
597 {
598 	static dev_info_t *i8042_dip = NULL;
599 	struct regspec i8042_regs[] = {
600 		{1, 0x60, 0x1},
601 		{1, 0x64, 0x1}
602 	};
603 	int i8042_intrs[] = {0x1, 0xc};
604 
605 	if (strcmp(nodename, keyboard_alias) != 0 &&
606 	    strcmp(nodename, mouse_alias) != 0)
607 		return (isa_dip);
608 
609 	if (i8042_dip)
610 		return (i8042_dip);
611 
612 	ndi_devi_alloc_sleep(isa_dip, "i8042", (pnode_t)DEVI_SID_NODEID,
613 	    &i8042_dip);
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);
621 	return (i8042_dip);
622 }
623 
624 /*
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
627  *
628  */
629 static int
630 process_properties(dev_info_t *xdip, property_t *properties)
631 {
632 	int	rv = 0;
633 
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)
638 			rv = 1;
639 		properties = properties->next;
640 	}
641 
642 	return (rv);
643 }
644 
645 void
646 eisa_to_str(ACPI_INTEGER id, char *np)
647 {
648 	static const char hextab[] = "0123456789ABCDEF";
649 
650 	/*
651 	 *  Expand an EISA device name:
652 	 *
653 	 * This routine converts a 32-bit EISA device "id" to a
654 	 * 7-byte ASCII device name, which is stored at "np".
655 	 */
656 
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];
664 	*np = 0;
665 }
666 
667 /*
668  * process_cids() -- process multiple CIDs in a package
669  */
670 static void
671 process_cids(ACPI_OBJECT *rv, device_id_t **dd)
672 {
673 	device_id_t *d;
674 	char tmp_cidstr[8];	/* 7-character EISA ID */
675 	int i;
676 
677 	if ((rv->Package.Count == 0) || rv->Package.Elements == NULL)
678 		return; /* empty package */
679 
680 	/*
681 	 * Work the package 'backwards' so the resulting list is
682 	 * in original order of preference.
683 	 */
684 	for (i = rv->Package.Count - 1; i >= 0; i--) {
685 		/* get the actual acpi_object */
686 		ACPI_OBJECT obj = rv->Package.Elements[i];
687 		switch (obj.Type) {
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);
692 			d->next = *dd;
693 			*dd = d;
694 			break;
695 		case ACPI_TYPE_STRING:
696 			d = mf_alloc_device_id();
697 			d->id = strdup(obj.String.Pointer);
698 			d->next = *dd;
699 			*dd = d;
700 			break;
701 		default:
702 			if (acpi_enum_debug & PROCESS_CIDS) {
703 				cmn_err(CE_NOTE, "!unexpected CID type: %d",
704 				    obj.Type);
705 			}
706 			break;
707 		}
708 	}
709 }
710 
711 /*
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.
715  */
716 static void
717 convert_to_pnp1275(char *pnpid, char *str, int strsize)
718 {
719 	char	vendor[5];
720 	uint_t	id;
721 
722 	if (strncmp(pnpid, "ACPI", 4) == 0) {
723 		/* Assume ACPI ID: ACPIxxxx */
724 		sscanf(pnpid, "%4s%x", vendor, &id);
725 	} else {
726 		/* Assume PNP ID: aaaxxxx */
727 		sscanf(pnpid, "%3s%x", vendor, &id);
728 	}
729 
730 	snprintf(str, strsize, "pnp%s,%x", vendor, id);
731 }
732 
733 /*
734  * Given a list of device ID elements in most-to-least-specific
735  * order, create a "compatible" property.
736  */
737 static void
738 create_compatible_property(dev_info_t *dip, device_id_t *ids)
739 {
740 	char		**strs;
741 	int		list_len, i;
742 	device_id_t	*d;
743 
744 	/* count list length */
745 	list_len = 0;
746 	d = ids;
747 	while (d != NULL) {
748 		list_len++;
749 		d = d->next;
750 	}
751 
752 	/* create string array */
753 	strs = (char **)kmem_zalloc(list_len * sizeof (char *), KM_SLEEP);
754 	i = 0;
755 	d = ids;
756 	while (d != NULL) {
757 		/* strlen("pnpXXXX,xxxx") + 1 = 13 */
758 		strs[i] = kmem_zalloc(13, KM_SLEEP);
759 		convert_to_pnp1275(d->id, strs[i++], 13);
760 		d = d->next;
761 	}
762 
763 	/* update property */
764 	(void) ndi_prop_update_string_array(DDI_DEV_T_NONE, dip,
765 	    "compatible", strs, list_len);
766 
767 
768 	/* free memory */
769 	for (i = 0; i < list_len; i++)
770 		kmem_free(strs[i], 13);
771 
772 	kmem_free(strs, list_len * sizeof (char *));
773 }
774 
775 /*
776  * isa_acpi_callback()
777  */
778 static ACPI_STATUS
779 isa_acpi_callback(ACPI_HANDLE ObjHandle, uint32_t NestingLevel, void *a,
780     void **b)
781 {
782 	_NOTE(ARGUNUSED(NestingLevel, b))
783 
784 	ACPI_BUFFER	rb;
785 	ACPI_DEVICE_INFO *info = NULL;
786 	char		*path = NULL;
787 	char		*hidstr = 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;
794 	int		status;
795 
796 	/*
797 	 * get full ACPI pathname for object
798 	 */
799 	rb.Length = ACPI_ALLOCATE_BUFFER;
800 	rb.Pointer = NULL;
801 	if (AcpiGetName(ObjHandle, ACPI_FULL_PATHNAME, &rb) != AE_OK) {
802 		cmn_err(CE_WARN, "!acpi_enum: could not get pathname");
803 		goto done;
804 	}
805 	path = (char *)rb.Pointer;
806 
807 	/*
808 	 * Get device info object
809 	 */
810 	if (AcpiGetObjectInfo(ObjHandle, &info) != AE_OK) {
811 		cmn_err(CE_WARN, "!acpi_enum: could not get device"
812 		    " info for %s", path);
813 		goto done;
814 	}
815 
816 	/*
817 	 * If device isn't present, we don't enumerate
818 	 * NEEDSWORK: what about docking bays and the like?
819 	 */
820 	if (ACPI_FAILURE(acpica_get_object_status(ObjHandle, &status))) {
821 		cmn_err(CE_WARN, "!acpi_enum: no _STA for %s", path);
822 		goto done;
823 	}
824 
825 	/*
826 	 * CA 6.3.6 _STA method
827 	 * Bit 0 -- device is present
828 	 * Bit 1 -- device is enabled
829 	 * Bit 2 -- device is shown in UI
830 	 */
831 	if ((status & 0x7) != 0x7) {
832 		if (acpi_enum_debug & DEVICES_NOT_ENUMED) {
833 			cmn_err(CE_NOTE, "!parse_resources() "
834 			    "Bad status 0x%x for %s",
835 			    status, path);
836 		}
837 		goto done;
838 	}
839 
840 	/*
841 	 * Keep track of _HID value
842 	 */
843 	if (!(info->Valid & ACPI_VALID_HID)) {
844 		/* No _HID, we skip this node */
845 		if (acpi_enum_debug & DEVICES_NOT_ENUMED) {
846 			cmn_err(CE_NOTE, "!parse_resources() "
847 			    "No _HID for %s", path);
848 		}
849 		goto done;
850 	}
851 	hidstr = info->HardwareId.String;
852 
853 	/*
854 	 * Attempt to get _CID value
855 	 */
856 	rb.Length = ACPI_ALLOCATE_BUFFER;
857 	rb.Pointer = NULL;
858 	if (AcpiEvaluateObject(ObjHandle, "_CID", NULL, &rb) == AE_OK &&
859 	    rb.Length != 0) {
860 		ACPI_OBJECT *rv = rb.Pointer;
861 
862 		switch (rv->Type) {
863 		case ACPI_TYPE_INTEGER:
864 			eisa_to_str(rv->Integer.Value, tmp_cidstr);
865 			d = mf_alloc_device_id();
866 			d->id = strdup(tmp_cidstr);
867 			d->next = device_ids;
868 			device_ids = d;
869 			break;
870 		case ACPI_TYPE_STRING:
871 			d = mf_alloc_device_id();
872 			d->id = strdup(rv->String.Pointer);
873 			d->next = device_ids;
874 			device_ids = d;
875 			break;
876 		case ACPI_TYPE_PACKAGE:
877 			process_cids(rv, &device_ids);
878 			break;
879 		default:
880 			break;
881 		}
882 		AcpiOsFree(rb.Pointer);
883 	}
884 
885 	/*
886 	 * Add _HID last so it's at the head of the list
887 	 */
888 	d = mf_alloc_device_id();
889 	d->id = strdup(hidstr);
890 	d->next = device_ids;
891 	device_ids = d;
892 
893 	/*
894 	 * master_file_lookup() expects _HID first in device_ids
895 	 */
896 	if ((m = master_file_lookup(device_ids)) !=  NULL) {
897 		/* PNP description found in master table */
898 		if (!(strncmp(hidstr, "ACPI", 4))) {
899 			dip = ddi_root_node();
900 		} else {
901 			dip = get_bus_dip(m->name, dip);
902 		}
903 		ndi_devi_alloc_sleep(dip, m->name,
904 		    (pnode_t)DEVI_SID_NODEID, &xdip);
905 		(void) ndi_prop_update_string(DDI_DEV_T_NONE, xdip,
906 		    "model", m->description);
907 		compatible_present = process_properties(xdip, m->properties);
908 	} else {
909 		/* for ISA devices not known to the master file */
910 		if (!(strncmp(hidstr, "PNP03", 5))) {
911 			/* a keyboard device includes PNP03xx */
912 			dip = get_bus_dip(keyboard_alias, dip);
913 			ndi_devi_alloc_sleep(dip, keyboard_alias,
914 			    (pnode_t)DEVI_SID_NODEID, &xdip);
915 			(void) ndi_prop_update_string(DDI_DEV_T_NONE, xdip,
916 			    "compatible", "pnpPNP,303");
917 			(void) ndi_prop_update_string(DDI_DEV_T_NONE, xdip,
918 			    "model", "PNP03xx keyboard");
919 		} else {
920 			if (!(strncmp(hidstr, "PNP0F", 5))) {
921 				/* a mouse device include PNP0Fxx */
922 				dip = get_bus_dip(mouse_alias, dip);
923 				ndi_devi_alloc_sleep(dip, mouse_alias,
924 				    (pnode_t)DEVI_SID_NODEID, &xdip);
925 				(void) ndi_prop_update_string(DDI_DEV_T_NONE,
926 				    xdip, "compatible", "pnpPNP,f03");
927 				(void) ndi_prop_update_string(DDI_DEV_T_NONE,
928 				    xdip, "model", "PNP0Fxx mouse");
929 			} else {
930 				(void) parse_resources(ObjHandle, xdip, path);
931 				goto done;
932 			}
933 		}
934 	}
935 
936 	(void) ndi_prop_update_string(DDI_DEV_T_NONE, xdip, "acpi-namespace",
937 	    path);
938 
939 	(void) parse_resources(ObjHandle, xdip, path);
940 
941 	/* Special processing for mouse and keyboard devices per IEEE 1275 */
942 	/* if master entry doesn't contain "compatible" then we add default */
943 	if (strcmp(m->name, keyboard_alias) == 0) {
944 		(void) ndi_prop_update_int(DDI_DEV_T_NONE, xdip, "reg", 0);
945 		(void) ndi_prop_update_string(DDI_DEV_T_NONE, xdip,
946 		    "device-type", keyboard_alias);
947 		if (!compatible_present)
948 			(void) ndi_prop_update_string(DDI_DEV_T_NONE, xdip,
949 			    "compatible", "pnpPNP,303");
950 	} else if (strcmp(m->name, mouse_alias) == 0) {
951 		(void) ndi_prop_update_int(DDI_DEV_T_NONE, xdip, "reg", 1);
952 		(void) ndi_prop_update_string(DDI_DEV_T_NONE, xdip,
953 		    "device-type", mouse_alias);
954 		if (!compatible_present)
955 			(void) ndi_prop_update_string(DDI_DEV_T_NONE, xdip,
956 			    "compatible", "pnpPNP,f03");
957 	}
958 
959 	/*
960 	 * Create default "compatible" property if required
961 	 */
962 	if (!ddi_prop_exists(DDI_DEV_T_ANY, xdip,
963 	    DDI_PROP_DONTPASS, "compatible"))
964 		create_compatible_property(xdip, device_ids);
965 
966 	(void) ndi_devi_bind_driver(xdip, 0);
967 
968 done:
969 	/* discard _HID/_CID list */
970 	d = device_ids;
971 	while (d != NULL) {
972 		device_id_t *next;
973 
974 		next = d->next;
975 		mf_free_device_id(d);
976 		d = next;
977 	}
978 
979 	if (path != NULL)
980 		AcpiOsFree(path);
981 	if (info != NULL)
982 		AcpiOsFree(info);
983 
984 	return (AE_OK);
985 }
986 
987 static void
988 used_res_interrupts(void)
989 {
990 	int intr[ACPI_ISA_LIMIT];
991 	int count = 0;
992 	int i;
993 
994 	for (i = 0; i < ACPI_ISA_LIMIT; i++) {
995 		if ((used_interrupts >> i) & 1) {
996 			intr[count++] = i;
997 		}
998 	}
999 	(void) ndi_prop_update_int_array(DDI_DEV_T_NONE, usedrdip,
1000 	    "interrupts", (int *)intr, count);
1001 }
1002 
1003 static void
1004 used_res_dmas(void)
1005 {
1006 	int dma[ACPI_ISA_LIMIT];
1007 	int count = 0;
1008 	int i;
1009 
1010 	for (i = 0; i < ACPI_ISA_LIMIT; i++) {
1011 		if ((used_dmas >> i) & 1) {
1012 			dma[count++] = i;
1013 		}
1014 	}
1015 	(void) ndi_prop_update_int_array(DDI_DEV_T_NONE, usedrdip,
1016 	    "dma-channels", (int *)dma, count);
1017 }
1018 
1019 static void
1020 used_res_io_mem(char *nodename, int *count, used_io_mem_t **head)
1021 {
1022 	int *io;
1023 	used_io_mem_t *used = *head;
1024 	int i;
1025 
1026 	*count *= 2;
1027 	io = (int *)kmem_zalloc(sizeof (int)*(*count), KM_SLEEP);
1028 	for (i = 0; i < *count; i += 2) {
1029 		used_io_mem_t *prev;
1030 		if (used != NULL) {
1031 			io[i] = used->start_addr;
1032 			io[i+1] = used->length;
1033 			prev = used;
1034 			used = used->next;
1035 			kmem_free(prev, sizeof (used_io_mem_t));
1036 		}
1037 	}
1038 	(void) ndi_prop_update_int_array(DDI_DEV_T_NONE, usedrdip,
1039 	    nodename, (int *)io, *count);
1040 	kmem_free(io, sizeof (int)*(*count));
1041 	*head = NULL;
1042 }
1043 
1044 /*
1045  * acpi_isa_device_enum() -- call from isa nexus driver
1046  * returns 1 if deviced enumeration is successful
1047  *         0 if deviced enumeration fails
1048  */
1049 int
1050 acpi_isa_device_enum(dev_info_t *isa_dip)
1051 {
1052 	char *acpi_prop;
1053 
1054 	if (ddi_prop_lookup_string(DDI_DEV_T_ANY, ddi_root_node(),
1055 	    DDI_PROP_DONTPASS, ACPI_ENUM_DEBUG, &acpi_prop) ==
1056 	    DDI_PROP_SUCCESS) {
1057 		long data;
1058 		if (ddi_strtol(acpi_prop, NULL, 0, &data) == 0) {
1059 			acpi_enum_debug = (unsigned long)data;
1060 			e_ddi_prop_remove(DDI_DEV_T_NONE, ddi_root_node(),
1061 			    ACPI_ENUM_DEBUG);
1062 			e_ddi_prop_update_int(DDI_DEV_T_NONE,
1063 			    ddi_root_node(), ACPI_ENUM_DEBUG, data);
1064 		}
1065 		ddi_prop_free(acpi_prop);
1066 	}
1067 
1068 	if (acpi_enum_debug & ISA_DEVICE_ENUM) {
1069 		cmn_err(CE_NOTE, "!acpi_isa_device_enum() called");
1070 	}
1071 
1072 	if (acpica_init() != AE_OK) {
1073 		cmn_err(CE_WARN, "!isa_enum: init failed");
1074 		/* Note, pickup by i8042 nexus */
1075 		(void) e_ddi_prop_update_string(DDI_DEV_T_NONE,
1076 		    ddi_root_node(), "acpi-enum", "off");
1077 		return (0);
1078 	}
1079 
1080 	usedrdip = ddi_find_devinfo(USED_RESOURCES, -1, 0);
1081 	if (usedrdip == NULL) {
1082 		ndi_devi_alloc_sleep(ddi_root_node(), USED_RESOURCES,
1083 		    (pnode_t)DEVI_SID_NODEID, &usedrdip);
1084 
1085 	}
1086 
1087 	process_master_file();
1088 
1089 	/*
1090 	 * Do the actual enumeration.  Avoid AcpiGetDevices because it
1091 	 * has an unnecessary internal callback that duplicates
1092 	 * determining if the device is present.
1093 	 */
1094 	(void) AcpiWalkNamespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
1095 	    UINT32_MAX, isa_acpi_callback, NULL, isa_dip, NULL);
1096 
1097 	free_master_data();
1098 	used_res_interrupts();
1099 	used_res_dmas();
1100 	used_res_io_mem("device-memory", &used_mem_count, &used_mem_head);
1101 	used_res_io_mem("io-space", &used_io_count, &used_io_head);
1102 	(void) ndi_devi_bind_driver(usedrdip, 0);
1103 
1104 	return (1);
1105 }
1106