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 2016, 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
insert_used_resource(used_io_mem_t * used,int * used_count,used_io_mem_t ** head)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
add_used_io_mem(struct regspec * io,int io_count)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
parse_resources_irq(ACPI_RESOURCE * resource_ptr,int * interrupt_count)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
parse_resources_dma(ACPI_RESOURCE * resource_ptr,int * dma_count)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
parse_resources_io(ACPI_RESOURCE * resource_ptr,struct regspec * io,int * io_count)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
parse_resources_fixed_io(ACPI_RESOURCE * resource_ptr,struct regspec * io,int * io_count)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
parse_resources_fixed_mem32(ACPI_RESOURCE * resource_ptr,struct regspec * io,int * io_count)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
parse_resources_mem32(ACPI_RESOURCE * resource_ptr,struct regspec * io,int * io_count)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
parse_resources_addr16(ACPI_RESOURCE * resource_ptr,struct regspec * io,int * io_count)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
parse_resources_addr32(ACPI_RESOURCE * resource_ptr,struct regspec * io,int * io_count)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
parse_resources_addr64(ACPI_RESOURCE * resource_ptr,struct regspec * io,int * io_count)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
parse_resources(ACPI_HANDLE handle,dev_info_t * xdip,char * path)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 *
get_bus_dip(char * nodename,dev_info_t * isa_dip)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
process_properties(dev_info_t * xdip,property_t * properties)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
eisa_to_str(ACPI_INTEGER id,char * np)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
process_cids(ACPI_OBJECT * rv,device_id_t ** dd)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
convert_to_pnp1275(char * pnpid,char * str,int strsize)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
create_compatible_property(dev_info_t * dip,device_id_t * ids)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
isa_acpi_callback(ACPI_HANDLE ObjHandle,uint32_t NestingLevel,void * a,void ** b)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
795 /*
796 * get full ACPI pathname for object
797 */
798 rb.Length = ACPI_ALLOCATE_BUFFER;
799 rb.Pointer = NULL;
800 if (AcpiGetName(ObjHandle, ACPI_FULL_PATHNAME, &rb) != AE_OK) {
801 cmn_err(CE_WARN, "!acpi_enum: could not get pathname");
802 goto done;
803 }
804 path = (char *)rb.Pointer;
805
806 /*
807 * Get device info object
808 */
809 if (AcpiGetObjectInfo(ObjHandle, &info) != AE_OK) {
810 cmn_err(CE_WARN, "!acpi_enum: could not get device"
811 " info for %s", path);
812 goto done;
813 }
814
815 /*
816 * If device isn't present, we don't enumerate
817 * NEEDSWORK: what about docking bays and the like?
818 */
819 if (info->Valid & ACPI_VALID_STA) {
820 /*
821 * CA 6.3.6 _STA method
822 * Bit 0 -- device is present
823 * Bit 1 -- device is enabled
824 * Bit 2 -- device is shown in UI
825 */
826 if (!((info->CurrentStatus & 0x7) == 7)) {
827 if (acpi_enum_debug & DEVICES_NOT_ENUMED) {
828 cmn_err(CE_NOTE, "!parse_resources() "
829 "Bad status 0x%x for %s",
830 info->CurrentStatus, path);
831 }
832 goto done;
833 }
834 } else {
835 cmn_err(CE_WARN, "!acpi_enum: no _STA for %s", path);
836 goto done;
837 }
838
839 /*
840 * Keep track of _HID value
841 */
842 if (!(info->Valid & ACPI_VALID_HID)) {
843 /* No _HID, we skip this node */
844 if (acpi_enum_debug & DEVICES_NOT_ENUMED) {
845 cmn_err(CE_NOTE, "!parse_resources() "
846 "No _HID for %s", path);
847 }
848 goto done;
849 }
850 hidstr = info->HardwareId.String;
851
852 /*
853 * Attempt to get _CID value
854 */
855 rb.Length = ACPI_ALLOCATE_BUFFER;
856 rb.Pointer = NULL;
857 if (AcpiEvaluateObject(ObjHandle, "_CID", NULL, &rb) == AE_OK &&
858 rb.Length != 0) {
859 ACPI_OBJECT *rv = rb.Pointer;
860
861 switch (rv->Type) {
862 case ACPI_TYPE_INTEGER:
863 eisa_to_str(rv->Integer.Value, tmp_cidstr);
864 d = mf_alloc_device_id();
865 d->id = strdup(tmp_cidstr);
866 d->next = device_ids;
867 device_ids = d;
868 break;
869 case ACPI_TYPE_STRING:
870 d = mf_alloc_device_id();
871 d->id = strdup(rv->String.Pointer);
872 d->next = device_ids;
873 device_ids = d;
874 break;
875 case ACPI_TYPE_PACKAGE:
876 process_cids(rv, &device_ids);
877 break;
878 default:
879 break;
880 }
881 AcpiOsFree(rb.Pointer);
882 }
883
884 /*
885 * Add _HID last so it's at the head of the list
886 */
887 d = mf_alloc_device_id();
888 d->id = strdup(hidstr);
889 d->next = device_ids;
890 device_ids = d;
891
892 /*
893 * master_file_lookup() expects _HID first in device_ids
894 */
895 if ((m = master_file_lookup(device_ids)) != NULL) {
896 /* PNP description found in master table */
897 if (!(strncmp(hidstr, "ACPI", 4))) {
898 dip = ddi_root_node();
899 } else {
900 dip = get_bus_dip(m->name, dip);
901 }
902 ndi_devi_alloc_sleep(dip, m->name,
903 (pnode_t)DEVI_SID_NODEID, &xdip);
904 (void) ndi_prop_update_string(DDI_DEV_T_NONE, xdip,
905 "model", m->description);
906 compatible_present = process_properties(xdip, m->properties);
907 } else {
908 /* for ISA devices not known to the master file */
909 if (!(strncmp(hidstr, "PNP03", 5))) {
910 /* a keyboard device includes PNP03xx */
911 dip = get_bus_dip(keyboard_alias, dip);
912 ndi_devi_alloc_sleep(dip, keyboard_alias,
913 (pnode_t)DEVI_SID_NODEID, &xdip);
914 (void) ndi_prop_update_string(DDI_DEV_T_NONE, xdip,
915 "compatible", "pnpPNP,303");
916 (void) ndi_prop_update_string(DDI_DEV_T_NONE, xdip,
917 "model", "PNP03xx keyboard");
918 } else {
919 if (!(strncmp(hidstr, "PNP0F", 5))) {
920 /* a mouse device include PNP0Fxx */
921 dip = get_bus_dip(mouse_alias, dip);
922 ndi_devi_alloc_sleep(dip, mouse_alias,
923 (pnode_t)DEVI_SID_NODEID, &xdip);
924 (void) ndi_prop_update_string(DDI_DEV_T_NONE,
925 xdip, "compatible", "pnpPNP,f03");
926 (void) ndi_prop_update_string(DDI_DEV_T_NONE,
927 xdip, "model", "PNP0Fxx mouse");
928 } else {
929 (void) parse_resources(ObjHandle, xdip, path);
930 goto done;
931 }
932 }
933 }
934
935 (void) ndi_prop_update_string(DDI_DEV_T_NONE, xdip, "acpi-namespace",
936 path);
937
938 (void) parse_resources(ObjHandle, xdip, path);
939
940 /* Special processing for mouse and keyboard devices per IEEE 1275 */
941 /* if master entry doesn't contain "compatible" then we add default */
942 if (strcmp(m->name, keyboard_alias) == 0) {
943 (void) ndi_prop_update_int(DDI_DEV_T_NONE, xdip, "reg", 0);
944 (void) ndi_prop_update_string(DDI_DEV_T_NONE, xdip,
945 "device-type", keyboard_alias);
946 if (!compatible_present)
947 (void) ndi_prop_update_string(DDI_DEV_T_NONE, xdip,
948 "compatible", "pnpPNP,303");
949 } else if (strcmp(m->name, mouse_alias) == 0) {
950 (void) ndi_prop_update_int(DDI_DEV_T_NONE, xdip, "reg", 1);
951 (void) ndi_prop_update_string(DDI_DEV_T_NONE, xdip,
952 "device-type", mouse_alias);
953 if (!compatible_present)
954 (void) ndi_prop_update_string(DDI_DEV_T_NONE, xdip,
955 "compatible", "pnpPNP,f03");
956 }
957
958 /*
959 * Create default "compatible" property if required
960 */
961 if (!ddi_prop_exists(DDI_DEV_T_ANY, xdip,
962 DDI_PROP_DONTPASS, "compatible"))
963 create_compatible_property(xdip, device_ids);
964
965 (void) ndi_devi_bind_driver(xdip, 0);
966
967 done:
968 /* discard _HID/_CID list */
969 d = device_ids;
970 while (d != NULL) {
971 device_id_t *next;
972
973 next = d->next;
974 mf_free_device_id(d);
975 d = next;
976 }
977
978 if (path != NULL)
979 AcpiOsFree(path);
980 if (info != NULL)
981 AcpiOsFree(info);
982
983 return (AE_OK);
984 }
985
986 static void
used_res_interrupts(void)987 used_res_interrupts(void)
988 {
989 int intr[ACPI_ISA_LIMIT];
990 int count = 0;
991 int i;
992
993 for (i = 0; i < ACPI_ISA_LIMIT; i++) {
994 if ((used_interrupts >> i) & 1) {
995 intr[count++] = i;
996 }
997 }
998 (void) ndi_prop_update_int_array(DDI_DEV_T_NONE, usedrdip,
999 "interrupts", (int *)intr, count);
1000 }
1001
1002 static void
used_res_dmas(void)1003 used_res_dmas(void)
1004 {
1005 int dma[ACPI_ISA_LIMIT];
1006 int count = 0;
1007 int i;
1008
1009 for (i = 0; i < ACPI_ISA_LIMIT; i++) {
1010 if ((used_dmas >> i) & 1) {
1011 dma[count++] = i;
1012 }
1013 }
1014 (void) ndi_prop_update_int_array(DDI_DEV_T_NONE, usedrdip,
1015 "dma-channels", (int *)dma, count);
1016 }
1017
1018 static void
used_res_io_mem(char * nodename,int * count,used_io_mem_t ** head)1019 used_res_io_mem(char *nodename, int *count, used_io_mem_t **head)
1020 {
1021 int *io;
1022 used_io_mem_t *used = *head;
1023 int i;
1024
1025 *count *= 2;
1026 io = (int *)kmem_zalloc(sizeof (int)*(*count), KM_SLEEP);
1027 for (i = 0; i < *count; i += 2) {
1028 used_io_mem_t *prev;
1029 if (used != NULL) {
1030 io[i] = used->start_addr;
1031 io[i+1] = used->length;
1032 prev = used;
1033 used = used->next;
1034 kmem_free(prev, sizeof (used_io_mem_t));
1035 }
1036 }
1037 (void) ndi_prop_update_int_array(DDI_DEV_T_NONE, usedrdip,
1038 nodename, (int *)io, *count);
1039 kmem_free(io, sizeof (int)*(*count));
1040 *head = NULL;
1041 }
1042
1043 /*
1044 * acpi_isa_device_enum() -- call from isa nexus driver
1045 * returns 1 if deviced enumeration is successful
1046 * 0 if deviced enumeration fails
1047 */
1048 int
acpi_isa_device_enum(dev_info_t * isa_dip)1049 acpi_isa_device_enum(dev_info_t *isa_dip)
1050 {
1051 char *acpi_prop;
1052
1053 if (ddi_prop_lookup_string(DDI_DEV_T_ANY, ddi_root_node(),
1054 DDI_PROP_DONTPASS, ACPI_ENUM_DEBUG, &acpi_prop) ==
1055 DDI_PROP_SUCCESS) {
1056 long data;
1057 if (ddi_strtol(acpi_prop, NULL, 0, &data) == 0) {
1058 acpi_enum_debug = (unsigned long)data;
1059 e_ddi_prop_remove(DDI_DEV_T_NONE, ddi_root_node(),
1060 ACPI_ENUM_DEBUG);
1061 e_ddi_prop_update_int(DDI_DEV_T_NONE,
1062 ddi_root_node(), ACPI_ENUM_DEBUG, data);
1063 }
1064 ddi_prop_free(acpi_prop);
1065 }
1066
1067 if (acpi_enum_debug & ISA_DEVICE_ENUM) {
1068 cmn_err(CE_NOTE, "!acpi_isa_device_enum() called");
1069 }
1070
1071 if (acpica_init() != AE_OK) {
1072 cmn_err(CE_WARN, "!isa_enum: init failed");
1073 /* Note, pickup by i8042 nexus */
1074 (void) e_ddi_prop_update_string(DDI_DEV_T_NONE,
1075 ddi_root_node(), "acpi-enum", "off");
1076 return (0);
1077 }
1078
1079 usedrdip = ddi_find_devinfo(USED_RESOURCES, -1, 0);
1080 if (usedrdip == NULL) {
1081 ndi_devi_alloc_sleep(ddi_root_node(), USED_RESOURCES,
1082 (pnode_t)DEVI_SID_NODEID, &usedrdip);
1083
1084 }
1085
1086 process_master_file();
1087
1088 /*
1089 * Do the actual enumeration. Avoid AcpiGetDevices because it
1090 * has an unnecessary internal callback that duplicates
1091 * determining if the device is present.
1092 */
1093 (void) AcpiWalkNamespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
1094 UINT32_MAX, isa_acpi_callback, NULL, isa_dip, NULL);
1095
1096 free_master_data();
1097 used_res_interrupts();
1098 used_res_dmas();
1099 used_res_io_mem("device-memory", &used_mem_count, &used_mem_head);
1100 used_res_io_mem("io-space", &used_io_count, &used_io_head);
1101 (void) ndi_devi_bind_driver(usedrdip, 0);
1102
1103 return (1);
1104 }
1105