diff options
-rw-r--r-- | sys/dev/midi.c | 1140 | ||||
-rw-r--r-- | sys/dev/midivar.h | 160 | ||||
-rw-r--r-- | sys/dev/usb/umidi.c | 489 | ||||
-rw-r--r-- | sys/dev/usb/umidi_quirks.c | 193 | ||||
-rw-r--r-- | sys/dev/usb/umidireg.h | 5 | ||||
-rw-r--r-- | sys/dev/usb/umidivar.h | 27 |
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 */ |