diff --git a/sys/dev/sound/isa/sbc.c b/sys/dev/sound/isa/sbc.c index c0516049f190..4452ff3cd045 100644 --- a/sys/dev/sound/isa/sbc.c +++ b/sys/dev/sound/isa/sbc.c @@ -34,31 +34,52 @@ #define SB_NOMIXER #include +#define IO_MAX 3 +#define IRQ_MAX 1 +#define DRQ_MAX 2 +#define INTR_MAX 2 + +struct sbc_ihl { + driver_intr_t *intr[INTR_MAX]; + void *intr_arg[INTR_MAX]; +}; + /* Here is the parameter structure per a device. */ struct sbc_softc { device_t dev; /* device */ - int io_rid[3]; /* io port rids */ - struct resource *io[3]; /* io port resources */ - int io_alloced[3]; /* io port alloc flag */ + int io_rid[IO_MAX]; /* io port rids */ + struct resource *io[IO_MAX]; /* io port resources */ + int io_alloced[IO_MAX]; /* io port alloc flag */ - int irq_rid; /* irq rids */ - struct resource *irq; /* irq resources */ - int irq_alloced; /* irq alloc flag */ + int irq_rid[IRQ_MAX]; /* irq rids */ + struct resource *irq[IRQ_MAX]; /* irq resources */ + int irq_alloced[IRQ_MAX]; /* irq alloc flag */ - int drq_rid[2]; /* drq rids */ - struct resource *drq[2]; /* drq resources */ - int drq_alloced[2]; /* drq alloc flag */ + int drq_rid[DRQ_MAX]; /* drq rids */ + struct resource *drq[DRQ_MAX]; /* drq resources */ + int drq_alloced[DRQ_MAX]; /* drq alloc flag */ + + struct sbc_ihl ihl[IRQ_MAX]; + + void *ih; u_int32_t bd_ver; }; static int sbc_probe(device_t dev); static int sbc_attach(device_t dev); +static void sbc_intr(void *p); + static struct resource *sbc_alloc_resource(device_t bus, device_t child, int type, int *rid, u_long start, u_long end, u_long count, u_int flags); static int sbc_release_resource(device_t bus, device_t child, int type, int rid, struct resource *r); +static int sbc_setup_intr(device_t dev, device_t child, struct resource *irq, + int flags, driver_intr_t *intr, void *arg, + void **cookiep); +static int sbc_teardown_intr(device_t dev, device_t child, struct resource *irq, + void *cookie); static int alloc_resource(struct sbc_softc *scp); static int release_resource(struct sbc_softc *scp); @@ -247,7 +268,7 @@ sbc_attach(device_t dev) device_t child; u_int32_t logical_id = isa_get_logicalid(dev); int flags = device_get_flags(dev); - int f, dh, dl, x, irq; + int f, dh, dl, x, irq, i; if (!logical_id && (flags & DV_F_DUAL_DMA)) { bus_set_resource(dev, SYS_RES_DRQ, 1, @@ -298,7 +319,7 @@ sbc_attach(device_t dev) } /* soft irq/dma configuration */ x = -1; - irq = rman_get_start(scp->irq); + irq = rman_get_start(scp->irq[0]); if (irq == 5) x = 2; else if (irq == 7) x = 4; else if (irq == 9) x = 1; @@ -323,6 +344,12 @@ sbc_attach(device_t dev) } scp->bd_ver |= f << 16; + err = "setup_intr"; + for (i = 0; i < IRQ_MAX; i++) { + if (bus_setup_intr(dev, scp->irq[i], INTR_TYPE_TTY, sbc_intr, &scp->ihl[i], &scp->ih)) + goto bad; + } + /* PCM Audio */ func = malloc(sizeof(struct sndcard_func), M_DEVBUF, M_NOWAIT); if (func == NULL) goto bad; @@ -359,6 +386,71 @@ bad: if (err) device_printf(dev, "%s\n", err); return (ENXIO); } +static void +sbc_intr(void *p) +{ + struct sbc_ihl *ihl = p; + int i; + + i = 0; + while (i < INTR_MAX) { + if (ihl->intr[i] != NULL) ihl->intr[i](ihl->intr_arg[i]); + i++; + } +} + +static int +sbc_setup_intr(device_t dev, device_t child, struct resource *irq, + int flags, driver_intr_t *intr, void *arg, + void **cookiep) +{ + struct sbc_softc *scp = device_get_softc(dev); + struct sbc_ihl *ihl = NULL; + int i; + + i = 0; + while (i < IRQ_MAX) { + if (irq == scp->irq[i]) ihl = &scp->ihl[i]; + i++; + } + if (ihl == NULL) return (EINVAL); + i = 0; + while (i < INTR_MAX) { + if (ihl->intr[i] == NULL) { + ihl->intr[i] = intr; + ihl->intr_arg[i] = arg; + *cookiep = &ihl->intr[i]; + return 0; + } else i++; + } + return (EINVAL); +} + +static int +sbc_teardown_intr(device_t dev, device_t child, struct resource *irq, + void *cookie) +{ + struct sbc_softc *scp = device_get_softc(dev); + struct sbc_ihl *ihl = NULL; + int i; + + i = 0; + while (i < IRQ_MAX) { + if (irq == scp->irq[i]) ihl = &scp->ihl[i]; + i++; + } + if (ihl == NULL) return (EINVAL); + i = 0; + while (i < INTR_MAX) { + if (cookie == &ihl->intr[i]) { + ihl->intr[i] = NULL; + ihl->intr_arg[i] = NULL; + return 0; + } else i++; + } + return (EINVAL); +} + static struct resource * sbc_alloc_resource(device_t bus, device_t child, int type, int *rid, u_long start, u_long end, u_long count, u_int flags) @@ -372,20 +464,20 @@ sbc_alloc_resource(device_t bus, device_t child, int type, int *rid, case SYS_RES_IOPORT: alloced = scp->io_alloced; res = scp->io; - rid_max = 2; + rid_max = IO_MAX - 1; alloced_max = 1; break; case SYS_RES_DRQ: alloced = scp->drq_alloced; res = scp->drq; - rid_max = 1; + rid_max = DRQ_MAX - 1; alloced_max = 1; break; case SYS_RES_IRQ: - alloced = &scp->irq_alloced; - res = &scp->irq; - rid_max = 0; - alloced_max = 2; /* pcm and mpu may share the irq. */ + alloced = scp->irq_alloced; + res = scp->irq; + rid_max = IRQ_MAX - 1; + alloced_max = INTR_MAX; /* pcm and mpu may share the irq. */ break; default: return (NULL); @@ -409,15 +501,15 @@ sbc_release_resource(device_t bus, device_t child, int type, int rid, switch (type) { case SYS_RES_IOPORT: alloced = scp->io_alloced; - rid_max = 2; + rid_max = IO_MAX - 1; break; case SYS_RES_DRQ: alloced = scp->drq_alloced; - rid_max = 1; + rid_max = DRQ_MAX - 1; break; case SYS_RES_IRQ: - alloced = &scp->irq_alloced; - rid_max = 0; + alloced = scp->irq_alloced; + rid_max = IRQ_MAX - 1; break; default: return (1); @@ -471,7 +563,7 @@ alloc_resource(struct sbc_softc *scp) { int i; - for (i = 0 ; i < sizeof(scp->io) / sizeof(*scp->io) ; i++) { + for (i = 0 ; i < IO_MAX ; i++) { if (scp->io[i] == NULL) { scp->io_rid[i] = i; scp->io[i] = bus_alloc_resource(scp->dev, SYS_RES_IOPORT, &scp->io_rid[i], @@ -481,7 +573,7 @@ alloc_resource(struct sbc_softc *scp) scp->io_alloced[i] = 0; } } - for (i = 0 ; i < sizeof(scp->drq) / sizeof(*scp->drq) ; i++) { + for (i = 0 ; i < DRQ_MAX ; i++) { if (scp->drq[i] == NULL) { scp->drq_rid[i] = i; scp->drq[i] = bus_alloc_resource(scp->dev, SYS_RES_DRQ, &scp->drq_rid[i], @@ -491,13 +583,15 @@ alloc_resource(struct sbc_softc *scp) scp->drq_alloced[i] = 0; } } - if (scp->irq == NULL) { - scp->irq_rid = 0; - scp->irq = bus_alloc_resource(scp->dev, SYS_RES_IRQ, &scp->irq_rid, - 0, ~0, 1, RF_ACTIVE); - if (scp->irq == NULL) - return (1); - scp->irq_alloced = 0; + for (i = 0 ; i < IRQ_MAX ; i++) { + if (scp->irq[i] == NULL) { + scp->irq_rid[i] = i; + scp->irq[i] = bus_alloc_resource(scp->dev, SYS_RES_IRQ, &scp->irq_rid[i], + 0, ~0, 1, RF_ACTIVE); + if (i == 0 && scp->irq[i] == NULL) + return (1); + scp->irq_alloced[i] = 0; + } } return (0); } @@ -507,22 +601,24 @@ release_resource(struct sbc_softc *scp) { int i; - for (i = 0 ; i < sizeof(scp->io) / sizeof(*scp->io) ; i++) { + for (i = 0 ; i < IO_MAX ; i++) { if (scp->io[i] != NULL) { bus_release_resource(scp->dev, SYS_RES_IOPORT, scp->io_rid[i], scp->io[i]); scp->io[i] = NULL; } } - if (scp->irq != NULL) { - bus_release_resource(scp->dev, SYS_RES_IRQ, scp->irq_rid, scp->irq); - scp->irq = NULL; - } - for (i = 0 ; i < sizeof(scp->drq) / sizeof(*scp->drq) ; i++) { + for (i = 0 ; i < DRQ_MAX ; i++) { if (scp->drq[i] != NULL) { bus_release_resource(scp->dev, SYS_RES_DRQ, scp->drq_rid[i], scp->drq[i]); scp->drq[i] = NULL; } } + for (i = 0 ; i < IRQ_MAX ; i++) { + if (scp->irq[i] != NULL) { + bus_release_resource(scp->dev, SYS_RES_IRQ, scp->irq_rid[i], scp->irq[i]); + scp->irq[i] = NULL; + } + } return (0); } @@ -543,8 +639,8 @@ static device_method_t sbc_methods[] = { DEVMETHOD(bus_release_resource, sbc_release_resource), DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), - DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), - DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), + DEVMETHOD(bus_setup_intr, sbc_setup_intr), + DEVMETHOD(bus_teardown_intr, sbc_teardown_intr), { 0, 0 } };