acpi_resource.c revision 108196
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: head/sys/dev/acpica/acpi_resource.c 108196 2002-12-23 03:48:59Z marcel $
28 */
29
30#include "opt_acpi.h"
31#include <sys/param.h>
32#include <sys/kernel.h>
33#include <sys/bus.h>
34
35#include <machine/bus.h>
36#include <machine/resource.h>
37#include <sys/rman.h>
38
39#include "acpi.h"
40
41#include <dev/acpica/acpivar.h>
42
43/*
44 * Hooks for the ACPI CA debugging infrastructure
45 */
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, struct acpi_parse_resource_set *set)
61{
62    ACPI_BUFFER		buf;
63    ACPI_RESOURCE	*res;
64    char		*curr, *last;
65    ACPI_STATUS		status;
66    void		*context;
67
68    ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
69
70    /*
71     * Special-case some devices that abuse _PRS/_CRS to mean
72     * something other than "I consume this resource".
73     *
74     * XXX do we really need this?  It's only relevant once
75     *     we start always-allocating these resources, and even
76     *     then, the only special-cased device is likely to be
77     *     the PCI interrupt link.
78     */
79
80    /*
81     * Fetch the device's current resources.
82     */
83    buf.Length = ACPI_ALLOCATE_BUFFER;
84    if (ACPI_FAILURE((status = AcpiGetCurrentResources(handle, &buf)))) {
85	if (status != AE_NOT_FOUND)
86	    printf("can't fetch resources for %s - %s\n",
87		   acpi_name(handle), AcpiFormatException(status));
88	return_ACPI_STATUS(status);
89    }
90    ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "%s - got %ld bytes of resources\n",
91		      acpi_name(handle), (long)buf.Length));
92    set->set_init(dev, &context);
93
94    /*
95     * Iterate through the resources
96     */
97    curr = buf.Pointer;
98    last = (char *)buf.Pointer + buf.Length;
99    while (curr < last) {
100	res = (ACPI_RESOURCE *)curr;
101	curr += res->Length;
102
103	/*
104	 * Handle the individual resource types
105	 */
106	switch(res->Id) {
107	case ACPI_RSTYPE_END_TAG:
108	    ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "EndTag\n"));
109	    curr = last;
110	    break;
111
112	case ACPI_RSTYPE_FIXED_IO:
113	    if (res->Data.FixedIo.RangeLength <= 0)
114		break;
115	    ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "FixedIo 0x%x/%d\n",
116			      res->Data.FixedIo.BaseAddress,
117			      res->Data.FixedIo.RangeLength));
118	    set->set_ioport(dev, context,
119			    res->Data.FixedIo.BaseAddress,
120			    res->Data.FixedIo.RangeLength);
121	    break;
122
123	case ACPI_RSTYPE_IO:
124	    if (res->Data.Io.RangeLength <= 0)
125		break;
126	    if (res->Data.Io.MinBaseAddress == res->Data.Io.MaxBaseAddress) {
127		ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Io 0x%x/%d\n",
128				  res->Data.Io.MinBaseAddress,
129				  res->Data.Io.RangeLength));
130		set->set_ioport(dev, context,
131				res->Data.Io.MinBaseAddress,
132				res->Data.Io.RangeLength);
133	    } else {
134		ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Io 0x%x-0x%x/%d\n",
135				  res->Data.Io.MinBaseAddress,
136				  res->Data.Io.MaxBaseAddress,
137				  res->Data.Io.RangeLength));
138		set->set_iorange(dev, context,
139				 res->Data.Io.MinBaseAddress,
140				 res->Data.Io.MaxBaseAddress,
141				 res->Data.Io.RangeLength, res->Data.Io.Alignment);
142	    }
143	    break;
144
145	case ACPI_RSTYPE_FIXED_MEM32:
146	    if (res->Data.FixedMemory32.RangeLength <= 0)
147		break;
148	    ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "FixedMemory32 0x%x/%d\n",
149			      res->Data.FixedMemory32.RangeBaseAddress,
150			      res->Data.FixedMemory32.RangeLength));
151	    set->set_memory(dev, context, res->Data.FixedMemory32.RangeBaseAddress,
152			    res->Data.FixedMemory32.RangeLength);
153	    break;
154
155	case ACPI_RSTYPE_MEM32:
156	    if (res->Data.Memory32.RangeLength <= 0)
157		break;
158	    if (res->Data.Memory32.MinBaseAddress == res->Data.Memory32.MaxBaseAddress) {
159		ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Memory32 0x%x/%d\n",
160				  res->Data.Memory32.MinBaseAddress,
161				  res->Data.Memory32.RangeLength));
162		set->set_memory(dev, context,
163				res->Data.Memory32.MinBaseAddress,
164				res->Data.Memory32.RangeLength);
165	    } else {
166		ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Memory32 0x%x-0x%x/%d\n",
167				  res->Data.Memory32.MinBaseAddress,
168				  res->Data.Memory32.MaxBaseAddress,
169				  res->Data.Memory32.RangeLength));
170		set->set_memoryrange(dev, context,
171				     res->Data.Memory32.MinBaseAddress,
172				     res->Data.Memory32.MaxBaseAddress,
173				     res->Data.Memory32.RangeLength,
174				     res->Data.Memory32.Alignment);
175	    }
176	    break;
177
178	case ACPI_RSTYPE_MEM24:
179	    if (res->Data.Memory24.RangeLength <= 0)
180		break;
181	    if (res->Data.Memory24.MinBaseAddress == res->Data.Memory24.MaxBaseAddress) {
182		ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Memory24 0x%x/%d\n",
183				  res->Data.Memory24.MinBaseAddress,
184				  res->Data.Memory24.RangeLength));
185		set->set_memory(dev, context, res->Data.Memory24.MinBaseAddress,
186				res->Data.Memory24.RangeLength);
187	    } else {
188		ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Memory24 0x%x-0x%x/%d\n",
189				  res->Data.Memory24.MinBaseAddress,
190				  res->Data.Memory24.MaxBaseAddress,
191				  res->Data.Memory24.RangeLength));
192		set->set_memoryrange(dev, context,
193				     res->Data.Memory24.MinBaseAddress,
194				     res->Data.Memory24.MaxBaseAddress,
195				     res->Data.Memory24.RangeLength,
196				     res->Data.Memory24.Alignment);
197	    }
198	    break;
199
200	case ACPI_RSTYPE_IRQ:
201	    /*
202	     * from 1.0b 6.4.2
203	     * "This structure is repeated for each separate interrupt
204	     * required"
205	     */
206	    set->set_irq(dev, context, res->Data.Irq.Interrupts,
207			 res->Data.Irq.NumberOfInterrupts);
208	    break;
209
210	case ACPI_RSTYPE_DMA:
211	    /*
212	     * from 1.0b 6.4.3
213	     * "This structure is repeated for each separate dma channel
214	     * required"
215	     */
216
217	    set->set_drq(dev, context, res->Data.Dma.Channels,
218			 res->Data.Dma.NumberOfChannels);
219	    break;
220
221	case ACPI_RSTYPE_START_DPF:
222	    ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "start dependant functions\n"));
223	    set->set_start_dependant(dev, context,
224				     res->Data.StartDpf.CompatibilityPriority);
225	    break;
226
227	case ACPI_RSTYPE_END_DPF:
228	    ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "end dependant functions\n"));
229	    set->set_end_dependant(dev, context);
230	    break;
231
232	case ACPI_RSTYPE_ADDRESS32:
233	    if (res->Data.Address32.AddressLength <= 0)
234		break;
235	    if (res->Data.Address32.ProducerConsumer != ACPI_CONSUMER) {
236		ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "ignored Address32 %s producer\n",
237				  (res->Data.Address32.ResourceType == ACPI_IO_RANGE) ?
238				     "IO" : "Memory"));
239		break;
240	    }
241	    if (res->Data.Address32.ResourceType != ACPI_MEMORY_RANGE &&
242		res->Data.Address32.ResourceType != ACPI_IO_RANGE) {
243		ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
244			"ignored Address32 for non-memory, non-I/O\n"));
245		break;
246	    }
247
248	    if ((res->Data.Address32.MinAddressFixed == ACPI_ADDRESS_FIXED) &&
249		(res->Data.Address32.MaxAddressFixed == ACPI_ADDRESS_FIXED)) {
250		if (res->Data.Address32.ResourceType == ACPI_MEMORY_RANGE) {
251		    ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Address32/Memory 0x%x/%d\n",
252				      res->Data.Address32.MinAddressRange,
253				      res->Data.Address32.AddressLength));
254		    set->set_memory(dev, context,
255				    res->Data.Address32.MinAddressRange,
256				    res->Data.Address32.AddressLength);
257		} else {
258		    ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Address32/IO 0x%x/%d\n",
259				      res->Data.Address32.MinAddressRange,
260				      res->Data.Address32.AddressLength));
261		    set->set_ioport(dev, context,
262				    res->Data.Address32.MinAddressRange,
263				    res->Data.Address32.AddressLength);
264		}
265	    } else {
266		if (res->Data.Address32.ResourceType == ACPI_MEMORY_RANGE) {
267		    ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Address32/Memory 0x%x-0x%x/%d\n",
268				      res->Data.Address32.MinAddressRange,
269				      res->Data.Address32.MaxAddressRange,
270				      res->Data.Address32.AddressLength));
271		    set->set_memoryrange(dev, context,
272					  res->Data.Address32.MinAddressRange,
273					  res->Data.Address32.MaxAddressRange,
274					  res->Data.Address32.AddressLength,
275					  res->Data.Address32.Granularity);
276		} else {
277		    ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Address32/IO 0x%x-0x%x/%d\n",
278				      res->Data.Address32.MinAddressRange,
279				      res->Data.Address32.MaxAddressRange,
280				      res->Data.Address32.AddressLength));
281		    set->set_iorange(dev, context,
282				     res->Data.Address32.MinAddressRange,
283				     res->Data.Address32.MaxAddressRange,
284				     res->Data.Address32.AddressLength,
285				     res->Data.Address32.Granularity);
286		}
287	    }
288	    break;
289
290	case ACPI_RSTYPE_ADDRESS16:
291	    if (res->Data.Address16.AddressLength <= 0)
292		break;
293	    if (res->Data.Address16.ProducerConsumer != ACPI_CONSUMER) {
294		ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "ignored Address16 %s producer\n",
295				  (res->Data.Address16.ResourceType == ACPI_IO_RANGE) ?
296				     "IO" : "Memory"));
297		break;
298	    }
299	    if (res->Data.Address16.ResourceType != ACPI_MEMORY_RANGE &&
300		res->Data.Address16.ResourceType != ACPI_IO_RANGE) {
301		ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
302			"ignored Address16 for non-memory, non-I/O\n"));
303		break;
304	    }
305
306	    if ((res->Data.Address16.MinAddressFixed == ACPI_ADDRESS_FIXED) &&
307		(res->Data.Address16.MaxAddressFixed == ACPI_ADDRESS_FIXED)) {
308		if (res->Data.Address16.ResourceType == ACPI_MEMORY_RANGE) {
309		    ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Address16/Memory 0x%x/%d\n",
310				      res->Data.Address16.MinAddressRange,
311				      res->Data.Address16.AddressLength));
312		    set->set_memory(dev, context,
313				    res->Data.Address16.MinAddressRange,
314				    res->Data.Address16.AddressLength);
315		} else {
316		    ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "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, "Address16/Memory 0x%x-0x%x/%d\n",
326				      res->Data.Address16.MinAddressRange,
327				      res->Data.Address16.MaxAddressRange,
328				      res->Data.Address16.AddressLength));
329		    set->set_memoryrange(dev, context,
330					  res->Data.Address16.MinAddressRange,
331					  res->Data.Address16.MaxAddressRange,
332					  res->Data.Address16.AddressLength,
333					  res->Data.Address16.Granularity);
334		} else {
335		    ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Address16/IO 0x%x-0x%x/%d\n",
336				      res->Data.Address16.MinAddressRange,
337				      res->Data.Address16.MaxAddressRange,
338				      res->Data.Address16.AddressLength));
339		    set->set_iorange(dev, context,
340				     res->Data.Address16.MinAddressRange,
341				     res->Data.Address16.MaxAddressRange,
342				     res->Data.Address16.AddressLength,
343				     res->Data.Address16.Granularity);
344		}
345	    }
346	    break;
347
348	case ACPI_RSTYPE_ADDRESS64:
349	    ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "unimplemented Address64 resource\n"));
350	    break;
351
352	case ACPI_RSTYPE_EXT_IRQ:
353	    /* XXX special handling? */
354	    set->set_irq(dev, context,res->Data.ExtendedIrq.Interrupts,
355			 res->Data.ExtendedIrq.NumberOfInterrupts);
356	    break;
357
358	case ACPI_RSTYPE_VENDOR:
359	    ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "unimplemented VendorSpecific resource\n"));
360	    break;
361	default:
362	    break;
363	}
364    }
365    AcpiOsFree(buf.Pointer);
366    set->set_done(dev, context);
367    return_ACPI_STATUS(AE_OK);
368}
369
370/*
371 * Resource-set vectors used to attach _CRS-derived resources
372 * to an ACPI device.
373 */
374static void	acpi_res_set_init(device_t dev, void **context);
375static void	acpi_res_set_done(device_t dev, void *context);
376static void	acpi_res_set_ioport(device_t dev, void *context, u_int32_t base, u_int32_t length);
377static void	acpi_res_set_iorange(device_t dev, void *context, u_int32_t low, u_int32_t high,
378				     u_int32_t length, u_int32_t align);
379static void	acpi_res_set_memory(device_t dev, void *context, u_int32_t base, u_int32_t length);
380static void	acpi_res_set_memoryrange(device_t dev, void *context, u_int32_t low, u_int32_t high,
381					 u_int32_t length, u_int32_t align);
382static void	acpi_res_set_irq(device_t dev, void *context, u_int32_t *irq,
383				 int count);
384static void	acpi_res_set_drq(device_t dev, void *context, u_int32_t *drq,
385				 int count);
386static void	acpi_res_set_start_dependant(device_t dev, void *context, int preference);
387static void	acpi_res_set_end_dependant(device_t dev, void *context);
388
389struct acpi_parse_resource_set acpi_res_parse_set = {
390    acpi_res_set_init,
391    acpi_res_set_done,
392    acpi_res_set_ioport,
393    acpi_res_set_iorange,
394    acpi_res_set_memory,
395    acpi_res_set_memoryrange,
396    acpi_res_set_irq,
397    acpi_res_set_drq,
398    acpi_res_set_start_dependant,
399    acpi_res_set_end_dependant
400};
401
402struct acpi_res_context {
403    int		ar_nio;
404    int		ar_nmem;
405    int		ar_nirq;
406    int		ar_ndrq;
407};
408
409static void
410acpi_res_set_init(device_t dev, void **context)
411{
412    struct acpi_res_context	*cp;
413
414    if ((cp = AcpiOsAllocate(sizeof(*cp))) != NULL) {
415	bzero(cp, sizeof(*cp));
416	*context = cp;
417    }
418}
419
420static void
421acpi_res_set_done(device_t dev, void *context)
422{
423    struct acpi_res_context	*cp = (struct acpi_res_context *)context;
424
425    if (cp == NULL)
426	return;
427    AcpiOsFree(cp);
428}
429
430static void
431acpi_res_set_ioport(device_t dev, void *context, u_int32_t base, u_int32_t length)
432{
433    struct acpi_res_context	*cp = (struct acpi_res_context *)context;
434
435    if (cp == NULL)
436	return;
437    bus_set_resource(dev, SYS_RES_IOPORT, cp->ar_nio++, base, length);
438}
439
440static void
441acpi_res_set_iorange(device_t dev, void *context, u_int32_t low, u_int32_t high, u_int32_t length, u_int32_t align)
442{
443    struct acpi_res_context	*cp = (struct acpi_res_context *)context;
444
445    if (cp == NULL)
446	return;
447    device_printf(dev, "I/O range not supported\n");
448}
449
450static void
451acpi_res_set_memory(device_t dev, void *context, u_int32_t base, u_int32_t length)
452{
453    struct acpi_res_context	*cp = (struct acpi_res_context *)context;
454
455    if (cp == NULL)
456	return;
457
458    bus_set_resource(dev, SYS_RES_MEMORY, cp->ar_nmem++, base, length);
459}
460
461static void
462acpi_res_set_memoryrange(device_t dev, void *context, u_int32_t low, u_int32_t high, u_int32_t length, u_int32_t align)
463{
464    struct acpi_res_context	*cp = (struct acpi_res_context *)context;
465
466    if (cp == NULL)
467	return;
468    device_printf(dev, "memory range not supported\n");
469}
470
471static void
472acpi_res_set_irq(device_t dev, void *context, u_int32_t *irq, int count)
473{
474    struct acpi_res_context	*cp = (struct acpi_res_context *)context;
475
476    if (cp == NULL)
477	return;
478    if (irq == NULL)
479	return;
480
481    /*This implements no resource relocation.*/
482    if(count != 1)
483	return;
484
485    bus_set_resource(dev, SYS_RES_IRQ, cp->ar_nirq++, *irq, 1);
486}
487
488static void
489acpi_res_set_drq(device_t dev, void *context, u_int32_t *drq, int count)
490{
491    struct acpi_res_context	*cp = (struct acpi_res_context *)context;
492
493    if (cp == NULL)
494	return;
495    if (drq == NULL)
496	return;
497
498    /*This implements no resource relocation.*/
499    if(count != 1)
500	return;
501
502    bus_set_resource(dev, SYS_RES_DRQ, cp->ar_ndrq++, *drq, 1);
503}
504
505static void
506acpi_res_set_start_dependant(device_t dev, void *context, int preference)
507{
508    struct acpi_res_context	*cp = (struct acpi_res_context *)context;
509
510    if (cp == NULL)
511	return;
512    device_printf(dev, "dependant functions not supported\n");
513}
514
515static void
516acpi_res_set_end_dependant(device_t dev, void *context)
517{
518    struct acpi_res_context	*cp = (struct acpi_res_context *)context;
519
520    if (cp == NULL)
521	return;
522}
523
524/*
525 * Resource-owning placeholders.
526 *
527 * This code "owns" system resource objects that aren't
528 * otherwise useful to devices, and which shouldn't be
529 * considered "free".
530 *
531 * Note that some systems claim *all* of the physical address space
532 * with a PNP0C01 device, so we cannot correctly "own" system memory
533 * here (must be done in the SMAP handler on x86 systems, for
534 * example).
535 */
536
537static int	acpi_sysresource_probe(device_t dev);
538static int	acpi_sysresource_attach(device_t dev);
539
540static device_method_t acpi_sysresource_methods[] = {
541    /* Device interface */
542    DEVMETHOD(device_probe,	acpi_sysresource_probe),
543    DEVMETHOD(device_attach,	acpi_sysresource_attach),
544
545    {0, 0}
546};
547
548static driver_t acpi_sysresource_driver = {
549    "acpi_sysresource",
550    acpi_sysresource_methods,
551    0,
552};
553
554static devclass_t acpi_sysresource_devclass;
555DRIVER_MODULE(acpi_sysresource, acpi, acpi_sysresource_driver, acpi_sysresource_devclass, 0, 0);
556
557static int
558acpi_sysresource_probe(device_t dev)
559{
560    if (acpi_disabled("sysresource"))
561	return(ENXIO);
562    if (acpi_MatchHid(dev, "PNP0C02")) {
563	device_set_desc(dev, "system resource");
564    } else {
565	return(ENXIO);
566    }
567    device_quiet(dev);
568    return(-100);
569}
570
571static int
572acpi_sysresource_attach(device_t dev)
573{
574    struct resource	*res;
575    int			i, rid;
576
577    /*
578     * Suck up all the resources that might have been assigned to us.
579     * Note that it's impossible to tell the difference between a
580     * resource that someone else has claimed, and one that doesn't
581     * exist.
582     */
583    for (i = 0; i < 100; i++) {
584	rid = i;
585	res = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid, 0, ~0, 1, 0);
586	rid = i;
587	res = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid, 0, ~0, 1, 0);
588	rid = i;
589	res = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 0, ~0, 1, RF_SHAREABLE);
590    }
591    return(0);
592}
593