1/* $NetBSD: acpi_resource.c,v 1.37 2015/07/27 04:50:50 msaitoh 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 2015/07/27 04:50:50 msaitoh 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
80ACPI_MODULE_NAME("RESOURCE")
81
82static ACPI_STATUS acpi_resource_parse_callback(ACPI_RESOURCE *, void *);
83
84struct resource_parse_callback_arg {
85 const struct acpi_resource_parse_ops *ops;
86 device_t dev;
87 void *context;
88};
89
90static ACPI_STATUS
91acpi_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 break;
152
153 case ACPI_RESOURCE_TYPE_MEMORY32:
154 if (res->Data.Memory32.Minimum ==
155 res->Data.Memory32.Maximum) {
156 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
157 "Memory32 0x%x/%u\n",
158 res->Data.Memory32.Minimum,
159 res->Data.Memory32.AddressLength));
160 if (ops->memory)
161 (*ops->memory)(arg->dev, arg->context,
162 res->Data.Memory32.Minimum,
163 res->Data.Memory32.AddressLength);
164 } else {
165 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
166 "Memory32 0x%x-0x%x/%u\n",
167 res->Data.Memory32.Minimum,
168 res->Data.Memory32.Maximum,
169 res->Data.Memory32.AddressLength));
170 if (ops->memrange)
171 (*ops->memrange)(arg->dev, arg->context,
172 res->Data.Memory32.Minimum,
173 res->Data.Memory32.Maximum,
174 res->Data.Memory32.AddressLength,
175 res->Data.Memory32.Alignment);
176 }
177 break;
178
179 case ACPI_RESOURCE_TYPE_MEMORY24:
180 if (res->Data.Memory24.Minimum ==
181 res->Data.Memory24.Maximum) {
182 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
183 "Memory24 0x%x/%u\n",
184 res->Data.Memory24.Minimum,
185 res->Data.Memory24.AddressLength));
186 if (ops->memory)
187 (*ops->memory)(arg->dev, arg->context,
188 res->Data.Memory24.Minimum,
189 res->Data.Memory24.AddressLength);
190 } else {
191 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
192 "Memory24 0x%x-0x%x/%u\n",
193 res->Data.Memory24.Minimum,
194 res->Data.Memory24.Maximum,
195 res->Data.Memory24.AddressLength));
196 if (ops->memrange)
197 (*ops->memrange)(arg->dev, arg->context,
198 res->Data.Memory24.Minimum,
199 res->Data.Memory24.Maximum,
200 res->Data.Memory24.AddressLength,
201 res->Data.Memory24.Alignment);
202 }
203 break;
204
205 case ACPI_RESOURCE_TYPE_IRQ:
206 for (i = 0; i < res->Data.Irq.InterruptCount; i++) {
207 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
208 "IRQ %u\n",
209 res->Data.Irq.Interrupts[i]));
210 if (ops->irq)
211 (*ops->irq)(arg->dev, arg->context,
212 res->Data.Irq.Interrupts[i],
213 res->Data.Irq.Triggering);
214 }
215 break;
216
217 case ACPI_RESOURCE_TYPE_DMA:
218 for (i = 0; i < res->Data.Dma.ChannelCount; i++) {
219 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
220 "DRQ %u\n",
221 res->Data.Dma.Channels[i]));
222 if (ops->drq)
223 (*ops->drq)(arg->dev, arg->context,
224 res->Data.Dma.Channels[i]);
225 }
226 break;
227
228 case ACPI_RESOURCE_TYPE_START_DEPENDENT:
229 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
230 "Start dependent functions: %u\n",
231 res->Data.StartDpf.CompatibilityPriority));
232 if (ops->start_dep)
233 (*ops->start_dep)(arg->dev, arg->context,
234 res->Data.StartDpf.CompatibilityPriority);
235 break;
236
237 case ACPI_RESOURCE_TYPE_END_DEPENDENT:
238 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
239 "End dependent functions\n"));
240 if (ops->end_dep)
241 (*ops->end_dep)(arg->dev, arg->context);
242 break;
243
244 case ACPI_RESOURCE_TYPE_ADDRESS32:
245 /* XXX Only fixed size supported for now */
246 if (res->Data.Address32.Address.AddressLength == 0 ||
247 res->Data.Address32.ProducerConsumer != ACPI_CONSUMER)
248 break;
249#define ADRRESS32_FIXED2(r) \
250 ((r)->Data.Address32.MinAddressFixed == ACPI_ADDRESS_FIXED && \
251 (r)->Data.Address32.MaxAddressFixed == ACPI_ADDRESS_FIXED)
252 switch (res->Data.Address32.ResourceType) {
253 case ACPI_MEMORY_RANGE:
254 if (ADRRESS32_FIXED2(res)) {
255 if (ops->memory)
256 (*ops->memory)(arg->dev, arg->context,
257 res->Data.Address32.Address.Minimum,
258 res->Data.Address32.Address.AddressLength);
259 } else {
260 if (ops->memrange)
261 (*ops->memrange)(arg->dev, arg->context,
262 res->Data.Address32.Address.Minimum,
263 res->Data.Address32.Address.Maximum,
264 res->Data.Address32.Address.AddressLength,
265 res->Data.Address32.Address.Granularity);
266 }
267 break;
268 case ACPI_IO_RANGE:
269 if (ADRRESS32_FIXED2(res)) {
270 if (ops->ioport)
271 (*ops->ioport)(arg->dev, arg->context,
272 res->Data.Address32.Address.Minimum,
273 res->Data.Address32.Address.AddressLength);
274 } else {
275 if (ops->iorange)
276 (*ops->iorange)(arg->dev, arg->context,
277 res->Data.Address32.Address.Minimum,
278 res->Data.Address32.Address.Maximum,
279 res->Data.Address32.Address.AddressLength,
280 res->Data.Address32.Address.Granularity);
281 }
282 break;
283 case ACPI_BUS_NUMBER_RANGE:
284 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
285 "Address32/BusNumber unimplemented\n"));
286 break;
287 }
288#undef ADRRESS32_FIXED2
289 break;
290
291 case ACPI_RESOURCE_TYPE_ADDRESS16:
292 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
293 "Address16 unimplemented\n"));
294 break;
295
296 case ACPI_RESOURCE_TYPE_ADDRESS64:
297 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
298 "Address64 unimplemented\n"));
299 break;
300 case ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64:
301 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
302 "Extended address64 unimplemented\n"));
303 break;
304
305 case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
306 if (res->Data.ExtendedIrq.ProducerConsumer != ACPI_CONSUMER) {
307 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
308 "ignored ExtIRQ producer\n"));
309 break;
310 }
311 for (i = 0; i < res->Data.ExtendedIrq.InterruptCount; i++) {
312 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
313 "ExtIRQ %u\n",
314 res->Data.ExtendedIrq.Interrupts[i]));
315 if (ops->irq)
316 (*ops->irq)(arg->dev, arg->context,
317 res->Data.ExtendedIrq.Interrupts[i],
318 res->Data.ExtendedIrq.Triggering);
319 }
320 break;
321
322 case ACPI_RESOURCE_TYPE_GENERIC_REGISTER:
323 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
324 "GenericRegister unimplemented\n"));
325 break;
326
327 case ACPI_RESOURCE_TYPE_VENDOR:
328 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
329 "VendorSpecific unimplemented\n"));
330 break;
331
332 default:
333 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
334 "Unknown resource type: %u\n", res->Type));
335 break;
336 }
337
338 return_ACPI_STATUS(AE_OK);
339}
340
341
342/*
343 * acpi_resource_parse:
344 *
345 * Parse a device node's resources and fill them in for the
346 * client.
347 *
348 * This API supports _CRS (current resources) and
349 * _PRS (possible resources).
350 *
351 * Note that it might be nice to also locate ACPI-specific resource
352 * items, such as GPE bits.
353 */
354ACPI_STATUS
355acpi_resource_parse(device_t dev, ACPI_HANDLE handle, const char *path,
356 void *arg, const struct acpi_resource_parse_ops *ops)
357{
358 struct resource_parse_callback_arg cbarg;
359 ACPI_STATUS rv;
360
361 ACPI_FUNCTION_TRACE(__func__);
362
363 if (ops->init)
364 (*ops->init)(dev, arg, &cbarg.context);
365 else
366 cbarg.context = arg;
367 cbarg.ops = ops;
368 cbarg.dev = dev;
369
370 rv = AcpiWalkResources(handle, path, acpi_resource_parse_callback,
371 &cbarg);
372 if (ACPI_FAILURE(rv)) {
373 aprint_error_dev(dev, "ACPI: unable to get %s resources: %s\n",
374 path, AcpiFormatException(rv));
375 return_ACPI_STATUS(rv);
376 }
377
378 if (ops->fini)
379 (*ops->fini)(dev, cbarg.context);
380
381 return_ACPI_STATUS(AE_OK);
382}
383
384/*
385 * acpi_resource_print:
386 *
387 * Print the resources assigned to a device.
388 */
389void
390acpi_resource_print(device_t dev, struct acpi_resources *res)
391{
392 const char *sep;
393
394 if (SIMPLEQ_EMPTY(&res->ar_io) &&
395 SIMPLEQ_EMPTY(&res->ar_iorange) &&
396 SIMPLEQ_EMPTY(&res->ar_mem) &&
397 SIMPLEQ_EMPTY(&res->ar_memrange) &&
398 SIMPLEQ_EMPTY(&res->ar_irq) &&
399 SIMPLEQ_EMPTY(&res->ar_drq))
400 return;
401
402 aprint_normal(":");
403
404 if (SIMPLEQ_EMPTY(&res->ar_io) == 0) {
405 struct acpi_io *ar;
406
407 sep = "";
408 aprint_normal(" io ");
409 SIMPLEQ_FOREACH(ar, &res->ar_io, ar_list) {
410 aprint_normal("%s0x%x", sep, ar->ar_base);
411 if (ar->ar_length > 1)
412 aprint_normal("-0x%x", ar->ar_base +
413 ar->ar_length - 1);
414 sep = ",";
415 }
416 }
417
418 /* XXX iorange */
419
420 if (SIMPLEQ_EMPTY(&res->ar_mem) == 0) {
421 struct acpi_mem *ar;
422
423 sep = "";
424 aprint_normal(" mem ");
425 SIMPLEQ_FOREACH(ar, &res->ar_mem, ar_list) {
426 aprint_normal("%s0x%x", sep, ar->ar_base);
427 if (ar->ar_length > 1)
428 aprint_normal("-0x%x", ar->ar_base +
429 ar->ar_length - 1);
430 sep = ",";
431 }
432 }
433
434 /* XXX memrange */
435
436 if (SIMPLEQ_EMPTY(&res->ar_irq) == 0) {
437 struct acpi_irq *ar;
438
439 sep = "";
440 aprint_normal(" irq ");
441 SIMPLEQ_FOREACH(ar, &res->ar_irq, ar_list) {
442 aprint_normal("%s%d", sep, ar->ar_irq);
443 sep = ",";
444 }
445 }
446
447 if (SIMPLEQ_EMPTY(&res->ar_drq) == 0) {
448 struct acpi_drq *ar;
449
450 sep = "";
451 aprint_normal(" drq ");
452 SIMPLEQ_FOREACH(ar, &res->ar_drq, ar_list) {
453 aprint_normal("%s%d", sep, ar->ar_drq);
454 sep = ",";
455 }
456 }
457
458 aprint_normal("\n");
459 aprint_naive("\n");
460}
461
462/*
463 * acpi_resource_cleanup:
464 *
465 * Free all allocated buffers
466 */
467void
468acpi_resource_cleanup(struct acpi_resources *res)
469{
470 while (!SIMPLEQ_EMPTY(&res->ar_io)) {
471 struct acpi_io *ar;
472 ar = SIMPLEQ_FIRST(&res->ar_io);
473 SIMPLEQ_REMOVE_HEAD(&res->ar_io, ar_list);
474 ACPI_FREE(ar);
475 }
476
477 while (!SIMPLEQ_EMPTY(&res->ar_iorange)) {
478 struct acpi_iorange *ar;
479 ar = SIMPLEQ_FIRST(&res->ar_iorange);
480 SIMPLEQ_REMOVE_HEAD(&res->ar_iorange, ar_list);
481 ACPI_FREE(ar);
482 }
483
484 while (!SIMPLEQ_EMPTY(&res->ar_mem)) {
485 struct acpi_mem *ar;
486 ar = SIMPLEQ_FIRST(&res->ar_mem);
487 SIMPLEQ_REMOVE_HEAD(&res->ar_mem, ar_list);
488 ACPI_FREE(ar);
489 }
490
491 while (!SIMPLEQ_EMPTY(&res->ar_memrange)) {
492 struct acpi_memrange *ar;
493 ar = SIMPLEQ_FIRST(&res->ar_memrange);
494 SIMPLEQ_REMOVE_HEAD(&res->ar_memrange, ar_list);
495 ACPI_FREE(ar);
496 }
497
498 while (!SIMPLEQ_EMPTY(&res->ar_irq)) {
499 struct acpi_irq *ar;
500 ar = SIMPLEQ_FIRST(&res->ar_irq);
501 SIMPLEQ_REMOVE_HEAD(&res->ar_irq, ar_list);
502 ACPI_FREE(ar);
503 }
504
505 while (!SIMPLEQ_EMPTY(&res->ar_drq)) {
506 struct acpi_drq *ar;
507 ar = SIMPLEQ_FIRST(&res->ar_drq);
508 SIMPLEQ_REMOVE_HEAD(&res->ar_drq, ar_list);
509 ACPI_FREE(ar);
510 }
511
512 res->ar_nio = res->ar_niorange = res->ar_nmem =
513 res->ar_nmemrange = res->ar_nirq = res->ar_ndrq = 0;
514}
515
516struct acpi_io *
517acpi_res_io(struct acpi_resources *res, int idx)
518{
519 struct acpi_io *ar;
520
521 SIMPLEQ_FOREACH(ar, &res->ar_io, ar_list) {
522 if (ar->ar_index == idx)
523 return ar;
524 }
525 return NULL;
526}
527
528struct acpi_iorange *
529acpi_res_iorange(struct acpi_resources *res, int idx)
530{
531 struct acpi_iorange *ar;
532
533 SIMPLEQ_FOREACH(ar, &res->ar_iorange, ar_list) {
534 if (ar->ar_index == idx)
535 return ar;
536 }
537 return NULL;
538}
539
540struct acpi_mem *
541acpi_res_mem(struct acpi_resources *res, int idx)
542{
543 struct acpi_mem *ar;
544
545 SIMPLEQ_FOREACH(ar, &res->ar_mem, ar_list) {
546 if (ar->ar_index == idx)
547 return ar;
548 }
549 return NULL;
550}
551
552struct acpi_memrange *
553acpi_res_memrange(struct acpi_resources *res, int idx)
554{
555 struct acpi_memrange *ar;
556
557 SIMPLEQ_FOREACH(ar, &res->ar_memrange, ar_list) {
558 if (ar->ar_index == idx)
559 return ar;
560 }
561 return NULL;
562}
563
564struct acpi_irq *
565acpi_res_irq(struct acpi_resources *res, int idx)
566{
567 struct acpi_irq *ar;
568
569 SIMPLEQ_FOREACH(ar, &res->ar_irq, ar_list) {
570 if (ar->ar_index == idx)
571 return ar;
572 }
573 return NULL;
574}
575
576struct acpi_drq *
577acpi_res_drq(struct acpi_resources *res, int idx)
578{
579 struct acpi_drq *ar;
580
581 SIMPLEQ_FOREACH(ar, &res->ar_drq, ar_list) {
582 if (ar->ar_index == idx)
583 return ar;
584 }
585 return NULL;
586}
587
588/*****************************************************************************
589 * Default ACPI resource parse operations.
590 *****************************************************************************/
591
592static void acpi_res_parse_init(device_t, void *, void **);
593static void acpi_res_parse_fini(device_t, void *);
594
595static void acpi_res_parse_ioport(device_t, void *, uint32_t,
596 uint32_t);
597static void acpi_res_parse_iorange(device_t, void *, uint32_t,
598 uint32_t, uint32_t, uint32_t);
599
600static void acpi_res_parse_memory(device_t, void *, uint32_t,
601 uint32_t);
602static void acpi_res_parse_memrange(device_t, void *, uint32_t,
603 uint32_t, uint32_t, uint32_t);
604
605static void acpi_res_parse_irq(device_t, void *, uint32_t, uint32_t);
606static void acpi_res_parse_drq(device_t, void *, uint32_t);
607
608static void acpi_res_parse_start_dep(device_t, void *, int);
609static void acpi_res_parse_end_dep(device_t, void *);
610
611const struct acpi_resource_parse_ops acpi_resource_parse_ops_default = {
612 .init = acpi_res_parse_init,
613 .fini = acpi_res_parse_fini,
614
615 .ioport = acpi_res_parse_ioport,
616 .iorange = acpi_res_parse_iorange,
617
618 .memory = acpi_res_parse_memory,
619 .memrange = acpi_res_parse_memrange,
620
621 .irq = acpi_res_parse_irq,
622 .drq = acpi_res_parse_drq,
623
624 .start_dep = acpi_res_parse_start_dep,
625 .end_dep = acpi_res_parse_end_dep,
626};
627
628const struct acpi_resource_parse_ops acpi_resource_parse_ops_quiet = {
629 .init = acpi_res_parse_init,
630 .fini = NULL,
631
632 .ioport = acpi_res_parse_ioport,
633 .iorange = acpi_res_parse_iorange,
634
635 .memory = acpi_res_parse_memory,
636 .memrange = acpi_res_parse_memrange,
637
638 .irq = acpi_res_parse_irq,
639 .drq = acpi_res_parse_drq,
640
641 .start_dep = acpi_res_parse_start_dep,
642 .end_dep = acpi_res_parse_end_dep,
643};
644
645static void
646acpi_res_parse_init(device_t dev, void *arg, void **contextp)
647{
648 struct acpi_resources *res = arg;
649
650 SIMPLEQ_INIT(&res->ar_io);
651 res->ar_nio = 0;
652
653 SIMPLEQ_INIT(&res->ar_iorange);
654 res->ar_niorange = 0;
655
656 SIMPLEQ_INIT(&res->ar_mem);
657 res->ar_nmem = 0;
658
659 SIMPLEQ_INIT(&res->ar_memrange);
660 res->ar_nmemrange = 0;
661
662 SIMPLEQ_INIT(&res->ar_irq);
663 res->ar_nirq = 0;
664
665 SIMPLEQ_INIT(&res->ar_drq);
666 res->ar_ndrq = 0;
667
668 *contextp = res;
669}
670
671static void
672acpi_res_parse_fini(device_t dev, void *context)
673{
674 struct acpi_resources *res = context;
675
676 /* Print the resources we're using. */
677 acpi_resource_print(dev, res);
678}
679
680static void
681acpi_res_parse_ioport(device_t dev, void *context, uint32_t base,
682 uint32_t length)
683{
684 struct acpi_resources *res = context;
685 struct acpi_io *ar;
686
687 /*
688 * Check if there is another I/O port directly below/under
689 * this one.
690 */
691 SIMPLEQ_FOREACH(ar, &res->ar_io, ar_list) {
692 if (ar->ar_base == base + length ) {
693 /*
694 * Entry just below existing entry - adjust
695 * the entry and return.
696 */
697 ar->ar_base = base;
698 ar->ar_length += length;
699 return;
700 } else if (ar->ar_base + ar->ar_length == base) {
701 /*
702 * Entry just above existing entry - adjust
703 * the entry and return.
704 */
705 ar->ar_length += length;
706 return;
707 }
708 }
709
710 ar = ACPI_ALLOCATE(sizeof(*ar));
711 if (ar == NULL) {
712 aprint_error_dev(dev, "ACPI: unable to allocate I/O resource %d\n",
713 res->ar_nio);
714 res->ar_nio++;
715 return;
716 }
717
718 ar->ar_index = res->ar_nio++;
719 ar->ar_base = base;
720 ar->ar_length = length;
721
722 SIMPLEQ_INSERT_TAIL(&res->ar_io, ar, ar_list);
723}
724
725static void
726acpi_res_parse_iorange(device_t dev, void *context, uint32_t low,
727 uint32_t high, uint32_t length, uint32_t align)
728{
729 struct acpi_resources *res = context;
730 struct acpi_iorange *ar;
731
732 ar = ACPI_ALLOCATE(sizeof(*ar));
733 if (ar == NULL) {
734 aprint_error_dev(dev, "ACPI: unable to allocate I/O range resource %d\n",
735 res->ar_niorange);
736 res->ar_niorange++;
737 return;
738 }
739
740 ar->ar_index = res->ar_niorange++;
741 ar->ar_low = low;
742 ar->ar_high = high;
743 ar->ar_length = length;
744 ar->ar_align = align;
745
746 SIMPLEQ_INSERT_TAIL(&res->ar_iorange, ar, ar_list);
747}
748
749static void
750acpi_res_parse_memory(device_t dev, void *context, uint32_t base,
751 uint32_t length)
752{
753 struct acpi_resources *res = context;
754 struct acpi_mem *ar;
755
756 ar = ACPI_ALLOCATE(sizeof(*ar));
757 if (ar == NULL) {
758 aprint_error_dev(dev, "ACPI: unable to allocate Memory resource %d\n",
759 res->ar_nmem);
760 res->ar_nmem++;
761 return;
762 }
763
764 ar->ar_index = res->ar_nmem++;
765 ar->ar_base = base;
766 ar->ar_length = length;
767
768 SIMPLEQ_INSERT_TAIL(&res->ar_mem, ar, ar_list);
769}
770
771static void
772acpi_res_parse_memrange(device_t dev, void *context, uint32_t low,
773 uint32_t high, uint32_t length, uint32_t align)
774{
775 struct acpi_resources *res = context;
776 struct acpi_memrange *ar;
777
778 ar = ACPI_ALLOCATE(sizeof(*ar));
779 if (ar == NULL) {
780 aprint_error_dev(dev, "ACPI: unable to allocate Memory range resource %d\n",
781 res->ar_nmemrange);
782 res->ar_nmemrange++;
783 return;
784 }
785
786 ar->ar_index = res->ar_nmemrange++;
787 ar->ar_low = low;
788 ar->ar_high = high;
789 ar->ar_length = length;
790 ar->ar_align = align;
791
792 SIMPLEQ_INSERT_TAIL(&res->ar_memrange, ar, ar_list);
793}
794
795static void
796acpi_res_parse_irq(device_t dev, void *context, uint32_t irq, uint32_t type)
797{
798 struct acpi_resources *res = context;
799 struct acpi_irq *ar;
800
801 ar = ACPI_ALLOCATE(sizeof(*ar));
802 if (ar == NULL) {
803 aprint_error_dev(dev, "ACPI: unable to allocate IRQ resource %d\n",
804 res->ar_nirq);
805 res->ar_nirq++;
806 return;
807 }
808
809 ar->ar_index = res->ar_nirq++;
810 ar->ar_irq = irq;
811 ar->ar_type = type;
812
813 SIMPLEQ_INSERT_TAIL(&res->ar_irq, ar, ar_list);
814}
815
816static void
817acpi_res_parse_drq(device_t dev, void *context, uint32_t drq)
818{
819 struct acpi_resources *res = context;
820 struct acpi_drq *ar;
821
822 ar = ACPI_ALLOCATE(sizeof(*ar));
823 if (ar == NULL) {
824 aprint_error_dev(dev, "ACPI: unable to allocate DRQ resource %d\n",
825 res->ar_ndrq);
826 res->ar_ndrq++;
827 return;
828 }
829
830 ar->ar_index = res->ar_ndrq++;
831 ar->ar_drq = drq;
832
833 SIMPLEQ_INSERT_TAIL(&res->ar_drq, ar, ar_list);
834}
835
836static void
837acpi_res_parse_start_dep(device_t dev, void *context,
838 int preference)
839{
840
841 aprint_error_dev(dev, "ACPI: dependent functions not supported\n");
842}
843
844static void
845acpi_res_parse_end_dep(device_t dev, void *context)
846{
847
848 /* Nothing to do. */
849}
850