xref: /netbsd-src/sys/dev/acpi/acpi_resource.c (revision 181254a7b1bdde6873432bffef2d2decc4b5c22f)
1 /*	$NetBSD: acpi_resource.c,v 1.41 2019/12/31 17:26:04 jmcneill 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.41 2019/12/31 17:26:04 jmcneill 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