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