xref: /openbsd-src/sys/dev/midi.c (revision 4c1e55dc91edd6e69ccc60ce855900fbc12cf34f)
1 /*	$OpenBSD: midi.c,v 1.28 2012/04/17 07:58:47 ratchov Exp $	*/
2 
3 /*
4  * Copyright (c) 2003, 2004 Alexandre Ratchov
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 /*
20  * TODO
21  *	- put the sequencer stuff in sequencer.c and sequencervar.h
22  *	  there is no reason to have it here. The sequencer
23  *	  driver need only to open the midi hw_if thus it does not
24  *	  need this driver
25  */
26 
27 #include "sequencer.h"
28 
29 #include <sys/param.h>
30 #include <sys/fcntl.h>
31 #include <sys/systm.h>
32 #include <sys/ioctl.h>
33 #include <sys/exec.h>
34 #include <sys/conf.h>
35 #include <sys/lkm.h>
36 #include <sys/proc.h>
37 #include <sys/poll.h>
38 #include <sys/kernel.h>
39 #include <sys/timeout.h>
40 #include <sys/vnode.h>
41 #include <sys/signalvar.h>
42 #include <sys/malloc.h>
43 #include <sys/device.h>
44 
45 #include <dev/midi_if.h>
46 #include <dev/audio_if.h>
47 #include <dev/midivar.h>
48 
49 
50 int	midiopen(dev_t, int, int, struct proc *);
51 int	midiclose(dev_t, int, int, struct proc *);
52 int	midiread(dev_t, struct uio *, int);
53 int	midiwrite(dev_t, struct uio *, int);
54 int	midipoll(dev_t, int, struct proc *);
55 int	midikqfilter(dev_t, struct knote *);
56 int	midiioctl(dev_t, u_long, caddr_t, int, struct proc *);
57 int	midiprobe(struct device *, void *, void *);
58 void	midiattach(struct device *, struct device *, void *);
59 int	mididetach(struct device *, int);
60 int	midiprint(void *, const char *);
61 
62 void	midi_iintr(void *, int);
63 void 	midi_ointr(void *);
64 void	midi_out_start(struct midi_softc *);
65 void	midi_out_stop(struct midi_softc *);
66 void	midi_out_do(struct midi_softc *);
67 void	midi_attach(struct midi_softc *, struct device *);
68 
69 
70 #if NSEQUENCER > 0
71 int	midi_unit_count(void);
72 void	midi_toevent(struct midi_softc *, int);
73 int	midi_writebytes(int, u_char *, int);
74 void	midiseq_in(struct midi_dev *, u_char *, int);
75 #endif
76 
77 struct cfattach midi_ca = {
78 	sizeof(struct midi_softc), midiprobe, midiattach, mididetach
79 };
80 
81 struct cfdriver midi_cd = {
82 	NULL, "midi", DV_DULL
83 };
84 
85 
86 void filt_midiwdetach(struct knote *);
87 int filt_midiwrite(struct knote *, long);
88 
89 struct filterops midiwrite_filtops = {
90 	1, NULL, filt_midiwdetach, filt_midiwrite
91 };
92 
93 void filt_midirdetach(struct knote *);
94 int filt_midiread(struct knote *, long);
95 
96 struct filterops midiread_filtops = {
97 	1, NULL, filt_midirdetach, filt_midiread
98 };
99 
100 
101 void
102 midi_iintr(void *addr, int data)
103 {
104 	struct midi_softc  *sc = (struct midi_softc *)addr;
105 	struct midi_buffer *mb = &sc->inbuf;
106 
107 	if (sc->isdying || !sc->isopen || !(sc->flags & FREAD))
108 		return;
109 
110 #if NSEQUENCER > 0
111 	if (sc->seqopen) {
112 		midi_toevent(sc, data);
113 		return;
114 	}
115 #endif
116 	if (MIDIBUF_ISFULL(mb))
117 		return; /* discard data */
118 
119 	MIDIBUF_WRITE(mb, data);
120 	if (mb->used == 1) {
121 		if (sc->rchan) {
122 			sc->rchan = 0;
123 			wakeup(&sc->rchan);
124 		}
125 		selwakeup(&sc->rsel);
126 		if (sc->async)
127 			psignal(sc->async, SIGIO);
128 	}
129 }
130 
131 
132 int
133 midiread(dev_t dev, struct uio *uio, int ioflag)
134 {
135 	struct midi_softc  *sc = MIDI_DEV2SC(dev);
136 	struct midi_buffer *mb = &sc->inbuf;
137 	unsigned 	    count;
138 	int		    s, error;
139 
140 	if (!(sc->flags & FREAD))
141 		return ENXIO;
142 
143 	/* if there is no data then sleep (unless IO_NDELAY flag is set) */
144 
145 	s = splaudio();
146 	while (MIDIBUF_ISEMPTY(mb)) {
147 		if (sc->isdying) {
148 			splx(s);
149 			return EIO;
150 		}
151 		if (ioflag & IO_NDELAY) {
152 			splx(s);
153 			return EWOULDBLOCK;
154 		}
155 		sc->rchan = 1;
156 		error = tsleep(&sc->rchan, PWAIT|PCATCH, "mid_rd", 0);
157 		if (error) {
158 			splx(s);
159 			return error;
160 		}
161 	}
162 
163 	/* at this stage, there is at least 1 byte */
164 
165 	while (uio->uio_resid > 0 && mb->used > 0) {
166 		count = MIDIBUF_SIZE - mb->start;
167 		if (count > mb->used)
168 			count = mb->used;
169 		if (count > uio->uio_resid)
170 			count = uio->uio_resid;
171 		error = uiomove(mb->data + mb->start, count, uio);
172 		if (error) {
173 			splx(s);
174 			return error;
175 		}
176 		MIDIBUF_REMOVE(mb, count);
177 	}
178 	splx(s);
179 	return 0;
180 }
181 
182 
183 void
184 midi_ointr(void *addr)
185 {
186 	struct midi_softc  *sc = (struct midi_softc *)addr;
187 	struct midi_buffer *mb;
188 	int 		    s;
189 
190 	if (sc->isopen && !sc->isdying) {
191 		mb = &sc->outbuf;
192 		s = splaudio();
193 		if (mb->used > 0) {
194 #ifdef MIDI_DEBUG
195 			if (!sc->isbusy) {
196 				printf("midi_ointr: output must be busy\n");
197 			}
198 #endif
199 			midi_out_do(sc);
200 		} else if (sc->isbusy)
201 			midi_out_stop(sc);
202 		splx(s);
203 	}
204 }
205 
206 
207 void
208 midi_out_start(struct midi_softc *sc)
209 {
210 	if (!sc->isbusy) {
211 		sc->isbusy = 1;
212 		midi_out_do(sc);
213 	}
214 }
215 
216 
217 void
218 midi_out_stop(struct midi_softc *sc)
219 {
220 	sc->isbusy = 0;
221 	if (sc->wchan) {
222 		sc->wchan = 0;
223 		wakeup(&sc->wchan);
224 	}
225 	selwakeup(&sc->wsel);
226 	if (sc->async)
227 		psignal(sc->async, SIGIO);
228 }
229 
230 
231 void
232 midi_out_do(struct midi_softc *sc)
233 {
234 	struct midi_buffer *mb = &sc->outbuf;
235 
236 	while (mb->used > 0) {
237 		if (!sc->hw_if->output(sc->hw_hdl, mb->data[mb->start]))
238 			break;
239 		MIDIBUF_REMOVE(mb, 1);
240 		if (MIDIBUF_ISEMPTY(mb)) {
241 			if (sc->hw_if->flush != NULL)
242 				sc->hw_if->flush(sc->hw_hdl);
243 			midi_out_stop(sc);
244 			return;
245 		}
246 	}
247 
248 	if (!(sc->props & MIDI_PROP_OUT_INTR)) {
249 		if (MIDIBUF_ISEMPTY(mb))
250 			midi_out_stop(sc);
251 		else
252 			timeout_add(&sc->timeo, 1);
253 	}
254 }
255 
256 
257 int
258 midiwrite(dev_t dev, struct uio *uio, int ioflag)
259 {
260 	struct midi_softc  *sc = MIDI_DEV2SC(dev);
261 	struct midi_buffer *mb = &sc->outbuf;
262 	unsigned 	    count;
263 	int		    s, error;
264 
265 	if (!(sc->flags & FWRITE))
266 		return ENXIO;
267 	if (sc->isdying)
268 		return EIO;
269 
270 	/*
271 	 * If IO_NDELAY flag is set then check if there is enough room
272 	 * in the buffer to store at least one byte. If not then dont
273 	 * start the write process.
274 	 */
275 
276 	if ((ioflag & IO_NDELAY) && MIDIBUF_ISFULL(mb) && (uio->uio_resid > 0))
277 		return EWOULDBLOCK;
278 
279 	while (uio->uio_resid > 0) {
280 		s = splaudio();
281 		while (MIDIBUF_ISFULL(mb)) {
282 			if (ioflag & IO_NDELAY) {
283 				/*
284 				 * At this stage at least one byte is already
285 				 * moved so we do not return EWOULDBLOCK
286 				 */
287 				splx(s);
288 				return 0;
289 			}
290 			sc->wchan = 1;
291 			error = tsleep(&sc->wchan, PWAIT|PCATCH, "mid_wr", 0);
292 			if (error) {
293 				splx(s);
294 				return error;
295 			}
296 			if (sc->isdying) {
297 				splx(s);
298 				return EIO;
299 			}
300 		}
301 
302 		count = MIDIBUF_SIZE - MIDIBUF_END(mb);
303 		if (count > MIDIBUF_AVAIL(mb))
304 			count = MIDIBUF_AVAIL(mb);
305 		if (count > uio->uio_resid)
306 			count = uio->uio_resid;
307 		error = uiomove(mb->data + MIDIBUF_END(mb), count, uio);
308 		if (error) {
309 			splx(s);
310 			return error;
311 		}
312 		mb->used += count;
313 		midi_out_start(sc);
314 		splx(s);
315 	}
316 	return 0;
317 }
318 
319 
320 int
321 midipoll(dev_t dev, int events, struct proc *p)
322 {
323 	struct midi_softc *sc = MIDI_DEV2SC(dev);
324 	int		   s, revents;
325 
326 	if (sc->isdying)
327 		return POLLERR;
328 
329 	revents = 0;
330 	s = splaudio();
331 	if (events & (POLLIN | POLLRDNORM)) {
332 		if (!MIDIBUF_ISEMPTY(&sc->inbuf))
333 			revents |= events & (POLLIN | POLLRDNORM);
334 	}
335 	if (events & (POLLOUT | POLLWRNORM)) {
336 		if (!MIDIBUF_ISFULL(&sc->outbuf))
337 			revents |= events & (POLLOUT | POLLWRNORM);
338 	}
339 	if (revents == 0) {
340 		if (events & (POLLIN | POLLRDNORM))
341 			selrecord(p, &sc->rsel);
342 		if (events & (POLLOUT | POLLWRNORM))
343 			selrecord(p, &sc->wsel);
344 	}
345 	splx(s);
346 	return (revents);
347 }
348 
349 
350 int
351 midikqfilter(dev_t dev, struct knote *kn)
352 {
353 	struct midi_softc *sc = MIDI_DEV2SC(dev);
354 	struct klist 	  *klist;
355 	int		   s;
356 
357 	switch (kn->kn_filter) {
358 	case EVFILT_READ:
359 		klist = &sc->rsel.si_note;
360 		kn->kn_fop = &midiread_filtops;
361 		break;
362 	case EVFILT_WRITE:
363 		klist = &sc->wsel.si_note;
364 		kn->kn_fop = &midiwrite_filtops;
365 		break;
366 	default:
367 		return (EINVAL);
368 	}
369 	kn->kn_hook = (void *)sc;
370 
371 	s = splaudio();
372 	SLIST_INSERT_HEAD(klist, kn, kn_selnext);
373 	splx(s);
374 
375 	return (0);
376 }
377 
378 
379 void
380 filt_midirdetach(struct knote *kn)
381 {
382 	struct midi_softc *sc = (struct midi_softc *)kn->kn_hook;
383 	int		   s;
384 
385 	s = splaudio();
386 	SLIST_REMOVE(&sc->rsel.si_note, kn, knote, kn_selnext);
387 	splx(s);
388 }
389 
390 
391 int
392 filt_midiread(struct knote *kn, long hint)
393 {
394 	struct midi_softc *sc = (struct midi_softc *)kn->kn_hook;
395 	int		   s, retval;
396 
397 	s = splaudio();
398 	retval = !MIDIBUF_ISEMPTY(&sc->inbuf);
399 	splx(s);
400 
401 	return (retval);
402 }
403 
404 
405 void
406 filt_midiwdetach(struct knote *kn)
407 {
408 	struct midi_softc *sc = (struct midi_softc *)kn->kn_hook;
409 	int 		   s;
410 
411 	s = splaudio();
412 	SLIST_REMOVE(&sc->wsel.si_note, kn, knote, kn_selnext);
413 	splx(s);
414 }
415 
416 
417 int
418 filt_midiwrite(struct knote *kn, long hint)
419 {
420 	struct midi_softc *sc = (struct midi_softc *)kn->kn_hook;
421 	int		   s, retval;
422 
423 	s = splaudio();
424 	retval = !MIDIBUF_ISFULL(&sc->outbuf);
425 	splx(s);
426 
427 	return (retval);
428 }
429 
430 
431 int
432 midiioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p)
433 {
434 	struct midi_softc *sc = MIDI_DEV2SC(dev);
435 
436 	if (sc->isdying)
437 		return EIO;
438 
439 	switch(cmd) {
440 	case FIONBIO:
441 		/* All handled in the upper FS layer */
442 		break;
443 	case FIOASYNC:
444 		if (*(int *)addr) {
445 			if (sc->async)
446 				return EBUSY;
447 			sc->async = p;
448 		} else
449 			sc->async = 0;
450 		break;
451 	default:
452 		return ENOTTY;
453 	}
454 	return 0;
455 }
456 
457 
458 int
459 midiopen(dev_t dev, int flags, int mode, struct proc *p)
460 {
461 	struct midi_softc *sc;
462 	int		   err;
463 
464 	if (MIDI_UNIT(dev) >= midi_cd.cd_ndevs)
465 		return ENXIO;
466 	sc = MIDI_DEV2SC(dev);
467 	if (sc == NULL)		/* there may be more units than devices */
468 		return ENXIO;
469 	if (sc->isdying)
470 		return EIO;
471 	if (sc->isopen)
472 		return EBUSY;
473 
474 	MIDIBUF_INIT(&sc->inbuf);
475 	MIDIBUF_INIT(&sc->outbuf);
476 	sc->isbusy = 0;
477 	sc->rchan = sc->wchan = 0;
478 	sc->async = 0;
479 	sc->flags = flags;
480 
481 	err = sc->hw_if->open(sc->hw_hdl, flags, midi_iintr, midi_ointr, sc);
482 	if (err)
483 		return err;
484 	sc->isopen = 1;
485 #if NSEQUENCER > 0
486 	sc->seq_md = 0;
487 	sc->seqopen = 0;
488 	sc->evstatus = 0xff;
489 #endif
490 	return 0;
491 }
492 
493 
494 int
495 midiclose(dev_t dev, int fflag, int devtype, struct proc *p)
496 {
497 	struct midi_softc  *sc = MIDI_DEV2SC(dev);
498 	struct midi_buffer *mb;
499 	int 		    error;
500 	int		    s;
501 
502 	mb = &sc->outbuf;
503 	if (!sc->isdying) {
504 		/* start draining output buffer */
505 		s = splaudio();
506 		if (!MIDIBUF_ISEMPTY(mb))
507 			midi_out_start(sc);
508 		while (sc->isbusy) {
509 			sc->wchan = 1;
510 			error = tsleep(&sc->wchan, PWAIT, "mid_dr", 5 * hz);
511 			if (error || sc->isdying)
512 				break;
513 		}
514 		splx(s);
515 	}
516 
517 	/*
518 	 * some hw_if->close() reset immediately the midi uart
519 	 * which flushes the internal buffer of the uart device,
520 	 * so we may lose some (important) data. To avoid this,
521 	 * sleep 20ms (around 64 bytes) to give the time to the
522 	 * uart to drain its internal buffers.
523 	 */
524 	tsleep(&sc->wchan, PWAIT, "mid_cl", hz * MIDI_MAXWRITE / MIDI_RATE);
525 	sc->hw_if->close(sc->hw_hdl);
526 	sc->isopen = 0;
527 	return 0;
528 }
529 
530 
531 int
532 midiprobe(struct device *parent, void *match, void *aux)
533 {
534 	struct audio_attach_args *sa = aux;
535 
536 	return (sa != NULL && (sa->type == AUDIODEV_TYPE_MIDI) ? 1 : 0);
537 }
538 
539 
540 void
541 midi_attach(struct midi_softc *sc, struct device *parent)
542 {
543 	struct midi_info 	  mi;
544 
545 	sc->isdying = 0;
546 	sc->hw_if->getinfo(sc->hw_hdl, &mi);
547 	sc->props = mi.props;
548 	sc->isopen = 0;
549 	timeout_set(&sc->timeo, midi_ointr, sc);
550 	printf(": <%s>\n", mi.name);
551 }
552 
553 
554 void
555 midiattach(struct device *parent, struct device *self, void *aux)
556 {
557 	struct midi_softc        *sc = (struct midi_softc *)self;
558 	struct audio_attach_args *sa = (struct audio_attach_args *)aux;
559 	struct midi_hw_if        *hwif = sa->hwif;
560 	void  			 *hdl = sa->hdl;
561 
562 #ifdef DIAGNOSTIC
563 	if (hwif == 0 ||
564 	    hwif->open == 0 ||
565 	    hwif->close == 0 ||
566 	    hwif->output == 0 ||
567 	    hwif->getinfo == 0) {
568 		printf("midi: missing method\n");
569 		return;
570 	}
571 #endif
572 	sc->hw_if = hwif;
573 	sc->hw_hdl = hdl;
574 	midi_attach(sc, parent);
575 }
576 
577 
578 int
579 mididetach(struct device *self, int flags)
580 {
581 	struct midi_softc *sc = (struct midi_softc *)self;
582 	int    maj, mn;
583 
584 	sc->isdying = 1;
585 	if (sc->wchan) {
586 		sc->wchan = 0;
587 		wakeup(&sc->wchan);
588 	}
589 	if (sc->rchan) {
590 		sc->rchan = 0;
591 		wakeup(&sc->rchan);
592 	}
593 
594 	/* locate the major number */
595 	for (maj = 0; maj < nchrdev; maj++) {
596 		if (cdevsw[maj].d_open == midiopen) {
597 			/* Nuke the vnodes for any open instances (calls close). */
598 			mn = self->dv_unit;
599 			vdevgone(maj, mn, mn, VCHR);
600 		}
601 	}
602 	return 0;
603 }
604 
605 
606 int
607 midiprint(void *aux, const char *pnp)
608 {
609 	if (pnp)
610 		printf("midi at %s", pnp);
611 	return (UNCONF);
612 }
613 
614 
615 void
616 midi_getinfo(dev_t dev, struct midi_info *mi)
617 {
618 	struct midi_softc *sc = MIDI_DEV2SC(dev);
619 
620 	if (MIDI_UNIT(dev) >= midi_cd.cd_ndevs || sc == NULL || sc->isdying) {
621 		mi->name = "unconfigured";
622 		mi->props = 0;
623 		return;
624 	}
625 	sc->hw_if->getinfo(sc->hw_hdl, mi);
626 }
627 
628 
629 struct device *
630 midi_attach_mi(struct midi_hw_if *hwif, void *hdl, struct device *dev)
631 {
632 	struct audio_attach_args arg;
633 
634 	arg.type = AUDIODEV_TYPE_MIDI;
635 	arg.hwif = hwif;
636 	arg.hdl = hdl;
637 	return config_found(dev, &arg, midiprint);
638 }
639 
640 
641 int
642 midi_unit_count(void)
643 {
644 	return midi_cd.cd_ndevs;
645 }
646 
647 
648 #if NSEQUENCER > 0
649 #define MIDI_EVLEN(status) 	(midi_evlen[((status) >> 4) & 7])
650 unsigned midi_evlen[] = { 2, 2, 2, 2, 1, 1, 2 };
651 
652 void
653 midi_toevent(struct midi_softc *sc, int data)
654 {
655 	unsigned char mesg[3];
656 
657 	if (data >= 0xf8) {		/* is it a realtime message ? */
658 		switch(data) {
659 		case 0xf8:		/* midi timer tic */
660 		case 0xfa:		/* midi timer start */
661 		case 0xfb:		/* midi timer continue (after stop) */
662 		case 0xfc:		/* midi timer stop */
663 			mesg[0] = data;
664 			midiseq_in(sc->seq_md, mesg, 1);
665 			break;
666 		default:
667 			break;
668 		}
669 	} else if (data >= 0x80) {	/* is it a common or voice message ? */
670 		sc->evstatus = data;
671 		sc->evindex = 0;
672 	} else {			/* else it is a data byte */
673 		/* strip common messages and bogus data */
674 		if (sc->evstatus >= 0xf0 || sc->evstatus < 0x80)
675 			return;
676 
677 		sc->evdata[sc->evindex++] = data;
678 		if (sc->evindex == MIDI_EVLEN(sc->evstatus)) {
679 			sc->evindex = 0;
680 			mesg[0] = sc->evstatus;
681 			mesg[1] = sc->evdata[0];
682 			mesg[2] = sc->evdata[1];
683 			midiseq_in(sc->seq_md, mesg, 1 + MIDI_EVLEN(sc->evstatus));
684 		}
685 	}
686 }
687 
688 
689 int
690 midi_writebytes(int unit, unsigned char *mesg, int mesglen)
691 {
692 	struct midi_softc  *sc = midi_cd.cd_devs[unit];
693 	struct midi_buffer *mb = &sc->outbuf;
694 	unsigned 	    count;
695 	int		    s;
696 
697 	s = splaudio();
698 	if (mesglen > MIDIBUF_AVAIL(mb)) {
699 		splx(s);
700 		return EWOULDBLOCK;
701 	}
702 
703 	while (mesglen > 0) {
704 		count = MIDIBUF_SIZE - MIDIBUF_END(mb);
705 		if (count > MIDIBUF_AVAIL(mb)) count = MIDIBUF_AVAIL(mb);
706 		if (count > mesglen) count = mesglen;
707 		bcopy(mesg, mb->data + MIDIBUF_END(mb), count);
708 		mb->used += count;
709 		mesg += count;
710 		mesglen -= count;
711 		midi_out_start(sc);
712 	}
713 	splx(s);
714 	return 0;
715 }
716 
717 #endif /* NSEQUENCER > 0 */
718