acpi_resource.c revision 130439
1/*-
2 * Copyright (c) 2000 Michael Smith
3 * Copyright (c) 2000 BSDi
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 */
27
28#include <sys/cdefs.h>
29__FBSDID("$FreeBSD: head/sys/dev/acpica/acpi_resource.c 130439 2004-06-13 22:52:30Z njl $");
30
31#include "opt_acpi.h"
32#include <sys/param.h>
33#include <sys/kernel.h>
34#include <sys/bus.h>
35#include <sys/malloc.h>
36#include <sys/module.h>
37
38#include <machine/bus.h>
39#include <machine/resource.h>
40#include <sys/rman.h>
41
42#include "acpi.h"
43#include <dev/acpica/acpivar.h>
44
45/* Hooks for the ACPI CA debugging infrastructure */
46#define _COMPONENT	ACPI_BUS
47ACPI_MODULE_NAME("RESOURCE")
48
49/*
50 * Fetch a device's resources and associate them with the device.
51 *
52 * Note that it might be nice to also locate ACPI-specific resource items, such
53 * as GPE bits.
54 *
55 * We really need to split the resource-fetching code out from the
56 * resource-parsing code, since we may want to use the parsing
57 * code for _PRS someday.
58 */
59ACPI_STATUS
60acpi_parse_resources(device_t dev, ACPI_HANDLE handle,
61		     struct acpi_parse_resource_set *set, void *arg)
62{
63    ACPI_BUFFER		buf;
64    ACPI_RESOURCE	*res;
65    char		*curr, *last;
66    ACPI_STATUS		status;
67    void		*context;
68
69    ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
70
71    /*
72     * Special-case some devices that abuse _PRS/_CRS to mean
73     * something other than "I consume this resource".
74     *
75     * XXX do we really need this?  It's only relevant once
76     *     we start always-allocating these resources, and even
77     *     then, the only special-cased device is likely to be
78     *     the PCI interrupt link.
79     */
80
81    /* Fetch the device's current resources. */
82    buf.Length = ACPI_ALLOCATE_BUFFER;
83    if (ACPI_FAILURE((status = AcpiGetCurrentResources(handle, &buf)))) {
84	if (status != AE_NOT_FOUND)
85	    printf("can't fetch resources for %s - %s\n",
86		   acpi_name(handle), AcpiFormatException(status));
87	return_ACPI_STATUS (status);
88    }
89    ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "%s - got %ld bytes of resources\n",
90		     acpi_name(handle), (long)buf.Length));
91    set->set_init(dev, arg, &context);
92
93    /* Iterate through the resources */
94    curr = buf.Pointer;
95    last = (char *)buf.Pointer + buf.Length;
96    while (curr < last) {
97	res = (ACPI_RESOURCE *)curr;
98	curr += res->Length;
99
100	/* Handle the individual resource types */
101	switch(res->Id) {
102	case ACPI_RSTYPE_END_TAG:
103	    ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "EndTag\n"));
104	    curr = last;
105	    break;
106	case ACPI_RSTYPE_FIXED_IO:
107	    if (res->Data.FixedIo.RangeLength <= 0)
108		break;
109	    ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "FixedIo 0x%x/%d\n",
110			     res->Data.FixedIo.BaseAddress,
111			     res->Data.FixedIo.RangeLength));
112	    set->set_ioport(dev, context,
113			    res->Data.FixedIo.BaseAddress,
114			    res->Data.FixedIo.RangeLength);
115	    break;
116	case ACPI_RSTYPE_IO:
117	    if (res->Data.Io.RangeLength <= 0)
118		break;
119	    if (res->Data.Io.MinBaseAddress == res->Data.Io.MaxBaseAddress) {
120		ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Io 0x%x/%d\n",
121				 res->Data.Io.MinBaseAddress,
122				 res->Data.Io.RangeLength));
123		set->set_ioport(dev, context,
124				res->Data.Io.MinBaseAddress,
125				res->Data.Io.RangeLength);
126	    } else {
127		ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Io 0x%x-0x%x/%d\n",
128				 res->Data.Io.MinBaseAddress,
129				 res->Data.Io.MaxBaseAddress,
130				 res->Data.Io.RangeLength));
131		set->set_iorange(dev, context,
132				 res->Data.Io.MinBaseAddress,
133				 res->Data.Io.MaxBaseAddress,
134				 res->Data.Io.RangeLength,
135				 res->Data.Io.Alignment);
136	    }
137	    break;
138	case ACPI_RSTYPE_FIXED_MEM32:
139	    if (res->Data.FixedMemory32.RangeLength <= 0)
140		break;
141	    ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "FixedMemory32 0x%x/%d\n",
142			      res->Data.FixedMemory32.RangeBaseAddress,
143			      res->Data.FixedMemory32.RangeLength));
144	    set->set_memory(dev, context,
145			    res->Data.FixedMemory32.RangeBaseAddress,
146			    res->Data.FixedMemory32.RangeLength);
147	    break;
148	case ACPI_RSTYPE_MEM32:
149	    if (res->Data.Memory32.RangeLength <= 0)
150		break;
151	    if (res->Data.Memory32.MinBaseAddress ==
152		res->Data.Memory32.MaxBaseAddress) {
153
154		ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Memory32 0x%x/%d\n",
155				  res->Data.Memory32.MinBaseAddress,
156				  res->Data.Memory32.RangeLength));
157		set->set_memory(dev, context,
158				res->Data.Memory32.MinBaseAddress,
159				res->Data.Memory32.RangeLength);
160	    } else {
161		ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Memory32 0x%x-0x%x/%d\n",
162				 res->Data.Memory32.MinBaseAddress,
163				 res->Data.Memory32.MaxBaseAddress,
164				 res->Data.Memory32.RangeLength));
165		set->set_memoryrange(dev, context,
166				     res->Data.Memory32.MinBaseAddress,
167				     res->Data.Memory32.MaxBaseAddress,
168				     res->Data.Memory32.RangeLength,
169				     res->Data.Memory32.Alignment);
170	    }
171	    break;
172	case ACPI_RSTYPE_MEM24:
173	    if (res->Data.Memory24.RangeLength <= 0)
174		break;
175	    if (res->Data.Memory24.MinBaseAddress ==
176		res->Data.Memory24.MaxBaseAddress) {
177
178		ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Memory24 0x%x/%d\n",
179				 res->Data.Memory24.MinBaseAddress,
180				 res->Data.Memory24.RangeLength));
181		set->set_memory(dev, context, res->Data.Memory24.MinBaseAddress,
182				res->Data.Memory24.RangeLength);
183	    } else {
184		ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Memory24 0x%x-0x%x/%d\n",
185				 res->Data.Memory24.MinBaseAddress,
186				 res->Data.Memory24.MaxBaseAddress,
187				 res->Data.Memory24.RangeLength));
188		set->set_memoryrange(dev, context,
189				     res->Data.Memory24.MinBaseAddress,
190				     res->Data.Memory24.MaxBaseAddress,
191				     res->Data.Memory24.RangeLength,
192				     res->Data.Memory24.Alignment);
193	    }
194	    break;
195	case ACPI_RSTYPE_IRQ:
196	    /*
197	     * from 1.0b 6.4.2
198	     * "This structure is repeated for each separate interrupt
199	     * required"
200	     */
201	    set->set_irq(dev, context, res->Data.Irq.Interrupts,
202		res->Data.Irq.NumberOfInterrupts, res->Data.Irq.EdgeLevel,
203		res->Data.Irq.ActiveHighLow);
204	    break;
205	case ACPI_RSTYPE_DMA:
206	    /*
207	     * from 1.0b 6.4.3
208	     * "This structure is repeated for each separate dma channel
209	     * required"
210	     */
211	    set->set_drq(dev, context, res->Data.Dma.Channels,
212			 res->Data.Dma.NumberOfChannels);
213	    break;
214	case ACPI_RSTYPE_START_DPF:
215	    ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "start dependant functions\n"));
216	    set->set_start_dependant(dev, context,
217				     res->Data.StartDpf.CompatibilityPriority);
218	    break;
219	case ACPI_RSTYPE_END_DPF:
220	    ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "end dependant functions\n"));
221	    set->set_end_dependant(dev, context);
222	    break;
223	case ACPI_RSTYPE_ADDRESS32:
224	    if (res->Data.Address32.AddressLength <= 0)
225		break;
226	    if (res->Data.Address32.ProducerConsumer != ACPI_CONSUMER) {
227		ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
228		    "ignored Address32 %s producer\n",
229		    res->Data.Address32.ResourceType == ACPI_IO_RANGE ?
230		    "IO" : "Memory"));
231		break;
232	    }
233	    if (res->Data.Address32.ResourceType != ACPI_MEMORY_RANGE &&
234		res->Data.Address32.ResourceType != ACPI_IO_RANGE) {
235		ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
236		    "ignored Address32 for non-memory, non-I/O\n"));
237		break;
238	    }
239
240	    if (res->Data.Address32.MinAddressFixed == ACPI_ADDRESS_FIXED &&
241		res->Data.Address32.MaxAddressFixed == ACPI_ADDRESS_FIXED) {
242
243		if (res->Data.Address32.ResourceType == ACPI_MEMORY_RANGE) {
244		    ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
245				     "Address32/Memory 0x%x/%d\n",
246				     res->Data.Address32.MinAddressRange,
247				     res->Data.Address32.AddressLength));
248		    set->set_memory(dev, context,
249				    res->Data.Address32.MinAddressRange,
250				    res->Data.Address32.AddressLength);
251		} else {
252		    ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
253				     "Address32/IO 0x%x/%d\n",
254				     res->Data.Address32.MinAddressRange,
255				     res->Data.Address32.AddressLength));
256		    set->set_ioport(dev, context,
257				    res->Data.Address32.MinAddressRange,
258				    res->Data.Address32.AddressLength);
259		}
260	    } else {
261		if (res->Data.Address32.ResourceType == ACPI_MEMORY_RANGE) {
262		    ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
263				     "Address32/Memory 0x%x-0x%x/%d\n",
264				     res->Data.Address32.MinAddressRange,
265				     res->Data.Address32.MaxAddressRange,
266				     res->Data.Address32.AddressLength));
267		    set->set_memoryrange(dev, context,
268					  res->Data.Address32.MinAddressRange,
269					  res->Data.Address32.MaxAddressRange,
270					  res->Data.Address32.AddressLength,
271					  res->Data.Address32.Granularity);
272		} else {
273		    ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
274				     "Address32/IO 0x%x-0x%x/%d\n",
275				     res->Data.Address32.MinAddressRange,
276				     res->Data.Address32.MaxAddressRange,
277				     res->Data.Address32.AddressLength));
278		    set->set_iorange(dev, context,
279				     res->Data.Address32.MinAddressRange,
280				     res->Data.Address32.MaxAddressRange,
281				     res->Data.Address32.AddressLength,
282				     res->Data.Address32.Granularity);
283		}
284	    }
285	    break;
286	case ACPI_RSTYPE_ADDRESS16:
287	    if (res->Data.Address16.AddressLength <= 0)
288		break;
289	    if (res->Data.Address16.ProducerConsumer != ACPI_CONSUMER) {
290		ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
291		    "ignored Address16 %s producer\n",
292		    res->Data.Address16.ResourceType == ACPI_IO_RANGE ?
293		    "IO" : "Memory"));
294		break;
295	    }
296	    if (res->Data.Address16.ResourceType != ACPI_MEMORY_RANGE &&
297		res->Data.Address16.ResourceType != ACPI_IO_RANGE) {
298		ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
299			"ignored Address16 for non-memory, non-I/O\n"));
300		break;
301	    }
302
303	    if (res->Data.Address16.MinAddressFixed == ACPI_ADDRESS_FIXED &&
304		res->Data.Address16.MaxAddressFixed == ACPI_ADDRESS_FIXED) {
305
306		if (res->Data.Address16.ResourceType == ACPI_MEMORY_RANGE) {
307		    ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
308				     "Address16/Memory 0x%x/%d\n",
309				     res->Data.Address16.MinAddressRange,
310				     res->Data.Address16.AddressLength));
311		    set->set_memory(dev, context,
312				    res->Data.Address16.MinAddressRange,
313				    res->Data.Address16.AddressLength);
314		} else {
315		    ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
316				     "Address16/IO 0x%x/%d\n",
317				     res->Data.Address16.MinAddressRange,
318				     res->Data.Address16.AddressLength));
319		    set->set_ioport(dev, context,
320				    res->Data.Address16.MinAddressRange,
321				    res->Data.Address16.AddressLength);
322		}
323	    } else {
324		if (res->Data.Address16.ResourceType == ACPI_MEMORY_RANGE) {
325		    ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
326				     "Address16/Memory 0x%x-0x%x/%d\n",
327				     res->Data.Address16.MinAddressRange,
328				     res->Data.Address16.MaxAddressRange,
329				     res->Data.Address16.AddressLength));
330		    set->set_memoryrange(dev, context,
331					  res->Data.Address16.MinAddressRange,
332					  res->Data.Address16.MaxAddressRange,
333					  res->Data.Address16.AddressLength,
334					  res->Data.Address16.Granularity);
335		} else {
336		    ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
337				     "Address16/IO 0x%x-0x%x/%d\n",
338				     res->Data.Address16.MinAddressRange,
339				     res->Data.Address16.MaxAddressRange,
340				     res->Data.Address16.AddressLength));
341		    set->set_iorange(dev, context,
342				     res->Data.Address16.MinAddressRange,
343				     res->Data.Address16.MaxAddressRange,
344				     res->Data.Address16.AddressLength,
345				     res->Data.Address16.Granularity);
346		}
347	    }
348	    break;
349	case ACPI_RSTYPE_ADDRESS64:
350	    ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
351			     "unimplemented Address64 resource\n"));
352	    break;
353	case ACPI_RSTYPE_EXT_IRQ:
354	    /* XXX special handling? */
355	    set->set_irq(dev, context,res->Data.ExtendedIrq.Interrupts,
356		res->Data.ExtendedIrq.NumberOfInterrupts,
357		res->Data.ExtendedIrq.EdgeLevel,
358		res->Data.ExtendedIrq.ActiveHighLow);
359	    break;
360	case ACPI_RSTYPE_VENDOR:
361	    ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
362			     "unimplemented VendorSpecific resource\n"));
363	    break;
364	default:
365	    break;
366	}
367    }
368
369    AcpiOsFree(buf.Pointer);
370    set->set_done(dev, context);
371    return_ACPI_STATUS (AE_OK);
372}
373
374/*
375 * Resource-set vectors used to attach _CRS-derived resources
376 * to an ACPI device.
377 */
378static void	acpi_res_set_init(device_t dev, void *arg, void **context);
379static void	acpi_res_set_done(device_t dev, void *context);
380static void	acpi_res_set_ioport(device_t dev, void *context,
381				    u_int32_t base, u_int32_t length);
382static void	acpi_res_set_iorange(device_t dev, void *context,
383				     u_int32_t low, u_int32_t high,
384				     u_int32_t length, u_int32_t align);
385static void	acpi_res_set_memory(device_t dev, void *context,
386				    u_int32_t base, u_int32_t length);
387static void	acpi_res_set_memoryrange(device_t dev, void *context,
388					 u_int32_t low, u_int32_t high,
389					 u_int32_t length, u_int32_t align);
390static void	acpi_res_set_irq(device_t dev, void *context, u_int32_t *irq,
391				 int count, int trig, int pol);
392static void	acpi_res_set_drq(device_t dev, void *context, u_int32_t *drq,
393				 int count);
394static void	acpi_res_set_start_dependant(device_t dev, void *context,
395					     int preference);
396static void	acpi_res_set_end_dependant(device_t dev, void *context);
397
398struct acpi_parse_resource_set acpi_res_parse_set = {
399    acpi_res_set_init,
400    acpi_res_set_done,
401    acpi_res_set_ioport,
402    acpi_res_set_iorange,
403    acpi_res_set_memory,
404    acpi_res_set_memoryrange,
405    acpi_res_set_irq,
406    acpi_res_set_drq,
407    acpi_res_set_start_dependant,
408    acpi_res_set_end_dependant
409};
410
411struct acpi_res_context {
412    int		ar_nio;
413    int		ar_nmem;
414    int		ar_nirq;
415    int		ar_ndrq;
416    void 	*ar_parent;
417};
418
419static void
420acpi_res_set_init(device_t dev, void *arg, void **context)
421{
422    struct acpi_res_context	*cp;
423
424    if ((cp = AcpiOsAllocate(sizeof(*cp))) != NULL) {
425	bzero(cp, sizeof(*cp));
426	cp->ar_parent = arg;
427	*context = cp;
428    }
429}
430
431static void
432acpi_res_set_done(device_t dev, void *context)
433{
434    struct acpi_res_context	*cp = (struct acpi_res_context *)context;
435
436    if (cp == NULL)
437	return;
438    AcpiOsFree(cp);
439}
440
441static void
442acpi_res_set_ioport(device_t dev, void *context, u_int32_t base,
443		    u_int32_t length)
444{
445    struct acpi_res_context	*cp = (struct acpi_res_context *)context;
446
447    if (cp == NULL)
448	return;
449    bus_set_resource(dev, SYS_RES_IOPORT, cp->ar_nio++, base, length);
450}
451
452static void
453acpi_res_set_iorange(device_t dev, void *context, u_int32_t low,
454		     u_int32_t high, u_int32_t length, u_int32_t align)
455{
456    struct acpi_res_context	*cp = (struct acpi_res_context *)context;
457
458    if (cp == NULL)
459	return;
460    device_printf(dev, "I/O range not supported\n");
461}
462
463static void
464acpi_res_set_memory(device_t dev, void *context, u_int32_t base,
465		    u_int32_t length)
466{
467    struct acpi_res_context	*cp = (struct acpi_res_context *)context;
468
469    if (cp == NULL)
470	return;
471
472    bus_set_resource(dev, SYS_RES_MEMORY, cp->ar_nmem++, base, length);
473}
474
475static void
476acpi_res_set_memoryrange(device_t dev, void *context, u_int32_t low,
477			 u_int32_t high, u_int32_t length, u_int32_t align)
478{
479    struct acpi_res_context	*cp = (struct acpi_res_context *)context;
480
481    if (cp == NULL)
482	return;
483    device_printf(dev, "memory range not supported\n");
484}
485
486static void
487acpi_res_set_irq(device_t dev, void *context, u_int32_t *irq, int count,
488    int trig, int pol)
489{
490    struct acpi_res_context	*cp = (struct acpi_res_context *)context;
491
492    if (cp == NULL || irq == NULL)
493	return;
494
495    /* This implements no resource relocation. */
496    if (count != 1)
497	return;
498
499    bus_set_resource(dev, SYS_RES_IRQ, cp->ar_nirq++, *irq, 1);
500    BUS_CONFIG_INTR(dev, *irq, (trig == ACPI_EDGE_SENSITIVE) ?
501	INTR_TRIGGER_EDGE : INTR_TRIGGER_LEVEL, (pol == ACPI_ACTIVE_HIGH) ?
502	INTR_POLARITY_HIGH : INTR_POLARITY_LOW);
503}
504
505static void
506acpi_res_set_drq(device_t dev, void *context, u_int32_t *drq, int count)
507{
508    struct acpi_res_context	*cp = (struct acpi_res_context *)context;
509
510    if (cp == NULL || drq == NULL)
511	return;
512
513    /* This implements no resource relocation. */
514    if (count != 1)
515	return;
516
517    bus_set_resource(dev, SYS_RES_DRQ, cp->ar_ndrq++, *drq, 1);
518}
519
520static void
521acpi_res_set_start_dependant(device_t dev, void *context, int preference)
522{
523    struct acpi_res_context	*cp = (struct acpi_res_context *)context;
524
525    if (cp == NULL)
526	return;
527    device_printf(dev, "dependant functions not supported\n");
528}
529
530static void
531acpi_res_set_end_dependant(device_t dev, void *context)
532{
533    struct acpi_res_context	*cp = (struct acpi_res_context *)context;
534
535    if (cp == NULL)
536	return;
537    device_printf(dev, "dependant functions not supported\n");
538}
539
540/*
541 * Resource-owning placeholders for IO and memory pseudo-devices.
542 *
543 * This code allocates system resource objects that will be owned by ACPI
544 * child devices.  Really, the acpi parent device should have the resources
545 * but this would significantly affect the device probe code.
546 */
547
548static int	acpi_sysres_probe(device_t dev);
549static int	acpi_sysres_attach(device_t dev);
550
551static device_method_t acpi_sysres_methods[] = {
552    /* Device interface */
553    DEVMETHOD(device_probe,	acpi_sysres_probe),
554    DEVMETHOD(device_attach,	acpi_sysres_attach),
555
556    {0, 0}
557};
558
559static driver_t acpi_sysres_driver = {
560    "acpi_sysresource",
561    acpi_sysres_methods,
562    0,
563};
564
565static devclass_t acpi_sysres_devclass;
566DRIVER_MODULE(acpi_sysresource, acpi, acpi_sysres_driver, acpi_sysres_devclass,
567    0, 0);
568MODULE_DEPEND(acpi_sysresource, acpi, 1, 1, 1);
569
570static int
571acpi_sysres_probe(device_t dev)
572{
573    ACPI_HANDLE h;
574
575    h = acpi_get_handle(dev);
576    if (acpi_disabled("sysresource") ||
577	(!acpi_MatchHid(h, "PNP0C01") && !acpi_MatchHid(h, "PNP0C02")))
578	return (ENXIO);
579
580    device_set_desc(dev, "System Resource");
581    device_quiet(dev);
582    return (-100);
583}
584
585static int
586acpi_sysres_attach(device_t dev)
587{
588    device_t gparent;
589    struct resource *res;
590    struct rman *rm;
591    struct resource_list_entry *rle;
592    struct resource_list *rl;
593
594    /*
595     * Pre-allocate/manage all memory and IO resources.  We detect duplicates
596     * by setting rle->res to the resource we got from the parent.  We can't
597     * ignore them since rman can't handle duplicates.
598     */
599    rl = BUS_GET_RESOURCE_LIST(device_get_parent(dev), dev);
600    SLIST_FOREACH(rle, rl, link) {
601	if (rle->res != NULL) {
602	    device_printf(dev, "duplicate resource for %lx\n", rle->start);
603	    continue;
604	}
605
606	/* Only memory and IO resources are valid here. */
607	switch (rle->type) {
608	case SYS_RES_IOPORT:
609	    rm = &acpi_rman_io;
610	    break;
611	case SYS_RES_MEMORY:
612	    rm = &acpi_rman_mem;
613	    break;
614	default:
615	    continue;
616	}
617
618	/* Pre-allocate resource and add to our rman pool. */
619	gparent = device_get_parent(device_get_parent(dev));
620	res = BUS_ALLOC_RESOURCE(gparent, dev, rle->type, &rle->rid,
621	    rle->start, rle->start + rle->count - 1, rle->count, 0);
622	if (res != NULL) {
623	    rman_manage_region(rm, rman_get_start(res), rman_get_end(res));
624	    rle->res = res;
625	}
626    }
627
628    return (0);
629}
630
631struct resource_list_entry *
632acpi_sysres_find(int type, u_long addr)
633{
634    device_t *devs;
635    int i, numdevs;
636    struct resource_list *rl;
637    struct resource_list_entry *rle;
638
639    /* We only consider IO and memory resources for our pool. */
640    rle = NULL;
641    if (type != SYS_RES_IOPORT && type != SYS_RES_MEMORY)
642        return (rle);
643
644    /* Find all the sysresource devices. */
645    if (devclass_get_devices(acpi_sysres_devclass, &devs, &numdevs) != 0)
646	return (rle);
647
648    /* Check each device for a resource that contains "addr". */
649    for (i = 0; i < numdevs && rle == NULL; i++) {
650	rl = BUS_GET_RESOURCE_LIST(device_get_parent(devs[i]), devs[i]);
651	if (rl == NULL)
652	    continue;
653	SLIST_FOREACH(rle, rl, link) {
654	    if (type == rle->type && addr >= rle->start &&
655		addr < rle->start + rle->count)
656		break;
657	}
658    }
659
660    free(devs, M_TEMP);
661    return (rle);
662}
663