- Mutexify midi(4). The driver runs under the giant lock by default.
If you ever want to run midi(4) out of the giant lock, uncomment MIDI_OUTOFGIANT in midi.h. Confirmed to work for csamidi with WITNESS and INVARIANTS. - midi_info, midi_open and seq_info are now tailqs, allowing arbitrary numbers of devices to be configured. - Do not send an active sensing message to reset midi modules. - Clone /dev/sequencer*. /dev/sequencer0 and /dev/sequencer are generated upon initialization.
This commit is contained in:
parent
ef0503b1ec
commit
87a636ccb0
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=73072
@ -383,8 +383,6 @@ static int emupnp_attach(device_t dev) __unused;
|
||||
|
||||
static d_open_t emu_open;
|
||||
static d_close_t emu_close;
|
||||
static d_read_t emu_read;
|
||||
static d_write_t emu_write;
|
||||
static d_ioctl_t emu_ioctl;
|
||||
static midi_callback_t emu_callback;
|
||||
|
||||
@ -397,6 +395,8 @@ struct emu_softc {
|
||||
device_t dev; /* device information */
|
||||
mididev_info *devinfo; /* midi device information */
|
||||
|
||||
struct mtx mtx; /* Mutex to protect a device */
|
||||
|
||||
struct resource *io[3]; /* Base of io port */
|
||||
int io_rid[3]; /* Io resource ID */
|
||||
|
||||
@ -518,11 +518,7 @@ mididev_info emu_op_desc = {
|
||||
|
||||
emu_open,
|
||||
emu_close,
|
||||
emu_read,
|
||||
emu_write,
|
||||
emu_ioctl,
|
||||
NULL,
|
||||
|
||||
emu_callback,
|
||||
|
||||
MIDI_BUFFSIZE, /* Queue Length */
|
||||
@ -723,23 +719,17 @@ emu_attach(device_t dev)
|
||||
emu_writehwcf3(scp, 0x0004);
|
||||
|
||||
/* Fill the softc for this unit. */
|
||||
scp->devinfo = devinfo = create_mididev_info_unit(&unit, MDT_SYNTH);
|
||||
bcopy(&emu_synthinfo, &scp->synthinfo, sizeof(emu_synthinfo));
|
||||
mtx_init(&scp->mtx, "emumid", MTX_DEF);
|
||||
scp->devinfo = devinfo = create_mididev_info_unit(MDT_SYNTH, &emu_op_desc, &midisynth_op_desc);
|
||||
|
||||
/* Fill the midi info. */
|
||||
bcopy(&emu_op_desc, devinfo, sizeof(emu_op_desc));
|
||||
midiinit(devinfo, dev);
|
||||
devinfo->flags = 0;
|
||||
bcopy(&midisynth_op_desc, &devinfo->synth, sizeof(midisynth_op_desc));
|
||||
devinfo->synth.readraw = emu_readraw;
|
||||
devinfo->synth.writeraw = emu_writeraw;
|
||||
snprintf(devinfo->midistat, sizeof(devinfo->midistat), "at 0x%x, 0x%x, 0x%x",
|
||||
(u_int)rman_get_start(scp->io[0]), (u_int)rman_get_start(scp->io[1]), (u_int)rman_get_start(scp->io[2]));
|
||||
|
||||
/* Init the queue. */
|
||||
devinfo->midi_dbuf_in.unit_size = devinfo->midi_dbuf_out.unit_size = 1;
|
||||
midibuf_init(&devinfo->midi_dbuf_in);
|
||||
midibuf_init(&devinfo->midi_dbuf_out);
|
||||
midiinit(devinfo, dev);
|
||||
|
||||
DEB(printf("emu%d: attached.\n", unit));
|
||||
|
||||
@ -764,59 +754,6 @@ emu_close(dev_t i_dev, int flags, int mode, struct proc *p)
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
emu_read(dev_t i_dev, struct uio *buf, int flag)
|
||||
{
|
||||
sc_p scp;
|
||||
mididev_info *devinfo;
|
||||
int unit/*, s, len, ret*/;
|
||||
|
||||
unit = MIDIUNIT(i_dev);
|
||||
|
||||
devinfo = get_mididev_info(i_dev, &unit);
|
||||
if (devinfo == NULL) {
|
||||
DEB(printf("emu_read: unit %d is not configured.\n", unit));
|
||||
return (ENXIO);
|
||||
}
|
||||
scp = devinfo->softc;
|
||||
if ((devinfo->fflags & FREAD) == 0) {
|
||||
DEB(printf("emu_read: unit %d is not for reading.\n", unit));
|
||||
return (EIO);
|
||||
}
|
||||
|
||||
/* Drain the data. */
|
||||
midibuf_init(&devinfo->midi_dbuf_in);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
emu_write(dev_t i_dev, struct uio *buf, int flag)
|
||||
{
|
||||
sc_p scp;
|
||||
mididev_info *devinfo;
|
||||
int unit/*, s, len, ret*/;
|
||||
|
||||
unit = MIDIUNIT(i_dev);
|
||||
|
||||
devinfo = get_mididev_info(i_dev, &unit);
|
||||
if (devinfo == NULL) {
|
||||
DEB(printf("emu_write: unit %d is not configured.\n", unit));
|
||||
return (ENXIO);
|
||||
}
|
||||
scp = devinfo->softc;
|
||||
if ((devinfo->fflags & FWRITE) == 0) {
|
||||
DEB(printf("emu_write: unit %d is not for writing.\n", unit));
|
||||
return (EIO);
|
||||
}
|
||||
|
||||
/* Drain the data. */
|
||||
midibuf_init(&devinfo->midi_dbuf_out);
|
||||
midibuf_init(&devinfo->midi_dbuf_passthru);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
emu_ioctl(dev_t i_dev, u_long cmd, caddr_t arg, int mode, struct proc *p)
|
||||
{
|
||||
@ -868,6 +805,8 @@ emu_ioctl(dev_t i_dev, u_long cmd, caddr_t arg, int mode, struct proc *p)
|
||||
static int
|
||||
emu_callback(mididev_info *devinfo, int reason)
|
||||
{
|
||||
mtx_assert(&devinfo->flagqueue_mtx, MA_OWNED);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
@ -169,12 +163,9 @@ static mididev_info mpu_op_desc = {
|
||||
|
||||
SNDCARD_MPU401,
|
||||
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
mpu_ioctl,
|
||||
NULL,
|
||||
|
||||
mpu_callback,
|
||||
|
||||
@ -362,12 +353,10 @@ mpu_attach(device_t dev)
|
||||
{
|
||||
sc_p scp;
|
||||
mididev_info *devinfo;
|
||||
int unit;
|
||||
|
||||
scp = device_get_softc(dev);
|
||||
unit = device_get_unit(dev);
|
||||
|
||||
DEB(printf("mpu%d: attaching.\n", unit));
|
||||
DEB(printf("mpu: attaching.\n"));
|
||||
|
||||
/* Allocate the resources, switch to uart mode. */
|
||||
if (mpu_allocres(scp, dev) || mpu_uartmode(scp)) {
|
||||
@ -379,14 +368,10 @@ mpu_attach(device_t dev)
|
||||
|
||||
/* Fill the softc. */
|
||||
scp->dev = dev;
|
||||
scp->devinfo = devinfo = create_mididev_info_unit(&unit, MDT_MIDI);
|
||||
callout_handle_init(&scp->dh);
|
||||
mtx_init(&scp->mtx, "mpumid", MTX_DEF);
|
||||
scp->devinfo = devinfo = create_mididev_info_unit(MDT_MIDI, &mpu_op_desc, &midisynth_op_desc);
|
||||
|
||||
/* Fill the midi info. */
|
||||
bcopy(&mpu_op_desc, devinfo, sizeof(mpu_op_desc));
|
||||
midiinit(devinfo, dev);
|
||||
devinfo->flags = 0;
|
||||
bcopy(&midisynth_op_desc, &devinfo->synth, sizeof(midisynth_op_desc));
|
||||
if (scp->irq != NULL)
|
||||
snprintf(devinfo->midistat, sizeof(devinfo->midistat), "at 0x%x irq %d",
|
||||
(u_int)rman_get_start(scp->io), (int)rman_get_start(scp->irq));
|
||||
@ -394,17 +379,14 @@ mpu_attach(device_t dev)
|
||||
snprintf(devinfo->midistat, sizeof(devinfo->midistat), "at 0x%x",
|
||||
(u_int)rman_get_start(scp->io));
|
||||
|
||||
/* Init the queue. */
|
||||
devinfo->midi_dbuf_in.unit_size = devinfo->midi_dbuf_out.unit_size = 1;
|
||||
midibuf_init(&devinfo->midi_dbuf_in);
|
||||
midibuf_init(&devinfo->midi_dbuf_out);
|
||||
midiinit(devinfo, dev);
|
||||
|
||||
/* Now we can handle the interrupts. */
|
||||
if (scp->irq != NULL)
|
||||
bus_setup_intr(dev, scp->irq, INTR_TYPE_TTY, mpu_intr, scp,
|
||||
&scp->ih);
|
||||
|
||||
DEB(printf("mpu%d: attached.\n", unit));
|
||||
DEB(printf("mpu: attached.\n"));
|
||||
|
||||
return (0);
|
||||
}
|
||||
@ -475,23 +457,34 @@ mpu_intr(void *arg)
|
||||
scp = (sc_p)arg;
|
||||
devinfo = scp->devinfo;
|
||||
|
||||
MIDI_DROP_GIANT_NOSWITCH();
|
||||
|
||||
mtx_lock(&devinfo->flagqueue_mtx);
|
||||
mtx_lock(&scp->mtx);
|
||||
|
||||
/* Read the received data. */
|
||||
while ((mpu_status(scp) & MPU_INPUTBUSY) == 0) {
|
||||
/* Receive the data. */
|
||||
c = mpu_readdata(scp);
|
||||
mtx_unlock(&scp->mtx);
|
||||
/* Queue into the passthru buffer and start transmitting if we can. */
|
||||
if ((devinfo->flags & MIDI_F_PASSTHRU) != 0 && ((devinfo->flags & MIDI_F_BUSY) == 0 || (devinfo->fflags & FWRITE) == 0)) {
|
||||
midibuf_input_intr(&devinfo->midi_dbuf_passthru, &c, sizeof(c));
|
||||
devinfo->callback(devinfo, MIDI_CB_START | MIDI_CB_WR);
|
||||
}
|
||||
/* Queue if we are reading. Discard an active sensing. */
|
||||
if ((devinfo->flags & MIDI_F_READING) != 0 && c != 0xfe)
|
||||
if ((devinfo->flags & MIDI_F_READING) != 0 && c != 0xfe) {
|
||||
midibuf_input_intr(&devinfo->midi_dbuf_in, &c, sizeof(c));
|
||||
}
|
||||
mtx_lock(&scp->mtx);
|
||||
}
|
||||
mtx_unlock(&scp->mtx);
|
||||
mtx_unlock(&devinfo->flagqueue_mtx);
|
||||
|
||||
/* Invoke the upper layer. */
|
||||
midi_intr(devinfo);
|
||||
|
||||
MIDI_PICKUP_GIANT();
|
||||
}
|
||||
|
||||
static int
|
||||
@ -500,6 +493,8 @@ mpu_callback(mididev_info *d, int reason)
|
||||
int unit;
|
||||
sc_p scp;
|
||||
|
||||
mtx_assert(&d->flagqueue_mtx, MA_OWNED);
|
||||
|
||||
if (d == NULL) {
|
||||
DEB(printf("mpu_callback: device not configured.\n"));
|
||||
return (ENXIO);
|
||||
@ -537,7 +532,6 @@ mpu_callback(mididev_info *d, int reason)
|
||||
|
||||
/*
|
||||
* Starts to play the data in the output queue.
|
||||
* Call this at >=splclock.
|
||||
*/
|
||||
static void
|
||||
mpu_startplay(sc_p scp)
|
||||
@ -546,16 +540,14 @@ mpu_startplay(sc_p scp)
|
||||
|
||||
devinfo = scp->devinfo;
|
||||
|
||||
mtx_assert(&devinfo->flagqueue_mtx, MA_OWNED);
|
||||
|
||||
/* Can we play now? */
|
||||
if (devinfo->midi_dbuf_out.rl == 0)
|
||||
return;
|
||||
|
||||
devinfo->flags |= MIDI_F_WRITING;
|
||||
#if MPU_USEMICROTIMER
|
||||
mpu_timeout(scp);
|
||||
#else
|
||||
mpu_xmit(scp);
|
||||
#endif /* MPU_USEMICROTIMER */
|
||||
}
|
||||
|
||||
static void
|
||||
@ -567,6 +559,8 @@ mpu_xmit(sc_p scp)
|
||||
|
||||
devinfo = scp->devinfo;
|
||||
|
||||
mtx_assert(&devinfo->flagqueue_mtx, MA_OWNED);
|
||||
|
||||
/* See which source to use. */
|
||||
if ((devinfo->flags & MIDI_F_PASSTHRU) == 0 || ((devinfo->flags & MIDI_F_BUSY) != 0 && (devinfo->fflags & FWRITE) != 0))
|
||||
dbuf = &devinfo->midi_dbuf_out;
|
||||
@ -574,59 +568,24 @@ mpu_xmit(sc_p scp)
|
||||
dbuf = &devinfo->midi_dbuf_passthru;
|
||||
|
||||
/* Transmit the data in the queue. */
|
||||
#if MPU_USEMICROTIMER
|
||||
while ((devinfo->flags & MIDI_F_WRITING) != 0 && (mpu_status(scp) & MPU_OUTPUTBUSY) == 0) {
|
||||
/* Do we have the data to transmit? */
|
||||
if (dbuf->rl == 0) {
|
||||
/* Stop playing. */
|
||||
devinfo->flags &= ~MIDI_F_WRITING;
|
||||
break;
|
||||
} else {
|
||||
/* Send the data. */
|
||||
midibuf_output_intr(dbuf, &c, sizeof(c));
|
||||
mpu_writedata(scp, c);
|
||||
/* We are playing now. */
|
||||
devinfo->flags |= MIDI_F_WRITING;
|
||||
while ((devinfo->flags & MIDI_F_WRITING) != 0) {
|
||||
if (dbuf->rl > 0) {
|
||||
mtx_lock(&scp->mtx);
|
||||
/* XXX Wait until we can write the data. */
|
||||
if ((mpu_status(scp) & MPU_OUTPUTBUSY) == 0) {
|
||||
/* Send the data. */
|
||||
midibuf_output_intr(dbuf, &c, sizeof(c));
|
||||
mpu_writedata(scp, c);
|
||||
/* We are playing now. */
|
||||
devinfo->flags |= MIDI_F_WRITING;
|
||||
}
|
||||
mtx_unlock(&scp->mtx);
|
||||
}
|
||||
}
|
||||
|
||||
/* De we have still more? */
|
||||
if ((devinfo->flags & MIDI_F_WRITING) != 0)
|
||||
/* Handle them on the next interrupt. */
|
||||
mpu_timeout(scp);
|
||||
#else
|
||||
while ((devinfo->flags & MIDI_F_WRITING) != 0 && dbuf->rl > 0) {
|
||||
/* XXX Wait until we can write the data. */
|
||||
while ((mpu_status(scp) & MPU_OUTPUTBUSY) != 0);
|
||||
/* Send the data. */
|
||||
midibuf_output_intr(dbuf, &c, sizeof(c));
|
||||
mpu_writedata(scp, c);
|
||||
/* We are playing now. */
|
||||
devinfo->flags |= MIDI_F_WRITING;
|
||||
}
|
||||
/* Stop playing. */
|
||||
devinfo->flags &= ~MIDI_F_WRITING;
|
||||
#endif /* MPU_USEMICROTIMER */
|
||||
}
|
||||
|
||||
#if MPU_USEMICROTIMER
|
||||
/* Arm a timer. */
|
||||
static void
|
||||
mpu_timeout(sc_p scp)
|
||||
{
|
||||
microtimeout(mpu_timer, scp, hz * hzmul / 3125);
|
||||
}
|
||||
|
||||
/* Called when a timer has beeped. */
|
||||
static void
|
||||
mpu_timer(void *arg)
|
||||
{
|
||||
sc_p scp;
|
||||
|
||||
scp = arg;
|
||||
mpu_xmit(scp);
|
||||
}
|
||||
#endif /* MPU_USEMICROTIMER */
|
||||
|
||||
/* Reset mpu. */
|
||||
static int
|
||||
@ -636,11 +595,13 @@ mpu_resetmode(sc_p scp)
|
||||
|
||||
/* Reset the mpu. */
|
||||
resp = 0;
|
||||
mtx_lock(&scp->mtx);
|
||||
for (i = 0 ; i < MPU_TRYDATA ; i++) {
|
||||
resp = mpu_command(scp, MPU_RESET);
|
||||
if (resp == 0)
|
||||
break;
|
||||
}
|
||||
mtx_unlock(&scp->mtx);
|
||||
if (resp != 0)
|
||||
return (1);
|
||||
|
||||
@ -656,11 +617,13 @@ mpu_uartmode(sc_p scp)
|
||||
|
||||
/* Switch to uart mode. */
|
||||
resp = 0;
|
||||
mtx_lock(&scp->mtx);
|
||||
for (i = 0 ; i < MPU_TRYDATA ; i++) {
|
||||
resp = mpu_command(scp, MPU_UART);
|
||||
if (resp == 0)
|
||||
break;
|
||||
}
|
||||
mtx_unlock(&scp->mtx);
|
||||
if (resp != 0)
|
||||
return (1);
|
||||
|
||||
@ -675,11 +638,13 @@ mpu_waitack(sc_p scp)
|
||||
int i, resp;
|
||||
|
||||
resp = 0;
|
||||
mtx_lock(&scp->mtx);
|
||||
for (i = 0 ; i < MPU_TRYDATA ; i++) {
|
||||
resp = mpu_readdata(scp);
|
||||
if (resp >= 0)
|
||||
break;
|
||||
}
|
||||
mtx_unlock(&scp->mtx);
|
||||
if (resp != MPU_ACK)
|
||||
return (1);
|
||||
|
||||
|
@ -457,6 +457,8 @@ struct opl_softc {
|
||||
device_t dev; /* device information */
|
||||
mididev_info *devinfo; /* midi device information */
|
||||
|
||||
struct mtx mtx; /* Mutex to protect the device. */
|
||||
|
||||
struct resource *io; /* Base of io port */
|
||||
int io_rid; /* Io resource ID */
|
||||
|
||||
@ -486,8 +488,6 @@ static int oplsbc_attach(device_t dev);
|
||||
|
||||
static d_open_t opl_open;
|
||||
static d_close_t opl_close;
|
||||
static d_read_t opl_read;
|
||||
static d_write_t opl_write;
|
||||
static d_ioctl_t opl_ioctl;
|
||||
static midi_callback_t opl_callback;
|
||||
|
||||
@ -496,7 +496,6 @@ static mdsy_readraw_t opl_readraw;
|
||||
static mdsy_writeraw_t opl_writeraw;
|
||||
|
||||
/* These functions are local. */
|
||||
static void opl_startplay(sc_p scp) __unused;
|
||||
static void opl_command(sc_p scp, int ch, int addr, u_int val);
|
||||
static int opl_status(sc_p scp);
|
||||
static void opl_enter4opmode(sc_p scp);
|
||||
@ -520,10 +519,7 @@ static mididev_info opl_op_desc = {
|
||||
|
||||
opl_open,
|
||||
opl_close,
|
||||
opl_read,
|
||||
opl_write,
|
||||
opl_ioctl,
|
||||
NULL,
|
||||
|
||||
opl_callback,
|
||||
|
||||
@ -643,18 +639,16 @@ opl_attach(device_t dev)
|
||||
{
|
||||
sc_p scp;
|
||||
mididev_info *devinfo;
|
||||
int unit, i, opl4_io, opl4_id;
|
||||
int i, opl4_io, opl4_id;
|
||||
struct resource *opl4;
|
||||
u_char signature, tmp;
|
||||
|
||||
scp = device_get_softc(dev);
|
||||
unit = device_get_unit(dev);
|
||||
|
||||
DEB(printf("opl%d: attaching.\n", unit));
|
||||
DEB(printf("opl: attaching.\n"));
|
||||
|
||||
/* Fill the softc for this unit. */
|
||||
scp->dev = dev;
|
||||
scp->devinfo = devinfo = create_mididev_info_unit(&unit, MDT_SYNTH);
|
||||
|
||||
/* Allocate other resources. */
|
||||
if (opl_allocres(scp, dev)) {
|
||||
@ -723,6 +717,7 @@ opl_attach(device_t dev)
|
||||
/* Fill the softc. */
|
||||
bcopy(&opl_synthinfo, &scp->synthinfo, sizeof(opl_synthinfo));
|
||||
snprintf(scp->synthinfo.name, 64, "Yamaha OPL%d FM", scp->model);
|
||||
mtx_init(&scp->mtx, "oplmid", MTX_DEF);
|
||||
bcopy(pv_map, scp->pv_map, sizeof(pv_map));
|
||||
if (scp->model < MODEL_OPL3) { /* OPL2. */
|
||||
scp->synthinfo.nr_voices = 9;
|
||||
@ -745,24 +740,19 @@ opl_attach(device_t dev)
|
||||
opl_command(scp, USE_RIGHT, CONNECTION_SELECT_REGISTER, 0);
|
||||
}
|
||||
|
||||
scp->devinfo = devinfo = create_mididev_info_unit(MDT_SYNTH, &opl_op_desc, &oplsynth_op_desc);
|
||||
|
||||
/* Fill the midi info. */
|
||||
bcopy(&opl_op_desc, devinfo, sizeof(opl_op_desc));
|
||||
midiinit(devinfo, dev);
|
||||
devinfo->flags = 0;
|
||||
bcopy(&oplsynth_op_desc, &devinfo->synth, sizeof(oplsynth_op_desc));
|
||||
devinfo->synth.readraw = opl_readraw;
|
||||
devinfo->synth.writeraw = opl_writeraw;
|
||||
devinfo->synth.alloc.max_voice = scp->synthinfo.nr_voices;
|
||||
strcpy(devinfo->name, scp->synthinfo.name);
|
||||
snprintf(devinfo->midistat, sizeof(devinfo->midistat), "at 0x%x", (u_int)rman_get_start(scp->io));
|
||||
|
||||
/* Init the queue. */
|
||||
devinfo->midi_dbuf_in.unit_size = devinfo->midi_dbuf_out.unit_size = 1;
|
||||
midibuf_init(&devinfo->midi_dbuf_in);
|
||||
midibuf_init(&devinfo->midi_dbuf_out);
|
||||
midiinit(devinfo, dev);
|
||||
|
||||
DEB(printf("opl%d: attached.\n", unit));
|
||||
DEB(printf("opl%d: the chip is OPL%d.\n", unit, scp->model));
|
||||
DEB(printf("opl: attached.\n"));
|
||||
DEB(printf("opl: the chip is OPL%d.\n", scp->model));
|
||||
|
||||
return (0);
|
||||
}
|
||||
@ -791,6 +781,7 @@ opl_open(dev_t i_dev, int flags, int mode, struct proc *p)
|
||||
}
|
||||
scp = devinfo->softc;
|
||||
|
||||
mtx_lock(&devinfo->synth.vc_mtx);
|
||||
if (scp->model < MODEL_OPL3)
|
||||
devinfo->synth.alloc.max_voice = 9;
|
||||
else
|
||||
@ -800,9 +791,13 @@ opl_open(dev_t i_dev, int flags, int mode, struct proc *p)
|
||||
devinfo->synth.alloc.map[i] = 0;
|
||||
devinfo->synth.alloc.alloc_times[i] = 0;
|
||||
}
|
||||
mtx_unlock(&devinfo->synth.vc_mtx);
|
||||
scp->cmask = 0; /* We are in 2 OP mode initially. */
|
||||
if (scp->model >= MODEL_OPL3)
|
||||
if (scp->model >= MODEL_OPL3) {
|
||||
mtx_lock(&scp->mtx);
|
||||
opl_command(scp, USE_RIGHT, CONNECTION_SELECT_REGISTER, scp->cmask);
|
||||
mtx_unlock(&scp->mtx);
|
||||
}
|
||||
|
||||
DEB(printf("opl%d: opened.\n", unit));
|
||||
|
||||
@ -827,10 +822,12 @@ opl_close(dev_t i_dev, int flags, int mode, struct proc *p)
|
||||
}
|
||||
scp = devinfo->softc;
|
||||
|
||||
mtx_lock(&devinfo->synth.vc_mtx);
|
||||
if (scp->model < MODEL_OPL3)
|
||||
devinfo->synth.alloc.max_voice = 9;
|
||||
else
|
||||
devinfo->synth.alloc.max_voice = 18;
|
||||
mtx_unlock(&devinfo->synth.vc_mtx);
|
||||
|
||||
/* Stop the OPL. */
|
||||
opl_reset(scp->devinfo);
|
||||
@ -840,61 +837,6 @@ opl_close(dev_t i_dev, int flags, int mode, struct proc *p)
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
opl_read(dev_t i_dev, struct uio *buf, int flag)
|
||||
{
|
||||
sc_p scp;
|
||||
mididev_info *devinfo;
|
||||
int unit, ret;
|
||||
|
||||
unit = MIDIUNIT(i_dev);
|
||||
|
||||
devinfo = get_mididev_info(i_dev, &unit);
|
||||
if (devinfo == NULL) {
|
||||
DEB(printf("opl_read: unit %d is not configured.\n", unit));
|
||||
return (ENXIO);
|
||||
}
|
||||
scp = devinfo->softc;
|
||||
if ((devinfo->fflags & FREAD) == 0) {
|
||||
DEB(printf("opl_read: unit %d is not for reading.\n", unit));
|
||||
return (EIO);
|
||||
}
|
||||
|
||||
/* Drain the data. */
|
||||
midibuf_init(&devinfo->midi_dbuf_in);
|
||||
ret = 0;
|
||||
|
||||
return (ret);
|
||||
}
|
||||
|
||||
static int
|
||||
opl_write(dev_t i_dev, struct uio *buf, int flag)
|
||||
{
|
||||
sc_p scp;
|
||||
mididev_info *devinfo;
|
||||
int unit, ret;
|
||||
|
||||
unit = MIDIUNIT(i_dev);
|
||||
|
||||
devinfo = get_mididev_info(i_dev, &unit);
|
||||
if (devinfo == NULL) {
|
||||
DEB(printf("opl_write: unit %d is not configured.\n", unit));
|
||||
return (ENXIO);
|
||||
}
|
||||
scp = devinfo->softc;
|
||||
if ((devinfo->fflags & FWRITE) == 0) {
|
||||
DEB(printf("opl_write: unit %d is not for writing.\n", unit));
|
||||
return (EIO);
|
||||
}
|
||||
|
||||
/* Drain the data. */
|
||||
midibuf_init(&devinfo->midi_dbuf_out);
|
||||
midibuf_init(&devinfo->midi_dbuf_passthru);
|
||||
ret = 0;
|
||||
|
||||
return (ret);
|
||||
}
|
||||
|
||||
static int
|
||||
opl_ioctl(dev_t i_dev, u_long cmd, caddr_t arg, int mode, struct proc *p)
|
||||
{
|
||||
@ -923,10 +865,9 @@ opl_ioctl(dev_t i_dev, u_long cmd, caddr_t arg, int mode, struct proc *p)
|
||||
return (ENXIO);
|
||||
bcopy(&scp->synthinfo, synthinfo, sizeof(scp->synthinfo));
|
||||
synthinfo->device = unit;
|
||||
if (devinfo->synth.alloc.max_voice == 12)
|
||||
synthinfo->nr_voices = devinfo->synth.alloc.max_voice;
|
||||
if (synthinfo->nr_voices == 12)
|
||||
synthinfo->nr_voices = 6;
|
||||
else
|
||||
synthinfo->nr_voices = devinfo->synth.alloc.max_voice;
|
||||
return (0);
|
||||
break;
|
||||
case SNDCTL_MIDI_INFO:
|
||||
@ -971,6 +912,8 @@ opl_callback(mididev_info *devinfo, int reason)
|
||||
int unit;
|
||||
sc_p scp;
|
||||
|
||||
mtx_assert(&devinfo->flagqueue_mtx, MA_OWNED);
|
||||
|
||||
if (devinfo == NULL) {
|
||||
DEB(printf("opl_callback: device not configured.\n"));
|
||||
return (ENXIO);
|
||||
@ -1059,21 +1002,26 @@ opl_killnote(mididev_info *md, int voice, int note, int vel)
|
||||
if (voice < 0 || voice >= md->synth.alloc.max_voice)
|
||||
return (0);
|
||||
|
||||
mtx_lock(&md->synth.vc_mtx);
|
||||
|
||||
md->synth.alloc.map[voice] = 0;
|
||||
mtx_lock(&scp->mtx);
|
||||
map = &scp->pv_map[scp->lv_map[voice]];
|
||||
|
||||
if (map->voice_mode == VOICE_NONE)
|
||||
return (0);
|
||||
if (map->voice_mode != VOICE_NONE) {
|
||||
opl_command(scp, map->ch, KEYON_BLOCK + map->voice_num, scp->voc[voice].keyon_byte & ~0x20);
|
||||
|
||||
opl_command(scp, map->ch, KEYON_BLOCK + map->voice_num, scp->voc[voice].keyon_byte & ~0x20);
|
||||
scp->voc[voice].keyon_byte = 0;
|
||||
scp->voc[voice].bender = 0;
|
||||
scp->voc[voice].volume = 64;
|
||||
scp->voc[voice].bender_range = 200;
|
||||
scp->voc[voice].orig_freq = 0;
|
||||
scp->voc[voice].current_freq = 0;
|
||||
scp->voc[voice].mode = 0;
|
||||
}
|
||||
|
||||
scp->voc[voice].keyon_byte = 0;
|
||||
scp->voc[voice].bender = 0;
|
||||
scp->voc[voice].volume = 64;
|
||||
scp->voc[voice].bender_range = 200;
|
||||
scp->voc[voice].orig_freq = 0;
|
||||
scp->voc[voice].current_freq = 0;
|
||||
scp->voc[voice].mode = 0;
|
||||
mtx_unlock(&scp->mtx);
|
||||
mtx_unlock(&md->synth.vc_mtx);
|
||||
|
||||
return (0);
|
||||
}
|
||||
@ -1093,7 +1041,9 @@ opl_setinstr(mididev_info *md, int voice, int instr_no)
|
||||
if (voice < 0 || voice >= md->synth.alloc.max_voice || instr_no < 0 || instr_no >= SBFM_MAXINSTR)
|
||||
return (0);
|
||||
|
||||
mtx_lock(&scp->mtx);
|
||||
scp->act_i[voice] = &scp->i_map[instr_no];
|
||||
mtx_unlock(&scp->mtx);
|
||||
|
||||
return (0);
|
||||
}
|
||||
@ -1115,13 +1065,17 @@ opl_startnote(mididev_info *md, int voice, int note, int volume)
|
||||
if (voice < 0 || voice >= md->synth.alloc.max_voice)
|
||||
return (0);
|
||||
|
||||
mtx_lock(&scp->mtx);
|
||||
map = &scp->pv_map[scp->lv_map[voice]];
|
||||
if (map->voice_mode == VOICE_NONE)
|
||||
if (map->voice_mode == VOICE_NONE) {
|
||||
mtx_unlock(&scp->mtx);
|
||||
return (0);
|
||||
}
|
||||
|
||||
if (note == 255) {
|
||||
/* Change the volume. */
|
||||
opl_setvoicevolume(scp, voice, volume, scp->voc[voice].volume);
|
||||
mtx_unlock(&scp->mtx);
|
||||
return (0);
|
||||
}
|
||||
|
||||
@ -1138,10 +1092,12 @@ opl_startnote(mididev_info *md, int voice, int note, int volume)
|
||||
if (instr == NULL)
|
||||
instr = &scp->i_map[0];
|
||||
if (instr->channel < 0) {
|
||||
mtx_unlock(&scp->mtx);
|
||||
printf("opl_startnote: the instrument for voice %d is undefined.\n", voice);
|
||||
return (0);
|
||||
}
|
||||
if (map->voice_mode == VOICE_2OP && instr->key == OPL3_PATCH) {
|
||||
mtx_unlock(&scp->mtx);
|
||||
printf("opl_startnote: the voice mode %d mismatches the key 0x%x.\n", map->voice_mode, instr->key);
|
||||
return (0);
|
||||
}
|
||||
@ -1208,6 +1164,8 @@ opl_startnote(mididev_info *md, int voice, int note, int volume)
|
||||
if (voice_mode == VOICE_4OP)
|
||||
opl_command(scp, map->ch, KEYON_BLOCK + map->voice_num + 3, scp->voc[voice].keyon_byte);
|
||||
|
||||
mtx_unlock(&scp->mtx);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
@ -1216,12 +1174,16 @@ opl_reset(mididev_info *md)
|
||||
{
|
||||
int unit, i;
|
||||
sc_p scp;
|
||||
struct physical_voice_info *map;
|
||||
|
||||
scp = md->softc;
|
||||
unit = md->unit;
|
||||
|
||||
DEB(printf("opl%d: resetting.\n", unit));
|
||||
|
||||
mtx_lock(&md->synth.vc_mtx);
|
||||
mtx_lock(&scp->mtx);
|
||||
|
||||
for (i = 0 ; i < MAX_VOICE ; i++)
|
||||
scp->lv_map[i] = i;
|
||||
|
||||
@ -1232,14 +1194,35 @@ opl_reset(mididev_info *md)
|
||||
opl_command(scp, scp->pv_map[scp->lv_map[i]].ch, KSL_LEVEL + scp->pv_map[scp->lv_map[i]].op[2], 0xff);
|
||||
opl_command(scp, scp->pv_map[scp->lv_map[i]].ch, KSL_LEVEL + scp->pv_map[scp->lv_map[i]].op[3], 0xff);
|
||||
}
|
||||
opl_killnote(md, i, 0, 64);
|
||||
/*
|
||||
* opl_killnote(md, i, 0, 64) inline-expanded to avoid
|
||||
* unlocking and relocking mutex unnecessarily.
|
||||
*/
|
||||
md->synth.alloc.map[i] = 0;
|
||||
map = &scp->pv_map[scp->lv_map[i]];
|
||||
|
||||
if (map->voice_mode != VOICE_NONE) {
|
||||
opl_command(scp, map->ch, KEYON_BLOCK + map->voice_num, scp->voc[i].keyon_byte & ~0x20);
|
||||
|
||||
scp->voc[i].keyon_byte = 0;
|
||||
scp->voc[i].bender = 0;
|
||||
scp->voc[i].volume = 64;
|
||||
scp->voc[i].bender_range = 200;
|
||||
scp->voc[i].orig_freq = 0;
|
||||
scp->voc[i].current_freq = 0;
|
||||
scp->voc[i].mode = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (scp->model >= MODEL_OPL3) {
|
||||
md->synth.alloc.max_voice = 18;
|
||||
for (i = 0 ; i < MAX_VOICE ; i++)
|
||||
scp->pv_map[i].voice_mode = VOICE_2OP;
|
||||
}
|
||||
|
||||
mtx_unlock(&md->synth.vc_mtx);
|
||||
mtx_unlock(&scp->mtx);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
@ -1283,12 +1266,12 @@ opl_panning(mididev_info *md, int chn, int pan)
|
||||
return (0);
|
||||
}
|
||||
|
||||
#define SET_VIBRATO(cell) { \
|
||||
int tmp; \
|
||||
tmp = instr->operators[(cell-1)+(((cell-1)/2)*OFFS_4OP)]; \
|
||||
if (press > 110) \
|
||||
tmp |= 0x40; /* Vibrato on */ \
|
||||
opl_command(scp, map->ch, AM_VIB + map->op[cell-1], tmp);}
|
||||
#define SET_VIBRATO(cell) do { \
|
||||
int tmp; \
|
||||
tmp = instr->operators[(cell-1)+(((cell-1)/2)*OFFS_4OP)]; \
|
||||
if (press > 110) \
|
||||
tmp |= 0x40; /* Vibrato on */ \
|
||||
opl_command(scp, map->ch, AM_VIB + map->op[cell-1], tmp);} while(0);
|
||||
|
||||
static int
|
||||
opl_aftertouch(mididev_info *md, int voice, int press)
|
||||
@ -1306,9 +1289,13 @@ opl_aftertouch(mididev_info *md, int voice, int press)
|
||||
if (voice < 0 || voice >= md->synth.alloc.max_voice)
|
||||
return (0);
|
||||
|
||||
mtx_lock(&scp->mtx);
|
||||
|
||||
map = &scp->pv_map[scp->lv_map[voice]];
|
||||
if (map->voice_mode == VOICE_NONE)
|
||||
if (map->voice_mode == VOICE_NONE) {
|
||||
mtx_unlock(&scp->mtx);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* Adjust the vibrato. */
|
||||
instr = scp->act_i[voice];
|
||||
@ -1341,6 +1328,8 @@ opl_aftertouch(mididev_info *md, int voice, int press)
|
||||
SET_VIBRATO(2);
|
||||
}
|
||||
|
||||
mtx_unlock(&scp->mtx);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
@ -1356,14 +1345,18 @@ opl_bendpitch(sc_p scp, int voice, int value)
|
||||
|
||||
DEB(printf("opl%d: setting the pitch bend, voice %d, value %d.\n", unit, voice, value));
|
||||
|
||||
mtx_lock(&scp->mtx);
|
||||
|
||||
map = &scp->pv_map[scp->lv_map[voice]];
|
||||
if (map->voice_mode == 0)
|
||||
if (map->voice_mode == 0) {
|
||||
mtx_unlock(&scp->mtx);
|
||||
return (0);
|
||||
}
|
||||
scp->voc[voice].bender = value;
|
||||
if (value == 0)
|
||||
return (0);
|
||||
if ((scp->voc[voice].keyon_byte & 0x20) == 0)
|
||||
if (value == 0 || (scp->voc[voice].keyon_byte & 0x20) == 0) {
|
||||
mtx_unlock(&scp->mtx);
|
||||
return (0);
|
||||
}
|
||||
|
||||
freq = opl_computefinetune(scp->voc[voice].orig_freq, scp->voc[voice].bender, scp->voc[voice].bender_range);
|
||||
scp->voc[voice].current_freq = freq;
|
||||
@ -1376,6 +1369,8 @@ opl_bendpitch(sc_p scp, int voice, int value)
|
||||
if (map->voice_mode == VOICE_4OP)
|
||||
opl_command(scp, map->ch, KEYON_BLOCK + map->voice_num + 3, scp->voc[voice].keyon_byte);
|
||||
|
||||
mtx_unlock(&scp->mtx);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
@ -1398,10 +1393,14 @@ opl_controller(mididev_info *md, int voice, int ctrlnum, int val)
|
||||
opl_bendpitch(scp, voice, val);
|
||||
break;
|
||||
case CTRL_PITCH_BENDER_RANGE:
|
||||
mtx_lock(&scp->mtx);
|
||||
scp->voc[voice].bender_range = val;
|
||||
mtx_unlock(&scp->mtx);
|
||||
break;
|
||||
case CTRL_MAIN_VOLUME:
|
||||
mtx_lock(&scp->mtx);
|
||||
scp->voc[voice].volume = val / 128;
|
||||
mtx_unlock(&scp->mtx);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -1440,11 +1439,15 @@ opl_allocvoice(mididev_info *md, int chn, int note, struct voice_alloc_info *all
|
||||
|
||||
best_time = 0x7fffffff;
|
||||
|
||||
mtx_lock(&md->synth.vc_mtx);
|
||||
|
||||
if (chn < 0 || chn >= 15)
|
||||
instr_no = 0;
|
||||
else
|
||||
instr_no = md->synth.chn_info[chn].pgm_num;
|
||||
|
||||
mtx_lock(&scp->mtx);
|
||||
|
||||
instr = &scp->i_map[instr_no];
|
||||
if (instr->channel < 0 || md->synth.alloc.max_voice != 12)
|
||||
is4op = 0;
|
||||
@ -1485,6 +1488,9 @@ opl_allocvoice(mididev_info *md, int chn, int note, struct voice_alloc_info *all
|
||||
else if (best > md->synth.alloc.max_voice)
|
||||
best -= md->synth.alloc.max_voice;
|
||||
|
||||
mtx_unlock(&scp->mtx);
|
||||
mtx_unlock(&md->synth.vc_mtx);
|
||||
|
||||
return best;
|
||||
}
|
||||
|
||||
@ -1498,11 +1504,17 @@ opl_setupvoice(mididev_info *md, int voice, int chn)
|
||||
|
||||
DEB(printf("opl%d: setting up a voice, voice %d, chn %d.\n", unit, voice, chn));
|
||||
|
||||
mtx_lock(&md->synth.vc_mtx);
|
||||
|
||||
info = &md->synth.chn_info[chn];
|
||||
|
||||
opl_setinstr(md, voice, info->pgm_num);
|
||||
mtx_lock(&scp->mtx);
|
||||
scp->voc[voice].bender = info->bender_value;
|
||||
scp->voc[voice].volume = info->controllers[CTL_MAIN_VOLUME];
|
||||
mtx_unlock(&scp->mtx);
|
||||
|
||||
mtx_lock(&md->synth.vc_mtx);
|
||||
|
||||
return (0);
|
||||
}
|
||||
@ -1532,25 +1544,6 @@ opl_volumemethod(mididev_info *md, int mode)
|
||||
* The functions below here are the libraries for the above ones.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Starts to play the data in the output queue.
|
||||
* Call this at >=splmidi.
|
||||
*/
|
||||
static void
|
||||
opl_startplay(sc_p scp)
|
||||
{
|
||||
mididev_info *devinfo;
|
||||
|
||||
devinfo = scp->devinfo;
|
||||
|
||||
/* Can we play now? */
|
||||
if (devinfo->midi_dbuf_out.rl == 0)
|
||||
return;
|
||||
|
||||
/* Begin playing. */
|
||||
devinfo->callback(devinfo, MIDI_CB_START | MIDI_CB_WR);
|
||||
}
|
||||
|
||||
/* Writes a command to the OPL chip. */
|
||||
static void
|
||||
opl_command(sc_p scp, int ch, int addr, u_int val)
|
||||
@ -1603,6 +1596,8 @@ opl_enter4opmode(sc_p scp)
|
||||
DEB(printf("opl%d: entering 4 OP mode.\n", unit));
|
||||
|
||||
/* Connect all possible 4 OP voice operators. */
|
||||
mtx_lock(&devinfo->synth.vc_mtx);
|
||||
mtx_lock(&scp->mtx);
|
||||
scp->cmask = 0x3f;
|
||||
opl_command(scp, USE_RIGHT, CONNECTION_SELECT_REGISTER, scp->cmask);
|
||||
|
||||
@ -1617,7 +1612,9 @@ opl_enter4opmode(sc_p scp)
|
||||
|
||||
for (i = 0 ; i < 12 ; i++)
|
||||
scp->lv_map[i] = v4op[i];
|
||||
mtx_unlock(&scp->mtx);
|
||||
devinfo->synth.alloc.max_voice = 12;
|
||||
mtx_unlock(&devinfo->synth.vc_mtx);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -101,6 +101,8 @@ struct uartsio_softc {
|
||||
device_t dev; /* device information */
|
||||
mididev_info *devinfo; /* midi device information */
|
||||
|
||||
struct mtx mtx; /* Mutex to protect the device. */
|
||||
|
||||
struct resource *io; /* Base of io port */
|
||||
int io_rid; /* Io resource ID */
|
||||
struct resource *irq; /* Irq */
|
||||
@ -132,12 +134,9 @@ static mididev_info uartsio_op_desc = {
|
||||
|
||||
SNDCARD_UART16550,
|
||||
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
uartsio_ioctl,
|
||||
NULL,
|
||||
|
||||
uartsio_callback,
|
||||
|
||||
@ -201,12 +200,10 @@ uartsio_attach(device_t dev)
|
||||
{
|
||||
sc_p scp;
|
||||
mididev_info *devinfo;
|
||||
int unit;
|
||||
|
||||
scp = device_get_softc(dev);
|
||||
unit = device_get_unit(dev);
|
||||
|
||||
DEB(printf("uartsio%d: attaching.\n", unit));
|
||||
DEB(printf("uartsio: attaching.\n"));
|
||||
|
||||
/* Allocate resources. */
|
||||
if (uartsio_allocres(scp, dev)) {
|
||||
@ -219,31 +216,13 @@ uartsio_attach(device_t dev)
|
||||
if ((uartsio_readport(scp, com_iir) & IIR_FIFO_MASK) == FIFO_RX_HIGH) {
|
||||
scp->has_fifo = 1;
|
||||
scp->tx_size = TX_FIFO_SIZE;
|
||||
DEB(printf("uartsio%d: uart is 16550A, tx size is %d bytes.\n", unit, scp->tx_size));
|
||||
DEB(printf("uartsio: uart is 16550A, tx size is %d bytes.\n", scp->tx_size));
|
||||
} else {
|
||||
scp->has_fifo = 0;
|
||||
scp->tx_size = 1;
|
||||
DEB(printf("uartsio%d: uart is not 16550A.\n", unit));
|
||||
DEB(printf("uartsio: uart is not 16550A.\n"));
|
||||
}
|
||||
|
||||
/* Fill the softc. */
|
||||
scp->dev = dev;
|
||||
scp->devinfo = devinfo = create_mididev_info_unit(&unit, MDT_MIDI);
|
||||
|
||||
/* Fill the midi info. */
|
||||
bcopy(&uartsio_op_desc, devinfo, sizeof(uartsio_op_desc));
|
||||
midiinit(devinfo, dev);
|
||||
devinfo->flags = 0;
|
||||
bcopy(&midisynth_op_desc, &devinfo->synth, sizeof(midisynth_op_desc));
|
||||
snprintf(devinfo->midistat, sizeof(devinfo->midistat), "at 0x%x irq %d",
|
||||
(u_int)rman_get_start(scp->io), (int)rman_get_start(scp->irq));
|
||||
|
||||
/* Init the queue. */
|
||||
devinfo->midi_dbuf_in.unit_size = devinfo->midi_dbuf_out.unit_size = 1;
|
||||
midibuf_init(&devinfo->midi_dbuf_in);
|
||||
midibuf_init(&devinfo->midi_dbuf_out);
|
||||
midibuf_init(&devinfo->midi_dbuf_passthru);
|
||||
|
||||
/* Configure the uart. */
|
||||
uartsio_writeport(scp, com_cfcr, CFCR_DLAB); /* Latch the divisor. */
|
||||
uartsio_writeport(scp, com_dlbl, 0x03);
|
||||
@ -262,10 +241,21 @@ uartsio_attach(device_t dev)
|
||||
uartsio_readport(scp, com_iir);
|
||||
uartsio_readport(scp, com_data);
|
||||
|
||||
/* Fill the softc. */
|
||||
scp->dev = dev;
|
||||
mtx_init(&scp->mtx, "siomid", MTX_DEF);
|
||||
scp->devinfo = devinfo = create_mididev_info_unit(MDT_MIDI, &uartsio_op_desc, &midisynth_op_desc);
|
||||
|
||||
/* Fill the midi info. */
|
||||
snprintf(devinfo->midistat, sizeof(devinfo->midistat), "at 0x%x irq %d",
|
||||
(u_int)rman_get_start(scp->io), (int)rman_get_start(scp->irq));
|
||||
|
||||
midiinit(devinfo, dev);
|
||||
|
||||
/* Now we can handle the interrupts. */
|
||||
bus_setup_intr(dev, scp->irq, INTR_TYPE_TTY, uartsio_intr, scp, &scp->ih);
|
||||
|
||||
DEB(printf("uartsio%d: attached.\n", unit));
|
||||
DEB(printf("uartsio: attached.\n"));
|
||||
|
||||
return (0);
|
||||
}
|
||||
@ -321,10 +311,16 @@ uartsio_intr(void *arg)
|
||||
scp = (sc_p)arg;
|
||||
devinfo = scp->devinfo;
|
||||
|
||||
MIDI_DROP_GIANT_NOSWITCH();
|
||||
|
||||
mtx_lock(&devinfo->flagqueue_mtx);
|
||||
uartsio_xmit(scp);
|
||||
mtx_unlock(&devinfo->flagqueue_mtx);
|
||||
|
||||
/* Invoke the upper layer. */
|
||||
midi_intr(devinfo);
|
||||
|
||||
MIDI_PICKUP_GIANT();
|
||||
}
|
||||
|
||||
static int
|
||||
@ -333,6 +329,8 @@ uartsio_callback(mididev_info *d, int reason)
|
||||
int unit;
|
||||
sc_p scp;
|
||||
|
||||
mtx_assert(&d->flagqueue_mtx, MA_OWNED);
|
||||
|
||||
if (d == NULL) {
|
||||
DEB(printf("uartsio_callback: device not configured.\n"));
|
||||
return (ENXIO);
|
||||
@ -347,7 +345,6 @@ uartsio_callback(mididev_info *d, int reason)
|
||||
/* Begin recording. */
|
||||
d->flags |= MIDI_F_READING;
|
||||
if ((reason & MIDI_CB_WR) != 0 && (d->flags & MIDI_F_WRITING) == 0)
|
||||
/* Start playing. */
|
||||
uartsio_startplay(scp);
|
||||
break;
|
||||
case MIDI_CB_STOP:
|
||||
@ -370,7 +367,6 @@ uartsio_callback(mididev_info *d, int reason)
|
||||
|
||||
/*
|
||||
* Starts to play the data in the output queue.
|
||||
* Call this at >=splmidi.
|
||||
*/
|
||||
static void
|
||||
uartsio_startplay(sc_p scp)
|
||||
@ -379,6 +375,8 @@ uartsio_startplay(sc_p scp)
|
||||
|
||||
devinfo = scp->devinfo;
|
||||
|
||||
mtx_assert(&devinfo->flagqueue_mtx, MA_OWNED);
|
||||
|
||||
/* Can we play now? */
|
||||
if (devinfo->midi_dbuf_out.rl == 0)
|
||||
return;
|
||||
@ -397,7 +395,10 @@ uartsio_xmit(sc_p scp)
|
||||
|
||||
devinfo = scp->devinfo;
|
||||
|
||||
do {
|
||||
mtx_assert(&devinfo->flagqueue_mtx, MA_OWNED);
|
||||
|
||||
mtx_lock(&scp->mtx);
|
||||
for (;;) {
|
||||
/* Read the received data. */
|
||||
while (((lsr = uartsio_readport(scp, com_lsr)) & LSR_RCV_MASK) != 0) {
|
||||
/* Is this a data or an error/break? */
|
||||
@ -406,6 +407,7 @@ uartsio_xmit(sc_p scp)
|
||||
else {
|
||||
/* Receive the data. */
|
||||
c[0] = uartsio_readport(scp, com_data);
|
||||
mtx_unlock(&scp->mtx);
|
||||
/* Queue into the passthru buffer and start transmitting if we can. */
|
||||
if ((devinfo->flags & MIDI_F_PASSTHRU) != 0 && ((devinfo->flags & MIDI_F_BUSY) == 0 || (devinfo->fflags & FWRITE) == 0)) {
|
||||
midibuf_input_intr(&devinfo->midi_dbuf_passthru, &c[0], sizeof(c[0]));
|
||||
@ -414,11 +416,10 @@ uartsio_xmit(sc_p scp)
|
||||
/* Queue if we are reading. Discard an active sensing. */
|
||||
if ((devinfo->flags & MIDI_F_READING) != 0 && c[0] != 0xfe)
|
||||
midibuf_input_intr(&devinfo->midi_dbuf_in, &c[0], sizeof(c[0]));
|
||||
mtx_lock(&scp->mtx);
|
||||
}
|
||||
}
|
||||
|
||||
/* Read MSR. */
|
||||
msr = uartsio_readport(scp, com_msr);
|
||||
mtx_unlock(&scp->mtx);
|
||||
|
||||
/* See which source to use. */
|
||||
if ((devinfo->flags & MIDI_F_PASSTHRU) == 0 || ((devinfo->flags & MIDI_F_BUSY) != 0 && (devinfo->fflags & FWRITE) != 0))
|
||||
@ -427,30 +428,41 @@ uartsio_xmit(sc_p scp)
|
||||
dbuf = &devinfo->midi_dbuf_passthru;
|
||||
|
||||
/* Transmit the data in the queue. */
|
||||
if ((devinfo->flags & MIDI_F_WRITING) != 0 && (lsr & LSR_TXRDY) != 0 && (msr & MSR_CTS) != 0) {
|
||||
|
||||
if ((devinfo->flags & MIDI_F_WRITING) != 0) {
|
||||
/* Do we have the data to transmit? */
|
||||
if (dbuf->rl == 0) {
|
||||
/* Stop playing. */
|
||||
devinfo->flags &= ~MIDI_F_WRITING;
|
||||
} else {
|
||||
/* send the data. */
|
||||
txsize = scp->tx_size;
|
||||
if (dbuf->rl < txsize)
|
||||
txsize = dbuf->rl;
|
||||
midibuf_output_intr(dbuf, c, txsize);
|
||||
for (i = 0 ; i < txsize ; i++)
|
||||
uartsio_writeport(scp, com_data, c[i]);
|
||||
/* We are playing now. */
|
||||
devinfo->flags |= MIDI_F_WRITING;
|
||||
mtx_lock(&scp->mtx);
|
||||
/* Read LSR and MSR. */
|
||||
lsr = uartsio_readport(scp, com_lsr);
|
||||
msr = uartsio_readport(scp, com_msr);
|
||||
/* Is the device ready?. */
|
||||
if ((lsr & LSR_TXRDY) != 0 && (msr & MSR_CTS) != 0) {
|
||||
/* send the data. */
|
||||
txsize = scp->tx_size;
|
||||
if (dbuf->rl < txsize)
|
||||
txsize = dbuf->rl;
|
||||
midibuf_output_intr(dbuf, c, txsize);
|
||||
for (i = 0 ; i < txsize ; i++)
|
||||
uartsio_writeport(scp, com_data, c[i]);
|
||||
/* We are playing now. */
|
||||
devinfo->flags |= MIDI_F_WRITING;
|
||||
} else {
|
||||
/* Do we have the data to transmit? */
|
||||
if (dbuf->rl > 0)
|
||||
/* Wait for the next interrupt. */
|
||||
devinfo->flags |= MIDI_F_WRITING;
|
||||
}
|
||||
mtx_unlock(&scp->mtx);
|
||||
}
|
||||
} else {
|
||||
/* Do we have the data to transmit? */
|
||||
if (dbuf->rl > 0)
|
||||
/* Wait for the next interrupt. */
|
||||
devinfo->flags |= MIDI_F_WRITING;
|
||||
}
|
||||
} while (((iir = uartsio_readport(scp, com_iir)) & IIR_IMASK) != IIR_NOPEND);
|
||||
mtx_lock(&scp->mtx);
|
||||
if (((iir = uartsio_readport(scp, com_iir)) & IIR_IMASK) == IIR_NOPEND)
|
||||
break;
|
||||
}
|
||||
mtx_unlock(&scp->mtx);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
@ -38,7 +38,7 @@
|
||||
* board-specific probe routine. If successful, a pointer to the
|
||||
* correct mididev_info is stored in mididev_last_probed, for subsequent
|
||||
* use in the attach routine. The generic attach routine copies
|
||||
* the template to a permanent descriptor (midi_info[unit] and
|
||||
* the template to a permanent descriptor (midi_info and
|
||||
* friends), initializes all generic parameters, and calls the
|
||||
* board-specific attach routine.
|
||||
*
|
||||
@ -90,8 +90,11 @@ static struct cdevsw midi_cdevsw = {
|
||||
* descriptors for active devices. also used as the public softc
|
||||
* of a device.
|
||||
*/
|
||||
static mididev_info midi_info[NMIDI_MAX];
|
||||
static TAILQ_HEAD(,_mididev_info) midi_info;
|
||||
static int nmidi, nsynth;
|
||||
/* Mutex to protect midi_info, nmidi and nsynth. */
|
||||
static struct mtx midiinfo_mtx;
|
||||
static int midiinfo_mtx_init;
|
||||
|
||||
/* These make the buffer for /dev/midistat */
|
||||
static int midistatbusy;
|
||||
@ -99,33 +102,39 @@ static char midistatbuf[4096];
|
||||
static int midistatptr;
|
||||
|
||||
/*
|
||||
* This is the generic init routine
|
||||
* This is the generic init routine.
|
||||
* Must be called after device-specific init.
|
||||
*/
|
||||
int
|
||||
midiinit(mididev_info *d, device_t dev)
|
||||
{
|
||||
int unit;
|
||||
|
||||
if (midi_devclass == NULL) {
|
||||
midi_devclass = device_get_devclass(dev);
|
||||
make_dev(&midi_cdevsw, MIDIMKMINOR(0, MIDI_DEV_STATUS),
|
||||
UID_ROOT, GID_WHEEL, 0444, "midistat");
|
||||
}
|
||||
|
||||
unit = device_get_unit(dev);
|
||||
make_dev(&midi_cdevsw, MIDIMKMINOR(unit, MIDI_DEV_MIDIN),
|
||||
UID_ROOT, GID_WHEEL, 0666, "midi%d", unit);
|
||||
|
||||
/*
|
||||
* initialize standard parameters for the device. This can be
|
||||
* overridden by device-specific configurations but better do
|
||||
* here the generic things.
|
||||
*/
|
||||
|
||||
d->unit = device_get_unit(dev);
|
||||
unit = d->unit;
|
||||
d->softc = device_get_softc(dev);
|
||||
d->dev = dev;
|
||||
d->magic = MAGIC(d->unit); /* debugging... */
|
||||
d->flags = 0;
|
||||
d->fflags = 0;
|
||||
d->midi_dbuf_in.unit_size = 1;
|
||||
d->midi_dbuf_out.unit_size = 1;
|
||||
d->midi_dbuf_passthru.unit_size = 1;
|
||||
|
||||
mtx_unlock(&d->flagqueue_mtx);
|
||||
|
||||
if (midi_devclass == NULL) {
|
||||
midi_devclass = device_get_devclass(dev);
|
||||
make_dev(&midi_cdevsw, MIDIMKMINOR(0, MIDI_DEV_STATUS),
|
||||
UID_ROOT, GID_WHEEL, 0444, "midistat");
|
||||
}
|
||||
make_dev(&midi_cdevsw, MIDIMKMINOR(unit, MIDI_DEV_MIDIN),
|
||||
UID_ROOT, GID_WHEEL, 0666, "midi%d", unit);
|
||||
|
||||
return 0 ;
|
||||
}
|
||||
@ -156,21 +165,55 @@ get_mididev_info(dev_t i_dev, int *unit)
|
||||
mididev_info *
|
||||
get_mididev_info_unit(int unit)
|
||||
{
|
||||
mididev_info *d;
|
||||
mididev_info *md;
|
||||
|
||||
if (unit >= nmidi + nsynth) {
|
||||
DEB(printf("get_mididev_info_unit: unit %d is not configured.\n", u));
|
||||
return NULL;
|
||||
/* XXX */
|
||||
if (!midiinfo_mtx_init) {
|
||||
midiinfo_mtx_init = 1;
|
||||
mtx_init(&midiinfo_mtx, "midinf", MTX_DEF);
|
||||
TAILQ_INIT(&midi_info);
|
||||
}
|
||||
d = &midi_info[unit];
|
||||
|
||||
return d;
|
||||
mtx_lock(&midiinfo_mtx);
|
||||
TAILQ_FOREACH(md, &midi_info, md_link) {
|
||||
if (md->unit == unit)
|
||||
break;
|
||||
}
|
||||
mtx_unlock(&midiinfo_mtx);
|
||||
|
||||
return md;
|
||||
}
|
||||
|
||||
/* Create a new midi device info structure. */
|
||||
/* TODO: lock md, then exit. */
|
||||
mididev_info *
|
||||
create_mididev_info_unit(int *unit, int type)
|
||||
create_mididev_info_unit(int type, mididev_info *mdinf, synthdev_info *syninf)
|
||||
{
|
||||
int unit;
|
||||
mididev_info *md, *mdnew;
|
||||
|
||||
/* XXX */
|
||||
if (!midiinfo_mtx_init) {
|
||||
midiinfo_mtx_init = 1;
|
||||
mtx_init(&midiinfo_mtx, "midinf", MTX_DEF);
|
||||
TAILQ_INIT(&midi_info);
|
||||
}
|
||||
|
||||
/* As malloc(9) might block, allocate mididev_info now. */
|
||||
mdnew = malloc(sizeof(mididev_info), M_DEVBUF, M_WAITOK | M_ZERO);
|
||||
if (mdnew == NULL)
|
||||
return NULL;
|
||||
bcopy(mdinf, mdnew, sizeof(mididev_info));
|
||||
bcopy(syninf, &mdnew->synth, sizeof(synthdev_info));
|
||||
midibuf_init(&mdnew->midi_dbuf_in);
|
||||
midibuf_init(&mdnew->midi_dbuf_out);
|
||||
midibuf_init(&mdnew->midi_dbuf_passthru);
|
||||
mtx_init(&mdnew->flagqueue_mtx, "midflq", MTX_DEF);
|
||||
mtx_init(&mdnew->synth.vc_mtx, "synsvc", MTX_DEF);
|
||||
mtx_init(&mdnew->synth.status_mtx, "synsst", MTX_DEF);
|
||||
|
||||
mtx_lock(&midiinfo_mtx);
|
||||
|
||||
/* XXX midi_info is still static. */
|
||||
switch (type) {
|
||||
case MDT_MIDI:
|
||||
@ -180,12 +223,34 @@ create_mididev_info_unit(int *unit, int type)
|
||||
nsynth++;
|
||||
break;
|
||||
default:
|
||||
mtx_unlock(&midiinfo_mtx);
|
||||
midibuf_destroy(&mdnew->midi_dbuf_in);
|
||||
midibuf_destroy(&mdnew->midi_dbuf_out);
|
||||
midibuf_destroy(&mdnew->midi_dbuf_passthru);
|
||||
mtx_destroy(&mdnew->flagqueue_mtx);
|
||||
mtx_destroy(&mdnew->synth.vc_mtx);
|
||||
mtx_destroy(&mdnew->synth.status_mtx);
|
||||
free(mdnew, M_DEVBUF);
|
||||
panic("unsupported device type");
|
||||
break;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
*unit = nmidi + nsynth - 1;
|
||||
return get_mididev_info_unit(*unit);
|
||||
for (unit = 0 ; ; unit++) {
|
||||
TAILQ_FOREACH(md, &midi_info, md_link) {
|
||||
if (md->unit == unit)
|
||||
break;
|
||||
}
|
||||
if (md == NULL)
|
||||
break;
|
||||
}
|
||||
|
||||
mdnew->unit = unit;
|
||||
mtx_lock(&mdnew->flagqueue_mtx);
|
||||
TAILQ_INSERT_TAIL(&midi_info, mdnew, md_link);
|
||||
|
||||
mtx_unlock(&midiinfo_mtx);
|
||||
|
||||
return mdnew;
|
||||
}
|
||||
|
||||
/* Return the number of configured devices. */
|
||||
@ -206,73 +271,136 @@ mididev_info_number(void)
|
||||
static int
|
||||
midiopen(dev_t i_dev, int flags, int mode, struct proc * p)
|
||||
{
|
||||
int ret;
|
||||
|
||||
MIDI_DROP_GIANT_NOSWITCH();
|
||||
|
||||
switch (MIDIDEV(i_dev)) {
|
||||
case MIDI_DEV_MIDIN:
|
||||
return midi_open(i_dev, flags, mode, p);
|
||||
ret = midi_open(i_dev, flags, mode, p);
|
||||
break;
|
||||
case MIDI_DEV_STATUS:
|
||||
return midistat_open(i_dev, flags, mode, p);
|
||||
ret = midistat_open(i_dev, flags, mode, p);
|
||||
break;
|
||||
default:
|
||||
ret = ENXIO;
|
||||
break;
|
||||
}
|
||||
|
||||
return (ENXIO);
|
||||
MIDI_PICKUP_GIANT();
|
||||
|
||||
return (ret);
|
||||
}
|
||||
|
||||
static int
|
||||
midiclose(dev_t i_dev, int flags, int mode, struct proc * p)
|
||||
{
|
||||
int ret;
|
||||
|
||||
MIDI_DROP_GIANT_NOSWITCH();
|
||||
|
||||
switch (MIDIDEV(i_dev)) {
|
||||
case MIDI_DEV_MIDIN:
|
||||
return midi_close(i_dev, flags, mode, p);
|
||||
ret = midi_close(i_dev, flags, mode, p);
|
||||
break;
|
||||
case MIDI_DEV_STATUS:
|
||||
return midistat_close(i_dev, flags, mode, p);
|
||||
ret = midistat_close(i_dev, flags, mode, p);
|
||||
break;
|
||||
default:
|
||||
ret = ENXIO;
|
||||
break;
|
||||
}
|
||||
|
||||
return (ENXIO);
|
||||
MIDI_PICKUP_GIANT();
|
||||
|
||||
return (ret);
|
||||
}
|
||||
|
||||
static int
|
||||
midiread(dev_t i_dev, struct uio * buf, int flag)
|
||||
{
|
||||
int ret;
|
||||
|
||||
MIDI_DROP_GIANT_NOSWITCH();
|
||||
|
||||
switch (MIDIDEV(i_dev)) {
|
||||
case MIDI_DEV_MIDIN:
|
||||
return midi_read(i_dev, buf, flag);
|
||||
ret = midi_read(i_dev, buf, flag);
|
||||
break;
|
||||
case MIDI_DEV_STATUS:
|
||||
return midistat_read(i_dev, buf, flag);
|
||||
ret = midistat_read(i_dev, buf, flag);
|
||||
break;
|
||||
default:
|
||||
ret = ENXIO;
|
||||
break;
|
||||
}
|
||||
|
||||
return (ENXIO);
|
||||
MIDI_PICKUP_GIANT();
|
||||
|
||||
return (ret);
|
||||
}
|
||||
|
||||
static int
|
||||
midiwrite(dev_t i_dev, struct uio * buf, int flag)
|
||||
{
|
||||
int ret;
|
||||
|
||||
MIDI_DROP_GIANT_NOSWITCH();
|
||||
|
||||
switch (MIDIDEV(i_dev)) {
|
||||
case MIDI_DEV_MIDIN:
|
||||
return midi_write(i_dev, buf, flag);
|
||||
ret = midi_write(i_dev, buf, flag);
|
||||
break;
|
||||
default:
|
||||
ret = ENXIO;
|
||||
break;
|
||||
}
|
||||
|
||||
return (ENXIO);
|
||||
MIDI_PICKUP_GIANT();
|
||||
|
||||
return (ret);
|
||||
}
|
||||
|
||||
static int
|
||||
midiioctl(dev_t i_dev, u_long cmd, caddr_t arg, int mode, struct proc * p)
|
||||
{
|
||||
int ret;
|
||||
|
||||
MIDI_DROP_GIANT_NOSWITCH();
|
||||
|
||||
switch (MIDIDEV(i_dev)) {
|
||||
case MIDI_DEV_MIDIN:
|
||||
return midi_ioctl(i_dev, cmd, arg, mode, p);
|
||||
ret = midi_ioctl(i_dev, cmd, arg, mode, p);
|
||||
break;
|
||||
default:
|
||||
ret = ENXIO;
|
||||
break;
|
||||
}
|
||||
|
||||
return (ENXIO);
|
||||
MIDI_PICKUP_GIANT();
|
||||
|
||||
return (ret);
|
||||
}
|
||||
|
||||
static int
|
||||
midipoll(dev_t i_dev, int events, struct proc * p)
|
||||
{
|
||||
int ret;
|
||||
|
||||
MIDI_DROP_GIANT_NOSWITCH();
|
||||
|
||||
switch (MIDIDEV(i_dev)) {
|
||||
case MIDI_DEV_MIDIN:
|
||||
return midi_poll(i_dev, events, p);
|
||||
ret = midi_poll(i_dev, events, p);
|
||||
break;
|
||||
default:
|
||||
ret = ENXIO;
|
||||
break;
|
||||
}
|
||||
|
||||
return (ENXIO);
|
||||
MIDI_PICKUP_GIANT();
|
||||
|
||||
return (ret);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -282,7 +410,7 @@ midipoll(dev_t i_dev, int events, struct proc * p)
|
||||
int
|
||||
midi_open(dev_t i_dev, int flags, int mode, struct proc * p)
|
||||
{
|
||||
int dev, unit, s, ret;
|
||||
int dev, unit, ret;
|
||||
mididev_info *d;
|
||||
|
||||
dev = minor(i_dev);
|
||||
@ -294,12 +422,11 @@ midi_open(dev_t i_dev, int flags, int mode, struct proc * p)
|
||||
if (d == NULL)
|
||||
return (ENXIO);
|
||||
|
||||
s = splmidi();
|
||||
|
||||
/* Mark this device busy. */
|
||||
mtx_lock(&d->flagqueue_mtx);
|
||||
device_busy(d->dev);
|
||||
if ((d->flags & MIDI_F_BUSY) != 0) {
|
||||
splx(s);
|
||||
mtx_unlock(&d->flagqueue_mtx);
|
||||
DEB(printf("opl_open: unit %d is busy.\n", unit));
|
||||
return (EBUSY);
|
||||
}
|
||||
@ -308,27 +435,27 @@ midi_open(dev_t i_dev, int flags, int mode, struct proc * p)
|
||||
d->fflags = flags;
|
||||
|
||||
/* Init the queue. */
|
||||
if ((d->fflags & FREAD) != 0)
|
||||
midibuf_init(&d->midi_dbuf_in);
|
||||
if ((d->fflags & FWRITE) != 0) {
|
||||
midibuf_init(&d->midi_dbuf_out);
|
||||
midibuf_init(&d->midi_dbuf_passthru);
|
||||
if ((flags & FREAD) != 0)
|
||||
midibuf_clear(&d->midi_dbuf_in);
|
||||
if ((flags & FWRITE) != 0) {
|
||||
midibuf_clear(&d->midi_dbuf_out);
|
||||
midibuf_clear(&d->midi_dbuf_passthru);
|
||||
}
|
||||
|
||||
mtx_unlock(&d->flagqueue_mtx);
|
||||
|
||||
if (d->open == NULL)
|
||||
ret = 0;
|
||||
else
|
||||
ret = d->open(i_dev, flags, mode, p);
|
||||
|
||||
splx(s);
|
||||
|
||||
return (ret);
|
||||
}
|
||||
|
||||
int
|
||||
midi_close(dev_t i_dev, int flags, int mode, struct proc * p)
|
||||
{
|
||||
int dev, unit, s, ret;
|
||||
int dev, unit, ret;
|
||||
mididev_info *d;
|
||||
|
||||
dev = minor(i_dev);
|
||||
@ -339,14 +466,20 @@ midi_close(dev_t i_dev, int flags, int mode, struct proc * p)
|
||||
if (d == NULL)
|
||||
return (ENXIO);
|
||||
|
||||
s = splmidi();
|
||||
mtx_lock(&d->flagqueue_mtx);
|
||||
|
||||
/* Stop recording and playing. */
|
||||
if ((d->flags & MIDI_F_READING) != 0)
|
||||
d->callback(d, MIDI_CB_ABORT | MIDI_CB_RD);
|
||||
if ((d->flags & MIDI_F_WRITING) != 0)
|
||||
d->callback(d, MIDI_CB_ABORT | MIDI_CB_WR);
|
||||
|
||||
/* Clear the queues. */
|
||||
if ((d->fflags & FREAD) != 0)
|
||||
midibuf_init(&d->midi_dbuf_in);
|
||||
midibuf_clear(&d->midi_dbuf_in);
|
||||
if ((d->fflags & FWRITE) != 0) {
|
||||
midibuf_init(&d->midi_dbuf_out);
|
||||
midibuf_init(&d->midi_dbuf_passthru);
|
||||
midibuf_clear(&d->midi_dbuf_out);
|
||||
midibuf_clear(&d->midi_dbuf_passthru);
|
||||
}
|
||||
|
||||
/* Stop playing and unmark this device busy. */
|
||||
@ -355,21 +488,24 @@ midi_close(dev_t i_dev, int flags, int mode, struct proc * p)
|
||||
|
||||
device_unbusy(d->dev);
|
||||
|
||||
mtx_unlock(&d->flagqueue_mtx);
|
||||
|
||||
if (d->close == NULL)
|
||||
ret = 0;
|
||||
else
|
||||
ret = d->close(i_dev, flags, mode, p);
|
||||
|
||||
splx(s);
|
||||
|
||||
return (ret);
|
||||
}
|
||||
|
||||
int
|
||||
midi_read(dev_t i_dev, struct uio * buf, int flag)
|
||||
{
|
||||
int dev, unit, s, len, ret;
|
||||
int dev, unit, len, ret;
|
||||
mididev_info *d ;
|
||||
#if defined(MIDI_OUTOFGIANT)
|
||||
char *buf2; /* XXX Until uiomove(9) becomes MP-safe. */
|
||||
#endif /* MIDI_OUTOFGIANT */
|
||||
|
||||
dev = minor(i_dev);
|
||||
|
||||
@ -380,27 +516,50 @@ midi_read(dev_t i_dev, struct uio * buf, int flag)
|
||||
return (ENXIO);
|
||||
|
||||
ret = 0;
|
||||
s = splmidi();
|
||||
|
||||
#if defined(MIDI_OUTOFGIANT)
|
||||
mtx_lock(&Giant);
|
||||
buf2 = malloc(buf->uio_resid, M_DEVBUF, M_WAITOK);
|
||||
mtx_unlock(&Giant);
|
||||
if (buf2 == NULL)
|
||||
return (ENOMEM);
|
||||
#endif /* MIDI_OUTOFGIANT */
|
||||
|
||||
mtx_lock(&d->flagqueue_mtx);
|
||||
|
||||
/* Begin recording. */
|
||||
d->callback(d, MIDI_CB_START | MIDI_CB_RD);
|
||||
|
||||
len = 0;
|
||||
|
||||
/* Have we got the data to read? */
|
||||
if ((d->flags & MIDI_F_NBIO) != 0 && d->midi_dbuf_in.rl == 0)
|
||||
ret = EAGAIN;
|
||||
else {
|
||||
#if defined(MIDI_OUTOFGIANT)
|
||||
len = buf->uio_resid;
|
||||
ret = midibuf_uioread(&d->midi_dbuf_in, buf, len);
|
||||
if ((d->flags & MIDI_F_NBIO) != 0 && len > d->midi_dbuf_in.rl)
|
||||
len = d->midi_dbuf_in.rl;
|
||||
ret = midibuf_seqread(&d->midi_dbuf_in, buf2, len, &d->flagqueue_mtx);
|
||||
#else
|
||||
len = buf->uio_resid;
|
||||
ret = midibuf_uioread(&d->midi_dbuf_in, buf, len, &d->flagqueue_mtx);
|
||||
#endif /* MIDI_OUTOFGIANT */
|
||||
if (ret < 0)
|
||||
ret = -ret;
|
||||
else
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
if (ret == 0 && d->read != NULL)
|
||||
ret = d->read(i_dev, buf, flag);
|
||||
mtx_unlock(&d->flagqueue_mtx);
|
||||
|
||||
splx(s);
|
||||
#if defined(MIDI_OUTOFGIANT)
|
||||
mtx_lock(&Giant);
|
||||
if (ret == 0)
|
||||
uiomove((caddr_t)buf2, len, buf);
|
||||
free(buf2, M_DEVBUF);
|
||||
mtx_unlock(&Giant);
|
||||
#endif /* MIDI_OUTOFGIANT */
|
||||
|
||||
return (ret);
|
||||
}
|
||||
@ -408,8 +567,12 @@ midi_read(dev_t i_dev, struct uio * buf, int flag)
|
||||
int
|
||||
midi_write(dev_t i_dev, struct uio * buf, int flag)
|
||||
{
|
||||
int dev, unit, s, len, ret;
|
||||
int dev, unit, len, ret;
|
||||
mididev_info *d;
|
||||
#if defined(MIDI_OUTOFGIANT)
|
||||
char *buf2, *p; /* XXX Until uiomove(9) becomes MP-safe. */
|
||||
int resid;
|
||||
#endif /* MIDI_OUTOFGIANT */
|
||||
|
||||
dev = minor(i_dev);
|
||||
d = get_mididev_info(i_dev, &unit);
|
||||
@ -420,33 +583,60 @@ midi_write(dev_t i_dev, struct uio * buf, int flag)
|
||||
return (ENXIO);
|
||||
|
||||
ret = 0;
|
||||
s = splmidi();
|
||||
|
||||
/* Begin playing. */
|
||||
d->callback(d, MIDI_CB_START | MIDI_CB_WR);
|
||||
#if defined(MIDI_OUTOFGIANT)
|
||||
resid = buf->uio_resid;
|
||||
mtx_lock(&d->flagqueue_mtx);
|
||||
if (resid > d->midi_dbuf_out.fl &&
|
||||
(d->flags & MIDI_F_NBIO))
|
||||
resid = d->midi_dbuf_out.fl;
|
||||
mtx_unlock(&d->flagqueue_mtx);
|
||||
mtx_lock(&Giant);
|
||||
buf2 = p = malloc(resid, M_DEVBUF, M_WAITOK);
|
||||
if (buf2 == NULL) {
|
||||
mtx_unlock(&Giant);
|
||||
return (ENOMEM);
|
||||
}
|
||||
ret = uiomove((caddr_t)buf2, resid, buf);
|
||||
#endif /* MIDI_OUTOFGIANT */
|
||||
|
||||
mtx_lock(&d->flagqueue_mtx);
|
||||
|
||||
/* Have we got the data to write? */
|
||||
if ((d->flags & MIDI_F_NBIO) != 0 && d->midi_dbuf_out.fl == 0)
|
||||
if ((d->flags & MIDI_F_NBIO) != 0 && d->midi_dbuf_out.fl == 0) {
|
||||
/* Begin playing. */
|
||||
d->callback(d, MIDI_CB_START | MIDI_CB_WR);
|
||||
ret = EAGAIN;
|
||||
else {
|
||||
} else {
|
||||
#if defined(MIDI_OUTOFGIANT)
|
||||
len = resid - (p - buf2);
|
||||
#else
|
||||
len = buf->uio_resid;
|
||||
#endif /* MIDI_OUTOFGIANT */
|
||||
if (len > d->midi_dbuf_out.fl &&
|
||||
(d->flags & MIDI_F_NBIO))
|
||||
len = d->midi_dbuf_out.fl;
|
||||
ret = midibuf_uiowrite(&d->midi_dbuf_out, buf, len);
|
||||
#if defined(MIDI_OUTOFGIANT)
|
||||
ret = midibuf_seqwrite(&d->midi_dbuf_out, p, len, &d->flagqueue_mtx);
|
||||
#else
|
||||
ret = midibuf_uiowrite(&d->midi_dbuf_out, buf, len, &d->flagqueue_mtx);
|
||||
#endif /* MIDI_OUTOFGIANT */
|
||||
if (ret < 0)
|
||||
ret = -ret;
|
||||
else
|
||||
else {
|
||||
/* Begin playing. */
|
||||
d->callback(d, MIDI_CB_START | MIDI_CB_WR);
|
||||
ret = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Begin playing. */
|
||||
d->callback(d, MIDI_CB_START | MIDI_CB_WR);
|
||||
mtx_unlock(&d->flagqueue_mtx);
|
||||
|
||||
if (ret == 0 && d->write != NULL)
|
||||
ret = d->write(i_dev, buf, flag);
|
||||
|
||||
splx(s);
|
||||
#if defined(MIDI_OUTOFGIANT)
|
||||
mtx_lock(&Giant);
|
||||
free(buf2, M_DEVBUF);
|
||||
mtx_unlock(&Giant);
|
||||
#endif /* MIDI_OUTOFGIANT */
|
||||
|
||||
return (ret);
|
||||
}
|
||||
@ -470,7 +660,6 @@ midi_ioctl(dev_t i_dev, u_long cmd, caddr_t arg, int mode, struct proc * p)
|
||||
int ret = ENOSYS, dev, unit;
|
||||
mididev_info *d;
|
||||
struct snd_size *sndsize;
|
||||
u_long s;
|
||||
|
||||
dev = minor(i_dev);
|
||||
d = get_mididev_info(i_dev, &unit);
|
||||
@ -492,7 +681,6 @@ midi_ioctl(dev_t i_dev, u_long cmd, caddr_t arg, int mode, struct proc * p)
|
||||
* all routines are called with int. blocked. Make sure that
|
||||
* ints are re-enabled when calling slow or blocking functions!
|
||||
*/
|
||||
s = splmidi();
|
||||
switch(cmd) {
|
||||
|
||||
/*
|
||||
@ -504,10 +692,14 @@ midi_ioctl(dev_t i_dev, u_long cmd, caddr_t arg, int mode, struct proc * p)
|
||||
|
||||
case AIOSSIZE: /* set the current blocksize */
|
||||
sndsize = (struct snd_size *)arg;
|
||||
mtx_lock(&d->flagqueue_mtx);
|
||||
if (sndsize->play_size <= d->midi_dbuf_out.unit_size && sndsize->rec_size <= d->midi_dbuf_in.unit_size) {
|
||||
d->flags &= ~MIDI_F_HAS_SIZE;
|
||||
d->midi_dbuf_out.blocksize = d->midi_dbuf_out.unit_size;
|
||||
d->midi_dbuf_in.blocksize = d->midi_dbuf_in.unit_size;
|
||||
sndsize->play_size = d->midi_dbuf_out.blocksize;
|
||||
sndsize->rec_size = d->midi_dbuf_in.blocksize;
|
||||
d->flags &= ~MIDI_F_HAS_SIZE;
|
||||
mtx_unlock(&d->flagqueue_mtx);
|
||||
}
|
||||
else {
|
||||
if (sndsize->play_size > d->midi_dbuf_out.bufsize / 4)
|
||||
@ -521,27 +713,36 @@ midi_ioctl(dev_t i_dev, u_long cmd, caddr_t arg, int mode, struct proc * p)
|
||||
d->midi_dbuf_in.blocksize =
|
||||
((sndsize->rec_size + d->midi_dbuf_in.unit_size - 1)
|
||||
/ d->midi_dbuf_in.unit_size) * d->midi_dbuf_in.unit_size;
|
||||
sndsize->play_size = d->midi_dbuf_out.blocksize;
|
||||
sndsize->rec_size = d->midi_dbuf_in.blocksize;
|
||||
d->flags |= MIDI_F_HAS_SIZE;
|
||||
mtx_unlock(&d->flagqueue_mtx);
|
||||
}
|
||||
/* FALLTHROUGH */
|
||||
|
||||
ret = 0;
|
||||
break;
|
||||
|
||||
case AIOGSIZE: /* get the current blocksize */
|
||||
sndsize = (struct snd_size *)arg;
|
||||
mtx_lock(&d->flagqueue_mtx);
|
||||
sndsize->play_size = d->midi_dbuf_out.blocksize;
|
||||
sndsize->rec_size = d->midi_dbuf_in.blocksize;
|
||||
mtx_unlock(&d->flagqueue_mtx);
|
||||
|
||||
ret = 0;
|
||||
break;
|
||||
|
||||
case AIOSTOP:
|
||||
mtx_lock(&d->flagqueue_mtx);
|
||||
if (*(int *)arg == AIOSYNC_PLAY) /* play */
|
||||
*(int *)arg = d->callback(d, MIDI_CB_STOP | MIDI_CB_WR);
|
||||
else if (*(int *)arg == AIOSYNC_CAPTURE)
|
||||
*(int *)arg = d->callback(d, MIDI_CB_STOP | MIDI_CB_RD);
|
||||
else {
|
||||
splx(s);
|
||||
DEB(printf("AIOSTOP: bad channel 0x%x\n", *(int *)arg));
|
||||
*(int *)arg = 0 ;
|
||||
}
|
||||
mtx_unlock(&d->flagqueue_mtx);
|
||||
break ;
|
||||
|
||||
case AIOSYNC:
|
||||
@ -561,20 +762,25 @@ midi_ioctl(dev_t i_dev, u_long cmd, caddr_t arg, int mode, struct proc * p)
|
||||
break;
|
||||
|
||||
case FIONBIO: /* set/clear non-blocking i/o */
|
||||
mtx_lock(&d->flagqueue_mtx);
|
||||
if ( *(int *)arg == 0 )
|
||||
d->flags &= ~MIDI_F_NBIO ;
|
||||
else
|
||||
d->flags |= MIDI_F_NBIO ;
|
||||
mtx_unlock(&d->flagqueue_mtx);
|
||||
break ;
|
||||
|
||||
case MIOSPASSTHRU: /* set/clear passthru */
|
||||
mtx_lock(&d->flagqueue_mtx);
|
||||
if ( *(int *)arg == 0 )
|
||||
d->flags &= ~MIDI_F_PASSTHRU ;
|
||||
else
|
||||
d->flags |= MIDI_F_PASSTHRU ;
|
||||
|
||||
/* Init the queue. */
|
||||
midibuf_init(&d->midi_dbuf_passthru);
|
||||
midibuf_clear(&d->midi_dbuf_passthru);
|
||||
|
||||
mtx_unlock(&d->flagqueue_mtx);
|
||||
|
||||
/* FALLTHROUGH */
|
||||
case MIOGPASSTHRU: /* get passthru */
|
||||
@ -590,14 +796,13 @@ midi_ioctl(dev_t i_dev, u_long cmd, caddr_t arg, int mode, struct proc * p)
|
||||
ret = EINVAL;
|
||||
break ;
|
||||
}
|
||||
splx(s);
|
||||
return ret ;
|
||||
}
|
||||
|
||||
int
|
||||
midi_poll(dev_t i_dev, int events, struct proc * p)
|
||||
{
|
||||
int unit, dev, ret, s, lim;
|
||||
int unit, dev, ret, lim;
|
||||
mididev_info *d;
|
||||
|
||||
dev = minor(i_dev);
|
||||
@ -606,11 +811,9 @@ midi_poll(dev_t i_dev, int events, struct proc * p)
|
||||
if (d == NULL)
|
||||
return (ENXIO);
|
||||
|
||||
if (d->poll)
|
||||
ret = d->poll(i_dev, events, p);
|
||||
|
||||
ret = 0;
|
||||
s = splmidi();
|
||||
|
||||
mtx_lock(&d->flagqueue_mtx);
|
||||
|
||||
/* Look up the apropriate queue and select it. */
|
||||
if ((events & (POLLOUT | POLLWRNORM)) != 0) {
|
||||
@ -645,7 +848,8 @@ midi_poll(dev_t i_dev, int events, struct proc * p)
|
||||
/* We can write now. */
|
||||
ret |= events & (POLLIN | POLLRDNORM);
|
||||
}
|
||||
splx(s);
|
||||
|
||||
mtx_unlock(&d->flagqueue_mtx);
|
||||
|
||||
return (ret);
|
||||
}
|
||||
@ -657,6 +861,36 @@ midi_intr(mididev_info *d)
|
||||
d->intr(d->intrarg, d);
|
||||
}
|
||||
|
||||
/* Flush the output queue. */
|
||||
#define MIDI_SYNC_TIMEOUT 1
|
||||
int
|
||||
midi_sync(mididev_info *d)
|
||||
{
|
||||
int i, rl;
|
||||
|
||||
mtx_assert(&d->flagqueue_mtx, MA_OWNED);
|
||||
|
||||
while (d->midi_dbuf_out.rl > 0) {
|
||||
if ((d->flags & MIDI_F_WRITING) == 0)
|
||||
d->callback(d, MIDI_CB_START | MIDI_CB_WR);
|
||||
rl = d->midi_dbuf_out.rl;
|
||||
i = msleep(&d->midi_dbuf_out.tsleep_out, &d->flagqueue_mtx, PRIBIO | PCATCH, "midsnc", (d->midi_dbuf_out.bufsize * 10 * hz / 38400) + MIDI_SYNC_TIMEOUT * hz);
|
||||
if (i == EINTR || i == ERESTART) {
|
||||
if (i == EINTR)
|
||||
d->callback(d, MIDI_CB_STOP | MIDI_CB_WR);
|
||||
return (i);
|
||||
}
|
||||
if (i == EWOULDBLOCK && rl == d->midi_dbuf_out.rl) {
|
||||
/* A queue seems to be stuck up. Give up and clear the queue. */
|
||||
d->callback(d, MIDI_CB_STOP | MIDI_CB_WR);
|
||||
midibuf_clear(&d->midi_dbuf_out);
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* These handle the status message of the midi drivers.
|
||||
*/
|
||||
@ -705,8 +939,8 @@ midi_initstatus(char *buf, int size)
|
||||
|
||||
p = 0;
|
||||
p += snprintf(buf, size, "FreeBSD Midi Driver (newmidi) %s %s\nInstalled devices:\n", __DATE__, __TIME__);
|
||||
for (i = 0 ; i < NMIDI_MAX ; i++) {
|
||||
md = &midi_info[i];
|
||||
for (i = 0 ; i < mididev_info_number() ; i++) {
|
||||
md = get_mididev_info_unit(i);
|
||||
if (!MIDICONFED(md))
|
||||
continue;
|
||||
dev = devclass_get_device(midi_devclass, i);
|
||||
@ -723,15 +957,13 @@ midi_initstatus(char *buf, int size)
|
||||
static int
|
||||
midi_readstatus(char *buf, int *ptr, struct uio *uio)
|
||||
{
|
||||
int s, len;
|
||||
int len;
|
||||
|
||||
s = splmidi();
|
||||
len = min(uio->uio_resid, strlen(&buf[*ptr]));
|
||||
if (len > 0) {
|
||||
uiomove(&buf[*ptr], len, uio);
|
||||
*ptr += len;
|
||||
}
|
||||
splx(s);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
@ -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.
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -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>
|
||||
|
||||
@ -69,6 +70,16 @@ typedef struct _seqdev_info seqdev_info;
|
||||
|
||||
typedef int (seq_callback_t)(seqdev_info *sd, int reason);
|
||||
|
||||
/*
|
||||
* The order of mutex lock (from the first to the last)
|
||||
*
|
||||
* 1. sequencer flags, queues, timer and device list
|
||||
* 2. midi synth voice and channel
|
||||
* 3. midi synth status
|
||||
* 4. generic midi flags and queues
|
||||
* 5. midi device
|
||||
*/
|
||||
|
||||
/*
|
||||
* descriptor of sequencer operations ...
|
||||
*
|
||||
@ -128,14 +139,20 @@ struct _seqdev_info {
|
||||
* mss codec type, etc. etc.
|
||||
*/
|
||||
|
||||
struct mtx flagqueue_mtx; /* Mutex to protect flags and queues */
|
||||
struct cv insync_cv; /* Conditional variable for sync */
|
||||
|
||||
/* Queues */
|
||||
midi_dbuf midi_dbuf_in; /* midi input event/message queue */
|
||||
midi_dbuf midi_dbuf_out; /* midi output event/message queue */
|
||||
|
||||
|
||||
/*
|
||||
* these parameters describe the operation of the board.
|
||||
* Generic things like busy flag, speed, etc are here.
|
||||
*/
|
||||
|
||||
/* Flags */
|
||||
volatile u_long flags ; /* 32 bits, used for various purposes. */
|
||||
|
||||
/*
|
||||
@ -186,6 +203,8 @@ struct _seqdev_info {
|
||||
*/
|
||||
#define SEQ_F_INIT 0x4000 /* changed parameters. need init */
|
||||
|
||||
#define SEQ_F_INSYNC 0x8000 /* a pending sync */
|
||||
|
||||
int play_blocksize, rec_blocksize; /* blocksize for io and dma ops */
|
||||
|
||||
#define swsel midi_dbuf_out.sel
|
||||
@ -194,6 +213,9 @@ struct _seqdev_info {
|
||||
u_long magic;
|
||||
#define MAGIC(unit) ( 0xa4d10de0 + unit )
|
||||
void *device_data ; /* just in case it is needed...*/
|
||||
|
||||
/* The tailq entry of the next sequencer device. */
|
||||
TAILQ_ENTRY(_seqdev_info) sd_link;
|
||||
} ;
|
||||
|
||||
|
||||
@ -226,8 +248,6 @@ struct _seqdev_info {
|
||||
#define DEB(x)
|
||||
#endif
|
||||
|
||||
extern seqdev_info seq_info[NSEQ_MAX] ;
|
||||
|
||||
#define MIDI_DEV_SEQ 1 /* Sequencer output /dev/sequencer (FM
|
||||
synthesizer and MIDI output) */
|
||||
|
||||
|
@ -89,6 +89,8 @@ struct csamidi_softc {
|
||||
mididev_info *devinfo; /* midi device information */
|
||||
struct csa_bridgeinfo *binfo; /* The state of the parent. */
|
||||
|
||||
struct mtx mtx; /* Mutex to protect the device. */
|
||||
|
||||
struct resource *io; /* Base of io map */
|
||||
int io_rid; /* Io map resource ID */
|
||||
struct resource *mem; /* Base of memory map */
|
||||
@ -128,12 +130,9 @@ static mididev_info csamidi_op_desc = {
|
||||
|
||||
SNDCARD_MPU401,
|
||||
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
csamidi_ioctl,
|
||||
NULL,
|
||||
|
||||
csamidi_callback,
|
||||
|
||||
@ -177,10 +176,8 @@ csamidi_attach(device_t dev)
|
||||
sc_p scp;
|
||||
mididev_info *devinfo;
|
||||
struct sndcard_func *func;
|
||||
int unit;
|
||||
|
||||
scp = device_get_softc(dev);
|
||||
unit = device_get_unit(dev);
|
||||
func = device_get_ivars(dev);
|
||||
scp->binfo = func->varinfo;
|
||||
|
||||
@ -192,20 +189,14 @@ csamidi_attach(device_t dev)
|
||||
|
||||
/* Fill the softc. */
|
||||
scp->dev = dev;
|
||||
scp->devinfo = devinfo = create_mididev_info_unit(&unit, MDT_MIDI);
|
||||
mtx_init(&scp->mtx, "csamid", MTX_DEF);
|
||||
scp->devinfo = devinfo = create_mididev_info_unit(MDT_MIDI, &csamidi_op_desc, &midisynth_op_desc);
|
||||
|
||||
/* Fill the midi info. */
|
||||
bcopy(&csamidi_op_desc, devinfo, sizeof(csamidi_op_desc));
|
||||
midiinit(devinfo, dev);
|
||||
devinfo->flags = 0;
|
||||
bcopy(&midisynth_op_desc, &devinfo->synth, sizeof(midisynth_op_desc));
|
||||
snprintf(devinfo->midistat, sizeof(devinfo->midistat), "at irq %d",
|
||||
(int)rman_get_start(scp->irq));
|
||||
|
||||
/* Init the queue. */
|
||||
devinfo->midi_dbuf_in.unit_size = devinfo->midi_dbuf_out.unit_size = 1;
|
||||
midibuf_init(&devinfo->midi_dbuf_in);
|
||||
midibuf_init(&devinfo->midi_dbuf_out);
|
||||
midiinit(devinfo, dev);
|
||||
|
||||
/* Enable interrupt. */
|
||||
if (bus_setup_intr(dev, scp->irq, INTR_TYPE_TTY, csamidi_intr, scp, &scp->ih)) {
|
||||
@ -271,26 +262,40 @@ csamidi_intr(void *arg)
|
||||
scp = (sc_p)arg;
|
||||
devinfo = scp->devinfo;
|
||||
|
||||
MIDI_DROP_GIANT_NOSWITCH();
|
||||
|
||||
mtx_lock(&devinfo->flagqueue_mtx);
|
||||
mtx_lock(&scp->mtx);
|
||||
|
||||
/* Read the received data. */
|
||||
while ((csamidi_status(scp) & MIDSR_RBE) == 0) {
|
||||
/* Receive the data. */
|
||||
c = (u_char)csamidi_readdata(scp);
|
||||
mtx_unlock(&scp->mtx);
|
||||
|
||||
/* Queue into the passthru buffer and start transmitting if we can. */
|
||||
if ((devinfo->flags & MIDI_F_PASSTHRU) != 0 && ((devinfo->flags & MIDI_F_BUSY) == 0 || (devinfo->fflags & FWRITE) == 0)) {
|
||||
midibuf_input_intr(&devinfo->midi_dbuf_passthru, &c, sizeof(c));
|
||||
devinfo->callback(devinfo, MIDI_CB_START | MIDI_CB_WR);
|
||||
}
|
||||
/* Queue if we are reading. Discard an active sensing. */
|
||||
if ((devinfo->flags & MIDI_F_READING) != 0 && c != 0xfe)
|
||||
if ((devinfo->flags & MIDI_F_READING) != 0 && c != 0xfe) {
|
||||
midibuf_input_intr(&devinfo->midi_dbuf_in, &c, sizeof(c));
|
||||
}
|
||||
mtx_lock(&scp->mtx);
|
||||
}
|
||||
mtx_unlock(&scp->mtx);
|
||||
|
||||
/* Transmit out data. */
|
||||
if ((devinfo->flags & MIDI_F_WRITING) != 0 && (csamidi_status(scp) & MIDSR_TBF) == 0)
|
||||
csamidi_xmit(scp);
|
||||
|
||||
mtx_unlock(&devinfo->flagqueue_mtx);
|
||||
|
||||
/* Invoke the upper layer. */
|
||||
midi_intr(devinfo);
|
||||
|
||||
MIDI_PICKUP_GIANT();
|
||||
}
|
||||
|
||||
static int
|
||||
@ -299,6 +304,8 @@ csamidi_callback(mididev_info *d, int reason)
|
||||
int unit;
|
||||
sc_p scp;
|
||||
|
||||
mtx_assert(&d->flagqueue_mtx, MA_OWNED);
|
||||
|
||||
if (d == NULL) {
|
||||
DEB(printf("csamidi_callback: device not configured.\n"));
|
||||
return (ENXIO);
|
||||
@ -336,7 +343,6 @@ csamidi_callback(mididev_info *d, int reason)
|
||||
|
||||
/*
|
||||
* Starts to play the data in the output queue.
|
||||
* Call this at >=splclock.
|
||||
*/
|
||||
static void
|
||||
csamidi_startplay(sc_p scp)
|
||||
@ -345,6 +351,8 @@ csamidi_startplay(sc_p scp)
|
||||
|
||||
devinfo = scp->devinfo;
|
||||
|
||||
mtx_assert(&devinfo->flagqueue_mtx, MA_OWNED);
|
||||
|
||||
/* Can we play now? */
|
||||
if (devinfo->midi_dbuf_out.rl == 0)
|
||||
return;
|
||||
@ -362,6 +370,8 @@ csamidi_xmit(sc_p scp)
|
||||
|
||||
devinfo = scp->devinfo;
|
||||
|
||||
mtx_assert(&devinfo->flagqueue_mtx, MA_OWNED);
|
||||
|
||||
/* See which source to use. */
|
||||
if ((devinfo->flags & MIDI_F_PASSTHRU) == 0 || ((devinfo->flags & MIDI_F_BUSY) != 0 && (devinfo->fflags & FWRITE) != 0))
|
||||
dbuf = &devinfo->midi_dbuf_out;
|
||||
@ -369,18 +379,24 @@ csamidi_xmit(sc_p scp)
|
||||
dbuf = &devinfo->midi_dbuf_passthru;
|
||||
|
||||
/* Transmit the data in the queue. */
|
||||
while ((devinfo->flags & MIDI_F_WRITING) != 0 && (csamidi_status(scp) & MIDSR_TBF) == 0) {
|
||||
while ((devinfo->flags & MIDI_F_WRITING) != 0) {
|
||||
/* Do we have the data to transmit? */
|
||||
if (dbuf->rl == 0) {
|
||||
/* Stop playing. */
|
||||
devinfo->flags &= ~MIDI_F_WRITING;
|
||||
break;
|
||||
} else {
|
||||
mtx_lock(&scp->mtx);
|
||||
if ((csamidi_status(scp) & MIDSR_TBF) != 0) {
|
||||
mtx_unlock(&scp->mtx);
|
||||
break;
|
||||
}
|
||||
/* Send the data. */
|
||||
midibuf_output_intr(dbuf, &c, sizeof(c));
|
||||
csamidi_writedata(scp, c);
|
||||
/* We are playing now. */
|
||||
devinfo->flags |= MIDI_F_WRITING;
|
||||
mtx_unlock(&scp->mtx);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -391,6 +407,8 @@ csamidi_reset(sc_p scp)
|
||||
{
|
||||
int i, resp;
|
||||
|
||||
mtx_lock(&scp->mtx);
|
||||
|
||||
/* Reset the midi. */
|
||||
resp = 0;
|
||||
for (i = 0 ; i < CSAMIDI_TRYDATA ; i++) {
|
||||
@ -398,8 +416,10 @@ csamidi_reset(sc_p scp)
|
||||
if (resp == 0)
|
||||
break;
|
||||
}
|
||||
if (resp != 0)
|
||||
if (resp != 0) {
|
||||
mtx_unlock(&scp->mtx);
|
||||
return (1);
|
||||
}
|
||||
for (i = 0 ; i < CSAMIDI_TRYDATA ; i++) {
|
||||
resp = csamidi_command(scp, MIDCR_TXE | MIDCR_RXE | MIDCR_RIE | MIDCR_TIE);
|
||||
if (resp == 0)
|
||||
@ -408,6 +428,8 @@ csamidi_reset(sc_p scp)
|
||||
if (resp != 0)
|
||||
return (1);
|
||||
|
||||
mtx_unlock(&scp->mtx);
|
||||
|
||||
DELAY(CSAMIDI_DELAY);
|
||||
|
||||
return (0);
|
||||
|
Loading…
Reference in New Issue
Block a user