summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys/dev/sound/isa/emu8000.c75
-rw-r--r--sys/dev/sound/isa/gusmidi.c87
-rw-r--r--sys/dev/sound/isa/mpu.c121
-rw-r--r--sys/dev/sound/isa/opl.c239
-rw-r--r--sys/dev/sound/isa/uartsio.c112
-rw-r--r--sys/dev/sound/midi/midi.c422
-rw-r--r--sys/dev/sound/midi/midi.h49
-rw-r--r--sys/dev/sound/midi/midibuf.c101
-rw-r--r--sys/dev/sound/midi/midibuf.h13
-rw-r--r--sys/dev/sound/midi/midisynth.c239
-rw-r--r--sys/dev/sound/midi/midisynth.h15
-rw-r--r--sys/dev/sound/midi/sequencer.c1278
-rw-r--r--sys/dev/sound/midi/sequencer.h24
-rw-r--r--sys/dev/sound/pci/csamidi.c58
14 files changed, 1710 insertions, 1123 deletions
diff --git a/sys/dev/sound/isa/emu8000.c b/sys/dev/sound/isa/emu8000.c
index 0efb05c..7067a8f 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));
@@ -765,59 +755,6 @@ emu_close(dev_t i_dev, int flags, int mode, struct proc *p)
}
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)
{
sc_p scp;
@@ -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 d95c75f..e40e8c1 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 4adb80d..2ccd0a2 100644
--- a/sys/dev/sound/isa/mpu.c
+++ b/sys/dev/sound/isa/mpu.c
@@ -45,8 +45,6 @@
#include <isa/sioreg.h>
#include <isa/ic/ns16550.h>
-#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);
@@ -171,10 +165,7 @@ static mididev_info mpu_op_desc = {
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 2d41321..a4a0e66 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);
@@ -841,61 +838,6 @@ opl_close(dev_t i_dev, int flags, int mode, struct proc *p)
}
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)
{
sc_p scp;
@@ -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 5f56e36..b98e0f3 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 */
@@ -134,10 +136,7 @@ static mididev_info uartsio_op_desc = {
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 1b504bc..3d6a16c 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);
+ }
+
+ mtx_lock(&midiinfo_mtx);
+ TAILQ_FOREACH(md, &midi_info, md_link) {
+ if (md->unit == unit)
+ break;
}
- d = &midi_info[unit];
+ mtx_unlock(&midiinfo_mtx);
- return d;
+ 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;
+ }
+
+ for (unit = 0 ; ; unit++) {
+ TAILQ_FOREACH(md, &midi_info, md_link) {
+ if (md->unit == unit)
+ break;
+ }
+ if (md == NULL)
+ break;
}
- *unit = nmidi + nsynth - 1;
- return get_mididev_info_unit(*unit);
+ 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);
-
- if (ret == 0 && d->write != NULL)
- ret = d->write(i_dev, buf, flag);
+ mtx_unlock(&d->flagqueue_mtx);
- 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 b0982c8..d9b81c7 100644
--- a/sys/dev/sound/midi/midi.h
+++ b/sys/dev/sound/midi/midi.h
@@ -65,6 +65,7 @@
#include <sys/rman.h>
#include <sys/mman.h>
#include <sys/poll.h>
+#include <sys/mutex.h>
#include <dev/sound/midi/miditypes.h>
#include <dev/sound/midi/midibuf.h>
@@ -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 5922a5b..e1f15c7 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 d40019d..68a7a37 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 481f79c..63b4423 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 d27e62b..db43354 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 7b010b4..dd4ce6a 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,57 +207,63 @@ 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));
+ seq_initunit(0);
+ EVENTHANDLER_REGISTER(dev_clone, seq_clone, 0, 1000);
- /* 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;
+ DEB(printf("seq: inited.\n"));
- 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);
- }
+ return (0);
+}
- /* We have inited. */
- seq_info_inited = 1;
+static int
+seq_initunit(int unit)
+{
+ sc_p scp;
+ seqdev_info *devinfo;
+ dev_t seqdev;
- if (nseq == 1)
- printf("seq0: Midi sequencer.\n");
- else
- printf("seq0-%lu: Midi sequencers.\n", nseq - 1);
+ /* 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);
+ }
- DEB(printf("seq: inited.\n"));
+ /* 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);
}
@@ -242,10 +271,9 @@ seq_init(void)
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;
+ 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);
+ 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;
- break;
- }
- if (!scp->midi_open[midiunit]) {
- ret = EBUSY;
+ 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_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;
- /*DEB(printf("seq%d: queueing.\n", unit));*/
+ mtx_assert(&sd->flagqueue_mtx, MA_OWNED);
- s = splmidi();
+ /*DEB(printf("seq%d: queueing.\n", unit));*/
- /* 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,52 +1906,67 @@ 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);
}
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;
+ }
+ }
+
+ /*
+ * 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);
}
- splx(s);
+
+ 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 get_seqdev_info_unit(u);
+}
+
+/*
+ * 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;
+ }
}
- d = &seq_info[u];
- return d ;
+ 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 e231b06..a81e041 100644
--- a/sys/dev/sound/midi/sequencer.h
+++ b/sys/dev/sound/midi/sequencer.h
@@ -53,6 +53,7 @@
#include <sys/syslog.h>
#include <sys/errno.h>
#include <sys/malloc.h>
+#include <sys/condvar.h>
#include <machine/clock.h> /* for DELAY */
#include <sys/soundcard.h>
@@ -70,6 +71,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 b29e9ba..256d485 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 */
@@ -130,10 +132,7 @@ static mididev_info csamidi_op_desc = {
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);
OpenPOWER on IntegriCloud