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