Home | History | Annotate | Line # | Download | only in dev
midi.c revision 1.5
      1  1.5  augustss /*	$NetBSD: midi.c,v 1.5 1998/08/24 17:59:25 augustss Exp $	*/
      2  1.1  augustss 
      3  1.1  augustss /*
      4  1.1  augustss  * Copyright (c) 1998 The NetBSD Foundation, Inc.
      5  1.1  augustss  * All rights reserved.
      6  1.1  augustss  *
      7  1.1  augustss  * Author: Lennart Augustsson
      8  1.1  augustss  *
      9  1.1  augustss  * Redistribution and use in source and binary forms, with or without
     10  1.1  augustss  * modification, are permitted provided that the following conditions
     11  1.1  augustss  * are met:
     12  1.1  augustss  * 1. Redistributions of source code must retain the above copyright
     13  1.1  augustss  *    notice, this list of conditions and the following disclaimer.
     14  1.1  augustss  * 2. Redistributions in binary form must reproduce the above copyright
     15  1.1  augustss  *    notice, this list of conditions and the following disclaimer in the
     16  1.1  augustss  *    documentation and/or other materials provided with the distribution.
     17  1.1  augustss  * 3. All advertising materials mentioning features or use of this software
     18  1.1  augustss  *    must display the following acknowledgement:
     19  1.1  augustss  *        This product includes software developed by the NetBSD
     20  1.1  augustss  *        Foundation, Inc. and its contributors.
     21  1.1  augustss  * 4. Neither the name of The NetBSD Foundation nor the names of its
     22  1.1  augustss  *    contributors may be used to endorse or promote products derived
     23  1.1  augustss  *    from this software without specific prior written permission.
     24  1.1  augustss  *
     25  1.1  augustss  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     26  1.1  augustss  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     27  1.1  augustss  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     28  1.1  augustss  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     29  1.1  augustss  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     30  1.1  augustss  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     31  1.1  augustss  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     32  1.1  augustss  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     33  1.1  augustss  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     34  1.1  augustss  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     35  1.1  augustss  * POSSIBILITY OF SUCH DAMAGE.
     36  1.1  augustss  */
     37  1.1  augustss 
     38  1.1  augustss #include "midi.h"
     39  1.1  augustss #if NMIDI > 0
     40  1.1  augustss 
     41  1.1  augustss #include "sequencer.h"
     42  1.1  augustss 
     43  1.1  augustss #include <sys/param.h>
     44  1.1  augustss #include <sys/ioctl.h>
     45  1.1  augustss #include <sys/fcntl.h>
     46  1.1  augustss #include <sys/vnode.h>
     47  1.1  augustss #include <sys/select.h>
     48  1.1  augustss #include <sys/poll.h>
     49  1.1  augustss #include <sys/malloc.h>
     50  1.1  augustss #include <sys/proc.h>
     51  1.1  augustss #include <sys/systm.h>
     52  1.1  augustss #include <sys/syslog.h>
     53  1.1  augustss #include <sys/kernel.h>
     54  1.1  augustss #include <sys/signalvar.h>
     55  1.1  augustss #include <sys/conf.h>
     56  1.1  augustss #include <sys/audioio.h>
     57  1.1  augustss #include <sys/midiio.h>
     58  1.1  augustss #include <sys/device.h>
     59  1.1  augustss 
     60  1.1  augustss #include <dev/audio_if.h>
     61  1.4  augustss #include <dev/midi_if.h>
     62  1.1  augustss #include <dev/midivar.h>
     63  1.1  augustss 
     64  1.1  augustss #ifdef AUDIO_DEBUG
     65  1.1  augustss #define DPRINTF(x)	if (mididebug) printf x
     66  1.1  augustss #define DPRINTFN(n,x)	if (mididebug >= (n)) printf x
     67  1.1  augustss int	mididebug = 0;
     68  1.1  augustss #else
     69  1.1  augustss #define DPRINTF(x)
     70  1.1  augustss #define DPRINTFN(n,x)
     71  1.1  augustss #endif
     72  1.1  augustss 
     73  1.1  augustss int midi_wait;
     74  1.1  augustss 
     75  1.2  augustss void	midi_in __P((void *, int));
     76  1.2  augustss void	midi_out __P((void *));
     77  1.2  augustss int	midi_start_output __P((struct midi_softc *, int));
     78  1.2  augustss int	midi_sleep_timo __P((int *, char *, int));
     79  1.2  augustss int	midi_sleep __P((int *, char *));
     80  1.2  augustss void	midi_wakeup __P((int *));
     81  1.2  augustss void	midi_initbuf __P((struct midi_buffer *));
     82  1.2  augustss void	midi_timeout __P((void *));
     83  1.1  augustss 
     84  1.1  augustss int	midiprobe __P((struct device *, struct cfdata *, void *));
     85  1.1  augustss void	midiattach __P((struct device *, struct device *, void *));
     86  1.1  augustss 
     87  1.1  augustss struct cfattach midi_ca = {
     88  1.1  augustss 	sizeof(struct midi_softc), midiprobe, midiattach
     89  1.1  augustss };
     90  1.1  augustss 
     91  1.4  augustss #ifdef MIDI_SAVE
     92  1.4  augustss #define MIDI_SAVE_SIZE 100000
     93  1.4  augustss int midicnt;
     94  1.4  augustss struct {
     95  1.4  augustss 	int cnt;
     96  1.4  augustss 	u_char buf[MIDI_SAVE_SIZE];
     97  1.4  augustss } midisave;
     98  1.4  augustss #define MIDI_GETSAVE		_IOWR('m', 100, int)
     99  1.4  augustss 
    100  1.4  augustss #endif
    101  1.4  augustss 
    102  1.1  augustss extern struct cfdriver midi_cd;
    103  1.1  augustss 
    104  1.1  augustss int
    105  1.1  augustss midiprobe(parent, match, aux)
    106  1.1  augustss 	struct device *parent;
    107  1.1  augustss 	struct cfdata *match;
    108  1.1  augustss 	void *aux;
    109  1.1  augustss {
    110  1.1  augustss 	struct audio_attach_args *sa = aux;
    111  1.1  augustss 
    112  1.1  augustss 	DPRINTFN(6,("midiprobe: type=%d sa=%p hw=%p\n",
    113  1.1  augustss 		 sa->type, sa, sa->hwif));
    114  1.1  augustss 	return (sa->type == AUDIODEV_TYPE_MIDI) ? 1 : 0;
    115  1.1  augustss }
    116  1.1  augustss 
    117  1.1  augustss void
    118  1.1  augustss midiattach(parent, self, aux)
    119  1.1  augustss 	struct device *parent, *self;
    120  1.1  augustss 	void *aux;
    121  1.1  augustss {
    122  1.1  augustss 	struct midi_softc *sc = (void *)self;
    123  1.1  augustss 	struct audio_attach_args *sa = aux;
    124  1.1  augustss 	struct midi_hw_if *hwp = sa->hwif;
    125  1.1  augustss 	void *hdlp = sa->hdl;
    126  1.1  augustss 
    127  1.1  augustss 	DPRINTFN(6, ("MIDI attach\n"));
    128  1.1  augustss 
    129  1.1  augustss #ifdef DIAGNOSTIC
    130  1.1  augustss 	if (hwp == 0 ||
    131  1.1  augustss 	    hwp->open == 0 ||
    132  1.1  augustss 	    hwp->close == 0 ||
    133  1.1  augustss 	    hwp->output == 0 ||
    134  1.1  augustss 	    hwp->getinfo == 0) {
    135  1.1  augustss 		printf("midi: missing method\n");
    136  1.1  augustss 		return;
    137  1.1  augustss 	}
    138  1.1  augustss #endif
    139  1.1  augustss 	sc->hw_if = hwp;
    140  1.1  augustss 	sc->hw_hdl = hdlp;
    141  1.2  augustss 	midi_attach(sc, parent);
    142  1.2  augustss }
    143  1.2  augustss 
    144  1.2  augustss void
    145  1.2  augustss midi_attach(sc, parent)
    146  1.2  augustss 	struct midi_softc *sc;
    147  1.2  augustss 	struct device *parent;
    148  1.2  augustss {
    149  1.2  augustss 	struct midi_info mi;
    150  1.2  augustss 
    151  1.1  augustss 	sc->isopen = 0;
    152  1.1  augustss 
    153  1.1  augustss 	midi_initbuf(&sc->outbuf);
    154  1.1  augustss 	midi_initbuf(&sc->inbuf);
    155  1.1  augustss 
    156  1.1  augustss 	midi_wait = MIDI_WAIT * hz / 1000000;
    157  1.1  augustss 	if (midi_wait == 0)
    158  1.1  augustss 		midi_wait = 1;
    159  1.1  augustss 
    160  1.2  augustss 	sc->sc_dev = parent;
    161  1.2  augustss 	sc->hw_if->getinfo(sc->hw_hdl, &mi);
    162  1.1  augustss 	sc->props = mi.props;
    163  1.2  augustss 	printf(": <%s>\n", mi.name);
    164  1.1  augustss }
    165  1.1  augustss 
    166  1.1  augustss int
    167  1.1  augustss midi_unit_count()
    168  1.1  augustss {
    169  1.1  augustss 	return midi_cd.cd_ndevs;
    170  1.1  augustss }
    171  1.1  augustss 
    172  1.1  augustss void
    173  1.1  augustss midi_initbuf(mb)
    174  1.1  augustss 	struct midi_buffer *mb;
    175  1.1  augustss {
    176  1.1  augustss 	mb->used = 0;
    177  1.1  augustss 	mb->usedhigh = MIDI_BUFSIZE;
    178  1.1  augustss 	mb->end = mb->start + mb->usedhigh;
    179  1.1  augustss 	mb->inp = mb->outp = mb->start;
    180  1.1  augustss }
    181  1.1  augustss 
    182  1.2  augustss int
    183  1.1  augustss midi_sleep_timo(chan, label, timo)
    184  1.1  augustss 	int *chan;
    185  1.1  augustss 	char *label;
    186  1.1  augustss 	int timo;
    187  1.1  augustss {
    188  1.1  augustss 	int st;
    189  1.1  augustss 
    190  1.1  augustss 	if (!label)
    191  1.1  augustss 		label = "midi";
    192  1.1  augustss 
    193  1.1  augustss 	DPRINTFN(5, ("midi_sleep_timo: %p %s %d\n", chan, label, timo));
    194  1.1  augustss 	*chan = 1;
    195  1.1  augustss 	st = tsleep(chan, PWAIT | PCATCH, label, timo);
    196  1.1  augustss 	*chan = 0;
    197  1.1  augustss #ifdef MIDI_DEBUG
    198  1.1  augustss 	if (st != 0)
    199  1.1  augustss 		printf("midi_sleep: %d\n", st);
    200  1.1  augustss #endif
    201  1.1  augustss 	return st;
    202  1.1  augustss }
    203  1.1  augustss 
    204  1.2  augustss int
    205  1.1  augustss midi_sleep(chan, label)
    206  1.1  augustss 	int *chan;
    207  1.1  augustss 	char *label;
    208  1.1  augustss {
    209  1.1  augustss 	return midi_sleep_timo(chan, label, 0);
    210  1.1  augustss }
    211  1.1  augustss 
    212  1.2  augustss void
    213  1.1  augustss midi_wakeup(chan)
    214  1.1  augustss 	int *chan;
    215  1.1  augustss {
    216  1.1  augustss 	if (*chan) {
    217  1.1  augustss 		DPRINTFN(5, ("midi_wakeup: %p\n", chan));
    218  1.1  augustss 		wakeup(chan);
    219  1.1  augustss 		*chan = 0;
    220  1.1  augustss 	}
    221  1.1  augustss }
    222  1.1  augustss 
    223  1.1  augustss static int midi_lengths[] = { 2,2,2,2,1,1,2,0 };
    224  1.1  augustss /* Number of bytes in a MIDI command */
    225  1.1  augustss #define MIDI_LENGTH(d) (midi_lengths[((d) >> 4) & 7])
    226  1.1  augustss 
    227  1.1  augustss void
    228  1.1  augustss midi_in(addr, data)
    229  1.1  augustss 	void *addr;
    230  1.1  augustss 	int data;
    231  1.1  augustss {
    232  1.1  augustss 	struct midi_softc *sc = addr;
    233  1.1  augustss 	struct midi_buffer *mb = &sc->inbuf;
    234  1.1  augustss 	int i;
    235  1.1  augustss 
    236  1.3  augustss 	if (!sc->isopen)
    237  1.3  augustss 		return;
    238  1.1  augustss 	if (data == MIDI_ACK)
    239  1.1  augustss 		return;
    240  1.1  augustss 	DPRINTFN(3, ("midi_in: %p 0x%02x\n", sc, data));
    241  1.1  augustss 	if (!(sc->flags & FREAD))
    242  1.1  augustss 		return;		/* discard data if not reading */
    243  1.1  augustss 
    244  1.1  augustss 	switch(sc->in_state) {
    245  1.1  augustss 	case MIDI_IN_START:
    246  1.1  augustss 		if (MIDI_IS_STATUS(data)) {
    247  1.1  augustss 			switch(data) {
    248  1.1  augustss 			case 0xf0: /* Sysex */
    249  1.1  augustss 				sc->in_state = MIDI_IN_SYSEX;
    250  1.1  augustss 				break;
    251  1.1  augustss 			case 0xf1: /* MTC quarter frame */
    252  1.1  augustss 			case 0xf3: /* Song select */
    253  1.1  augustss 				sc->in_state = MIDI_IN_DATA;
    254  1.1  augustss 				sc->in_msg[0] = data;
    255  1.1  augustss 				sc->in_pos = 1;
    256  1.1  augustss 				sc->in_left = 1;
    257  1.1  augustss 				break;
    258  1.1  augustss 			case 0xf2: /* Song position pointer */
    259  1.1  augustss 				sc->in_state = MIDI_IN_DATA;
    260  1.1  augustss 				sc->in_msg[0] = data;
    261  1.1  augustss 				sc->in_pos = 1;
    262  1.1  augustss 				sc->in_left = 2;
    263  1.1  augustss 				break;
    264  1.1  augustss 			default:
    265  1.1  augustss 				if (MIDI_IS_COMMON(data)) {
    266  1.1  augustss 					sc->in_msg[0] = data;
    267  1.1  augustss 					sc->in_pos = 1;
    268  1.1  augustss 					goto deliver;
    269  1.1  augustss 				} else {
    270  1.1  augustss 					sc->in_state = MIDI_IN_DATA;
    271  1.1  augustss 					sc->in_msg[0] = sc->in_status = data;
    272  1.1  augustss 					sc->in_pos = 1;
    273  1.1  augustss 					sc->in_left = MIDI_LENGTH(sc->in_status);
    274  1.1  augustss 				}
    275  1.1  augustss 				break;
    276  1.1  augustss 			}
    277  1.1  augustss 		} else {
    278  1.1  augustss 			if (MIDI_IS_STATUS(sc->in_status)) {
    279  1.1  augustss 				sc->in_state = MIDI_IN_DATA;
    280  1.1  augustss 				sc->in_msg[0] = sc->in_status;
    281  1.1  augustss 				sc->in_msg[1] = data;
    282  1.1  augustss 				sc->in_pos = 2;
    283  1.1  augustss 				sc->in_left = MIDI_LENGTH(sc->in_status) - 1;
    284  1.1  augustss 			}
    285  1.1  augustss 		}
    286  1.1  augustss 		return;
    287  1.1  augustss 	case MIDI_IN_DATA:
    288  1.1  augustss 		sc->in_msg[sc->in_pos++] = data;
    289  1.1  augustss 		if (--sc->in_left <= 0)
    290  1.1  augustss 			break;	/* deliver data */
    291  1.1  augustss 		return;
    292  1.1  augustss 	case MIDI_IN_SYSEX:
    293  1.1  augustss 		if (data == MIDI_SYSEX_END)
    294  1.1  augustss 			sc->in_state = MIDI_IN_START;
    295  1.1  augustss 		return;
    296  1.1  augustss 	}
    297  1.1  augustss deliver:
    298  1.1  augustss 	sc->in_state = MIDI_IN_START;
    299  1.1  augustss #if NSEQUENCER > 0
    300  1.1  augustss 	if (sc->seqopen) {
    301  1.2  augustss 		extern void midiseq_in __P((struct midi_softc *,u_char *,int));
    302  1.2  augustss 		midiseq_in(sc, sc->in_msg, sc->in_pos);
    303  1.1  augustss 		return;
    304  1.1  augustss 	}
    305  1.1  augustss #endif
    306  1.1  augustss 
    307  1.1  augustss 	if (mb->used + sc->in_pos > mb->usedhigh) {
    308  1.1  augustss 		DPRINTF(("midi_in: buffer full, discard data=0x%02x\n",
    309  1.1  augustss 			 sc->in_msg[0]));
    310  1.1  augustss 		return;
    311  1.1  augustss 	}
    312  1.1  augustss 	for (i = 0; i < sc->in_pos; i++) {
    313  1.1  augustss 		*mb->inp++ = sc->in_msg[i];
    314  1.1  augustss 		if (mb->inp >= mb->end)
    315  1.1  augustss 			mb->inp = mb->start;
    316  1.1  augustss 		mb->used++;
    317  1.1  augustss 	}
    318  1.1  augustss 	midi_wakeup(&sc->rchan);
    319  1.1  augustss 	selwakeup(&sc->rsel);
    320  1.1  augustss 	if (sc->async)
    321  1.1  augustss 		psignal(sc->async, SIGIO);
    322  1.1  augustss }
    323  1.1  augustss 
    324  1.1  augustss void
    325  1.1  augustss midi_out(addr)
    326  1.1  augustss 	void *addr;
    327  1.1  augustss {
    328  1.1  augustss 	struct midi_softc *sc = addr;
    329  1.3  augustss 
    330  1.3  augustss 	if (!sc->isopen)
    331  1.3  augustss 		return;
    332  1.1  augustss 	DPRINTFN(3, ("midi_out: %p\n", sc));
    333  1.1  augustss 	midi_start_output(sc, 1);
    334  1.1  augustss }
    335  1.1  augustss 
    336  1.1  augustss int
    337  1.1  augustss midiopen(dev, flags, ifmt, p)
    338  1.1  augustss 	dev_t dev;
    339  1.1  augustss 	int flags, ifmt;
    340  1.1  augustss 	struct proc *p;
    341  1.1  augustss {
    342  1.1  augustss 	int unit = MIDIUNIT(dev);
    343  1.1  augustss 	struct midi_softc *sc;
    344  1.1  augustss 	struct midi_hw_if *hw;
    345  1.1  augustss 	int error;
    346  1.1  augustss 
    347  1.1  augustss 	if (unit >= midi_cd.cd_ndevs ||
    348  1.1  augustss 	    (sc = midi_cd.cd_devs[unit]) == NULL)
    349  1.1  augustss 		return ENXIO;
    350  1.1  augustss 	DPRINTF(("midiopen %p\n", sc));
    351  1.1  augustss 
    352  1.1  augustss 	hw = sc->hw_if;
    353  1.1  augustss 	if (!hw)
    354  1.1  augustss 		return ENXIO;
    355  1.1  augustss 	if (sc->isopen)
    356  1.1  augustss 		return EBUSY;
    357  1.1  augustss 	sc->in_state = MIDI_IN_START;
    358  1.1  augustss 	sc->in_status = 0;
    359  1.1  augustss 	error = hw->open(sc->hw_hdl, flags, midi_in, midi_out, sc);
    360  1.1  augustss 	if (error)
    361  1.1  augustss 		return error;
    362  1.1  augustss 	sc->isopen++;
    363  1.1  augustss 	sc->flags = flags;
    364  1.1  augustss 	sc->rchan = 0;
    365  1.1  augustss 	sc->wchan = 0;
    366  1.1  augustss 	sc->pbus = 0;
    367  1.1  augustss 	sc->async = 0;
    368  1.1  augustss 
    369  1.4  augustss #ifdef MIDI_SAVE
    370  1.4  augustss 	if (midicnt != 0) {
    371  1.4  augustss 		midisave.cnt = midicnt;
    372  1.4  augustss 		midicnt = 0;
    373  1.4  augustss 	}
    374  1.4  augustss #endif
    375  1.4  augustss 
    376  1.1  augustss 	return 0;
    377  1.1  augustss }
    378  1.1  augustss 
    379  1.1  augustss int
    380  1.1  augustss midiclose(dev, flags, ifmt, p)
    381  1.1  augustss 	dev_t dev;
    382  1.1  augustss 	int flags, ifmt;
    383  1.1  augustss 	struct proc *p;
    384  1.1  augustss {
    385  1.1  augustss 	int unit = MIDIUNIT(dev);
    386  1.1  augustss 	struct midi_softc *sc = midi_cd.cd_devs[unit];
    387  1.1  augustss 	struct midi_hw_if *hw = sc->hw_if;
    388  1.1  augustss 	int s, error;
    389  1.1  augustss 
    390  1.1  augustss 	DPRINTF(("midiclose %p\n", sc));
    391  1.1  augustss 
    392  1.1  augustss 	midi_start_output(sc, 0);
    393  1.1  augustss 	error = 0;
    394  1.1  augustss 	s = splaudio();
    395  1.1  augustss 	while (sc->outbuf.used > 0 && !error) {
    396  1.1  augustss 		DPRINTFN(2,("midiclose sleep used=%d\n", sc->outbuf.used));
    397  1.3  augustss 		error = midi_sleep_timo(&sc->wchan, "mid_dr", 30*hz);
    398  1.1  augustss 	}
    399  1.3  augustss 	sc->isopen = 0;
    400  1.1  augustss 	splx(s);
    401  1.1  augustss 	hw->close(sc->hw_hdl);
    402  1.1  augustss #if NSEQUENCER > 0
    403  1.1  augustss 	sc->seqopen = 0;
    404  1.1  augustss #endif
    405  1.1  augustss 	return 0;
    406  1.1  augustss }
    407  1.1  augustss 
    408  1.1  augustss int
    409  1.1  augustss midiread(dev, uio, ioflag)
    410  1.1  augustss 	dev_t dev;
    411  1.1  augustss 	struct uio *uio;
    412  1.1  augustss 	int ioflag;
    413  1.1  augustss {
    414  1.1  augustss 	int unit = MIDIUNIT(dev);
    415  1.1  augustss 	struct midi_softc *sc = midi_cd.cd_devs[unit];
    416  1.1  augustss 	struct midi_buffer *mb = &sc->inbuf;
    417  1.1  augustss 	int error;
    418  1.1  augustss 	u_char *outp;
    419  1.1  augustss 	int used, cc, n, resid;
    420  1.1  augustss 	int s;
    421  1.1  augustss 
    422  1.1  augustss 	DPRINTF(("midiread: %p, count=%d\n", sc, uio->uio_resid));
    423  1.1  augustss 
    424  1.1  augustss 	error = 0;
    425  1.1  augustss 	resid = uio->uio_resid;
    426  1.1  augustss 	while (uio->uio_resid == resid && !error) {
    427  1.1  augustss 		s = splaudio();
    428  1.1  augustss 		while (mb->used <= 0) {
    429  1.1  augustss 			if (ioflag & IO_NDELAY) {
    430  1.1  augustss 				splx(s);
    431  1.1  augustss 				return EWOULDBLOCK;
    432  1.1  augustss 			}
    433  1.1  augustss 			error = midi_sleep(&sc->rchan, "mid rd");
    434  1.1  augustss 			if (error) {
    435  1.1  augustss 				splx(s);
    436  1.1  augustss 				return error;
    437  1.1  augustss 			}
    438  1.1  augustss 		}
    439  1.1  augustss 		used = mb->used;
    440  1.1  augustss 		outp = mb->outp;
    441  1.1  augustss 		splx(s);
    442  1.1  augustss 		cc = used;	/* maximum to read */
    443  1.1  augustss 		n = mb->end - outp;
    444  1.1  augustss 		if (n < cc)
    445  1.1  augustss 			cc = n;	/* don't read beyond end of buffer */
    446  1.1  augustss 		if (uio->uio_resid < cc)
    447  1.1  augustss 			cc = uio->uio_resid; /* and no more than we want */
    448  1.1  augustss 		DPRINTFN(3, ("midiread: uiomove cc=%d\n", cc));
    449  1.1  augustss 		error = uiomove(outp, cc, uio);
    450  1.1  augustss 		if (error)
    451  1.1  augustss 			break;
    452  1.1  augustss 		used -= cc;
    453  1.1  augustss 		outp += cc;
    454  1.1  augustss 		if (outp >= mb->end)
    455  1.1  augustss 			outp = mb->start;
    456  1.1  augustss 		s = splaudio();
    457  1.1  augustss 		mb->outp = outp;
    458  1.1  augustss 		mb->used = used;
    459  1.1  augustss 		splx(s);
    460  1.1  augustss 	}
    461  1.1  augustss 	return error;
    462  1.1  augustss }
    463  1.1  augustss 
    464  1.1  augustss void
    465  1.1  augustss midi_timeout(arg)
    466  1.1  augustss 	void *arg;
    467  1.1  augustss {
    468  1.1  augustss 	struct midi_softc *sc = arg;
    469  1.1  augustss 
    470  1.1  augustss 	DPRINTFN(3,("midi_timeout: %p\n", sc));
    471  1.1  augustss 	midi_start_output(sc, 1);
    472  1.1  augustss }
    473  1.1  augustss 
    474  1.1  augustss int
    475  1.1  augustss midi_start_output(sc, intr)
    476  1.1  augustss 	struct midi_softc *sc;
    477  1.1  augustss 	int intr;
    478  1.1  augustss {
    479  1.1  augustss 	struct midi_buffer *mb = &sc->outbuf;
    480  1.1  augustss 	u_char *outp;
    481  1.1  augustss 	int error;
    482  1.1  augustss 	int s;
    483  1.1  augustss 	int i, mmax;
    484  1.1  augustss 
    485  1.1  augustss 	error = 0;
    486  1.1  augustss 	mmax = sc->props & MIDI_PROP_OUT_INTR ? 1 : MIDI_MAX_WRITE;
    487  1.1  augustss 	s = splaudio();
    488  1.1  augustss 	if (sc->pbus && !intr) {
    489  1.1  augustss 		DPRINTFN(4, ("midi_start_output: busy\n"));
    490  1.1  augustss 		splx(s);
    491  1.1  augustss 		return 0;
    492  1.1  augustss 	}
    493  1.1  augustss 	sc->pbus = 1;
    494  1.1  augustss 	for (i = 0; i < mmax && mb->used > 0 && !error; i++) {
    495  1.1  augustss 		outp = mb->outp;
    496  1.1  augustss 		splx(s);
    497  1.1  augustss 		DPRINTFN(4, ("midi_start_output: %p i=%d, data=0x%02x\n",
    498  1.1  augustss 			     sc, i, *outp));
    499  1.4  augustss #ifdef MIDI_SAVE
    500  1.4  augustss 		midisave.buf[midicnt] = *outp;
    501  1.4  augustss 		midicnt = (midicnt + 1) % MIDI_SAVE_SIZE;
    502  1.4  augustss #endif
    503  1.1  augustss 		error = sc->hw_if->output(sc->hw_hdl, *outp++);
    504  1.1  augustss 		if (outp >= mb->end)
    505  1.1  augustss 			outp = mb->start;
    506  1.1  augustss 		s = splaudio();
    507  1.1  augustss 		mb->outp = outp;
    508  1.1  augustss 		mb->used--;
    509  1.1  augustss 	}
    510  1.1  augustss 	midi_wakeup(&sc->wchan);
    511  1.1  augustss 	selwakeup(&sc->wsel);
    512  1.1  augustss 	if (sc->async)
    513  1.1  augustss 		psignal(sc->async, SIGIO);
    514  1.1  augustss 	if (mb->used > 0) {
    515  1.1  augustss 		if (!(sc->props & MIDI_PROP_OUT_INTR))
    516  1.1  augustss 			timeout(midi_timeout, sc, midi_wait);
    517  1.1  augustss 	} else
    518  1.1  augustss 		sc->pbus = 0;
    519  1.1  augustss 	splx(s);
    520  1.1  augustss 	return error;
    521  1.1  augustss }
    522  1.1  augustss 
    523  1.1  augustss int
    524  1.1  augustss midiwrite(dev, uio, ioflag)
    525  1.1  augustss 	dev_t dev;
    526  1.1  augustss 	struct uio *uio;
    527  1.1  augustss 	int ioflag;
    528  1.1  augustss {
    529  1.1  augustss 	int unit = MIDIUNIT(dev);
    530  1.1  augustss 	struct midi_softc *sc = midi_cd.cd_devs[unit];
    531  1.1  augustss 	struct midi_buffer *mb = &sc->outbuf;
    532  1.1  augustss 	int error;
    533  1.1  augustss 	u_char *inp;
    534  1.1  augustss 	int used, cc, n;
    535  1.1  augustss 	int s;
    536  1.1  augustss 
    537  1.1  augustss 	DPRINTFN(2, ("midiwrite: %p, unit=%d, count=%d\n", sc, unit,
    538  1.1  augustss 		     uio->uio_resid));
    539  1.1  augustss 
    540  1.1  augustss 	error = 0;
    541  1.1  augustss 	while (uio->uio_resid > 0 && !error) {
    542  1.1  augustss 		s = splaudio();
    543  1.1  augustss 		if (mb->used >= mb->usedhigh) {
    544  1.1  augustss 			DPRINTFN(3,("midi_write: sleep used=%d hiwat=%d\n",
    545  1.1  augustss 				 mb->used, mb->usedhigh));
    546  1.1  augustss 			if (ioflag & IO_NDELAY) {
    547  1.1  augustss 				splx(s);
    548  1.1  augustss 				return EWOULDBLOCK;
    549  1.1  augustss 			}
    550  1.1  augustss 			error = midi_sleep(&sc->wchan, "mid wr");
    551  1.1  augustss 			if (error) {
    552  1.1  augustss 				splx(s);
    553  1.1  augustss 				return error;
    554  1.1  augustss 			}
    555  1.1  augustss 		}
    556  1.1  augustss 		used = mb->used;
    557  1.1  augustss 		inp = mb->inp;
    558  1.1  augustss 		splx(s);
    559  1.1  augustss 		cc = mb->usedhigh - used; 	/* maximum to write */
    560  1.1  augustss 		n = mb->end - inp;
    561  1.1  augustss 		if (n < cc)
    562  1.1  augustss 			cc = n;			/* don't write beyond end of buffer */
    563  1.1  augustss 		if (uio->uio_resid < cc)
    564  1.1  augustss 			cc = uio->uio_resid; 	/* and no more than we have */
    565  1.1  augustss 		error = uiomove(inp, cc, uio);
    566  1.1  augustss #ifdef MIDI_DEBUG
    567  1.1  augustss 		if (error)
    568  1.1  augustss 		        printf("midi_write:(1) uiomove failed %d; cc=%d inp=%p\n",
    569  1.1  augustss 			       error, cc, inp);
    570  1.1  augustss #endif
    571  1.1  augustss 		if (error)
    572  1.1  augustss 			break;
    573  1.1  augustss 		inp = mb->inp + cc;
    574  1.1  augustss 		if (inp >= mb->end)
    575  1.1  augustss 			inp = mb->start;
    576  1.1  augustss 		s = splaudio();
    577  1.1  augustss 		mb->inp = inp;
    578  1.1  augustss 		mb->used += cc;
    579  1.1  augustss 		splx(s);
    580  1.1  augustss 		error = midi_start_output(sc, 0);
    581  1.1  augustss 	}
    582  1.1  augustss 	return error;
    583  1.5  augustss }
    584  1.5  augustss 
    585  1.5  augustss /*
    586  1.5  augustss  * This write routine is only called from sequencer code and expect
    587  1.5  augustss  * a write that is smaller than the MIDI buffer.
    588  1.5  augustss  */
    589  1.5  augustss int
    590  1.5  augustss midi_writebytes(unit, buf, cc)
    591  1.5  augustss 	int unit;
    592  1.5  augustss 	u_char *buf;
    593  1.5  augustss 	int cc;
    594  1.5  augustss {
    595  1.5  augustss 	struct midi_softc *sc = midi_cd.cd_devs[unit];
    596  1.5  augustss 	struct midi_buffer *mb = &sc->outbuf;
    597  1.5  augustss 	int n, s;
    598  1.5  augustss 
    599  1.5  augustss 	DPRINTFN(2, ("midi_writebytes: %p, unit=%d, cc=%d\n", sc, unit, cc));
    600  1.5  augustss 
    601  1.5  augustss 	s = splaudio();
    602  1.5  augustss 	if (mb->used + cc >= mb->usedhigh) {
    603  1.5  augustss 		splx(s);
    604  1.5  augustss 		return (EWOULDBLOCK);
    605  1.5  augustss 	}
    606  1.5  augustss 	n = mb->end - mb->inp;
    607  1.5  augustss 	if (cc < n)
    608  1.5  augustss 		n = cc;
    609  1.5  augustss 	memcpy(mb->inp, buf, cc);
    610  1.5  augustss 	mb->inp += n;
    611  1.5  augustss 	if (mb->inp >= mb->end) {
    612  1.5  augustss 		mb->inp = mb->start;
    613  1.5  augustss 		cc -= n;
    614  1.5  augustss 		if (cc > 0) {
    615  1.5  augustss 			memcpy(mb->inp, buf + n, cc);
    616  1.5  augustss 			mb->inp += cc;
    617  1.5  augustss 		}
    618  1.5  augustss 	}
    619  1.5  augustss 	mb->used += cc;
    620  1.5  augustss 	splx(s);
    621  1.5  augustss 	return (midi_start_output(sc, 0));
    622  1.1  augustss }
    623  1.1  augustss 
    624  1.1  augustss int
    625  1.1  augustss midiioctl(dev, cmd, addr, flag, p)
    626  1.1  augustss 	dev_t dev;
    627  1.1  augustss 	u_long cmd;
    628  1.1  augustss 	caddr_t addr;
    629  1.1  augustss 	int flag;
    630  1.1  augustss 	struct proc *p;
    631  1.1  augustss {
    632  1.1  augustss 	int unit = MIDIUNIT(dev);
    633  1.1  augustss 	struct midi_softc *sc = midi_cd.cd_devs[unit];
    634  1.1  augustss 	struct midi_hw_if *hw = sc->hw_if;
    635  1.1  augustss 	int error;
    636  1.1  augustss 
    637  1.1  augustss 	DPRINTF(("midiioctl: %p cmd=0x%08lx\n", sc, cmd));
    638  1.1  augustss 	error = 0;
    639  1.1  augustss 	switch (cmd) {
    640  1.1  augustss 	case FIONBIO:
    641  1.1  augustss 		/* All handled in the upper FS layer. */
    642  1.1  augustss 		break;
    643  1.1  augustss 
    644  1.1  augustss 	case FIOASYNC:
    645  1.1  augustss 		if (*(int *)addr) {
    646  1.1  augustss 			if (sc->async)
    647  1.1  augustss 				return EBUSY;
    648  1.1  augustss 			sc->async = p;
    649  1.1  augustss 			DPRINTF(("midi_ioctl: FIOASYNC %p\n", p));
    650  1.1  augustss 		} else
    651  1.1  augustss 			sc->async = 0;
    652  1.1  augustss 		break;
    653  1.1  augustss 
    654  1.1  augustss #if 0
    655  1.1  augustss 	case MIDI_PRETIME:
    656  1.1  augustss 		/* XXX OSS
    657  1.1  augustss 		 * This should set up a read timeout, but that's
    658  1.1  augustss 		 * why we have poll(), so there's nothing yet. */
    659  1.1  augustss 		error = EINVAL;
    660  1.1  augustss 		break;
    661  1.1  augustss #endif
    662  1.1  augustss 
    663  1.4  augustss #ifdef MIDI_SAVE
    664  1.4  augustss 	case MIDI_GETSAVE:
    665  1.4  augustss 		error = copyout(&midisave, *(void **)addr, sizeof midisave);
    666  1.4  augustss   		break;
    667  1.4  augustss #endif
    668  1.4  augustss 
    669  1.1  augustss 	default:
    670  1.1  augustss 		if (hw->ioctl)
    671  1.2  augustss 			error = hw->ioctl(sc->hw_hdl, cmd, addr, flag, p);
    672  1.1  augustss 		else
    673  1.1  augustss 			error = EINVAL;
    674  1.1  augustss 		break;
    675  1.1  augustss 	}
    676  1.1  augustss 	return error;
    677  1.1  augustss }
    678  1.1  augustss 
    679  1.1  augustss int
    680  1.1  augustss midipoll(dev, events, p)
    681  1.1  augustss 	dev_t dev;
    682  1.1  augustss 	int events;
    683  1.1  augustss 	struct proc *p;
    684  1.1  augustss {
    685  1.1  augustss 	int unit = MIDIUNIT(dev);
    686  1.1  augustss 	struct midi_softc *sc = midi_cd.cd_devs[unit];
    687  1.1  augustss 	int revents = 0;
    688  1.1  augustss 	int s = splaudio();
    689  1.1  augustss 
    690  1.1  augustss 	DPRINTF(("midipoll: %p events=0x%x\n", sc, events));
    691  1.1  augustss 
    692  1.1  augustss 	if (events & (POLLIN | POLLRDNORM))
    693  1.1  augustss 		if (sc->inbuf.used > 0)
    694  1.1  augustss 			revents |= events & (POLLIN | POLLRDNORM);
    695  1.1  augustss 
    696  1.1  augustss 	if (events & (POLLOUT | POLLWRNORM))
    697  1.1  augustss 		if (sc->outbuf.used < sc->outbuf.usedhigh)
    698  1.1  augustss 			revents |= events & (POLLOUT | POLLWRNORM);
    699  1.1  augustss 
    700  1.1  augustss 	if (revents == 0) {
    701  1.1  augustss 		if (events & (POLLIN | POLLRDNORM))
    702  1.1  augustss 			selrecord(p, &sc->rsel);
    703  1.1  augustss 
    704  1.1  augustss 		if (events & (POLLOUT | POLLWRNORM))
    705  1.1  augustss 			selrecord(p, &sc->wsel);
    706  1.1  augustss 	}
    707  1.1  augustss 
    708  1.1  augustss 	splx(s);
    709  1.1  augustss 	return revents;
    710  1.1  augustss }
    711  1.1  augustss 
    712  1.1  augustss void
    713  1.1  augustss midi_getinfo(dev, mi)
    714  1.1  augustss 	dev_t dev;
    715  1.1  augustss 	struct midi_info *mi;
    716  1.1  augustss {
    717  1.1  augustss 	int unit = MIDIUNIT(dev);
    718  1.1  augustss 	struct midi_softc *sc;
    719  1.1  augustss 
    720  1.1  augustss 	if (unit >= midi_cd.cd_ndevs ||
    721  1.1  augustss 	    (sc = midi_cd.cd_devs[unit]) == NULL)
    722  1.1  augustss 		return;
    723  1.1  augustss 	sc->hw_if->getinfo(sc->hw_hdl, mi);
    724  1.4  augustss }
    725  1.4  augustss 
    726  1.4  augustss int	audioprint __P((void *, const char *));
    727  1.4  augustss 
    728  1.4  augustss void
    729  1.4  augustss midi_attach_mi(mhwp, hdlp, dev)
    730  1.4  augustss 	struct midi_hw_if *mhwp;
    731  1.4  augustss 	void *hdlp;
    732  1.4  augustss 	struct device *dev;
    733  1.4  augustss {
    734  1.4  augustss 	struct audio_attach_args arg;
    735  1.4  augustss 
    736  1.4  augustss #ifdef DIAGNOSTIC
    737  1.4  augustss 	if (mhwp == NULL) {
    738  1.4  augustss 		printf("midi_attach_mi: NULL\n");
    739  1.4  augustss 		return;
    740  1.4  augustss 	}
    741  1.4  augustss #endif
    742  1.4  augustss 	arg.type = AUDIODEV_TYPE_MIDI;
    743  1.4  augustss 	arg.hwif = mhwp;
    744  1.4  augustss 	arg.hdl = hdlp;
    745  1.4  augustss 	(void)config_found(dev, &arg, audioprint);
    746  1.1  augustss }
    747  1.1  augustss 
    748  1.1  augustss #endif /* NMIDI > 0 */
    749