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