summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sys/dev/midi.c1140
-rw-r--r--sys/dev/midivar.h160
-rw-r--r--sys/dev/usb/umidi.c489
-rw-r--r--sys/dev/usb/umidi_quirks.c193
-rw-r--r--sys/dev/usb/umidireg.h5
-rw-r--r--sys/dev/usb/umidivar.h27
6 files changed, 1023 insertions, 991 deletions
diff --git a/sys/dev/midi.c b/sys/dev/midi.c
index 710f59d1456..ed9fe56c21c 100644
--- a/sys/dev/midi.c
+++ b/sys/dev/midi.c
@@ -1,778 +1,648 @@
-/* $OpenBSD: midi.c,v 1.9 2003/09/23 16:51:12 millert Exp $ */
-/* $NetBSD: midi.c,v 1.10 1998/12/20 14:26:44 drochner Exp $ */
-
/*
- * Copyright (c) 1998 The NetBSD Foundation, Inc.
- * All rights reserved.
- *
- * This code is derived from software contributed to The NetBSD Foundation
- * by Lennart Augustsson (augustss@netbsd.org).
+ * Copyright (c) 2003, 2004 Alexandre Ratchov
*
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the NetBSD
- * Foundation, Inc. and its contributors.
- * 4. Neither the name of The NetBSD Foundation nor the names of its
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
*
- * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
- * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
- * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
- * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * TODO
+ * - put the sequencer stuff in sequencer.c and sequencervar.h
+ * there is no reason to have it here. The sequencer
+ * driver need only to open the midi hw_if thus it does not
+ * need this driver
*/
#include "midi.h"
-#include "audio.h"
#include "sequencer.h"
+#if NMIDI > 0
#include <sys/param.h>
-#include <sys/ioctl.h>
#include <sys/fcntl.h>
-#include <sys/vnode.h>
-#include <sys/select.h>
-#include <sys/poll.h>
-#include <sys/malloc.h>
-#include <sys/proc.h>
#include <sys/systm.h>
-#include <sys/syslog.h>
+#include <sys/ioctl.h>
+#include <sys/exec.h>
+#include <sys/conf.h>
+#include <sys/lkm.h>
+#include <sys/proc.h>
+#include <sys/poll.h>
#include <sys/kernel.h>
+#include <sys/timeout.h>
+#include <sys/vnode.h>
#include <sys/signalvar.h>
-#include <sys/conf.h>
-#include <sys/audioio.h>
-#include <sys/midiio.h>
+#include <sys/malloc.h>
#include <sys/device.h>
-#include <dev/audio_if.h>
#include <dev/midi_if.h>
+#include <dev/audio_if.h>
#include <dev/midivar.h>
-#if NMIDI > 0
-
-#ifdef AUDIO_DEBUG
-#define DPRINTF(x) if (mididebug) printf x
-#define DPRINTFN(n,x) if (mididebug >= (n)) printf x
-int mididebug = 0;
-#else
-#define DPRINTF(x)
-#define DPRINTFN(n,x)
-#endif
+int midiopen(dev_t, int, int, struct proc *);
+int midiclose(dev_t, int, int, struct proc *);
+int midiread(dev_t, struct uio *, int);
+int midiwrite(dev_t, struct uio *, int);
+int midipoll(dev_t, int, struct proc *);
+int midiioctl(dev_t, u_long, caddr_t, int, struct proc *);
+int midiprobe(struct device *, void *, void *);
+void midiattach(struct device *, struct device *, void *);
+int mididetach(struct device *, int);
+int midiprint(void *, const char *);
-int midi_wait;
+void midi_iintr(void *, int);
+void midi_ointr(void *);
+void midi_out_start(struct midi_softc *);
+void midi_out_stop(struct midi_softc *);
+void midi_out_do(struct midi_softc *);
+void midi_attach(struct midi_softc *, struct device *);
-void midi_in(void *, int);
-void midi_out(void *);
-int midi_start_output(struct midi_softc *, int);
-int midi_sleep_timo(int *, char *, int);
-int midi_sleep(int *, char *);
-void midi_wakeup(int *);
-void midi_initbuf(struct midi_buffer *);
-void midi_timeout(void *);
-#define __BROKEN_INDIRECT_CONFIG /* XXX */
-#ifdef __BROKEN_INDIRECT_CONFIG
-int midiprobe(struct device *, void *, void *);
-#else
-int midiprobe(struct device *, struct cfdata *, void *);
+#if NSEQUENCER > 0
+int midi_unit_count(void);
+struct midi_hw_if *midi_get_hwif(int);
+void midi_toevent(struct midi_softc *, int);
+int midi_writebytes(int, u_char *, int);
+void midiseq_in(struct midi_dev *, u_char *, int);
#endif
-void midiattach(struct device *, struct device *, void *);
struct cfattach midi_ca = {
- sizeof(struct midi_softc), midiprobe, midiattach
+ sizeof(struct midi_softc), midiprobe, midiattach, mididetach
};
struct cfdriver midi_cd = {
NULL, "midi", DV_DULL
};
-#ifdef MIDI_SAVE
-#define MIDI_SAVE_SIZE 100000
-int midicnt;
-struct {
- int cnt;
- u_char buf[MIDI_SAVE_SIZE];
-} midisave;
-#define MIDI_GETSAVE _IOWR('m', 100, int)
-
-#endif
-
-int
-midiprobe(parent, match, aux)
- struct device *parent;
-#ifdef __BROKEN_INDIRECT_CONFIG
- void *match;
-#else
- struct cfdata *match;
-#endif
- void *aux;
-{
- struct audio_attach_args *sa = aux;
-
- DPRINTFN(6,("midiprobe: type=%d sa=%p hw=%p\n",
- sa->type, sa, sa->hwif));
- return ((sa->type == AUDIODEV_TYPE_MIDI) ? 1 : 0);
-}
void
-midiattach(parent, self, aux)
- struct device *parent, *self;
- void *aux;
+midi_iintr(void *addr, int data)
{
- struct midi_softc *sc = (void *)self;
- struct audio_attach_args *sa = aux;
- struct midi_hw_if *hwp = sa->hwif;
- void *hdlp = sa->hdl;
-
- DPRINTFN(6, ("MIDI attach\n"));
-
-#ifdef DIAGNOSTIC
- if (hwp == 0 ||
- hwp->open == 0 ||
- hwp->close == 0 ||
- hwp->output == 0 ||
- hwp->getinfo == 0) {
- printf("midi: missing method\n");
+ struct midi_softc *sc = (struct midi_softc *)addr;
+ struct midi_buffer *mb = &sc->inbuf;
+ int s;
+
+ if (sc->isdying || !sc->isopen || !(sc->flags & FREAD)) return;
+
+#if NSEQUENCER > 0
+ if (sc->seqopen) {
+ midi_toevent(sc, data);
return;
}
#endif
- sc->hw_if = hwp;
- sc->hw_hdl = hdlp;
- midi_attach(sc, parent);
+ if (MIDIBUF_ISFULL(mb))
+ return; /* discard data */
+
+ s = splaudio();
+ MIDIBUF_WRITE(mb, data);
+ splx(s);
+
+ if (sc->rchan) {
+ sc->rchan = 0;
+ wakeup(&sc->rchan);
+ }
+ selwakeup(&sc->rsel);
+ if (sc->async)
+ psignal(sc->async, SIGIO);
}
-void
-midi_attach(sc, parent)
- struct midi_softc *sc;
- struct device *parent;
-{
- struct midi_info mi;
-
- sc->isopen = 0;
-
- midi_wait = MIDI_WAIT * hz / 1000000;
- if (midi_wait == 0)
- midi_wait = 1;
-
- sc->sc_dev = parent;
- sc->hw_if->getinfo(sc->hw_hdl, &mi);
- sc->props = mi.props;
- timeout_set(&sc->timeo, midi_timeout, sc);
- printf(": <%s>\n", mi.name);
-}
int
-midi_unit_count()
+midiread(dev_t dev, struct uio *uio, int ioflag)
{
- return (midi_cd.cd_ndevs);
-}
+ struct midi_softc *sc = MIDI_DEV2SC(dev);
+ struct midi_buffer *mb = &sc->inbuf;
+ unsigned count;
+ int s, error;
+
+ if (!(sc->flags & FREAD))
+ return ENXIO;
+
+ /* if there is no data then sleep (unless IO_NDELAY flag is set) */
-void
-midi_initbuf(mb)
- struct midi_buffer *mb;
-{
- mb->used = 0;
- mb->usedhigh = MIDI_BUFSIZE;
- mb->end = mb->start + mb->usedhigh;
- mb->inp = mb->outp = mb->start;
+ s = splaudio();
+ while(MIDIBUF_ISEMPTY(mb)) {
+ if (sc->isdying) {
+ splx(s);
+ return EIO;
+ }
+ if (ioflag & IO_NDELAY) {
+ splx(s);
+ return EWOULDBLOCK;
+ }
+ sc->rchan = 1;
+ error = tsleep(&sc->rchan, PWAIT|PCATCH, "mid_rd", 0);
+ if (error) {
+ splx(s);
+ return error;
+ }
+ }
+
+ /* at this stage, there is at least 1 byte */
+
+ while (uio->uio_resid > 0 && mb->used > 0) {
+ count = MIDIBUF_SIZE - mb->start;
+ if (count > mb->used)
+ count = mb->used;
+ if (count > uio->uio_resid)
+ count = uio->uio_resid;
+ error = uiomove(mb->data + mb->start, count, uio);
+ if (error) {
+ splx(s);
+ return error;
+ }
+ MIDIBUF_REMOVE(mb, count);
+ }
+ splx(s);
+ return 0;
}
-int
-midi_sleep_timo(chan, label, timo)
- int *chan;
- char *label;
- int timo;
-{
- int st;
-
- if (!label)
- label = "midi";
- DPRINTFN(5, ("midi_sleep_timo: %p %s %d\n", chan, label, timo));
- *chan = 1;
- st = tsleep(chan, PWAIT | PCATCH, label, timo);
- *chan = 0;
+void
+midi_ointr(void *addr)
+{
+ struct midi_softc *sc = (struct midi_softc *)addr;
+ struct midi_buffer *mb;
+ int s;
+
+ if (sc->isopen && !sc->isdying) {
#ifdef MIDI_DEBUG
- if (st != 0)
- printf("midi_sleep: %d\n", st);
+ if (!sc->isbusy) {
+ printf("midi_ointr: output should be busy\n");
+ }
#endif
- return (st);
+ mb = &sc->outbuf;
+ s = splaudio();
+ if (mb->used == 0)
+ midi_out_stop(sc);
+ else
+ midi_out_do(sc); /* restart output */
+ splx(s);
+ }
}
-int
-midi_sleep(chan, label)
- int *chan;
- char *label;
-{
- return (midi_sleep_timo(chan, label, 0));
-}
void
-midi_wakeup(chan)
- int *chan;
+midi_out_start(struct midi_softc *sc)
{
- if (*chan) {
- DPRINTFN(5, ("midi_wakeup: %p\n", chan));
- wakeup(chan);
- *chan = 0;
+ if (!sc->isbusy) {
+ sc->isbusy = 1;
+ midi_out_do(sc);
}
}
-static int midi_lengths[] = { 2,2,2,2,1,1,2,0 };
-/* Number of bytes in a MIDI command */
-#define MIDI_LENGTH(d) (midi_lengths[((d) >> 4) & 7])
-
void
-midi_in(addr, data)
- void *addr;
- int data;
+midi_out_stop(struct midi_softc *sc)
{
- struct midi_softc *sc = addr;
- struct midi_buffer *mb = &sc->inbuf;
- int i;
-
- if (!sc->isopen)
- return;
- if (data == MIDI_ACK)
- return;
- DPRINTFN(3, ("midi_in: %p 0x%02x\n", sc, data));
- if (!(sc->flags & FREAD))
- return; /* discard data if not reading */
-
- switch(sc->in_state) {
- case MIDI_IN_START:
- if (MIDI_IS_STATUS(data)) {
- switch(data) {
- case 0xf0: /* Sysex */
- sc->in_state = MIDI_IN_SYSEX;
- break;
- case 0xf1: /* MTC quarter frame */
- case 0xf3: /* Song select */
- sc->in_state = MIDI_IN_DATA;
- sc->in_msg[0] = data;
- sc->in_pos = 1;
- sc->in_left = 1;
- break;
- case 0xf2: /* Song position pointer */
- sc->in_state = MIDI_IN_DATA;
- sc->in_msg[0] = data;
- sc->in_pos = 1;
- sc->in_left = 2;
- break;
- default:
- if (MIDI_IS_COMMON(data)) {
- sc->in_msg[0] = data;
- sc->in_pos = 1;
- goto deliver;
- } else {
- sc->in_state = MIDI_IN_DATA;
- sc->in_msg[0] = sc->in_status = data;
- sc->in_pos = 1;
- sc->in_left =
- MIDI_LENGTH(sc->in_status);
- }
- break;
- }
- } else {
- if (MIDI_IS_STATUS(sc->in_status)) {
- sc->in_state = MIDI_IN_DATA;
- sc->in_msg[0] = sc->in_status;
- sc->in_msg[1] = data;
- sc->in_pos = 2;
- sc->in_left = MIDI_LENGTH(sc->in_status) - 1;
- }
- }
- return;
- case MIDI_IN_DATA:
- sc->in_msg[sc->in_pos++] = data;
- if (--sc->in_left <= 0)
- break; /* deliver data */
- return;
- case MIDI_IN_SYSEX:
- if (data == MIDI_SYSEX_END)
- sc->in_state = MIDI_IN_START;
- return;
- }
-deliver:
- sc->in_state = MIDI_IN_START;
-#if NSEQUENCER > 0
- if (sc->seqopen) {
- extern void midiseq_in(struct midi_dev *,u_char *,int);
- midiseq_in(sc->seq_md, sc->in_msg, sc->in_pos);
- return;
- }
-#endif
-
- if (mb->used + sc->in_pos > mb->usedhigh) {
- DPRINTF(("midi_in: buffer full, discard data=0x%02x\n",
- sc->in_msg[0]));
- return;
+ sc->isbusy = 0;
+ if (sc->wchan) {
+ sc->wchan = 0;
+ wakeup(&sc->wchan);
}
- for (i = 0; i < sc->in_pos; i++) {
- *mb->inp++ = sc->in_msg[i];
- if (mb->inp >= mb->end)
- mb->inp = mb->start;
- mb->used++;
- }
- midi_wakeup(&sc->rchan);
- selwakeup(&sc->rsel);
+ selwakeup(&sc->wsel);
if (sc->async)
psignal(sc->async, SIGIO);
}
-void
-midi_out(addr)
- void *addr;
-{
- struct midi_softc *sc = addr;
-
- if (!sc->isopen)
- return;
- DPRINTFN(3, ("midi_out: %p\n", sc));
- midi_start_output(sc, 1);
-}
-int
-midiopen(dev, flags, ifmt, p)
- dev_t dev;
- int flags, ifmt;
- struct proc *p;
+ /*
+ * drain output buffer, must be called with
+ * interrupts disabled
+ */
+void
+midi_out_do(struct midi_softc *sc)
{
- int unit = MIDIUNIT(dev);
- struct midi_softc *sc;
- struct midi_hw_if *hw;
- int error;
-
- if (unit >= midi_cd.cd_ndevs ||
- (sc = midi_cd.cd_devs[unit]) == NULL)
- return (ENXIO);
- DPRINTF(("midiopen %p\n", sc));
-
- hw = sc->hw_if;
- if (!hw)
- return (ENXIO);
- if (sc->isopen)
- return (EBUSY);
- sc->in_state = MIDI_IN_START;
- sc->in_status = 0;
- error = hw->open(sc->hw_hdl, flags, midi_in, midi_out, sc);
- if (error)
- return (error);
- sc->isopen++;
- midi_initbuf(&sc->outbuf);
- midi_initbuf(&sc->inbuf);
- sc->flags = flags;
- sc->rchan = 0;
- sc->wchan = 0;
- sc->pbus = 0;
- sc->async = 0;
+ struct midi_buffer *mb = &sc->outbuf;
+ unsigned i, max;
+ unsigned data;
+ int error;
+
+ /*
+ * If output interrupts are not supported then we write MIDI_MAXWRITE
+ * bytes instead of 1, and then we wait sc->wait
+ */
+
+ max = sc->props & MIDI_PROP_OUT_INTR ? 1 : MIDI_MAXWRITE;
+ for (i = max; i != 0;) {
+ if (mb->used == 0)
+ break;
-#ifdef MIDI_SAVE
- if (midicnt != 0) {
- midisave.cnt = midicnt;
- midicnt = 0;
+ MIDIBUF_READ(mb, data);
+ error = sc->hw_if->output(sc->hw_hdl, data);
+ /*
+ * EINPROGRESS means that data has been handled,
+ * but will not be sent immediately and thus will
+ * not generate interrupt, in this case we can
+ * send another byte
+ */
+ if (error == EINPROGRESS) {
+ if (MIDIBUF_ISEMPTY(mb)) {
+ midi_out_stop(sc);
+ return;
+ }
+ } else
+ i--;
}
-#endif
-
- return (0);
-}
-
-int
-midiclose(dev, flags, ifmt, p)
- dev_t dev;
- int flags, ifmt;
- struct proc *p;
-{
- int unit = MIDIUNIT(dev);
- struct midi_softc *sc = midi_cd.cd_devs[unit];
- struct midi_hw_if *hw = sc->hw_if;
- int s, error;
-
- DPRINTF(("midiclose %p\n", sc));
-
- midi_start_output(sc, 0);
- error = 0;
- s = splaudio();
- while (sc->outbuf.used > 0 && !error) {
- DPRINTFN(2,("midiclose sleep used=%d\n", sc->outbuf.used));
- error = midi_sleep_timo(&sc->wchan, "mid_dr", 30*hz);
+
+ if (!(sc->props & MIDI_PROP_OUT_INTR)) {
+ if (i < max) {
+ if (MIDIBUF_ISEMPTY(mb))
+ midi_out_stop(sc);
+ } else
+ timeout_add(&sc->timeo, sc->wait);
}
- splx(s);
- sc->isopen = 0;
- hw->close(sc->hw_hdl);
-#if NSEQUENCER > 0
- sc->seqopen = 0;
- sc->seq_md = 0;
-#endif
- return (0);
}
+
int
-midiread(dev, uio, ioflag)
- dev_t dev;
- struct uio *uio;
- int ioflag;
+midiwrite(dev_t dev, struct uio *uio, int ioflag)
{
- int unit = MIDIUNIT(dev);
- struct midi_softc *sc = midi_cd.cd_devs[unit];
- struct midi_buffer *mb = &sc->inbuf;
- int error;
- u_char *outp;
- int used, cc, n, resid;
- int s;
-
- DPRINTF(("midiread: %p, count=%d\n", sc, uio->uio_resid));
-
- error = 0;
- resid = uio->uio_resid;
- while (uio->uio_resid == resid && !error) {
+ struct midi_softc *sc = MIDI_DEV2SC(dev);
+ struct midi_buffer *mb = &sc->outbuf;
+ unsigned count;
+ int s, error;
+
+ if (!(sc->flags & FWRITE))
+ return ENXIO;
+ if (sc->isdying)
+ return EIO;
+
+ /*
+ * If IO_NDELAY flag is set then check if there is enough room
+ * in the buffer to store at least one byte. If not then dont
+ * start the write process.
+ */
+
+ if ((ioflag & IO_NDELAY) && MIDIBUF_ISFULL(mb) &&
+ (uio->uio_resid > 0))
+ return EWOULDBLOCK;
+
+ while (uio->uio_resid > 0) {
s = splaudio();
- while (mb->used <= 0) {
+ while (MIDIBUF_ISFULL(mb)) {
if (ioflag & IO_NDELAY) {
+ /*
+ * At this stage at least one byte is already
+ * moved so we do not return EWOULDBLOCK
+ */
splx(s);
- return (EWOULDBLOCK);
+ return 0;
}
- error = midi_sleep(&sc->rchan, "mid rd");
+ sc->wchan = 1;
+ error = tsleep(&sc->wchan, PWAIT|PCATCH, "mid_wr", 0);
if (error) {
splx(s);
- return (error);
+ return error;
+ }
+ if (sc->isdying) {
+ splx(s);
+ return EIO;
}
}
- used = mb->used;
- outp = mb->outp;
- splx(s);
- cc = used; /* maximum to read */
- n = mb->end - outp;
- if (n < cc)
- cc = n; /* don't read beyond end of buffer */
- if (uio->uio_resid < cc)
- cc = uio->uio_resid; /* and no more than we want */
- DPRINTFN(3, ("midiread: uiomove cc=%d\n", cc));
- error = uiomove(outp, cc, uio);
- if (error)
- break;
- used -= cc;
- outp += cc;
- if (outp >= mb->end)
- outp = mb->start;
- s = splaudio();
- mb->outp = outp;
- mb->used = used;
+
+ count = MIDIBUF_SIZE - MIDIBUF_END(mb);
+ if (count > MIDIBUF_AVAIL(mb))
+ count = MIDIBUF_AVAIL(mb);
+ if (count > uio->uio_resid)
+ count = uio->uio_resid;
+ error = uiomove(mb->data + MIDIBUF_END(mb), count, uio);
+ if (error) {
+ splx(s);
+ return error;
+ }
+ mb->used += count;
+ midi_out_start(sc);
splx(s);
}
- return (error);
+ return 0;
}
-void
-midi_timeout(arg)
- void *arg;
-{
- struct midi_softc *sc = arg;
-
- DPRINTFN(3,("midi_timeout: %p\n", sc));
- midi_start_output(sc, 1);
-}
int
-midi_start_output(sc, intr)
- struct midi_softc *sc;
- int intr;
+midipoll(dev_t dev, int events, struct proc *p)
{
- struct midi_buffer *mb = &sc->outbuf;
- u_char *outp;
- int error;
- int s;
- int i, mmax;
+ struct midi_softc *sc = MIDI_DEV2SC(dev);
+ int s, revents;
+
+ if (sc->isdying)
+ return EIO;
- error = 0;
- mmax = sc->props & MIDI_PROP_OUT_INTR ? 1 : MIDI_MAX_WRITE;
+ revents = 0;
s = splaudio();
- if (sc->pbus && !intr) {
- DPRINTFN(4, ("midi_start_output: busy\n"));
- splx(s);
- return (0);
+ if (events & (POLLIN | POLLRDNORM)) {
+ if (!MIDIBUF_ISEMPTY(&sc->inbuf))
+ revents |= events & (POLLIN | POLLRDNORM);
}
- sc->pbus = 1;
- for (i = 0; i < mmax && mb->used > 0 && !error; i++) {
- outp = mb->outp;
- splx(s);
- DPRINTFN(4, ("midi_start_output: %p i=%d, data=0x%02x\n",
- sc, i, *outp));
-#ifdef MIDI_SAVE
- midisave.buf[midicnt] = *outp;
- midicnt = (midicnt + 1) % MIDI_SAVE_SIZE;
-#endif
- error = sc->hw_if->output(sc->hw_hdl, *outp++);
- if (outp >= mb->end)
- outp = mb->start;
- s = splaudio();
- mb->outp = outp;
- mb->used--;
+ if (events & (POLLOUT | POLLWRNORM)) {
+ if (!MIDIBUF_ISFULL(&sc->outbuf))
+ revents |= events & (POLLOUT | POLLWRNORM);
+ }
+ if (revents == 0) {
+ if (events & (POLLIN | POLLRDNORM))
+ selrecord(p, &sc->rsel);
+ if (events & (POLLOUT | POLLWRNORM))
+ selrecord(p, &sc->wsel);
}
- midi_wakeup(&sc->wchan);
- selwakeup(&sc->wsel);
- if (sc->async)
- psignal(sc->async, SIGIO);
- if (mb->used > 0) {
- if (!(sc->props & MIDI_PROP_OUT_INTR))
- timeout_add(&sc->timeo, midi_wait);
- } else
- sc->pbus = 0;
splx(s);
- return (error);
+ return (revents);
}
+
int
-midiwrite(dev, uio, ioflag)
- dev_t dev;
- struct uio *uio;
- int ioflag;
+midiioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p)
{
- int unit = MIDIUNIT(dev);
- struct midi_softc *sc = midi_cd.cd_devs[unit];
- struct midi_buffer *mb = &sc->outbuf;
- int error;
- u_char *inp;
- int used, cc, n;
- int s;
+ struct midi_softc *sc = MIDI_DEV2SC(dev);
- DPRINTFN(2, ("midiwrite: %p, unit=%d, count=%d\n", sc, unit,
- uio->uio_resid));
+ if (sc->isdying) return EIO;
- error = 0;
- while (uio->uio_resid > 0 && !error) {
- s = splaudio();
- if (mb->used >= mb->usedhigh) {
- DPRINTFN(3,("midi_write: sleep used=%d hiwat=%d\n",
- mb->used, mb->usedhigh));
- if (ioflag & IO_NDELAY) {
- splx(s);
- return (EWOULDBLOCK);
- }
- error = midi_sleep(&sc->wchan, "mid wr");
- if (error) {
- splx(s);
- return (error);
- }
- }
- used = mb->used;
- inp = mb->inp;
- splx(s);
- cc = mb->usedhigh - used; /* maximum to write */
- n = mb->end - inp;
- if (n < cc)
- cc = n; /* don't write beyond end of buffer */
- if (uio->uio_resid < cc)
- cc = uio->uio_resid; /* and no more than we have */
- error = uiomove(inp, cc, uio);
-#ifdef MIDI_DEBUG
- if (error)
- printf("midi_write:(1) uiomove failed %d; "
- "cc=%d inp=%p\n",
- error, cc, inp);
-#endif
- if (error)
- break;
- inp = mb->inp + cc;
- if (inp >= mb->end)
- inp = mb->start;
- s = splaudio();
- mb->inp = inp;
- mb->used += cc;
- splx(s);
- error = midi_start_output(sc, 0);
+ switch(cmd) {
+ case FIONBIO:
+ /* All handled in the upper FS layer */
+ break;
+ case FIOASYNC:
+ if (*(int *)addr) {
+ if (sc->async) return EBUSY;
+ sc->async = p;
+ } else
+ sc->async = 0;
+ break;
+ default:
+ return ENOTTY;
+ break;
}
- return (error);
+ return 0;
}
-/*
- * This write routine is only called from sequencer code and expects
- * a write that is smaller than the MIDI buffer.
- */
+
int
-midi_writebytes(unit, buf, cc)
- int unit;
- u_char *buf;
- int cc;
+midiopen(dev_t dev, int flags, int mode, struct proc *p)
{
- struct midi_softc *sc = midi_cd.cd_devs[unit];
- struct midi_buffer *mb = &sc->outbuf;
- int n, s;
+ struct midi_softc *sc;
+ int err;
+
+ if (MIDI_UNIT(dev) >= midi_cd.cd_ndevs)
+ return ENXIO;
+ sc = MIDI_DEV2SC(dev);
+ if (sc == NULL) /* there may be more units than devices */
+ return ENXIO;
+ if (sc->isdying)
+ return EIO;
+ if (sc->isopen)
+ return EBUSY;
- DPRINTFN(2, ("midi_writebytes: %p, unit=%d, cc=%d\n", sc, unit, cc));
- DPRINTFN(3, ("midi_writebytes: %x %x %x\n",buf[0],buf[1],buf[2]));
+ MIDIBUF_INIT(&sc->inbuf);
+ MIDIBUF_INIT(&sc->outbuf);
+ sc->isbusy = 0;
+ sc->rchan = sc->wchan = 0;
+ sc->async = 0;
+ sc->flags = flags;
- s = splaudio();
- if (mb->used + cc >= mb->usedhigh) {
- splx(s);
- return (EWOULDBLOCK);
- }
- n = mb->end - mb->inp;
- if (cc < n)
- n = cc;
- mb->used += cc;
- bcopy(buf, mb->inp, n);
- mb->inp += n;
- if (mb->inp >= mb->end) {
- mb->inp = mb->start;
- cc -= n;
- if (cc > 0) {
- bcopy(buf + n, mb->inp, cc);
- mb->inp += cc;
+ err = sc->hw_if->open(sc->hw_hdl, flags, midi_iintr, midi_ointr, sc);
+ if (err)
+ return err;
+ sc->isopen = 1;
+#if NSEQUENCER > 0
+ sc->seq_md = 0;
+ sc->seqopen = 0;
+ sc->evstatus = 0xff;
+#endif
+ return 0;
+}
+
+
+int
+midiclose(dev_t dev, int fflag, int devtype, struct proc *p)
+{
+ struct midi_softc *sc = MIDI_DEV2SC(dev);
+ struct midi_buffer *mb;
+ int error;
+ int s;
+
+ mb = &sc->outbuf;
+ if (!sc->isdying) {
+ /* start draining output buffer */
+ s = splaudio();
+ if (!MIDIBUF_ISEMPTY(mb))
+ midi_out_start(sc);
+ while (sc->isbusy) {
+ sc->wchan = 1;
+ error = tsleep(&sc->wchan, PWAIT|PCATCH, "mid_dr", 0);
+ if (error || sc->isdying)
+ break;
}
+ splx(s);
}
- splx(s);
- return (midi_start_output(sc, 0));
+
+ /*
+ * some hw_if->close() reset immediately the midi uart
+ * which flushes the internal buffer of the uart device,
+ * so we may lose some (important) data. To avoid this, we sleep 2*wait,
+ * which gives the time to the uart to drain its internal buffers.
+ *
+ * Note: we'd better sleep in the corresponding hw_if->close()
+ */
+
+ tsleep(&sc->wchan, PWAIT|PCATCH, "mid_cl", 2 * sc->wait);
+ sc->hw_if->close(sc->hw_hdl);
+ sc->isopen = 0;
+ return 0;
}
+
int
-midiioctl(dev, cmd, addr, flag, p)
- dev_t dev;
- u_long cmd;
- caddr_t addr;
- int flag;
- struct proc *p;
+midiprobe(struct device *parent, void *match, void *aux)
{
- int unit = MIDIUNIT(dev);
- struct midi_softc *sc = midi_cd.cd_devs[unit];
- struct midi_hw_if *hw = sc->hw_if;
- int error;
-
- DPRINTF(("midiioctl: %p cmd=0x%08lx\n", sc, cmd));
- error = 0;
- switch (cmd) {
- case FIONBIO:
- /* All handled in the upper FS layer. */
- break;
+ struct audio_attach_args *sa = aux;
+ return (sa != NULL && (sa->type == AUDIODEV_TYPE_MIDI) ? 1 : 0);
+}
- case FIOASYNC:
- if (*(int *)addr) {
- if (sc->async)
- return (EBUSY);
- sc->async = p;
- DPRINTF(("midi_ioctl: FIOASYNC %p\n", p));
- } else
- sc->async = 0;
- break;
-#if 0
- case MIDI_PRETIME:
- /* XXX OSS
- * This should set up a read timeout, but that's
- * why we have poll(), so there's nothing yet. */
- error = EINVAL;
- break;
-#endif
+void
+midi_attach(struct midi_softc *sc, struct device *parent)
+{
+ struct midi_info mi;
+
+ sc->isdying = 0;
+ sc->wait = (hz * MIDI_MAXWRITE) / MIDI_RATE;
+ if (sc->wait == 0)
+ sc->wait = 1;
+ sc->hw_if->getinfo(sc->hw_hdl, &mi);
+ sc->props = mi.props;
+ sc->isopen = 0;
+ timeout_set(&sc->timeo, midi_ointr, sc);
+ printf(": <%s>\n", mi.name);
+}
-#ifdef MIDI_SAVE
- case MIDI_GETSAVE:
- error = copyout(&midisave, *(void **)addr, sizeof midisave);
- break;
-#endif
- default:
- if (hw->ioctl)
- error = hw->ioctl(sc->hw_hdl, cmd, addr, flag, p);
- else
- error = ENOTTY;
- break;
+void
+midiattach(struct device *parent, struct device *self, void *aux)
+{
+ struct midi_softc *sc = (struct midi_softc *)self;
+ struct audio_attach_args *sa = (struct audio_attach_args *)aux;
+ struct midi_hw_if *hwif = sa->hwif;
+ void *hdl = sa->hdl;
+
+#ifdef DIAGNOSTIC
+ if (hwif == 0 ||
+ hwif->open == 0 ||
+ hwif->close == 0 ||
+ hwif->output == 0 ||
+ hwif->getinfo == 0) {
+ printf("midi: missing method\n");
+ return;
}
- return (error);
+#endif
+ sc->hw_if = hwif;
+ sc->hw_hdl = hdl;
+ midi_attach(sc, parent);
}
+
int
-midipoll(dev, events, p)
- dev_t dev;
- int events;
- struct proc *p;
+mididetach(struct device *self, int flags)
{
- int unit = MIDIUNIT(dev);
- struct midi_softc *sc = midi_cd.cd_devs[unit];
- int revents = 0, s = splaudio();
-
- DPRINTF(("midipoll: %p events=0x%x\n", sc, events));
-
- if (events & (POLLIN | POLLRDNORM)) {
- if (sc->inbuf.used > 0)
- revents |= events & (POLLIN | POLLRDNORM);
- }
- if (events & (POLLOUT | POLLWRNORM)) {
- if (sc->outbuf.used < sc->outbuf.usedhigh)
- revents |= events & (POLLOUT | POLLWRNORM);
+ struct midi_softc *sc = (struct midi_softc *)self;
+ int maj, mn;
+
+ sc->isdying = 1;
+ if (sc->wchan) {
+ sc->wchan = 0;
+ wakeup(&sc->wchan);
}
- if (revents == 0) {
- if (events & (POLLIN | POLLRDNORM))
- selrecord(p, &sc->rsel);
- if (events & (POLLOUT | POLLWRNORM))
- selrecord(p, &sc->wsel);
+ if (sc->rchan) {
+ sc->rchan = 0;
+ wakeup(&sc->rchan);
}
+
+ /* locate the major number */
+ for (maj = 0; maj < nchrdev; maj++)
+ if (cdevsw[maj].d_open == midiopen)
+ break;
- splx(s);
- return (revents);
+ /* Nuke the vnodes for any open instances (calls close). */
+ mn = self->dv_unit;
+ vdevgone(maj, mn, mn, VCHR);
+
+ return 0;
}
-void
-midi_getinfo(dev, mi)
- dev_t dev;
- struct midi_info *mi;
+
+int
+midiprint(void *aux, const char *pnp)
{
- int unit = MIDIUNIT(dev);
- struct midi_softc *sc;
+ if (pnp)
+ printf("midi at %s", pnp);
+ return (UNCONF);
+}
+
- if (unit >= midi_cd.cd_ndevs ||
- (sc = midi_cd.cd_devs[unit]) == NULL)
+void
+midi_getinfo(dev_t dev, struct midi_info *mi)
+{
+ struct midi_softc *sc = MIDI_DEV2SC(dev);
+ if (MIDI_UNIT(dev) >= midi_cd.cd_ndevs || sc == NULL || sc->isdying) {
+ mi->name = "unconfigured";
+ mi->props = 0;
return;
+ }
sc->hw_if->getinfo(sc->hw_hdl, mi);
}
-#endif /* NMIDI > 0 */
-
-#if (NMIDI > 0 || NMIDIBUS > 0) && NAUDIO > 0
-
-int midiprint(void *, const char *);
struct device *
-midi_attach_mi(mhwp, hdlp, dev)
- struct midi_hw_if *mhwp;
- void *hdlp;
- struct device *dev;
+midi_attach_mi(struct midi_hw_if *hwif, void *hdl, struct device *dev)
{
struct audio_attach_args arg;
-#ifdef DIAGNOSTIC
- if (mhwp == NULL) {
- printf("midi_attach_mi: NULL\n");
- return 0;
- }
-#endif
arg.type = AUDIODEV_TYPE_MIDI;
- arg.hwif = mhwp;
- arg.hdl = hdlp;
+ arg.hwif = hwif;
+ arg.hdl = hdl;
return config_found(dev, &arg, midiprint);
}
+
int
-midiprint(aux, pnp)
- void *aux;
- const char *pnp;
+midi_unit_count(void)
{
- if (pnp)
- printf("midi at %s", pnp);
- return (UNCONF);
+ return midi_cd.cd_ndevs;
}
-#endif /* NMIDI > 0 || NMIDIBUS > 0 */
+
+#if NSEQUENCER > 0
+#define MIDI_EVLEN(status) (midi_evlen[((status) >> 4) & 7])
+unsigned midi_evlen[] = { 2, 2, 2, 2, 1, 1, 2 };
+
+void
+midi_toevent(struct midi_softc *sc, int data)
+{
+ unsigned char mesg[3];
+
+ if (data >= 0xf8) { /* is it a realtime message ? */
+ switch(data) {
+ case 0xf8: /* midi timer tic */
+ case 0xfa: /* midi timer start */
+ case 0xfb: /* midi timer continue (after stop) */
+ case 0xfc: /* midi timer stop */
+ mesg[0] = data;
+ midiseq_in(sc->seq_md, mesg, 1);
+ break;
+ default:
+ break;
+ }
+ } else if (data >= 0x80) { /* is it a common or voice message ? */
+ sc->evstatus = data;
+ sc->evindex = 0;
+ } else { /* else it is a data byte */
+ /* strip common messages and bogus data */
+ if (sc->evstatus >= 0xf0 || sc->evstatus < 0x80)
+ return;
+
+ sc->evdata[sc->evindex++] = data;
+ if (sc->evindex == MIDI_EVLEN(sc->evstatus)) {
+ sc->evindex = 0;
+ mesg[0] = sc->evstatus;
+ mesg[1] = sc->evdata[0];
+ mesg[2] = sc->evdata[1];
+ midiseq_in(sc->seq_md, mesg, 1 + MIDI_EVLEN(sc->evstatus));
+ }
+ }
+}
+
+
+int
+midi_writebytes(int unit, unsigned char *mesg, int mesglen)
+{
+ struct midi_softc *sc = midi_cd.cd_devs[unit];
+ struct midi_buffer *mb = &sc->outbuf;
+ unsigned count;
+ int s;
+
+ s = splaudio();
+ if (mesglen > MIDIBUF_AVAIL(mb)) {
+ splx(s);
+ return EWOULDBLOCK;
+ }
+
+ while (mesglen > 0) {
+ count = MIDIBUF_SIZE - MIDIBUF_END(mb);
+ if (count > MIDIBUF_AVAIL(mb)) count = MIDIBUF_AVAIL(mb);
+ if (count > mesglen) count = mesglen;
+ bcopy(mesg, mb->data + MIDIBUF_END(mb), count);
+ mb->used += count;
+ mesg += count;
+ mesglen -= count;
+ midi_out_start(sc);
+ }
+ splx(s);
+ return 0;
+}
+
+#endif /* NSEQUENCER > 0 */
+#endif /* NMIDI > 0 */
diff --git a/sys/dev/midivar.h b/sys/dev/midivar.h
index 2576d7e6051..030b69dc27b 100644
--- a/sys/dev/midivar.h
+++ b/sys/dev/midivar.h
@@ -1,96 +1,102 @@
-/* $OpenBSD: midivar.h,v 1.2 2000/06/26 22:43:22 art Exp $ */
-/* $NetBSD: midivar.h,v 1.6 1998/11/25 22:17:07 augustss Exp $ */
-
/*
- * Copyright (c) 1998 The NetBSD Foundation, Inc.
- * All rights reserved.
- *
- * This code is derived from software contributed to The NetBSD Foundation
- * by Lennart Augustsson (augustss@netbsd.org).
+ * Copyright (c) 2003, 2004 Alexandre Ratchov
*
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the NetBSD
- * Foundation, Inc. and its contributors.
- * 4. Neither the name of The NetBSD Foundation nor the names of its
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
*
- * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
- * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
- * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
- * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef _SYS_DEV_MIDIVAR_H_
#define _SYS_DEV_MIDIVAR_H_
-#define MIDI_BUFSIZE 1024
+#include <dev/midi_if.h>
+#include <sys/device.h>
+#include <sys/select.h>
+#include <sys/proc.h>
+#include <sys/timeout.h>
+
+#define MIDI_MAXWRITE 32 /* max bytes to give to the uart at once */
+#define MIDI_RATE 3125 /* midi uart baud rate in bytes/second */
+#define MIDI_UNIT(a) ((a) & 0xff)
+#define MIDI_DEV2SC(a) (midi_cd.cd_devs[MIDI_UNIT(a)])
#include "sequencer.h"
-#include <sys/timeout.h>
+#if NSEQUENCER > 0
+struct midi_dev; /* defined in sequencervar.h */
+#endif
+
+/*
+ * simple ring buffer
+ */
+#define MIDIBUF_SIZE (1 << 10)
+#define MIDIBUF_MASK (MIDIBUF_SIZE - 1)
struct midi_buffer {
- u_char *inp;
- u_char *outp;
- u_char *end;
- int used;
- int usedhigh;
- u_char start[MIDI_BUFSIZE];
+ unsigned char data[MIDIBUF_SIZE];
+ unsigned start, used;
};
-
-#define MIDI_MAX_WRITE 32 /* max bytes written with busy wait */
-#define MIDI_WAIT 10000 /* microseconds to wait after busy wait */
+#define MIDIBUF_START(buf) ((buf)->start)
+#define MIDIBUF_END(buf) (((buf)->start + (buf)->used) & MIDIBUF_MASK)
+#define MIDIBUF_USED(buf) ((buf)->used)
+#define MIDIBUF_AVAIL(buf) (MIDIBUF_SIZE - (buf)->used)
+#define MIDIBUF_ISFULL(buf) ((buf)->used >= MIDIBUF_SIZE)
+#define MIDIBUF_ISEMPTY(buf) ((buf)->used == 0)
+#define MIDIBUF_WRITE(buf, byte) \
+ do { \
+ (buf)->data[MIDIBUF_END(buf)] = (byte); \
+ (buf)->used++; \
+ } while(0)
+#define MIDIBUF_READ(buf, byte) \
+ do { \
+ (byte) = (buf)->data[(buf)->start++]; \
+ (buf)->start &= MIDIBUF_MASK; \
+ (buf)->used--; \
+ } while(0)
+#define MIDIBUF_REMOVE(buf, count) \
+ do { \
+ (buf)->start += (count); \
+ (buf)->start &= MIDIBUF_MASK; \
+ (buf)->used -= (count); \
+ } while(0)
+#define MIDIBUF_INIT(buf) \
+ do { \
+ (buf)->start = (buf)->used = 0; \
+ } while(0)
+
struct midi_softc {
- struct device dev;
- void *hw_hdl; /* Hardware driver handle */
- struct midi_hw_if *hw_if; /* Hardware interface */
- struct device *sc_dev; /* Hardware device struct */
- int isopen; /* Open indicator */
- int flags; /* Open flags */
- struct midi_buffer outbuf;
- struct midi_buffer inbuf;
- int props;
- int rchan, wchan;
- int pbus;
- struct selinfo wsel; /* write selector */
- struct selinfo rsel; /* read selector */
- struct proc *async; /* process who wants audio SIGIO */
- struct timeout timeo; /* timeout handle */
-
- /* MIDI input state machine */
- int in_state;
-#define MIDI_IN_START 0
-#define MIDI_IN_DATA 1
-#define MIDI_IN_SYSEX 2
- u_char in_msg[3];
- u_char in_status;
- u_int in_left;
- u_int in_pos;
-
+ struct device dev;
+ struct midi_hw_if *hw_if;
+ void *hw_hdl;
+ int isopen;
+ int isbusy; /* concerns only the output */
+ int isdying;
+ int flags; /* open flags */
+ int props; /* midi hw proprieties */
+ int rchan;
+ int wchan;
+ unsigned wait; /* see midi_out_do */
+ struct selinfo rsel;
+ struct selinfo wsel;
+ struct proc *async;
+ struct timeout timeo;
+ struct midi_buffer inbuf;
+ struct midi_buffer outbuf;
#if NSEQUENCER > 0
- /* Synthesizer emulation stuff */
- int seqopen;
- struct midi_dev *seq_md; /* structure that links us with the seq. */
-#endif
+ int seqopen;
+ struct midi_dev *seq_md; /* structure that links us with the seq. */
+ int evindex;
+ unsigned char evstatus;
+ unsigned char evdata[2];
+#endif /* NSEQUENCER > 0 */
};
-#define MIDIUNIT(d) ((d) & 0xff)
-
#endif /* _SYS_DEV_MIDIVAR_H_ */
diff --git a/sys/dev/usb/umidi.c b/sys/dev/usb/umidi.c
index 266b719820d..9188f8fb55d 100644
--- a/sys/dev/usb/umidi.c
+++ b/sys/dev/usb/umidi.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: umidi.c,v 1.9 2003/05/19 00:36:33 nate Exp $ */
+/* $OpenBSD: umidi.c,v 1.10 2004/06/27 19:44:48 deraadt Exp $ */
/* $NetBSD: umidi.c,v 1.16 2002/07/11 21:14:32 augustss Exp $ */
/*
* Copyright (c) 2001 The NetBSD Foundation, Inc.
@@ -123,7 +123,7 @@ static usbd_status start_output_transfer(struct umidi_endpoint *);
static int out_jack_output(struct umidi_jack *, int);
static void in_intr(usbd_xfer_handle, usbd_private_handle, usbd_status);
static void out_intr(usbd_xfer_handle, usbd_private_handle, usbd_status);
-static void out_build_packet(int, struct umidi_packet *, uByte);
+static int out_build_packet(int, struct umidi_packet *, uByte);
struct midi_hw_if umidi_hw_if = {
@@ -163,6 +163,7 @@ USB_ATTACH(umidi)
usbd_status err;
USB_ATTACH_START(umidi, sc, uaa);
char devinfo[1024];
+ int i;
DPRINTFN(1,("umidi_attach\n"));
@@ -180,15 +181,11 @@ USB_ATTACH(umidi)
err = alloc_all_endpoints(sc);
if (err!=USBD_NORMAL_COMPLETION) {
- printf("%s: alloc_all_endpoints failed. (err=%d)\n",
- USBDEVNAME(sc->sc_dev), err);
goto error;
}
err = alloc_all_jacks(sc);
if (err!=USBD_NORMAL_COMPLETION) {
free_all_endpoints(sc);
- printf("%s: alloc_all_jacks failed. (err=%d)\n",
- USBDEVNAME(sc->sc_dev), err);
goto error;
}
printf("%s: out=%d, in=%d\n",
@@ -200,22 +197,22 @@ USB_ATTACH(umidi)
unbind_all_jacks(sc);
free_all_jacks(sc);
free_all_endpoints(sc);
- printf("%s: assign_all_jacks_automatically failed. (err=%d)\n",
- USBDEVNAME(sc->sc_dev), err);
goto error;
}
err = attach_all_mididevs(sc);
if (err!=USBD_NORMAL_COMPLETION) {
free_all_jacks(sc);
free_all_endpoints(sc);
- printf("%s: attach_all_mididevs failed. (err=%d)\n",
- USBDEVNAME(sc->sc_dev), err);
}
#ifdef UMIDI_DEBUG
dump_sc(sc);
#endif
+ for (i = 0; i < sc->sc_in_num_endpoints; i++) {
+ (void)start_input_transfer(&sc->sc_in_ep[i]);
+ }
+
usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH,
sc->sc_udev, USBDEV(sc->sc_dev));
@@ -328,7 +325,6 @@ void
umidi_getinfo(void *addr, struct midi_info *mi)
{
struct umidi_mididev *mididev = addr;
-/* struct umidi_softc *sc = mididev->sc; */
mi->name = "USB MIDI I/F"; /* XXX: model name */
mi->props = MIDI_PROP_OUT_INTR;
@@ -349,23 +345,22 @@ alloc_pipe(struct umidi_endpoint *ep)
usbd_status err;
DPRINTF(("%s: alloc_pipe %p\n", USBDEVNAME(sc->sc_dev), ep));
- LIST_INIT(&ep->queue_head);
+ TAILQ_INIT(&ep->queue_head);
ep->xfer = usbd_alloc_xfer(sc->sc_udev);
if (ep->xfer == NULL) {
- err = USBD_NOMEM;
- goto quit;
+ return USBD_NOMEM;
}
- ep->buffer = usbd_alloc_buffer(ep->xfer, UMIDI_PACKET_SIZE);
+ ep->buffer = usbd_alloc_buffer(ep->xfer, ep->packetsize);
if (ep->buffer == NULL) {
- usbd_free_xfer(ep->xfer);
- err = USBD_NOMEM;
- goto quit;
+ usbd_free_xfer(ep->xfer);
+ return USBD_NOMEM;
}
err = usbd_open_pipe(sc->sc_iface, ep->addr, 0, &ep->pipe);
- if (err)
- usbd_free_xfer(ep->xfer);
-quit:
- return err;
+ if (err != USBD_NORMAL_COMPLETION) {
+ usbd_free_xfer(ep->xfer);
+ return err;
+ }
+ return USBD_NORMAL_COMPLETION;
}
static void
@@ -403,14 +398,17 @@ alloc_all_endpoints(struct umidi_softc *sc)
ep = sc->sc_endpoints;
for (i=sc->sc_out_num_endpoints+sc->sc_in_num_endpoints; i>0; i--) {
- err = alloc_pipe(ep++);
+ err = alloc_pipe(ep);
if (err!=USBD_NORMAL_COMPLETION) {
- for (; ep!=sc->sc_endpoints; ep--)
- free_pipe(ep-1);
+ while(ep != sc->sc_endpoints) {
+ ep--;
+ free_pipe(ep);
+ }
free(sc->sc_endpoints, M_USBDEV);
sc->sc_endpoints = sc->sc_out_ep = sc->sc_in_ep = NULL;
break;
}
+ ep++;
}
return err;
}
@@ -459,8 +457,8 @@ alloc_all_endpoints_fixed_ep(struct umidi_softc *sc)
sc->sc_iface,
fp->out_ep[i].ep);
if (!epd) {
- printf("%s: cannot get endpoint descriptor(out:%d)\n",
- USBDEVNAME(sc->sc_dev), fp->out_ep[i].ep);
+ DPRINTF(("%s: cannot get endpoint descriptor(out:%d)\n",
+ USBDEVNAME(sc->sc_dev), fp->out_ep[i].ep));
err = USBD_INVAL;
goto error;
}
@@ -472,12 +470,13 @@ alloc_all_endpoints_fixed_ep(struct umidi_softc *sc)
goto error;
}
ep->sc = sc;
+ ep->packetsize = UGETW(epd->wMaxPacketSize);
ep->addr = epd->bEndpointAddress;
ep->num_jacks = fp->out_ep[i].num_jacks;
sc->sc_out_num_jacks += fp->out_ep[i].num_jacks;
ep->num_open = 0;
memset(ep->jacks, 0, sizeof(ep->jacks));
- LIST_INIT(&ep->queue_head);
+ TAILQ_INIT(&ep->queue_head);
ep++;
}
ep = &sc->sc_in_ep[0];
@@ -486,8 +485,8 @@ alloc_all_endpoints_fixed_ep(struct umidi_softc *sc)
sc->sc_iface,
fp->in_ep[i].ep);
if (!epd) {
- printf("%s: cannot get endpoint descriptor(in:%d)\n",
- USBDEVNAME(sc->sc_dev), fp->in_ep[i].ep);
+ DPRINTF(("%s: cannot get endpoint descriptor(in:%d)\n",
+ USBDEVNAME(sc->sc_dev), fp->in_ep[i].ep));
err = USBD_INVAL;
goto error;
}
@@ -500,6 +499,7 @@ alloc_all_endpoints_fixed_ep(struct umidi_softc *sc)
}
ep->sc = sc;
ep->addr = epd->bEndpointAddress;
+ ep->packetsize = UGETW(epd->wMaxPacketSize);
ep->num_jacks = fp->in_ep[i].num_jacks;
sc->sc_in_num_jacks += fp->in_ep[i].num_jacks;
ep->num_open = 0;
@@ -520,7 +520,7 @@ alloc_all_endpoints_yamaha(struct umidi_softc *sc)
/* This driver currently supports max 1in/1out bulk endpoints */
usb_descriptor_t *desc;
usb_endpoint_descriptor_t *epd;
- int out_addr, in_addr, i;
+ int out_addr, in_addr, in_packetsize, i;
int dir;
size_t remain, descsize;
@@ -535,8 +535,10 @@ alloc_all_endpoints_yamaha(struct umidi_softc *sc)
dir = UE_GET_DIR(epd->bEndpointAddress);
if (dir==UE_DIR_OUT && !out_addr)
out_addr = epd->bEndpointAddress;
- else if (dir==UE_DIR_IN && !in_addr)
+ else if (dir==UE_DIR_IN && !in_addr) {
in_addr = epd->bEndpointAddress;
+ in_packetsize = UGETW(epd->wMaxPacketSize);
+ }
}
}
desc = NEXT_D(desc);
@@ -591,6 +593,7 @@ alloc_all_endpoints_yamaha(struct umidi_softc *sc)
sc->sc_out_ep = sc->sc_endpoints;
sc->sc_out_ep->sc = sc;
sc->sc_out_ep->addr = out_addr;
+ sc->sc_out_ep->packetsize = UMIDI_PACKET_SIZE;
sc->sc_out_ep->num_jacks = sc->sc_out_num_jacks;
sc->sc_out_ep->num_open = 0;
memset(sc->sc_out_ep->jacks, 0, sizeof(sc->sc_out_ep->jacks));
@@ -601,6 +604,7 @@ alloc_all_endpoints_yamaha(struct umidi_softc *sc)
sc->sc_in_ep = sc->sc_endpoints+sc->sc_out_num_endpoints;
sc->sc_in_ep->sc = sc;
sc->sc_in_ep->addr = in_addr;
+ sc->sc_in_ep->packetsize = in_packetsize;
sc->sc_in_ep->num_jacks = sc->sc_in_num_jacks;
sc->sc_in_ep->num_open = 0;
memset(sc->sc_in_ep->jacks, 0, sizeof(sc->sc_in_ep->jacks));
@@ -613,20 +617,17 @@ alloc_all_endpoints_yamaha(struct umidi_softc *sc)
static usbd_status
alloc_all_endpoints_genuine(struct umidi_softc *sc)
{
+ usb_interface_descriptor_t *interface_desc;
+ usb_config_descriptor_t *config_desc;
usb_descriptor_t *desc;
int num_ep;
size_t remain, descsize;
struct umidi_endpoint *p, *q, *lowest, *endep, tmpep;
- int epaddr;
+ int epaddr, eppacketsize;
- desc = TO_D(usbd_get_interface_descriptor(sc->sc_iface));
- num_ep = TO_IFD(desc)->bNumEndpoints;
- desc = NEXT_D(desc); /* ifd -> csifd */
- remain = ((size_t)UGETW(TO_CSIFD(desc)->wTotalLength) -
- (size_t)desc->bLength);
- desc = NEXT_D(desc);
-
- sc->sc_endpoints = p = malloc(sizeof(struct umidi_endpoint)*num_ep,
+ interface_desc = usbd_get_interface_descriptor(sc->sc_iface);
+ num_ep = interface_desc->bNumEndpoints;
+ sc->sc_endpoints = p = malloc(sizeof(struct umidi_endpoint) * num_ep,
M_USBDEV, M_WAITOK);
if (!p)
return USBD_NOMEM;
@@ -636,6 +637,9 @@ alloc_all_endpoints_genuine(struct umidi_softc *sc)
epaddr = -1;
/* get the list of endpoints for midi stream */
+ config_desc = usbd_get_config_descriptor(sc->sc_udev);
+ desc = (usb_descriptor_t *) config_desc;
+ remain = (size_t)UGETW(config_desc->wTotalLength);
while (remain>=sizeof(usb_descriptor_t)) {
descsize = desc->bLength;
if (descsize>remain || descsize==0)
@@ -644,6 +648,7 @@ alloc_all_endpoints_genuine(struct umidi_softc *sc)
remain>=USB_ENDPOINT_DESCRIPTOR_SIZE &&
UE_GET_XFERTYPE(TO_EPD(desc)->bmAttributes) == UE_BULK) {
epaddr = TO_EPD(desc)->bEndpointAddress;
+ eppacketsize = UGETW(TO_EPD(desc)->wMaxPacketSize);
} else if (desc->bDescriptorType==UDESC_CS_ENDPOINT &&
remain>=UMIDI_CS_ENDPOINT_DESCRIPTOR_SIZE &&
epaddr!=-1) {
@@ -651,6 +656,7 @@ alloc_all_endpoints_genuine(struct umidi_softc *sc)
num_ep--;
p->sc = sc;
p->addr = epaddr;
+ p->packetsize = eppacketsize;
p->num_jacks = TO_CSEPD(desc)->bNumEmbMIDIJack;
if (UE_GET_DIR(epaddr)==UE_DIR_OUT) {
sc->sc_out_num_endpoints++;
@@ -860,8 +866,6 @@ assign_all_jacks_automatically(struct umidi_softc *sc)
static usbd_status
open_out_jack(struct umidi_jack *jack, void *arg, void (*intr)(void *))
{
- struct umidi_endpoint *ep = jack->endpoint;
-
if (jack->opened)
return USBD_IN_USE;
@@ -869,59 +873,34 @@ open_out_jack(struct umidi_jack *jack, void *arg, void (*intr)(void *))
jack->u.out.intr = intr;
init_packet(&jack->packet);
jack->opened = 1;
- ep->num_open++;
-
+ jack->endpoint->num_open++;
+
return USBD_NORMAL_COMPLETION;
}
static usbd_status
open_in_jack(struct umidi_jack *jack, void *arg, void (*intr)(void *, int))
{
- usbd_status err = USBD_NORMAL_COMPLETION;
- struct umidi_endpoint *ep = jack->endpoint;
-
if (jack->opened)
return USBD_IN_USE;
jack->arg = arg;
jack->u.in.intr = intr;
jack->opened = 1;
- if (ep->num_open++==0 && UE_GET_DIR(ep->addr)==UE_DIR_IN) {
- err = start_input_transfer(ep);
- if (err!=USBD_NORMAL_COMPLETION) {
- ep->num_open--;
- }
- }
-
- return err;
+ jack->endpoint->num_open++;
+
+ return USBD_NORMAL_COMPLETION;
}
static void
close_out_jack(struct umidi_jack *jack)
{
- struct umidi_jack *tail;
- int s;
-
if (jack->opened) {
- s = splusb();
- LIST_FOREACH(tail,
- &jack->endpoint->queue_head,
- u.out.queue_entry)
- if (tail == jack) {
- LIST_REMOVE(jack, u.out.queue_entry);
- break;
- }
- if (jack == jack->endpoint->queue_tail) {
- /* find tail */
- LIST_FOREACH(tail,
- &jack->endpoint->queue_head,
- u.out.queue_entry) {
- if (!LIST_NEXT(tail, u.out.queue_entry)) {
- jack->endpoint->queue_tail = tail;
- }
- }
+#ifdef UMIDI_DEBUG
+ if (!TAILQ_EMPTY(&jack->endpoint->queue_head)) {
+ printf("close_out_jack: queue_head still not empty\n");
}
- splx(s);
+#endif
jack->opened = 0;
jack->endpoint->num_open--;
}
@@ -932,7 +911,7 @@ close_in_jack(struct umidi_jack *jack)
{
if (jack->opened) {
jack->opened = 0;
- jack->endpoint->num_open--;
+ jack->endpoint->num_open--;
}
}
@@ -1109,28 +1088,6 @@ static const int packet_length[16] = {
/*F*/ 1,
};
-static const struct {
- int cin;
- packet_state_t next;
-} packet_0xFX[16] = {
- /*F0: SysEx */ { 0x04, PS_EXCL_1 },
- /*F1: MTC */ { 0x02, PS_NORMAL_1OF2 },
- /*F2: S.POS */ { 0x03, PS_NORMAL_1OF3 },
- /*F3: S.SEL */ { 0x02, PS_NORMAL_1OF2 },
- /*F4: UNDEF */ { 0x00, PS_INITIAL },
- /*F5: UNDEF */ { 0x00, PS_INITIAL },
- /*F6: Tune */ { 0x0F, PS_END },
- /*F7: EofEx */ { 0x00, PS_INITIAL },
- /*F8: Timing */ { 0x0F, PS_END },
- /*F9: UNDEF */ { 0x00, PS_INITIAL },
- /*FA: Start */ { 0x0F, PS_END },
- /*FB: Cont */ { 0x0F, PS_END },
- /*FC: Stop */ { 0x0F, PS_END },
- /*FD: UNDEF */ { 0x00, PS_INITIAL },
- /*FE: ActS */ { 0x0F, PS_END },
- /*FF: Reset */ { 0x0F, PS_END },
-};
-
#define GET_CN(p) (((unsigned char)(p)>>4)&0x0F)
#define GET_CIN(p) ((unsigned char)(p)&0x0F)
#define MIX_CN_CIN(cn, cin) \
@@ -1140,33 +1097,46 @@ static const struct {
static void
init_packet(struct umidi_packet *packet)
{
- memset(packet->buffer, 0, UMIDI_PACKET_SIZE);
- packet->state = PS_INITIAL;
+ packet->status = 0;
+ packet->index = 0;
}
static usbd_status
start_input_transfer(struct umidi_endpoint *ep)
{
+ usbd_status err;
usbd_setup_xfer(ep->xfer, ep->pipe,
(usbd_private_handle)ep,
- ep->buffer, UMIDI_PACKET_SIZE,
- USBD_NO_COPY, USBD_NO_TIMEOUT, in_intr);
- return usbd_transfer(ep->xfer);
+ ep->buffer, ep->packetsize,
+ USBD_SHORT_XFER_OK | USBD_NO_COPY, USBD_NO_TIMEOUT, in_intr);
+ err = usbd_transfer(ep->xfer);
+ if (err != USBD_NORMAL_COMPLETION && err != USBD_IN_PROGRESS) {
+ DPRINTF(("%s: start_input_transfer: usbd_transfer() failed err=%s\n",
+ USBDEVNAME(ep->sc->sc_dev), usbd_errstr(err)));
+ return err;
+ }
+ return USBD_NORMAL_COMPLETION;
}
static usbd_status
start_output_transfer(struct umidi_endpoint *ep)
{
+ usbd_status err;
usbd_setup_xfer(ep->xfer, ep->pipe,
(usbd_private_handle)ep,
ep->buffer, UMIDI_PACKET_SIZE,
USBD_NO_COPY, USBD_NO_TIMEOUT, out_intr);
- return usbd_transfer(ep->xfer);
+ err = usbd_transfer(ep->xfer);
+ if (err != USBD_NORMAL_COMPLETION && err != USBD_IN_PROGRESS) {
+ DPRINTF(("%s: start_output_transfer: usbd_transfer() failed err=%s\n",
+ USBDEVNAME(ep->sc->sc_dev), usbd_errstr(err)));
+ return err;
+ }
+ return USBD_NORMAL_COMPLETION;
}
#ifdef UMIDI_DEBUG
#define DPR_PACKET(dir, sc, p) \
-if ((unsigned char)(p)->buffer[1]!=0xFE) \
DPRINTFN(500, \
("%s: umidi packet(" #dir "): %02X %02X %02X %02X\n", \
USBDEVNAME(sc->sc_dev), \
@@ -1183,76 +1153,74 @@ out_jack_output(struct umidi_jack *out_jack, int d)
{
struct umidi_endpoint *ep = out_jack->endpoint;
struct umidi_softc *sc = ep->sc;
- int error;
int s;
if (sc->sc_dying)
return EIO;
- error = 0;
- if (out_jack->opened) {
- DPRINTFN(1000, ("umidi_output: ep=%p 0x%02x\n", ep, d));
- out_build_packet(out_jack->cable_number, &out_jack->packet, d);
- switch (out_jack->packet.state) {
- case PS_EXCL_0:
- case PS_END:
- DPR_PACKET(out, sc, &out_jack->packet);
- s = splusb();
- if (LIST_EMPTY(&ep->queue_head)) {
- memcpy(ep->buffer,
- out_jack->packet.buffer,
- UMIDI_PACKET_SIZE);
- start_output_transfer(ep);
- }
- if (LIST_EMPTY(&ep->queue_head))
- LIST_INSERT_HEAD(&ep->queue_head,
- out_jack, u.out.queue_entry);
- else
- LIST_INSERT_AFTER(ep->queue_tail,
- out_jack, u.out.queue_entry);
- ep->queue_tail = out_jack;
- splx(s);
- break;
- default:
- error = EINPROGRESS;
+ if (!out_jack->opened) {
+ return ENODEV;
+ }
+
+ if (out_build_packet(out_jack->cable_number, &out_jack->packet, d)) {
+ DPR_PACKET(out, sc, &out_jack->packet);
+ s = splusb();
+ if (TAILQ_EMPTY(&ep->queue_head)) {
+ memcpy(ep->buffer,
+ out_jack->packet.buffer,
+ UMIDI_PACKET_SIZE);
+ TAILQ_INSERT_TAIL(&ep->queue_head,
+ out_jack, u.out.queue_entry);
+ start_output_transfer(ep);
+ } else {
+ DPRINTF(("%s: out_jack_output: packet ignored\n", USBDEVNAME(sc->sc_dev)));
}
- } else
- error = ENODEV;
-
- return error;
+ splx(s);
+ return 0;
+ }
+
+ return EINPROGRESS;
}
static void
in_intr(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status)
{
- int cn, len, i;
+ int cn, evlen, remain, i;
+ unsigned char *buf;
struct umidi_endpoint *ep = (struct umidi_endpoint *)priv;
struct umidi_jack *jack;
- if (ep->sc->sc_dying || !ep->num_open)
+ if (ep->sc->sc_dying)
return;
- cn = GET_CN(ep->buffer[0]);
- len = packet_length[GET_CIN(ep->buffer[0])];
- jack = ep->jacks[cn];
- if (cn>=ep->num_jacks || !jack) {
- DPRINTF(("%s: stray umidi packet (in): %02X %02X %02X %02X\n",
- USBDEVNAME(ep->sc->sc_dev),
- (unsigned)ep->buffer[0],
- (unsigned)ep->buffer[1],
- (unsigned)ep->buffer[2],
- (unsigned)ep->buffer[3]));
- return;
- }
- if (!jack->binded || !jack->opened)
- return;
- DPR_PACKET(in, ep->sc, &jack->packet);
- if (jack->u.in.intr) {
- for (i=0; i<len; i++) {
- (*jack->u.in.intr)(jack->arg, ep->buffer[i+1]);
- }
+ usbd_get_xfer_status(xfer, NULL, NULL, &remain, NULL);
+ if (status != USBD_NORMAL_COMPLETION) {
+ DPRINTF(("umidi: in_intr: abnormal status: %s\n", usbd_errstr(status)));
+ goto quit;
+ }
+ buf = ep->buffer;
+ while (remain >= UMIDI_PACKET_SIZE) {
+ cn = GET_CN(buf[0]);
+ if (cn < ep->num_jacks && (jack = ep->jacks[cn]) &&
+ jack->binded && jack->opened && jack->u.in.intr) {
+ evlen = packet_length[GET_CIN(buf[0])];
+ for (i=0; i<evlen; i++)
+ (*jack->u.in.intr)(jack->arg, buf[i+1]);
+ } else
+ DPRINTFN(10, ("in_intr: unused packet %02x %02x %02x %02x\n",
+ buf[0], buf[1], buf[2], buf[3]));
+
+ buf += UMIDI_PACKET_SIZE;
+ remain -= UMIDI_PACKET_SIZE;
}
+#ifdef UMIDI_DEBUG
+ if (remain != 0) {
+ DPRINTF(("umidi: in_intr: remain != 0\n"));
+ }
+#endif
+
+quit:
(void)start_input_transfer(ep);
}
@@ -1262,120 +1230,129 @@ out_intr(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status)
struct umidi_endpoint *ep = (struct umidi_endpoint *)priv;
struct umidi_softc *sc = ep->sc;
struct umidi_jack *jack;
-
- if (sc->sc_dying || !ep->num_open)
+ int s;
+
+ if (sc->sc_dying)
return;
- jack = LIST_FIRST(&ep->queue_head);
- if (jack && jack->opened) {
- LIST_REMOVE(jack, u.out.queue_entry);
- if (!LIST_EMPTY(&ep->queue_head)) {
+ s = splusb();
+ jack = TAILQ_FIRST(&ep->queue_head);
+ if (jack) {
+ TAILQ_REMOVE(&ep->queue_head, jack, u.out.queue_entry);
+ if (!TAILQ_EMPTY(&ep->queue_head)) {
memcpy(ep->buffer,
- LIST_FIRST(&ep->queue_head)->packet.buffer,
+ TAILQ_FIRST(&ep->queue_head)->packet.buffer,
UMIDI_PACKET_SIZE);
(void)start_output_transfer(ep);
}
- if (jack->u.out.intr) {
+ if (jack->opened && jack->u.out.intr)
(*jack->u.out.intr)(jack->arg);
- }
}
+ splx(s);
}
-static void
-out_build_packet(int cable_number, struct umidi_packet *packet, uByte in)
+#define UMIDI_VOICELEN(status) (umidi_evlen[((status) >> 4) & 7])
+unsigned umidi_evlen[] = { 4, 4, 4, 4, 3, 3, 4 };
+
+#define EV_SYSEX 0xf0
+#define EV_MTC 0xf1
+#define EV_SPP 0xf2
+#define EV_SONGSEL 0xf3
+#define EV_TUNE_REQ 0xf6
+#define EV_SYSEX_STOP 0xf7
+
+static int
+out_build_packet(int cable_number, struct umidi_packet *packet, uByte data)
{
- int cin;
- uByte prev;
-
-retry:
- switch (packet->state) {
- case PS_END:
- case PS_INITIAL:
- prev = packet->buffer[1];
- memset(packet->buffer, 0, UMIDI_PACKET_SIZE);
- if (in<0x80) {
- if (prev>=0x80 && prev<0xf0) {
- /* running status */
- out_build_packet(cable_number, packet, prev);
- goto retry;
- }
- /* ??? */
+ if (data >= 0xf8) { /* is it a realtime message ? */
+ packet->buffer[0] = data >> 4 | cable_number << 4;
+ packet->buffer[1] = data;
+ packet->buffer[2] = 0;
+ packet->buffer[3] = 0;
+ return 1;
+ }
+ if (data >= 0xf0) { /* is it a common message ? */
+ switch(data) {
+ case EV_SYSEX:
+ packet->buffer[1] = packet->status = data;
+ packet->index = 2;
+ break;
+ case EV_SYSEX_STOP:
+ if (packet->status != EV_SYSEX) break;
+ packet->status = data;
+ packet->buffer[packet->index++] = data;
+ packet->buffer[0] = (0x4 - 1 + packet->index) | cable_number << 4;
+ goto packetready;
+ case EV_TUNE_REQ:
+ packet->status = data;
+ packet->buffer[0] = 0x5 | cable_number << 4;
+ packet->index = 1;
+ goto packetready;
+ default:
+ packet->status = data;
break;
}
- if (in>=0xf0) {
- cin=packet_0xFX[in&0x0F].cin;
- packet->state=packet_0xFX[in&0x0F].next;
- } else {
- cin=(unsigned char)in>>4;
- switch (packet_length[cin]) {
- case 2:
- packet->state = PS_NORMAL_1OF2;
- break;
- case 3:
- packet->state = PS_NORMAL_1OF3;
- break;
- default:
- /* ??? */
- packet->state = PS_INITIAL;
+ return 0;
+ }
+ if (data >= 0x80) { /* is it a voice message ? */
+ packet->status = data;
+ packet->index = 0;
+ return 0;
+ }
+
+ /* else it is a data byte */
+ if (packet->status >= 0xf0) {
+ switch(packet->status) {
+ case EV_SYSEX: /* sysex starts or continues */
+ if (packet->index == 0)
+ packet->index = 1;
+
+ packet->buffer[packet->index++] = data;
+ if (packet->index >= UMIDI_PACKET_SIZE) {
+ packet->buffer[0] = 0x4 | cable_number << 4;
+ goto packetready;
}
- }
- packet->buffer[0] = MIX_CN_CIN(cable_number, cin);
- packet->buffer[1] = in;
- break;
- case PS_NORMAL_1OF3:
- if (in>=0x80) { /* ??? */ packet->state = PS_END; break; }
- packet->buffer[2] = in;
- packet->state = PS_NORMAL_2OF3;
- break;
- case PS_NORMAL_2OF3:
- if (in>=0x80) { /* ??? */ packet->state = PS_END; break; }
- packet->buffer[3] = in;
- packet->state = PS_END;
- break;
- case PS_NORMAL_1OF2:
- if (in>=0x80) { /* ??? */ packet->state = PS_END; break; }
- packet->buffer[2] = in;
- packet->state = PS_END;
- break;
- case PS_EXCL_0:
- memset(packet->buffer, 0, UMIDI_PACKET_SIZE);
- if (in==0xF7) {
- packet->buffer[0] = MIX_CN_CIN(cable_number, 0x05);
- packet->buffer[1] = 0xF7;
- packet->state = PS_END;
break;
- }
- if (in>=0x80) { /* ??? */ packet->state = PS_END; break; }
- packet->buffer[1] = in;
- packet->state = PS_EXCL_1;
- break;
- case PS_EXCL_1:
- if (in==0xF7) {
- packet->buffer[0] = MIX_CN_CIN(cable_number, 0x06);
- packet->buffer[2] = 0xF7;
- packet->state = PS_END;
+ case EV_MTC: /* messages with 1 data byte */
+ case EV_SONGSEL:
+ packet->buffer[0] = 0x2 | cable_number << 4;
+ packet->buffer[1] = packet->status;
+ packet->buffer[2] = data;
+ packet->index = 3;
+ goto packetready;
+ case EV_SPP: /* messages with 2 data bytes */
+ if (packet->index == 0) {
+ packet->buffer[0] = 0x3 | cable_number << 4;
+ packet->index = 1;
+ }
+ packet->buffer[packet->index++] = data;
+ if (packet->index >= UMIDI_PACKET_SIZE) {
+ packet->buffer[1] = packet->status;
+ goto packetready;
+ }
break;
- }
- if (in>=0x80) { /* ??? */ packet->state = PS_END; break; }
- packet->buffer[2] = in;
- packet->state = PS_EXCL_2;
- break;
- case PS_EXCL_2:
- if (in==0xF7) {
- packet->buffer[0] = MIX_CN_CIN(cable_number, 0x07);
- packet->buffer[3] = 0xF7;
- packet->state = PS_END;
+ default: /* ignore data with unknown status */
break;
}
- if (in>=0x80) { /* ??? */ packet->state = PS_END; break; }
- packet->buffer[0] = MIX_CN_CIN(cable_number, 0x04);
- packet->buffer[3] = in;
- packet->state = PS_EXCL_0;
- break;
- default:
- printf("umidi: ambiguous state.\n");
- packet->state = PS_INITIAL;
- goto retry;
+ return 0;
+ }
+ if (packet->status >= 0x80) { /* is it a voice message ? */
+ if (packet->index == 0) {
+ packet->buffer[0] = packet->status >> 4 | cable_number << 4;
+ packet->buffer[1] = packet->status;
+ packet->index = 2;
+ }
+ packet->buffer[packet->index++] = data;
+ if (packet->index >= UMIDI_VOICELEN(packet->status))
+ goto packetready;
}
+ /* ignore data with unknown status */
+ return 0;
+
+packetready:
+ while (packet->index < UMIDI_PACKET_SIZE)
+ packet->buffer[packet->index++] = 0;
+
+ packet->index = 0;
+ return 1;
}
-
diff --git a/sys/dev/usb/umidi_quirks.c b/sys/dev/usb/umidi_quirks.c
index 37c9c826549..d1cfe011191 100644
--- a/sys/dev/usb/umidi_quirks.c
+++ b/sys/dev/usb/umidi_quirks.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: umidi_quirks.c,v 1.5 2003/05/19 00:36:52 nate Exp $ */
+/* $OpenBSD: umidi_quirks.c,v 1.6 2004/06/27 19:44:48 deraadt Exp $ */
/* $NetBSD: umidi_quirks.c,v 1.4 2002/06/19 13:55:30 tshiozak Exp $ */
/*
@@ -166,6 +166,185 @@ UMQ_DEF(ROLAND, ROLAND_UM880N, 0) = {
UMQ_TERMINATOR
};
+/*
+ * ROLAND UA-100
+ */
+UMQ_FIXED_EP_DEF(ROLAND, ROLAND_UA100, 2, 1, 1) = {
+ /* out */
+ { 0, 3 },
+ /* in */
+ { 1, 3 }
+};
+
+UMQ_DEF(ROLAND, ROLAND_UA100, 2) = {
+ UMQ_FIXED_EP_REG(ROLAND, ROLAND_UA100, 2),
+ UMQ_TERMINATOR
+};
+
+/*
+ * ROLAND UM-4
+ */
+UMQ_FIXED_EP_DEF(ROLAND, ROLAND_UM4, 2, 1, 1) = {
+ /* out */
+ { 0, 4 },
+ /* in */
+ { 1, 4 }
+};
+
+UMQ_DEF(ROLAND, ROLAND_UM4, 2) = {
+ UMQ_FIXED_EP_REG(ROLAND, ROLAND_UM4, 2),
+ UMQ_TERMINATOR
+};
+
+/*
+ * ROLAND U-8
+ */
+UMQ_FIXED_EP_DEF(ROLAND, ROLAND_U8, 2, 1, 1) = {
+ /* out */
+ { 0, 2 },
+ /* in */
+ { 1, 2 }
+};
+
+UMQ_DEF(ROLAND, ROLAND_U8, 2) = {
+ UMQ_FIXED_EP_REG(ROLAND, ROLAND_U8, 2),
+ UMQ_TERMINATOR
+};
+
+/*
+ * ROLAND UM-2
+ */
+UMQ_FIXED_EP_DEF(ROLAND, ROLAND_UM2, 2, 1, 1) = {
+ /* out */
+ { 0, 2 },
+ /* in */
+ { 1, 2 }
+};
+
+UMQ_DEF(ROLAND, ROLAND_UM2, 2) = {
+ UMQ_FIXED_EP_REG(ROLAND, ROLAND_UM2, 2),
+ UMQ_TERMINATOR
+};
+
+/*
+ * ROLAND SC-8820
+ */
+UMQ_FIXED_EP_DEF(ROLAND, ROLAND_SC8820, 2, 1, 1) = {
+ /* out */
+ { 0, 5 }, /* cables 0, 1, 4 only */
+ /* in */
+ { 1, 5 } /* do. */
+};
+
+UMQ_DEF(ROLAND, ROLAND_SC8820, 2) = {
+ UMQ_FIXED_EP_REG(ROLAND, ROLAND_SC8820, 2),
+ UMQ_TERMINATOR
+};
+
+/*
+ * ROLAND PC-300
+ */
+UMQ_FIXED_EP_DEF(ROLAND, ROLAND_PC300, 2, 1, 1) = {
+ /* out */
+ { 0, 1 },
+ /* in */
+ { 1, 1 }
+};
+
+UMQ_DEF(ROLAND, ROLAND_PC300, 2) = {
+ UMQ_FIXED_EP_REG(ROLAND, ROLAND_PC300, 2),
+ UMQ_TERMINATOR
+};
+
+/*
+ * ROLAND SK-500
+ */
+UMQ_FIXED_EP_DEF(ROLAND, ROLAND_SK500, 2, 1, 1) = {
+ /* out */
+ { 0, 5 }, /* cables 0, 1, 4 only */
+ /* in */
+ { 1, 5 } /* do. */
+};
+
+UMQ_DEF(ROLAND, ROLAND_SK500, 2) = {
+ UMQ_FIXED_EP_REG(ROLAND, ROLAND_SK500, 2),
+ UMQ_TERMINATOR
+};
+
+/*
+ * ROLAND SC-D70
+ */
+UMQ_FIXED_EP_DEF(ROLAND, ROLAND_SCD70, 2, 1, 1) = {
+ /* out */
+ { 0, 3 },
+ /* in */
+ { 1, 3 }
+};
+
+UMQ_DEF(ROLAND, ROLAND_SCD70, 2) = {
+ UMQ_FIXED_EP_REG(ROLAND, ROLAND_SCD70, 2),
+ UMQ_TERMINATOR
+};
+
+/*
+ * ROLAND UM-550
+ */
+UMQ_FIXED_EP_DEF(ROLAND, ROLAND_UM550, 0, 1, 1) = {
+ /* out */
+ { 0, 6 },
+ /* in */
+ { 1, 6 }
+};
+
+UMQ_DEF(ROLAND, ROLAND_UM550, 0) = {
+ UMQ_FIXED_EP_REG(ROLAND, ROLAND_UM550, 0),
+ UMQ_TERMINATOR
+};
+
+/*
+ * ROLAND SD-20
+ */
+UMQ_FIXED_EP_DEF(ROLAND, ROLAND_SD20, 0, 1, 1) = {
+ /* out */
+ { 0, 2 },
+ /* in */
+ { 1, 3 }
+};
+
+UMQ_DEF(ROLAND, ROLAND_SD20, 0) = {
+ UMQ_FIXED_EP_REG(ROLAND, ROLAND_SD20, 0),
+ UMQ_TERMINATOR
+};
+
+/*
+ * ROLAND SD-80
+ */
+UMQ_FIXED_EP_DEF(ROLAND, ROLAND_SD80, 0, 1, 1) = {
+ /* out */
+ { 0, 4 },
+ /* in */
+ { 1, 4 }
+};
+
+UMQ_DEF(ROLAND, ROLAND_SD80, 0) = {
+ UMQ_FIXED_EP_REG(ROLAND, ROLAND_SD80, 0),
+ UMQ_TERMINATOR
+};
+
+/*
+ * ROLAND UA-700
+ */
+UMQ_FIXED_EP_DEF(ROLAND, ROLAND_UA700, 3, 1, 1) = {
+ /* out */
+ { 0, 2 },
+ /* in */
+ { 1, 2 }
+};
+
+UMQ_DEF(ROLAND, ROLAND_UA700, 3) = {
+ UMQ_FIXED_EP_REG(ROLAND, ROLAND_UA700, 3),
+ UMQ_TERMINATOR
+};
/*
@@ -178,6 +357,18 @@ struct umidi_quirk umidi_quirklist[] = {
UMQ_REG(ROLAND, ROLAND_SC8850, 2),
UMQ_REG(ROLAND, ROLAND_SD90, 2),
UMQ_REG(ROLAND, ROLAND_UM880N, 0),
+ UMQ_REG(ROLAND, ROLAND_UA100, 2),
+ UMQ_REG(ROLAND, ROLAND_UM4, 2),
+ UMQ_REG(ROLAND, ROLAND_U8, 2),
+ UMQ_REG(ROLAND, ROLAND_UM2, 2),
+ UMQ_REG(ROLAND, ROLAND_SC8820, 2),
+ UMQ_REG(ROLAND, ROLAND_PC300, 2),
+ UMQ_REG(ROLAND, ROLAND_SK500, 2),
+ UMQ_REG(ROLAND, ROLAND_SCD70, 2),
+ UMQ_REG(ROLAND, ROLAND_UM550, 0),
+ UMQ_REG(ROLAND, ROLAND_SD20, 0),
+ UMQ_REG(ROLAND, ROLAND_SD80, 0),
+ UMQ_REG(ROLAND, ROLAND_UA700, 3),
UMQ_TERMINATOR
};
diff --git a/sys/dev/usb/umidireg.h b/sys/dev/usb/umidireg.h
index 77bc91ad544..e2a51b40f4a 100644
--- a/sys/dev/usb/umidireg.h
+++ b/sys/dev/usb/umidireg.h
@@ -1,11 +1,10 @@
-/* $OpenBSD: umidireg.h,v 1.3 2002/06/11 07:49:57 nate Exp $ */
-/* $NetBSD: umidireg.h,v 1.2 2001/05/28 20:52:06 tshiozak Exp $ */
+/* $NetBSD: umidireg.h,v 1.3 2003/12/04 13:57:31 keihan Exp $ */
/*
* Copyright (c) 2001 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
- * by Takuya SHIOZAKI (tshiozak@netbsd.org).
+ * by Takuya SHIOZAKI (tshiozak@NetBSD.org).
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
diff --git a/sys/dev/usb/umidivar.h b/sys/dev/usb/umidivar.h
index 4b6d34a1d45..46c38d2cc25 100644
--- a/sys/dev/usb/umidivar.h
+++ b/sys/dev/usb/umidivar.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: umidivar.h,v 1.7 2002/11/11 02:32:32 nate Exp $ */
+/* $OpenBSD: umidivar.h,v 1.8 2004/06/27 19:44:48 deraadt Exp $ */
/* $NetBSD: umidivar.h,v 1.5 2002/09/12 21:00:42 augustss Exp $ */
/*
* Copyright (c) 2001 The NetBSD Foundation, Inc.
@@ -36,22 +36,11 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
-/* pending MUX-MIDI packet */
-typedef enum {
- PS_EXCL_0=-2, /* put, and next state is PS_EXCL_0 */
- PS_END=-1, /* put, and next state is PS_INITIAL */
- PS_INITIAL=0, /* 0>= : not put, and state is keeped */
- PS_NORMAL_1OF3=1,
- PS_NORMAL_2OF3=2,
- PS_NORMAL_1OF2=3,
- PS_EXCL_1=4,
- PS_EXCL_2=5
-} packet_state_t;
-
#define UMIDI_PACKET_SIZE 4
struct umidi_packet {
- char buffer[UMIDI_PACKET_SIZE];
- packet_state_t state;
+ unsigned status;
+ unsigned index;
+ unsigned char buffer[UMIDI_PACKET_SIZE];
};
/*
@@ -88,7 +77,7 @@ struct umidi_jack {
union {
struct {
void (*intr)(void *);
- LIST_ENTRY(umidi_jack) queue_entry;
+ TAILQ_ENTRY(umidi_jack) queue_entry;
} out;
struct {
void (*intr)(void *, int);
@@ -104,12 +93,12 @@ struct umidi_endpoint {
int addr;
usbd_pipe_handle pipe;
usbd_xfer_handle xfer;
- char *buffer;
+ unsigned char *buffer;
+ unsigned packetsize;
int num_open;
int num_jacks;
struct umidi_jack *jacks[UMIDI_MAX_EPJACKS];
- LIST_HEAD(, umidi_jack) queue_head;
- struct umidi_jack *queue_tail;
+ TAILQ_HEAD(, umidi_jack) queue_head;
};
/* software context */