diff --git a/sys/dev/sound/isa/emu8000.c b/sys/dev/sound/isa/emu8000.c index 0efb05ceb6eb..7067a8fdf548 100644 --- a/sys/dev/sound/isa/emu8000.c +++ b/sys/dev/sound/isa/emu8000.c @@ -383,8 +383,6 @@ static int emupnp_attach(device_t dev) __unused; static d_open_t emu_open; static d_close_t emu_close; -static d_read_t emu_read; -static d_write_t emu_write; static d_ioctl_t emu_ioctl; static midi_callback_t emu_callback; @@ -397,6 +395,8 @@ struct emu_softc { device_t dev; /* device information */ mididev_info *devinfo; /* midi device information */ + struct mtx mtx; /* Mutex to protect a device */ + struct resource *io[3]; /* Base of io port */ int io_rid[3]; /* Io resource ID */ @@ -518,11 +518,7 @@ mididev_info emu_op_desc = { emu_open, emu_close, - emu_read, - emu_write, emu_ioctl, - NULL, - emu_callback, MIDI_BUFFSIZE, /* Queue Length */ @@ -723,23 +719,17 @@ emu_attach(device_t dev) emu_writehwcf3(scp, 0x0004); /* Fill the softc for this unit. */ - scp->devinfo = devinfo = create_mididev_info_unit(&unit, MDT_SYNTH); bcopy(&emu_synthinfo, &scp->synthinfo, sizeof(emu_synthinfo)); + mtx_init(&scp->mtx, "emumid", MTX_DEF); + scp->devinfo = devinfo = create_mididev_info_unit(MDT_SYNTH, &emu_op_desc, &midisynth_op_desc); /* Fill the midi info. */ - bcopy(&emu_op_desc, devinfo, sizeof(emu_op_desc)); - midiinit(devinfo, dev); - devinfo->flags = 0; - bcopy(&midisynth_op_desc, &devinfo->synth, sizeof(midisynth_op_desc)); devinfo->synth.readraw = emu_readraw; devinfo->synth.writeraw = emu_writeraw; snprintf(devinfo->midistat, sizeof(devinfo->midistat), "at 0x%x, 0x%x, 0x%x", (u_int)rman_get_start(scp->io[0]), (u_int)rman_get_start(scp->io[1]), (u_int)rman_get_start(scp->io[2])); - /* Init the queue. */ - devinfo->midi_dbuf_in.unit_size = devinfo->midi_dbuf_out.unit_size = 1; - midibuf_init(&devinfo->midi_dbuf_in); - midibuf_init(&devinfo->midi_dbuf_out); + midiinit(devinfo, dev); DEB(printf("emu%d: attached.\n", unit)); @@ -764,59 +754,6 @@ emu_close(dev_t i_dev, int flags, int mode, struct proc *p) return (0); } -static int -emu_read(dev_t i_dev, struct uio *buf, int flag) -{ - sc_p scp; - mididev_info *devinfo; - int unit/*, s, len, ret*/; - - unit = MIDIUNIT(i_dev); - - devinfo = get_mididev_info(i_dev, &unit); - if (devinfo == NULL) { - DEB(printf("emu_read: unit %d is not configured.\n", unit)); - return (ENXIO); - } - scp = devinfo->softc; - if ((devinfo->fflags & FREAD) == 0) { - DEB(printf("emu_read: unit %d is not for reading.\n", unit)); - return (EIO); - } - - /* Drain the data. */ - midibuf_init(&devinfo->midi_dbuf_in); - - return (0); -} - -static int -emu_write(dev_t i_dev, struct uio *buf, int flag) -{ - sc_p scp; - mididev_info *devinfo; - int unit/*, s, len, ret*/; - - unit = MIDIUNIT(i_dev); - - devinfo = get_mididev_info(i_dev, &unit); - if (devinfo == NULL) { - DEB(printf("emu_write: unit %d is not configured.\n", unit)); - return (ENXIO); - } - scp = devinfo->softc; - if ((devinfo->fflags & FWRITE) == 0) { - DEB(printf("emu_write: unit %d is not for writing.\n", unit)); - return (EIO); - } - - /* Drain the data. */ - midibuf_init(&devinfo->midi_dbuf_out); - midibuf_init(&devinfo->midi_dbuf_passthru); - - return (0); -} - static int emu_ioctl(dev_t i_dev, u_long cmd, caddr_t arg, int mode, struct proc *p) { @@ -868,6 +805,8 @@ emu_ioctl(dev_t i_dev, u_long cmd, caddr_t arg, int mode, struct proc *p) static int emu_callback(mididev_info *devinfo, int reason) { + mtx_assert(&devinfo->flagqueue_mtx, MA_OWNED); + return (0); } diff --git a/sys/dev/sound/isa/gusmidi.c b/sys/dev/sound/isa/gusmidi.c index d95c75ff191f..e40e8c1432d0 100644 --- a/sys/dev/sound/isa/gusmidi.c +++ b/sys/dev/sound/isa/gusmidi.c @@ -97,14 +97,14 @@ struct gusmidi_softc { device_t dev; /* device information */ mididev_info *devinfo; /* midi device information */ + struct mtx mtx; /* Mutex to protect the device. */ + struct resource *io; /* Base of io port */ int io_rid; /* Io resource ID */ struct resource *irq; /* Irq */ int irq_rid; /* Irq resource ID */ void *ih; /* Interrupt cookie */ - struct callout_handle dh; /* Callout handler for delay */ - int ctl; /* Control bits. */ }; @@ -129,10 +129,7 @@ static mididev_info gusmidi_op_desc = { gusmidi_open, NULL, - NULL, - NULL, gusmidi_ioctl, - NULL, gusmidi_callback, @@ -192,21 +189,15 @@ gusmidi_init(device_t dev) { sc_p scp; mididev_info *devinfo; - int unit; scp = device_get_softc(dev); - unit = device_get_unit(dev); /* Fill the softc. */ scp->dev = dev; - scp->devinfo = devinfo = create_mididev_info_unit(&unit, MDT_MIDI); + mtx_init(&scp->mtx, "gusmid", MTX_DEF); + scp->devinfo = devinfo = create_mididev_info_unit(MDT_MIDI, &gusmidi_op_desc, &midisynth_op_desc); /* Fill the midi info. */ - bcopy(&gusmidi_op_desc, devinfo, sizeof(gusmidi_op_desc)); - midiinit(devinfo, dev); - devinfo->flags = 0; - bcopy(&midisynth_op_desc, &devinfo->synth, sizeof(midisynth_op_desc)); - if (scp->irq != NULL) snprintf(devinfo->midistat, sizeof(devinfo->midistat), "at 0x%x irq %d", (u_int)rman_get_start(scp->io), (int)rman_get_start(scp->irq)); @@ -214,10 +205,7 @@ gusmidi_init(device_t dev) snprintf(devinfo->midistat, sizeof(devinfo->midistat), "at 0x%x", (u_int)rman_get_start(scp->io)); - /* Init the queue. */ - devinfo->midi_dbuf_in.unit_size = devinfo->midi_dbuf_out.unit_size = 1; - midibuf_init(&devinfo->midi_dbuf_in); - midibuf_init(&devinfo->midi_dbuf_out); + midiinit(devinfo, dev); bus_setup_intr(dev, scp->irq, INTR_TYPE_TTY, gusmidi_intr, scp, &scp->ih); @@ -241,11 +229,15 @@ gusmidi_open(dev_t i_dev, int flags, int mode, struct proc *p) } scp = devinfo->softc; + mtx_lock(&scp->mtx); + gusmidi_writeport(scp, PORT_CTL, MIDICTL_MASTER_RESET); DELAY(100); gusmidi_writeport(scp, PORT_CTL, scp->ctl); + mtx_unlock(&scp->mtx); + return (0); } @@ -295,7 +287,6 @@ void gusmidi_intr(void *arg) { sc_p scp; - int s; u_char c; mididev_info *devinfo; int stat, did_something; @@ -303,14 +294,18 @@ gusmidi_intr(void *arg) scp = (sc_p)arg; devinfo = scp->devinfo; - s = splclock(); + MIDI_DROP_GIANT_NOSWITCH(); /* XXX No framing/overrun checks... */ + mtx_lock(&devinfo->flagqueue_mtx); + mtx_lock(&scp->mtx); + do { stat = gusmidi_readport(scp, PORT_ST); did_something = 0; if (stat & MIDIST_RXFULL) { c = gusmidi_readport(scp, PORT_RX); + mtx_unlock(&scp->mtx); if ((devinfo->flags & MIDI_F_PASSTHRU) && (!(devinfo->flags & MIDI_F_BUSY) || !(devinfo->fflags & FWRITE))) { @@ -319,27 +314,35 @@ gusmidi_intr(void *arg) devinfo->callback(devinfo, MIDI_CB_START | MIDI_CB_WR); } - if ((devinfo->flags & MIDI_F_READING) && c != 0xfe) + if ((devinfo->flags & MIDI_F_READING) && c != 0xfe) { midibuf_input_intr(&devinfo->midi_dbuf_in, &c, sizeof c); + } did_something = 1; - } + } else + mtx_unlock(&scp->mtx); if (stat & MIDIST_TXDONE) { if (devinfo->flags & MIDI_F_WRITING) { gusmidi_xmit(scp); did_something = 1; + mtx_lock(&scp->mtx); } else if (scp->ctl & MIDICTL_TX_IRQ_EN) { /* This shouldn't happen. */ - scp->ctl &= ~MIDICTL_TX_IRQ_EN; + mtx_lock(&scp->mtx); + scp->ctl &= ~MIDICTL_TX_IRQ_EN; gusmidi_writeport(scp, PORT_CTL, scp->ctl); } - } + } else + mtx_lock(&scp->mtx); } while (did_something != 0); + mtx_unlock(&scp->mtx); + mtx_unlock(&devinfo->flagqueue_mtx); + /* Invoke the upper layer. */ midi_intr(devinfo); - splx(s); + MIDI_PICKUP_GIANT(); } static int @@ -348,6 +351,8 @@ gusmidi_callback(mididev_info *d, int reason) int unit; sc_p scp; + mtx_assert(&d->flagqueue_mtx, MA_OWNED); + if (d == NULL) { DEB(printf("gusmidi_callback: device not configured.\n")); return (ENXIO); @@ -361,7 +366,10 @@ gusmidi_callback(mididev_info *d, int reason) if ((reason & MIDI_CB_RD) != 0 && (d->flags & MIDI_F_READING) == 0) { /* Begin recording. */ d->flags |= MIDI_F_READING; + mtx_lock(&scp->mtx); scp->ctl |= MIDICTL_RX_IRQ_EN; + gusmidi_writeport(scp, PORT_CTL, scp->ctl); + mtx_unlock(&scp->mtx); } if ((reason & MIDI_CB_WR) != 0 && (d->flags & MIDI_F_WRITING) == 0) /* Start playing. */ @@ -369,6 +377,7 @@ gusmidi_callback(mididev_info *d, int reason) break; case MIDI_CB_STOP: case MIDI_CB_ABORT: + mtx_lock(&scp->mtx); if ((reason & MIDI_CB_RD) != 0 && (d->flags & MIDI_F_READING) != 0) { /* Stop recording. */ d->flags &= ~MIDI_F_READING; @@ -379,9 +388,10 @@ gusmidi_callback(mididev_info *d, int reason) d->flags &= ~MIDI_F_WRITING; scp->ctl &= ~MIDICTL_TX_IRQ_EN; } + gusmidi_writeport(scp, PORT_CTL, scp->ctl); + mtx_unlock(&scp->mtx); break; } - gusmidi_writeport(scp, PORT_CTL, scp->ctl); return (0); } @@ -392,7 +402,6 @@ gusmidi_callback(mididev_info *d, int reason) /* * Starts to play the data in the output queue. - * Call this at >=splclock. */ static void gusmidi_startplay(sc_p scp) @@ -401,12 +410,16 @@ gusmidi_startplay(sc_p scp) devinfo = scp->devinfo; + mtx_assert(&devinfo->flagqueue_mtx, MA_OWNED); + /* Can we play now? */ if (devinfo->midi_dbuf_out.rl == 0) return; devinfo->flags |= MIDI_F_WRITING; + mtx_lock(&scp->mtx); scp->ctl |= MIDICTL_TX_IRQ_EN; + mtx_unlock(&scp->mtx); } static void @@ -418,6 +431,8 @@ gusmidi_xmit(sc_p scp) devinfo = scp->devinfo; + mtx_assert(&devinfo->flagqueue_mtx, MA_OWNED); + /* See which source to use. */ if ((devinfo->flags & MIDI_F_PASSTHRU) == 0 || ((devinfo->flags & MIDI_F_BUSY) != 0 && (devinfo->fflags & FWRITE) != 0)) dbuf = &devinfo->midi_dbuf_out; @@ -425,20 +440,28 @@ gusmidi_xmit(sc_p scp) dbuf = &devinfo->midi_dbuf_passthru; /* Transmit the data in the queue. */ - while ((devinfo->flags & MIDI_F_WRITING) && - (gusmidi_readport(scp, PORT_ST) & MIDIST_TXDONE)) { + while (devinfo->flags & MIDI_F_WRITING) { /* Do we have the data to transmit? */ if (dbuf->rl == 0) { /* Stop playing. */ devinfo->flags &= ~MIDI_F_WRITING; + mtx_lock(&scp->mtx); scp->ctl &= ~MIDICTL_TX_IRQ_EN; gusmidi_writeport(scp, PORT_CTL, scp->ctl); + mtx_unlock(&scp->mtx); break; } else { - /* Send the data. */ - midibuf_output_intr(dbuf, &c, sizeof(c)); - gusmidi_writeport(scp, PORT_TX, c); - /* We are playing now. */ + mtx_lock(&scp->mtx); + if (gusmidi_readport(scp, PORT_ST) & MIDIST_TXDONE) { + /* Send the data. */ + midibuf_output_intr(dbuf, &c, sizeof(c)); + gusmidi_writeport(scp, PORT_TX, c); + /* We are playing now. */ + } else { + mtx_unlock(&scp->mtx); + break; + } + mtx_unlock(&scp->mtx); } } } diff --git a/sys/dev/sound/isa/mpu.c b/sys/dev/sound/isa/mpu.c index 4adb80db2757..2ccd0a2c970c 100644 --- a/sys/dev/sound/isa/mpu.c +++ b/sys/dev/sound/isa/mpu.c @@ -45,8 +45,6 @@ #include #include -#define MPU_USEMICROTIMER 0 - static devclass_t midi_devclass; #ifndef DDB @@ -128,6 +126,8 @@ struct mpu_softc { device_t dev; /* device information */ mididev_info *devinfo; /* midi device information */ + struct mtx mtx; /* Mutex to protect the device. */ + struct resource *io; /* Base of io port */ int io_rid; /* Io resource ID */ u_long irq_val; /* Irq value */ @@ -135,8 +135,6 @@ struct mpu_softc { int irq_rid; /* Irq resource ID */ void *ih; /* Interrupt cookie */ - struct callout_handle dh; /* Callout handler for delay */ - int fflags; /* File flags */ }; @@ -145,10 +143,6 @@ typedef struct mpu_softc *sc_p; /* These functions are local. */ static void mpu_startplay(sc_p scp); static void mpu_xmit(sc_p scp); -#if MPU_USEMICROTIMER -static void mpu_timeout(sc_p scp); -static timeout_t mpu_timer; -#endif /* MPU_USEMICROTIMER */ static int mpu_resetmode(sc_p scp); static int mpu_uartmode(sc_p scp); static int mpu_waitack(sc_p scp); @@ -169,12 +163,9 @@ static mididev_info mpu_op_desc = { SNDCARD_MPU401, - NULL, - NULL, NULL, NULL, mpu_ioctl, - NULL, mpu_callback, @@ -362,12 +353,10 @@ mpu_attach(device_t dev) { sc_p scp; mididev_info *devinfo; - int unit; scp = device_get_softc(dev); - unit = device_get_unit(dev); - DEB(printf("mpu%d: attaching.\n", unit)); + DEB(printf("mpu: attaching.\n")); /* Allocate the resources, switch to uart mode. */ if (mpu_allocres(scp, dev) || mpu_uartmode(scp)) { @@ -379,14 +368,10 @@ mpu_attach(device_t dev) /* Fill the softc. */ scp->dev = dev; - scp->devinfo = devinfo = create_mididev_info_unit(&unit, MDT_MIDI); - callout_handle_init(&scp->dh); + mtx_init(&scp->mtx, "mpumid", MTX_DEF); + scp->devinfo = devinfo = create_mididev_info_unit(MDT_MIDI, &mpu_op_desc, &midisynth_op_desc); /* Fill the midi info. */ - bcopy(&mpu_op_desc, devinfo, sizeof(mpu_op_desc)); - midiinit(devinfo, dev); - devinfo->flags = 0; - bcopy(&midisynth_op_desc, &devinfo->synth, sizeof(midisynth_op_desc)); if (scp->irq != NULL) snprintf(devinfo->midistat, sizeof(devinfo->midistat), "at 0x%x irq %d", (u_int)rman_get_start(scp->io), (int)rman_get_start(scp->irq)); @@ -394,17 +379,14 @@ mpu_attach(device_t dev) snprintf(devinfo->midistat, sizeof(devinfo->midistat), "at 0x%x", (u_int)rman_get_start(scp->io)); - /* Init the queue. */ - devinfo->midi_dbuf_in.unit_size = devinfo->midi_dbuf_out.unit_size = 1; - midibuf_init(&devinfo->midi_dbuf_in); - midibuf_init(&devinfo->midi_dbuf_out); + midiinit(devinfo, dev); /* Now we can handle the interrupts. */ if (scp->irq != NULL) bus_setup_intr(dev, scp->irq, INTR_TYPE_TTY, mpu_intr, scp, &scp->ih); - DEB(printf("mpu%d: attached.\n", unit)); + DEB(printf("mpu: attached.\n")); return (0); } @@ -475,23 +457,34 @@ mpu_intr(void *arg) scp = (sc_p)arg; devinfo = scp->devinfo; + MIDI_DROP_GIANT_NOSWITCH(); + + mtx_lock(&devinfo->flagqueue_mtx); + mtx_lock(&scp->mtx); + /* Read the received data. */ while ((mpu_status(scp) & MPU_INPUTBUSY) == 0) { /* Receive the data. */ c = mpu_readdata(scp); + mtx_unlock(&scp->mtx); /* Queue into the passthru buffer and start transmitting if we can. */ if ((devinfo->flags & MIDI_F_PASSTHRU) != 0 && ((devinfo->flags & MIDI_F_BUSY) == 0 || (devinfo->fflags & FWRITE) == 0)) { midibuf_input_intr(&devinfo->midi_dbuf_passthru, &c, sizeof(c)); devinfo->callback(devinfo, MIDI_CB_START | MIDI_CB_WR); } /* Queue if we are reading. Discard an active sensing. */ - if ((devinfo->flags & MIDI_F_READING) != 0 && c != 0xfe) + if ((devinfo->flags & MIDI_F_READING) != 0 && c != 0xfe) { midibuf_input_intr(&devinfo->midi_dbuf_in, &c, sizeof(c)); + } + mtx_lock(&scp->mtx); } + mtx_unlock(&scp->mtx); + mtx_unlock(&devinfo->flagqueue_mtx); /* Invoke the upper layer. */ midi_intr(devinfo); + MIDI_PICKUP_GIANT(); } static int @@ -500,6 +493,8 @@ mpu_callback(mididev_info *d, int reason) int unit; sc_p scp; + mtx_assert(&d->flagqueue_mtx, MA_OWNED); + if (d == NULL) { DEB(printf("mpu_callback: device not configured.\n")); return (ENXIO); @@ -537,7 +532,6 @@ mpu_callback(mididev_info *d, int reason) /* * Starts to play the data in the output queue. - * Call this at >=splclock. */ static void mpu_startplay(sc_p scp) @@ -546,16 +540,14 @@ mpu_startplay(sc_p scp) devinfo = scp->devinfo; + mtx_assert(&devinfo->flagqueue_mtx, MA_OWNED); + /* Can we play now? */ if (devinfo->midi_dbuf_out.rl == 0) return; devinfo->flags |= MIDI_F_WRITING; -#if MPU_USEMICROTIMER - mpu_timeout(scp); -#else mpu_xmit(scp); -#endif /* MPU_USEMICROTIMER */ } static void @@ -567,6 +559,8 @@ mpu_xmit(sc_p scp) devinfo = scp->devinfo; + mtx_assert(&devinfo->flagqueue_mtx, MA_OWNED); + /* See which source to use. */ if ((devinfo->flags & MIDI_F_PASSTHRU) == 0 || ((devinfo->flags & MIDI_F_BUSY) != 0 && (devinfo->fflags & FWRITE) != 0)) dbuf = &devinfo->midi_dbuf_out; @@ -574,59 +568,24 @@ mpu_xmit(sc_p scp) dbuf = &devinfo->midi_dbuf_passthru; /* Transmit the data in the queue. */ -#if MPU_USEMICROTIMER - while ((devinfo->flags & MIDI_F_WRITING) != 0 && (mpu_status(scp) & MPU_OUTPUTBUSY) == 0) { - /* Do we have the data to transmit? */ - if (dbuf->rl == 0) { - /* Stop playing. */ - devinfo->flags &= ~MIDI_F_WRITING; - break; - } else { - /* Send the data. */ - midibuf_output_intr(dbuf, &c, sizeof(c)); - mpu_writedata(scp, c); - /* We are playing now. */ - devinfo->flags |= MIDI_F_WRITING; + while ((devinfo->flags & MIDI_F_WRITING) != 0) { + if (dbuf->rl > 0) { + mtx_lock(&scp->mtx); + /* XXX Wait until we can write the data. */ + if ((mpu_status(scp) & MPU_OUTPUTBUSY) == 0) { + /* Send the data. */ + midibuf_output_intr(dbuf, &c, sizeof(c)); + mpu_writedata(scp, c); + /* We are playing now. */ + devinfo->flags |= MIDI_F_WRITING; + } + mtx_unlock(&scp->mtx); } } - - /* De we have still more? */ - if ((devinfo->flags & MIDI_F_WRITING) != 0) - /* Handle them on the next interrupt. */ - mpu_timeout(scp); -#else - while ((devinfo->flags & MIDI_F_WRITING) != 0 && dbuf->rl > 0) { - /* XXX Wait until we can write the data. */ - while ((mpu_status(scp) & MPU_OUTPUTBUSY) != 0); - /* Send the data. */ - midibuf_output_intr(dbuf, &c, sizeof(c)); - mpu_writedata(scp, c); - /* We are playing now. */ - devinfo->flags |= MIDI_F_WRITING; - } /* Stop playing. */ devinfo->flags &= ~MIDI_F_WRITING; -#endif /* MPU_USEMICROTIMER */ } -#if MPU_USEMICROTIMER -/* Arm a timer. */ -static void -mpu_timeout(sc_p scp) -{ - microtimeout(mpu_timer, scp, hz * hzmul / 3125); -} - -/* Called when a timer has beeped. */ -static void -mpu_timer(void *arg) -{ - sc_p scp; - - scp = arg; - mpu_xmit(scp); -} -#endif /* MPU_USEMICROTIMER */ /* Reset mpu. */ static int @@ -636,11 +595,13 @@ mpu_resetmode(sc_p scp) /* Reset the mpu. */ resp = 0; + mtx_lock(&scp->mtx); for (i = 0 ; i < MPU_TRYDATA ; i++) { resp = mpu_command(scp, MPU_RESET); if (resp == 0) break; } + mtx_unlock(&scp->mtx); if (resp != 0) return (1); @@ -656,11 +617,13 @@ mpu_uartmode(sc_p scp) /* Switch to uart mode. */ resp = 0; + mtx_lock(&scp->mtx); for (i = 0 ; i < MPU_TRYDATA ; i++) { resp = mpu_command(scp, MPU_UART); if (resp == 0) break; } + mtx_unlock(&scp->mtx); if (resp != 0) return (1); @@ -675,11 +638,13 @@ mpu_waitack(sc_p scp) int i, resp; resp = 0; + mtx_lock(&scp->mtx); for (i = 0 ; i < MPU_TRYDATA ; i++) { resp = mpu_readdata(scp); if (resp >= 0) break; } + mtx_unlock(&scp->mtx); if (resp != MPU_ACK) return (1); diff --git a/sys/dev/sound/isa/opl.c b/sys/dev/sound/isa/opl.c index 2d41321df55a..a4a0e6635341 100644 --- a/sys/dev/sound/isa/opl.c +++ b/sys/dev/sound/isa/opl.c @@ -457,6 +457,8 @@ struct opl_softc { device_t dev; /* device information */ mididev_info *devinfo; /* midi device information */ + struct mtx mtx; /* Mutex to protect the device. */ + struct resource *io; /* Base of io port */ int io_rid; /* Io resource ID */ @@ -486,8 +488,6 @@ static int oplsbc_attach(device_t dev); static d_open_t opl_open; static d_close_t opl_close; -static d_read_t opl_read; -static d_write_t opl_write; static d_ioctl_t opl_ioctl; static midi_callback_t opl_callback; @@ -496,7 +496,6 @@ static mdsy_readraw_t opl_readraw; static mdsy_writeraw_t opl_writeraw; /* These functions are local. */ -static void opl_startplay(sc_p scp) __unused; static void opl_command(sc_p scp, int ch, int addr, u_int val); static int opl_status(sc_p scp); static void opl_enter4opmode(sc_p scp); @@ -520,10 +519,7 @@ static mididev_info opl_op_desc = { opl_open, opl_close, - opl_read, - opl_write, opl_ioctl, - NULL, opl_callback, @@ -643,18 +639,16 @@ opl_attach(device_t dev) { sc_p scp; mididev_info *devinfo; - int unit, i, opl4_io, opl4_id; + int i, opl4_io, opl4_id; struct resource *opl4; u_char signature, tmp; scp = device_get_softc(dev); - unit = device_get_unit(dev); - DEB(printf("opl%d: attaching.\n", unit)); + DEB(printf("opl: attaching.\n")); /* Fill the softc for this unit. */ scp->dev = dev; - scp->devinfo = devinfo = create_mididev_info_unit(&unit, MDT_SYNTH); /* Allocate other resources. */ if (opl_allocres(scp, dev)) { @@ -723,6 +717,7 @@ opl_attach(device_t dev) /* Fill the softc. */ bcopy(&opl_synthinfo, &scp->synthinfo, sizeof(opl_synthinfo)); snprintf(scp->synthinfo.name, 64, "Yamaha OPL%d FM", scp->model); + mtx_init(&scp->mtx, "oplmid", MTX_DEF); bcopy(pv_map, scp->pv_map, sizeof(pv_map)); if (scp->model < MODEL_OPL3) { /* OPL2. */ scp->synthinfo.nr_voices = 9; @@ -745,24 +740,19 @@ opl_attach(device_t dev) opl_command(scp, USE_RIGHT, CONNECTION_SELECT_REGISTER, 0); } + scp->devinfo = devinfo = create_mididev_info_unit(MDT_SYNTH, &opl_op_desc, &oplsynth_op_desc); + /* Fill the midi info. */ - bcopy(&opl_op_desc, devinfo, sizeof(opl_op_desc)); - midiinit(devinfo, dev); - devinfo->flags = 0; - bcopy(&oplsynth_op_desc, &devinfo->synth, sizeof(oplsynth_op_desc)); devinfo->synth.readraw = opl_readraw; devinfo->synth.writeraw = opl_writeraw; devinfo->synth.alloc.max_voice = scp->synthinfo.nr_voices; strcpy(devinfo->name, scp->synthinfo.name); snprintf(devinfo->midistat, sizeof(devinfo->midistat), "at 0x%x", (u_int)rman_get_start(scp->io)); - /* Init the queue. */ - devinfo->midi_dbuf_in.unit_size = devinfo->midi_dbuf_out.unit_size = 1; - midibuf_init(&devinfo->midi_dbuf_in); - midibuf_init(&devinfo->midi_dbuf_out); + midiinit(devinfo, dev); - DEB(printf("opl%d: attached.\n", unit)); - DEB(printf("opl%d: the chip is OPL%d.\n", unit, scp->model)); + DEB(printf("opl: attached.\n")); + DEB(printf("opl: the chip is OPL%d.\n", scp->model)); return (0); } @@ -791,6 +781,7 @@ opl_open(dev_t i_dev, int flags, int mode, struct proc *p) } scp = devinfo->softc; + mtx_lock(&devinfo->synth.vc_mtx); if (scp->model < MODEL_OPL3) devinfo->synth.alloc.max_voice = 9; else @@ -800,9 +791,13 @@ opl_open(dev_t i_dev, int flags, int mode, struct proc *p) devinfo->synth.alloc.map[i] = 0; devinfo->synth.alloc.alloc_times[i] = 0; } + mtx_unlock(&devinfo->synth.vc_mtx); scp->cmask = 0; /* We are in 2 OP mode initially. */ - if (scp->model >= MODEL_OPL3) + if (scp->model >= MODEL_OPL3) { + mtx_lock(&scp->mtx); opl_command(scp, USE_RIGHT, CONNECTION_SELECT_REGISTER, scp->cmask); + mtx_unlock(&scp->mtx); + } DEB(printf("opl%d: opened.\n", unit)); @@ -827,10 +822,12 @@ opl_close(dev_t i_dev, int flags, int mode, struct proc *p) } scp = devinfo->softc; + mtx_lock(&devinfo->synth.vc_mtx); if (scp->model < MODEL_OPL3) devinfo->synth.alloc.max_voice = 9; else devinfo->synth.alloc.max_voice = 18; + mtx_unlock(&devinfo->synth.vc_mtx); /* Stop the OPL. */ opl_reset(scp->devinfo); @@ -840,61 +837,6 @@ opl_close(dev_t i_dev, int flags, int mode, struct proc *p) return (0); } -static int -opl_read(dev_t i_dev, struct uio *buf, int flag) -{ - sc_p scp; - mididev_info *devinfo; - int unit, ret; - - unit = MIDIUNIT(i_dev); - - devinfo = get_mididev_info(i_dev, &unit); - if (devinfo == NULL) { - DEB(printf("opl_read: unit %d is not configured.\n", unit)); - return (ENXIO); - } - scp = devinfo->softc; - if ((devinfo->fflags & FREAD) == 0) { - DEB(printf("opl_read: unit %d is not for reading.\n", unit)); - return (EIO); - } - - /* Drain the data. */ - midibuf_init(&devinfo->midi_dbuf_in); - ret = 0; - - return (ret); -} - -static int -opl_write(dev_t i_dev, struct uio *buf, int flag) -{ - sc_p scp; - mididev_info *devinfo; - int unit, ret; - - unit = MIDIUNIT(i_dev); - - devinfo = get_mididev_info(i_dev, &unit); - if (devinfo == NULL) { - DEB(printf("opl_write: unit %d is not configured.\n", unit)); - return (ENXIO); - } - scp = devinfo->softc; - if ((devinfo->fflags & FWRITE) == 0) { - DEB(printf("opl_write: unit %d is not for writing.\n", unit)); - return (EIO); - } - - /* Drain the data. */ - midibuf_init(&devinfo->midi_dbuf_out); - midibuf_init(&devinfo->midi_dbuf_passthru); - ret = 0; - - return (ret); -} - static int opl_ioctl(dev_t i_dev, u_long cmd, caddr_t arg, int mode, struct proc *p) { @@ -923,10 +865,9 @@ opl_ioctl(dev_t i_dev, u_long cmd, caddr_t arg, int mode, struct proc *p) return (ENXIO); bcopy(&scp->synthinfo, synthinfo, sizeof(scp->synthinfo)); synthinfo->device = unit; - if (devinfo->synth.alloc.max_voice == 12) + synthinfo->nr_voices = devinfo->synth.alloc.max_voice; + if (synthinfo->nr_voices == 12) synthinfo->nr_voices = 6; - else - synthinfo->nr_voices = devinfo->synth.alloc.max_voice; return (0); break; case SNDCTL_MIDI_INFO: @@ -971,6 +912,8 @@ opl_callback(mididev_info *devinfo, int reason) int unit; sc_p scp; + mtx_assert(&devinfo->flagqueue_mtx, MA_OWNED); + if (devinfo == NULL) { DEB(printf("opl_callback: device not configured.\n")); return (ENXIO); @@ -1059,21 +1002,26 @@ opl_killnote(mididev_info *md, int voice, int note, int vel) if (voice < 0 || voice >= md->synth.alloc.max_voice) return (0); + mtx_lock(&md->synth.vc_mtx); + md->synth.alloc.map[voice] = 0; + mtx_lock(&scp->mtx); map = &scp->pv_map[scp->lv_map[voice]]; - if (map->voice_mode == VOICE_NONE) - return (0); + if (map->voice_mode != VOICE_NONE) { + opl_command(scp, map->ch, KEYON_BLOCK + map->voice_num, scp->voc[voice].keyon_byte & ~0x20); - opl_command(scp, map->ch, KEYON_BLOCK + map->voice_num, scp->voc[voice].keyon_byte & ~0x20); + scp->voc[voice].keyon_byte = 0; + scp->voc[voice].bender = 0; + scp->voc[voice].volume = 64; + scp->voc[voice].bender_range = 200; + scp->voc[voice].orig_freq = 0; + scp->voc[voice].current_freq = 0; + scp->voc[voice].mode = 0; + } - scp->voc[voice].keyon_byte = 0; - scp->voc[voice].bender = 0; - scp->voc[voice].volume = 64; - scp->voc[voice].bender_range = 200; - scp->voc[voice].orig_freq = 0; - scp->voc[voice].current_freq = 0; - scp->voc[voice].mode = 0; + mtx_unlock(&scp->mtx); + mtx_unlock(&md->synth.vc_mtx); return (0); } @@ -1093,7 +1041,9 @@ opl_setinstr(mididev_info *md, int voice, int instr_no) if (voice < 0 || voice >= md->synth.alloc.max_voice || instr_no < 0 || instr_no >= SBFM_MAXINSTR) return (0); + mtx_lock(&scp->mtx); scp->act_i[voice] = &scp->i_map[instr_no]; + mtx_unlock(&scp->mtx); return (0); } @@ -1115,13 +1065,17 @@ opl_startnote(mididev_info *md, int voice, int note, int volume) if (voice < 0 || voice >= md->synth.alloc.max_voice) return (0); + mtx_lock(&scp->mtx); map = &scp->pv_map[scp->lv_map[voice]]; - if (map->voice_mode == VOICE_NONE) + if (map->voice_mode == VOICE_NONE) { + mtx_unlock(&scp->mtx); return (0); + } if (note == 255) { /* Change the volume. */ opl_setvoicevolume(scp, voice, volume, scp->voc[voice].volume); + mtx_unlock(&scp->mtx); return (0); } @@ -1138,10 +1092,12 @@ opl_startnote(mididev_info *md, int voice, int note, int volume) if (instr == NULL) instr = &scp->i_map[0]; if (instr->channel < 0) { + mtx_unlock(&scp->mtx); printf("opl_startnote: the instrument for voice %d is undefined.\n", voice); return (0); } if (map->voice_mode == VOICE_2OP && instr->key == OPL3_PATCH) { + mtx_unlock(&scp->mtx); printf("opl_startnote: the voice mode %d mismatches the key 0x%x.\n", map->voice_mode, instr->key); return (0); } @@ -1208,6 +1164,8 @@ opl_startnote(mididev_info *md, int voice, int note, int volume) if (voice_mode == VOICE_4OP) opl_command(scp, map->ch, KEYON_BLOCK + map->voice_num + 3, scp->voc[voice].keyon_byte); + mtx_unlock(&scp->mtx); + return (0); } @@ -1216,12 +1174,16 @@ opl_reset(mididev_info *md) { int unit, i; sc_p scp; + struct physical_voice_info *map; scp = md->softc; unit = md->unit; DEB(printf("opl%d: resetting.\n", unit)); + mtx_lock(&md->synth.vc_mtx); + mtx_lock(&scp->mtx); + for (i = 0 ; i < MAX_VOICE ; i++) scp->lv_map[i] = i; @@ -1232,14 +1194,35 @@ opl_reset(mididev_info *md) opl_command(scp, scp->pv_map[scp->lv_map[i]].ch, KSL_LEVEL + scp->pv_map[scp->lv_map[i]].op[2], 0xff); opl_command(scp, scp->pv_map[scp->lv_map[i]].ch, KSL_LEVEL + scp->pv_map[scp->lv_map[i]].op[3], 0xff); } - opl_killnote(md, i, 0, 64); + /* + * opl_killnote(md, i, 0, 64) inline-expanded to avoid + * unlocking and relocking mutex unnecessarily. + */ + md->synth.alloc.map[i] = 0; + map = &scp->pv_map[scp->lv_map[i]]; + + if (map->voice_mode != VOICE_NONE) { + opl_command(scp, map->ch, KEYON_BLOCK + map->voice_num, scp->voc[i].keyon_byte & ~0x20); + + scp->voc[i].keyon_byte = 0; + scp->voc[i].bender = 0; + scp->voc[i].volume = 64; + scp->voc[i].bender_range = 200; + scp->voc[i].orig_freq = 0; + scp->voc[i].current_freq = 0; + scp->voc[i].mode = 0; + } } + if (scp->model >= MODEL_OPL3) { md->synth.alloc.max_voice = 18; for (i = 0 ; i < MAX_VOICE ; i++) scp->pv_map[i].voice_mode = VOICE_2OP; } + mtx_unlock(&md->synth.vc_mtx); + mtx_unlock(&scp->mtx); + return (0); } @@ -1283,12 +1266,12 @@ opl_panning(mididev_info *md, int chn, int pan) return (0); } -#define SET_VIBRATO(cell) { \ - int tmp; \ - tmp = instr->operators[(cell-1)+(((cell-1)/2)*OFFS_4OP)]; \ - if (press > 110) \ - tmp |= 0x40; /* Vibrato on */ \ - opl_command(scp, map->ch, AM_VIB + map->op[cell-1], tmp);} +#define SET_VIBRATO(cell) do { \ + int tmp; \ + tmp = instr->operators[(cell-1)+(((cell-1)/2)*OFFS_4OP)]; \ + if (press > 110) \ + tmp |= 0x40; /* Vibrato on */ \ + opl_command(scp, map->ch, AM_VIB + map->op[cell-1], tmp);} while(0); static int opl_aftertouch(mididev_info *md, int voice, int press) @@ -1306,9 +1289,13 @@ opl_aftertouch(mididev_info *md, int voice, int press) if (voice < 0 || voice >= md->synth.alloc.max_voice) return (0); + mtx_lock(&scp->mtx); + map = &scp->pv_map[scp->lv_map[voice]]; - if (map->voice_mode == VOICE_NONE) + if (map->voice_mode == VOICE_NONE) { + mtx_unlock(&scp->mtx); return (0); + } /* Adjust the vibrato. */ instr = scp->act_i[voice]; @@ -1341,6 +1328,8 @@ opl_aftertouch(mididev_info *md, int voice, int press) SET_VIBRATO(2); } + mtx_unlock(&scp->mtx); + return (0); } @@ -1356,14 +1345,18 @@ opl_bendpitch(sc_p scp, int voice, int value) DEB(printf("opl%d: setting the pitch bend, voice %d, value %d.\n", unit, voice, value)); + mtx_lock(&scp->mtx); + map = &scp->pv_map[scp->lv_map[voice]]; - if (map->voice_mode == 0) + if (map->voice_mode == 0) { + mtx_unlock(&scp->mtx); return (0); + } scp->voc[voice].bender = value; - if (value == 0) - return (0); - if ((scp->voc[voice].keyon_byte & 0x20) == 0) + if (value == 0 || (scp->voc[voice].keyon_byte & 0x20) == 0) { + mtx_unlock(&scp->mtx); return (0); + } freq = opl_computefinetune(scp->voc[voice].orig_freq, scp->voc[voice].bender, scp->voc[voice].bender_range); scp->voc[voice].current_freq = freq; @@ -1376,6 +1369,8 @@ opl_bendpitch(sc_p scp, int voice, int value) if (map->voice_mode == VOICE_4OP) opl_command(scp, map->ch, KEYON_BLOCK + map->voice_num + 3, scp->voc[voice].keyon_byte); + mtx_unlock(&scp->mtx); + return (0); } @@ -1398,10 +1393,14 @@ opl_controller(mididev_info *md, int voice, int ctrlnum, int val) opl_bendpitch(scp, voice, val); break; case CTRL_PITCH_BENDER_RANGE: + mtx_lock(&scp->mtx); scp->voc[voice].bender_range = val; + mtx_unlock(&scp->mtx); break; case CTRL_MAIN_VOLUME: + mtx_lock(&scp->mtx); scp->voc[voice].volume = val / 128; + mtx_unlock(&scp->mtx); break; } @@ -1440,11 +1439,15 @@ opl_allocvoice(mididev_info *md, int chn, int note, struct voice_alloc_info *all best_time = 0x7fffffff; + mtx_lock(&md->synth.vc_mtx); + if (chn < 0 || chn >= 15) instr_no = 0; else instr_no = md->synth.chn_info[chn].pgm_num; + mtx_lock(&scp->mtx); + instr = &scp->i_map[instr_no]; if (instr->channel < 0 || md->synth.alloc.max_voice != 12) is4op = 0; @@ -1485,6 +1488,9 @@ opl_allocvoice(mididev_info *md, int chn, int note, struct voice_alloc_info *all else if (best > md->synth.alloc.max_voice) best -= md->synth.alloc.max_voice; + mtx_unlock(&scp->mtx); + mtx_unlock(&md->synth.vc_mtx); + return best; } @@ -1498,11 +1504,17 @@ opl_setupvoice(mididev_info *md, int voice, int chn) DEB(printf("opl%d: setting up a voice, voice %d, chn %d.\n", unit, voice, chn)); + mtx_lock(&md->synth.vc_mtx); + info = &md->synth.chn_info[chn]; opl_setinstr(md, voice, info->pgm_num); + mtx_lock(&scp->mtx); scp->voc[voice].bender = info->bender_value; scp->voc[voice].volume = info->controllers[CTL_MAIN_VOLUME]; + mtx_unlock(&scp->mtx); + + mtx_lock(&md->synth.vc_mtx); return (0); } @@ -1532,25 +1544,6 @@ opl_volumemethod(mididev_info *md, int mode) * The functions below here are the libraries for the above ones. */ -/* - * Starts to play the data in the output queue. - * Call this at >=splmidi. - */ -static void -opl_startplay(sc_p scp) -{ - mididev_info *devinfo; - - devinfo = scp->devinfo; - - /* Can we play now? */ - if (devinfo->midi_dbuf_out.rl == 0) - return; - - /* Begin playing. */ - devinfo->callback(devinfo, MIDI_CB_START | MIDI_CB_WR); -} - /* Writes a command to the OPL chip. */ static void opl_command(sc_p scp, int ch, int addr, u_int val) @@ -1603,6 +1596,8 @@ opl_enter4opmode(sc_p scp) DEB(printf("opl%d: entering 4 OP mode.\n", unit)); /* Connect all possible 4 OP voice operators. */ + mtx_lock(&devinfo->synth.vc_mtx); + mtx_lock(&scp->mtx); scp->cmask = 0x3f; opl_command(scp, USE_RIGHT, CONNECTION_SELECT_REGISTER, scp->cmask); @@ -1617,7 +1612,9 @@ opl_enter4opmode(sc_p scp) for (i = 0 ; i < 12 ; i++) scp->lv_map[i] = v4op[i]; + mtx_unlock(&scp->mtx); devinfo->synth.alloc.max_voice = 12; + mtx_unlock(&devinfo->synth.vc_mtx); } static void diff --git a/sys/dev/sound/isa/uartsio.c b/sys/dev/sound/isa/uartsio.c index 5f56e363f2f6..b98e0f368a71 100644 --- a/sys/dev/sound/isa/uartsio.c +++ b/sys/dev/sound/isa/uartsio.c @@ -101,6 +101,8 @@ struct uartsio_softc { device_t dev; /* device information */ mididev_info *devinfo; /* midi device information */ + struct mtx mtx; /* Mutex to protect the device. */ + struct resource *io; /* Base of io port */ int io_rid; /* Io resource ID */ struct resource *irq; /* Irq */ @@ -132,12 +134,9 @@ static mididev_info uartsio_op_desc = { SNDCARD_UART16550, - NULL, - NULL, NULL, NULL, uartsio_ioctl, - NULL, uartsio_callback, @@ -201,12 +200,10 @@ uartsio_attach(device_t dev) { sc_p scp; mididev_info *devinfo; - int unit; scp = device_get_softc(dev); - unit = device_get_unit(dev); - DEB(printf("uartsio%d: attaching.\n", unit)); + DEB(printf("uartsio: attaching.\n")); /* Allocate resources. */ if (uartsio_allocres(scp, dev)) { @@ -219,31 +216,13 @@ uartsio_attach(device_t dev) if ((uartsio_readport(scp, com_iir) & IIR_FIFO_MASK) == FIFO_RX_HIGH) { scp->has_fifo = 1; scp->tx_size = TX_FIFO_SIZE; - DEB(printf("uartsio%d: uart is 16550A, tx size is %d bytes.\n", unit, scp->tx_size)); + DEB(printf("uartsio: uart is 16550A, tx size is %d bytes.\n", scp->tx_size)); } else { scp->has_fifo = 0; scp->tx_size = 1; - DEB(printf("uartsio%d: uart is not 16550A.\n", unit)); + DEB(printf("uartsio: uart is not 16550A.\n")); } - /* Fill the softc. */ - scp->dev = dev; - scp->devinfo = devinfo = create_mididev_info_unit(&unit, MDT_MIDI); - - /* Fill the midi info. */ - bcopy(&uartsio_op_desc, devinfo, sizeof(uartsio_op_desc)); - midiinit(devinfo, dev); - devinfo->flags = 0; - bcopy(&midisynth_op_desc, &devinfo->synth, sizeof(midisynth_op_desc)); - snprintf(devinfo->midistat, sizeof(devinfo->midistat), "at 0x%x irq %d", - (u_int)rman_get_start(scp->io), (int)rman_get_start(scp->irq)); - - /* Init the queue. */ - devinfo->midi_dbuf_in.unit_size = devinfo->midi_dbuf_out.unit_size = 1; - midibuf_init(&devinfo->midi_dbuf_in); - midibuf_init(&devinfo->midi_dbuf_out); - midibuf_init(&devinfo->midi_dbuf_passthru); - /* Configure the uart. */ uartsio_writeport(scp, com_cfcr, CFCR_DLAB); /* Latch the divisor. */ uartsio_writeport(scp, com_dlbl, 0x03); @@ -262,10 +241,21 @@ uartsio_attach(device_t dev) uartsio_readport(scp, com_iir); uartsio_readport(scp, com_data); + /* Fill the softc. */ + scp->dev = dev; + mtx_init(&scp->mtx, "siomid", MTX_DEF); + scp->devinfo = devinfo = create_mididev_info_unit(MDT_MIDI, &uartsio_op_desc, &midisynth_op_desc); + + /* Fill the midi info. */ + snprintf(devinfo->midistat, sizeof(devinfo->midistat), "at 0x%x irq %d", + (u_int)rman_get_start(scp->io), (int)rman_get_start(scp->irq)); + + midiinit(devinfo, dev); + /* Now we can handle the interrupts. */ bus_setup_intr(dev, scp->irq, INTR_TYPE_TTY, uartsio_intr, scp, &scp->ih); - DEB(printf("uartsio%d: attached.\n", unit)); + DEB(printf("uartsio: attached.\n")); return (0); } @@ -321,10 +311,16 @@ uartsio_intr(void *arg) scp = (sc_p)arg; devinfo = scp->devinfo; + MIDI_DROP_GIANT_NOSWITCH(); + + mtx_lock(&devinfo->flagqueue_mtx); uartsio_xmit(scp); + mtx_unlock(&devinfo->flagqueue_mtx); /* Invoke the upper layer. */ midi_intr(devinfo); + + MIDI_PICKUP_GIANT(); } static int @@ -333,6 +329,8 @@ uartsio_callback(mididev_info *d, int reason) int unit; sc_p scp; + mtx_assert(&d->flagqueue_mtx, MA_OWNED); + if (d == NULL) { DEB(printf("uartsio_callback: device not configured.\n")); return (ENXIO); @@ -347,7 +345,6 @@ uartsio_callback(mididev_info *d, int reason) /* Begin recording. */ d->flags |= MIDI_F_READING; if ((reason & MIDI_CB_WR) != 0 && (d->flags & MIDI_F_WRITING) == 0) - /* Start playing. */ uartsio_startplay(scp); break; case MIDI_CB_STOP: @@ -370,7 +367,6 @@ uartsio_callback(mididev_info *d, int reason) /* * Starts to play the data in the output queue. - * Call this at >=splmidi. */ static void uartsio_startplay(sc_p scp) @@ -379,6 +375,8 @@ uartsio_startplay(sc_p scp) devinfo = scp->devinfo; + mtx_assert(&devinfo->flagqueue_mtx, MA_OWNED); + /* Can we play now? */ if (devinfo->midi_dbuf_out.rl == 0) return; @@ -397,7 +395,10 @@ uartsio_xmit(sc_p scp) devinfo = scp->devinfo; - do { + mtx_assert(&devinfo->flagqueue_mtx, MA_OWNED); + + mtx_lock(&scp->mtx); + for (;;) { /* Read the received data. */ while (((lsr = uartsio_readport(scp, com_lsr)) & LSR_RCV_MASK) != 0) { /* Is this a data or an error/break? */ @@ -406,6 +407,7 @@ uartsio_xmit(sc_p scp) else { /* Receive the data. */ c[0] = uartsio_readport(scp, com_data); + mtx_unlock(&scp->mtx); /* Queue into the passthru buffer and start transmitting if we can. */ if ((devinfo->flags & MIDI_F_PASSTHRU) != 0 && ((devinfo->flags & MIDI_F_BUSY) == 0 || (devinfo->fflags & FWRITE) == 0)) { midibuf_input_intr(&devinfo->midi_dbuf_passthru, &c[0], sizeof(c[0])); @@ -414,11 +416,10 @@ uartsio_xmit(sc_p scp) /* Queue if we are reading. Discard an active sensing. */ if ((devinfo->flags & MIDI_F_READING) != 0 && c[0] != 0xfe) midibuf_input_intr(&devinfo->midi_dbuf_in, &c[0], sizeof(c[0])); + mtx_lock(&scp->mtx); } } - - /* Read MSR. */ - msr = uartsio_readport(scp, com_msr); + mtx_unlock(&scp->mtx); /* See which source to use. */ if ((devinfo->flags & MIDI_F_PASSTHRU) == 0 || ((devinfo->flags & MIDI_F_BUSY) != 0 && (devinfo->fflags & FWRITE) != 0)) @@ -427,30 +428,41 @@ uartsio_xmit(sc_p scp) dbuf = &devinfo->midi_dbuf_passthru; /* Transmit the data in the queue. */ - if ((devinfo->flags & MIDI_F_WRITING) != 0 && (lsr & LSR_TXRDY) != 0 && (msr & MSR_CTS) != 0) { - + if ((devinfo->flags & MIDI_F_WRITING) != 0) { /* Do we have the data to transmit? */ if (dbuf->rl == 0) { /* Stop playing. */ devinfo->flags &= ~MIDI_F_WRITING; } else { - /* send the data. */ - txsize = scp->tx_size; - if (dbuf->rl < txsize) - txsize = dbuf->rl; - midibuf_output_intr(dbuf, c, txsize); - for (i = 0 ; i < txsize ; i++) - uartsio_writeport(scp, com_data, c[i]); - /* We are playing now. */ - devinfo->flags |= MIDI_F_WRITING; + mtx_lock(&scp->mtx); + /* Read LSR and MSR. */ + lsr = uartsio_readport(scp, com_lsr); + msr = uartsio_readport(scp, com_msr); + /* Is the device ready?. */ + if ((lsr & LSR_TXRDY) != 0 && (msr & MSR_CTS) != 0) { + /* send the data. */ + txsize = scp->tx_size; + if (dbuf->rl < txsize) + txsize = dbuf->rl; + midibuf_output_intr(dbuf, c, txsize); + for (i = 0 ; i < txsize ; i++) + uartsio_writeport(scp, com_data, c[i]); + /* We are playing now. */ + devinfo->flags |= MIDI_F_WRITING; + } else { + /* Do we have the data to transmit? */ + if (dbuf->rl > 0) + /* Wait for the next interrupt. */ + devinfo->flags |= MIDI_F_WRITING; + } + mtx_unlock(&scp->mtx); } - } else { - /* Do we have the data to transmit? */ - if (dbuf->rl > 0) - /* Wait for the next interrupt. */ - devinfo->flags |= MIDI_F_WRITING; } - } while (((iir = uartsio_readport(scp, com_iir)) & IIR_IMASK) != IIR_NOPEND); + mtx_lock(&scp->mtx); + if (((iir = uartsio_readport(scp, com_iir)) & IIR_IMASK) == IIR_NOPEND) + break; + } + mtx_unlock(&scp->mtx); return (0); } diff --git a/sys/dev/sound/midi/midi.c b/sys/dev/sound/midi/midi.c index 1b504bc92b4c..3d6a16c0764d 100644 --- a/sys/dev/sound/midi/midi.c +++ b/sys/dev/sound/midi/midi.c @@ -38,7 +38,7 @@ * board-specific probe routine. If successful, a pointer to the * correct mididev_info is stored in mididev_last_probed, for subsequent * use in the attach routine. The generic attach routine copies - * the template to a permanent descriptor (midi_info[unit] and + * the template to a permanent descriptor (midi_info and * friends), initializes all generic parameters, and calls the * board-specific attach routine. * @@ -90,8 +90,11 @@ static struct cdevsw midi_cdevsw = { * descriptors for active devices. also used as the public softc * of a device. */ -static mididev_info midi_info[NMIDI_MAX]; +static TAILQ_HEAD(,_mididev_info) midi_info; static int nmidi, nsynth; +/* Mutex to protect midi_info, nmidi and nsynth. */ +static struct mtx midiinfo_mtx; +static int midiinfo_mtx_init; /* These make the buffer for /dev/midistat */ static int midistatbusy; @@ -99,33 +102,39 @@ static char midistatbuf[4096]; static int midistatptr; /* - * This is the generic init routine + * This is the generic init routine. + * Must be called after device-specific init. */ int midiinit(mididev_info *d, device_t dev) { int unit; - if (midi_devclass == NULL) { - midi_devclass = device_get_devclass(dev); - make_dev(&midi_cdevsw, MIDIMKMINOR(0, MIDI_DEV_STATUS), - UID_ROOT, GID_WHEEL, 0444, "midistat"); - } - - unit = device_get_unit(dev); - make_dev(&midi_cdevsw, MIDIMKMINOR(unit, MIDI_DEV_MIDIN), - UID_ROOT, GID_WHEEL, 0666, "midi%d", unit); - /* * initialize standard parameters for the device. This can be * overridden by device-specific configurations but better do * here the generic things. */ - d->unit = device_get_unit(dev); + unit = d->unit; d->softc = device_get_softc(dev); d->dev = dev; d->magic = MAGIC(d->unit); /* debugging... */ + d->flags = 0; + d->fflags = 0; + d->midi_dbuf_in.unit_size = 1; + d->midi_dbuf_out.unit_size = 1; + d->midi_dbuf_passthru.unit_size = 1; + + mtx_unlock(&d->flagqueue_mtx); + + if (midi_devclass == NULL) { + midi_devclass = device_get_devclass(dev); + make_dev(&midi_cdevsw, MIDIMKMINOR(0, MIDI_DEV_STATUS), + UID_ROOT, GID_WHEEL, 0444, "midistat"); + } + make_dev(&midi_cdevsw, MIDIMKMINOR(unit, MIDI_DEV_MIDIN), + UID_ROOT, GID_WHEEL, 0666, "midi%d", unit); return 0 ; } @@ -156,21 +165,55 @@ get_mididev_info(dev_t i_dev, int *unit) mididev_info * get_mididev_info_unit(int unit) { - mididev_info *d; + mididev_info *md; - if (unit >= nmidi + nsynth) { - DEB(printf("get_mididev_info_unit: unit %d is not configured.\n", u)); - return NULL; + /* XXX */ + if (!midiinfo_mtx_init) { + midiinfo_mtx_init = 1; + mtx_init(&midiinfo_mtx, "midinf", MTX_DEF); + TAILQ_INIT(&midi_info); } - d = &midi_info[unit]; - return d; + mtx_lock(&midiinfo_mtx); + TAILQ_FOREACH(md, &midi_info, md_link) { + if (md->unit == unit) + break; + } + mtx_unlock(&midiinfo_mtx); + + return md; } /* Create a new midi device info structure. */ +/* TODO: lock md, then exit. */ mididev_info * -create_mididev_info_unit(int *unit, int type) +create_mididev_info_unit(int type, mididev_info *mdinf, synthdev_info *syninf) { + int unit; + mididev_info *md, *mdnew; + + /* XXX */ + if (!midiinfo_mtx_init) { + midiinfo_mtx_init = 1; + mtx_init(&midiinfo_mtx, "midinf", MTX_DEF); + TAILQ_INIT(&midi_info); + } + + /* As malloc(9) might block, allocate mididev_info now. */ + mdnew = malloc(sizeof(mididev_info), M_DEVBUF, M_WAITOK | M_ZERO); + if (mdnew == NULL) + return NULL; + bcopy(mdinf, mdnew, sizeof(mididev_info)); + bcopy(syninf, &mdnew->synth, sizeof(synthdev_info)); + midibuf_init(&mdnew->midi_dbuf_in); + midibuf_init(&mdnew->midi_dbuf_out); + midibuf_init(&mdnew->midi_dbuf_passthru); + mtx_init(&mdnew->flagqueue_mtx, "midflq", MTX_DEF); + mtx_init(&mdnew->synth.vc_mtx, "synsvc", MTX_DEF); + mtx_init(&mdnew->synth.status_mtx, "synsst", MTX_DEF); + + mtx_lock(&midiinfo_mtx); + /* XXX midi_info is still static. */ switch (type) { case MDT_MIDI: @@ -180,12 +223,34 @@ create_mididev_info_unit(int *unit, int type) nsynth++; break; default: + mtx_unlock(&midiinfo_mtx); + midibuf_destroy(&mdnew->midi_dbuf_in); + midibuf_destroy(&mdnew->midi_dbuf_out); + midibuf_destroy(&mdnew->midi_dbuf_passthru); + mtx_destroy(&mdnew->flagqueue_mtx); + mtx_destroy(&mdnew->synth.vc_mtx); + mtx_destroy(&mdnew->synth.status_mtx); + free(mdnew, M_DEVBUF); panic("unsupported device type"); - break; + return NULL; } - *unit = nmidi + nsynth - 1; - return get_mididev_info_unit(*unit); + for (unit = 0 ; ; unit++) { + TAILQ_FOREACH(md, &midi_info, md_link) { + if (md->unit == unit) + break; + } + if (md == NULL) + break; + } + + mdnew->unit = unit; + mtx_lock(&mdnew->flagqueue_mtx); + TAILQ_INSERT_TAIL(&midi_info, mdnew, md_link); + + mtx_unlock(&midiinfo_mtx); + + return mdnew; } /* Return the number of configured devices. */ @@ -206,73 +271,136 @@ mididev_info_number(void) static int midiopen(dev_t i_dev, int flags, int mode, struct proc * p) { + int ret; + + MIDI_DROP_GIANT_NOSWITCH(); + switch (MIDIDEV(i_dev)) { case MIDI_DEV_MIDIN: - return midi_open(i_dev, flags, mode, p); + ret = midi_open(i_dev, flags, mode, p); + break; case MIDI_DEV_STATUS: - return midistat_open(i_dev, flags, mode, p); + ret = midistat_open(i_dev, flags, mode, p); + break; + default: + ret = ENXIO; + break; } - return (ENXIO); + MIDI_PICKUP_GIANT(); + + return (ret); } static int midiclose(dev_t i_dev, int flags, int mode, struct proc * p) { + int ret; + + MIDI_DROP_GIANT_NOSWITCH(); + switch (MIDIDEV(i_dev)) { case MIDI_DEV_MIDIN: - return midi_close(i_dev, flags, mode, p); + ret = midi_close(i_dev, flags, mode, p); + break; case MIDI_DEV_STATUS: - return midistat_close(i_dev, flags, mode, p); + ret = midistat_close(i_dev, flags, mode, p); + break; + default: + ret = ENXIO; + break; } - return (ENXIO); + MIDI_PICKUP_GIANT(); + + return (ret); } static int midiread(dev_t i_dev, struct uio * buf, int flag) { + int ret; + + MIDI_DROP_GIANT_NOSWITCH(); + switch (MIDIDEV(i_dev)) { case MIDI_DEV_MIDIN: - return midi_read(i_dev, buf, flag); + ret = midi_read(i_dev, buf, flag); + break; case MIDI_DEV_STATUS: - return midistat_read(i_dev, buf, flag); + ret = midistat_read(i_dev, buf, flag); + break; + default: + ret = ENXIO; + break; } - return (ENXIO); + MIDI_PICKUP_GIANT(); + + return (ret); } static int midiwrite(dev_t i_dev, struct uio * buf, int flag) { + int ret; + + MIDI_DROP_GIANT_NOSWITCH(); + switch (MIDIDEV(i_dev)) { case MIDI_DEV_MIDIN: - return midi_write(i_dev, buf, flag); + ret = midi_write(i_dev, buf, flag); + break; + default: + ret = ENXIO; + break; } - return (ENXIO); + MIDI_PICKUP_GIANT(); + + return (ret); } static int midiioctl(dev_t i_dev, u_long cmd, caddr_t arg, int mode, struct proc * p) { + int ret; + + MIDI_DROP_GIANT_NOSWITCH(); + switch (MIDIDEV(i_dev)) { case MIDI_DEV_MIDIN: - return midi_ioctl(i_dev, cmd, arg, mode, p); + ret = midi_ioctl(i_dev, cmd, arg, mode, p); + break; + default: + ret = ENXIO; + break; } - return (ENXIO); + MIDI_PICKUP_GIANT(); + + return (ret); } static int midipoll(dev_t i_dev, int events, struct proc * p) { + int ret; + + MIDI_DROP_GIANT_NOSWITCH(); + switch (MIDIDEV(i_dev)) { case MIDI_DEV_MIDIN: - return midi_poll(i_dev, events, p); + ret = midi_poll(i_dev, events, p); + break; + default: + ret = ENXIO; + break; } - return (ENXIO); + MIDI_PICKUP_GIANT(); + + return (ret); } /* @@ -282,7 +410,7 @@ midipoll(dev_t i_dev, int events, struct proc * p) int midi_open(dev_t i_dev, int flags, int mode, struct proc * p) { - int dev, unit, s, ret; + int dev, unit, ret; mididev_info *d; dev = minor(i_dev); @@ -294,12 +422,11 @@ midi_open(dev_t i_dev, int flags, int mode, struct proc * p) if (d == NULL) return (ENXIO); - s = splmidi(); - /* Mark this device busy. */ + mtx_lock(&d->flagqueue_mtx); device_busy(d->dev); if ((d->flags & MIDI_F_BUSY) != 0) { - splx(s); + mtx_unlock(&d->flagqueue_mtx); DEB(printf("opl_open: unit %d is busy.\n", unit)); return (EBUSY); } @@ -308,27 +435,27 @@ midi_open(dev_t i_dev, int flags, int mode, struct proc * p) d->fflags = flags; /* Init the queue. */ - if ((d->fflags & FREAD) != 0) - midibuf_init(&d->midi_dbuf_in); - if ((d->fflags & FWRITE) != 0) { - midibuf_init(&d->midi_dbuf_out); - midibuf_init(&d->midi_dbuf_passthru); + if ((flags & FREAD) != 0) + midibuf_clear(&d->midi_dbuf_in); + if ((flags & FWRITE) != 0) { + midibuf_clear(&d->midi_dbuf_out); + midibuf_clear(&d->midi_dbuf_passthru); } + mtx_unlock(&d->flagqueue_mtx); + if (d->open == NULL) ret = 0; else ret = d->open(i_dev, flags, mode, p); - splx(s); - return (ret); } int midi_close(dev_t i_dev, int flags, int mode, struct proc * p) { - int dev, unit, s, ret; + int dev, unit, ret; mididev_info *d; dev = minor(i_dev); @@ -339,14 +466,20 @@ midi_close(dev_t i_dev, int flags, int mode, struct proc * p) if (d == NULL) return (ENXIO); - s = splmidi(); + mtx_lock(&d->flagqueue_mtx); + + /* Stop recording and playing. */ + if ((d->flags & MIDI_F_READING) != 0) + d->callback(d, MIDI_CB_ABORT | MIDI_CB_RD); + if ((d->flags & MIDI_F_WRITING) != 0) + d->callback(d, MIDI_CB_ABORT | MIDI_CB_WR); /* Clear the queues. */ if ((d->fflags & FREAD) != 0) - midibuf_init(&d->midi_dbuf_in); + midibuf_clear(&d->midi_dbuf_in); if ((d->fflags & FWRITE) != 0) { - midibuf_init(&d->midi_dbuf_out); - midibuf_init(&d->midi_dbuf_passthru); + midibuf_clear(&d->midi_dbuf_out); + midibuf_clear(&d->midi_dbuf_passthru); } /* Stop playing and unmark this device busy. */ @@ -355,21 +488,24 @@ midi_close(dev_t i_dev, int flags, int mode, struct proc * p) device_unbusy(d->dev); + mtx_unlock(&d->flagqueue_mtx); + if (d->close == NULL) ret = 0; else ret = d->close(i_dev, flags, mode, p); - splx(s); - return (ret); } int midi_read(dev_t i_dev, struct uio * buf, int flag) { - int dev, unit, s, len, ret; + int dev, unit, len, ret; mididev_info *d ; +#if defined(MIDI_OUTOFGIANT) + char *buf2; /* XXX Until uiomove(9) becomes MP-safe. */ +#endif /* MIDI_OUTOFGIANT */ dev = minor(i_dev); @@ -380,27 +516,50 @@ midi_read(dev_t i_dev, struct uio * buf, int flag) return (ENXIO); ret = 0; - s = splmidi(); + +#if defined(MIDI_OUTOFGIANT) + mtx_lock(&Giant); + buf2 = malloc(buf->uio_resid, M_DEVBUF, M_WAITOK); + mtx_unlock(&Giant); + if (buf2 == NULL) + return (ENOMEM); +#endif /* MIDI_OUTOFGIANT */ + + mtx_lock(&d->flagqueue_mtx); /* Begin recording. */ d->callback(d, MIDI_CB_START | MIDI_CB_RD); + len = 0; + /* Have we got the data to read? */ if ((d->flags & MIDI_F_NBIO) != 0 && d->midi_dbuf_in.rl == 0) ret = EAGAIN; else { +#if defined(MIDI_OUTOFGIANT) len = buf->uio_resid; - ret = midibuf_uioread(&d->midi_dbuf_in, buf, len); + if ((d->flags & MIDI_F_NBIO) != 0 && len > d->midi_dbuf_in.rl) + len = d->midi_dbuf_in.rl; + ret = midibuf_seqread(&d->midi_dbuf_in, buf2, len, &d->flagqueue_mtx); +#else + len = buf->uio_resid; + ret = midibuf_uioread(&d->midi_dbuf_in, buf, len, &d->flagqueue_mtx); +#endif /* MIDI_OUTOFGIANT */ if (ret < 0) ret = -ret; else ret = 0; } - if (ret == 0 && d->read != NULL) - ret = d->read(i_dev, buf, flag); + mtx_unlock(&d->flagqueue_mtx); - splx(s); +#if defined(MIDI_OUTOFGIANT) + mtx_lock(&Giant); + if (ret == 0) + uiomove((caddr_t)buf2, len, buf); + free(buf2, M_DEVBUF); + mtx_unlock(&Giant); +#endif /* MIDI_OUTOFGIANT */ return (ret); } @@ -408,8 +567,12 @@ midi_read(dev_t i_dev, struct uio * buf, int flag) int midi_write(dev_t i_dev, struct uio * buf, int flag) { - int dev, unit, s, len, ret; + int dev, unit, len, ret; mididev_info *d; +#if defined(MIDI_OUTOFGIANT) + char *buf2, *p; /* XXX Until uiomove(9) becomes MP-safe. */ + int resid; +#endif /* MIDI_OUTOFGIANT */ dev = minor(i_dev); d = get_mididev_info(i_dev, &unit); @@ -420,33 +583,60 @@ midi_write(dev_t i_dev, struct uio * buf, int flag) return (ENXIO); ret = 0; - s = splmidi(); - /* Begin playing. */ - d->callback(d, MIDI_CB_START | MIDI_CB_WR); +#if defined(MIDI_OUTOFGIANT) + resid = buf->uio_resid; + mtx_lock(&d->flagqueue_mtx); + if (resid > d->midi_dbuf_out.fl && + (d->flags & MIDI_F_NBIO)) + resid = d->midi_dbuf_out.fl; + mtx_unlock(&d->flagqueue_mtx); + mtx_lock(&Giant); + buf2 = p = malloc(resid, M_DEVBUF, M_WAITOK); + if (buf2 == NULL) { + mtx_unlock(&Giant); + return (ENOMEM); + } + ret = uiomove((caddr_t)buf2, resid, buf); +#endif /* MIDI_OUTOFGIANT */ + + mtx_lock(&d->flagqueue_mtx); /* Have we got the data to write? */ - if ((d->flags & MIDI_F_NBIO) != 0 && d->midi_dbuf_out.fl == 0) + if ((d->flags & MIDI_F_NBIO) != 0 && d->midi_dbuf_out.fl == 0) { + /* Begin playing. */ + d->callback(d, MIDI_CB_START | MIDI_CB_WR); ret = EAGAIN; - else { + } else { +#if defined(MIDI_OUTOFGIANT) + len = resid - (p - buf2); +#else len = buf->uio_resid; +#endif /* MIDI_OUTOFGIANT */ if (len > d->midi_dbuf_out.fl && (d->flags & MIDI_F_NBIO)) len = d->midi_dbuf_out.fl; - ret = midibuf_uiowrite(&d->midi_dbuf_out, buf, len); +#if defined(MIDI_OUTOFGIANT) + ret = midibuf_seqwrite(&d->midi_dbuf_out, p, len, &d->flagqueue_mtx); +#else + ret = midibuf_uiowrite(&d->midi_dbuf_out, buf, len, &d->flagqueue_mtx); +#endif /* MIDI_OUTOFGIANT */ if (ret < 0) ret = -ret; - else + else { + /* Begin playing. */ + d->callback(d, MIDI_CB_START | MIDI_CB_WR); ret = 0; + } } - /* Begin playing. */ - d->callback(d, MIDI_CB_START | MIDI_CB_WR); + mtx_unlock(&d->flagqueue_mtx); - if (ret == 0 && d->write != NULL) - ret = d->write(i_dev, buf, flag); - - splx(s); +#if defined(MIDI_OUTOFGIANT) + mtx_lock(&Giant); + free(buf2, M_DEVBUF); + mtx_unlock(&Giant); +#endif /* MIDI_OUTOFGIANT */ return (ret); } @@ -470,7 +660,6 @@ midi_ioctl(dev_t i_dev, u_long cmd, caddr_t arg, int mode, struct proc * p) int ret = ENOSYS, dev, unit; mididev_info *d; struct snd_size *sndsize; - u_long s; dev = minor(i_dev); d = get_mididev_info(i_dev, &unit); @@ -492,7 +681,6 @@ midi_ioctl(dev_t i_dev, u_long cmd, caddr_t arg, int mode, struct proc * p) * all routines are called with int. blocked. Make sure that * ints are re-enabled when calling slow or blocking functions! */ - s = splmidi(); switch(cmd) { /* @@ -504,10 +692,14 @@ midi_ioctl(dev_t i_dev, u_long cmd, caddr_t arg, int mode, struct proc * p) case AIOSSIZE: /* set the current blocksize */ sndsize = (struct snd_size *)arg; + mtx_lock(&d->flagqueue_mtx); if (sndsize->play_size <= d->midi_dbuf_out.unit_size && sndsize->rec_size <= d->midi_dbuf_in.unit_size) { - d->flags &= ~MIDI_F_HAS_SIZE; d->midi_dbuf_out.blocksize = d->midi_dbuf_out.unit_size; d->midi_dbuf_in.blocksize = d->midi_dbuf_in.unit_size; + sndsize->play_size = d->midi_dbuf_out.blocksize; + sndsize->rec_size = d->midi_dbuf_in.blocksize; + d->flags &= ~MIDI_F_HAS_SIZE; + mtx_unlock(&d->flagqueue_mtx); } else { if (sndsize->play_size > d->midi_dbuf_out.bufsize / 4) @@ -521,27 +713,36 @@ midi_ioctl(dev_t i_dev, u_long cmd, caddr_t arg, int mode, struct proc * p) d->midi_dbuf_in.blocksize = ((sndsize->rec_size + d->midi_dbuf_in.unit_size - 1) / d->midi_dbuf_in.unit_size) * d->midi_dbuf_in.unit_size; + sndsize->play_size = d->midi_dbuf_out.blocksize; + sndsize->rec_size = d->midi_dbuf_in.blocksize; d->flags |= MIDI_F_HAS_SIZE; + mtx_unlock(&d->flagqueue_mtx); } - /* FALLTHROUGH */ + + ret = 0; + break; + case AIOGSIZE: /* get the current blocksize */ sndsize = (struct snd_size *)arg; + mtx_lock(&d->flagqueue_mtx); sndsize->play_size = d->midi_dbuf_out.blocksize; sndsize->rec_size = d->midi_dbuf_in.blocksize; + mtx_unlock(&d->flagqueue_mtx); ret = 0; break; case AIOSTOP: + mtx_lock(&d->flagqueue_mtx); if (*(int *)arg == AIOSYNC_PLAY) /* play */ *(int *)arg = d->callback(d, MIDI_CB_STOP | MIDI_CB_WR); else if (*(int *)arg == AIOSYNC_CAPTURE) *(int *)arg = d->callback(d, MIDI_CB_STOP | MIDI_CB_RD); else { - splx(s); DEB(printf("AIOSTOP: bad channel 0x%x\n", *(int *)arg)); *(int *)arg = 0 ; } + mtx_unlock(&d->flagqueue_mtx); break ; case AIOSYNC: @@ -561,20 +762,25 @@ midi_ioctl(dev_t i_dev, u_long cmd, caddr_t arg, int mode, struct proc * p) break; case FIONBIO: /* set/clear non-blocking i/o */ + mtx_lock(&d->flagqueue_mtx); if ( *(int *)arg == 0 ) d->flags &= ~MIDI_F_NBIO ; else d->flags |= MIDI_F_NBIO ; + mtx_unlock(&d->flagqueue_mtx); break ; case MIOSPASSTHRU: /* set/clear passthru */ + mtx_lock(&d->flagqueue_mtx); if ( *(int *)arg == 0 ) d->flags &= ~MIDI_F_PASSTHRU ; else d->flags |= MIDI_F_PASSTHRU ; /* Init the queue. */ - midibuf_init(&d->midi_dbuf_passthru); + midibuf_clear(&d->midi_dbuf_passthru); + + mtx_unlock(&d->flagqueue_mtx); /* FALLTHROUGH */ case MIOGPASSTHRU: /* get passthru */ @@ -590,14 +796,13 @@ midi_ioctl(dev_t i_dev, u_long cmd, caddr_t arg, int mode, struct proc * p) ret = EINVAL; break ; } - splx(s); return ret ; } int midi_poll(dev_t i_dev, int events, struct proc * p) { - int unit, dev, ret, s, lim; + int unit, dev, ret, lim; mididev_info *d; dev = minor(i_dev); @@ -606,11 +811,9 @@ midi_poll(dev_t i_dev, int events, struct proc * p) if (d == NULL) return (ENXIO); - if (d->poll) - ret = d->poll(i_dev, events, p); - ret = 0; - s = splmidi(); + + mtx_lock(&d->flagqueue_mtx); /* Look up the apropriate queue and select it. */ if ((events & (POLLOUT | POLLWRNORM)) != 0) { @@ -645,7 +848,8 @@ midi_poll(dev_t i_dev, int events, struct proc * p) /* We can write now. */ ret |= events & (POLLIN | POLLRDNORM); } - splx(s); + + mtx_unlock(&d->flagqueue_mtx); return (ret); } @@ -657,6 +861,36 @@ midi_intr(mididev_info *d) d->intr(d->intrarg, d); } +/* Flush the output queue. */ +#define MIDI_SYNC_TIMEOUT 1 +int +midi_sync(mididev_info *d) +{ + int i, rl; + + mtx_assert(&d->flagqueue_mtx, MA_OWNED); + + while (d->midi_dbuf_out.rl > 0) { + if ((d->flags & MIDI_F_WRITING) == 0) + d->callback(d, MIDI_CB_START | MIDI_CB_WR); + rl = d->midi_dbuf_out.rl; + i = msleep(&d->midi_dbuf_out.tsleep_out, &d->flagqueue_mtx, PRIBIO | PCATCH, "midsnc", (d->midi_dbuf_out.bufsize * 10 * hz / 38400) + MIDI_SYNC_TIMEOUT * hz); + if (i == EINTR || i == ERESTART) { + if (i == EINTR) + d->callback(d, MIDI_CB_STOP | MIDI_CB_WR); + return (i); + } + if (i == EWOULDBLOCK && rl == d->midi_dbuf_out.rl) { + /* A queue seems to be stuck up. Give up and clear the queue. */ + d->callback(d, MIDI_CB_STOP | MIDI_CB_WR); + midibuf_clear(&d->midi_dbuf_out); + return (0); + } + } + + return 0; +} + /* * These handle the status message of the midi drivers. */ @@ -705,8 +939,8 @@ midi_initstatus(char *buf, int size) p = 0; p += snprintf(buf, size, "FreeBSD Midi Driver (newmidi) %s %s\nInstalled devices:\n", __DATE__, __TIME__); - for (i = 0 ; i < NMIDI_MAX ; i++) { - md = &midi_info[i]; + for (i = 0 ; i < mididev_info_number() ; i++) { + md = get_mididev_info_unit(i); if (!MIDICONFED(md)) continue; dev = devclass_get_device(midi_devclass, i); @@ -723,15 +957,13 @@ midi_initstatus(char *buf, int size) static int midi_readstatus(char *buf, int *ptr, struct uio *uio) { - int s, len; + int len; - s = splmidi(); len = min(uio->uio_resid, strlen(&buf[*ptr])); if (len > 0) { uiomove(&buf[*ptr], len, uio); *ptr += len; } - splx(s); return (0); } diff --git a/sys/dev/sound/midi/midi.h b/sys/dev/sound/midi/midi.h index b0982c884630..d9b81c7ec2a3 100644 --- a/sys/dev/sound/midi/midi.h +++ b/sys/dev/sound/midi/midi.h @@ -65,6 +65,7 @@ #include #include #include +#include #include #include @@ -72,6 +73,31 @@ #define MIDI_CDEV_MAJOR 30 +/*#define MIDI_OUTOFGIANT*/ + +#if defined(MIDI_OUTOFGIANT) +#define MIDI_DROP_GIANT DROP_GIANT +#define MIDI_DROP_GIANT_NOSWITCH DROP_GIANT_NOSWITCH +#define MIDI_PICKUP_GIANT PICKUP_GIANT +#define MIDI_PARTIAL_PICKUP_GIANT PARTIAL_PICKUP_GIANT +#else +#define MIDI_DROP_GIANT() +#define MIDI_DROP_GIANT_NOSWITCH() +#define MIDI_PICKUP_GIANT() +#define MIDI_PARTIAL_PICKUP_GIANT() +#endif /* MIDI_OUTOFGIANT */ + + +/* + * The order of mutex lock (from the first to the last) + * + * 1. sequencer flags, queues, timer and device list + * 2. midi synth voice and channel + * 3. midi synth status + * 4. generic midi flags and queues + * 5. midi device + */ + /* * descriptor of midi operations ... * @@ -89,10 +115,7 @@ struct _mididev_info { d_open_t *open; d_close_t *close; - d_read_t *read; - d_write_t *write; d_ioctl_t *ioctl; - d_poll_t *poll; midi_callback_t *callback; /* @@ -133,6 +156,9 @@ struct _mididev_info { * mss codec type, etc. etc. */ + struct mtx flagqueue_mtx; /* Mutex to protect flags and queues */ + + /* Queues */ midi_dbuf midi_dbuf_in; /* midi input event/message queue */ midi_dbuf midi_dbuf_out; /* midi output event/message queue */ midi_dbuf midi_dbuf_passthru; /* midi passthru event/message queue */ @@ -142,6 +168,7 @@ struct _mididev_info { * Generic things like busy flag, speed, etc are here. */ + /* Flags */ volatile u_long flags ; /* 32 bits, used for various purposes. */ int fflags; /* file flag */ @@ -211,6 +238,12 @@ struct _mididev_info { /* This is the status message to display via /dev/midistat */ char midistat[128]; + + /* The tailq entry of the next midi device. */ + TAILQ_ENTRY(_mididev_info) md_link; + + /* The tailq entry of the next midi device opened by a sequencer. */ + TAILQ_ENTRY(_mididev_info) md_linkseq; } ; /* @@ -243,7 +276,7 @@ struct _mididev_info { /* * finally, all default parameters */ -#define MIDI_BUFFSIZE (4 * 1024) /* XXX */ +#define MIDI_BUFFSIZE (1024) /* XXX */ /* * some macros for debugging purposes @@ -263,7 +296,7 @@ struct _mididev_info { /* This provides an access to the mididev_info. */ mididev_info *get_mididev_info(dev_t i_dev, int *unit); mididev_info *get_mididev_info_unit(int unit); - mididev_info *create_mididev_info_unit(int *unit, int type); + mididev_info *create_mididev_info_unit(int type, mididev_info *mdinf, synthdev_info *syninf); int mididev_info_number(void); #define MDT_MIDI (0) #define MDT_SYNTH (1) @@ -279,10 +312,8 @@ struct _mididev_info { /* Common interrupt handler */ void midi_intr(mididev_info *); -/* - * library functions (in midi.c) - */ -#define splmidi() spltty() +/* Sync output */ +int midi_sync(mididev_info *); /* * Minor numbers for the midi driver. diff --git a/sys/dev/sound/midi/midibuf.c b/sys/dev/sound/midi/midibuf.c index 5922a5b95022..e1f15c79cb9d 100644 --- a/sys/dev/sound/midi/midibuf.c +++ b/sys/dev/sound/midi/midibuf.c @@ -44,6 +44,7 @@ static void queuerawdata(midi_dbuf *dbuf, char *data, int len); static void queueuiodata(midi_dbuf *dbuf, struct uio *buf, int len); static void dequeuerawdata(midi_dbuf *dbuf, char *data, int len); +static void undequeuerawdata(midi_dbuf *dbuf, char *data, int len); static void copyrawdata(midi_dbuf *dbuf, char *data, int len); static void dequeueuiodata(midi_dbuf *dbuf, struct uio *buf, int len); @@ -57,7 +58,23 @@ midibuf_init(midi_dbuf *dbuf) { if (dbuf->buf != NULL) free(dbuf->buf, M_DEVBUF); - dbuf->buf = malloc(MIDI_BUFFSIZE, M_DEVBUF, M_NOWAIT); + dbuf->buf = malloc(MIDI_BUFFSIZE, M_DEVBUF, M_WAITOK | M_ZERO); + + return (midibuf_clear(dbuf)); +} + +int +midibuf_destroy(midi_dbuf *dbuf) +{ + if (dbuf->buf != NULL) + free(dbuf->buf, M_DEVBUF); + + return (0); +} + +int +midibuf_clear(midi_dbuf *dbuf) +{ bzero(dbuf->buf, MIDI_BUFFSIZE); dbuf->bufsize = MIDI_BUFFSIZE; dbuf->rp = dbuf->fp = 0; @@ -77,7 +94,7 @@ midibuf_init(midi_dbuf *dbuf) /* The sequencer calls this function to queue data. */ int -midibuf_seqwrite(midi_dbuf *dbuf, u_char* data, int len) +midibuf_seqwrite(midi_dbuf *dbuf, u_char* data, int len, struct mtx *m) { int i, lwrt, lwritten; @@ -104,7 +121,7 @@ midibuf_seqwrite(midi_dbuf *dbuf, u_char* data, int len) /* Have we got still more data to write? */ if (len > 0) { /* Yes, sleep until we have enough space. */ - i = tsleep((void *)&dbuf->tsleep_out, PRIBIO | PCATCH, "mbsqwt", 0); + i = msleep((void *)&dbuf->tsleep_out, m, PRIBIO | PCATCH, "mbsqwt", 0); if (i == EINTR || i == ERESTART) return (-i); } @@ -115,7 +132,7 @@ midibuf_seqwrite(midi_dbuf *dbuf, u_char* data, int len) /* sndwrite calls this function to queue data. */ int -midibuf_uiowrite(midi_dbuf *dbuf, struct uio *buf, int len) +midibuf_uiowrite(midi_dbuf *dbuf, struct uio *buf, int len, struct mtx *m) { int i, lwrt, lwritten; @@ -141,7 +158,7 @@ midibuf_uiowrite(midi_dbuf *dbuf, struct uio *buf, int len) /* Have we got still more data to write? */ if (len > 0) { /* Yes, sleep until we have enough space. */ - i = tsleep(&dbuf->tsleep_out, PRIBIO | PCATCH, "mbuiwt", 0); + i = msleep(&dbuf->tsleep_out, m, PRIBIO | PCATCH, "mbuiwt", 0); if (i == EINTR || i == ERESTART) return (-i); } @@ -202,7 +219,7 @@ midibuf_input_intr(midi_dbuf *dbuf, u_char *data, int len) /* The sequencer calls this function to dequeue data. */ int -midibuf_seqread(midi_dbuf *dbuf, u_char* data, int len) +midibuf_seqread(midi_dbuf *dbuf, u_char* data, int len, struct mtx *m) { int i, lrd, lread; @@ -216,7 +233,7 @@ midibuf_seqread(midi_dbuf *dbuf, u_char* data, int len) /* Have we got data to read? */ if ((lrd = DATA_AVAIL(dbuf)) == 0) { /* No, sleep until we have data ready to read. */ - i = tsleep(&dbuf->tsleep_in, PRIBIO | PCATCH, "mbsqrd", 0); + i = msleep(&dbuf->tsleep_in, m, PRIBIO | PCATCH, "mbsqrd", 0); if (i == EINTR || i == ERESTART) return (-i); if (i == EWOULDBLOCK) @@ -240,9 +257,49 @@ midibuf_seqread(midi_dbuf *dbuf, u_char* data, int len) return (lread); } +/* The sequencer calls this function to undo dequeued data. */ +int +midibuf_sequnread(midi_dbuf *dbuf, u_char* data, int len, struct mtx *m) +{ + int i, lrd, lunread; + + /* Is this a real queue? */ + if (dbuf == (midi_dbuf *)NULL) + return (0); + + lunread = 0; + /* Write down every single byte. */ + while (len > 0) { + /* Have we got data to read? */ + if ((lrd = SPACE_AVAIL(dbuf)) == 0) { + /* No, sleep until we have data ready to read. */ + i = msleep(&dbuf->tsleep_in, m, PRIBIO | PCATCH, "mbsqur", 0); + if (i == EINTR || i == ERESTART) + return (-i); + if (i == EWOULDBLOCK) + continue; + /* Find out the number of bytes to unread. */ + lrd = SPACE_AVAIL(dbuf); + } + + if (lrd > len) + lrd = len; + if (lrd > 0) { + /* We can read some data now. Dequeue the data. */ + undequeuerawdata(dbuf, data, lrd); + + lunread += lrd; + len -= lrd; + data += lrd; + } + } + + return (lunread); +} + /* The sequencer calls this function to copy data without dequeueing. */ int -midibuf_seqcopy(midi_dbuf *dbuf, u_char* data, int len) +midibuf_seqcopy(midi_dbuf *dbuf, u_char* data, int len, struct mtx *m) { int i, lrd, lread; @@ -256,7 +313,7 @@ midibuf_seqcopy(midi_dbuf *dbuf, u_char* data, int len) /* Have we got data to read? */ if ((lrd = DATA_AVAIL(dbuf)) == 0) { /* No, sleep until we have data ready to read. */ - i = tsleep(&dbuf->tsleep_in, PRIBIO | PCATCH, "mbsqrd", 0); + i = msleep(&dbuf->tsleep_in, m, PRIBIO | PCATCH, "mbsqrd", 0); if (i == EINTR || i == ERESTART) return (-i); if (i == EWOULDBLOCK) @@ -282,7 +339,7 @@ midibuf_seqcopy(midi_dbuf *dbuf, u_char* data, int len) /* sndread calls this function to dequeue data. */ int -midibuf_uioread(midi_dbuf *dbuf, struct uio *buf, int len) +midibuf_uioread(midi_dbuf *dbuf, struct uio *buf, int len, struct mtx *m) { int i, lrd, lread; @@ -295,7 +352,7 @@ midibuf_uioread(midi_dbuf *dbuf, struct uio *buf, int len) /* Have we got data to read? */ if ((lrd = DATA_AVAIL(dbuf)) == 0) { /* No, sleep until we have data ready to read. */ - i = tsleep(&dbuf->tsleep_in, PRIBIO | PCATCH, "mbuird", 0); + i = msleep(&dbuf->tsleep_in, m, PRIBIO | PCATCH, "mbuird", 0); if (i == EINTR || i == ERESTART) return (-i); if (i == EWOULDBLOCK) @@ -385,6 +442,28 @@ dequeuerawdata(midi_dbuf *dbuf, char *data, int len) selwakeup(&dbuf->sel); } +/* Undo the last dequeue. */ +static void +undequeuerawdata(midi_dbuf *dbuf, char *data, int len) +{ + /* Copy the data. */ + if (dbuf->rp < len) { + memcpy(dbuf->buf, data + (len - dbuf->rp), dbuf->rp); + memcpy(dbuf->buf + (dbuf->bufsize - (len - dbuf->rp)), data, len - dbuf->rp); + } else + memcpy(dbuf->buf + (dbuf->rp - len), data, len); + + /* Adjust the pointer and the length counters. */ + dbuf->rp = (dbuf->rp - len + dbuf->bufsize) % dbuf->bufsize; + dbuf->rl += len; + dbuf->fl -= len; + + /* Wake up the processes sleeping on queueing. */ + wakeup(&dbuf->tsleep_in); + if (dbuf->sel.si_pid && dbuf->rl >= dbuf->blocksize) + selwakeup(&dbuf->sel); +} + static void copyrawdata(midi_dbuf *dbuf, char *data, int len) { diff --git a/sys/dev/sound/midi/midibuf.h b/sys/dev/sound/midi/midibuf.h index d40019db8a5a..68a7a377d43a 100644 --- a/sys/dev/sound/midi/midibuf.h +++ b/sys/dev/sound/midi/midibuf.h @@ -55,10 +55,13 @@ typedef struct _midi_dbuf { * These are the midi buffer methods, used in midi interface devices. */ int midibuf_init(midi_dbuf *dbuf); -int midibuf_seqwrite(midi_dbuf *dbuf, u_char* data, int len); -int midibuf_uiowrite(midi_dbuf *dbuf, struct uio *buf, int len); +int midibuf_destroy(midi_dbuf *dbuf); +int midibuf_clear(midi_dbuf *dbuf); +int midibuf_seqwrite(midi_dbuf *dbuf, u_char* data, int len, struct mtx *m); +int midibuf_uiowrite(midi_dbuf *dbuf, struct uio *buf, int len, struct mtx *m); int midibuf_output_intr(midi_dbuf *dbuf, u_char *data, int len); int midibuf_input_intr(midi_dbuf *dbuf, u_char *data, int len); -int midibuf_seqread(midi_dbuf *dbuf, u_char* data, int len); -int midibuf_seqcopy(midi_dbuf *dbuf, u_char* data, int len); -int midibuf_uioread(midi_dbuf *dbuf, struct uio *buf, int len); +int midibuf_seqread(midi_dbuf *dbuf, u_char* data, int len, struct mtx *m); +int midibuf_sequnread(midi_dbuf *dbuf, u_char* data, int len, struct mtx *m); +int midibuf_seqcopy(midi_dbuf *dbuf, u_char* data, int len, struct mtx *m); +int midibuf_uioread(midi_dbuf *dbuf, struct uio *buf, int len, struct mtx *m); diff --git a/sys/dev/sound/midi/midisynth.c b/sys/dev/sound/midi/midisynth.c index 481f79ccf02c..63b442351b9b 100644 --- a/sys/dev/sound/midi/midisynth.c +++ b/sys/dev/sound/midi/midisynth.c @@ -107,7 +107,7 @@ static int synth_leavesysex(mididev_info *md); static int synth_killnote(mididev_info *md, int chn, int note, int vel) { - int unit, msg, chp; + int unit; synthdev_info *sd; u_char c[3]; @@ -120,41 +120,21 @@ synth_killnote(mididev_info *md, int chn, int note, int vel) if (synth_leavesysex(md) == EAGAIN) return (EAGAIN); - msg = sd->prev_out_status & 0xf0; - chp = sd->prev_out_status & 0x0f; - - if (chp == chn && ((msg == 0x90 && vel == 64) || msg == 0x80)) { - /* Use running status. */ - c[0] = (u_char)note; - if (msg == 0x90) - /* The note was on. */ - c[1] = 0; - else - c[1] = (u_char)vel; - - if (synth_prefixcmd(md, c[0])) - return (0); - if (md->synth.writeraw(md, c, 2, 1) == EAGAIN) - return (EAGAIN); + if (vel == 64) { + c[0] = 0x90 | (chn & 0x0f); /* Note on. */ + c[1] = (u_char)note; + c[2] = 0; } else { - if (vel == 64) { - c[0] = 0x90 | (chn & 0x0f); /* Note on. */ - c[1] = (u_char)note; - c[2] = 0; - } else { - c[0] = 0x80 | (chn & 0x0f); /* Note off. */ - c[1] = (u_char)note; - c[2] = (u_char)vel; - } - - if (synth_prefixcmd(md, c[0])) - return (0); - if (md->synth.writeraw(md, c, 3, 1) == EAGAIN) - return EAGAIN; - /* Update the status. */ - sd->prev_out_status = c[0]; + c[0] = 0x80 | (chn & 0x0f); /* Note off. */ + c[1] = (u_char)note; + c[2] = (u_char)vel; } + if (synth_prefixcmd(md, c[0])) + return (0); + if (md->synth.writeraw(md, c, 3, 1) == EAGAIN) + return EAGAIN; + return (0); } @@ -178,8 +158,6 @@ synth_setinstr(mididev_info *md, int chn, int instr) c[1] = (u_char)instr; if (md->synth.writeraw(md, c, 3, 1) == EAGAIN) return (EAGAIN); - /* Update the status. */ - sd->prev_out_status = c[0]; return (0); } @@ -187,7 +165,7 @@ synth_setinstr(mididev_info *md, int chn, int instr) static int synth_startnote(mididev_info *md, int chn, int note, int vel) { - int unit, msg, chp; + int unit; synthdev_info *sd; u_char c[3]; @@ -200,28 +178,13 @@ synth_startnote(mididev_info *md, int chn, int note, int vel) if (synth_leavesysex(md) == EAGAIN) return (EAGAIN); - msg = sd->prev_out_status & 0xf0; - chp = sd->prev_out_status & 0x0f; - - if (chp == chn && msg == 0x90) { - /* Use running status. */ - c[0] = (u_char)note; - c[1] = (u_char)vel; - if (synth_prefixcmd(md, c[0])) - return (0); - if (md->synth.writeraw(md, c, 2, 1) == EAGAIN) - return (EAGAIN); - } else { - c[0] = 0x90 | (chn & 0x0f); /* Note on. */ - c[1] = (u_char)note; - c[2] = (u_char)vel; - if (synth_prefixcmd(md, c[0])) - return (0); - if (md->synth.writeraw(md, c, 3, 1) == EAGAIN) - return (EAGAIN); - /* Update the status. */ - sd->prev_out_status = c[0]; - } + c[0] = 0x90 | (chn & 0x0f); /* Note on. */ + c[1] = (u_char)note; + c[2] = (u_char)vel; + if (synth_prefixcmd(md, c[0])) + return (0); + if (md->synth.writeraw(md, c, 3, 1) == EAGAIN) + return (EAGAIN); return (0); } @@ -292,8 +255,6 @@ synth_loadpatch(mididev_info *md, int format, struct uio *buf, int offs, int cou } if (!first_byte && (c[i] & 0x80) != 0) { md->synth.writeraw(md, c, i + 1, 0); - /* Update the status. */ - sd->prev_out_status = c[i]; return (0); } first_byte = 0; @@ -302,7 +263,6 @@ synth_loadpatch(mididev_info *md, int format, struct uio *buf, int offs, int cou if (!eox_seen) { c[0] = 0xf7; md->synth.writeraw(md, c, 1, 0); - sd->prev_out_status = c[0]; } return (0); @@ -318,7 +278,7 @@ synth_panning(mididev_info *md, int chn, int pan) static int synth_aftertouch(mididev_info *md, int chn, int press) { - int unit, msg, chp; + int unit; synthdev_info *sd; u_char c[2]; @@ -330,26 +290,12 @@ synth_aftertouch(mididev_info *md, int chn, int press) if (synth_leavesysex(md) == EAGAIN) return (EAGAIN); - msg = sd->prev_out_status & 0xf0; - chp = sd->prev_out_status & 0x0f; - - if (chp == chn && msg == 0xd0) { - /* Use running status. */ - c[0] = (u_char)press; - if (synth_prefixcmd(md, c[0])) - return (0); - if (md->synth.writeraw(md, c, 1, 1) == EAGAIN) - return (EAGAIN); - } else { - c[0] = 0xd0 | (chn & 0x0f); /* Channel Pressure. */ - c[1] = (u_char)press; - if (synth_prefixcmd(md, c[0])) - return (0); - if (md->synth.writeraw(md, c, 2, 1) == EAGAIN) - return (EAGAIN); - /* Update the status. */ - sd->prev_out_status = c[0]; - } + c[0] = 0xd0 | (chn & 0x0f); /* Channel Pressure. */ + c[1] = (u_char)press; + if (synth_prefixcmd(md, c[0])) + return (0); + if (md->synth.writeraw(md, c, 2, 1) == EAGAIN) + return (EAGAIN); return (0); } @@ -357,7 +303,7 @@ synth_aftertouch(mididev_info *md, int chn, int press) static int synth_controller(mididev_info *md, int chn, int ctrlnum, int val) { - int unit, msg, chp; + int unit; synthdev_info *sd; u_char c[3]; @@ -369,27 +315,12 @@ synth_controller(mididev_info *md, int chn, int ctrlnum, int val) if (synth_leavesysex(md) == EAGAIN) return (EAGAIN); - msg = sd->prev_out_status & 0xf0; - chp = sd->prev_out_status & 0x0f; - - if (chp == chn && msg == 0xb0) { - /* Use running status. */ - c[0] = (u_char)ctrlnum; - c[1] = (u_char)val & 0x7f; - if (synth_prefixcmd(md, c[0])) - return (0); - if (md->synth.writeraw(md, c, 2, 1) == EAGAIN) - return (EAGAIN); - } else { - c[0] = 0xb0 | (chn & 0x0f); /* Control Message. */ - c[1] = (u_char)ctrlnum; - if (synth_prefixcmd(md, c[0])) - return (0); - if (md->synth.writeraw(md, c, 3, 1) == EAGAIN) - return (EAGAIN); - /* Update the status. */ - sd->prev_out_status = c[0]; - } + c[0] = 0xb0 | (chn & 0x0f); /* Control Message. */ + c[1] = (u_char)ctrlnum; + if (synth_prefixcmd(md, c[0])) + return (0); + if (md->synth.writeraw(md, c, 3, 1) == EAGAIN) + return (EAGAIN); return (0); } @@ -403,7 +334,7 @@ synth_patchmgr(mididev_info *md, struct patmgr_info *rec) static int synth_bender(mididev_info *md, int chn, int val) { - int unit, msg, chp; + int unit; synthdev_info *sd; u_char c[3]; @@ -415,28 +346,13 @@ synth_bender(mididev_info *md, int chn, int val) if (synth_leavesysex(md) == EAGAIN) return (EAGAIN); - msg = sd->prev_out_status & 0xf0; - chp = sd->prev_out_status & 0x0f; - - if (chp == chn && msg == 0xe0) { - /* Use running status. */ - c[0] = (u_char)val & 0x7f; - c[1] = (u_char)(val >> 7) & 0x7f; - if (synth_prefixcmd(md, c[0])) - return (0); - if (md->synth.writeraw(md, c, 2, 1) == EAGAIN) - return (EAGAIN); - } else { - c[0] = 0xe0 | (chn & 0x0f); /* Pitch bend. */ - c[1] = (u_char)val & 0x7f; - c[2] = (u_char)(val >> 7) & 0x7f; - if (synth_prefixcmd(md, c[0])) - return (0); - if (md->synth.writeraw(md, c, 3, 1) == EAGAIN) - return (EAGAIN); - /* Update the status. */ - sd->prev_out_status = c[0]; - } + c[0] = 0xe0 | (chn & 0x0f); /* Pitch bend. */ + c[1] = (u_char)val & 0x7f; + c[2] = (u_char)(val >> 7) & 0x7f; + if (synth_prefixcmd(md, c[0])) + return (0); + if (md->synth.writeraw(md, c, 3, 1) == EAGAIN) + return (EAGAIN); return (0); } @@ -458,30 +374,37 @@ synth_setupvoice(mididev_info *md, int voice, int chn) static int synth_sendsysex(mididev_info *md, u_char *sysex, int len) { - int unit, i, j; + int unit, i; synthdev_info *sd; u_char c[len]; unit = md->unit; sd = &md->synth; + mtx_lock(&sd->status_mtx); for (i = 0 ; i < len ; i++) { switch (sysex[i]) { case 0xf0: /* Sysex begins. */ - if (synth_prefixcmd(md, 0xf0)) + if (synth_prefixcmd(md, 0xf0)) { + mtx_unlock(&sd->status_mtx); return (0); + } sd->sysex_state = 1; break; case 0xf7: /* Sysex ends. */ - if (!sd->sysex_state) + if (!sd->sysex_state) { + mtx_unlock(&sd->status_mtx); return (0); + } sd->sysex_state = 0; break; default: - if (!sd->sysex_state) + if (!sd->sysex_state) { + mtx_unlock(&sd->status_mtx); return (0); + } if ((sysex[i] & 0x80) != 0) { /* A status in a sysex? */ sysex[i] = 0xf7; @@ -493,16 +416,10 @@ synth_sendsysex(mididev_info *md, u_char *sysex, int len) if (!sd->sysex_state) break; } + mtx_unlock(&sd->status_mtx); if (md->synth.writeraw(md, c, i, 1) == EAGAIN) return (EAGAIN); - /* Update the status. */ - for (j = i - 1 ; j >= 0 ; j--) - if ((c[j] & 0x80) != 0) { - sd->prev_out_status = c[j]; - break; - } - return (0); } @@ -523,7 +440,7 @@ synth_volumemethod(mididev_info *md, int mode) static int synth_readraw(mididev_info *md, u_char *buf, int len, int nonblock) { - int unit, ret, s; + int unit, ret; if (md == NULL) return (ENXIO); @@ -534,20 +451,23 @@ synth_readraw(mididev_info *md, u_char *buf, int len, int nonblock) return (EIO); } - s = splmidi(); + mtx_lock(&md->flagqueue_mtx); /* Begin recording. */ - md->callback(md, MIDI_CB_START | MIDI_CB_RD); + if ((md->flags & MIDI_F_READING) == 0) + md->callback(md, MIDI_CB_START | MIDI_CB_RD); if (nonblock) { /* Have we got enough data to read? */ - if (md->midi_dbuf_in.rl < len) + if (md->midi_dbuf_in.rl < len) { + mtx_unlock(&md->flagqueue_mtx); return (EAGAIN); + } } - ret = midibuf_seqread(&md->midi_dbuf_in, buf, len); + ret = midibuf_seqread(&md->midi_dbuf_in, buf, len, &md->flagqueue_mtx); - splx(s); + mtx_unlock(&md->flagqueue_mtx); if (ret < 0) ret = -ret; @@ -560,7 +480,7 @@ synth_readraw(mididev_info *md, u_char *buf, int len, int nonblock) static int synth_writeraw(mididev_info *md, u_char *buf, int len, int nonblock) { - int unit, ret, s; + int unit, ret; if (md == NULL) return (ENXIO); @@ -573,21 +493,25 @@ synth_writeraw(mididev_info *md, u_char *buf, int len, int nonblock) } /* For nonblocking, have we got enough space to write? */ - if (nonblock && md->midi_dbuf_out.fl < len) + mtx_lock(&md->flagqueue_mtx); + if (nonblock && md->midi_dbuf_out.fl < len) { + /* Begin playing. */ + md->callback(md, MIDI_CB_START | MIDI_CB_WR); + mtx_unlock(&md->flagqueue_mtx); return (EAGAIN); + } - s = splmidi(); + ret = midibuf_seqwrite(&md->midi_dbuf_out, buf, len, &md->flagqueue_mtx); - ret = midibuf_seqwrite(&md->midi_dbuf_out, buf, len); if (ret < 0) ret = -ret; - else + else { + /* Begin playing. */ + md->callback(md, MIDI_CB_START | MIDI_CB_WR); ret = 0; + } - /* Begin playing. */ - md->callback(md, MIDI_CB_START | MIDI_CB_WR); - - splx(s); + mtx_unlock(&md->flagqueue_mtx); return (ret); } @@ -606,16 +530,17 @@ synth_leavesysex(mididev_info *md) unit = md->unit; sd = &md->synth; - if (!sd->sysex_state) + mtx_lock(&sd->status_mtx); + if (!sd->sysex_state) { + mtx_unlock(&sd->status_mtx); return (0); + } sd->sysex_state = 0; + mtx_unlock(&sd->status_mtx); c = 0xf7; if (md->synth.writeraw(md, &c, sizeof(c), 1) == EAGAIN) return (EAGAIN); - sd->sysex_state = 0; - /* Update the status. */ - sd->prev_out_status = c; return (0); } diff --git a/sys/dev/sound/midi/midisynth.h b/sys/dev/sound/midi/midisynth.h index d27e62bea771..db43354facbc 100644 --- a/sys/dev/sound/midi/midisynth.h +++ b/sys/dev/sound/midi/midisynth.h @@ -67,6 +67,16 @@ typedef int (mdsy_volumemethod_t)(mididev_info *md, int mode); typedef int (mdsy_readraw_t)(mididev_info *md, u_char *buf, int len, int nonblock); typedef int (mdsy_writeraw_t)(mididev_info *md, u_char *buf, int len, int nonblock); +/* + * The order of mutex lock (from the first to the last) + * + * 1. sequencer flags, queues, timer and devlice list + * 2. midi synth voice and channel + * 3. midi synth status + * 4. generic midi flags and queues + * 5. midi device + */ + /* This is a midi synthesizer interface and state. */ struct _synthdev_info { mdsy_killnote_t *killnote; @@ -88,10 +98,13 @@ struct _synthdev_info { mdsy_readraw_t *readraw; mdsy_writeraw_t *writeraw; + /* Voice and channel */ + struct mtx vc_mtx; /* Mutex to protect voice and channel. */ struct voice_alloc_info alloc; /* Voice allocation. */ struct channel_info chn_info[16]; /* Channel information. */ - u_char prev_out_status; /* Previous status. */ + /* Status */ + struct mtx status_mtx; /* Mutex to protect status. */ int sysex_state; /* State of sysex transmission. */ }; typedef struct _synthdev_info synthdev_info; diff --git a/sys/dev/sound/midi/sequencer.c b/sys/dev/sound/midi/sequencer.c index 7b010b4248c3..dd4ce6aeab13 100644 --- a/sys/dev/sound/midi/sequencer.c +++ b/sys/dev/sound/midi/sequencer.c @@ -58,6 +58,11 @@ enum { QUEUEFULL }; +/* Lookup modes */ +#define LOOKUP_EXIST (0) +#define LOOKUP_OPEN (1) +#define LOOKUP_CLOSE (2) + /* * These functions goes into seq_op_desc to get called * from sound.c. @@ -96,24 +101,35 @@ seqdev_info seq_op_desc = { 0, /* XXX This is not an *audio* device! */ }; + + /* Here is the parameter structure per a device. */ struct seq_softc { seqdev_info *devinfo; /* sequencer device information */ + /* Flags (protected by flag_mtx of mididev_info) */ int fflags; /* Access mode */ + int queueout_pending; /* Pending for the output queue */ + /* Timer counters */ u_long seq_time; /* The beggining time of this sequence */ u_long prev_event_time; /* The time of the previous event output */ u_long prev_input_time; /* The time of the previous event input */ u_long prev_wakeup_time; /* The time of the previous wakeup */ - struct callout_handle timeout_ch; /* Timer callout handler */ + struct callout timeout_ch; /* Timer callout handler */ long timer_current; /* Current timer value */ int timer_running; /* State of timer */ - int midi_open[NMIDI_MAX]; /* State of midi devices. */ int pending_timer; /* Timer change operation */ - int output_threshould; /* Sequence output threshould */ int pre_event_timeout; /* Time to wait event input */ - int queueout_pending; /* Pending for the output queue */ + + /* Device list */ + TAILQ_HEAD(,_mididev_info) midi_open; /* Midi devices opened by this sequencer. */ + + /* + * XXX not sure to which category these belong. + * (and some might be no-op) + */ + int output_threshould; /* Sequence output threshould */ snd_sync_parm sync_parm; /* AIOSYNC parameter set */ struct proc *sync_proc; /* AIOSYNCing process */ }; @@ -145,12 +161,15 @@ static struct cdevsw seq_cdevsw = { /* bmaj */ -1 }; -seqdev_info seq_info[NSEQ_MAX] ; -static int seq_info_inited; -u_long nseq = NSEQ_MAX; /* total number of sequencers */ +static TAILQ_HEAD(,_seqdev_info) seq_info; +/* Mutex to protect seq_info and nseq. */ +static struct mtx seqinfo_mtx; +static u_long nseq; /* total number of sequencers */ +static dev_t seq_alias = NODEV; /* The followings are the local function. */ static int seq_init(void); +static int seq_initunit(int unit); static int seq_queue(sc_p scp, u_char *note); static void seq_startplay(sc_p scp); static int seq_playevent(sc_p scp, u_char *event); @@ -162,7 +181,7 @@ static int seq_copytoinput(sc_p scp, u_char *event, int len); static int seq_extended(sc_p scp, u_char *event); static int seq_chnvoice(sc_p scp, u_char *event); static int seq_findvoice(mididev_info *md, int chn, int note) __unused; -static int seq_allocvoice(mididev_info *md, int chn, int note) __unused; +static int seq_allocvoice(sc_p scp, mididev_info *md, int chn, int note) __unused; static int seq_chncommon(sc_p scp, u_char *event); static int seq_timing(sc_p scp, u_char *event); static int seq_local(sc_p scp, u_char *event); @@ -175,6 +194,10 @@ static void seq_panic(sc_p scp); static int seq_sync(sc_p scp); static seqdev_info *get_seqdev_info(dev_t i_dev, int *unit); +static seqdev_info *get_seqdev_info_unit(int unit); +static seqdev_info *create_seqdev_info_unit(int unit, seqdev_info *seq); +static int lookup_mididev(sc_p scp, int unit, int mode, mididev_info **mdp); +static void seq_clone(void *arg, char *name, int namelen, dev_t *dev); /* * Here are the main functions to interact to the user process. @@ -184,68 +207,73 @@ static seqdev_info *get_seqdev_info(dev_t i_dev, int *unit); static int seq_init(void) { - int unit; - sc_p scp; - seqdev_info *devinfo; - DEB(printf("seq: initing.\n")); - /* Have we already inited? */ - if (seq_info_inited) - return (1); + mtx_init(&seqinfo_mtx, "seqinf", MTX_DEF); + TAILQ_INIT(&seq_info); - for (unit = 0 ; unit < nseq ; unit++) { - /* Allocate the softc. */ - scp = malloc(sizeof(*scp), M_DEVBUF, M_NOWAIT); - if (scp == (sc_p)NULL) { - printf("seq%d: softc allocation failed.\n", unit); - return (1); - } - bzero(scp, sizeof(*scp)); - - /* Fill the softc and the seq_info for this unit. */ - scp->seq_time = seq_gettime(); - scp->prev_event_time = 0; - scp->prev_input_time = 0; - scp->prev_wakeup_time = scp->seq_time; - callout_handle_init(&scp->timeout_ch); - scp->timer_current = 0; - scp->timer_running = 0; - scp->queueout_pending = 0; - - scp->devinfo = devinfo = &seq_info[unit]; - bcopy(&seq_op_desc, devinfo, sizeof(seq_op_desc)); - devinfo->unit = unit; - devinfo->softc = scp; - devinfo->flags = 0; - devinfo->midi_dbuf_in.unit_size = devinfo->midi_dbuf_out.unit_size = EV_SZ; - midibuf_init(&devinfo->midi_dbuf_in); - midibuf_init(&devinfo->midi_dbuf_out); - - make_dev(&seq_cdevsw, MIDIMKMINOR(unit, SND_DEV_SEQ), - UID_ROOT, GID_WHEEL, 0666, "sequencer%d", unit); - } - - /* We have inited. */ - seq_info_inited = 1; - - if (nseq == 1) - printf("seq0: Midi sequencer.\n"); - else - printf("seq0-%lu: Midi sequencers.\n", nseq - 1); + seq_initunit(0); + EVENTHANDLER_REGISTER(dev_clone, seq_clone, 0, 1000); DEB(printf("seq: inited.\n")); return (0); } +static int +seq_initunit(int unit) +{ + sc_p scp; + seqdev_info *devinfo; + dev_t seqdev; + + /* Allocate the softc. */ + scp = malloc(sizeof(*scp), M_DEVBUF, M_WAITOK | M_ZERO); + if (scp == (sc_p)NULL) { + printf("seq%d: softc allocation failed.\n", unit); + return (1); + } + + /* Fill the softc and the seq_info for this unit. */ + scp->seq_time = seq_gettime(); + scp->prev_event_time = 0; + scp->prev_input_time = 0; + scp->prev_wakeup_time = scp->seq_time; +#if defined(MIDI_OUTOFGIANT) + callout_init(&scp->timeout_ch, 1); +#else + callout_init(&scp->timeout_ch, 0); +#endif /* MIDI_OUTOFGIANT */ + scp->timer_current = 0; + scp->timer_running = 0; + scp->queueout_pending = 0; + TAILQ_INIT(&scp->midi_open); + + scp->devinfo = devinfo = create_seqdev_info_unit(unit, &seq_op_desc); + devinfo->midi_dbuf_in.unit_size = devinfo->midi_dbuf_out.unit_size = EV_SZ; + devinfo->softc = scp; + devinfo->flags = 0; + mtx_unlock(&devinfo->flagqueue_mtx); + + seqdev = make_dev(&seq_cdevsw, MIDIMKMINOR(unit, SND_DEV_SEQ), + UID_ROOT, GID_WHEEL, 0666, "sequencer%d", unit); + mtx_lock(&seqinfo_mtx); + if (seq_alias != NODEV) { + destroy_dev(seq_alias); + seq_alias = NODEV; + } + seq_alias = make_dev_alias(seqdev, "sequencer"); + mtx_unlock(&seqinfo_mtx); + + return (0); +} + int seq_open(dev_t i_dev, int flags, int mode, struct proc *p) { - int unit, s, midiunit; + int unit; sc_p scp; seqdev_info *sd; - mididev_info *md; unit = MIDIUNIT(i_dev); @@ -263,10 +291,13 @@ seq_open(dev_t i_dev, int flags, int mode, struct proc *p) } scp = sd->softc; - s = splmidi(); + MIDI_DROP_GIANT_NOSWITCH(); + /* Mark this device busy. */ + mtx_lock(&sd->flagqueue_mtx); if ((sd->flags & SEQ_F_BUSY) != 0) { - splx(s); + mtx_unlock(&sd->flagqueue_mtx); + MIDI_PARTIAL_PICKUP_GIANT(); DEB(printf("seq_open: unit %d is busy.\n", unit)); return (EBUSY); } @@ -275,8 +306,8 @@ seq_open(dev_t i_dev, int flags, int mode, struct proc *p) scp->fflags = flags; /* Init the queue. */ - midibuf_init(&sd->midi_dbuf_in); - midibuf_init(&sd->midi_dbuf_out); + midibuf_clear(&sd->midi_dbuf_in); + midibuf_clear(&sd->midi_dbuf_out); /* Init timestamp. */ scp->seq_time = seq_gettime(); @@ -284,14 +315,9 @@ seq_open(dev_t i_dev, int flags, int mode, struct proc *p) scp->prev_input_time = 0; scp->prev_wakeup_time = scp->seq_time; - splx(s); + mtx_unlock(&sd->flagqueue_mtx); - /* Open midi devices. */ - for (midiunit = 0 ; midiunit < mididev_info_number() ; midiunit++) { - md = get_mididev_info_unit(midiunit); - if (MIDICONFED(md)) - seq_openmidi(scp, md, scp->fflags, MIDIDEV_MODE, p); - } + MIDI_PICKUP_GIANT(); DEB(printf("seq%d: opened.\n", unit)); @@ -301,7 +327,7 @@ seq_open(dev_t i_dev, int flags, int mode, struct proc *p) int seq_close(dev_t i_dev, int flags, int mode, struct proc *p) { - int unit, s, i; + int unit; sc_p scp; seqdev_info *sd; mididev_info *md; @@ -322,7 +348,9 @@ seq_close(dev_t i_dev, int flags, int mode, struct proc *p) } scp = sd->softc; - s = splmidi(); + MIDI_DROP_GIANT_NOSWITCH(); + + mtx_lock(&sd->flagqueue_mtx); if (!(sd->flags & MIDI_F_NBIO)) seq_sync(scp); @@ -335,16 +363,16 @@ seq_close(dev_t i_dev, int flags, int mode, struct proc *p) seq_sync(scp); /* Clean up the midi device. */ - for (i = 0 ; i < mididev_info_number() ; i++) { - md = get_mididev_info_unit(i); - if (MIDICONFED(md)) - seq_closemidi(scp, md, scp->fflags, MIDIDEV_MODE, p); - } + TAILQ_FOREACH(md, &scp->midi_open, md_linkseq) + lookup_mididev(scp, md->unit, LOOKUP_CLOSE, NULL); + mtx_unlock(&sd->flagqueue_mtx); /* Stop playing and unmark this device busy. */ - sd->flags &= ~(SEQ_F_BUSY | SEQ_F_READING | SEQ_F_WRITING); + mtx_lock(&sd->flagqueue_mtx); + sd->flags &= ~(SEQ_F_BUSY | SEQ_F_READING | SEQ_F_WRITING | SEQ_F_INSYNC); + mtx_unlock(&sd->flagqueue_mtx); - splx(s); + MIDI_PICKUP_GIANT(); DEB(printf("seq%d: closed.\n", unit)); @@ -354,9 +382,12 @@ seq_close(dev_t i_dev, int flags, int mode, struct proc *p) int seq_read(dev_t i_dev, struct uio *buf, int flag) { - int unit, ret, s, len; + int unit, ret, len; sc_p scp; seqdev_info *sd; +#if defined(MIDI_OUTOFGIANT) + char *buf2; /* XXX Until uiomove(9) becomes MP-safe. */ +#endif /* MIDI_OUTOFGIANT */ unit = MIDIUNIT(i_dev); @@ -378,23 +409,49 @@ seq_read(dev_t i_dev, struct uio *buf, int flag) return (EIO); } - s = splmidi(); +#if defined(MIDI_OUTOFGIANT) + buf2 = malloc(buf->uio_resid, M_DEVBUF, M_WAITOK); + if (buf2 == NULL) + return (ENOMEM); +#endif /* MIDI_OUTOFGIANT */ + + MIDI_DROP_GIANT_NOSWITCH(); + + mtx_lock(&sd->flagqueue_mtx); /* Begin recording. */ - sd->callback(sd, SEQ_CB_START | SEQ_CB_RD); + if ((sd->flags & SEQ_F_READING) == 0) + sd->callback(sd, SEQ_CB_START | SEQ_CB_RD); + + len = 0; /* Have we got the data to read? */ if ((sd->flags & SEQ_F_NBIO) != 0 && sd->midi_dbuf_in.rl == 0) ret = EAGAIN; else { +#if defined(MIDI_OUTOFGIANT) len = buf->uio_resid; - ret = midibuf_uioread(&sd->midi_dbuf_in, buf, len); + if ((sd->flags & SEQ_F_NBIO) != 0 && len > sd->midi_dbuf_in.rl) + len = sd->midi_dbuf_in.rl; + ret = midibuf_seqread(&sd->midi_dbuf_in, buf2, len, &sd->flagqueue_mtx); +#else + len = buf->uio_resid; + ret = midibuf_uioread(&sd->midi_dbuf_in, buf, len, &sd->flagqueue_mtx); +#endif /* MIDI_OUTOFGIANT */ if (ret < 0) ret = -ret; else ret = 0; } - splx(s); + mtx_unlock(&sd->flagqueue_mtx); + + MIDI_PICKUP_GIANT(); + +#if defined(MIDI_OUTOFGIANT) + if (ret == 0) + uiomove((caddr_t)buf2, len, buf); + free(buf2, M_DEVBUF); +#endif /* MIDI_OUTOFGIANT */ return (ret); } @@ -403,7 +460,7 @@ int seq_write(dev_t i_dev, struct uio *buf, int flag) { u_char event[EV_SZ], ev_code; - int unit, count, countorg, midiunit, ev_size, p, ret, s; + int unit, count, countorg, midiunit, ev_size, p, ret; sc_p scp; seqdev_info *sd; mididev_info *md; @@ -432,15 +489,18 @@ seq_write(dev_t i_dev, struct uio *buf, int flag) countorg = buf->uio_resid; count = countorg; - s = splmidi(); - /* Begin playing. */ - sd->callback(sd, SEQ_CB_START | SEQ_CB_WR); - splx(s); + MIDI_DROP_GIANT_NOSWITCH(); /* Pick up an event. */ while (count >= 4) { +#if defined(MIDI_OUTOFGIANT) + mtx_lock(&Giant); +#endif /* MIDI_OUTOFGIANT */ if (uiomove((caddr_t)event, 4, buf)) printf("seq_write: user memory mangled?\n"); +#if defined(MIDI_OUTOFGIANT) + mtx_unlock(&Giant); +#endif /* MIDI_OUTOFGIANT */ ev_code = event[0]; /* Have a look at the event code. */ @@ -448,22 +508,18 @@ seq_write(dev_t i_dev, struct uio *buf, int flag) /* A long event, these are the patches/samples for a synthesizer. */ midiunit = *(u_short *)&event[2]; - if (midiunit < 0 || midiunit >= mididev_info_number()) - return (ENXIO); - md = get_mididev_info_unit(midiunit); - if (!MIDICONFED(md)) - return (ENXIO); - s = splmidi(); - if ((md->flags & MIDI_F_BUSY) == 0 - && seq_openmidi(scp, md, scp->fflags, MIDIDEV_MODE, curproc) != 0) { - splx(s); - return (ENXIO); + mtx_lock(&sd->flagqueue_mtx); + ret = lookup_mididev(scp, midiunit, LOOKUP_OPEN, &md); + mtx_unlock(&sd->flagqueue_mtx); + if (ret != 0) { + MIDI_PARTIAL_PICKUP_GIANT(); + return (ret); } DEB(printf("seq_write: loading a patch to the unit %d.\n", midiunit)); ret = md->synth.loadpatch(md, *(short *)&event[0], buf, p + 4, count, 0); - splx(s); + MIDI_PARTIAL_PICKUP_GIANT(); return (ret); } @@ -472,6 +528,7 @@ seq_write(dev_t i_dev, struct uio *buf, int flag) /* Some sort of an extended event. The size is eight bytes. */ #if notyet if (scp->seq_mode == SEQ_2 && ev_code == SEQ_EXTENDED) { + MIDI_PARTIAL_PICKUP_GIANT(); printf("seq%d: invalid level two event %x.\n", unit, ev_code); return (EINVAL); } @@ -480,19 +537,28 @@ seq_write(dev_t i_dev, struct uio *buf, int flag) if (count < ev_size) { /* No more data. Start playing now. */ - s = splmidi(); - sd->callback(sd, SEQ_CB_START | SEQ_CB_WR); - splx(s); + mtx_lock(&sd->flagqueue_mtx); + if ((sd->flags & SEQ_F_WRITING) == 0) + sd->callback(sd, SEQ_CB_START | SEQ_CB_WR); + mtx_unlock(&sd->flagqueue_mtx); + MIDI_PARTIAL_PICKUP_GIANT(); return (0); } +#if defined(MIDI_OUTOFGIANT) + mtx_lock(&Giant); +#endif /* MIDI_OUTOFGIANT */ if (uiomove((caddr_t)&event[4], 4, buf)) printf("seq_write: user memory mangled?\n"); +#if defined(MIDI_OUTOFGIANT) + mtx_unlock(&Giant); +#endif /* MIDI_OUTOFGIANT */ } else { /* Not an extended event. The size is four bytes. */ #if notyet if (scp->seq_mode == SEQ_2) { + MIDI_PARTIAL_PICKUP_GIANT(); printf("seq%d: four byte event in level two mode.\n", unit); return (EINVAL); } @@ -502,40 +568,47 @@ seq_write(dev_t i_dev, struct uio *buf, int flag) if (ev_code == SEQ_MIDIPUTC) { /* An event passed to the midi device itself. */ midiunit = event[2]; - if (midiunit < 0 || midiunit >= mididev_info_number()) - return (ENXIO); - md = get_mididev_info_unit(midiunit); - if (!MIDICONFED(md)) - return (ENXIO); - if ((md->flags & MIDI_F_BUSY) == 0 - && (ret = seq_openmidi(scp, md, scp->fflags, MIDIDEV_MODE, curproc)) != 0) { - seq_reset(scp); + mtx_lock(&sd->flagqueue_mtx); + ret = lookup_mididev(scp, midiunit, LOOKUP_OPEN, &md); + mtx_unlock(&sd->flagqueue_mtx); + if (ret != 0) { + MIDI_PARTIAL_PICKUP_GIANT(); return (ret); } } /*DEB(printf("seq_write: queueing event %d.\n", event[0]));*/ /* Now we queue the event. */ + mtx_lock(&sd->flagqueue_mtx); switch (seq_queue(scp, event)) { case EAGAIN: - s = splmidi(); /* The queue is full. Start playing now. */ - sd->callback(sd, SEQ_CB_START | SEQ_CB_WR); - splx(s); + if ((sd->flags & SEQ_F_WRITING) == 0) + sd->callback(sd, SEQ_CB_START | SEQ_CB_WR); + mtx_unlock(&sd->flagqueue_mtx); + MIDI_PARTIAL_PICKUP_GIANT(); return (0); case EINTR: + mtx_unlock(&sd->flagqueue_mtx); + MIDI_PARTIAL_PICKUP_GIANT(); return (EINTR); case ERESTART: + mtx_unlock(&sd->flagqueue_mtx); + MIDI_PARTIAL_PICKUP_GIANT(); return (ERESTART); } + mtx_unlock(&sd->flagqueue_mtx); p += ev_size; count -= ev_size; } /* We have written every single data. Start playing now. */ - s = splmidi(); - sd->callback(sd, SEQ_CB_START | SEQ_CB_WR); - splx(s); + mtx_lock(&sd->flagqueue_mtx); + if ((sd->flags & SEQ_F_WRITING) == 0) + sd->callback(sd, SEQ_CB_START | SEQ_CB_WR); + mtx_unlock(&sd->flagqueue_mtx); + + MIDI_PICKUP_GIANT(); return (0); } @@ -543,7 +616,7 @@ seq_write(dev_t i_dev, struct uio *buf, int flag) int seq_ioctl(dev_t i_dev, u_long cmd, caddr_t arg, int mode, struct proc *p) { - int unit, midiunit, ret, tmp, s, arg2; + int unit, midiunit, ret, tmp, arg2; sc_p scp; seqdev_info *sd; mididev_info *md; @@ -569,6 +642,8 @@ seq_ioctl(dev_t i_dev, u_long cmd, caddr_t arg, int mode, struct proc *p) } scp = sd->softc; + MIDI_DROP_GIANT_NOSWITCH(); + ret = 0; switch (cmd) { @@ -582,10 +657,14 @@ seq_ioctl(dev_t i_dev, u_long cmd, caddr_t arg, int mode, struct proc *p) case AIOSSIZE: /* set the current blocksize */ sndsize = (struct snd_size *)arg; + mtx_lock(&sd->flagqueue_mtx); if (sndsize->play_size <= sd->midi_dbuf_out.unit_size && sndsize->rec_size <= sd->midi_dbuf_in.unit_size) { - sd->flags &= ~MIDI_F_HAS_SIZE; sd->midi_dbuf_out.blocksize = sd->midi_dbuf_out.unit_size; sd->midi_dbuf_in.blocksize = sd->midi_dbuf_in.unit_size; + sndsize->play_size = sd->midi_dbuf_out.blocksize; + sndsize->rec_size = sd->midi_dbuf_in.blocksize; + sd->flags &= ~MIDI_F_HAS_SIZE; + mtx_unlock(&sd->flagqueue_mtx); } else { if (sndsize->play_size > sd->midi_dbuf_out.bufsize / 4) @@ -599,53 +678,59 @@ seq_ioctl(dev_t i_dev, u_long cmd, caddr_t arg, int mode, struct proc *p) sd->midi_dbuf_in.blocksize = ((sndsize->rec_size + sd->midi_dbuf_in.unit_size - 1) / sd->midi_dbuf_in.unit_size) * sd->midi_dbuf_in.unit_size; + sndsize->play_size = sd->midi_dbuf_out.blocksize; + sndsize->rec_size = sd->midi_dbuf_in.blocksize; sd->flags |= MIDI_F_HAS_SIZE; - } - /* FALLTHROUGH */ + mtx_unlock(&sd->flagqueue_mtx); + } + + ret = 0; + break; + case AIOGSIZE: /* get the current blocksize */ sndsize = (struct snd_size *)arg; + mtx_lock(&sd->flagqueue_mtx); sndsize->play_size = sd->midi_dbuf_out.blocksize; sndsize->rec_size = sd->midi_dbuf_in.blocksize; + mtx_unlock(&sd->flagqueue_mtx); ret = 0; break; case AIOSTOP: if (*(int *)arg == AIOSYNC_PLAY) { - s = splmidi(); /* Stop writing. */ + mtx_lock(&sd->flagqueue_mtx); sd->callback(sd, SEQ_CB_ABORT | SEQ_CB_WR); + mtx_unlock(&sd->flagqueue_mtx); /* Pass the ioctl to the midi devices. */ - for (midiunit = 0 ; midiunit < mididev_info_number() ; midiunit++) { - md = get_mididev_info_unit(midiunit); - if (MIDICONFED(md) && scp->midi_open[midiunit] && (md->flags & MIDI_F_WRITING) != 0) { + TAILQ_FOREACH(md, &scp->midi_open, md_linkseq) { + if ((md->flags & MIDI_F_WRITING) != 0) { arg2 = *(int *)arg; - midi_ioctl(MIDIMKDEV(major(i_dev), midiunit, SND_DEV_MIDIN), cmd, (caddr_t)&arg2, mode, p); + midi_ioctl(MIDIMKDEV(major(i_dev), md->unit, SND_DEV_MIDIN), cmd, (caddr_t)&arg2, mode, p); } } *(int *)arg = sd->midi_dbuf_out.rl; - splx(s); } else if (*(int *)arg == AIOSYNC_CAPTURE) { - s = splmidi(); /* Stop reading. */ + mtx_lock(&sd->flagqueue_mtx); sd->callback(sd, SEQ_CB_ABORT | SEQ_CB_RD); + mtx_unlock(&sd->flagqueue_mtx); /* Pass the ioctl to the midi devices. */ - for (midiunit = 0 ; midiunit < mididev_info_number() ; midiunit++) { - md = get_mididev_info_unit(midiunit); - if (MIDICONFED(md) && scp->midi_open[midiunit] && (md->flags & MIDI_F_WRITING) != 0) { + TAILQ_FOREACH(md, &scp->midi_open, md_linkseq) { + if ((md->flags & MIDI_F_WRITING) != 0) { arg2 = *(int *)arg; - midi_ioctl(MIDIMKDEV(major(i_dev), midiunit, SND_DEV_MIDIN), cmd, (caddr_t)&arg2, mode, p); + midi_ioctl(MIDIMKDEV(major(i_dev), md->unit, SND_DEV_MIDIN), cmd, (caddr_t)&arg2, mode, p); } } *(int *)arg = sd->midi_dbuf_in.rl; - splx(s); } ret = 0; @@ -692,7 +777,9 @@ seq_ioctl(dev_t i_dev, u_long cmd, caddr_t arg, int mode, struct proc *p) ret = 0; break; case SNDCTL_SEQ_PANIC: + mtx_lock(&scp->devinfo->flagqueue_mtx); seq_panic(scp); + mtx_unlock(&scp->devinfo->flagqueue_mtx); ret = 0; break; case SNDCTL_SEQ_SYNC: @@ -700,24 +787,21 @@ seq_ioctl(dev_t i_dev, u_long cmd, caddr_t arg, int mode, struct proc *p) ret = 0; break; } + mtx_lock(&scp->devinfo->flagqueue_mtx); ret = seq_sync(scp); + mtx_unlock(&scp->devinfo->flagqueue_mtx); break; case SNDCTL_SEQ_RESET: + mtx_lock(&scp->devinfo->flagqueue_mtx); seq_reset(scp); + mtx_unlock(&scp->devinfo->flagqueue_mtx); ret = 0; break; case SNDCTL_SEQ_TESTMIDI: midiunit = *(int *)arg; - if (midiunit >= mididev_info_number()) { - ret = ENXIO; - break; - } - md = get_mididev_info_unit(midiunit); - if (MIDICONFED(md) && !scp->midi_open[midiunit]) { - ret = seq_openmidi(scp, md, scp->fflags, MIDIDEV_MODE, curproc); - break; - } - ret = 0; + mtx_lock(&sd->flagqueue_mtx); + ret = lookup_mididev(scp, midiunit, LOOKUP_OPEN, &md); + mtx_unlock(&sd->flagqueue_mtx); break; case SNDCTL_SEQ_GETINCOUNT: if (mode == O_WRONLY) @@ -749,21 +833,11 @@ seq_ioctl(dev_t i_dev, u_long cmd, caddr_t arg, int mode, struct proc *p) break; case SNDCTL_SEQ_RESETSAMPLES: midiunit = *(int *)arg; - if (midiunit >= mididev_info_number()) { - ret = ENXIO; + mtx_lock(&sd->flagqueue_mtx); + ret = lookup_mididev(scp, midiunit, LOOKUP_OPEN, &md); + mtx_unlock(&sd->flagqueue_mtx); + if (ret != 0) break; - } - if (!scp->midi_open[midiunit]) { - md = get_mididev_info_unit(midiunit); - if (MIDICONFED(md)) { - ret = seq_openmidi(scp, md, scp->fflags, MIDIDEV_MODE, curproc); - if (ret != 0) - break; - } else { - ret = EBUSY; - break; - } - } ret = midi_ioctl(MIDIMKDEV(major(i_dev), midiunit, SND_DEV_MIDIN), cmd, arg, mode, p); break; case SNDCTL_SEQ_NRSYNTHS: @@ -776,97 +850,66 @@ seq_ioctl(dev_t i_dev, u_long cmd, caddr_t arg, int mode, struct proc *p) break; case SNDCTL_SYNTH_MEMAVL: midiunit = *(int *)arg; - if (midiunit >= mididev_info_number()) { - ret = ENXIO; + mtx_lock(&sd->flagqueue_mtx); + ret = lookup_mididev(scp, midiunit, LOOKUP_OPEN, &md); + mtx_unlock(&sd->flagqueue_mtx); + if (ret != 0) break; - } - if (!scp->midi_open[midiunit]) { - md = get_mididev_info_unit(midiunit); - if (MIDICONFED(md)) { - ret = seq_openmidi(scp, md, scp->fflags, MIDIDEV_MODE, curproc); - if (ret != 0) - break; - } else { - ret = EBUSY; - break; - } - } ret = midi_ioctl(MIDIMKDEV(major(i_dev), midiunit, SND_DEV_MIDIN), cmd, arg, mode, p); break; case SNDCTL_FM_4OP_ENABLE: midiunit = *(int *)arg; - if (midiunit >= mididev_info_number()) { - ret = ENXIO; + mtx_lock(&sd->flagqueue_mtx); + ret = lookup_mididev(scp, midiunit, LOOKUP_OPEN, &md); + mtx_unlock(&sd->flagqueue_mtx); + if (ret != 0) break; - } - if (!scp->midi_open[midiunit]) { - md = get_mididev_info_unit(midiunit); - if (MIDICONFED(md)) { - ret = seq_openmidi(scp, md, scp->fflags, MIDIDEV_MODE, curproc); - if (ret != 0) - break; - } else { - ret = EBUSY; - break; - } - } ret = midi_ioctl(MIDIMKDEV(major(i_dev), midiunit, SND_DEV_MIDIN), cmd, arg, mode, p); break; case SNDCTL_SYNTH_INFO: synthinfo = (struct synth_info *)arg; midiunit = synthinfo->device; - if (midiunit >= mididev_info_number()) { - ret = ENXIO; + mtx_lock(&sd->flagqueue_mtx); + ret = lookup_mididev(scp, midiunit, LOOKUP_OPEN, &md); + mtx_unlock(&sd->flagqueue_mtx); + if (ret != 0) break; - } ret = midi_ioctl(MIDIMKDEV(major(i_dev), midiunit, SND_DEV_MIDIN), cmd, arg, mode, p); break; case SNDCTL_SEQ_OUTOFBAND: event = (struct seq_event_rec *)arg; - s = splmidi(); + mtx_lock(&sd->flagqueue_mtx); ret = seq_playevent(scp, event->arr); - splx(s); + mtx_unlock(&sd->flagqueue_mtx); break; case SNDCTL_MIDI_INFO: midiinfo = (struct midi_info *)arg; midiunit = midiinfo->device; - if (midiunit >= mididev_info_number()) { - ret = ENXIO; + mtx_lock(&sd->flagqueue_mtx); + ret = lookup_mididev(scp, midiunit, LOOKUP_OPEN, &md); + mtx_unlock(&sd->flagqueue_mtx); + if (ret != 0) break; - } ret = midi_ioctl(MIDIMKDEV(major(i_dev), midiunit, SND_DEV_MIDIN), cmd, arg, mode, p); break; case SNDCTL_PMGR_IFACE: patinfo = (struct patmgr_info *)arg; midiunit = patinfo->device; - if (midiunit >= mididev_info_number()) { - ret = ENXIO; + mtx_lock(&sd->flagqueue_mtx); + ret = lookup_mididev(scp, midiunit, LOOKUP_OPEN, &md); + mtx_unlock(&sd->flagqueue_mtx); + if (ret != 0) break; - } - if (!scp->midi_open[midiunit]) { - ret = EBUSY; - break; - } ret = midi_ioctl(MIDIMKDEV(major(i_dev), midiunit, SND_DEV_MIDIN), cmd, arg, mode, p); break; case SNDCTL_PMGR_ACCESS: patinfo = (struct patmgr_info *)arg; midiunit = patinfo->device; - if (midiunit >= mididev_info_number()) { - ret = ENXIO; + mtx_lock(&sd->flagqueue_mtx); + ret = lookup_mididev(scp, midiunit, LOOKUP_OPEN, &md); + mtx_unlock(&sd->flagqueue_mtx); + if (ret != 0) break; - } - if (!scp->midi_open[midiunit]) { - md = get_mididev_info_unit(midiunit); - if (MIDICONFED(md)) { - ret = seq_openmidi(scp, md, scp->fflags, MIDIDEV_MODE, curproc); - if (ret != 0) - break; - } else { - ret = EBUSY; - break; - } - } ret = midi_ioctl(MIDIMKDEV(major(i_dev), midiunit, SND_DEV_MIDIN), cmd, arg, mode, p); break; case SNDCTL_SEQ_THRESHOLD: @@ -888,28 +931,24 @@ seq_ioctl(dev_t i_dev, u_long cmd, caddr_t arg, int mode, struct proc *p) ret = EIO; break; } - if (!scp->midi_open[0]) { - md = get_mididev_info_unit(0); - if (MIDICONFED(md)) { - ret = seq_openmidi(scp, md, scp->fflags, MIDIDEV_MODE, curproc); - if (ret != 0) - break; - } else { - ret = EBUSY; - break; - } - } + mtx_lock(&sd->flagqueue_mtx); + ret = lookup_mididev(scp, 0, LOOKUP_OPEN, &md); + mtx_unlock(&sd->flagqueue_mtx); + if (ret != 0) + break; ret = midi_ioctl(MIDIMKDEV(major(i_dev), 0, SND_DEV_MIDIN), cmd, arg, mode, p); break; } + MIDI_PICKUP_GIANT(); + return (ret); } int seq_poll(dev_t i_dev, int events, struct proc *p) { - int unit, ret, s, lim; + int unit, ret, lim; sc_p scp; seqdev_info *sd; @@ -928,8 +967,11 @@ seq_poll(dev_t i_dev, int events, struct proc *p) } scp = sd->softc; + MIDI_DROP_GIANT_NOSWITCH(); + + mtx_lock(&sd->flagqueue_mtx); + ret = 0; - s = splmidi(); /* Look up the apropriate queue and select it. */ if ((events & (POLLOUT | POLLWRNORM)) != 0) { @@ -964,7 +1006,10 @@ seq_poll(dev_t i_dev, int events, struct proc *p) /* We can write now. */ ret |= events & (POLLIN | POLLRDNORM); } - splx(s); + + mtx_unlock(&sd->flagqueue_mtx); + + MIDI_PICKUP_GIANT(); return (ret); } @@ -978,12 +1023,20 @@ seq_intr(void *p, mididev_info *md) sd = (seqdev_info *)p; scp = sd->softc; + MIDI_DROP_GIANT_NOSWITCH(); + + mtx_lock(&sd->flagqueue_mtx); + /* Restart playing if we have the data to output. */ if (scp->queueout_pending) sd->callback(sd, SEQ_CB_START | SEQ_CB_WR); /* Check the midi device if we are reading. */ if ((sd->flags & SEQ_F_READING) != 0) seq_midiinput(scp, md); + + mtx_unlock(&sd->flagqueue_mtx); + + MIDI_PICKUP_GIANT(); } static int @@ -1001,6 +1054,8 @@ seq_callback(seqdev_info *sd, int reason) scp = sd->softc; unit = sd->unit; + mtx_assert(&sd->flagqueue_mtx, MA_OWNED); + switch (reason & SEQ_CB_REASON_MASK) { case SEQ_CB_START: if ((reason & SEQ_CB_RD) != 0 && (sd->flags & SEQ_F_READING) == 0) @@ -1013,24 +1068,21 @@ seq_callback(seqdev_info *sd, int reason) case SEQ_CB_STOP: case SEQ_CB_ABORT: if ((reason & SEQ_CB_RD) != 0 && (sd->flags & SEQ_F_READING) != 0) { - /* Stop the timer. */ - scp->seq_time = seq_gettime(); - scp->prev_input_time = 0; - /* Stop recording. */ sd->flags &= ~SEQ_F_READING; + scp->seq_time = seq_gettime(); + scp->prev_input_time = 0; } if ((reason & SEQ_CB_WR) != 0 && (sd->flags & SEQ_F_WRITING) != 0) { - /* Stop the timer. */ - seq_stoptimer(scp); - scp->seq_time = seq_gettime(); - scp->prev_event_time = 0; - /* Stop Playing. */ sd->flags &= ~SEQ_F_WRITING; scp->queueout_pending = 0; + scp->seq_time = seq_gettime(); + scp->prev_input_time = 0; + + /* Stop the timer. */ + seq_stoptimer(scp); } - break; } return (0); @@ -1043,49 +1095,52 @@ seq_callback(seqdev_info *sd, int reason) static int seq_queue(sc_p scp, u_char *note) { - int unit, err, s; + int unit, err; seqdev_info *sd; sd = scp->devinfo; unit = sd->unit; + mtx_assert(&sd->flagqueue_mtx, MA_OWNED); + /*DEB(printf("seq%d: queueing.\n", unit));*/ - s = splmidi(); - - /* Start playing if we have some data in the queue. */ - if (sd->midi_dbuf_out.rl >= EV_SZ) - sd->callback(sd, SEQ_CB_START | SEQ_CB_WR); + if ((sd->flags & SEQ_F_INSYNC) != 0) { + cv_wait(&sd->insync_cv, &sd->flagqueue_mtx); + cv_signal(&sd->insync_cv); + } if (sd->midi_dbuf_out.fl < EV_SZ) { /* We have no space. Start playing if not yet. */ - sd->callback(sd, SEQ_CB_START | SEQ_CB_WR); - if ((sd->flags & SEQ_F_NBIO) != 0 && sd->midi_dbuf_out.fl < EV_SZ) { + if ((sd->flags & SEQ_F_WRITING) == 0) + sd->callback(sd, SEQ_CB_START | SEQ_CB_WR); + if ((sd->flags & SEQ_F_NBIO) != 0 && sd->midi_dbuf_out.fl < EV_SZ) /* We would block. */ - splx(s); return (EAGAIN); - } else + else { while (sd->midi_dbuf_out.fl < EV_SZ) { /* We have no space. Good night. */ - err = tsleep(&sd->midi_dbuf_out.tsleep_out, PRIBIO | PCATCH, "seqque", 0); - if (err == EINTR) - sd->callback(sd, SEQ_CB_STOP | SEQ_CB_WR); + err = msleep(&sd->midi_dbuf_out.tsleep_out, &sd->flagqueue_mtx, PRIBIO | PCATCH, "seqque", 0); if (err == EINTR || err == ERESTART) { - splx(s); + if (err == EINTR) + sd->callback(sd, SEQ_CB_STOP | SEQ_CB_WR); return (err); } } + } } /* We now have enough space to write. */ - err = midibuf_seqwrite(&sd->midi_dbuf_out, note, EV_SZ); - - splx(s); + err = midibuf_seqwrite(&sd->midi_dbuf_out, note, EV_SZ, &sd->flagqueue_mtx); if (err < 0) err = -err; - else + else { err = 0; + /* Start playing if we have some data in the queue. */ + if (sd->midi_dbuf_out.rl >= EV_SZ && ((sd->flags & SEQ_F_WRITING) == 0)) + sd->callback(sd, SEQ_CB_START | SEQ_CB_WR); + } return (err); } @@ -1100,26 +1155,21 @@ seq_startplay(sc_p scp) sd = scp->devinfo; unit = sd->unit; + mtx_assert(&sd->flagqueue_mtx, MA_OWNED); + /* Dequeue the events to play. */ while (sd->midi_dbuf_out.rl >= EV_SZ) { - /* We are playing now. */ - sd->flags |= SEQ_F_WRITING; - - /* We only copy the event, not dequeue. */ - midibuf_seqcopy(&sd->midi_dbuf_out, event, EV_SZ); + midibuf_seqread(&sd->midi_dbuf_out, event, EV_SZ, &sd->flagqueue_mtx); switch (seq_playevent(scp, event)) { case TIMERARMED: - /* Dequeue the event. */ - midibuf_seqread(&sd->midi_dbuf_out, event, EV_SZ); - /* FALLTHRU */ + return; case QUEUEFULL: - /* We cannot play further. */ + /* We cannot play any further. */ + midibuf_sequnread(&sd->midi_dbuf_out, event, EV_SZ, &sd->flagqueue_mtx); return; case MORE: - /* Dequeue the event. */ - midibuf_seqread(&sd->midi_dbuf_out, event, EV_SZ); break; } } @@ -1139,26 +1189,31 @@ seq_playevent(sc_p scp, u_char *event) sd = scp->devinfo; unit = sd->unit; - md = get_mididev_info_unit(0); - if (!MIDICONFED(md)) + mtx_assert(&sd->flagqueue_mtx, MA_OWNED); + + ret = lookup_mididev(scp, 0, LOOKUP_OPEN, &md); + if (ret != 0) return (MORE); switch(event[0]) { case SEQ_NOTEOFF: - if ((md->flags & MIDI_F_BUSY) != 0 || seq_openmidi(scp, md, scp->fflags, MIDIDEV_MODE, curproc) == 0) - if (md->synth.killnote(md, event[1], 255, event[3]) == EAGAIN) { - ret = QUEUEFULL; - break; - } + mtx_unlock(&sd->flagqueue_mtx); + if (md->synth.killnote(md, event[1], 255, event[3]) == EAGAIN) { + mtx_lock(&sd->flagqueue_mtx); + ret = QUEUEFULL; + break; + } + mtx_lock(&sd->flagqueue_mtx); ret = MORE; break; case SEQ_NOTEON: - if (((md->flags & MIDI_F_BUSY) != 0 || seq_openmidi(scp, md, scp->fflags, MIDIDEV_MODE, curproc) == 0) - && (event[4] < 128 || event[4] == 255)) - if (md->synth.startnote(md, event[1], event[2], event[3]) == EAGAIN) { - ret = QUEUEFULL; - break; - } + mtx_unlock(&sd->flagqueue_mtx); + if ((event[4] < 128 || event[4] == 255) && md->synth.startnote(md, event[1], event[2], event[3]) == EAGAIN) { + mtx_lock(&sd->flagqueue_mtx); + ret = QUEUEFULL; + break; + } + mtx_lock(&sd->flagqueue_mtx); ret = MORE; break; case SEQ_WAIT: @@ -1169,7 +1224,6 @@ seq_playevent(sc_p scp, u_char *event) if (*delay > 0) { /* Arm the timer. */ sd->flags |= SEQ_F_WRITING; - scp->prev_event_time = *delay; if (seq_requesttimer(scp, *delay)) { ret = TIMERARMED; break; @@ -1178,11 +1232,13 @@ seq_playevent(sc_p scp, u_char *event) ret = MORE; break; case SEQ_PGMCHANGE: - if ((md->flags & MIDI_F_BUSY) != 0 || seq_openmidi(scp, md, scp->fflags, MIDIDEV_MODE, curproc) == 0) - if (md->synth.setinstr(md, event[1], event[2]) == EAGAIN) { - ret = QUEUEFULL; - break; - } + mtx_unlock(&sd->flagqueue_mtx); + if (md->synth.setinstr(md, event[1], event[2]) == EAGAIN) { + mtx_lock(&sd->flagqueue_mtx); + ret = QUEUEFULL; + break; + } + mtx_lock(&sd->flagqueue_mtx); ret = MORE; break; case SEQ_SYNCTIMER: @@ -1195,16 +1251,19 @@ seq_playevent(sc_p scp, u_char *event) break; case SEQ_MIDIPUTC: /* Pass through to the midi device. */ - if (event[2] < mididev_info_number()) { - md = get_mididev_info_unit(event[2]); - if (MIDICONFED(md) && ((md->flags & MIDI_F_BUSY) != 0 || seq_openmidi(scp, md, scp->fflags, MIDIDEV_MODE, curproc) == 0)) { - if (md->synth.writeraw(md, &event[1], sizeof(event[1]), 1) == EAGAIN) { - /* The queue was full. Try again later. */ - ret = QUEUEFULL; - break; - } - } + ret = lookup_mididev(scp, event[2], LOOKUP_OPEN, &md); + if (ret != 0) { + ret = MORE; + break; } + mtx_unlock(&sd->flagqueue_mtx); + if (md->synth.writeraw(md, &event[1], sizeof(event[1]), 1) == EAGAIN) { + mtx_lock(&sd->flagqueue_mtx); + /* The queue was full. Try again later. */ + ret = QUEUEFULL; + break; + } + mtx_lock(&sd->flagqueue_mtx); ret = MORE; break; case SEQ_ECHO: @@ -1216,13 +1275,18 @@ seq_playevent(sc_p scp, u_char *event) ret = MORE; break; case SEQ_PRIVATE: - if (event[1] < mididev_info_number()) { - md = get_mididev_info_unit(event[1]); - if (MIDICONFED(md) && md->synth.hwcontrol(md, event) == EAGAIN) { - ret = QUEUEFULL; - break; - } + ret = lookup_mididev(scp, event[1], LOOKUP_OPEN, &md); + if (ret != 0) { + ret = MORE; + break; } + mtx_unlock(&sd->flagqueue_mtx); + if (md->synth.hwcontrol(md, event) == EAGAIN) { + mtx_lock(&sd->flagqueue_mtx); + ret = QUEUEFULL; + break; + } + mtx_lock(&sd->flagqueue_mtx); ret = MORE; break; case SEQ_EXTENDED: @@ -1282,15 +1346,20 @@ seq_requesttimer(sc_p scp, int delay) /*DEB(printf("seq%d: requested timer at delay of %d.\n", unit, delay));*/ + mtx_assert(&scp->devinfo->flagqueue_mtx, MA_OWNED); + cur_time = seq_gettime(); + scp->prev_event_time = delay; if (delay < 0) /* Request a new timer. */ delay = -delay; else { rel_base = cur_time - scp->seq_time; - if (delay <= rel_base) + if (delay <= rel_base) { + seq_stoptimer(scp); return 0; + } delay -= rel_base; } @@ -1309,8 +1378,9 @@ seq_requesttimer(sc_p scp, int delay) } #endif /* notdef */ - scp->timeout_ch = timeout(seq_timer, (void *)scp, delay); + callout_reset(&scp->timeout_ch, delay, seq_timer, (void *)scp); scp->timer_running = 1; + return 1; } @@ -1319,8 +1389,10 @@ seq_stoptimer(sc_p scp) { /*DEB(printf("seq%d: stopping timer.\n", unit));*/ + mtx_assert(&scp->devinfo->flagqueue_mtx, MA_OWNED); + if (scp->timer_running) { - untimeout(seq_timer, (void *)scp, scp->timeout_ch); + callout_stop(&scp->timeout_ch); scp->timer_running = 0; } } @@ -1333,14 +1405,17 @@ seq_midiinput(sc_p scp, mididev_info *md) u_char event[4]; seqdev_info *sd; + mtx_assert(&scp->devinfo->flagqueue_mtx, MA_OWNED); + sd = scp->devinfo; unit = sd->unit; /* Can this midi device interrupt for input? */ midiunit = md->unit; - if (scp->midi_open[midiunit] - && (md->flags & MIDI_F_READING) != 0 - && md->intrarg == sd) + if (lookup_mididev(scp, midiunit, LOOKUP_EXIST, NULL) != 0) + return; + + if ((md->flags & MIDI_F_READING) != 0 && md->intrarg == sd) { /* Read the input data. */ while (md->synth.readraw(md, &event[1], sizeof(event[1]), 1) == 0) { tstamp = seq_gettime() - scp->seq_time; @@ -1355,6 +1430,7 @@ seq_midiinput(sc_p scp, mididev_info *md) event[3] = 0; seq_copytoinput(scp, event, sizeof(event)); } + } } static int @@ -1364,6 +1440,8 @@ seq_copytoinput(sc_p scp, u_char *event, int len) sd = scp->devinfo; + mtx_assert(&sd->flagqueue_mtx, MA_OWNED); + if (midibuf_input_intr(&sd->midi_dbuf_in, event, len) == -EAGAIN) return (EAGAIN); @@ -1380,42 +1458,67 @@ seq_extended(sc_p scp, u_char *event) sd = scp->devinfo; unit = sd->unit; - if (event[2] >= mididev_info_number()) - return (MORE); - md = get_mididev_info_unit(event[2]); - if (!MIDICONFED(md) && (md->flags & MIDI_F_BUSY) == 0 && seq_openmidi(scp, md, scp->fflags, MIDIDEV_MODE, curproc) != 0) + mtx_assert(&sd->flagqueue_mtx, MA_OWNED); + + if (lookup_mididev(scp, event[2], LOOKUP_OPEN, &md) != 0) return (MORE); switch (event[1]) { case SEQ_NOTEOFF: - if (md->synth.killnote(md, event[3], event[4], event[5]) == EAGAIN) + mtx_unlock(&sd->flagqueue_mtx); + if (md->synth.killnote(md, event[3], event[4], event[5]) == EAGAIN) { + mtx_lock(&sd->flagqueue_mtx); return (QUEUEFULL); + } + mtx_lock(&sd->flagqueue_mtx); break; case SEQ_NOTEON: - if (event[4] < 128 || event[4] == 255) - if (md->synth.startnote(md, event[3], event[4], event[5]) == EAGAIN) - return (QUEUEFULL); + mtx_unlock(&sd->flagqueue_mtx); + if ((event[4] < 128 || event[4] == 255) && md->synth.startnote(md, event[3], event[4], event[5]) == EAGAIN) { + mtx_lock(&sd->flagqueue_mtx); + return (QUEUEFULL); + } + mtx_lock(&sd->flagqueue_mtx); break; case SEQ_PGMCHANGE: - if (md->synth.setinstr(md, event[3], event[4]) == EAGAIN) + mtx_unlock(&sd->flagqueue_mtx); + if (md->synth.setinstr(md, event[3], event[4]) == EAGAIN) { + mtx_lock(&sd->flagqueue_mtx); return (QUEUEFULL); + } + mtx_lock(&sd->flagqueue_mtx); break; case SEQ_AFTERTOUCH: - if (md->synth.aftertouch(md, event[3], event[4]) == EAGAIN) + mtx_unlock(&sd->flagqueue_mtx); + if (md->synth.aftertouch(md, event[3], event[4]) == EAGAIN) { + mtx_lock(&sd->flagqueue_mtx); return (QUEUEFULL); + } + mtx_lock(&sd->flagqueue_mtx); break; case SEQ_BALANCE: - if (md->synth.panning(md, event[3], (char)event[4]) == EAGAIN) + mtx_unlock(&sd->flagqueue_mtx); + if (md->synth.panning(md, event[3], (char)event[4]) == EAGAIN) { + mtx_lock(&sd->flagqueue_mtx); return (QUEUEFULL); + } + mtx_lock(&sd->flagqueue_mtx); break; case SEQ_CONTROLLER: - if (md->synth.controller(md, event[3], event[4], *(short *)&event[5]) == EAGAIN) + mtx_unlock(&sd->flagqueue_mtx); + if (md->synth.controller(md, event[3], event[4], *(short *)&event[5]) == EAGAIN) { + mtx_lock(&sd->flagqueue_mtx); return (QUEUEFULL); + } + mtx_lock(&sd->flagqueue_mtx); break; case SEQ_VOLMODE: - if (md->synth.volumemethod != NULL) - if (md->synth.volumemethod(md, event[3]) == EAGAIN) - return (QUEUEFULL); + mtx_unlock(&sd->flagqueue_mtx); + if (md->synth.volumemethod != NULL && md->synth.volumemethod(md, event[3]) == EAGAIN) { + mtx_lock(&sd->flagqueue_mtx); + return (QUEUEFULL); + } + mtx_lock(&sd->flagqueue_mtx); break; } @@ -1439,17 +1542,14 @@ seq_chnvoice(sc_p scp, u_char *event) sd = scp->devinfo; - if (dev >= mididev_info_number()) - return (MORE); - md = get_mididev_info_unit(dev); - if (!MIDICONFED(md) && (md->flags & MIDI_F_BUSY) == 0 && seq_openmidi(scp, md, scp->fflags, MIDIDEV_MODE, curproc) != 0) + mtx_assert(&sd->flagqueue_mtx, MA_OWNED); + + if (lookup_mididev(scp, dev, LOOKUP_OPEN, &md) != 0) return (MORE); #if notyet - if (scp->seq_mode == SEQ_2) { - if (md->synth.allocvoice) - voice = seq_allocvoice(md, chn, note); - } + if (scp->seq_mode == SEQ_2 && md->synth.allocvoice != NULL) + voice = seq_allocvoice(scp, md, chn, note); #endif /* notyet */ switch (cmd) { case MIDI_NOTEON: @@ -1457,38 +1557,60 @@ seq_chnvoice(sc_p scp, u_char *event) #if notyet if (voice == -1 && scp->seq_mode == SEQ_2 && md->synth.allocvoice) /* This is an internal synthesizer. (FM, GUS, etc) */ - if ((voice = seq_allocvoice(md, chn, note)) == -EAGAIN) + if ((voice = seq_allocvoice(scp, md, chn, note)) == -EAGAIN) return (QUEUEFULL); #endif /* notyet */ if (voice == -1) voice = chn; #if notyet - if (scp->seq_mode == SEQ_2 && dev < mididev_info_number() && chn == 9) { + if (scp->seq_mode == SEQ_2 && chn == 9) { /* This channel is a percussion. The note number is the patch number. */ - if (md->synth.setinstr(md, voice, 128 + note) == EAGAIN) + mtx_unlock(&sd->flagqueue_mtx); + if (md->synth.setinstr(md, voice, 128 + note) == EAGAIN) { + mtx_lock(&sd->flagqueue_mtx); return (QUEUEFULL); + } + mtx_lock(&sd->flagqueue_mtx); + note = 60; /* Middle C. */ } - if (scp->seq_mode == SEQ_2) - if (md->synth.setupvoice(md, voice, chn) == EAGAIN) + if (scp->seq_mode == SEQ_2) { + mtx_unlock(&sd->flagqueue_mtx); + if (md->synth.setupvoice(md, voice, chn) == EAGAIN) { + mtx_lock(&sd->flagqueue_mtx); return (QUEUEFULL); + } + mtx_lock(&sd->flagqueue_mtx); + } #endif /* notyet */ - if (md->synth.startnote(md, voice, note, parm) == EAGAIN) + mtx_unlock(&sd->flagqueue_mtx); + if (md->synth.startnote(md, voice, note, parm) == EAGAIN) { + mtx_lock(&sd->flagqueue_mtx); return (QUEUEFULL); + } + mtx_lock(&sd->flagqueue_mtx); } break; case MIDI_NOTEOFF: if (voice == -1) voice = chn; - if (md->synth.killnote(md, voice, note, parm) == EAGAIN) + mtx_unlock(&sd->flagqueue_mtx); + if (md->synth.killnote(md, voice, note, parm) == EAGAIN) { + mtx_lock(&sd->flagqueue_mtx); return (QUEUEFULL); + } + mtx_lock(&sd->flagqueue_mtx); break; case MIDI_KEY_PRESSURE: if (voice == -1) voice = chn; - if (md->synth.aftertouch(md, voice, parm) == EAGAIN) + mtx_unlock(&sd->flagqueue_mtx); + if (md->synth.aftertouch(md, voice, parm) == EAGAIN) { + mtx_lock(&sd->flagqueue_mtx); return (QUEUEFULL); + } + mtx_lock(&sd->flagqueue_mtx); break; } @@ -1503,25 +1625,38 @@ seq_findvoice(mididev_info *md, int chn, int note) key = (chn << 8) | (note + 1); + mtx_lock(&md->synth.vc_mtx); for (i = 0 ; i < md->synth.alloc.max_voice ; i++) - if (md->synth.alloc.map[i] == key) + if (md->synth.alloc.map[i] == key) { + mtx_unlock(&md->synth.vc_mtx); return (i); + } + mtx_unlock(&md->synth.vc_mtx); return (-1); } static int -seq_allocvoice(mididev_info *md, int chn, int note) +seq_allocvoice(sc_p scp, mididev_info *md, int chn, int note) { int voice; u_short key; + mtx_assert(&scp->devinfo->flagqueue_mtx, MA_OWNED); + key = (chn << 8) | (note + 1); - if ((voice = md->synth.allocvoice(md, chn, note, &md->synth.alloc)) == -EAGAIN) + mtx_unlock(&scp->devinfo->flagqueue_mtx); + if ((voice = md->synth.allocvoice(md, chn, note, &md->synth.alloc)) == -EAGAIN) { + mtx_lock(&scp->devinfo->flagqueue_mtx); return (-EAGAIN); + } + mtx_lock(&scp->devinfo->flagqueue_mtx); + + mtx_lock(&md->synth.vc_mtx); md->synth.alloc.map[voice] = key; md->synth.alloc.alloc_times[voice] = md->synth.alloc.timestamp++; + mtx_unlock(&md->synth.vc_mtx); return (voice); } @@ -1544,77 +1679,113 @@ seq_chncommon(sc_p scp, u_char *event) sd = scp->devinfo; unit = sd->unit; - if (dev >= mididev_info_number()) - return (MORE); - md = get_mididev_info_unit(dev); - if (!MIDICONFED(md) && (md->flags & MIDI_F_BUSY) == 0 && seq_openmidi(scp, md, scp->fflags, MIDIDEV_MODE, curproc) != 0) + mtx_assert(&sd->flagqueue_mtx, MA_OWNED); + + if (lookup_mididev(scp, dev, LOOKUP_OPEN, &md) != 0) return (MORE); switch (cmd) { case MIDI_PGM_CHANGE: #if notyet if (scp->seq_mode == SEQ_2) { + mtx_lock(&md->synth.vc_mtx); md->synth.chn_info[chn].pgm_num = p1; - if (dev < mididev_info_number()) - if (md->synth.setinstr(md, chn, p1) == EAGAIN) - return (QUEUEFULL); - } else + mtx_unlock(&md->synth.vc_mtx); + mtx_unlock(&sd->flagqueue_mtx); + if (md->synth.setinstr(md, chn, p1) == EAGAIN) { + mtx_lock(&sd->flagqueue_mtx); + return (QUEUEFULL); + } + mtx_lock(&sd->flagqueue_mtx); + } else { #endif /* notyet */ /* For Mode 1. */ - if (md->synth.setinstr(md, chn, p1) == EAGAIN) + mtx_unlock(&sd->flagqueue_mtx); + if (md->synth.setinstr(md, chn, p1) == EAGAIN) { + mtx_lock(&sd->flagqueue_mtx); return (QUEUEFULL); + } + mtx_lock(&sd->flagqueue_mtx); +#if notyet + } +#endif /* notyet */ break; case MIDI_CTL_CHANGE: + /* mtx_lock(&md->giant); */ #if notyet if (scp->seq_mode == SEQ_2) { if (chn < 16 && p1 < 128) { + mtx_lock(&md->synth.vc_mtx); md->synth.chn_info[chn].controllers[p1] = w14 & 0x7f; if (p1 < 32) /* We have set the MSB, clear the LSB. */ md->synth.chn_info[chn].controllers[p1 + 32] = 0; - if (dev < mididev_info_number()) { - val = w14 & 0x7f; - if (p1 < 64) { - /* Combine the MSB and the LSB. */ - val = ((md->synth.chn_info[chn].controllers[p1 & ~32] & 0x7f) << 7) - | (md->synth.chn_info[chn].controllers[p1 | 32] & 0x7f); - p1 &= ~32; + val = w14 & 0x7f; + if (p1 < 64) { + /* Combine the MSB and the LSB. */ + val = ((md->synth.chn_info[chn].controllers[p1 & ~32] & 0x7f) << 7) + | (md->synth.chn_info[chn].controllers[p1 | 32] & 0x7f); + p1 &= ~32; + } + /* Handle all of the notes playing on this channel. */ + key = ((int)chn << 8); + for (i = 0 ; i < md->synth.alloc.max_voice ; i++) + if ((md->synth.alloc.map[i] & 0xff00) == key) { + mtx_unlock(&md->synth.vc_mtx); + mtx_unlock(&sd->flagqueue_mtx); + if (md->synth.controller(md, i, p1, val) == EAGAIN) { + mtx_lock(&sd->flagqueue_mtx); + return (QUEUEFULL); + } + mtx_lock(&sd->flagqueue_mtx); + mtx_lock(&md->synth.vc_mtx); } - /* Handle all of the notes playing on this channel. */ - key = ((int)chn << 8); - for (i = 0 ; i < md->synth.alloc.max_voice ; i++) - if ((md->synth.alloc.map[i] & 0xff00) == key) - if (md->synth.controller(md, i, p1, val) == EAGAIN) - return (QUEUEFULL); - } else - if (md->synth.controller(md, chn, p1, w14) == EAGAIN) - return (QUEUEFULL); + mtx_unlock(&md->synth.vc_mtx); } - } else + } else { #endif /* notyet */ /* For Mode 1. */ - if (md->synth.controller(md, chn, p1, w14) == EAGAIN) + mtx_unlock(&sd->flagqueue_mtx); + if (md->synth.controller(md, chn, p1, w14) == EAGAIN) { + mtx_lock(&sd->flagqueue_mtx); return (QUEUEFULL); + } + mtx_lock(&sd->flagqueue_mtx); +#if notyet + } +#endif /* notyet */ break; case MIDI_PITCH_BEND: #if notyet if (scp->seq_mode == SEQ_2) { + mtx_lock(&md->synth.vc_mtx); md->synth.chn_info[chn].bender_value = w14; - if (dev < mididev_info_number()) { - /* Handle all of the notes playing on this channel. */ - key = ((int)chn << 8); - for (i = 0 ; i < md->synth.alloc.max_voice ; i++) - if ((md->synth.alloc.map[i] & 0xff00) == key) - if (md->synth.bender(md, i, w14) == EAGAIN) - return (QUEUEFULL); - } else - if (md->synth.bender(md, chn, w14) == EAGAIN) - return (QUEUEFULL); - } else + /* Handle all of the notes playing on this channel. */ + key = ((int)chn << 8); + for (i = 0 ; i < md->synth.alloc.max_voice ; i++) + if ((md->synth.alloc.map[i] & 0xff00) == key) { + mtx_unlock(&md->synth.vc_mtx); + mtx_unlock(&sd->flagqueue_mtx); + if (md->synth.bender(md, i, w14) == EAGAIN) { + mtx_lock(&sd->flagqueue_mtx); + return (QUEUEFULL); + } + mtx_lock(&sd->flagqueue_mtx); + mtx_lock(&md->synth.vc_mtx); + } + mtx_unlock(&md->synth.vc_mtx); + } else { #endif /* notyet */ /* For Mode 1. */ - if (md->synth.bender(md, chn, w14) == EAGAIN) + mtx_unlock(&sd->flagqueue_mtx); + if (md->synth.bender(md, chn, w14) == EAGAIN) { + mtx_lock(&sd->flagqueue_mtx); return (QUEUEFULL); + } + mtx_lock(&sd->flagqueue_mtx); +#if notyet + } +#endif /* notyet */ break; } @@ -1631,6 +1802,8 @@ seq_timing(sc_p scp, u_char *event) sd = scp->devinfo; unit = sd->unit; + mtx_assert(&sd->flagqueue_mtx, MA_OWNED); + parm = *(long *)&event[4]; #if notyet @@ -1639,12 +1812,11 @@ seq_timing(sc_p scp, u_char *event) #endif /* notyet */ switch (event[1]) { case TMR_WAIT_REL: - parm += scp->prev_event_time; - /* FALLTHRU */ case TMR_WAIT_ABS: + if (event[1] == TMR_WAIT_REL) + parm += scp->prev_event_time; if (parm > 0) { sd->flags |= SEQ_F_WRITING; - scp->prev_event_time = parm; if (seq_requesttimer(scp, parm)) return (TIMERARMED); } @@ -1687,6 +1859,8 @@ seq_local(sc_p scp, u_char *event) sd = scp->devinfo; unit = sd->unit; + mtx_assert(&sd->flagqueue_mtx, MA_OWNED); + switch (event[1]) { case LOCL_STARTAUDIO: #if notyet @@ -1708,19 +1882,22 @@ seq_sysex(sc_p scp, u_char *event) sd = scp->devinfo; unit = sd->unit; - if (event[1] >= mididev_info_number()) - return (MORE); - md = get_mididev_info_unit(event[1]); - if (!MIDICONFED(md) || md->synth.sendsysex == NULL - || ((md->flags & MIDI_F_BUSY) == 0 && seq_openmidi(scp, md, scp->fflags, MIDIDEV_MODE, curproc) != 0)) + mtx_assert(&sd->flagqueue_mtx, MA_OWNED); + + if (lookup_mididev(scp, event[1], LOOKUP_OPEN, &md) != 0) return (MORE); l = 0; for (i = 0 ; i < 6 && event[i + 2] != 0xff ; i++) l = i + 1; - if (l > 0) - if (md->synth.sendsysex(md, &event[2], l) == EAGAIN) + if (l > 0) { + mtx_unlock(&sd->flagqueue_mtx); + if (md->synth.sendsysex(md, &event[2], l) == EAGAIN) { + mtx_lock(&sd->flagqueue_mtx); return (QUEUEFULL); + } + mtx_lock(&sd->flagqueue_mtx); + } return (MORE); } @@ -1729,44 +1906,57 @@ static void seq_timer(void *arg) { sc_p scp; + seqdev_info *sd; scp = arg; + sd = scp->devinfo; /*DEB(printf("seq_timer: timer fired.\n"));*/ /* Record the current timestamp. */ - scp->prev_wakeup_time = seq_gettime(); + mtx_lock(&sd->flagqueue_mtx); + scp->timer_running = 0; + scp->prev_wakeup_time = seq_gettime(); seq_startplay(scp); + + mtx_unlock(&sd->flagqueue_mtx); } static int seq_openmidi(sc_p scp, mididev_info *md, int flags, int mode, struct proc *p) { - int midiunit, s, err; + int midiunit, err, insync; + + mtx_assert(&scp->devinfo->flagqueue_mtx, MA_OWNED); - if (md == NULL || !MIDICONFED(md)) { - DEB(printf("seq_openmidi: midi device does not exist.\n")); - return (ENXIO); - } midiunit = md->unit; DEB(printf("seq_openmidi: opening midi unit %d.\n", midiunit)); - if (!scp->midi_open[midiunit]) { - err = midi_open(MIDIMKDEV(MIDI_CDEV_MAJOR, midiunit, SND_DEV_MIDIN), flags, mode, p); - if (err != 0) { - printf("seq_openmidi: failed to open midi device %d.\n", midiunit); - return (err); - } - s = splmidi(); - scp->midi_open[midiunit] = 1; - md->intr = seq_intr; - md->intrarg = scp->devinfo; - md->synth.prev_out_status = 0; - md->synth.sysex_state = 0; - splx(s); + err = midi_open(MIDIMKDEV(MIDI_CDEV_MAJOR, midiunit, SND_DEV_MIDIN), flags, mode, p); + if (err != 0) { + printf("seq_openmidi: failed to open midi device %d.\n", midiunit); + return (err); } + mtx_lock(&md->synth.status_mtx); + mtx_lock(&md->flagqueue_mtx); + md->intr = seq_intr; + md->intrarg = scp->devinfo; + mtx_unlock(&md->flagqueue_mtx); + md->synth.sysex_state = 0; + mtx_unlock(&md->synth.status_mtx); + + insync = 0; + if ((scp->devinfo->flags & SEQ_F_INSYNC) != 0) { + insync = 1; + cv_wait(&scp->devinfo->insync_cv, &scp->devinfo->flagqueue_mtx); + } + + TAILQ_INSERT_TAIL(&scp->midi_open, md, md_linkseq); + + if (insync) + cv_signal(&scp->devinfo->insync_cv); return (0); } @@ -1774,7 +1964,9 @@ seq_openmidi(sc_p scp, mididev_info *md, int flags, int mode, struct proc *p) static int seq_closemidi(sc_p scp, mididev_info *md, int flags, int mode, struct proc *p) { - int midiunit, s; + int midiunit, insync; + + mtx_assert(&scp->devinfo->flagqueue_mtx, MA_OWNED); if (md == NULL || !MIDICONFED(md)) { DEB(printf("seq_closemidi: midi device does not exist.\n")); @@ -1784,28 +1976,38 @@ seq_closemidi(sc_p scp, mididev_info *md, int flags, int mode, struct proc *p) DEB(printf("seq_closemidi: closing midi unit %d.\n", midiunit)); - if (scp->midi_open[midiunit]) { - midi_close(MIDIMKDEV(MIDI_CDEV_MAJOR, midiunit, SND_DEV_MIDIN), flags, mode, p); - s = splmidi(); - scp->midi_open[midiunit] = 0; - md->intr = NULL; - md->intrarg = NULL; - splx(s); + midi_close(MIDIMKDEV(MIDI_CDEV_MAJOR, midiunit, SND_DEV_MIDIN), flags, mode, p); + mtx_lock(&md->flagqueue_mtx); + md->intr = NULL; + md->intrarg = NULL; + mtx_unlock(&md->flagqueue_mtx); + + insync = 0; + if ((scp->devinfo->flags & SEQ_F_INSYNC) != 0) { + insync = 1; + cv_wait(&scp->devinfo->insync_cv, &scp->devinfo->flagqueue_mtx); } + TAILQ_REMOVE(&scp->midi_open, md, md_linkseq); + + if (insync) + cv_signal(&scp->devinfo->insync_cv); + return (0); } static void seq_panic(sc_p scp) { + mtx_assert(&scp->devinfo->flagqueue_mtx, MA_OWNED); + seq_reset(scp); } static int seq_reset(sc_p scp) { - int unit, i, s, chn; + int unit, chn; seqdev_info *sd; mididev_info *md; u_char c[3]; @@ -1813,76 +2015,53 @@ seq_reset(sc_p scp) sd = scp->devinfo; unit = sd->unit; - s = splmidi(); + mtx_assert(&sd->flagqueue_mtx, MA_OWNED); + + if ((sd->flags & SEQ_F_INSYNC) != 0) { + cv_wait(&sd->insync_cv, &sd->flagqueue_mtx); + cv_signal(&sd->insync_cv); + } /* Stop reading and writing. */ sd->callback(sd, SEQ_CB_ABORT | SEQ_CB_RD | SEQ_CB_WR); /* Clear the queues. */ - midibuf_init(&sd->midi_dbuf_in); - midibuf_init(&sd->midi_dbuf_out); + midibuf_clear(&sd->midi_dbuf_in); + midibuf_clear(&sd->midi_dbuf_out); #if notyet /* Reset the synthesizers. */ - for (i = 0 ; i < mididev_info_number() ; i++) { - md = get_mididev_info_unit(i); - if (MIDICONFED(md) && scp->midi_open[i]) - md->synth.reset(md); - } + TAILQ_FOREACH(md, &scp->midi_open, md_linkseq) + md->synth.reset(md); #endif /* notyet */ #if notyet if (scp->seq_mode == SEQ_2) { - for (chn = 0 ; chn < 16 ; chn++) - for (i = 0 ; i < mididev_info_number() ; i++) - if (midi_open[i]) { - md = get_mididev_info_unit(i); - if (!MIDICONFED(md)) - continue; - if (md->synth.controller(md, chn, 123, 0) == EAGAIN /* All notes off. */ - || md->synth.controller(md, chn, 121, 0) == EAGAIN /* Reset all controllers. */ - || md->synth.bender(md, chn, 1 << 13) == EAGAIN) { /* Reset pitch bend. */ - splx(s); - return (EAGAIN); - } - } - splx(s); + for (chn = 0 ; chn < 16 ; chn++) { + TAILQ_FOREACH(md, &scp->midi_open, md_linkseq) { + if (md->synth.controller(md, chn, 123, 0) == EAGAIN /* All notes off. */ + || md->synth.controller(md, chn, 121, 0) == EAGAIN /* Reset all controllers. */ + || md->synth.bender(md, chn, 1 << 13) == EAGAIN) /* Reset pitch bend. */ + return (EAGAIN); + } + } } else { #endif /* notyet */ - splx(s); - for (i = 0 ; i < mididev_info_number() ; i++) { - md = get_mididev_info_unit(i); - if (!MIDICONFED(md)) - continue; - - /* Send active sensing. */ - c[0] = 0xfe; /* Active Sensing. */ - if (md->synth.writeraw(md, c, 1, 0) == EAGAIN) - return (EAGAIN); - /* - * We need a sleep to reset a midi device using an active sensing. - * SC-88 resets after 420ms... - */ - tsleep(md, PRIBIO, "seqrst", 500 * hz / 1000); + TAILQ_FOREACH(md, &scp->midi_open, md_linkseq) { for (chn = 0 ; chn < 16 ; chn++) { c[0] = 0xb0 | (chn & 0x0f); c[1] = (u_char)0x78; /* All sound off */ c[2] = (u_char)0; - if (md->synth.writeraw(md, c, 3, 0) == EAGAIN) - return (EAGAIN); + md->synth.writeraw(md, c, 3, 0); c[1] = (u_char)0x7b; /* All note off */ - if (md->synth.writeraw(md, c, 3, 0) == EAGAIN) - return (EAGAIN); + md->synth.writeraw(md, c, 3, 0); c[1] = (u_char)0x79; /* Reset all controller */ - if (md->synth.writeraw(md, c, 3, 0) == EAGAIN) - return (EAGAIN); + md->synth.writeraw(md, c, 3, 0); } } - for (i = 0 ; i < mididev_info_number() ; i++){ - md = get_mididev_info_unit(i); - if (MIDICONFED(md)) - seq_closemidi(scp, md, scp->fflags, MIDIDEV_MODE, curproc); - } + seq_sync(scp); + TAILQ_FOREACH(md, &scp->midi_open, md_linkseq) + lookup_mididev(scp, md->unit, LOOKUP_CLOSE, NULL); #if notyet } #endif /* notyet */ @@ -1890,30 +2069,61 @@ seq_reset(sc_p scp) return (0); } +#define SEQ_SYNC_TIMEOUT 8 static int seq_sync(sc_p scp) { - int unit, s, i; + int i, rl; seqdev_info *sd; + mididev_info *md; sd = scp->devinfo; - unit = sd->unit; - s = splmidi(); + mtx_assert(&sd->flagqueue_mtx, MA_OWNED); - if (sd->midi_dbuf_out.rl >= EV_SZ) - sd->callback(sd, SEQ_CB_START | SEQ_CB_WR); + sd->flags |= SEQ_F_INSYNC; - while ((sd->flags & SEQ_F_WRITING) != 0 && sd->midi_dbuf_out.rl >= EV_SZ) { - i = tsleep(&sd->midi_dbuf_out.tsleep_out, PRIBIO | PCATCH, "seqsnc", 0); - if (i == EINTR) - sd->callback(sd, SEQ_CB_STOP | SEQ_CB_WR); + while (sd->midi_dbuf_out.rl >= EV_SZ) { + if ((sd->flags & SEQ_F_WRITING) == 0) + sd->callback(sd, SEQ_CB_START | SEQ_CB_WR); + rl = sd->midi_dbuf_out.rl; + i = msleep(&sd->midi_dbuf_out.tsleep_out, &sd->flagqueue_mtx, PRIBIO | PCATCH, "seqsnc", SEQ_SYNC_TIMEOUT * hz); if (i == EINTR || i == ERESTART) { - splx(s); + if (i == EINTR) + sd->callback(sd, SEQ_CB_STOP | SEQ_CB_WR); + sd->flags &= ~SEQ_F_INSYNC; return (i); } + if (i == EWOULDBLOCK && rl == sd->midi_dbuf_out.rl && !scp->timer_running) { + /* A queue seems to be stuck up. Give up and clear queues. */ + sd->callback(sd, SEQ_CB_STOP | SEQ_CB_WR); + midibuf_clear(&sd->midi_dbuf_out); + TAILQ_FOREACH(md, &scp->midi_open, md_linkseq) { + mtx_lock(&md->flagqueue_mtx); + md->callback(md, MIDI_CB_ABORT | MIDI_CB_WR); + midibuf_clear(&md->midi_dbuf_out); + mtx_unlock(&md->flagqueue_mtx); + } + break; + } } - splx(s); + + /* + * Since syncing a midi device might block, unlock sd->flagqueue_mtx. + * Keep sd->midi_dbuf_out from writing by setting SEQ_F_INSYNC. + * sd->insync_cv is signalled when sync is finished. + */ + mtx_unlock(&sd->flagqueue_mtx); + + TAILQ_FOREACH(md, &scp->midi_open, md_linkseq) { + mtx_lock(&md->flagqueue_mtx); + midi_sync(md); + mtx_unlock(&md->flagqueue_mtx); + } + + mtx_lock(&sd->flagqueue_mtx); + sd->flags &= ~SEQ_F_INSYNC; + cv_signal(&sd->insync_cv); return (0); } @@ -1927,7 +2137,6 @@ static seqdev_info * get_seqdev_info(dev_t i_dev, int *unit) { int u; - seqdev_info *d = NULL ; if (MIDIDEV(i_dev) != SND_DEV_SEQ && MIDIDEV(i_dev) != SND_DEV_SEQ2) return NULL; @@ -1935,13 +2144,105 @@ get_seqdev_info(dev_t i_dev, int *unit) if (unit) *unit = u ; - if (u >= NSEQ_MAX) { - DEB(printf("get_seqdev_info: unit %d is not configured.\n", u)); - return NULL; - } - d = &seq_info[u]; + return get_seqdev_info_unit(u); +} - return d ; +/* + * a small utility function which, given a unit number, returns + * a pointer to the associated mididev_info struct. + */ +seqdev_info * +get_seqdev_info_unit(int unit) +{ + seqdev_info *sd; + + mtx_lock(&seqinfo_mtx); + TAILQ_FOREACH(sd, &seq_info, sd_link) { + if (sd->unit == unit) + break; + } + mtx_unlock(&seqinfo_mtx); + + return sd; +} + +/* Create a new sequencer device info structure. */ +seqdev_info * +create_seqdev_info_unit(int unit, seqdev_info *seq) +{ + seqdev_info *sd, *sdnew; + + /* As malloc(9) might block, allocate seqdev_info now. */ + sdnew = malloc(sizeof(seqdev_info), M_DEVBUF, M_WAITOK | M_ZERO); + if (sdnew == NULL) + return NULL; + bcopy(seq, sdnew, sizeof(seqdev_info)); + sdnew->unit = unit; + midibuf_init(&sdnew->midi_dbuf_in); + midibuf_init(&sdnew->midi_dbuf_out); + mtx_init(&sdnew->flagqueue_mtx, "seqflq", MTX_DEF); + cv_init(&sdnew->insync_cv, "seqins"); + + mtx_lock(&seqinfo_mtx); + + TAILQ_FOREACH(sd, &seq_info, sd_link) { + if (sd->unit == unit) { + mtx_unlock(&seqinfo_mtx); + midibuf_destroy(&sdnew->midi_dbuf_in); + midibuf_destroy(&sdnew->midi_dbuf_out); + mtx_destroy(&sdnew->flagqueue_mtx); + cv_destroy(&sdnew->insync_cv); + free(sdnew, M_DEVBUF); + return sd; + } + } + + mtx_lock(&sdnew->flagqueue_mtx); + TAILQ_INSERT_TAIL(&seq_info, sdnew, sd_link); + nseq++; + + mtx_unlock(&seqinfo_mtx); + + return sdnew; +} + +/* + * Look up a midi device by its unit number opened by this sequencer. + * If the device is not opened and mode is LOOKUP_OPEN, open the device. + */ +static int +lookup_mididev(sc_p scp, int unit, int mode, mididev_info **mdp) +{ + int ret; + mididev_info *md; + + if (mdp == NULL) + mdp = &md; + + *mdp = NULL; + + mtx_assert(&scp->devinfo->flagqueue_mtx, MA_OWNED); + + TAILQ_FOREACH(md, &scp->midi_open, md_linkseq) { + if (md->unit == unit) { + *mdp = md; + if (mode == LOOKUP_CLOSE) + return seq_closemidi(scp, md, scp->fflags, MIDIDEV_MODE, curproc); + + return (md != NULL && MIDICONFED(md)) ? 0 : ENXIO; + } + } + + if (mode == LOOKUP_OPEN) { + md = get_mididev_info_unit(unit); + if (md != NULL) { + *mdp = md; + ret = seq_openmidi(scp, md, scp->fflags, MIDIDEV_MODE, curproc); + return ret; + } + } + + return ENXIO; } /* XXX These functions are actually redundant. */ @@ -2036,3 +2337,28 @@ seq_modevent(module_t mod, int type, void *data) } DEV_MODULE(seq, seq_modevent, NULL); + +static void +seq_clone(arg, name, namelen, dev) + void *arg; + char *name; + int namelen; + dev_t *dev; +{ + int u; + + if (*dev != NODEV) + return; + if (bcmp(name, "sequencer", 9) != 0) + return; + if (name[10] != '\0' && name[11] != '\0') + return; + u = name[9] - '0'; + if (name[10] != '\0') { + u *= 10; + u += name[10] - '0'; + } + seq_initunit(u); + *dev = MIDIMKDEV(SEQ_CDEV_MAJOR, u, MIDI_DEV_SEQ); + return; +} diff --git a/sys/dev/sound/midi/sequencer.h b/sys/dev/sound/midi/sequencer.h index e231b0642eac..a81e041f6ce1 100644 --- a/sys/dev/sound/midi/sequencer.h +++ b/sys/dev/sound/midi/sequencer.h @@ -53,6 +53,7 @@ #include #include #include +#include #include /* for DELAY */ #include @@ -69,6 +70,16 @@ typedef struct _seqdev_info seqdev_info; typedef int (seq_callback_t)(seqdev_info *sd, int reason); +/* + * The order of mutex lock (from the first to the last) + * + * 1. sequencer flags, queues, timer and device list + * 2. midi synth voice and channel + * 3. midi synth status + * 4. generic midi flags and queues + * 5. midi device + */ + /* * descriptor of sequencer operations ... * @@ -128,14 +139,20 @@ struct _seqdev_info { * mss codec type, etc. etc. */ + struct mtx flagqueue_mtx; /* Mutex to protect flags and queues */ + struct cv insync_cv; /* Conditional variable for sync */ + + /* Queues */ midi_dbuf midi_dbuf_in; /* midi input event/message queue */ midi_dbuf midi_dbuf_out; /* midi output event/message queue */ + /* * these parameters describe the operation of the board. * Generic things like busy flag, speed, etc are here. */ + /* Flags */ volatile u_long flags ; /* 32 bits, used for various purposes. */ /* @@ -186,6 +203,8 @@ struct _seqdev_info { */ #define SEQ_F_INIT 0x4000 /* changed parameters. need init */ +#define SEQ_F_INSYNC 0x8000 /* a pending sync */ + int play_blocksize, rec_blocksize; /* blocksize for io and dma ops */ #define swsel midi_dbuf_out.sel @@ -194,6 +213,9 @@ struct _seqdev_info { u_long magic; #define MAGIC(unit) ( 0xa4d10de0 + unit ) void *device_data ; /* just in case it is needed...*/ + + /* The tailq entry of the next sequencer device. */ + TAILQ_ENTRY(_seqdev_info) sd_link; } ; @@ -226,8 +248,6 @@ struct _seqdev_info { #define DEB(x) #endif - extern seqdev_info seq_info[NSEQ_MAX] ; - #define MIDI_DEV_SEQ 1 /* Sequencer output /dev/sequencer (FM synthesizer and MIDI output) */ diff --git a/sys/dev/sound/pci/csamidi.c b/sys/dev/sound/pci/csamidi.c index b29e9bab5f42..256d48518f25 100644 --- a/sys/dev/sound/pci/csamidi.c +++ b/sys/dev/sound/pci/csamidi.c @@ -89,6 +89,8 @@ struct csamidi_softc { mididev_info *devinfo; /* midi device information */ struct csa_bridgeinfo *binfo; /* The state of the parent. */ + struct mtx mtx; /* Mutex to protect the device. */ + struct resource *io; /* Base of io map */ int io_rid; /* Io map resource ID */ struct resource *mem; /* Base of memory map */ @@ -128,12 +130,9 @@ static mididev_info csamidi_op_desc = { SNDCARD_MPU401, - NULL, - NULL, NULL, NULL, csamidi_ioctl, - NULL, csamidi_callback, @@ -177,10 +176,8 @@ csamidi_attach(device_t dev) sc_p scp; mididev_info *devinfo; struct sndcard_func *func; - int unit; scp = device_get_softc(dev); - unit = device_get_unit(dev); func = device_get_ivars(dev); scp->binfo = func->varinfo; @@ -192,20 +189,14 @@ csamidi_attach(device_t dev) /* Fill the softc. */ scp->dev = dev; - scp->devinfo = devinfo = create_mididev_info_unit(&unit, MDT_MIDI); + mtx_init(&scp->mtx, "csamid", MTX_DEF); + scp->devinfo = devinfo = create_mididev_info_unit(MDT_MIDI, &csamidi_op_desc, &midisynth_op_desc); /* Fill the midi info. */ - bcopy(&csamidi_op_desc, devinfo, sizeof(csamidi_op_desc)); - midiinit(devinfo, dev); - devinfo->flags = 0; - bcopy(&midisynth_op_desc, &devinfo->synth, sizeof(midisynth_op_desc)); snprintf(devinfo->midistat, sizeof(devinfo->midistat), "at irq %d", (int)rman_get_start(scp->irq)); - /* Init the queue. */ - devinfo->midi_dbuf_in.unit_size = devinfo->midi_dbuf_out.unit_size = 1; - midibuf_init(&devinfo->midi_dbuf_in); - midibuf_init(&devinfo->midi_dbuf_out); + midiinit(devinfo, dev); /* Enable interrupt. */ if (bus_setup_intr(dev, scp->irq, INTR_TYPE_TTY, csamidi_intr, scp, &scp->ih)) { @@ -271,26 +262,40 @@ csamidi_intr(void *arg) scp = (sc_p)arg; devinfo = scp->devinfo; + MIDI_DROP_GIANT_NOSWITCH(); + + mtx_lock(&devinfo->flagqueue_mtx); + mtx_lock(&scp->mtx); + /* Read the received data. */ while ((csamidi_status(scp) & MIDSR_RBE) == 0) { /* Receive the data. */ c = (u_char)csamidi_readdata(scp); + mtx_unlock(&scp->mtx); + /* Queue into the passthru buffer and start transmitting if we can. */ if ((devinfo->flags & MIDI_F_PASSTHRU) != 0 && ((devinfo->flags & MIDI_F_BUSY) == 0 || (devinfo->fflags & FWRITE) == 0)) { midibuf_input_intr(&devinfo->midi_dbuf_passthru, &c, sizeof(c)); devinfo->callback(devinfo, MIDI_CB_START | MIDI_CB_WR); } /* Queue if we are reading. Discard an active sensing. */ - if ((devinfo->flags & MIDI_F_READING) != 0 && c != 0xfe) + if ((devinfo->flags & MIDI_F_READING) != 0 && c != 0xfe) { midibuf_input_intr(&devinfo->midi_dbuf_in, &c, sizeof(c)); + } + mtx_lock(&scp->mtx); } + mtx_unlock(&scp->mtx); /* Transmit out data. */ if ((devinfo->flags & MIDI_F_WRITING) != 0 && (csamidi_status(scp) & MIDSR_TBF) == 0) csamidi_xmit(scp); + mtx_unlock(&devinfo->flagqueue_mtx); + /* Invoke the upper layer. */ midi_intr(devinfo); + + MIDI_PICKUP_GIANT(); } static int @@ -299,6 +304,8 @@ csamidi_callback(mididev_info *d, int reason) int unit; sc_p scp; + mtx_assert(&d->flagqueue_mtx, MA_OWNED); + if (d == NULL) { DEB(printf("csamidi_callback: device not configured.\n")); return (ENXIO); @@ -336,7 +343,6 @@ csamidi_callback(mididev_info *d, int reason) /* * Starts to play the data in the output queue. - * Call this at >=splclock. */ static void csamidi_startplay(sc_p scp) @@ -345,6 +351,8 @@ csamidi_startplay(sc_p scp) devinfo = scp->devinfo; + mtx_assert(&devinfo->flagqueue_mtx, MA_OWNED); + /* Can we play now? */ if (devinfo->midi_dbuf_out.rl == 0) return; @@ -362,6 +370,8 @@ csamidi_xmit(sc_p scp) devinfo = scp->devinfo; + mtx_assert(&devinfo->flagqueue_mtx, MA_OWNED); + /* See which source to use. */ if ((devinfo->flags & MIDI_F_PASSTHRU) == 0 || ((devinfo->flags & MIDI_F_BUSY) != 0 && (devinfo->fflags & FWRITE) != 0)) dbuf = &devinfo->midi_dbuf_out; @@ -369,18 +379,24 @@ csamidi_xmit(sc_p scp) dbuf = &devinfo->midi_dbuf_passthru; /* Transmit the data in the queue. */ - while ((devinfo->flags & MIDI_F_WRITING) != 0 && (csamidi_status(scp) & MIDSR_TBF) == 0) { + while ((devinfo->flags & MIDI_F_WRITING) != 0) { /* Do we have the data to transmit? */ if (dbuf->rl == 0) { /* Stop playing. */ devinfo->flags &= ~MIDI_F_WRITING; break; } else { + mtx_lock(&scp->mtx); + if ((csamidi_status(scp) & MIDSR_TBF) != 0) { + mtx_unlock(&scp->mtx); + break; + } /* Send the data. */ midibuf_output_intr(dbuf, &c, sizeof(c)); csamidi_writedata(scp, c); /* We are playing now. */ devinfo->flags |= MIDI_F_WRITING; + mtx_unlock(&scp->mtx); } } } @@ -391,6 +407,8 @@ csamidi_reset(sc_p scp) { int i, resp; + mtx_lock(&scp->mtx); + /* Reset the midi. */ resp = 0; for (i = 0 ; i < CSAMIDI_TRYDATA ; i++) { @@ -398,8 +416,10 @@ csamidi_reset(sc_p scp) if (resp == 0) break; } - if (resp != 0) + if (resp != 0) { + mtx_unlock(&scp->mtx); return (1); + } for (i = 0 ; i < CSAMIDI_TRYDATA ; i++) { resp = csamidi_command(scp, MIDCR_TXE | MIDCR_RXE | MIDCR_RIE | MIDCR_TIE); if (resp == 0) @@ -408,6 +428,8 @@ csamidi_reset(sc_p scp) if (resp != 0) return (1); + mtx_unlock(&scp->mtx); + DELAY(CSAMIDI_DELAY); return (0);