xref: /freebsd/sys/dev/sound/midi/midi.c (revision 9a138abb21e17cabb8823f2cefab983d2926d82b)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause
3  *
4  * Copyright (c) 2003 Mathew Kanner
5  * Copyright (c) 1998 The NetBSD Foundation, Inc.
6  * All rights reserved.
7  *
8  * This code is derived from software contributed to The NetBSD Foundation
9  * by Lennart Augustsson (augustss@netbsd.org).
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in the
18  *    documentation and/or other materials provided with the distribution.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
21  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
24  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30  * POSSIBILITY OF SUCH DAMAGE.
31  */
32 
33 #include <sys/param.h>
34 #include <sys/systm.h>
35 #include <sys/queue.h>
36 #include <sys/kernel.h>
37 #include <sys/lock.h>
38 #include <sys/mutex.h>
39 #include <sys/proc.h>
40 #include <sys/signalvar.h>
41 #include <sys/conf.h>
42 #include <sys/selinfo.h>
43 #include <sys/sysctl.h>
44 #include <sys/malloc.h>
45 #include <sys/sx.h>
46 #include <sys/proc.h>
47 #include <sys/fcntl.h>
48 #include <sys/types.h>
49 #include <sys/uio.h>
50 #include <sys/poll.h>
51 #include <sys/sbuf.h>
52 #include <sys/kobj.h>
53 #include <sys/module.h>
54 
55 #ifdef HAVE_KERNEL_OPTION_HEADERS
56 #include "opt_snd.h"
57 #endif
58 
59 #include <dev/sound/midi/midi.h>
60 #include "mpu_if.h"
61 
62 #include <dev/sound/midi/midiq.h>
63 MALLOC_DEFINE(M_MIDI, "midi buffers", "Midi data allocation area");
64 
65 #ifndef KOBJMETHOD_END
66 #define KOBJMETHOD_END	{ NULL, NULL }
67 #endif
68 
69 #define MIDI_DEV_MIDICTL 12
70 
71 enum midi_states {
72 	MIDI_IN_START, MIDI_IN_SYSEX, MIDI_IN_DATA
73 };
74 
75 #define MIDI_NAMELEN   16
76 struct snd_midi {
77 	KOBJ_FIELDS;
78 	struct mtx lock;		/* Protects all but queues */
79 	void   *cookie;
80 
81 	int	unit;			/* Should only be used in midistat */
82 	int	channel;		/* Should only be used in midistat */
83 
84 	int	busy;
85 	int	flags;			/* File flags */
86 	char	name[MIDI_NAMELEN];
87 	struct mtx qlock;		/* Protects inq, outq and flags */
88 	MIDIQ_HEAD(, char) inq, outq;
89 	int	rchan, wchan;
90 	struct selinfo rsel, wsel;
91 	int	hiwat;			/* QLEN(outq)>High-water -> disable
92 					 * writes from userland */
93 	enum midi_states inq_state;
94 	int	inq_status, inq_left;	/* Variables for the state machine in
95 					 * Midi_in, this is to provide that
96 					 * signals only get issued only
97 					 * complete command packets. */
98 	struct proc *async;
99 	struct cdev *dev;
100 	TAILQ_ENTRY(snd_midi) link;
101 };
102 
103 TAILQ_HEAD(, snd_midi) midi_devs;
104 
105 struct sx mstat_lock;
106 
107 static d_open_t midi_open;
108 static d_close_t midi_close;
109 static d_ioctl_t midi_ioctl;
110 static d_read_t midi_read;
111 static d_write_t midi_write;
112 static d_poll_t midi_poll;
113 
114 static struct cdevsw midi_cdevsw = {
115 	.d_version = D_VERSION,
116 	.d_open = midi_open,
117 	.d_close = midi_close,
118 	.d_read = midi_read,
119 	.d_write = midi_write,
120 	.d_ioctl = midi_ioctl,
121 	.d_poll = midi_poll,
122 	.d_name = "rmidi",
123 };
124 
125 static int      midi_destroy(struct snd_midi *, int);
126 static int      midi_load(void);
127 static int      midi_unload(void);
128 
129 SYSCTL_NODE(_hw, OID_AUTO, midi, CTLFLAG_RD | CTLFLAG_MPSAFE, 0,
130     "Midi driver");
131 
132 int             midi_debug;
133 /* XXX: should this be moved into debug.midi? */
134 SYSCTL_INT(_hw_midi, OID_AUTO, debug, CTLFLAG_RW, &midi_debug, 0, "");
135 
136 #define MIDI_DEBUG(l,a)	if(midi_debug>=l) a
137 
138 void
midistat_lock(void)139 midistat_lock(void)
140 {
141 	sx_xlock(&mstat_lock);
142 }
143 
144 void
midistat_unlock(void)145 midistat_unlock(void)
146 {
147 	sx_xunlock(&mstat_lock);
148 }
149 
150 void
midistat_lockassert(void)151 midistat_lockassert(void)
152 {
153 	sx_assert(&mstat_lock, SA_XLOCKED);
154 }
155 
156 /*
157  * Register a new rmidi device. cls midi_if interface unit == 0 means
158  * auto-assign new unit number unit != 0 already assigned a unit number, eg.
159  * not the first channel provided by this device. channel,	sub-unit
160  * cookie is passed back on MPU calls Typical device drivers will call with
161  * unit=0, channel=1..(number of channels) and cookie=soft_c and won't care
162  * what unit number is used.
163  *
164  * It is an error to call midi_init with an already used unit/channel combo.
165  */
166 struct snd_midi *
midi_init(kobj_class_t cls,int unit,int channel,void * cookie)167 midi_init(kobj_class_t cls, int unit, int channel, void *cookie)
168 {
169 	struct snd_midi *m;
170 	int i;
171 	int inqsize, outqsize;
172 	uint8_t *buf;
173 
174 	MIDI_DEBUG(1, printf("midiinit: unit %d/%d.\n", unit, channel));
175 	midistat_lock();
176 	/*
177 	 * Protect against call with existing unit/channel or auto-allocate a
178 	 * new unit number.
179 	 */
180 	i = -1;
181 	TAILQ_FOREACH(m, &midi_devs, link) {
182 		mtx_lock(&m->lock);
183 		if (unit != 0) {
184 			if (m->unit == unit && m->channel == channel) {
185 				mtx_unlock(&m->lock);
186 				goto err0;
187 			}
188 		} else {
189 			/*
190 			 * Find a better unit number
191 			 */
192 			if (m->unit > i)
193 				i = m->unit;
194 		}
195 		mtx_unlock(&m->lock);
196 	}
197 
198 	if (unit == 0)
199 		unit = i + 1;
200 
201 	MIDI_DEBUG(1, printf("midiinit #2: unit %d/%d.\n", unit, channel));
202 	m = malloc(sizeof(*m), M_MIDI, M_WAITOK | M_ZERO);
203 	kobj_init((kobj_t)m, cls);
204 	inqsize = MPU_INQSIZE(m, cookie);
205 	outqsize = MPU_OUTQSIZE(m, cookie);
206 
207 	MIDI_DEBUG(1, printf("midiinit queues %d/%d.\n", inqsize, outqsize));
208 	if (!inqsize && !outqsize)
209 		goto err1;
210 
211 	mtx_init(&m->lock, "raw midi", NULL, 0);
212 	mtx_init(&m->qlock, "q raw midi", NULL, 0);
213 
214 	mtx_lock(&m->lock);
215 	mtx_lock(&m->qlock);
216 
217 	if (inqsize)
218 		buf = malloc(sizeof(uint8_t) * inqsize, M_MIDI, M_NOWAIT);
219 	else
220 		buf = NULL;
221 
222 	MIDIQ_INIT(m->inq, buf, inqsize);
223 
224 	if (outqsize)
225 		buf = malloc(sizeof(uint8_t) * outqsize, M_MIDI, M_NOWAIT);
226 	else
227 		buf = NULL;
228 	m->hiwat = outqsize / 2;
229 
230 	MIDIQ_INIT(m->outq, buf, outqsize);
231 
232 	if ((inqsize && !MIDIQ_BUF(m->inq)) ||
233 	    (outqsize && !MIDIQ_BUF(m->outq)))
234 		goto err2;
235 
236 	m->busy = 0;
237 	m->flags = 0;
238 	m->unit = unit;
239 	m->channel = channel;
240 	m->cookie = cookie;
241 
242 	if (MPU_INIT(m, cookie))
243 		goto err2;
244 
245 	mtx_unlock(&m->lock);
246 	mtx_unlock(&m->qlock);
247 
248 	TAILQ_INSERT_TAIL(&midi_devs, m, link);
249 
250 	midistat_unlock();
251 
252 	m->dev = make_dev(&midi_cdevsw, unit, UID_ROOT, GID_WHEEL, 0666,
253 	    "midi%d.%d", unit, channel);
254 	m->dev->si_drv1 = m;
255 
256 	return m;
257 
258 err2:
259 	mtx_destroy(&m->qlock);
260 	mtx_destroy(&m->lock);
261 
262 	if (MIDIQ_BUF(m->inq))
263 		free(MIDIQ_BUF(m->inq), M_MIDI);
264 	if (MIDIQ_BUF(m->outq))
265 		free(MIDIQ_BUF(m->outq), M_MIDI);
266 err1:
267 	free(m, M_MIDI);
268 err0:
269 	midistat_unlock();
270 	MIDI_DEBUG(1, printf("midi_init ended in error\n"));
271 	return NULL;
272 }
273 
274 /*
275  * midi_uninit does not call MIDI_UNINIT, as since this is the implementors
276  * entry point. midi_uninit if fact, does not send any methods. A call to
277  * midi_uninit is a defacto promise that you won't manipulate ch anymore
278  */
279 int
midi_uninit(struct snd_midi * m)280 midi_uninit(struct snd_midi *m)
281 {
282 	int err;
283 
284 	err = EBUSY;
285 	midistat_lock();
286 	mtx_lock(&m->lock);
287 	if (m->busy) {
288 		if (!(m->rchan || m->wchan))
289 			goto err;
290 
291 		if (m->rchan) {
292 			wakeup(&m->rchan);
293 			m->rchan = 0;
294 		}
295 		if (m->wchan) {
296 			wakeup(&m->wchan);
297 			m->wchan = 0;
298 		}
299 	}
300 	err = midi_destroy(m, 0);
301 	if (!err)
302 		goto exit;
303 
304 err:
305 	mtx_unlock(&m->lock);
306 exit:
307 	midistat_unlock();
308 	return err;
309 }
310 
311 #ifdef notdef
312 static int midi_lengths[] = {2, 2, 2, 2, 1, 1, 2, 0};
313 
314 #endif					/* notdef */
315 /* Number of bytes in a MIDI command */
316 #define MIDI_LENGTH(d) (midi_lengths[((d) >> 4) & 7])
317 #define MIDI_ACK	0xfe
318 #define MIDI_IS_STATUS(d) ((d) >= 0x80)
319 #define MIDI_IS_COMMON(d) ((d) >= 0xf0)
320 
321 #define MIDI_SYSEX_START	0xF0
322 #define MIDI_SYSEX_END	    0xF7
323 
324 /*
325  * midi_in: process all data until the queue is full, then discards the rest.
326  * Since midi_in is a state machine, data discards can cause it to get out of
327  * whack.  Process as much as possible.  It calls, wakeup, selnotify and
328  * psignal at most once.
329  */
330 int
midi_in(struct snd_midi * m,uint8_t * buf,int size)331 midi_in(struct snd_midi *m, uint8_t *buf, int size)
332 {
333 	/* int             i, sig, enq; */
334 	int used;
335 
336 	/* uint8_t       data; */
337 	MIDI_DEBUG(5, printf("midi_in: m=%p size=%d\n", m, size));
338 
339 /*
340  * XXX: locking flub
341  */
342 	if (!(m->flags & M_RX))
343 		return size;
344 
345 	used = 0;
346 
347 	mtx_lock(&m->qlock);
348 #if 0
349 	/*
350 	 * Don't bother queuing if not in read mode.  Discard everything and
351 	 * return size so the caller doesn't freak out.
352 	 */
353 
354 	if (!(m->flags & M_RX))
355 		return size;
356 
357 	for (i = sig = 0; i < size; i++) {
358 		data = buf[i];
359 		enq = 0;
360 		if (data == MIDI_ACK)
361 			continue;
362 
363 		switch (m->inq_state) {
364 		case MIDI_IN_START:
365 			if (MIDI_IS_STATUS(data)) {
366 				switch (data) {
367 				case 0xf0:	/* Sysex */
368 					m->inq_state = MIDI_IN_SYSEX;
369 					break;
370 				case 0xf1:	/* MTC quarter frame */
371 				case 0xf3:	/* Song select */
372 					m->inq_state = MIDI_IN_DATA;
373 					enq = 1;
374 					m->inq_left = 1;
375 					break;
376 				case 0xf2:	/* Song position pointer */
377 					m->inq_state = MIDI_IN_DATA;
378 					enq = 1;
379 					m->inq_left = 2;
380 					break;
381 				default:
382 					if (MIDI_IS_COMMON(data)) {
383 						enq = 1;
384 						sig = 1;
385 					} else {
386 						m->inq_state = MIDI_IN_DATA;
387 						enq = 1;
388 						m->inq_status = data;
389 						m->inq_left = MIDI_LENGTH(data);
390 					}
391 					break;
392 				}
393 			} else if (MIDI_IS_STATUS(m->inq_status)) {
394 				m->inq_state = MIDI_IN_DATA;
395 				if (!MIDIQ_FULL(m->inq)) {
396 					used++;
397 					MIDIQ_ENQ(m->inq, &m->inq_status, 1);
398 				}
399 				enq = 1;
400 				m->inq_left = MIDI_LENGTH(m->inq_status) - 1;
401 			}
402 			break;
403 			/*
404 			 * End of case MIDI_IN_START:
405 			 */
406 
407 		case MIDI_IN_DATA:
408 			enq = 1;
409 			if (--m->inq_left <= 0)
410 				sig = 1;/* deliver data */
411 			break;
412 		case MIDI_IN_SYSEX:
413 			if (data == MIDI_SYSEX_END)
414 				m->inq_state = MIDI_IN_START;
415 			break;
416 		}
417 
418 		if (enq)
419 			if (!MIDIQ_FULL(m->inq)) {
420 				MIDIQ_ENQ(m->inq, &data, 1);
421 				used++;
422 			}
423 		/*
424 	         * End of the state machines main "for loop"
425 	         */
426 	}
427 	if (sig) {
428 #endif
429 		MIDI_DEBUG(6, printf("midi_in: len %jd avail %jd\n",
430 		    (intmax_t)MIDIQ_LEN(m->inq),
431 		    (intmax_t)MIDIQ_AVAIL(m->inq)));
432 		if (MIDIQ_AVAIL(m->inq) > size) {
433 			used = size;
434 			MIDIQ_ENQ(m->inq, buf, size);
435 		} else {
436 			MIDI_DEBUG(4, printf("midi_in: Discarding data qu\n"));
437 			mtx_unlock(&m->qlock);
438 			return 0;
439 		}
440 		if (m->rchan) {
441 			wakeup(&m->rchan);
442 			m->rchan = 0;
443 		}
444 		selwakeup(&m->rsel);
445 		if (m->async) {
446 			PROC_LOCK(m->async);
447 			kern_psignal(m->async, SIGIO);
448 			PROC_UNLOCK(m->async);
449 		}
450 #if 0
451 	}
452 #endif
453 	mtx_unlock(&m->qlock);
454 	return used;
455 }
456 
457 /*
458  * midi_out: The only clearer of the M_TXEN flag.
459  */
460 int
midi_out(struct snd_midi * m,uint8_t * buf,int size)461 midi_out(struct snd_midi *m, uint8_t *buf, int size)
462 {
463 	int used;
464 
465 /*
466  * XXX: locking flub
467  */
468 	if (!(m->flags & M_TXEN))
469 		return 0;
470 
471 	MIDI_DEBUG(2, printf("midi_out: %p\n", m));
472 	mtx_lock(&m->qlock);
473 	used = MIN(size, MIDIQ_LEN(m->outq));
474 	MIDI_DEBUG(3, printf("midi_out: used %d\n", used));
475 	if (used)
476 		MIDIQ_DEQ(m->outq, buf, used);
477 	if (MIDIQ_EMPTY(m->outq)) {
478 		m->flags &= ~M_TXEN;
479 		MPU_CALLBACKP(m, m->cookie, m->flags);
480 	}
481 	if (used && MIDIQ_AVAIL(m->outq) > m->hiwat) {
482 		if (m->wchan) {
483 			wakeup(&m->wchan);
484 			m->wchan = 0;
485 		}
486 		selwakeup(&m->wsel);
487 		if (m->async) {
488 			PROC_LOCK(m->async);
489 			kern_psignal(m->async, SIGIO);
490 			PROC_UNLOCK(m->async);
491 		}
492 	}
493 	mtx_unlock(&m->qlock);
494 	return used;
495 }
496 
497 int
midi_open(struct cdev * i_dev,int flags,int mode,struct thread * td)498 midi_open(struct cdev *i_dev, int flags, int mode, struct thread *td)
499 {
500 	struct snd_midi *m = i_dev->si_drv1;
501 	int retval;
502 
503 	MIDI_DEBUG(1, printf("midiopen %p %s %s\n", td,
504 	    flags & FREAD ? "M_RX" : "", flags & FWRITE ? "M_TX" : ""));
505 	if (m == NULL)
506 		return ENXIO;
507 
508 	mtx_lock(&m->lock);
509 	mtx_lock(&m->qlock);
510 
511 	retval = 0;
512 
513 	if (flags & FREAD) {
514 		if (MIDIQ_SIZE(m->inq) == 0)
515 			retval = ENXIO;
516 		else if (m->flags & M_RX)
517 			retval = EBUSY;
518 		if (retval)
519 			goto err;
520 	}
521 	if (flags & FWRITE) {
522 		if (MIDIQ_SIZE(m->outq) == 0)
523 			retval = ENXIO;
524 		else if (m->flags & M_TX)
525 			retval = EBUSY;
526 		if (retval)
527 			goto err;
528 	}
529 	m->busy++;
530 
531 	m->rchan = 0;
532 	m->wchan = 0;
533 	m->async = 0;
534 
535 	if (flags & FREAD) {
536 		m->flags |= M_RX | M_RXEN;
537 		/*
538 	         * Only clear the inq, the outq might still have data to drain
539 	         * from a previous session
540 	         */
541 		MIDIQ_CLEAR(m->inq);
542 	}
543 
544 	if (flags & FWRITE)
545 		m->flags |= M_TX;
546 
547 	MPU_CALLBACK(m, m->cookie, m->flags);
548 
549 	MIDI_DEBUG(2, printf("midi_open: opened.\n"));
550 
551 err:	mtx_unlock(&m->qlock);
552 	mtx_unlock(&m->lock);
553 	return retval;
554 }
555 
556 int
midi_close(struct cdev * i_dev,int flags,int mode,struct thread * td)557 midi_close(struct cdev *i_dev, int flags, int mode, struct thread *td)
558 {
559 	struct snd_midi *m = i_dev->si_drv1;
560 	int retval;
561 	int oldflags;
562 
563 	MIDI_DEBUG(1, printf("midi_close %p %s %s\n", td,
564 	    flags & FREAD ? "M_RX" : "", flags & FWRITE ? "M_TX" : ""));
565 
566 	if (m == NULL)
567 		return ENXIO;
568 
569 	mtx_lock(&m->lock);
570 	mtx_lock(&m->qlock);
571 
572 	if ((flags & FREAD && !(m->flags & M_RX)) ||
573 	    (flags & FWRITE && !(m->flags & M_TX))) {
574 		retval = ENXIO;
575 		goto err;
576 	}
577 	m->busy--;
578 
579 	oldflags = m->flags;
580 
581 	if (flags & FREAD)
582 		m->flags &= ~(M_RX | M_RXEN);
583 	if (flags & FWRITE)
584 		m->flags &= ~M_TX;
585 
586 	if ((m->flags & (M_TXEN | M_RXEN)) != (oldflags & (M_RXEN | M_TXEN)))
587 		MPU_CALLBACK(m, m->cookie, m->flags);
588 
589 	MIDI_DEBUG(1, printf("midi_close: closed, busy = %d.\n", m->busy));
590 
591 	mtx_unlock(&m->qlock);
592 	mtx_unlock(&m->lock);
593 	retval = 0;
594 err:	return retval;
595 }
596 
597 /*
598  * TODO: midi_read, per oss programmer's guide pg. 42 should return as soon
599  * as data is available.
600  */
601 int
midi_read(struct cdev * i_dev,struct uio * uio,int ioflag)602 midi_read(struct cdev *i_dev, struct uio *uio, int ioflag)
603 {
604 #define MIDI_RSIZE 32
605 	struct snd_midi *m = i_dev->si_drv1;
606 	int retval;
607 	int used;
608 	char buf[MIDI_RSIZE];
609 
610 	MIDI_DEBUG(5, printf("midiread: count=%lu\n",
611 	    (unsigned long)uio->uio_resid));
612 
613 	retval = EIO;
614 
615 	if (m == NULL)
616 		goto err0;
617 
618 	mtx_lock(&m->lock);
619 	mtx_lock(&m->qlock);
620 
621 	if (!(m->flags & M_RX))
622 		goto err1;
623 
624 	while (uio->uio_resid > 0) {
625 		while (MIDIQ_EMPTY(m->inq)) {
626 			retval = EWOULDBLOCK;
627 			if (ioflag & O_NONBLOCK)
628 				goto err1;
629 			mtx_unlock(&m->lock);
630 			m->rchan = 1;
631 			retval = msleep(&m->rchan, &m->qlock,
632 			    PCATCH | PDROP, "midi RX", 0);
633 			/*
634 			 * We slept, maybe things have changed since last
635 			 * dying check
636 			 */
637 			if (retval == EINTR)
638 				goto err0;
639 			if (m != i_dev->si_drv1)
640 				retval = ENXIO;
641 			/* if (retval && retval != ERESTART) */
642 			if (retval)
643 				goto err0;
644 			mtx_lock(&m->lock);
645 			mtx_lock(&m->qlock);
646 			m->rchan = 0;
647 			if (!m->busy)
648 				goto err1;
649 		}
650 		MIDI_DEBUG(6, printf("midi_read start\n"));
651 		/*
652 	         * At this point, it is certain that m->inq has data
653 	         */
654 
655 		used = MIN(MIDIQ_LEN(m->inq), uio->uio_resid);
656 		used = MIN(used, MIDI_RSIZE);
657 
658 		MIDI_DEBUG(6, printf("midiread: uiomove cc=%d\n", used));
659 		MIDIQ_DEQ(m->inq, buf, used);
660 		retval = uiomove(buf, used, uio);
661 		if (retval)
662 			goto err1;
663 	}
664 
665 	/*
666 	 * If we Made it here then transfer is good
667 	 */
668 	retval = 0;
669 err1:	mtx_unlock(&m->qlock);
670 	mtx_unlock(&m->lock);
671 err0:	MIDI_DEBUG(4, printf("midi_read: ret %d\n", retval));
672 	return retval;
673 }
674 
675 /*
676  * midi_write: The only setter of M_TXEN
677  */
678 
679 int
midi_write(struct cdev * i_dev,struct uio * uio,int ioflag)680 midi_write(struct cdev *i_dev, struct uio *uio, int ioflag)
681 {
682 #define MIDI_WSIZE 32
683 	struct snd_midi *m = i_dev->si_drv1;
684 	int retval;
685 	int used;
686 	char buf[MIDI_WSIZE];
687 
688 	MIDI_DEBUG(4, printf("midi_write\n"));
689 	retval = 0;
690 	if (m == NULL)
691 		goto err0;
692 
693 	mtx_lock(&m->lock);
694 	mtx_lock(&m->qlock);
695 
696 	if (!(m->flags & M_TX))
697 		goto err1;
698 
699 	while (uio->uio_resid > 0) {
700 		while (MIDIQ_AVAIL(m->outq) == 0) {
701 			retval = EWOULDBLOCK;
702 			if (ioflag & O_NONBLOCK)
703 				goto err1;
704 			mtx_unlock(&m->lock);
705 			m->wchan = 1;
706 			MIDI_DEBUG(3, printf("midi_write msleep\n"));
707 			retval = msleep(&m->wchan, &m->qlock,
708 			    PCATCH | PDROP, "midi TX", 0);
709 			/*
710 			 * We slept, maybe things have changed since last
711 			 * dying check
712 			 */
713 			if (retval == EINTR)
714 				goto err0;
715 			if (m != i_dev->si_drv1)
716 				retval = ENXIO;
717 			if (retval)
718 				goto err0;
719 			mtx_lock(&m->lock);
720 			mtx_lock(&m->qlock);
721 			m->wchan = 0;
722 			if (!m->busy)
723 				goto err1;
724 		}
725 
726 		/*
727 	         * We are certain than data can be placed on the queue
728 	         */
729 
730 		used = MIN(MIDIQ_AVAIL(m->outq), uio->uio_resid);
731 		used = MIN(used, MIDI_WSIZE);
732 		MIDI_DEBUG(5, printf("midiout: resid %zd len %jd avail %jd\n",
733 		    uio->uio_resid, (intmax_t)MIDIQ_LEN(m->outq),
734 		    (intmax_t)MIDIQ_AVAIL(m->outq)));
735 
736 		MIDI_DEBUG(5, printf("midi_write: uiomove cc=%d\n", used));
737 		retval = uiomove(buf, used, uio);
738 		if (retval)
739 			goto err1;
740 		MIDIQ_ENQ(m->outq, buf, used);
741 		/*
742 	         * Inform the bottom half that data can be written
743 	         */
744 		if (!(m->flags & M_TXEN)) {
745 			m->flags |= M_TXEN;
746 			MPU_CALLBACK(m, m->cookie, m->flags);
747 		}
748 	}
749 	/*
750 	 * If we Made it here then transfer is good
751 	 */
752 	retval = 0;
753 err1:	mtx_unlock(&m->qlock);
754 	mtx_unlock(&m->lock);
755 err0:	return retval;
756 }
757 
758 int
midi_ioctl(struct cdev * i_dev,u_long cmd,caddr_t arg,int mode,struct thread * td)759 midi_ioctl(struct cdev *i_dev, u_long cmd, caddr_t arg, int mode,
760     struct thread *td)
761 {
762 	return ENXIO;
763 }
764 
765 int
midi_poll(struct cdev * i_dev,int events,struct thread * td)766 midi_poll(struct cdev *i_dev, int events, struct thread *td)
767 {
768 	struct snd_midi *m = i_dev->si_drv1;
769 	int revents;
770 
771 	if (m == NULL)
772 		return 0;
773 
774 	revents = 0;
775 
776 	mtx_lock(&m->lock);
777 	mtx_lock(&m->qlock);
778 
779 	if (events & (POLLIN | POLLRDNORM))
780 		if (!MIDIQ_EMPTY(m->inq))
781 			events |= events & (POLLIN | POLLRDNORM);
782 
783 	if (events & (POLLOUT | POLLWRNORM))
784 		if (MIDIQ_AVAIL(m->outq) < m->hiwat)
785 			events |= events & (POLLOUT | POLLWRNORM);
786 
787 	if (revents == 0) {
788 		if (events & (POLLIN | POLLRDNORM))
789 			selrecord(td, &m->rsel);
790 
791 		if (events & (POLLOUT | POLLWRNORM))
792 			selrecord(td, &m->wsel);
793 	}
794 	mtx_unlock(&m->lock);
795 	mtx_unlock(&m->qlock);
796 
797 	return (revents);
798 }
799 
800 /*
801  * Single point of midi destructions.
802  */
803 static int
midi_destroy(struct snd_midi * m,int midiuninit)804 midi_destroy(struct snd_midi *m, int midiuninit)
805 {
806 	midistat_lockassert();
807 	mtx_assert(&m->lock, MA_OWNED);
808 
809 	MIDI_DEBUG(3, printf("midi_destroy\n"));
810 	m->dev->si_drv1 = NULL;
811 	mtx_unlock(&m->lock);	/* XXX */
812 	destroy_dev(m->dev);
813 	TAILQ_REMOVE(&midi_devs, m, link);
814 	if (midiuninit)
815 		MPU_UNINIT(m, m->cookie);
816 	free(MIDIQ_BUF(m->inq), M_MIDI);
817 	free(MIDIQ_BUF(m->outq), M_MIDI);
818 	mtx_destroy(&m->qlock);
819 	mtx_destroy(&m->lock);
820 	free(m, M_MIDI);
821 	return 0;
822 }
823 
824 static int
midi_load(void)825 midi_load(void)
826 {
827 	sx_init(&mstat_lock, "midistat lock");
828 	TAILQ_INIT(&midi_devs);
829 
830 	return 0;
831 }
832 
833 static int
midi_unload(void)834 midi_unload(void)
835 {
836 	struct snd_midi *m, *tmp;
837 	int retval;
838 
839 	MIDI_DEBUG(1, printf("midi_unload()\n"));
840 	retval = EBUSY;
841 	midistat_lock();
842 	TAILQ_FOREACH_SAFE(m, &midi_devs, link, tmp) {
843 		mtx_lock(&m->lock);
844 		if (m->busy)
845 			retval = EBUSY;
846 		else
847 			retval = midi_destroy(m, 1);
848 		if (retval)
849 			goto exit;
850 	}
851 	midistat_unlock();
852 
853 	sx_destroy(&mstat_lock);
854 	return 0;
855 
856 exit:
857 	mtx_unlock(&m->lock);
858 	midistat_unlock();
859 	if (retval)
860 		MIDI_DEBUG(2, printf("midi_unload: failed\n"));
861 	return retval;
862 }
863 
864 static int
midi_modevent(module_t mod,int type,void * data)865 midi_modevent(module_t mod, int type, void *data)
866 {
867 	int retval;
868 
869 	retval = 0;
870 
871 	switch (type) {
872 	case MOD_LOAD:
873 		retval = midi_load();
874 		break;
875 
876 	case MOD_UNLOAD:
877 		retval = midi_unload();
878 		break;
879 
880 	default:
881 		break;
882 	}
883 
884 	return retval;
885 }
886 
887 DEV_MODULE(midi, midi_modevent, NULL);
888 MODULE_VERSION(midi, 1);
889