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