Home | History | Annotate | Line # | Download | only in acpi
      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