summaryrefslogtreecommitdiff
path: root/sys/dev/midi.c
diff options
context:
space:
mode:
authorTheo de Raadt <deraadt@cvs.openbsd.org>2004-06-27 19:44:49 +0000
committerTheo de Raadt <deraadt@cvs.openbsd.org>2004-06-27 19:44:49 +0000
commitaf9cf440474893bc7dab5537c61e8bebcbc81807 (patch)
treeadcdf8143d4db11402ff24fedfaf1d5bd6362ef7 /sys/dev/midi.c
parent739008766bfd25d4eb6ba3069aa0b9562d33c322 (diff)
better midi stuff from alex@caoua.org
Diffstat (limited to 'sys/dev/midi.c')
-rw-r--r--sys/dev/midi.c1140
1 files changed, 505 insertions, 635 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 */