acpi_resource.c revision 1.37.18.2 1 /* $NetBSD: acpi_resource.c,v 1.37.18.2 2020/04/08 14:08:02 martin Exp $ */
2
3 /*
4 * Copyright 2001 Wasabi Systems, Inc.
5 * All rights reserved.
6 *
7 * Written by Jason R. Thorpe for Wasabi Systems, Inc.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. All advertising materials mentioning features or use of this software
18 * must display the following acknowledgement:
19 * This product includes software developed for the NetBSD Project by
20 * Wasabi Systems, Inc.
21 * 4. The name of Wasabi Systems, Inc. may not be used to endorse
22 * or promote products derived from this software without specific prior
23 * written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
27 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
28 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC
29 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
30 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
31 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
32 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35 * POSSIBILITY OF SUCH DAMAGE.
36 */
37
38 /*-
39 * Copyright (c) 2000 Michael Smith
40 * Copyright (c) 2000 BSDi
41 * All rights reserved.
42 *
43 * Redistribution and use in source and binary forms, with or without
44 * modification, are permitted provided that the following conditions
45 * are met:
46 * 1. Redistributions of source code must retain the above copyright
47 * notice, this list of conditions and the following disclaimer.
48 * 2. Redistributions in binary form must reproduce the above copyright
49 * notice, this list of conditions and the following disclaimer in the
50 * documentation and/or other materials provided with the distribution.
51 *
52 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
53 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
54 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
55 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
56 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
57 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
58 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
59 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
60 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
61 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
62 * SUCH DAMAGE.
63 */
64
65 /*
66 * ACPI resource parsing.
67 */
68
69 #include <sys/cdefs.h>
70 __KERNEL_RCSID(0, "$NetBSD: acpi_resource.c,v 1.37.18.2 2020/04/08 14:08:02 martin Exp $");
71
72 #include <sys/param.h>
73 #include <sys/device.h>
74 #include <sys/systm.h>
75
76 #include <dev/acpi/acpireg.h>
77 #include <dev/acpi/acpivar.h>
78
79 #define _COMPONENT ACPI_RESOURCE_COMPONENT
80 ACPI_MODULE_NAME("RESOURCE")
81
82 static ACPI_STATUS acpi_resource_parse_callback(ACPI_RESOURCE *, void *);
83
84 struct resource_parse_callback_arg {
85 const struct acpi_resource_parse_ops *ops;
86 device_t dev;
87 void *context;
88 };
89
90 static ACPI_STATUS
91 acpi_resource_parse_callback(ACPI_RESOURCE *res, void *context)
92 {
93 struct resource_parse_callback_arg *arg = context;
94 const struct acpi_resource_parse_ops *ops;
95 int i;
96
97 ACPI_FUNCTION_TRACE(__func__);
98
99 ops = arg->ops;
100
101 switch (res->Type) {
102 case ACPI_RESOURCE_TYPE_END_TAG:
103 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "EndTag\n"));
104 break;
105 case ACPI_RESOURCE_TYPE_FIXED_IO:
106 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
107 "FixedIo 0x%x/%u\n",
108 res->Data.FixedIo.Address,
109 res->Data.FixedIo.AddressLength));
110 if (ops->ioport)
111 (*ops->ioport)(arg->dev, arg->context,
112 res->Data.FixedIo.Address,
113 res->Data.FixedIo.AddressLength);
114 break;
115
116 case ACPI_RESOURCE_TYPE_IO:
117 if (res->Data.Io.Minimum ==
118 res->Data.Io.Maximum) {
119 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
120 "Io 0x%x/%u\n",
121 res->Data.Io.Minimum,
122 res->Data.Io.AddressLength));
123 if (ops->ioport)
124 (*ops->ioport)(arg->dev, arg->context,
125 res->Data.Io.Minimum,
126 res->Data.Io.AddressLength);
127 } else {
128 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
129 "Io 0x%x-0x%x/%u\n",
130 res->Data.Io.Minimum,
131 res->Data.Io.Maximum,
132 res->Data.Io.AddressLength));
133 if (ops->iorange)
134 (*ops->iorange)(arg->dev, arg->context,
135 res->Data.Io.Minimum,
136 res->Data.Io.Maximum,
137 res->Data.Io.AddressLength,
138 res->Data.Io.Alignment);
139 }
140 break;
141
142 case ACPI_RESOURCE_TYPE_FIXED_MEMORY32:
143 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
144 "FixedMemory32 0x%x/%u\n",
145 res->Data.FixedMemory32.Address,
146 res->Data.FixedMemory32.AddressLength));
147 if (ops->memory)
148 (*ops->memory)(arg->dev, arg->context,
149 res->Data.FixedMemory32.Address,
150 res->Data.FixedMemory32.AddressLength,
151 res->Data.FixedMemory32.Address);
152 break;
153
154 case ACPI_RESOURCE_TYPE_MEMORY32:
155 if (res->Data.Memory32.Minimum ==
156 res->Data.Memory32.Maximum) {
157 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
158 "Memory32 0x%x/%u\n",
159 res->Data.Memory32.Minimum,
160 res->Data.Memory32.AddressLength));
161 if (ops->memory)
162 (*ops->memory)(arg->dev, arg->context,
163 res->Data.Memory32.Minimum,
164 res->Data.Memory32.AddressLength,
165 res->Data.Memory32.Minimum);
166 } else {
167 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
168 "Memory32 0x%x-0x%x/%u\n",
169 res->Data.Memory32.Minimum,
170 res->Data.Memory32.Maximum,
171 res->Data.Memory32.AddressLength));
172 if (ops->memrange)
173 (*ops->memrange)(arg->dev, arg->context,
174 res->Data.Memory32.Minimum,
175 res->Data.Memory32.Maximum,
176 res->Data.Memory32.AddressLength,
177 res->Data.Memory32.Alignment);
178 }
179 break;
180
181 case ACPI_RESOURCE_TYPE_MEMORY24:
182 if (res->Data.Memory24.Minimum ==
183 res->Data.Memory24.Maximum) {
184 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
185 "Memory24 0x%x/%u\n",
186 res->Data.Memory24.Minimum,
187 res->Data.Memory24.AddressLength));
188 if (ops->memory)
189 (*ops->memory)(arg->dev, arg->context,
190 res->Data.Memory24.Minimum,
191 res->Data.Memory24.AddressLength,
192 res->Data.Memory24.Minimum);
193 } else {
194 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
195 "Memory24 0x%x-0x%x/%u\n",
196 res->Data.Memory24.Minimum,
197 res->Data.Memory24.Maximum,
198 res->Data.Memory24.AddressLength));
199 if (ops->memrange)
200 (*ops->memrange)(arg->dev, arg->context,
201 res->Data.Memory24.Minimum,
202 res->Data.Memory24.Maximum,
203 res->Data.Memory24.AddressLength,
204 res->Data.Memory24.Alignment);
205 }
206 break;
207
208 case ACPI_RESOURCE_TYPE_IRQ:
209 for (i = 0; i < res->Data.Irq.InterruptCount; i++) {
210 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
211 "IRQ %u\n",
212 res->Data.Irq.Interrupts[i]));
213 if (ops->irq)
214 (*ops->irq)(arg->dev, arg->context,
215 res->Data.Irq.Interrupts[i],
216 res->Data.Irq.Triggering);
217 }
218 break;
219
220 case ACPI_RESOURCE_TYPE_DMA:
221 for (i = 0; i < res->Data.Dma.ChannelCount; i++) {
222 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
223 "DRQ %u\n",
224 res->Data.Dma.Channels[i]));
225 if (ops->drq)
226 (*ops->drq)(arg->dev, arg->context,
227 res->Data.Dma.Channels[i]);
228 }
229 break;
230
231 case ACPI_RESOURCE_TYPE_START_DEPENDENT:
232 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
233 "Start dependent functions: %u\n",
234 res->Data.StartDpf.CompatibilityPriority));
235 if (ops->start_dep)
236 (*ops->start_dep)(arg->dev, arg->context,
237 res->Data.StartDpf.CompatibilityPriority);
238 break;
239
240 case ACPI_RESOURCE_TYPE_END_DEPENDENT:
241 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
242 "End dependent functions\n"));
243 if (ops->end_dep)
244 (*ops->end_dep)(arg->dev, arg->context);
245 break;
246
247 case ACPI_RESOURCE_TYPE_ADDRESS32:
248 /* XXX Only fixed size supported for now */
249 if (res->Data.Address32.Address.AddressLength == 0 ||
250 res->Data.Address32.ProducerConsumer != ACPI_CONSUMER)
251 break;
252 #define ADDRESS32_FIXED2(r) \
253 ((r)->Data.Address32.MinAddressFixed == ACPI_ADDRESS_FIXED && \
254 (r)->Data.Address32.MaxAddressFixed == ACPI_ADDRESS_FIXED)
255 switch (res->Data.Address32.ResourceType) {
256 case ACPI_MEMORY_RANGE:
257 if (ADDRESS32_FIXED2(res)) {
258 if (ops->memory)
259 (*ops->memory)(arg->dev, arg->context,
260 res->Data.Address32.Address.Minimum,
261 res->Data.Address32.Address.AddressLength,
262 res->Data.Address32.Address.Minimum +
263 res->Data.Address32.Address.TranslationOffset);
264 } else {
265 if (ops->memrange)
266 (*ops->memrange)(arg->dev, arg->context,
267 res->Data.Address32.Address.Minimum,
268 res->Data.Address32.Address.Maximum,
269 res->Data.Address32.Address.AddressLength,
270 res->Data.Address32.Address.Granularity);
271 }
272 break;
273 case ACPI_IO_RANGE:
274 if (ADDRESS32_FIXED2(res)) {
275 if (ops->ioport)
276 (*ops->ioport)(arg->dev, arg->context,
277 res->Data.Address32.Address.Minimum,
278 res->Data.Address32.Address.AddressLength);
279 } else {
280 if (ops->iorange)
281 (*ops->iorange)(arg->dev, arg->context,
282 res->Data.Address32.Address.Minimum,
283 res->Data.Address32.Address.Maximum,
284 res->Data.Address32.Address.AddressLength,
285 res->Data.Address32.Address.Granularity);
286 }
287 break;
288 case ACPI_BUS_NUMBER_RANGE:
289 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
290 "Address32/BusNumber unimplemented\n"));
291 break;
292 }
293 #undef ADDRESS32_FIXED2
294 break;
295
296 case ACPI_RESOURCE_TYPE_ADDRESS16:
297 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
298 "Address16 unimplemented\n"));
299 break;
300
301 case ACPI_RESOURCE_TYPE_ADDRESS64:
302 #ifdef _LP64
303 /* XXX Only fixed size supported for now */
304 if (res->Data.Address64.Address.AddressLength == 0 ||
305 res->Data.Address64.ProducerConsumer != ACPI_CONSUMER)
306 break;
307 #define ADDRESS64_FIXED2(r) \
308 ((r)->Data.Address64.MinAddressFixed == ACPI_ADDRESS_FIXED && \
309 (r)->Data.Address64.MaxAddressFixed == ACPI_ADDRESS_FIXED)
310 switch (res->Data.Address64.ResourceType) {
311 case ACPI_MEMORY_RANGE:
312 if (ADDRESS64_FIXED2(res)) {
313 if (ops->memory)
314 (*ops->memory)(arg->dev, arg->context,
315 res->Data.Address64.Address.Minimum,
316 res->Data.Address64.Address.AddressLength,
317 res->Data.Address64.Address.Minimum +
318 res->Data.Address64.Address.TranslationOffset);
319 } else {
320 if (ops->memrange)
321 (*ops->memrange)(arg->dev, arg->context,
322 res->Data.Address64.Address.Minimum,
323 res->Data.Address64.Address.Maximum,
324 res->Data.Address64.Address.AddressLength,
325 res->Data.Address64.Address.Granularity);
326 }
327 break;
328 case ACPI_IO_RANGE:
329 if (ADDRESS64_FIXED2(res)) {
330 if (ops->ioport)
331 (*ops->ioport)(arg->dev, arg->context,
332 res->Data.Address64.Address.Minimum,
333 res->Data.Address64.Address.AddressLength);
334 } else {
335 if (ops->iorange)
336 (*ops->iorange)(arg->dev, arg->context,
337 res->Data.Address64.Address.Minimum,
338 res->Data.Address64.Address.Maximum,
339 res->Data.Address64.Address.AddressLength,
340 res->Data.Address64.Address.Granularity);
341 }
342 break;
343 case ACPI_BUS_NUMBER_RANGE:
344 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
345 "Address64/BusNumber unimplemented\n"));
346 break;
347 }
348 #undef ADDRESS64_FIXED2
349 #else
350 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
351 "Address64 unimplemented\n"));
352 #endif
353 break;
354 case ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64:
355 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
356 "Extended address64 unimplemented\n"));
357 break;
358
359 case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
360 if (res->Data.ExtendedIrq.ProducerConsumer != ACPI_CONSUMER) {
361 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
362 "ignored ExtIRQ producer\n"));
363 break;
364 }
365 for (i = 0; i < res->Data.ExtendedIrq.InterruptCount; i++) {
366 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
367 "ExtIRQ %u\n",
368 res->Data.ExtendedIrq.Interrupts[i]));
369 if (ops->irq)
370 (*ops->irq)(arg->dev, arg->context,
371 res->Data.ExtendedIrq.Interrupts[i],
372 res->Data.ExtendedIrq.Triggering);
373 }
374 break;
375
376 case ACPI_RESOURCE_TYPE_GENERIC_REGISTER:
377 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
378 "GenericRegister unimplemented\n"));
379 break;
380
381 case ACPI_RESOURCE_TYPE_VENDOR:
382 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
383 "VendorSpecific unimplemented\n"));
384 break;
385
386 default:
387 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
388 "Unknown resource type: %u\n", res->Type));
389 break;
390 }
391
392 return_ACPI_STATUS(AE_OK);
393 }
394
395
396 /*
397 * acpi_resource_parse:
398 *
399 * Parse a device node's resources and fill them in for the
400 * client.
401 *
402 * This API supports _CRS (current resources) and
403 * _PRS (possible resources).
404 *
405 * Note that it might be nice to also locate ACPI-specific resource
406 * items, such as GPE bits.
407 */
408 ACPI_STATUS
409 acpi_resource_parse(device_t dev, ACPI_HANDLE handle, const char *path,
410 void *arg, const struct acpi_resource_parse_ops *ops)
411 {
412 struct resource_parse_callback_arg cbarg;
413 ACPI_STATUS rv;
414
415 ACPI_FUNCTION_TRACE(__func__);
416
417 if (ops->init)
418 (*ops->init)(dev, arg, &cbarg.context);
419 else
420 cbarg.context = arg;
421 cbarg.ops = ops;
422 cbarg.dev = dev;
423
424 rv = AcpiWalkResources(handle, path, acpi_resource_parse_callback,
425 &cbarg);
426 if (ACPI_FAILURE(rv)) {
427 aprint_error_dev(dev, "ACPI: unable to get %s resources: %s\n",
428 path, AcpiFormatException(rv));
429 return_ACPI_STATUS(rv);
430 }
431
432 if (ops->fini)
433 (*ops->fini)(dev, cbarg.context);
434
435 return_ACPI_STATUS(AE_OK);
436 }
437
438 /*
439 * acpi_resource_print:
440 *
441 * Print the resources assigned to a device.
442 */
443 void
444 acpi_resource_print(device_t dev, struct acpi_resources *res)
445 {
446 const char *sep;
447
448 if (SIMPLEQ_EMPTY(&res->ar_io) &&
449 SIMPLEQ_EMPTY(&res->ar_iorange) &&
450 SIMPLEQ_EMPTY(&res->ar_mem) &&
451 SIMPLEQ_EMPTY(&res->ar_memrange) &&
452 SIMPLEQ_EMPTY(&res->ar_irq) &&
453 SIMPLEQ_EMPTY(&res->ar_drq))
454 return;
455
456 aprint_normal(":");
457
458 if (SIMPLEQ_EMPTY(&res->ar_io) == 0) {
459 struct acpi_io *ar;
460
461 sep = "";
462 aprint_normal(" io ");
463 SIMPLEQ_FOREACH(ar, &res->ar_io, ar_list) {
464 aprint_normal("%s0x%x", sep, ar->ar_base);
465 if (ar->ar_length > 1)
466 aprint_normal("-0x%x", ar->ar_base +
467 ar->ar_length - 1);
468 sep = ",";
469 }
470 }
471
472 /* XXX iorange */
473
474 if (SIMPLEQ_EMPTY(&res->ar_mem) == 0) {
475 struct acpi_mem *ar;
476
477 sep = "";
478 aprint_normal(" mem ");
479 SIMPLEQ_FOREACH(ar, &res->ar_mem, ar_list) {
480 aprint_normal("%s0x%" PRIx64, sep,
481 (uint64_t)ar->ar_base);
482 if (ar->ar_length > 1)
483 aprint_normal("-0x%" PRIx64,
484 (uint64_t)ar->ar_base +
485 ar->ar_length - 1);
486 sep = ",";
487 }
488 }
489
490 /* XXX memrange */
491
492 if (SIMPLEQ_EMPTY(&res->ar_irq) == 0) {
493 struct acpi_irq *ar;
494
495 sep = "";
496 aprint_normal(" irq ");
497 SIMPLEQ_FOREACH(ar, &res->ar_irq, ar_list) {
498 aprint_normal("%s%d", sep, ar->ar_irq);
499 sep = ",";
500 }
501 }
502
503 if (SIMPLEQ_EMPTY(&res->ar_drq) == 0) {
504 struct acpi_drq *ar;
505
506 sep = "";
507 aprint_normal(" drq ");
508 SIMPLEQ_FOREACH(ar, &res->ar_drq, ar_list) {
509 aprint_normal("%s%d", sep, ar->ar_drq);
510 sep = ",";
511 }
512 }
513
514 aprint_normal("\n");
515 aprint_naive("\n");
516 }
517
518 /*
519 * acpi_resource_cleanup:
520 *
521 * Free all allocated buffers
522 */
523 void
524 acpi_resource_cleanup(struct acpi_resources *res)
525 {
526 while (!SIMPLEQ_EMPTY(&res->ar_io)) {
527 struct acpi_io *ar;
528 ar = SIMPLEQ_FIRST(&res->ar_io);
529 SIMPLEQ_REMOVE_HEAD(&res->ar_io, ar_list);
530 ACPI_FREE(ar);
531 }
532
533 while (!SIMPLEQ_EMPTY(&res->ar_iorange)) {
534 struct acpi_iorange *ar;
535 ar = SIMPLEQ_FIRST(&res->ar_iorange);
536 SIMPLEQ_REMOVE_HEAD(&res->ar_iorange, ar_list);
537 ACPI_FREE(ar);
538 }
539
540 while (!SIMPLEQ_EMPTY(&res->ar_mem)) {
541 struct acpi_mem *ar;
542 ar = SIMPLEQ_FIRST(&res->ar_mem);
543 SIMPLEQ_REMOVE_HEAD(&res->ar_mem, ar_list);
544 ACPI_FREE(ar);
545 }
546
547 while (!SIMPLEQ_EMPTY(&res->ar_memrange)) {
548 struct acpi_memrange *ar;
549 ar = SIMPLEQ_FIRST(&res->ar_memrange);
550 SIMPLEQ_REMOVE_HEAD(&res->ar_memrange, ar_list);
551 ACPI_FREE(ar);
552 }
553
554 while (!SIMPLEQ_EMPTY(&res->ar_irq)) {
555 struct acpi_irq *ar;
556 ar = SIMPLEQ_FIRST(&res->ar_irq);
557 SIMPLEQ_REMOVE_HEAD(&res->ar_irq, ar_list);
558 ACPI_FREE(ar);
559 }
560
561 while (!SIMPLEQ_EMPTY(&res->ar_drq)) {
562 struct acpi_drq *ar;
563 ar = SIMPLEQ_FIRST(&res->ar_drq);
564 SIMPLEQ_REMOVE_HEAD(&res->ar_drq, ar_list);
565 ACPI_FREE(ar);
566 }
567
568 res->ar_nio = res->ar_niorange = res->ar_nmem =
569 res->ar_nmemrange = res->ar_nirq = res->ar_ndrq = 0;
570 }
571
572 struct acpi_io *
573 acpi_res_io(struct acpi_resources *res, int idx)
574 {
575 struct acpi_io *ar;
576
577 SIMPLEQ_FOREACH(ar, &res->ar_io, ar_list) {
578 if (ar->ar_index == idx)
579 return ar;
580 }
581 return NULL;
582 }
583
584 struct acpi_iorange *
585 acpi_res_iorange(struct acpi_resources *res, int idx)
586 {
587 struct acpi_iorange *ar;
588
589 SIMPLEQ_FOREACH(ar, &res->ar_iorange, ar_list) {
590 if (ar->ar_index == idx)
591 return ar;
592 }
593 return NULL;
594 }
595
596 struct acpi_mem *
597 acpi_res_mem(struct acpi_resources *res, int idx)
598 {
599 struct acpi_mem *ar;
600
601 SIMPLEQ_FOREACH(ar, &res->ar_mem, ar_list) {
602 if (ar->ar_index == idx)
603 return ar;
604 }
605 return NULL;
606 }
607
608 struct acpi_memrange *
609 acpi_res_memrange(struct acpi_resources *res, int idx)
610 {
611 struct acpi_memrange *ar;
612
613 SIMPLEQ_FOREACH(ar, &res->ar_memrange, ar_list) {
614 if (ar->ar_index == idx)
615 return ar;
616 }
617 return NULL;
618 }
619
620 struct acpi_irq *
621 acpi_res_irq(struct acpi_resources *res, int idx)
622 {
623 struct acpi_irq *ar;
624
625 SIMPLEQ_FOREACH(ar, &res->ar_irq, ar_list) {
626 if (ar->ar_index == idx)
627 return ar;
628 }
629 return NULL;
630 }
631
632 struct acpi_drq *
633 acpi_res_drq(struct acpi_resources *res, int idx)
634 {
635 struct acpi_drq *ar;
636
637 SIMPLEQ_FOREACH(ar, &res->ar_drq, ar_list) {
638 if (ar->ar_index == idx)
639 return ar;
640 }
641 return NULL;
642 }
643
644 /*****************************************************************************
645 * Default ACPI resource parse operations.
646 *****************************************************************************/
647
648 static void acpi_res_parse_init(device_t, void *, void **);
649 static void acpi_res_parse_fini(device_t, void *);
650
651 static void acpi_res_parse_ioport(device_t, void *, uint32_t,
652 uint32_t);
653 static void acpi_res_parse_iorange(device_t, void *, uint32_t,
654 uint32_t, uint32_t, uint32_t);
655
656 static void acpi_res_parse_memory(device_t, void *, uint64_t,
657 uint64_t, uint64_t);
658 static void acpi_res_parse_memrange(device_t, void *, uint64_t,
659 uint64_t, uint64_t, uint64_t);
660
661 static void acpi_res_parse_irq(device_t, void *, uint32_t, uint32_t);
662 static void acpi_res_parse_drq(device_t, void *, uint32_t);
663
664 static void acpi_res_parse_start_dep(device_t, void *, int);
665 static void acpi_res_parse_end_dep(device_t, void *);
666
667 const struct acpi_resource_parse_ops acpi_resource_parse_ops_default = {
668 .init = acpi_res_parse_init,
669 .fini = acpi_res_parse_fini,
670
671 .ioport = acpi_res_parse_ioport,
672 .iorange = acpi_res_parse_iorange,
673
674 .memory = acpi_res_parse_memory,
675 .memrange = acpi_res_parse_memrange,
676
677 .irq = acpi_res_parse_irq,
678 .drq = acpi_res_parse_drq,
679
680 .start_dep = acpi_res_parse_start_dep,
681 .end_dep = acpi_res_parse_end_dep,
682 };
683
684 const struct acpi_resource_parse_ops acpi_resource_parse_ops_quiet = {
685 .init = acpi_res_parse_init,
686 .fini = NULL,
687
688 .ioport = acpi_res_parse_ioport,
689 .iorange = acpi_res_parse_iorange,
690
691 .memory = acpi_res_parse_memory,
692 .memrange = acpi_res_parse_memrange,
693
694 .irq = acpi_res_parse_irq,
695 .drq = acpi_res_parse_drq,
696
697 .start_dep = acpi_res_parse_start_dep,
698 .end_dep = acpi_res_parse_end_dep,
699 };
700
701 static void
702 acpi_res_parse_init(device_t dev, void *arg, void **contextp)
703 {
704 struct acpi_resources *res = arg;
705
706 SIMPLEQ_INIT(&res->ar_io);
707 res->ar_nio = 0;
708
709 SIMPLEQ_INIT(&res->ar_iorange);
710 res->ar_niorange = 0;
711
712 SIMPLEQ_INIT(&res->ar_mem);
713 res->ar_nmem = 0;
714
715 SIMPLEQ_INIT(&res->ar_memrange);
716 res->ar_nmemrange = 0;
717
718 SIMPLEQ_INIT(&res->ar_irq);
719 res->ar_nirq = 0;
720
721 SIMPLEQ_INIT(&res->ar_drq);
722 res->ar_ndrq = 0;
723
724 *contextp = res;
725 }
726
727 static void
728 acpi_res_parse_fini(device_t dev, void *context)
729 {
730 struct acpi_resources *res = context;
731
732 /* Print the resources we're using. */
733 acpi_resource_print(dev, res);
734 }
735
736 static void
737 acpi_res_parse_ioport(device_t dev, void *context, uint32_t base,
738 uint32_t length)
739 {
740 struct acpi_resources *res = context;
741 struct acpi_io *ar;
742
743 /*
744 * Check if there is another I/O port directly below/under
745 * this one.
746 */
747 SIMPLEQ_FOREACH(ar, &res->ar_io, ar_list) {
748 if (ar->ar_base == base + length ) {
749 /*
750 * Entry just below existing entry - adjust
751 * the entry and return.
752 */
753 ar->ar_base = base;
754 ar->ar_length += length;
755 return;
756 } else if (ar->ar_base + ar->ar_length == base) {
757 /*
758 * Entry just above existing entry - adjust
759 * the entry and return.
760 */
761 ar->ar_length += length;
762 return;
763 }
764 }
765
766 ar = ACPI_ALLOCATE(sizeof(*ar));
767 if (ar == NULL) {
768 aprint_error_dev(dev, "ACPI: unable to allocate I/O resource %d\n",
769 res->ar_nio);
770 res->ar_nio++;
771 return;
772 }
773
774 ar->ar_index = res->ar_nio++;
775 ar->ar_base = base;
776 ar->ar_length = length;
777
778 SIMPLEQ_INSERT_TAIL(&res->ar_io, ar, ar_list);
779 }
780
781 static void
782 acpi_res_parse_iorange(device_t dev, void *context, uint32_t low,
783 uint32_t high, uint32_t length, uint32_t align)
784 {
785 struct acpi_resources *res = context;
786 struct acpi_iorange *ar;
787
788 ar = ACPI_ALLOCATE(sizeof(*ar));
789 if (ar == NULL) {
790 aprint_error_dev(dev, "ACPI: unable to allocate I/O range resource %d\n",
791 res->ar_niorange);
792 res->ar_niorange++;
793 return;
794 }
795
796 ar->ar_index = res->ar_niorange++;
797 ar->ar_low = low;
798 ar->ar_high = high;
799 ar->ar_length = length;
800 ar->ar_align = align;
801
802 SIMPLEQ_INSERT_TAIL(&res->ar_iorange, ar, ar_list);
803 }
804
805 static void
806 acpi_res_parse_memory(device_t dev, void *context, uint64_t base,
807 uint64_t length, uint64_t xbase)
808 {
809 struct acpi_resources *res = context;
810 struct acpi_mem *ar;
811
812 ar = ACPI_ALLOCATE(sizeof(*ar));
813 if (ar == NULL) {
814 aprint_error_dev(dev, "ACPI: unable to allocate Memory resource %d\n",
815 res->ar_nmem);
816 res->ar_nmem++;
817 return;
818 }
819
820 ar->ar_index = res->ar_nmem++;
821 ar->ar_base = base;
822 ar->ar_length = length;
823 ar->ar_xbase = xbase;
824
825 SIMPLEQ_INSERT_TAIL(&res->ar_mem, ar, ar_list);
826 }
827
828 static void
829 acpi_res_parse_memrange(device_t dev, void *context, uint64_t low,
830 uint64_t high, uint64_t length, uint64_t align)
831 {
832 struct acpi_resources *res = context;
833 struct acpi_memrange *ar;
834
835 ar = ACPI_ALLOCATE(sizeof(*ar));
836 if (ar == NULL) {
837 aprint_error_dev(dev, "ACPI: unable to allocate Memory range resource %d\n",
838 res->ar_nmemrange);
839 res->ar_nmemrange++;
840 return;
841 }
842
843 ar->ar_index = res->ar_nmemrange++;
844 ar->ar_low = low;
845 ar->ar_high = high;
846 ar->ar_length = length;
847 ar->ar_align = align;
848
849 SIMPLEQ_INSERT_TAIL(&res->ar_memrange, ar, ar_list);
850 }
851
852 static void
853 acpi_res_parse_irq(device_t dev, void *context, uint32_t irq, uint32_t type)
854 {
855 struct acpi_resources *res = context;
856 struct acpi_irq *ar;
857
858 ar = ACPI_ALLOCATE(sizeof(*ar));
859 if (ar == NULL) {
860 aprint_error_dev(dev, "ACPI: unable to allocate IRQ resource %d\n",
861 res->ar_nirq);
862 res->ar_nirq++;
863 return;
864 }
865
866 ar->ar_index = res->ar_nirq++;
867 ar->ar_irq = irq;
868 ar->ar_type = type;
869
870 SIMPLEQ_INSERT_TAIL(&res->ar_irq, ar, ar_list);
871 }
872
873 static void
874 acpi_res_parse_drq(device_t dev, void *context, uint32_t drq)
875 {
876 struct acpi_resources *res = context;
877 struct acpi_drq *ar;
878
879 ar = ACPI_ALLOCATE(sizeof(*ar));
880 if (ar == NULL) {
881 aprint_error_dev(dev, "ACPI: unable to allocate DRQ resource %d\n",
882 res->ar_ndrq);
883 res->ar_ndrq++;
884 return;
885 }
886
887 ar->ar_index = res->ar_ndrq++;
888 ar->ar_drq = drq;
889
890 SIMPLEQ_INSERT_TAIL(&res->ar_drq, ar, ar_list);
891 }
892
893 static void
894 acpi_res_parse_start_dep(device_t dev, void *context,
895 int preference)
896 {
897
898 aprint_error_dev(dev, "ACPI: dependent functions not supported\n");
899 }
900
901 static void
902 acpi_res_parse_end_dep(device_t dev, void *context)
903 {
904
905 /* Nothing to do. */
906 }
907