Merge from vendor branch FILE:
[dragonfly.git] / sys / dev / acpica5 / acpi_resource.c
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  * $FreeBSD: src/sys/dev/acpica/acpi_resource.c,v 1.25 2004/06/13 22:52:30 njl Exp $
28  * $DragonFly: src/sys/dev/acpica5/acpi_resource.c,v 1.9 2007/10/23 03:04:48 y0netan1 Exp $
29  */
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 #include <sys/rman.h>
38
39 #include "acpi.h"
40 #include <dev/acpica5/acpivar.h>
41
42 /* Hooks for the ACPI CA debugging infrastructure */
43 #define _COMPONENT      ACPI_BUS
44 ACPI_MODULE_NAME("RESOURCE")
45
46 /*
47  * Fetch a device's resources and associate them with the device.
48  *
49  * Note that it might be nice to also locate ACPI-specific resource items, such
50  * as GPE bits.
51  *
52  * We really need to split the resource-fetching code out from the
53  * resource-parsing code, since we may want to use the parsing
54  * code for _PRS someday.
55  */
56 ACPI_STATUS
57 acpi_parse_resources(device_t dev, ACPI_HANDLE handle,
58                      struct acpi_parse_resource_set *set, void *arg)
59 {
60     ACPI_BUFFER         buf;
61     ACPI_RESOURCE       *res;
62     char                *curr, *last;
63     ACPI_STATUS         status;
64     void                *context;
65
66     ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
67
68     /*
69      * Special-case some devices that abuse _PRS/_CRS to mean
70      * something other than "I consume this resource".
71      *
72      * XXX do we really need this?  It's only relevant once
73      *     we start always-allocating these resources, and even
74      *     then, the only special-cased device is likely to be
75      *     the PCI interrupt link.
76      */
77
78     /* Fetch the device's current resources. */
79     buf.Length = ACPI_ALLOCATE_BUFFER;
80     if (ACPI_FAILURE((status = AcpiGetCurrentResources(handle, &buf)))) {
81         if (status != AE_NOT_FOUND && status != AE_TYPE)
82             kprintf("can't fetch resources for %s - %s\n",
83                    acpi_name(handle), AcpiFormatException(status));
84         return_ACPI_STATUS (status);
85     }
86     ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "%s - got %ld bytes of resources\n",
87                      acpi_name(handle), (long)buf.Length));
88     set->set_init(dev, arg, &context);
89
90     /* Iterate through the resources */
91     curr = buf.Pointer;
92     last = (char *)buf.Pointer + buf.Length;
93     while (curr < last) {
94         res = (ACPI_RESOURCE *)curr;
95         curr += res->Length;
96
97         /* Handle the individual resource types */
98         switch(res->Type) {
99         case ACPI_RESOURCE_TYPE_END_TAG:
100             ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "EndTag\n"));
101             curr = last;
102             break;
103         case ACPI_RESOURCE_TYPE_FIXED_IO:
104             if (res->Data.FixedIo.AddressLength <= 0)
105                 break;
106             ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "FixedIo 0x%x/%d\n",
107                              res->Data.FixedIo.Address,
108                              res->Data.FixedIo.AddressLength));
109             set->set_ioport(dev, context,
110                             res->Data.FixedIo.Address,
111                             res->Data.FixedIo.AddressLength);
112             break;
113         case ACPI_RESOURCE_TYPE_IO:
114             if (res->Data.Io.AddressLength <= 0)
115                 break;
116             if (res->Data.Io.Minimum == res->Data.Io.Maximum) {
117                 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Io 0x%x/%d\n",
118                                  res->Data.Io.Minimum,
119                                  res->Data.Io.AddressLength));
120                 set->set_ioport(dev, context,
121                                 res->Data.Io.Minimum,
122                                 res->Data.Io.AddressLength);
123             } else {
124                 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Io 0x%x-0x%x/%d\n",
125                                  res->Data.Io.Minimum,
126                                  res->Data.Io.Maximum, 
127                                  res->Data.Io.AddressLength));
128                 set->set_iorange(dev, context,
129                                  res->Data.Io.Minimum,
130                                  res->Data.Io.Maximum, 
131                                  res->Data.Io.AddressLength,
132                                  res->Data.Io.Alignment);
133             }
134             break;
135         case ACPI_RESOURCE_TYPE_FIXED_MEMORY32:
136             if (res->Data.FixedMemory32.AddressLength <= 0)
137                 break;
138             ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "FixedMemory32 0x%x/%d\n",
139                               res->Data.FixedMemory32.Address, 
140                               res->Data.FixedMemory32.AddressLength));
141             set->set_memory(dev, context,
142                             res->Data.FixedMemory32.Address, 
143                             res->Data.FixedMemory32.AddressLength);
144             break;
145         case ACPI_RESOURCE_TYPE_MEMORY32:
146             if (res->Data.Memory32.AddressLength <= 0)
147                 break;
148             if (res->Data.Memory32.Minimum ==
149                 res->Data.Memory32.Maximum) {
150
151                 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Memory32 0x%x/%d\n",
152                                   res->Data.Memory32.Minimum, 
153                                   res->Data.Memory32.AddressLength));
154                 set->set_memory(dev, context,
155                                 res->Data.Memory32.Minimum,
156                                 res->Data.Memory32.AddressLength);
157             } else {
158                 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Memory32 0x%x-0x%x/%d\n",
159                                  res->Data.Memory32.Minimum, 
160                                  res->Data.Memory32.Maximum,
161                                  res->Data.Memory32.AddressLength));
162                 set->set_memoryrange(dev, context,
163                                      res->Data.Memory32.Minimum,
164                                      res->Data.Memory32.Maximum,
165                                      res->Data.Memory32.AddressLength,
166                                      res->Data.Memory32.Alignment);
167             }
168             break;
169         case ACPI_RESOURCE_TYPE_MEMORY24:
170             if (res->Data.Memory24.AddressLength <= 0)
171                 break;
172             if (res->Data.Memory24.Minimum ==
173                 res->Data.Memory24.Maximum) {
174
175                 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Memory24 0x%x/%d\n",
176                                  res->Data.Memory24.Minimum, 
177                                  res->Data.Memory24.AddressLength));
178                 set->set_memory(dev, context, res->Data.Memory24.Minimum,
179                                 res->Data.Memory24.AddressLength);
180             } else {
181                 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Memory24 0x%x-0x%x/%d\n",
182                                  res->Data.Memory24.Minimum, 
183                                  res->Data.Memory24.Maximum,
184                                  res->Data.Memory24.AddressLength));
185                 set->set_memoryrange(dev, context,
186                                      res->Data.Memory24.Minimum,
187                                      res->Data.Memory24.Maximum,
188                                      res->Data.Memory24.AddressLength,
189                                      res->Data.Memory24.Alignment);
190             }
191             break;
192         case ACPI_RESOURCE_TYPE_IRQ:
193             /*
194              * from 1.0b 6.4.2 
195              * "This structure is repeated for each separate interrupt
196              * required"
197              */
198             set->set_irq(dev, context, res->Data.Irq.Interrupts,
199                 res->Data.Irq.InterruptCount, res->Data.Irq.Triggering,
200                 res->Data.Irq.Polarity);
201             break;
202         case ACPI_RESOURCE_TYPE_DMA:
203             /*
204              * from 1.0b 6.4.3 
205              * "This structure is repeated for each separate dma channel
206              * required"
207              */
208             set->set_drq(dev, context, res->Data.Dma.Channels,
209                          res->Data.Dma.ChannelCount);
210             break;
211         case ACPI_RESOURCE_TYPE_START_DEPENDENT:
212             ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "start dependent functions\n"));
213             set->set_start_dependant(dev, context,
214                                      res->Data.StartDpf.CompatibilityPriority);
215             break;
216         case ACPI_RESOURCE_TYPE_END_DEPENDENT:
217             ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "end dependent functions\n"));
218             set->set_end_dependant(dev, context);
219             break;
220         case ACPI_RESOURCE_TYPE_ADDRESS32:
221             if (res->Data.Address32.AddressLength <= 0)
222                 break;
223             if (res->Data.Address32.ProducerConsumer != ACPI_CONSUMER) {
224                 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
225                     "ignored Address32 %s producer\n",
226                     res->Data.Address32.ResourceType == ACPI_IO_RANGE ?
227                     "IO" : "Memory"));
228                 break;
229             }
230             if (res->Data.Address32.ResourceType != ACPI_MEMORY_RANGE &&
231                 res->Data.Address32.ResourceType != ACPI_IO_RANGE) {
232                 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
233                     "ignored Address32 for non-memory, non-I/O\n"));
234                 break;
235             }
236
237             if (res->Data.Address32.Minimum == ACPI_ADDRESS_FIXED &&
238                 res->Data.Address32.Maximum == ACPI_ADDRESS_FIXED) {
239
240                 if (res->Data.Address32.ResourceType == ACPI_MEMORY_RANGE) {
241                     ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
242                                      "Address32/Memory 0x%x/%d\n",
243                                      res->Data.Address32.Minimum,
244                                      res->Data.Address32.AddressLength));
245                     set->set_memory(dev, context,
246                                     res->Data.Address32.Minimum,
247                                     res->Data.Address32.AddressLength);
248                 } else {
249                     ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
250                                      "Address32/IO 0x%x/%d\n",
251                                      res->Data.Address32.Minimum,
252                                      res->Data.Address32.AddressLength));
253                     set->set_ioport(dev, context,
254                                     res->Data.Address32.Minimum,
255                                     res->Data.Address32.AddressLength);
256                 }
257             } else {
258                 if (res->Data.Address32.ResourceType == ACPI_MEMORY_RANGE) {
259                     ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
260                                      "Address32/Memory 0x%x-0x%x/%d\n",
261                                      res->Data.Address32.Minimum,
262                                      res->Data.Address32.Maximum,
263                                      res->Data.Address32.AddressLength));
264                     set->set_memoryrange(dev, context,
265                                           res->Data.Address32.Minimum,
266                                           res->Data.Address32.Maximum,
267                                           res->Data.Address32.AddressLength,
268                                           res->Data.Address32.Granularity);
269                 } else {
270                     ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
271                                      "Address32/IO 0x%x-0x%x/%d\n",
272                                      res->Data.Address32.Minimum,
273                                      res->Data.Address32.Maximum,
274                                      res->Data.Address32.AddressLength));
275                     set->set_iorange(dev, context,
276                                      res->Data.Address32.Minimum,
277                                      res->Data.Address32.Maximum,
278                                      res->Data.Address32.AddressLength,
279                                      res->Data.Address32.Granularity);
280                 }
281             }               
282             break;
283         case ACPI_RESOURCE_TYPE_ADDRESS16:
284             if (res->Data.Address16.AddressLength <= 0)
285                 break;
286             if (res->Data.Address16.ProducerConsumer != ACPI_CONSUMER) {
287                 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
288                     "ignored Address16 %s producer\n",
289                     res->Data.Address16.ResourceType == ACPI_IO_RANGE ?
290                     "IO" : "Memory"));
291                 break;
292             }
293             if (res->Data.Address16.ResourceType != ACPI_MEMORY_RANGE &&
294                 res->Data.Address16.ResourceType != ACPI_IO_RANGE) {
295                 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
296                         "ignored Address16 for non-memory, non-I/O\n"));
297                 break;
298             }
299
300             if (res->Data.Address16.Minimum == ACPI_ADDRESS_FIXED &&
301                 res->Data.Address16.Maximum == ACPI_ADDRESS_FIXED) {
302
303                 if (res->Data.Address16.ResourceType == ACPI_MEMORY_RANGE) {
304                     ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
305                                      "Address16/Memory 0x%x/%d\n",
306                                      res->Data.Address16.Minimum,
307                                      res->Data.Address16.AddressLength));
308                     set->set_memory(dev, context,
309                                     res->Data.Address16.Minimum,
310                                     res->Data.Address16.AddressLength);
311                 } else {
312                     ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
313                                      "Address16/IO 0x%x/%d\n",
314                                      res->Data.Address16.Minimum,
315                                      res->Data.Address16.AddressLength));
316                     set->set_ioport(dev, context,
317                                     res->Data.Address16.Minimum,
318                                     res->Data.Address16.AddressLength);
319                 }
320             } else {
321                 if (res->Data.Address16.ResourceType == ACPI_MEMORY_RANGE) {
322                     ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
323                                      "Address16/Memory 0x%x-0x%x/%d\n",
324                                      res->Data.Address16.Minimum,
325                                      res->Data.Address16.Maximum,
326                                      res->Data.Address16.AddressLength));
327                     set->set_memoryrange(dev, context,
328                                           res->Data.Address16.Minimum,
329                                           res->Data.Address16.Maximum,
330                                           res->Data.Address16.AddressLength,
331                                           res->Data.Address16.Granularity);
332                 } else {
333                     ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
334                                      "Address16/IO 0x%x-0x%x/%d\n",
335                                      res->Data.Address16.Minimum,
336                                      res->Data.Address16.Maximum,
337                                      res->Data.Address16.AddressLength));
338                     set->set_iorange(dev, context,
339                                      res->Data.Address16.Minimum,
340                                      res->Data.Address16.Maximum,
341                                      res->Data.Address16.AddressLength,
342                                      res->Data.Address16.Granularity);
343                 }
344             }               
345             break;
346         case ACPI_RESOURCE_TYPE_ADDRESS64:
347             ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
348                              "unimplemented Address64 resource\n"));
349             break;
350         case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
351             /* XXX special handling? */
352             set->set_ext_irq(dev, context, res->Data.ExtendedIrq.Interrupts,
353                 res->Data.ExtendedIrq.InterruptCount,
354                 res->Data.ExtendedIrq.Triggering,
355                 res->Data.ExtendedIrq.Polarity);
356             break;
357         case ACPI_RESOURCE_TYPE_VENDOR:
358             ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
359                              "unimplemented VendorSpecific resource\n"));
360             break;
361         default:
362             break;
363         }
364     }    
365
366     AcpiOsFree(buf.Pointer);
367     set->set_done(dev, context);
368     return_ACPI_STATUS (AE_OK);
369 }
370
371 /*
372  * Resource-set vectors used to attach _CRS-derived resources 
373  * to an ACPI device.
374  */
375 static void     acpi_res_set_init(device_t dev, void *arg, void **context);
376 static void     acpi_res_set_done(device_t dev, void *context);
377 static void     acpi_res_set_ioport(device_t dev, void *context,
378                                     u_int32_t base, u_int32_t length);
379 static void     acpi_res_set_iorange(device_t dev, void *context,
380                                      u_int32_t low, u_int32_t high, 
381                                      u_int32_t length, u_int32_t align);
382 static void     acpi_res_set_memory(device_t dev, void *context,
383                                     u_int32_t base, u_int32_t length);
384 static void     acpi_res_set_memoryrange(device_t dev, void *context,
385                                          u_int32_t low, u_int32_t high, 
386                                          u_int32_t length, u_int32_t align);
387 static void     acpi_res_set_irq(device_t dev, void *context, u_int8_t *irq,
388                                  int count, int trig, int pol);
389 static void     acpi_res_set_ext_irq(device_t dev, void *context,
390                                      u_int32_t *irq, int count, int trig,
391                                      int pol);
392 static void     acpi_res_set_drq(device_t dev, void *context, u_int8_t *drq,
393                                  int count);
394 static void     acpi_res_set_start_dependant(device_t dev, void *context,
395                                              int preference);
396 static void     acpi_res_set_end_dependant(device_t dev, void *context);
397
398 struct 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_ext_irq,
407     acpi_res_set_drq,
408     acpi_res_set_start_dependant,
409     acpi_res_set_end_dependant
410 };
411
412 struct acpi_res_context {
413     int         ar_nio;
414     int         ar_nmem;
415     int         ar_nirq;
416     int         ar_ndrq;
417     void        *ar_parent;
418 };
419
420 static void
421 acpi_res_set_init(device_t dev, void *arg, void **context)
422 {
423     struct acpi_res_context     *cp;
424
425     if ((cp = AcpiOsAllocate(sizeof(*cp))) != NULL) {
426         bzero(cp, sizeof(*cp));
427         cp->ar_parent = arg;
428         *context = cp;
429     }
430 }
431
432 static void
433 acpi_res_set_done(device_t dev, void *context)
434 {
435     struct acpi_res_context     *cp = (struct acpi_res_context *)context;
436
437     if (cp == NULL)
438         return;
439     AcpiOsFree(cp);
440 }
441
442 static void
443 acpi_res_set_ioport(device_t dev, void *context, u_int32_t base,
444                     u_int32_t length)
445 {
446     struct acpi_res_context     *cp = (struct acpi_res_context *)context;
447
448     if (cp == NULL)
449         return;
450     bus_set_resource(dev, SYS_RES_IOPORT, cp->ar_nio++, base, length);
451 }
452
453 static void
454 acpi_res_set_iorange(device_t dev, void *context, u_int32_t low,
455                      u_int32_t high, u_int32_t length, u_int32_t align)
456 {
457     struct acpi_res_context     *cp = (struct acpi_res_context *)context;
458
459     if (cp == NULL)
460         return;
461     device_printf(dev, "I/O range not supported\n");
462 }
463
464 static void
465 acpi_res_set_memory(device_t dev, void *context, u_int32_t base,
466                     u_int32_t length)
467 {
468     struct acpi_res_context     *cp = (struct acpi_res_context *)context;
469
470     if (cp == NULL)
471         return;
472
473     bus_set_resource(dev, SYS_RES_MEMORY, cp->ar_nmem++, base, length);
474 }
475
476 static void
477 acpi_res_set_memoryrange(device_t dev, void *context, u_int32_t low,
478                          u_int32_t high, u_int32_t length, u_int32_t align)
479 {
480     struct acpi_res_context     *cp = (struct acpi_res_context *)context;
481
482     if (cp == NULL)
483         return;
484     device_printf(dev, "memory range not supported\n");
485 }
486
487 static void
488 acpi_res_set_irq(device_t dev, void *context, u_int8_t *irq, int count,
489     int trig, int pol)
490 {
491     struct acpi_res_context     *cp = (struct acpi_res_context *)context;
492
493     if (cp == NULL || irq == NULL)
494         return;
495
496     /* This implements no resource relocation. */
497     if (count != 1)
498         return;
499
500     bus_set_resource(dev, SYS_RES_IRQ, cp->ar_nirq++, *irq, 1);
501 #if 0   /* From FreeBSD-5 XXX */
502     BUS_CONFIG_INTR(dev, *irq, (trig == ACPI_EDGE_SENSITIVE) ?
503         INTR_TRIGGER_EDGE : INTR_TRIGGER_LEVEL, (pol == ACPI_ACTIVE_HIGH) ?
504         INTR_POLARITY_HIGH : INTR_POLARITY_LOW);
505 #endif
506 }
507
508 static void
509 acpi_res_set_ext_irq(device_t dev, void *context, u_int32_t *irq, int count,
510     int trig, int pol)
511 {
512     struct acpi_res_context     *cp = (struct acpi_res_context *)context;
513
514     if (cp == NULL || irq == NULL)
515         return;
516
517     /* This implements no resource relocation. */
518     if (count != 1)
519         return;
520
521     bus_set_resource(dev, SYS_RES_IRQ, cp->ar_nirq++, *irq, 1);
522 #if 0   /* From FreeBSD-5 XXX */
523     BUS_CONFIG_INTR(dev, *irq, (trig == ACPI_EDGE_SENSITIVE) ?
524         INTR_TRIGGER_EDGE : INTR_TRIGGER_LEVEL, (pol == ACPI_ACTIVE_HIGH) ?
525         INTR_POLARITY_HIGH : INTR_POLARITY_LOW);
526 #endif
527 }
528
529 static void
530 acpi_res_set_drq(device_t dev, void *context, u_int8_t *drq, int count)
531 {
532     struct acpi_res_context     *cp = (struct acpi_res_context *)context;
533
534     if (cp == NULL || drq == NULL)
535         return;
536     
537     /* This implements no resource relocation. */
538     if (count != 1)
539         return;
540
541     bus_set_resource(dev, SYS_RES_DRQ, cp->ar_ndrq++, *drq, 1);
542 }
543
544 static void
545 acpi_res_set_start_dependant(device_t dev, void *context, int preference)
546 {
547     struct acpi_res_context     *cp = (struct acpi_res_context *)context;
548
549     if (cp == NULL)
550         return;
551     device_printf(dev, "dependent functions not supported\n");
552 }
553
554 static void
555 acpi_res_set_end_dependant(device_t dev, void *context)
556 {
557     struct acpi_res_context     *cp = (struct acpi_res_context *)context;
558
559     if (cp == NULL)
560         return;
561     device_printf(dev, "dependent functions not supported\n");
562 }
563
564 /*
565  * Resource-owning placeholders for IO and memory pseudo-devices.
566  *
567  * This code allocates system resource objects that will be owned by ACPI
568  * child devices.  Really, the acpi parent device should have the resources
569  * but this would significantly affect the device probe code.
570  */
571
572 static int      acpi_sysres_probe(device_t dev);
573 static int      acpi_sysres_attach(device_t dev);
574
575 static device_method_t acpi_sysres_methods[] = {
576     /* Device interface */
577     DEVMETHOD(device_probe,     acpi_sysres_probe),
578     DEVMETHOD(device_attach,    acpi_sysres_attach),
579
580     {0, 0}
581 };
582
583 static driver_t acpi_sysres_driver = {
584     "acpi_sysresource",
585     acpi_sysres_methods,
586     0,
587 };
588
589 static devclass_t acpi_sysres_devclass;
590 DRIVER_MODULE(acpi_sysresource, acpi, acpi_sysres_driver, acpi_sysres_devclass,
591     0, 0);
592 MODULE_DEPEND(acpi_sysresource, acpi, 1, 1, 1);
593
594 static int
595 acpi_sysres_probe(device_t dev)
596 {
597     ACPI_HANDLE h;
598
599     h = acpi_get_handle(dev);
600     if (acpi_disabled("sysresource") ||
601         (!acpi_MatchHid(h, "PNP0C01") && !acpi_MatchHid(h, "PNP0C02")))
602         return (ENXIO);
603
604     device_set_desc(dev, "System Resource");
605     device_quiet(dev);
606     return (-100);
607 }
608
609 static int
610 acpi_sysres_attach(device_t dev)
611 {
612     device_t gparent;
613     struct resource *res;
614     struct rman *rm;
615     struct resource_list_entry *rle;
616     struct resource_list *rl;
617
618     /*
619      * Pre-allocate/manage all memory and IO resources.  We detect duplicates
620      * by setting rle->res to the resource we got from the parent.  We can't
621      * ignore them since rman can't handle duplicates.
622      */
623     rl = BUS_GET_RESOURCE_LIST(device_get_parent(dev), dev);
624     SLIST_FOREACH(rle, rl, link) {
625         if (rle->res != NULL) {
626             device_printf(dev, "duplicate resource for %lx\n", rle->start);
627             continue;
628         }
629
630         /* Only memory and IO resources are valid here. */
631         switch (rle->type) {
632         case SYS_RES_IOPORT:
633             rm = &acpi_rman_io;
634             break;
635         case SYS_RES_MEMORY:
636             rm = &acpi_rman_mem;
637             break;
638         default:
639             continue;
640         }
641
642         /* Pre-allocate resource and add to our rman pool. */
643         gparent = device_get_parent(device_get_parent(dev));
644         res = BUS_ALLOC_RESOURCE(gparent, dev, rle->type, &rle->rid,
645             rle->start, rle->start + rle->count - 1, rle->count, 0);
646         if (res != NULL) {
647             rman_manage_region(rm, rman_get_start(res), rman_get_end(res));
648             rle->res = res;
649         }
650     }
651
652     return (0);
653 }
654
655 struct resource_list_entry *
656 acpi_sysres_find(int type, u_long addr)
657 {
658     device_t *devs;
659     int i, numdevs;
660     struct resource_list *rl;
661     struct resource_list_entry *rle;
662
663     /* We only consider IO and memory resources for our pool. */
664     rle = NULL;
665     if (type != SYS_RES_IOPORT && type != SYS_RES_MEMORY)
666         return (rle);
667
668     /* Find all the sysresource devices. */
669     if (devclass_get_devices(acpi_sysres_devclass, &devs, &numdevs) != 0)
670         return (rle);
671
672     /* Check each device for a resource that contains "addr". */
673     for (i = 0; i < numdevs && rle == NULL; i++) {
674         rl = BUS_GET_RESOURCE_LIST(device_get_parent(devs[i]), devs[i]);
675         if (rl == NULL)
676             continue;
677         SLIST_FOREACH(rle, rl, link) {
678             if (type == rle->type && addr >= rle->start &&
679                 addr < rle->start + rle->count)
680                 break;
681         }
682     }
683
684     kfree(devs, M_TEMP);
685     return (rle);
686 }