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