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