Home | History | Annotate | Line # | Download | only in dev
midi.c revision 1.1
      1  1.1  augustss /*	$NetBSD: midi.c,v 1.1 1998/08/07 00:00:58 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.1  augustss #include <dev/midivar.h>
     62  1.1  augustss 
     63  1.1  augustss #ifdef AUDIO_DEBUG
     64  1.1  augustss #define DPRINTF(x)	if (mididebug) printf x
     65  1.1  augustss #define DPRINTFN(n,x)	if (mididebug >= (n)) printf x
     66  1.1  augustss int	mididebug = 0;
     67  1.1  augustss #else
     68  1.1  augustss #define DPRINTF(x)
     69  1.1  augustss #define DPRINTFN(n,x)
     70  1.1  augustss #endif
     71  1.1  augustss 
     72  1.1  augustss int midi_wait;
     73  1.1  augustss 
     74  1.1  augustss void midi_in(void *, int);
     75  1.1  augustss void midi_out(void *);
     76  1.1  augustss int midi_start_output(struct midi_softc *, int);
     77  1.1  augustss static __inline int midi_sleep_timo(int *, char *, int);
     78  1.1  augustss static __inline int midi_sleep(int *, char *);
     79  1.1  augustss static __inline void midi_wakeup(int *);
     80  1.1  augustss void midi_initbuf(struct midi_buffer *);
     81  1.1  augustss void midi_timeout(void *);
     82  1.1  augustss 
     83  1.1  augustss int	midiprobe __P((struct device *, struct cfdata *, void *));
     84  1.1  augustss void	midiattach __P((struct device *, struct device *, void *));
     85  1.1  augustss 
     86  1.1  augustss struct cfattach midi_ca = {
     87  1.1  augustss 	sizeof(struct midi_softc), midiprobe, midiattach
     88  1.1  augustss };
     89  1.1  augustss 
     90  1.1  augustss extern struct cfdriver midi_cd;
     91  1.1  augustss 
     92  1.1  augustss int
     93  1.1  augustss midiprobe(parent, match, aux)
     94  1.1  augustss 	struct device *parent;
     95  1.1  augustss 	struct cfdata *match;
     96  1.1  augustss 	void *aux;
     97  1.1  augustss {
     98  1.1  augustss 	struct audio_attach_args *sa = aux;
     99  1.1  augustss 
    100  1.1  augustss 	DPRINTFN(6,("midiprobe: type=%d sa=%p hw=%p\n",
    101  1.1  augustss 		 sa->type, sa, sa->hwif));
    102  1.1  augustss 	return (sa->type == AUDIODEV_TYPE_MIDI) ? 1 : 0;
    103  1.1  augustss }
    104  1.1  augustss 
    105  1.1  augustss void
    106  1.1  augustss midiattach(parent, self, aux)
    107  1.1  augustss 	struct device *parent, *self;
    108  1.1  augustss 	void *aux;
    109  1.1  augustss {
    110  1.1  augustss 	struct midi_softc *sc = (void *)self;
    111  1.1  augustss 	struct audio_attach_args *sa = aux;
    112  1.1  augustss 	struct midi_hw_if *hwp = sa->hwif;
    113  1.1  augustss 	void *hdlp = sa->hdl;
    114  1.1  augustss 	struct midi_info mi;
    115  1.1  augustss 
    116  1.1  augustss 	DPRINTFN(6, ("MIDI attach\n"));
    117  1.1  augustss 
    118  1.1  augustss #ifdef DIAGNOSTIC
    119  1.1  augustss 	if (hwp == 0 ||
    120  1.1  augustss 	    hwp->open == 0 ||
    121  1.1  augustss 	    hwp->close == 0 ||
    122  1.1  augustss 	    hwp->output == 0 ||
    123  1.1  augustss 	    hwp->getinfo == 0) {
    124  1.1  augustss 		printf("midi: missing method\n");
    125  1.1  augustss 		return;
    126  1.1  augustss 	}
    127  1.1  augustss #endif
    128  1.1  augustss 
    129  1.1  augustss 	sc->hw_if = hwp;
    130  1.1  augustss 	sc->hw_hdl = hdlp;
    131  1.1  augustss 	sc->sc_dev = parent;
    132  1.1  augustss 	sc->isopen = 0;
    133  1.1  augustss 
    134  1.1  augustss 	midi_initbuf(&sc->outbuf);
    135  1.1  augustss 	midi_initbuf(&sc->inbuf);
    136  1.1  augustss 
    137  1.1  augustss 	midi_wait = MIDI_WAIT * hz / 1000000;
    138  1.1  augustss 	if (midi_wait == 0)
    139  1.1  augustss 		midi_wait = 1;
    140  1.1  augustss 
    141  1.1  augustss 	hwp->getinfo(hdlp, &mi);
    142  1.1  augustss 	sc->props = mi.props;
    143  1.1  augustss 	printf(" <%s>\n", mi.name);
    144  1.1  augustss }
    145  1.1  augustss 
    146  1.1  augustss int
    147  1.1  augustss midi_unit_count()
    148  1.1  augustss {
    149  1.1  augustss 	return midi_cd.cd_ndevs;
    150  1.1  augustss }
    151  1.1  augustss 
    152  1.1  augustss void
    153  1.1  augustss midi_initbuf(mb)
    154  1.1  augustss 	struct midi_buffer *mb;
    155  1.1  augustss {
    156  1.1  augustss 	mb->used = 0;
    157  1.1  augustss 	mb->usedhigh = MIDI_BUFSIZE;
    158  1.1  augustss 	mb->end = mb->start + mb->usedhigh;
    159  1.1  augustss 	mb->inp = mb->outp = mb->start;
    160  1.1  augustss }
    161  1.1  augustss 
    162  1.1  augustss static __inline int
    163  1.1  augustss midi_sleep_timo(chan, label, timo)
    164  1.1  augustss 	int *chan;
    165  1.1  augustss 	char *label;
    166  1.1  augustss 	int timo;
    167  1.1  augustss {
    168  1.1  augustss 	int st;
    169  1.1  augustss 
    170  1.1  augustss 	if (!label)
    171  1.1  augustss 		label = "midi";
    172  1.1  augustss 
    173  1.1  augustss 	DPRINTFN(5, ("midi_sleep_timo: %p %s %d\n", chan, label, timo));
    174  1.1  augustss 	*chan = 1;
    175  1.1  augustss 	st = tsleep(chan, PWAIT | PCATCH, label, timo);
    176  1.1  augustss 	*chan = 0;
    177  1.1  augustss #ifdef MIDI_DEBUG
    178  1.1  augustss 	if (st != 0)
    179  1.1  augustss 		printf("midi_sleep: %d\n", st);
    180  1.1  augustss #endif
    181  1.1  augustss 	return st;
    182  1.1  augustss }
    183  1.1  augustss 
    184  1.1  augustss static __inline int
    185  1.1  augustss midi_sleep(chan, label)
    186  1.1  augustss 	int *chan;
    187  1.1  augustss 	char *label;
    188  1.1  augustss {
    189  1.1  augustss 	return midi_sleep_timo(chan, label, 0);
    190  1.1  augustss }
    191  1.1  augustss 
    192  1.1  augustss static __inline void
    193  1.1  augustss midi_wakeup(chan)
    194  1.1  augustss 	int *chan;
    195  1.1  augustss {
    196  1.1  augustss 	if (*chan) {
    197  1.1  augustss 		DPRINTFN(5, ("midi_wakeup: %p\n", chan));
    198  1.1  augustss 		wakeup(chan);
    199  1.1  augustss 		*chan = 0;
    200  1.1  augustss 	}
    201  1.1  augustss }
    202  1.1  augustss 
    203  1.1  augustss static int midi_lengths[] = { 2,2,2,2,1,1,2,0 };
    204  1.1  augustss /* Number of bytes in a MIDI command */
    205  1.1  augustss #define MIDI_LENGTH(d) (midi_lengths[((d) >> 4) & 7])
    206  1.1  augustss 
    207  1.1  augustss void
    208  1.1  augustss midi_in(addr, data)
    209  1.1  augustss 	void *addr;
    210  1.1  augustss 	int data;
    211  1.1  augustss {
    212  1.1  augustss 	struct midi_softc *sc = addr;
    213  1.1  augustss 	struct midi_buffer *mb = &sc->inbuf;
    214  1.1  augustss 	int i;
    215  1.1  augustss 
    216  1.1  augustss 	if (data == MIDI_ACK)
    217  1.1  augustss 		return;
    218  1.1  augustss 	DPRINTFN(3, ("midi_in: %p 0x%02x\n", sc, data));
    219  1.1  augustss 	if (!(sc->flags & FREAD))
    220  1.1  augustss 		return;		/* discard data if not reading */
    221  1.1  augustss 
    222  1.1  augustss 	switch(sc->in_state) {
    223  1.1  augustss 	case MIDI_IN_START:
    224  1.1  augustss 		if (MIDI_IS_STATUS(data)) {
    225  1.1  augustss 			switch(data) {
    226  1.1  augustss 			case 0xf0: /* Sysex */
    227  1.1  augustss 				sc->in_state = MIDI_IN_SYSEX;
    228  1.1  augustss 				break;
    229  1.1  augustss 			case 0xf1: /* MTC quarter frame */
    230  1.1  augustss 			case 0xf3: /* Song select */
    231  1.1  augustss 				sc->in_state = MIDI_IN_DATA;
    232  1.1  augustss 				sc->in_msg[0] = data;
    233  1.1  augustss 				sc->in_pos = 1;
    234  1.1  augustss 				sc->in_left = 1;
    235  1.1  augustss 				break;
    236  1.1  augustss 			case 0xf2: /* Song position pointer */
    237  1.1  augustss 				sc->in_state = MIDI_IN_DATA;
    238  1.1  augustss 				sc->in_msg[0] = data;
    239  1.1  augustss 				sc->in_pos = 1;
    240  1.1  augustss 				sc->in_left = 2;
    241  1.1  augustss 				break;
    242  1.1  augustss 			default:
    243  1.1  augustss 				if (MIDI_IS_COMMON(data)) {
    244  1.1  augustss 					sc->in_msg[0] = data;
    245  1.1  augustss 					sc->in_pos = 1;
    246  1.1  augustss 					goto deliver;
    247  1.1  augustss 				} else {
    248  1.1  augustss 					sc->in_state = MIDI_IN_DATA;
    249  1.1  augustss 					sc->in_msg[0] = sc->in_status = data;
    250  1.1  augustss 					sc->in_pos = 1;
    251  1.1  augustss 					sc->in_left = MIDI_LENGTH(sc->in_status);
    252  1.1  augustss 				}
    253  1.1  augustss 				break;
    254  1.1  augustss 			}
    255  1.1  augustss 		} else {
    256  1.1  augustss 			if (MIDI_IS_STATUS(sc->in_status)) {
    257  1.1  augustss 				sc->in_state = MIDI_IN_DATA;
    258  1.1  augustss 				sc->in_msg[0] = sc->in_status;
    259  1.1  augustss 				sc->in_msg[1] = data;
    260  1.1  augustss 				sc->in_pos = 2;
    261  1.1  augustss 				sc->in_left = MIDI_LENGTH(sc->in_status) - 1;
    262  1.1  augustss 			}
    263  1.1  augustss 		}
    264  1.1  augustss 		return;
    265  1.1  augustss 	case MIDI_IN_DATA:
    266  1.1  augustss 		sc->in_msg[sc->in_pos++] = data;
    267  1.1  augustss 		if (--sc->in_left <= 0)
    268  1.1  augustss 			break;	/* deliver data */
    269  1.1  augustss 		return;
    270  1.1  augustss 	case MIDI_IN_SYSEX:
    271  1.1  augustss 		if (data == MIDI_SYSEX_END)
    272  1.1  augustss 			sc->in_state = MIDI_IN_START;
    273  1.1  augustss 		return;
    274  1.1  augustss 	}
    275  1.1  augustss deliver:
    276  1.1  augustss 	sc->in_state = MIDI_IN_START;
    277  1.1  augustss #if NSEQUENCER > 0
    278  1.1  augustss 	if (sc->seqopen) {
    279  1.1  augustss 		extern void midisyn_in __P((struct midi_softc *,u_char *,int));
    280  1.1  augustss 		midisyn_in(sc, sc->in_msg, sc->in_pos);
    281  1.1  augustss 		return;
    282  1.1  augustss 	}
    283  1.1  augustss #endif
    284  1.1  augustss 
    285  1.1  augustss 	if (mb->used + sc->in_pos > mb->usedhigh) {
    286  1.1  augustss 		DPRINTF(("midi_in: buffer full, discard data=0x%02x\n",
    287  1.1  augustss 			 sc->in_msg[0]));
    288  1.1  augustss 		return;
    289  1.1  augustss 	}
    290  1.1  augustss 	for (i = 0; i < sc->in_pos; i++) {
    291  1.1  augustss 		*mb->inp++ = sc->in_msg[i];
    292  1.1  augustss 		if (mb->inp >= mb->end)
    293  1.1  augustss 			mb->inp = mb->start;
    294  1.1  augustss 		mb->used++;
    295  1.1  augustss 	}
    296  1.1  augustss 	midi_wakeup(&sc->rchan);
    297  1.1  augustss 	selwakeup(&sc->rsel);
    298  1.1  augustss 	if (sc->async)
    299  1.1  augustss 		psignal(sc->async, SIGIO);
    300  1.1  augustss }
    301  1.1  augustss 
    302  1.1  augustss void
    303  1.1  augustss midi_out(addr)
    304  1.1  augustss 	void *addr;
    305  1.1  augustss {
    306  1.1  augustss 	struct midi_softc *sc = addr;
    307  1.1  augustss 	DPRINTFN(3, ("midi_out: %p\n", sc));
    308  1.1  augustss 	midi_start_output(sc, 1);
    309  1.1  augustss }
    310  1.1  augustss 
    311  1.1  augustss int
    312  1.1  augustss midiopen(dev, flags, ifmt, p)
    313  1.1  augustss 	dev_t dev;
    314  1.1  augustss 	int flags, ifmt;
    315  1.1  augustss 	struct proc *p;
    316  1.1  augustss {
    317  1.1  augustss 	int unit = MIDIUNIT(dev);
    318  1.1  augustss 	struct midi_softc *sc;
    319  1.1  augustss 	struct midi_hw_if *hw;
    320  1.1  augustss 	int error;
    321  1.1  augustss 
    322  1.1  augustss 	if (unit >= midi_cd.cd_ndevs ||
    323  1.1  augustss 	    (sc = midi_cd.cd_devs[unit]) == NULL)
    324  1.1  augustss 		return ENXIO;
    325  1.1  augustss 	DPRINTF(("midiopen %p\n", sc));
    326  1.1  augustss 
    327  1.1  augustss 	hw = sc->hw_if;
    328  1.1  augustss 	if (!hw)
    329  1.1  augustss 		return ENXIO;
    330  1.1  augustss 	if (sc->isopen)
    331  1.1  augustss 		return EBUSY;
    332  1.1  augustss 	sc->in_state = MIDI_IN_START;
    333  1.1  augustss 	sc->in_status = 0;
    334  1.1  augustss 	error = hw->open(sc->hw_hdl, flags, midi_in, midi_out, sc);
    335  1.1  augustss 	if (error)
    336  1.1  augustss 		return error;
    337  1.1  augustss 	sc->isopen++;
    338  1.1  augustss 	sc->flags = flags;
    339  1.1  augustss 	sc->rchan = 0;
    340  1.1  augustss 	sc->wchan = 0;
    341  1.1  augustss 	sc->pbus = 0;
    342  1.1  augustss 	sc->async = 0;
    343  1.1  augustss 
    344  1.1  augustss 	return 0;
    345  1.1  augustss }
    346  1.1  augustss 
    347  1.1  augustss int
    348  1.1  augustss midiclose(dev, flags, ifmt, p)
    349  1.1  augustss 	dev_t dev;
    350  1.1  augustss 	int flags, ifmt;
    351  1.1  augustss 	struct proc *p;
    352  1.1  augustss {
    353  1.1  augustss 	int unit = MIDIUNIT(dev);
    354  1.1  augustss 	struct midi_softc *sc = midi_cd.cd_devs[unit];
    355  1.1  augustss 	struct midi_hw_if *hw = sc->hw_if;
    356  1.1  augustss 	int s, error;
    357  1.1  augustss 
    358  1.1  augustss 	DPRINTF(("midiclose %p\n", sc));
    359  1.1  augustss 
    360  1.1  augustss 	midi_start_output(sc, 0);
    361  1.1  augustss 	error = 0;
    362  1.1  augustss 	s = splaudio();
    363  1.1  augustss 	while (sc->outbuf.used > 0 && !error) {
    364  1.1  augustss 		DPRINTFN(2,("midiclose sleep used=%d\n", sc->outbuf.used));
    365  1.1  augustss 		error = midi_sleep_timo(&sc->wchan, "mid dr", 10*hz);
    366  1.1  augustss 	}
    367  1.1  augustss 	splx(s);
    368  1.1  augustss 	hw->close(sc->hw_hdl);
    369  1.1  augustss 	sc->isopen = 0;
    370  1.1  augustss #if NSEQUENCER > 0
    371  1.1  augustss 	sc->seqopen = 0;
    372  1.1  augustss #endif
    373  1.1  augustss 	return 0;
    374  1.1  augustss }
    375  1.1  augustss 
    376  1.1  augustss int
    377  1.1  augustss midiread(dev, uio, ioflag)
    378  1.1  augustss 	dev_t dev;
    379  1.1  augustss 	struct uio *uio;
    380  1.1  augustss 	int ioflag;
    381  1.1  augustss {
    382  1.1  augustss 	int unit = MIDIUNIT(dev);
    383  1.1  augustss 	struct midi_softc *sc = midi_cd.cd_devs[unit];
    384  1.1  augustss 	struct midi_buffer *mb = &sc->inbuf;
    385  1.1  augustss 	int error;
    386  1.1  augustss 	u_char *outp;
    387  1.1  augustss 	int used, cc, n, resid;
    388  1.1  augustss 	int s;
    389  1.1  augustss 
    390  1.1  augustss 	DPRINTF(("midiread: %p, count=%d\n", sc, uio->uio_resid));
    391  1.1  augustss 
    392  1.1  augustss 	error = 0;
    393  1.1  augustss 	resid = uio->uio_resid;
    394  1.1  augustss 	while (uio->uio_resid == resid && !error) {
    395  1.1  augustss 		s = splaudio();
    396  1.1  augustss 		while (mb->used <= 0) {
    397  1.1  augustss 			if (ioflag & IO_NDELAY) {
    398  1.1  augustss 				splx(s);
    399  1.1  augustss 				return EWOULDBLOCK;
    400  1.1  augustss 			}
    401  1.1  augustss 			error = midi_sleep(&sc->rchan, "mid rd");
    402  1.1  augustss 			if (error) {
    403  1.1  augustss 				splx(s);
    404  1.1  augustss 				return error;
    405  1.1  augustss 			}
    406  1.1  augustss 		}
    407  1.1  augustss 		used = mb->used;
    408  1.1  augustss 		outp = mb->outp;
    409  1.1  augustss 		splx(s);
    410  1.1  augustss 		cc = used;	/* maximum to read */
    411  1.1  augustss 		n = mb->end - outp;
    412  1.1  augustss 		if (n < cc)
    413  1.1  augustss 			cc = n;	/* don't read beyond end of buffer */
    414  1.1  augustss 		if (uio->uio_resid < cc)
    415  1.1  augustss 			cc = uio->uio_resid; /* and no more than we want */
    416  1.1  augustss 		DPRINTFN(3, ("midiread: uiomove cc=%d\n", cc));
    417  1.1  augustss 		error = uiomove(outp, cc, uio);
    418  1.1  augustss 		if (error)
    419  1.1  augustss 			break;
    420  1.1  augustss 		used -= cc;
    421  1.1  augustss 		outp += cc;
    422  1.1  augustss 		if (outp >= mb->end)
    423  1.1  augustss 			outp = mb->start;
    424  1.1  augustss 		s = splaudio();
    425  1.1  augustss 		mb->outp = outp;
    426  1.1  augustss 		mb->used = used;
    427  1.1  augustss 		splx(s);
    428  1.1  augustss 	}
    429  1.1  augustss 	return error;
    430  1.1  augustss }
    431  1.1  augustss 
    432  1.1  augustss void
    433  1.1  augustss midi_timeout(arg)
    434  1.1  augustss 	void *arg;
    435  1.1  augustss {
    436  1.1  augustss 	struct midi_softc *sc = arg;
    437  1.1  augustss 
    438  1.1  augustss 	DPRINTFN(3,("midi_timeout: %p\n", sc));
    439  1.1  augustss 	midi_start_output(sc, 1);
    440  1.1  augustss }
    441  1.1  augustss 
    442  1.1  augustss int
    443  1.1  augustss midi_start_output(sc, intr)
    444  1.1  augustss 	struct midi_softc *sc;
    445  1.1  augustss 	int intr;
    446  1.1  augustss {
    447  1.1  augustss 	struct midi_buffer *mb = &sc->outbuf;
    448  1.1  augustss 	u_char *outp;
    449  1.1  augustss 	int error;
    450  1.1  augustss 	int s;
    451  1.1  augustss 	int i, mmax;
    452  1.1  augustss 
    453  1.1  augustss 	error = 0;
    454  1.1  augustss 	mmax = sc->props & MIDI_PROP_OUT_INTR ? 1 : MIDI_MAX_WRITE;
    455  1.1  augustss 	s = splaudio();
    456  1.1  augustss 	if (sc->pbus && !intr) {
    457  1.1  augustss 		DPRINTFN(4, ("midi_start_output: busy\n"));
    458  1.1  augustss 		splx(s);
    459  1.1  augustss 		return 0;
    460  1.1  augustss 	}
    461  1.1  augustss 	sc->pbus = 1;
    462  1.1  augustss 	for (i = 0; i < mmax && mb->used > 0 && !error; i++) {
    463  1.1  augustss 		outp = mb->outp;
    464  1.1  augustss 		splx(s);
    465  1.1  augustss 		DPRINTFN(4, ("midi_start_output: %p i=%d, data=0x%02x\n",
    466  1.1  augustss 			     sc, i, *outp));
    467  1.1  augustss 		error = sc->hw_if->output(sc->hw_hdl, *outp++);
    468  1.1  augustss 		if (outp >= mb->end)
    469  1.1  augustss 			outp = mb->start;
    470  1.1  augustss 		s = splaudio();
    471  1.1  augustss 		mb->outp = outp;
    472  1.1  augustss 		mb->used--;
    473  1.1  augustss 	}
    474  1.1  augustss 	midi_wakeup(&sc->wchan);
    475  1.1  augustss 	selwakeup(&sc->wsel);
    476  1.1  augustss 	if (sc->async)
    477  1.1  augustss 		psignal(sc->async, SIGIO);
    478  1.1  augustss 	if (mb->used > 0) {
    479  1.1  augustss 		if (!(sc->props & MIDI_PROP_OUT_INTR))
    480  1.1  augustss 			timeout(midi_timeout, sc, midi_wait);
    481  1.1  augustss 	} else
    482  1.1  augustss 		sc->pbus = 0;
    483  1.1  augustss 	splx(s);
    484  1.1  augustss 	return error;
    485  1.1  augustss }
    486  1.1  augustss 
    487  1.1  augustss int
    488  1.1  augustss midiwrite(dev, uio, ioflag)
    489  1.1  augustss 	dev_t dev;
    490  1.1  augustss 	struct uio *uio;
    491  1.1  augustss 	int ioflag;
    492  1.1  augustss {
    493  1.1  augustss 	int unit = MIDIUNIT(dev);
    494  1.1  augustss 	struct midi_softc *sc = midi_cd.cd_devs[unit];
    495  1.1  augustss 	struct midi_buffer *mb = &sc->outbuf;
    496  1.1  augustss 	int error;
    497  1.1  augustss 	u_char *inp;
    498  1.1  augustss 	int used, cc, n;
    499  1.1  augustss 	int s;
    500  1.1  augustss 
    501  1.1  augustss 	DPRINTFN(2, ("midiwrite: %p, unit=%d, count=%d\n", sc, unit,
    502  1.1  augustss 		     uio->uio_resid));
    503  1.1  augustss 
    504  1.1  augustss 	error = 0;
    505  1.1  augustss 	while (uio->uio_resid > 0 && !error) {
    506  1.1  augustss 		s = splaudio();
    507  1.1  augustss 		if (mb->used >= mb->usedhigh) {
    508  1.1  augustss 			DPRINTFN(3,("midi_write: sleep used=%d hiwat=%d\n",
    509  1.1  augustss 				 mb->used, mb->usedhigh));
    510  1.1  augustss 			if (ioflag & IO_NDELAY) {
    511  1.1  augustss 				splx(s);
    512  1.1  augustss 				return EWOULDBLOCK;
    513  1.1  augustss 			}
    514  1.1  augustss 			error = midi_sleep(&sc->wchan, "mid wr");
    515  1.1  augustss 			if (error) {
    516  1.1  augustss 				splx(s);
    517  1.1  augustss 				return error;
    518  1.1  augustss 			}
    519  1.1  augustss 		}
    520  1.1  augustss 		used = mb->used;
    521  1.1  augustss 		inp = mb->inp;
    522  1.1  augustss 		splx(s);
    523  1.1  augustss 		cc = mb->usedhigh - used; 	/* maximum to write */
    524  1.1  augustss 		n = mb->end - inp;
    525  1.1  augustss 		if (n < cc)
    526  1.1  augustss 			cc = n;			/* don't write beyond end of buffer */
    527  1.1  augustss 		if (uio->uio_resid < cc)
    528  1.1  augustss 			cc = uio->uio_resid; 	/* and no more than we have */
    529  1.1  augustss 		error = uiomove(inp, cc, uio);
    530  1.1  augustss #ifdef MIDI_DEBUG
    531  1.1  augustss 		if (error)
    532  1.1  augustss 		        printf("midi_write:(1) uiomove failed %d; cc=%d inp=%p\n",
    533  1.1  augustss 			       error, cc, inp);
    534  1.1  augustss #endif
    535  1.1  augustss 		if (error)
    536  1.1  augustss 			break;
    537  1.1  augustss 		inp = mb->inp + cc;
    538  1.1  augustss 		if (inp >= mb->end)
    539  1.1  augustss 			inp = mb->start;
    540  1.1  augustss 		s = splaudio();
    541  1.1  augustss 		mb->inp = inp;
    542  1.1  augustss 		mb->used += cc;
    543  1.1  augustss 		splx(s);
    544  1.1  augustss 		error = midi_start_output(sc, 0);
    545  1.1  augustss 	}
    546  1.1  augustss 	return error;
    547  1.1  augustss }
    548  1.1  augustss 
    549  1.1  augustss int
    550  1.1  augustss midiioctl(dev, cmd, addr, flag, p)
    551  1.1  augustss 	dev_t dev;
    552  1.1  augustss 	u_long cmd;
    553  1.1  augustss 	caddr_t addr;
    554  1.1  augustss 	int flag;
    555  1.1  augustss 	struct proc *p;
    556  1.1  augustss {
    557  1.1  augustss 	int unit = MIDIUNIT(dev);
    558  1.1  augustss 	struct midi_softc *sc = midi_cd.cd_devs[unit];
    559  1.1  augustss 	struct midi_hw_if *hw = sc->hw_if;
    560  1.1  augustss 	int error;
    561  1.1  augustss 
    562  1.1  augustss 	DPRINTF(("midiioctl: %p cmd=0x%08lx\n", sc, cmd));
    563  1.1  augustss 	error = 0;
    564  1.1  augustss 	switch (cmd) {
    565  1.1  augustss 	case FIONBIO:
    566  1.1  augustss 		/* All handled in the upper FS layer. */
    567  1.1  augustss 		break;
    568  1.1  augustss 
    569  1.1  augustss 	case FIOASYNC:
    570  1.1  augustss 		if (*(int *)addr) {
    571  1.1  augustss 			if (sc->async)
    572  1.1  augustss 				return EBUSY;
    573  1.1  augustss 			sc->async = p;
    574  1.1  augustss 			DPRINTF(("midi_ioctl: FIOASYNC %p\n", p));
    575  1.1  augustss 		} else
    576  1.1  augustss 			sc->async = 0;
    577  1.1  augustss 		break;
    578  1.1  augustss 
    579  1.1  augustss #if 0
    580  1.1  augustss 	case MIDI_PRETIME:
    581  1.1  augustss 		/* XXX OSS
    582  1.1  augustss 		 * This should set up a read timeout, but that's
    583  1.1  augustss 		 * why we have poll(), so there's nothing yet. */
    584  1.1  augustss 		error = EINVAL;
    585  1.1  augustss 		break;
    586  1.1  augustss #endif
    587  1.1  augustss 
    588  1.1  augustss 	default:
    589  1.1  augustss 		if (hw->ioctl)
    590  1.1  augustss 			error = hw->ioctl(cmd, addr, flag, p);
    591  1.1  augustss 		else
    592  1.1  augustss 			error = EINVAL;
    593  1.1  augustss 		break;
    594  1.1  augustss 	}
    595  1.1  augustss 	return error;
    596  1.1  augustss }
    597  1.1  augustss 
    598  1.1  augustss int
    599  1.1  augustss midipoll(dev, events, p)
    600  1.1  augustss 	dev_t dev;
    601  1.1  augustss 	int events;
    602  1.1  augustss 	struct proc *p;
    603  1.1  augustss {
    604  1.1  augustss 	int unit = MIDIUNIT(dev);
    605  1.1  augustss 	struct midi_softc *sc = midi_cd.cd_devs[unit];
    606  1.1  augustss 	int revents = 0;
    607  1.1  augustss 	int s = splaudio();
    608  1.1  augustss 
    609  1.1  augustss 	DPRINTF(("midipoll: %p events=0x%x\n", sc, events));
    610  1.1  augustss 
    611  1.1  augustss 	if (events & (POLLIN | POLLRDNORM))
    612  1.1  augustss 		if (sc->inbuf.used > 0)
    613  1.1  augustss 			revents |= events & (POLLIN | POLLRDNORM);
    614  1.1  augustss 
    615  1.1  augustss 	if (events & (POLLOUT | POLLWRNORM))
    616  1.1  augustss 		if (sc->outbuf.used < sc->outbuf.usedhigh)
    617  1.1  augustss 			revents |= events & (POLLOUT | POLLWRNORM);
    618  1.1  augustss 
    619  1.1  augustss 	if (revents == 0) {
    620  1.1  augustss 		if (events & (POLLIN | POLLRDNORM))
    621  1.1  augustss 			selrecord(p, &sc->rsel);
    622  1.1  augustss 
    623  1.1  augustss 		if (events & (POLLOUT | POLLWRNORM))
    624  1.1  augustss 			selrecord(p, &sc->wsel);
    625  1.1  augustss 	}
    626  1.1  augustss 
    627  1.1  augustss 	splx(s);
    628  1.1  augustss 	return revents;
    629  1.1  augustss }
    630  1.1  augustss 
    631  1.1  augustss void
    632  1.1  augustss midi_getinfo(dev, mi)
    633  1.1  augustss 	dev_t dev;
    634  1.1  augustss 	struct midi_info *mi;
    635  1.1  augustss {
    636  1.1  augustss 	int unit = MIDIUNIT(dev);
    637  1.1  augustss 	struct midi_softc *sc;
    638  1.1  augustss 
    639  1.1  augustss 	if (unit >= midi_cd.cd_ndevs ||
    640  1.1  augustss 	    (sc = midi_cd.cd_devs[unit]) == NULL)
    641  1.1  augustss 		return;
    642  1.1  augustss 	sc->hw_if->getinfo(sc->hw_hdl, mi);
    643  1.1  augustss }
    644  1.1  augustss 
    645  1.1  augustss #endif /* NMIDI > 0 */
    646