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