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