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