xref: /openbsd-src/sys/dev/midi.c (revision 5e3c7963eb248119b7dfd4b0defad58a7d9cd306)
1 /*	$OpenBSD: midi.c,v 1.43 2017/07/19 22:23:54 kettenis 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 #include <sys/param.h>
20 #include <sys/fcntl.h>
21 #include <sys/systm.h>
22 #include <sys/ioctl.h>
23 #include <sys/conf.h>
24 #include <sys/poll.h>
25 #include <sys/kernel.h>
26 #include <sys/timeout.h>
27 #include <sys/vnode.h>
28 #include <sys/signalvar.h>
29 #include <sys/device.h>
30 
31 #include <dev/midi_if.h>
32 #include <dev/audio_if.h>
33 #include <dev/midivar.h>
34 
35 
36 int	midiopen(dev_t, int, int, struct proc *);
37 int	midiclose(dev_t, int, int, struct proc *);
38 int	midiread(dev_t, struct uio *, int);
39 int	midiwrite(dev_t, struct uio *, int);
40 int	midipoll(dev_t, int, struct proc *);
41 int	midikqfilter(dev_t, struct knote *);
42 int	midiioctl(dev_t, u_long, caddr_t, int, struct proc *);
43 int	midiprobe(struct device *, void *, void *);
44 void	midiattach(struct device *, struct device *, void *);
45 int	mididetach(struct device *, int);
46 int	midiprint(void *, const char *);
47 
48 void	midi_iintr(void *, int);
49 void 	midi_ointr(void *);
50 void	midi_timeout(void *);
51 void	midi_out_start(struct midi_softc *);
52 void	midi_out_stop(struct midi_softc *);
53 void	midi_out_do(struct midi_softc *);
54 void	midi_attach(struct midi_softc *, struct device *);
55 
56 
57 struct cfattach midi_ca = {
58 	sizeof(struct midi_softc), midiprobe, midiattach, mididetach
59 };
60 
61 struct cfdriver midi_cd = {
62 	NULL, "midi", DV_DULL
63 };
64 
65 
66 void filt_midiwdetach(struct knote *);
67 int filt_midiwrite(struct knote *, long);
68 
69 struct filterops midiwrite_filtops = {
70 	1, NULL, filt_midiwdetach, filt_midiwrite
71 };
72 
73 void filt_midirdetach(struct knote *);
74 int filt_midiread(struct knote *, long);
75 
76 struct filterops midiread_filtops = {
77 	1, NULL, filt_midirdetach, filt_midiread
78 };
79 
80 void
81 midi_iintr(void *addr, int data)
82 {
83 	struct midi_softc  *sc = (struct midi_softc *)addr;
84 	struct midi_buffer *mb = &sc->inbuf;
85 
86 	MUTEX_ASSERT_LOCKED(&audio_lock);
87 	if (!(sc->dev.dv_flags & DVF_ACTIVE) || !(sc->flags & FREAD))
88 		return;
89 
90 	if (MIDIBUF_ISFULL(mb))
91 		return; /* discard data */
92 
93 	MIDIBUF_WRITE(mb, data);
94 	if (mb->used == 1) {
95 		if (sc->rchan) {
96 			sc->rchan = 0;
97 			wakeup(&sc->rchan);
98 		}
99 		selwakeup(&sc->rsel);
100 	}
101 }
102 
103 int
104 midiread(dev_t dev, struct uio *uio, int ioflag)
105 {
106 	struct midi_softc *sc;
107 	struct midi_buffer *mb;
108 	size_t count;
109 	int error;
110 
111 	sc = (struct midi_softc *)device_lookup(&midi_cd, minor(dev));
112 	if (sc == NULL)
113 		return ENXIO;
114 	if (!(sc->flags & FREAD)) {
115 		error = ENXIO;
116 		goto done;
117 	}
118 	mb = &sc->inbuf;
119 
120 	/* if there is no data then sleep (unless IO_NDELAY flag is set) */
121 	error = 0;
122 	mtx_enter(&audio_lock);
123 	while (MIDIBUF_ISEMPTY(mb)) {
124 		if (ioflag & IO_NDELAY) {
125 			error = EWOULDBLOCK;
126 			goto done_mtx;
127 		}
128 		sc->rchan = 1;
129 		error = msleep(&sc->rchan, &audio_lock, PWAIT | PCATCH, "mid_rd", 0);
130 		if (!(sc->dev.dv_flags & DVF_ACTIVE))
131 			error = EIO;
132 		if (error)
133 			goto done_mtx;
134 	}
135 
136 	/* at this stage, there is at least 1 byte */
137 
138 	while (uio->uio_resid > 0 && mb->used > 0) {
139 		count = MIDIBUF_SIZE - mb->start;
140 		if (count > mb->used)
141 			count = mb->used;
142 		if (count > uio->uio_resid)
143 			count = uio->uio_resid;
144 		mtx_leave(&audio_lock);
145 		error = uiomove(mb->data + mb->start, count, uio);
146 		if (error)
147 			goto done;
148 		mtx_enter(&audio_lock);
149 		MIDIBUF_REMOVE(mb, count);
150 	}
151 
152 done_mtx:
153 	mtx_leave(&audio_lock);
154 done:
155 	device_unref(&sc->dev);
156 	return error;
157 }
158 
159 void
160 midi_ointr(void *addr)
161 {
162 	struct midi_softc *sc = (struct midi_softc *)addr;
163 	struct midi_buffer *mb;
164 
165 	MUTEX_ASSERT_LOCKED(&audio_lock);
166 	if (!(sc->dev.dv_flags & DVF_ACTIVE) || !(sc->flags & FWRITE))
167 		return;
168 
169 	mb = &sc->outbuf;
170 	if (mb->used > 0) {
171 #ifdef MIDI_DEBUG
172 		if (!sc->isbusy) {
173 			printf("midi_ointr: output must be busy\n");
174 		}
175 #endif
176 		midi_out_do(sc);
177 	} else if (sc->isbusy)
178 		midi_out_stop(sc);
179 }
180 
181 void
182 midi_timeout(void *addr)
183 {
184 	mtx_enter(&audio_lock);
185 	midi_ointr(addr);
186 	mtx_leave(&audio_lock);
187 }
188 
189 void
190 midi_out_start(struct midi_softc *sc)
191 {
192 	if (!sc->isbusy) {
193 		sc->isbusy = 1;
194 		midi_out_do(sc);
195 	}
196 }
197 
198 void
199 midi_out_stop(struct midi_softc *sc)
200 {
201 	sc->isbusy = 0;
202 	if (sc->wchan) {
203 		sc->wchan = 0;
204 		wakeup(&sc->wchan);
205 	}
206 	selwakeup(&sc->wsel);
207 }
208 
209 void
210 midi_out_do(struct midi_softc *sc)
211 {
212 	struct midi_buffer *mb = &sc->outbuf;
213 
214 	while (mb->used > 0) {
215 		if (!sc->hw_if->output(sc->hw_hdl, mb->data[mb->start]))
216 			break;
217 		MIDIBUF_REMOVE(mb, 1);
218 		if (MIDIBUF_ISEMPTY(mb)) {
219 			if (sc->hw_if->flush != NULL)
220 				sc->hw_if->flush(sc->hw_hdl);
221 			midi_out_stop(sc);
222 			return;
223 		}
224 	}
225 
226 	if (!(sc->props & MIDI_PROP_OUT_INTR)) {
227 		if (MIDIBUF_ISEMPTY(mb))
228 			midi_out_stop(sc);
229 		else
230 			timeout_add(&sc->timeo, 1);
231 	}
232 }
233 
234 int
235 midiwrite(dev_t dev, struct uio *uio, int ioflag)
236 {
237 	struct midi_softc *sc;
238 	struct midi_buffer *mb;
239 	size_t count;
240 	int error;
241 
242 	sc = (struct midi_softc *)device_lookup(&midi_cd, minor(dev));
243 	if (sc == NULL)
244 		return ENXIO;
245 	if (!(sc->flags & FWRITE)) {
246 		error = ENXIO;
247 		goto done;
248 	}
249 	mb = &sc->outbuf;
250 
251 	/*
252 	 * If IO_NDELAY flag is set then check if there is enough room
253 	 * in the buffer to store at least one byte. If not then dont
254 	 * start the write process.
255 	 */
256 	error = 0;
257 	mtx_enter(&audio_lock);
258 	if ((ioflag & IO_NDELAY) && MIDIBUF_ISFULL(mb) && (uio->uio_resid > 0)) {
259 		error = EWOULDBLOCK;
260 		goto done_mtx;
261 	}
262 
263 	while (uio->uio_resid > 0) {
264 		while (MIDIBUF_ISFULL(mb)) {
265 			if (ioflag & IO_NDELAY) {
266 				/*
267 				 * At this stage at least one byte is already
268 				 * moved so we do not return EWOULDBLOCK
269 				 */
270 				goto done_mtx;
271 			}
272 			sc->wchan = 1;
273 			error = msleep(&sc->wchan, &audio_lock,
274 			    PWAIT | PCATCH, "mid_wr", 0);
275 			if (!(sc->dev.dv_flags & DVF_ACTIVE))
276 				error = EIO;
277 			if (error)
278 				goto done_mtx;
279 		}
280 
281 		count = MIDIBUF_SIZE - MIDIBUF_END(mb);
282 		if (count > MIDIBUF_AVAIL(mb))
283 			count = MIDIBUF_AVAIL(mb);
284 		if (count > uio->uio_resid)
285 			count = uio->uio_resid;
286 		mtx_leave(&audio_lock);
287 		error = uiomove(mb->data + MIDIBUF_END(mb), count, uio);
288 		if (error)
289 			goto done;
290 		mtx_enter(&audio_lock);
291 		mb->used += count;
292 		midi_out_start(sc);
293 	}
294 
295 done_mtx:
296 	mtx_leave(&audio_lock);
297 done:
298 	device_unref(&sc->dev);
299 	return error;
300 }
301 
302 int
303 midipoll(dev_t dev, int events, struct proc *p)
304 {
305 	struct midi_softc *sc;
306 	int revents;
307 
308 	sc = (struct midi_softc *)device_lookup(&midi_cd, minor(dev));
309 	if (sc == NULL)
310 		return POLLERR;
311 	revents = 0;
312 	mtx_enter(&audio_lock);
313 	if (events & (POLLIN | POLLRDNORM)) {
314 		if (!MIDIBUF_ISEMPTY(&sc->inbuf))
315 			revents |= events & (POLLIN | POLLRDNORM);
316 	}
317 	if (events & (POLLOUT | POLLWRNORM)) {
318 		if (!MIDIBUF_ISFULL(&sc->outbuf))
319 			revents |= events & (POLLOUT | POLLWRNORM);
320 	}
321 	if (revents == 0) {
322 		if (events & (POLLIN | POLLRDNORM))
323 			selrecord(p, &sc->rsel);
324 		if (events & (POLLOUT | POLLWRNORM))
325 			selrecord(p, &sc->wsel);
326 	}
327 	mtx_leave(&audio_lock);
328 	device_unref(&sc->dev);
329 	return (revents);
330 }
331 
332 int
333 midikqfilter(dev_t dev, struct knote *kn)
334 {
335 	struct midi_softc *sc;
336 	struct klist 	  *klist;
337 	int error;
338 
339 	sc = (struct midi_softc *)device_lookup(&midi_cd, minor(dev));
340 	if (sc == NULL)
341 		return ENXIO;
342 	error = 0;
343 	switch (kn->kn_filter) {
344 	case EVFILT_READ:
345 		klist = &sc->rsel.si_note;
346 		kn->kn_fop = &midiread_filtops;
347 		break;
348 	case EVFILT_WRITE:
349 		klist = &sc->wsel.si_note;
350 		kn->kn_fop = &midiwrite_filtops;
351 		break;
352 	default:
353 		error = EINVAL;
354 		goto done;
355 	}
356 	kn->kn_hook = (void *)sc;
357 
358 	mtx_enter(&audio_lock);
359 	SLIST_INSERT_HEAD(klist, kn, kn_selnext);
360 	mtx_leave(&audio_lock);
361 done:
362 	device_unref(&sc->dev);
363 	return error;
364 }
365 
366 void
367 filt_midirdetach(struct knote *kn)
368 {
369 	struct midi_softc *sc = (struct midi_softc *)kn->kn_hook;
370 
371 	mtx_enter(&audio_lock);
372 	SLIST_REMOVE(&sc->rsel.si_note, kn, knote, kn_selnext);
373 	mtx_leave(&audio_lock);
374 }
375 
376 int
377 filt_midiread(struct knote *kn, long hint)
378 {
379 	struct midi_softc *sc = (struct midi_softc *)kn->kn_hook;
380 	int retval;
381 
382 	mtx_enter(&audio_lock);
383 	retval = !MIDIBUF_ISEMPTY(&sc->inbuf);
384 	mtx_leave(&audio_lock);
385 
386 	return (retval);
387 }
388 
389 void
390 filt_midiwdetach(struct knote *kn)
391 {
392 	struct midi_softc *sc = (struct midi_softc *)kn->kn_hook;
393 
394 	mtx_enter(&audio_lock);
395 	SLIST_REMOVE(&sc->wsel.si_note, kn, knote, kn_selnext);
396 	mtx_leave(&audio_lock);
397 }
398 
399 int
400 filt_midiwrite(struct knote *kn, long hint)
401 {
402 	struct midi_softc *sc = (struct midi_softc *)kn->kn_hook;
403 	int		   retval;
404 
405 	mtx_enter(&audio_lock);
406 	retval = !MIDIBUF_ISFULL(&sc->outbuf);
407 	mtx_leave(&audio_lock);
408 
409 	return (retval);
410 }
411 
412 int
413 midiioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p)
414 {
415 	struct midi_softc *sc;
416 	int error;
417 
418 	sc = (struct midi_softc *)device_lookup(&midi_cd, minor(dev));
419 	if (sc == NULL)
420 		return ENXIO;
421 	error = 0;
422 	switch(cmd) {
423 	case FIONBIO:
424 		/* All handled in the upper FS layer */
425 		break;
426 	default:
427 		error = ENOTTY;
428 	}
429 	device_unref(&sc->dev);
430 	return error;
431 }
432 
433 int
434 midiopen(dev_t dev, int flags, int mode, struct proc *p)
435 {
436 	struct midi_softc *sc;
437 	int error;
438 
439 	sc = (struct midi_softc *)device_lookup(&midi_cd, minor(dev));
440 	if (sc == NULL)
441 		return ENXIO;
442 	error = 0;
443 	if (sc->flags) {
444 		error = EBUSY;
445 		goto done;
446 	}
447 	MIDIBUF_INIT(&sc->inbuf);
448 	MIDIBUF_INIT(&sc->outbuf);
449 	sc->isbusy = 0;
450 	sc->rchan = sc->wchan = 0;
451 	sc->flags = flags;
452 	error = sc->hw_if->open(sc->hw_hdl, flags, midi_iintr, midi_ointr, sc);
453 	if (error)
454 		sc->flags = 0;
455 done:
456 	device_unref(&sc->dev);
457 	return error;
458 }
459 
460 int
461 midiclose(dev_t dev, int fflag, int devtype, struct proc *p)
462 {
463 	struct midi_softc *sc;
464 	struct midi_buffer *mb;
465 	int error;
466 
467 	sc = (struct midi_softc *)device_lookup(&midi_cd, minor(dev));
468 	if (sc == NULL)
469 		return ENXIO;
470 
471 	/* start draining output buffer */
472 	error = 0;
473 	mb = &sc->outbuf;
474 	mtx_enter(&audio_lock);
475 	if (!MIDIBUF_ISEMPTY(mb))
476 		midi_out_start(sc);
477 	while (sc->isbusy) {
478 		sc->wchan = 1;
479 		error = msleep(&sc->wchan, &audio_lock,
480 		    PWAIT, "mid_dr", 5 * hz);
481 		if (!(sc->dev.dv_flags & DVF_ACTIVE))
482 			error = EIO;
483 		if (error)
484 			break;
485 	}
486 	mtx_leave(&audio_lock);
487 
488 	/*
489 	 * some hw_if->close() reset immediately the midi uart
490 	 * which flushes the internal buffer of the uart device,
491 	 * so we may lose some (important) data. To avoid this,
492 	 * sleep 20ms (around 64 bytes) to give the time to the
493 	 * uart to drain its internal buffers.
494 	 */
495 	tsleep(&sc->wchan, PWAIT, "mid_cl", hz * MIDI_MAXWRITE / MIDI_RATE);
496 	sc->hw_if->close(sc->hw_hdl);
497 	sc->flags = 0;
498 	device_unref(&sc->dev);
499 	return 0;
500 }
501 
502 int
503 midiprobe(struct device *parent, void *match, void *aux)
504 {
505 	struct audio_attach_args *sa = aux;
506 
507 	return (sa != NULL && (sa->type == AUDIODEV_TYPE_MIDI) ? 1 : 0);
508 }
509 
510 void
511 midiattach(struct device *parent, struct device *self, void *aux)
512 {
513 	struct midi_info	  mi;
514 	struct midi_softc        *sc = (struct midi_softc *)self;
515 	struct audio_attach_args *sa = (struct audio_attach_args *)aux;
516 	struct midi_hw_if        *hwif = sa->hwif;
517 	void  			 *hdl = sa->hdl;
518 
519 #ifdef DIAGNOSTIC
520 	if (hwif == 0 ||
521 	    hwif->open == 0 ||
522 	    hwif->close == 0 ||
523 	    hwif->output == 0 ||
524 	    hwif->getinfo == 0) {
525 		printf("midi: missing method\n");
526 		return;
527 	}
528 #endif
529 	sc->hw_if = hwif;
530 	sc->hw_hdl = hdl;
531 	sc->hw_if->getinfo(sc->hw_hdl, &mi);
532 	sc->props = mi.props;
533 	sc->flags = 0;
534 	timeout_set(&sc->timeo, midi_timeout, sc);
535 	printf(": <%s>\n", mi.name);
536 }
537 
538 int
539 mididetach(struct device *self, int flags)
540 {
541 	struct midi_softc *sc = (struct midi_softc *)self;
542 	int maj, mn;
543 
544 	/* locate the major number */
545 	for (maj = 0; maj < nchrdev; maj++) {
546 		if (cdevsw[maj].d_open == midiopen) {
547 			/* Nuke the vnodes for any open instances (calls close). */
548 			mn = self->dv_unit;
549 			vdevgone(maj, mn, mn, VCHR);
550 		}
551 	}
552 
553 	/*
554 	 * The close() method did nothing (device_lookup() returns
555 	 * NULL), so quickly halt transfers (normally parent is already
556 	 * gone, and code below is no-op), and wake-up user-land blocked
557 	 * in read/write/ioctl, which return EIO.
558 	 */
559 	if (sc->flags) {
560 		if (sc->flags & FREAD) {
561 			sc->rchan = 0;
562 			wakeup(&sc->rchan);
563 			selwakeup(&sc->rsel);
564 		}
565 		if (sc->flags & FWRITE) {
566 			sc->wchan = 0;
567 			wakeup(&sc->wchan);
568 			selwakeup(&sc->wsel);
569 		}
570 		sc->hw_if->close(sc->hw_hdl);
571 		sc->flags = 0;
572 	}
573 	return 0;
574 }
575 
576 int
577 midiprint(void *aux, const char *pnp)
578 {
579 	if (pnp)
580 		printf("midi at %s", pnp);
581 	return (UNCONF);
582 }
583 
584 struct device *
585 midi_attach_mi(struct midi_hw_if *hwif, void *hdl, struct device *dev)
586 {
587 	struct audio_attach_args arg;
588 
589 	arg.type = AUDIODEV_TYPE_MIDI;
590 	arg.hwif = hwif;
591 	arg.hdl = hdl;
592 	return config_found(dev, &arg, midiprint);
593 }
594