xref: /netbsd-src/sys/dev/acpi/acpi_resource.c (revision b0bb4503535f46d986306941621a58cbe2316831)
1 /*	$NetBSD: acpi_resource.c,v 1.44 2025/01/02 16:32:34 andvar 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.44 2025/01/02 16:32:34 andvar 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 	bool include_producer;
87 	device_t dev;
88 	void *context;
89 };
90 
91 static ACPI_STATUS
92 acpi_resource_parse_callback(ACPI_RESOURCE *res, void *context)
93 {
94 	struct resource_parse_callback_arg *arg = context;
95 	const struct acpi_resource_parse_ops *ops;
96 	int i;
97 
98 	ACPI_FUNCTION_TRACE(__func__);
99 
100 	ops = arg->ops;
101 
102 	switch (res->Type) {
103 	case ACPI_RESOURCE_TYPE_END_TAG:
104 		ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "EndTag\n"));
105 		break;
106 	case ACPI_RESOURCE_TYPE_FIXED_IO:
107 		ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
108 				     "FixedIo 0x%x/%u\n",
109 				     res->Data.FixedIo.Address,
110 				     res->Data.FixedIo.AddressLength));
111 		if (ops->ioport)
112 			(*ops->ioport)(arg->dev, arg->context,
113 			    res->Data.FixedIo.Address,
114 			    res->Data.FixedIo.AddressLength);
115 		break;
116 
117 	case ACPI_RESOURCE_TYPE_IO:
118 		if (res->Data.Io.Minimum ==
119 		    res->Data.Io.Maximum) {
120 			ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
121 					     "Io 0x%x/%u\n",
122 					     res->Data.Io.Minimum,
123 					     res->Data.Io.AddressLength));
124 			if (ops->ioport)
125 				(*ops->ioport)(arg->dev, arg->context,
126 				    res->Data.Io.Minimum,
127 				    res->Data.Io.AddressLength);
128 		} else {
129 			ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
130 					     "Io 0x%x-0x%x/%u\n",
131 					     res->Data.Io.Minimum,
132 					     res->Data.Io.Maximum,
133 					     res->Data.Io.AddressLength));
134 			if (ops->iorange)
135 				(*ops->iorange)(arg->dev, arg->context,
136 				    res->Data.Io.Minimum,
137 				    res->Data.Io.Maximum,
138 				    res->Data.Io.AddressLength,
139 				    res->Data.Io.Alignment);
140 		}
141 		break;
142 
143 	case ACPI_RESOURCE_TYPE_FIXED_MEMORY32:
144 		ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
145 				     "FixedMemory32 0x%x/%u\n",
146 				     res->Data.FixedMemory32.Address,
147 				     res->Data.FixedMemory32.AddressLength));
148 		if (ops->memory)
149 			(*ops->memory)(arg->dev, arg->context,
150 			    res->Data.FixedMemory32.Address,
151 			    res->Data.FixedMemory32.AddressLength,
152 			    res->Data.FixedMemory32.Address);
153 		break;
154 
155 	case ACPI_RESOURCE_TYPE_MEMORY32:
156 		if (res->Data.Memory32.Minimum ==
157 		    res->Data.Memory32.Maximum) {
158 			ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
159 					     "Memory32 0x%x/%u\n",
160 					     res->Data.Memory32.Minimum,
161 					     res->Data.Memory32.AddressLength));
162 			if (ops->memory)
163 				(*ops->memory)(arg->dev, arg->context,
164 				    res->Data.Memory32.Minimum,
165 				    res->Data.Memory32.AddressLength,
166 				    res->Data.Memory32.Minimum);
167 		} else {
168 			ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
169 					     "Memory32 0x%x-0x%x/%u\n",
170 					     res->Data.Memory32.Minimum,
171 					     res->Data.Memory32.Maximum,
172 					     res->Data.Memory32.AddressLength));
173 			if (ops->memrange)
174 				(*ops->memrange)(arg->dev, arg->context,
175 				    res->Data.Memory32.Minimum,
176 				    res->Data.Memory32.Maximum,
177 				    res->Data.Memory32.AddressLength,
178 				    res->Data.Memory32.Alignment);
179 		}
180 		break;
181 
182 	case ACPI_RESOURCE_TYPE_MEMORY24:
183 		if (res->Data.Memory24.Minimum ==
184 		    res->Data.Memory24.Maximum) {
185 			ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
186 					     "Memory24 0x%x/%u\n",
187 					     res->Data.Memory24.Minimum,
188 					     res->Data.Memory24.AddressLength));
189 			if (ops->memory)
190 				(*ops->memory)(arg->dev, arg->context,
191 				    res->Data.Memory24.Minimum,
192 				    res->Data.Memory24.AddressLength,
193 				    res->Data.Memory24.Minimum);
194 		} else {
195 			ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
196 					     "Memory24 0x%x-0x%x/%u\n",
197 					     res->Data.Memory24.Minimum,
198 					     res->Data.Memory24.Maximum,
199 					     res->Data.Memory24.AddressLength));
200 			if (ops->memrange)
201 				(*ops->memrange)(arg->dev, arg->context,
202 				    res->Data.Memory24.Minimum,
203 				    res->Data.Memory24.Maximum,
204 				    res->Data.Memory24.AddressLength,
205 				    res->Data.Memory24.Alignment);
206 		}
207 		break;
208 
209 	case ACPI_RESOURCE_TYPE_IRQ:
210 		for (i = 0; i < res->Data.Irq.InterruptCount; i++) {
211 			ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
212 					     "IRQ %u\n",
213 					     res->Data.Irq.Interrupts[i]));
214 			if (ops->irq)
215 				(*ops->irq)(arg->dev, arg->context,
216 				    res->Data.Irq.Interrupts[i],
217 				    res->Data.Irq.Triggering);
218 		}
219 		break;
220 
221 	case ACPI_RESOURCE_TYPE_DMA:
222 		for (i = 0; i < res->Data.Dma.ChannelCount; i++) {
223 			ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
224 					     "DRQ %u\n",
225 					     res->Data.Dma.Channels[i]));
226 			if (ops->drq)
227 				(*ops->drq)(arg->dev, arg->context,
228 				    res->Data.Dma.Channels[i]);
229 		}
230 		break;
231 
232 	case ACPI_RESOURCE_TYPE_START_DEPENDENT:
233 		ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
234 				     "Start dependent functions: %u\n",
235 				     res->Data.StartDpf.CompatibilityPriority));
236 		if (ops->start_dep)
237 			(*ops->start_dep)(arg->dev, arg->context,
238 			    res->Data.StartDpf.CompatibilityPriority);
239 		break;
240 
241 	case ACPI_RESOURCE_TYPE_END_DEPENDENT:
242 		ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
243 				     "End dependent functions\n"));
244 		if (ops->end_dep)
245 			(*ops->end_dep)(arg->dev, arg->context);
246 		break;
247 
248 	case ACPI_RESOURCE_TYPE_ADDRESS32:
249 		/* XXX Only fixed size supported for now */
250 		if (res->Data.Address32.Address.AddressLength == 0)
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 			break;
306 #define ADDRESS64_FIXED2(r)						\
307 	((r)->Data.Address64.MinAddressFixed == ACPI_ADDRESS_FIXED &&	\
308 	 (r)->Data.Address64.MaxAddressFixed == ACPI_ADDRESS_FIXED)
309 		switch (res->Data.Address64.ResourceType) {
310 		case ACPI_MEMORY_RANGE:
311 			if (ADDRESS64_FIXED2(res)) {
312 				if (ops->memory)
313 					(*ops->memory)(arg->dev, arg->context,
314 					    res->Data.Address64.Address.Minimum,
315 					    res->Data.Address64.Address.AddressLength,
316 					    res->Data.Address64.Address.Minimum +
317 					        res->Data.Address64.Address.TranslationOffset);
318 			} else {
319 				if (ops->memrange)
320 					(*ops->memrange)(arg->dev, arg->context,
321 					    res->Data.Address64.Address.Minimum,
322 					    res->Data.Address64.Address.Maximum,
323 					    res->Data.Address64.Address.AddressLength,
324 					    res->Data.Address64.Address.Granularity);
325 			}
326 			break;
327 		case ACPI_IO_RANGE:
328 			if (ADDRESS64_FIXED2(res)) {
329 				if (ops->ioport)
330 					(*ops->ioport)(arg->dev, arg->context,
331 					    res->Data.Address64.Address.Minimum,
332 					    res->Data.Address64.Address.AddressLength);
333 			} else {
334 				if (ops->iorange)
335 					(*ops->iorange)(arg->dev, arg->context,
336 					    res->Data.Address64.Address.Minimum,
337 					    res->Data.Address64.Address.Maximum,
338 					    res->Data.Address64.Address.AddressLength,
339 					    res->Data.Address64.Address.Granularity);
340 			}
341 			break;
342 		case ACPI_BUS_NUMBER_RANGE:
343 			ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
344 				      "Address64/BusNumber unimplemented\n"));
345 			break;
346 		}
347 #undef ADDRESS64_FIXED2
348 #else
349 		ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
350 				     "Address64 unimplemented\n"));
351 #endif
352 		break;
353 	case ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64:
354 		ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
355 				     "Extended address64 unimplemented\n"));
356 		break;
357 
358 	case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
359 		if (!arg->include_producer &&
360 		    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 	cbarg.include_producer = false;
424 
425 	rv = AcpiWalkResources(handle, path, acpi_resource_parse_callback,
426 	    &cbarg);
427 	if (ACPI_FAILURE(rv)) {
428 		aprint_error_dev(dev, "ACPI: unable to get %s resources: %s\n",
429 		    path, AcpiFormatException(rv));
430 		return_ACPI_STATUS(rv);
431 	}
432 
433 	if (ops->fini)
434 		(*ops->fini)(dev, cbarg.context);
435 
436 	return_ACPI_STATUS(AE_OK);
437 }
438 
439 /*
440  * acpi_resource_parse_any:
441  *
442  *	Parse a device node's resources and fill them in for the
443  *	client. Like acpi_resource_parse, but doesn't skip ResourceProducer
444  *	type resources.
445  */
446 ACPI_STATUS
447 acpi_resource_parse_any(device_t dev, ACPI_HANDLE handle, const char *path,
448     void *arg, const struct acpi_resource_parse_ops *ops)
449 {
450 	struct resource_parse_callback_arg cbarg;
451 	ACPI_STATUS rv;
452 
453 	ACPI_FUNCTION_TRACE(__func__);
454 
455 	if (ops->init)
456 		(*ops->init)(dev, arg, &cbarg.context);
457 	else
458 		cbarg.context = arg;
459 	cbarg.ops = ops;
460 	cbarg.dev = dev;
461 	cbarg.include_producer = true;
462 
463 	rv = AcpiWalkResources(handle, path, acpi_resource_parse_callback,
464 	    &cbarg);
465 	if (ACPI_FAILURE(rv)) {
466 		aprint_error_dev(dev, "ACPI: unable to get %s resources: %s\n",
467 		    path, AcpiFormatException(rv));
468 		return_ACPI_STATUS(rv);
469 	}
470 
471 	if (ops->fini)
472 		(*ops->fini)(dev, cbarg.context);
473 
474 	return_ACPI_STATUS(AE_OK);
475 }
476 
477 
478 /*
479  * acpi_resource_print:
480  *
481  *	Print the resources assigned to a device.
482  */
483 void
484 acpi_resource_print(device_t dev, struct acpi_resources *res)
485 {
486 	const char *sep;
487 
488 	if (SIMPLEQ_EMPTY(&res->ar_io) &&
489 	    SIMPLEQ_EMPTY(&res->ar_iorange) &&
490 	    SIMPLEQ_EMPTY(&res->ar_mem) &&
491 	    SIMPLEQ_EMPTY(&res->ar_memrange) &&
492 	    SIMPLEQ_EMPTY(&res->ar_irq) &&
493 	    SIMPLEQ_EMPTY(&res->ar_drq))
494 		return;
495 
496 	aprint_normal(":");
497 
498 	if (SIMPLEQ_EMPTY(&res->ar_io) == 0) {
499 		struct acpi_io *ar;
500 
501 		sep = "";
502 		aprint_normal(" io ");
503 		SIMPLEQ_FOREACH(ar, &res->ar_io, ar_list) {
504 			aprint_normal("%s0x%x", sep, ar->ar_base);
505 			if (ar->ar_length > 1)
506 				aprint_normal("-0x%x", ar->ar_base +
507 				    ar->ar_length - 1);
508 			sep = ",";
509 		}
510 	}
511 
512 	/* XXX iorange */
513 
514 	if (SIMPLEQ_EMPTY(&res->ar_mem) == 0) {
515 		struct acpi_mem *ar;
516 
517 		sep = "";
518 		aprint_normal(" mem ");
519 		SIMPLEQ_FOREACH(ar, &res->ar_mem, ar_list) {
520 			aprint_normal("%s0x%" PRIx64, sep,
521 			    (uint64_t)ar->ar_base);
522 			if (ar->ar_length > 1)
523 				aprint_normal("-0x%" PRIx64,
524 				    (uint64_t)ar->ar_base +
525 				    ar->ar_length - 1);
526 			sep = ",";
527 		}
528 	}
529 
530 	/* XXX memrange */
531 
532 	if (SIMPLEQ_EMPTY(&res->ar_irq) == 0) {
533 		struct acpi_irq *ar;
534 
535 		sep = "";
536 		aprint_normal(" irq ");
537 		SIMPLEQ_FOREACH(ar, &res->ar_irq, ar_list) {
538 			aprint_normal("%s%d", sep, ar->ar_irq);
539 			sep = ",";
540 		}
541 	}
542 
543 	if (SIMPLEQ_EMPTY(&res->ar_drq) == 0) {
544 		struct acpi_drq *ar;
545 
546 		sep = "";
547 		aprint_normal(" drq ");
548 		SIMPLEQ_FOREACH(ar, &res->ar_drq, ar_list) {
549 			aprint_normal("%s%d", sep, ar->ar_drq);
550 			sep = ",";
551 		}
552 	}
553 
554 	aprint_normal("\n");
555 	aprint_naive("\n");
556 }
557 
558 /*
559  * acpi_resource_cleanup:
560  *
561  *	Free all allocated buffers
562  */
563 void
564 acpi_resource_cleanup(struct acpi_resources *res)
565 {
566 	while (!SIMPLEQ_EMPTY(&res->ar_io)) {
567 		struct acpi_io *ar;
568 		ar = SIMPLEQ_FIRST(&res->ar_io);
569 		SIMPLEQ_REMOVE_HEAD(&res->ar_io, ar_list);
570 		ACPI_FREE(ar);
571 	}
572 
573 	while (!SIMPLEQ_EMPTY(&res->ar_iorange)) {
574 		struct acpi_iorange *ar;
575 		ar = SIMPLEQ_FIRST(&res->ar_iorange);
576 		SIMPLEQ_REMOVE_HEAD(&res->ar_iorange, ar_list);
577 		ACPI_FREE(ar);
578 	}
579 
580 	while (!SIMPLEQ_EMPTY(&res->ar_mem)) {
581 		struct acpi_mem *ar;
582 		ar = SIMPLEQ_FIRST(&res->ar_mem);
583 		SIMPLEQ_REMOVE_HEAD(&res->ar_mem, ar_list);
584 		ACPI_FREE(ar);
585 	}
586 
587 	while (!SIMPLEQ_EMPTY(&res->ar_memrange)) {
588 		struct acpi_memrange *ar;
589 		ar = SIMPLEQ_FIRST(&res->ar_memrange);
590 		SIMPLEQ_REMOVE_HEAD(&res->ar_memrange, ar_list);
591 		ACPI_FREE(ar);
592 	}
593 
594 	while (!SIMPLEQ_EMPTY(&res->ar_irq)) {
595 		struct acpi_irq *ar;
596 		ar = SIMPLEQ_FIRST(&res->ar_irq);
597 		SIMPLEQ_REMOVE_HEAD(&res->ar_irq, ar_list);
598 		ACPI_FREE(ar);
599 	}
600 
601 	while (!SIMPLEQ_EMPTY(&res->ar_drq)) {
602 		struct acpi_drq *ar;
603 		ar = SIMPLEQ_FIRST(&res->ar_drq);
604 		SIMPLEQ_REMOVE_HEAD(&res->ar_drq, ar_list);
605 		ACPI_FREE(ar);
606 	}
607 
608 	res->ar_nio = res->ar_niorange = res->ar_nmem =
609 	    res->ar_nmemrange = res->ar_nirq = res->ar_ndrq = 0;
610 }
611 
612 struct acpi_io *
613 acpi_res_io(struct acpi_resources *res, int idx)
614 {
615 	struct acpi_io *ar;
616 
617 	SIMPLEQ_FOREACH(ar, &res->ar_io, ar_list) {
618 		if (ar->ar_index == idx)
619 			return ar;
620 	}
621 	return NULL;
622 }
623 
624 struct acpi_iorange *
625 acpi_res_iorange(struct acpi_resources *res, int idx)
626 {
627 	struct acpi_iorange *ar;
628 
629 	SIMPLEQ_FOREACH(ar, &res->ar_iorange, ar_list) {
630 		if (ar->ar_index == idx)
631 			return ar;
632 	}
633 	return NULL;
634 }
635 
636 struct acpi_mem *
637 acpi_res_mem(struct acpi_resources *res, int idx)
638 {
639 	struct acpi_mem *ar;
640 
641 	SIMPLEQ_FOREACH(ar, &res->ar_mem, ar_list) {
642 		if (ar->ar_index == idx)
643 			return ar;
644 	}
645 	return NULL;
646 }
647 
648 struct acpi_memrange *
649 acpi_res_memrange(struct acpi_resources *res, int idx)
650 {
651 	struct acpi_memrange *ar;
652 
653 	SIMPLEQ_FOREACH(ar, &res->ar_memrange, ar_list) {
654 		if (ar->ar_index == idx)
655 			return ar;
656 	}
657 	return NULL;
658 }
659 
660 struct acpi_irq *
661 acpi_res_irq(struct acpi_resources *res, int idx)
662 {
663 	struct acpi_irq *ar;
664 
665 	SIMPLEQ_FOREACH(ar, &res->ar_irq, ar_list) {
666 		if (ar->ar_index == idx)
667 			return ar;
668 	}
669 	return NULL;
670 }
671 
672 struct acpi_drq *
673 acpi_res_drq(struct acpi_resources *res, int idx)
674 {
675 	struct acpi_drq *ar;
676 
677 	SIMPLEQ_FOREACH(ar, &res->ar_drq, ar_list) {
678 		if (ar->ar_index == idx)
679 			return ar;
680 	}
681 	return NULL;
682 }
683 
684 /*****************************************************************************
685  * Default ACPI resource parse operations.
686  *****************************************************************************/
687 
688 static void	acpi_res_parse_init(device_t, void *, void **);
689 static void	acpi_res_parse_fini(device_t, void *);
690 
691 static void	acpi_res_parse_ioport(device_t, void *, uint32_t,
692 		    uint32_t);
693 static void	acpi_res_parse_iorange(device_t, void *, uint32_t,
694 		    uint32_t, uint32_t, uint32_t);
695 
696 static void	acpi_res_parse_memory(device_t, void *, uint64_t,
697 		    uint64_t, uint64_t);
698 static void	acpi_res_parse_memrange(device_t, void *, uint64_t,
699 		    uint64_t, uint64_t, uint64_t);
700 
701 static void	acpi_res_parse_irq(device_t, void *, uint32_t, uint32_t);
702 static void	acpi_res_parse_drq(device_t, void *, uint32_t);
703 
704 static void	acpi_res_parse_start_dep(device_t, void *, int);
705 static void	acpi_res_parse_end_dep(device_t, void *);
706 
707 const struct acpi_resource_parse_ops acpi_resource_parse_ops_default = {
708 	.init = acpi_res_parse_init,
709 	.fini = acpi_res_parse_fini,
710 
711 	.ioport = acpi_res_parse_ioport,
712 	.iorange = acpi_res_parse_iorange,
713 
714 	.memory = acpi_res_parse_memory,
715 	.memrange = acpi_res_parse_memrange,
716 
717 	.irq = acpi_res_parse_irq,
718 	.drq = acpi_res_parse_drq,
719 
720 	.start_dep = acpi_res_parse_start_dep,
721 	.end_dep = acpi_res_parse_end_dep,
722 };
723 
724 const struct acpi_resource_parse_ops acpi_resource_parse_ops_quiet = {
725 	.init = acpi_res_parse_init,
726 	.fini = NULL,
727 
728 	.ioport = acpi_res_parse_ioport,
729 	.iorange = acpi_res_parse_iorange,
730 
731 	.memory = acpi_res_parse_memory,
732 	.memrange = acpi_res_parse_memrange,
733 
734 	.irq = acpi_res_parse_irq,
735 	.drq = acpi_res_parse_drq,
736 
737 	.start_dep = acpi_res_parse_start_dep,
738 	.end_dep = acpi_res_parse_end_dep,
739 };
740 
741 static void
742 acpi_res_parse_init(device_t dev, void *arg, void **contextp)
743 {
744 	struct acpi_resources *res = arg;
745 
746 	SIMPLEQ_INIT(&res->ar_io);
747 	res->ar_nio = 0;
748 
749 	SIMPLEQ_INIT(&res->ar_iorange);
750 	res->ar_niorange = 0;
751 
752 	SIMPLEQ_INIT(&res->ar_mem);
753 	res->ar_nmem = 0;
754 
755 	SIMPLEQ_INIT(&res->ar_memrange);
756 	res->ar_nmemrange = 0;
757 
758 	SIMPLEQ_INIT(&res->ar_irq);
759 	res->ar_nirq = 0;
760 
761 	SIMPLEQ_INIT(&res->ar_drq);
762 	res->ar_ndrq = 0;
763 
764 	*contextp = res;
765 }
766 
767 static void
768 acpi_res_parse_fini(device_t dev, void *context)
769 {
770 	struct acpi_resources *res = context;
771 
772 	/* Print the resources we're using. */
773 	acpi_resource_print(dev, res);
774 }
775 
776 static void
777 acpi_res_parse_ioport(device_t dev, void *context, uint32_t base,
778     uint32_t length)
779 {
780 	struct acpi_resources *res = context;
781 	struct acpi_io *ar;
782 
783 	/*
784 	 * Check if there is another I/O port directly below/under
785 	 * this one.
786 	 */
787 	SIMPLEQ_FOREACH(ar, &res->ar_io, ar_list) {
788 		if (ar->ar_base == base + length ) {
789 			/*
790 			 * Entry just below existing entry - adjust
791 			 * the entry and return.
792 			 */
793 			ar->ar_base = base;
794 			ar->ar_length += length;
795 			return;
796 		} else if (ar->ar_base + ar->ar_length == base) {
797 			/*
798 			 * Entry just above existing entry - adjust
799 			 * the entry and return.
800 			 */
801 			ar->ar_length += length;
802 			return;
803 		}
804 	}
805 
806 	/* IO and FixedIO I/O resource addresses are limited to 10/16-bit. */
807 	if (base + length - 1 > UINT16_MAX) {
808 		aprint_error_dev(dev, "ACPI: invalid I/O register resource %d,"
809 		    " base 0x%x, length %d\n",
810 		    res->ar_nio, base, length);
811 		res->ar_nio++;
812 		return;
813 	}
814 
815 	ar = ACPI_ALLOCATE(sizeof(*ar));
816 	if (ar == NULL) {
817 		aprint_error_dev(dev, "ACPI: unable to allocate I/O resource %d\n",
818 		    res->ar_nio);
819 		res->ar_nio++;
820 		return;
821 	}
822 
823 	ar->ar_index = res->ar_nio++;
824 	ar->ar_base = base;
825 	ar->ar_length = length;
826 
827 	SIMPLEQ_INSERT_TAIL(&res->ar_io, ar, ar_list);
828 }
829 
830 static void
831 acpi_res_parse_iorange(device_t dev, void *context, uint32_t low,
832     uint32_t high, uint32_t length, uint32_t align)
833 {
834 	struct acpi_resources *res = context;
835 	struct acpi_iorange *ar;
836 
837 	ar = ACPI_ALLOCATE(sizeof(*ar));
838 	if (ar == NULL) {
839 		aprint_error_dev(dev, "ACPI: unable to allocate I/O range resource %d\n",
840 		    res->ar_niorange);
841 		res->ar_niorange++;
842 		return;
843 	}
844 
845 	ar->ar_index = res->ar_niorange++;
846 	ar->ar_low = low;
847 	ar->ar_high = high;
848 	ar->ar_length = length;
849 	ar->ar_align = align;
850 
851 	SIMPLEQ_INSERT_TAIL(&res->ar_iorange, ar, ar_list);
852 }
853 
854 static void
855 acpi_res_parse_memory(device_t dev, void *context, uint64_t base,
856     uint64_t length, uint64_t xbase)
857 {
858 	struct acpi_resources *res = context;
859 	struct acpi_mem *ar;
860 
861 	ar = ACPI_ALLOCATE(sizeof(*ar));
862 	if (ar == NULL) {
863 		aprint_error_dev(dev, "ACPI: unable to allocate Memory resource %d\n",
864 		    res->ar_nmem);
865 		res->ar_nmem++;
866 		return;
867 	}
868 
869 	ar->ar_index = res->ar_nmem++;
870 	ar->ar_base = base;
871 	ar->ar_length = length;
872 	ar->ar_xbase = xbase;
873 
874 	SIMPLEQ_INSERT_TAIL(&res->ar_mem, ar, ar_list);
875 }
876 
877 static void
878 acpi_res_parse_memrange(device_t dev, void *context, uint64_t low,
879     uint64_t high, uint64_t length, uint64_t align)
880 {
881 	struct acpi_resources *res = context;
882 	struct acpi_memrange *ar;
883 
884 	ar = ACPI_ALLOCATE(sizeof(*ar));
885 	if (ar == NULL) {
886 		aprint_error_dev(dev, "ACPI: unable to allocate Memory range resource %d\n",
887 		    res->ar_nmemrange);
888 		res->ar_nmemrange++;
889 		return;
890 	}
891 
892 	ar->ar_index = res->ar_nmemrange++;
893 	ar->ar_low = low;
894 	ar->ar_high = high;
895 	ar->ar_length = length;
896 	ar->ar_align = align;
897 
898 	SIMPLEQ_INSERT_TAIL(&res->ar_memrange, ar, ar_list);
899 }
900 
901 static void
902 acpi_res_parse_irq(device_t dev, void *context, uint32_t irq, uint32_t type)
903 {
904 	struct acpi_resources *res = context;
905 	struct acpi_irq *ar;
906 
907 	ar = ACPI_ALLOCATE(sizeof(*ar));
908 	if (ar == NULL) {
909 		aprint_error_dev(dev, "ACPI: unable to allocate IRQ resource %d\n",
910 		    res->ar_nirq);
911 		res->ar_nirq++;
912 		return;
913 	}
914 
915 	ar->ar_index = res->ar_nirq++;
916 	ar->ar_irq = irq;
917 	ar->ar_type = type;
918 
919 	SIMPLEQ_INSERT_TAIL(&res->ar_irq, ar, ar_list);
920 }
921 
922 static void
923 acpi_res_parse_drq(device_t dev, void *context, uint32_t drq)
924 {
925 	struct acpi_resources *res = context;
926 	struct acpi_drq *ar;
927 
928 	ar = ACPI_ALLOCATE(sizeof(*ar));
929 	if (ar == NULL) {
930 		aprint_error_dev(dev, "ACPI: unable to allocate DRQ resource %d\n",
931 		    res->ar_ndrq);
932 		res->ar_ndrq++;
933 		return;
934 	}
935 
936 	ar->ar_index = res->ar_ndrq++;
937 	ar->ar_drq = drq;
938 
939 	SIMPLEQ_INSERT_TAIL(&res->ar_drq, ar, ar_list);
940 }
941 
942 static void
943 acpi_res_parse_start_dep(device_t dev, void *context,
944     int preference)
945 {
946 
947 	aprint_error_dev(dev, "ACPI: dependent functions not supported\n");
948 }
949 
950 static void
951 acpi_res_parse_end_dep(device_t dev, void *context)
952 {
953 
954 	/* Nothing to do. */
955 }
956