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