Home | History | Annotate | Line # | Download | only in pci
pcib.c revision 1.6
      1 /*	$NetBSD: pcib.c,v 1.6 2001/06/21 05:20:54 thorpej Exp $	*/
      2 
      3 /*-
      4  * Copyright (c) 2000, 2001 The NetBSD Foundation, Inc.
      5  * All rights reserved.
      6  *
      7  * This code is derived from software contributed to The NetBSD Foundation
      8  * by Jason R. Thorpe.
      9  *
     10  * Redistribution and use in source and binary forms, with or without
     11  * modification, are permitted provided that the following conditions
     12  * are met:
     13  * 1. Redistributions of source code must retain the above copyright
     14  *    notice, this list of conditions and the following disclaimer.
     15  * 2. Redistributions in binary form must reproduce the above copyright
     16  *    notice, this list of conditions and the following disclaimer in the
     17  *    documentation and/or other materials provided with the distribution.
     18  * 3. All advertising materials mentioning features or use of this software
     19  *    must display the following acknowledgement:
     20  *	This product includes software developed by the NetBSD
     21  *	Foundation, Inc. and its contributors.
     22  * 4. Neither the name of The NetBSD Foundation nor the names of its
     23  *    contributors may be used to endorse or promote products derived
     24  *    from this software without specific prior written permission.
     25  *
     26  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     27  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     28  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     29  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     30  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     31  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     32  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     33  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     34  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     35  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     36  * POSSIBILITY OF SUCH DAMAGE.
     37  */
     38 
     39 #include <sys/cdefs.h>			/* RCS ID & Copyright macro defns */
     40 
     41 __KERNEL_RCSID(0, "$NetBSD: pcib.c,v 1.6 2001/06/21 05:20:54 thorpej Exp $");
     42 
     43 #include "opt_algor_p5064.h"
     44 #include "opt_algor_p6032.h"
     45 
     46 #include <sys/param.h>
     47 #include <sys/systm.h>
     48 #include <sys/kernel.h>
     49 #include <sys/device.h>
     50 #include <sys/malloc.h>
     51 
     52 #include <machine/intr.h>
     53 #include <machine/bus.h>
     54 
     55 #include <dev/isa/isareg.h>
     56 #include <dev/isa/isavar.h>
     57 
     58 #include <dev/pci/pcireg.h>
     59 #include <dev/pci/pcivar.h>
     60 #include <dev/pci/pcidevs.h>
     61 
     62 #include <dev/ic/i8259reg.h>
     63 
     64 #ifdef ALGOR_P5064
     65 #include <algor/algor/algor_p5064var.h>
     66 #endif
     67 
     68 #ifdef ALGOR_P6032
     69 #include <algor/algor/algor_p6032var.h>
     70 #endif
     71 
     72 const char *pcib_intrnames[16] = {
     73 	"irq 0",
     74 	"irq 1",
     75 	"irq 2",
     76 	"irq 3",
     77 	"irq 4",
     78 	"irq 5",
     79 	"irq 6",
     80 	"irq 7",
     81 	"irq 8",
     82 	"irq 9",
     83 	"irq 10",
     84 	"irq 11",
     85 	"irq 12",
     86 	"irq 13",
     87 	"irq 14",
     88 	"irq 15",
     89 };
     90 
     91 struct pcib_intrhead {
     92 	LIST_HEAD(, algor_intrhand) intr_q;
     93 	struct evcnt intr_count;
     94 	int intr_type;
     95 };
     96 
     97 struct pcib_softc {
     98 	struct device	sc_dev;
     99 
    100 	bus_space_tag_t	sc_iot;
    101 	bus_space_handle_t sc_ioh_icu1;
    102 	bus_space_handle_t sc_ioh_icu2;
    103 	bus_space_handle_t sc_ioh_elcr;
    104 
    105 	struct algor_isa_chipset sc_ic;
    106 
    107 	struct pcib_intrhead sc_intrtab[16];
    108 
    109 	u_int16_t	sc_imask;
    110 	u_int16_t	sc_elcr;
    111 
    112 #if defined(ALGOR_P5064)
    113 	isa_chipset_tag_t sc_parent_ic;
    114 #endif
    115 
    116 	u_int16_t	sc_reserved;
    117 
    118 	void		*sc_ih;
    119 };
    120 
    121 int	pcib_match(struct device *, struct cfdata *, void *);
    122 void	pcib_attach(struct device *, struct device *, void *);
    123 
    124 struct cfattach pcib_ca = {
    125 	sizeof(struct pcib_softc), pcib_match, pcib_attach,
    126 };
    127 
    128 int	pcib_print(void *, const char *pnp);
    129 void	pcib_isa_attach_hook(struct device *, struct device *,
    130 	    struct isabus_attach_args *);
    131 
    132 int	pcib_intr(void *);
    133 
    134 void	pcib_bridge_callback(struct device *);
    135 
    136 const struct evcnt *pcib_isa_intr_evcnt(void *, int);
    137 void	*pcib_isa_intr_establish(void *, int, int, int,
    138 	    int (*)(void *), void *);
    139 void	pcib_isa_intr_disestablish(void *, void *);
    140 int	pcib_isa_intr_alloc(void *, int, int, int *);
    141 
    142 void	pcib_set_icus(struct pcib_softc *);
    143 
    144 int
    145 pcib_match(struct device *parent, struct cfdata *match, void *aux)
    146 {
    147 	struct pci_attach_args *pa = aux;
    148 
    149 	if (PCI_CLASS(pa->pa_class) == PCI_CLASS_BRIDGE &&
    150 	    PCI_SUBCLASS(pa->pa_class) == PCI_SUBCLASS_BRIDGE_ISA)
    151 		return (1);
    152 
    153 	return (0);
    154 }
    155 
    156 void
    157 pcib_attach(struct device *parent, struct device *self, void *aux)
    158 {
    159 	struct pcib_softc *sc = (void *) self;
    160 	struct pci_attach_args *pa = aux;
    161 	char devinfo[256];
    162 	int i;
    163 
    164 	pci_devinfo(pa->pa_id, pa->pa_class, 0, devinfo);
    165 	printf(": %s (rev. 0x%02x)\n", devinfo,
    166 	    PCI_REVISION(pa->pa_class));
    167 
    168 	sc->sc_iot = pa->pa_iot;
    169 
    170 	/*
    171 	 * Map the PIC/ELCR registers.
    172 	 */
    173 	if (bus_space_map(sc->sc_iot, 0x4d0, 2, 0, &sc->sc_ioh_elcr) != 0)
    174 		printf("%s: unable to map ELCR registers\n",
    175 		    sc->sc_dev.dv_xname);
    176 	if (bus_space_map(sc->sc_iot, IO_ICU1, 2, 0, &sc->sc_ioh_icu1) != 0)
    177 		printf("%s: unable to map ICU1 registers\n",
    178 		    sc->sc_dev.dv_xname);
    179 	if (bus_space_map(sc->sc_iot, IO_ICU2, 2, 0, &sc->sc_ioh_icu2) != 0)
    180 		printf("%s: unable to map ICU2 registers\n",
    181 		    sc->sc_dev.dv_xname);
    182 
    183 	/* All interrupts default to "masked off". */
    184 	sc->sc_imask = 0xffff;
    185 
    186 	/* All interrupts default to edge-triggered. */
    187 	sc->sc_elcr = 0;
    188 
    189 	/*
    190 	 * Initialize the 8259s.
    191 	 */
    192 
    193 	/* reset, program device, 4 bytes */
    194 	bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu1, PIC_ICW1,
    195 	    ICW_SELECT(1) | ICW1_IC4);
    196 	bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu1, PIC_ICW2,
    197 	    ICW2_VECTOR(32)/*XXX*/);
    198 	bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu1, PIC_ICW3,
    199 	    ICW3_CASCADE);
    200 	bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu1, PIC_ICW4,
    201 	    ICW4_8086);
    202 
    203 	/* mask all interrupts */
    204 	bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu1, PIC_OCW1,
    205 	    sc->sc_imask & 0xff);
    206 
    207 	/* enable special mask mode */
    208 	bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu1, PIC_OCW3,
    209 	    OCW3_SELECT | OCW3_ESMM | OCW3_SMM);
    210 
    211 	/* read IRR by default */
    212 	bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu1, PIC_OCW3,
    213 	    OCW3_SELECT | OCW3_RR_CMD(OCW3_RR_CMD_READ_IRQ));
    214 
    215 
    216 	/* reset; program device, 4 bytes */
    217 	bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu2, PIC_ICW1,
    218 	    ICW_SELECT(1) | ICW1_IC4);
    219 	bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu2, PIC_ICW2,
    220 	    ICW2_VECTOR(32 + 8)/*XXX*/);
    221 	bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu2, PIC_ICW3,
    222 	    ICW3_SIC(2));
    223 	bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu2, PIC_ICW4,
    224 	    ICW4_8086);
    225 
    226 	/* mask all interrupts */
    227 	bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu2, PIC_OCW1,
    228 	    (sc->sc_imask >> 8) & 0xff);
    229 
    230 	/* enable special mask mode */
    231 	bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu2, PIC_OCW3,
    232 	    OCW3_SELECT | OCW3_ESMM | OCW3_SMM);
    233 
    234 	/* read IRR by default */
    235 	bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu2, PIC_OCW3,
    236 	    OCW3_SELECT | OCW3_RR_CMD(OCW3_RR_CMD_READ_IRQ));
    237 
    238 	/*
    239 	 * Default all interrupts to edge-triggered.
    240 	 */
    241 	bus_space_write_1(sc->sc_iot, sc->sc_ioh_elcr, 0,
    242 	    sc->sc_elcr & 0xff);
    243 	bus_space_write_1(sc->sc_iot, sc->sc_ioh_elcr, 1,
    244 	    (sc->sc_elcr >> 8) & 0xff);
    245 
    246 	/*
    247 	 * Some ISA interrupts are reserved for devices that
    248 	 * we know are hard-wired to certain IRQs.
    249 	 */
    250 	sc->sc_reserved =
    251 		(1U << 0) |	/* timer */
    252 		(1U << 1) |	/* keyboard controller */
    253 		(1U << 3) |	/* COM 2 */
    254 		(1U << 4) |	/* COM 1 */
    255 		(1U << 6) |	/* floppy */
    256 		(1U << 7) |	/* centronics */
    257 		(1U << 8) |	/* RTC */
    258 		(1U << 12) |	/* keyboard controller */
    259 		(1U << 14) |	/* IDE 0 */
    260 		(1U << 15);	/* IDE 1 */
    261 
    262 #if defined(ALGOR_P5064)
    263 	/*
    264 	 * Some "ISA" interrupts are a little wacky, wired up directly
    265 	 * to the P-5064 interrupt controller.
    266 	 */
    267 	sc->sc_parent_ic = &p5064_configuration.ac_ic;
    268 #endif /* ALGOR_P5064 */
    269 
    270 	/* Set up our ISA chipset. */
    271 	sc->sc_ic.ic_v = sc;
    272 	sc->sc_ic.ic_intr_evcnt = pcib_isa_intr_evcnt;
    273 	sc->sc_ic.ic_intr_establish = pcib_isa_intr_establish;
    274 	sc->sc_ic.ic_intr_disestablish = pcib_isa_intr_disestablish;
    275 	sc->sc_ic.ic_intr_alloc = pcib_isa_intr_alloc;
    276 
    277 	/* Initialize our interrupt table. */
    278 	for (i = 0; i < 16; i++) {
    279 		LIST_INIT(&sc->sc_intrtab[i].intr_q);
    280 		evcnt_attach_dynamic(&sc->sc_intrtab[i].intr_count,
    281 		    EVCNT_TYPE_INTR, NULL, "pcib", pcib_intrnames[i]);
    282 		sc->sc_intrtab[i].intr_type = IST_NONE;
    283 	}
    284 
    285 	/* Hook up our interrupt handler. */
    286 #if defined(ALGOR_P5064)
    287 	sc->sc_ih = (*algor_intr_establish)(P5064_IRQ_ISABRIDGE,
    288 	    pcib_intr, sc);
    289 #elif defined(ALGOR_P6032)
    290 	sc->sc_ih = (*algor_intr_establish)(XXX,
    291 	    pcib_intr, sc);
    292 #endif
    293 	if (sc->sc_ih == NULL)
    294 		printf("%s: WARNING: unable to register interrupt handler\n",
    295 		    sc->sc_dev.dv_xname);
    296 
    297 	config_defer(self, pcib_bridge_callback);
    298 }
    299 
    300 void
    301 pcib_bridge_callback(self)
    302 	struct device *self;
    303 {
    304 	struct pcib_softc *sc = (struct pcib_softc *)self;
    305 	struct isabus_attach_args iba;
    306 
    307 	memset(&iba, 0, sizeof(iba));
    308 
    309 	iba.iba_busname = "isa";
    310 #if defined(ALGOR_P5064)
    311 	    {
    312 		struct p5064_config *acp = &p5064_configuration;
    313 
    314 		iba.iba_iot = &acp->ac_iot;
    315 		iba.iba_memt = &acp->ac_memt;
    316 		iba.iba_dmat = &acp->ac_isa_dmat;
    317 	    }
    318 #elif defined(ALGOR_P6032)
    319 	    {
    320 		/* XXX */
    321 	    }
    322 #endif
    323 
    324 	iba.iba_ic = &sc->sc_ic;
    325 	iba.iba_ic->ic_attach_hook = pcib_isa_attach_hook;
    326 
    327 	(void) config_found(&sc->sc_dev, &iba, pcib_print);
    328 }
    329 
    330 int
    331 pcib_print(void *aux, const char *pnp)
    332 {
    333 	struct isabus_attach_args *iba;
    334 
    335 	if (pnp)
    336 		printf("%s at %s", iba->iba_busname, pnp);
    337 	return (UNCONF);
    338 }
    339 
    340 void
    341 pcib_isa_attach_hook(struct device *parent, struct device *self,
    342     struct isabus_attach_args *iba)
    343 {
    344 
    345 	/* Nothing to do. */
    346 }
    347 
    348 void
    349 pcib_set_icus(struct pcib_softc *sc)
    350 {
    351 
    352 	/* Enable the cascade IRQ (2) if 8-15 is enabled. */
    353 	if ((sc->sc_imask & 0xff00) != 0xff00)
    354 		sc->sc_imask &= ~(1U << 2);
    355 	else
    356 		sc->sc_imask |= (1U << 2);
    357 
    358 	bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu1, PIC_OCW1,
    359 	    sc->sc_imask & 0xff);
    360 	bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu2, PIC_OCW1,
    361 	    (sc->sc_imask >> 8) & 0xff);
    362 
    363 	bus_space_write_1(sc->sc_iot, sc->sc_ioh_elcr, 0,
    364 	    sc->sc_elcr & 0xff);
    365 	bus_space_write_1(sc->sc_iot, sc->sc_ioh_elcr, 1,
    366 	    (sc->sc_elcr >> 8) & 0xff);
    367 }
    368 
    369 int
    370 pcib_intr(void *v)
    371 {
    372 	struct pcib_softc *sc = v;
    373 	struct algor_intrhand *ih;
    374 	int irq;
    375 
    376 	bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu1, PIC_OCW3,
    377 	    OCW3_SELECT | OCW3_POLL);
    378 	irq = bus_space_read_1(sc->sc_iot, sc->sc_ioh_icu1,
    379 	    PIC_OCW3) & 0x7f;
    380 
    381 	if (irq == 2) {
    382 		bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu2, PIC_OCW3,
    383 		    OCW3_SELECT | OCW3_POLL);
    384 		irq = (bus_space_read_1(sc->sc_iot, sc->sc_ioh_icu2,
    385 		    PIC_OCW3) & 0x7f) + 8;
    386 	}
    387 
    388 	sc->sc_intrtab[irq].intr_count.ev_count++;
    389 	for (ih = LIST_FIRST(&sc->sc_intrtab[irq].intr_q);
    390 	     ih != NULL; ih = LIST_NEXT(ih, ih_q)) {
    391 		(*ih->ih_func)(ih->ih_arg);
    392 	}
    393 
    394 	/* Send a specific EOI to the 8259. */
    395 	if (irq > 7)
    396 		bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu2,
    397 		    PIC_OCW2, OCW2_SELECT | OCW2_OP(OCW2_OP_SPECIFIC_EOI_CMD) |
    398 		    OCW2_ILS(irq & 7));
    399 
    400 	bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu1, PIC_OCW2,
    401 	    OCW2_SELECT | OCW2_OP(OCW2_OP_SPECIFIC_EOI_CMD) |
    402 	    (irq > 7 ? OCW2_ILS(2) : OCW2_ILS(irq)));
    403 
    404 	return (1);
    405 }
    406 
    407 const struct evcnt *
    408 pcib_isa_intr_evcnt(void *v, int irq)
    409 {
    410 	struct pcib_softc *sc = v;
    411 
    412 #if defined(ALGOR_P5064)
    413 	if (p5064_isa_to_irqmap[irq] != -1)
    414 		return (isa_intr_evcnt(sc->sc_parent_ic, irq));
    415 #endif
    416 
    417 	return (&sc->sc_intrtab[irq].intr_count);
    418 }
    419 
    420 void *
    421 pcib_isa_intr_establish(void *v, int irq, int type, int level,
    422     int (*func)(void *), void *arg)
    423 {
    424 	struct pcib_softc *sc = v;
    425 	struct algor_intrhand *ih;
    426 	int s;
    427 
    428 	if (irq > 15 || irq == 2 || type == IST_NONE)
    429 		panic("pcib_isa_intr_establish: bad irq or type");
    430 
    431 #if defined(ALGOR_P5064)
    432 	if (p5064_isa_to_irqmap[irq] != -1)
    433 		return (isa_intr_establish(sc->sc_parent_ic, irq, type,
    434 		    level, func, arg));
    435 #endif
    436 
    437 	switch (sc->sc_intrtab[irq].intr_type) {
    438 	case IST_NONE:
    439 		sc->sc_intrtab[irq].intr_type = type;
    440 		break;
    441 
    442 	case IST_EDGE:
    443 	case IST_LEVEL:
    444 		if (type == sc->sc_intrtab[irq].intr_type)
    445 			break;
    446 		/* FALLTHROUGH */
    447 	case IST_PULSE:
    448 		/*
    449 		 * We can't share interrupts in this case.
    450 		 */
    451 		return (NULL);
    452 	}
    453 
    454 	ih = malloc(sizeof(*ih), M_DEVBUF, M_NOWAIT);
    455 	if (ih == NULL)
    456 		return (NULL);
    457 
    458 	ih->ih_func = func;
    459 	ih->ih_arg = arg;
    460 	ih->ih_irq = irq;
    461 	ih->ih_irqmap = NULL;
    462 
    463 	s = splhigh();
    464 
    465 	/* Insert the handler into the table. */
    466 	LIST_INSERT_HEAD(&sc->sc_intrtab[irq].intr_q, ih, ih_q);
    467 	sc->sc_intrtab[irq].intr_type = type;
    468 
    469 	/* Enable it, set trigger mode. */
    470 	sc->sc_imask &= ~(1 << irq);
    471 	if (sc->sc_intrtab[irq].intr_type == IST_LEVEL)
    472 		sc->sc_elcr |= (1 << irq);
    473 	else
    474 		sc->sc_elcr &= ~(1 << irq);
    475 
    476 	pcib_set_icus(sc);
    477 
    478 	splx(s);
    479 
    480 	return (ih);
    481 }
    482 
    483 void
    484 pcib_isa_intr_disestablish(void *v, void *arg)
    485 {
    486 	struct pcib_softc *sc = v;
    487 	struct algor_intrhand *ih = arg;
    488 	int s;
    489 
    490 #if defined(ALGOR_P5064)
    491 	if (p5064_isa_to_irqmap[ih->ih_irq] != -1) {
    492 		isa_intr_disestablish(sc->sc_parent_ic, ih);
    493 		return;
    494 	}
    495 #endif
    496 
    497 	s = splhigh();
    498 
    499 	LIST_REMOVE(ih, ih_q);
    500 
    501 	/* If there are no more handlers on this IRQ, disable it. */
    502 	if (LIST_FIRST(&sc->sc_intrtab[ih->ih_irq].intr_q) == NULL) {
    503 		sc->sc_imask |= (1 << ih->ih_irq);
    504 		pcib_set_icus(sc);
    505 	}
    506 
    507 	splx(s);
    508 
    509 	free(ih, M_DEVBUF);
    510 }
    511 
    512 int
    513 pcib_isa_intr_alloc(void *v, int mask, int type, int *irq)
    514 {
    515 	struct pcib_softc *sc = v;
    516 	int i, tmp, bestirq, count;
    517 	struct algor_intrhand *ih;
    518 
    519 	if (type == IST_NONE)
    520 		panic("pcib_intr_alloc: bogus type");
    521 
    522 	bestirq = -1;
    523 	count = -1;
    524 
    525 #if defined(ALGOR_P5064)
    526 	mask &= ~sc->sc_reserved;
    527 #endif
    528 
    529 #if 0
    530 	printf("pcib_intr_alloc: mask = 0x%04x\n", mask);
    531 #endif
    532 
    533 	for (i = 0; i < 16; i++) {
    534 		if (i == 2 || (mask & (1 << i)) == 0)
    535 			continue;
    536 
    537 		switch (sc->sc_intrtab[i].intr_type) {
    538 		case IST_NONE:
    539 			/*
    540 			 * If nothing's using the IRQ, just return it.
    541 			 */
    542 			*irq = i;
    543 			return (0);
    544 
    545 		case IST_EDGE:
    546 		case IST_LEVEL:
    547 			if (type != sc->sc_intrtab[i].intr_type)
    548 				continue;
    549 			/*
    550 			 * If the IRQ is sharable, count the number of
    551 			 * other handlers, and if it's smaller than the
    552 			 * last IRQ like this, remember it.
    553 			 */
    554 			tmp = 0;
    555 			for (ih = LIST_FIRST(&sc->sc_intrtab[i].intr_q);
    556 			     ih != NULL; ih = LIST_NEXT(ih, ih_q))
    557 				tmp++;
    558 			if (bestirq == -1 || count > tmp) {
    559 				bestirq = i;
    560 				count = tmp;
    561 			}
    562 			break;
    563 
    564 		case IST_PULSE:
    565 			/* This just isn't sharable. */
    566 			continue;
    567 		}
    568 	}
    569 
    570 	if (bestirq == -1)
    571 		return (1);
    572 
    573 	*irq = bestirq;
    574 	return (0);
    575 }
    576