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