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 /*
34 * Parts of this file started out as NetBSD: midi.c 1.31
35 * They are mostly gone. Still the most obvious will be the state
36 * machine midi_in
37 */
38
39 #include <sys/param.h>
40 #include <sys/systm.h>
41 #include <sys/queue.h>
42 #include <sys/kernel.h>
43 #include <sys/lock.h>
44 #include <sys/mutex.h>
45 #include <sys/proc.h>
46 #include <sys/signalvar.h>
47 #include <sys/conf.h>
48 #include <sys/selinfo.h>
49 #include <sys/sysctl.h>
50 #include <sys/malloc.h>
51 #include <sys/sx.h>
52 #include <sys/proc.h>
53 #include <sys/fcntl.h>
54 #include <sys/types.h>
55 #include <sys/uio.h>
56 #include <sys/poll.h>
57 #include <sys/sbuf.h>
58 #include <sys/kobj.h>
59 #include <sys/module.h>
60
61 #ifdef HAVE_KERNEL_OPTION_HEADERS
62 #include "opt_snd.h"
63 #endif
64
65 #include <dev/sound/midi/midi.h>
66 #include "mpu_if.h"
67
68 #include <dev/sound/midi/midiq.h>
69 #include "synth_if.h"
70 MALLOC_DEFINE(M_MIDI, "midi buffers", "Midi data allocation area");
71
72 #ifndef KOBJMETHOD_END
73 #define KOBJMETHOD_END { NULL, NULL }
74 #endif
75
76 #define PCMMKMINOR(u, d, c) ((((c) & 0xff) << 16) | (((u) & 0x0f) << 4) | ((d) & 0x0f))
77 #define MIDIMKMINOR(u, d, c) PCMMKMINOR(u, d, c)
78
79 #define MIDI_DEV_RAW 2
80 #define MIDI_DEV_MIDICTL 12
81
82 enum midi_states {
83 MIDI_IN_START, MIDI_IN_SYSEX, MIDI_IN_DATA
84 };
85
86 /*
87 * The MPU interface current has init() uninit() inqsize() outqsize()
88 * callback() : fiddle with the tx|rx status.
89 */
90
91 #include "mpu_if.h"
92
93 /*
94 * /dev/rmidi Structure definitions
95 */
96
97 #define MIDI_NAMELEN 16
98 struct snd_midi {
99 KOBJ_FIELDS;
100 struct mtx lock; /* Protects all but queues */
101 void *cookie;
102
103 int unit; /* Should only be used in midistat */
104 int channel; /* Should only be used in midistat */
105
106 int busy;
107 int flags; /* File flags */
108 char name[MIDI_NAMELEN];
109 struct mtx qlock; /* Protects inq, outq and flags */
110 MIDIQ_HEAD(, char) inq, outq;
111 int rchan, wchan;
112 struct selinfo rsel, wsel;
113 int hiwat; /* QLEN(outq)>High-water -> disable
114 * writes from userland */
115 enum midi_states inq_state;
116 int inq_status, inq_left; /* Variables for the state machine in
117 * Midi_in, this is to provide that
118 * signals only get issued only
119 * complete command packets. */
120 struct proc *async;
121 struct cdev *dev;
122 struct synth_midi *synth;
123 int synth_flags;
124 TAILQ_ENTRY(snd_midi) link;
125 };
126
127 struct synth_midi {
128 KOBJ_FIELDS;
129 struct snd_midi *m;
130 };
131
132 static synth_open_t midisynth_open;
133 static synth_close_t midisynth_close;
134 static synth_writeraw_t midisynth_writeraw;
135 static synth_killnote_t midisynth_killnote;
136 static synth_startnote_t midisynth_startnote;
137 static synth_setinstr_t midisynth_setinstr;
138 static synth_alloc_t midisynth_alloc;
139 static synth_controller_t midisynth_controller;
140 static synth_bender_t midisynth_bender;
141
142 static kobj_method_t midisynth_methods[] = {
143 KOBJMETHOD(synth_open, midisynth_open),
144 KOBJMETHOD(synth_close, midisynth_close),
145 KOBJMETHOD(synth_writeraw, midisynth_writeraw),
146 KOBJMETHOD(synth_setinstr, midisynth_setinstr),
147 KOBJMETHOD(synth_startnote, midisynth_startnote),
148 KOBJMETHOD(synth_killnote, midisynth_killnote),
149 KOBJMETHOD(synth_alloc, midisynth_alloc),
150 KOBJMETHOD(synth_controller, midisynth_controller),
151 KOBJMETHOD(synth_bender, midisynth_bender),
152 KOBJMETHOD_END
153 };
154
155 DEFINE_CLASS(midisynth, midisynth_methods, 0);
156
157 /*
158 * Module Exports & Interface
159 *
160 * struct midi_chan *midi_init(MPU_CLASS cls, int unit, int chan,
161 * void *cookie)
162 * int midi_uninit(struct snd_midi *)
163 *
164 * 0 == no error
165 * EBUSY or other error
166 *
167 * int midi_in(struct snd_midi *, char *buf, int count)
168 * int midi_out(struct snd_midi *, char *buf, int count)
169 *
170 * midi_{in,out} return actual size transfered
171 *
172 */
173
174 /*
175 * midi_devs tailq, holder of all rmidi instances protected by midistat_lock
176 */
177
178 TAILQ_HEAD(, snd_midi) midi_devs;
179
180 /*
181 * /dev/midistat variables and declarations, protected by midistat_lock
182 */
183
184 static struct sx midistat_lock;
185 static int midistat_isopen = 0;
186 static struct sbuf midistat_sbuf;
187 static struct cdev *midistat_dev;
188
189 /*
190 * /dev/midistat dev_t declarations
191 */
192
193 static d_open_t midistat_open;
194 static d_close_t midistat_close;
195 static d_read_t midistat_read;
196
197 static struct cdevsw midistat_cdevsw = {
198 .d_version = D_VERSION,
199 .d_open = midistat_open,
200 .d_close = midistat_close,
201 .d_read = midistat_read,
202 .d_name = "midistat",
203 };
204
205 /*
206 * /dev/rmidi dev_t declarations, struct variable access is protected by
207 * locks contained within the structure.
208 */
209
210 static d_open_t midi_open;
211 static d_close_t midi_close;
212 static d_ioctl_t midi_ioctl;
213 static d_read_t midi_read;
214 static d_write_t midi_write;
215 static d_poll_t midi_poll;
216
217 static struct cdevsw midi_cdevsw = {
218 .d_version = D_VERSION,
219 .d_open = midi_open,
220 .d_close = midi_close,
221 .d_read = midi_read,
222 .d_write = midi_write,
223 .d_ioctl = midi_ioctl,
224 .d_poll = midi_poll,
225 .d_name = "rmidi",
226 };
227
228 /*
229 * Prototypes of library functions
230 */
231
232 static int midi_destroy(struct snd_midi *, int);
233 static int midistat_prepare(struct sbuf * s);
234 static int midi_load(void);
235 static int midi_unload(void);
236
237 /*
238 * Misc declr.
239 */
240 SYSCTL_NODE(_hw, OID_AUTO, midi, CTLFLAG_RD | CTLFLAG_MPSAFE, 0,
241 "Midi driver");
242 static SYSCTL_NODE(_hw_midi, OID_AUTO, stat, CTLFLAG_RD | CTLFLAG_MPSAFE, 0,
243 "Status device");
244
245 int midi_debug;
246 /* XXX: should this be moved into debug.midi? */
247 SYSCTL_INT(_hw_midi, OID_AUTO, debug, CTLFLAG_RW, &midi_debug, 0, "");
248
249 int midi_dumpraw;
250 SYSCTL_INT(_hw_midi, OID_AUTO, dumpraw, CTLFLAG_RW, &midi_dumpraw, 0, "");
251
252 int midi_instroff;
253 SYSCTL_INT(_hw_midi, OID_AUTO, instroff, CTLFLAG_RW, &midi_instroff, 0, "");
254
255 int midistat_verbose;
256 SYSCTL_INT(_hw_midi_stat, OID_AUTO, verbose, CTLFLAG_RW,
257 &midistat_verbose, 0, "");
258
259 #define MIDI_DEBUG(l,a) if(midi_debug>=l) a
260 /*
261 * CODE START
262 */
263
264 /*
265 * Register a new rmidi device. cls midi_if interface unit == 0 means
266 * auto-assign new unit number unit != 0 already assigned a unit number, eg.
267 * not the first channel provided by this device. channel, sub-unit
268 * cookie is passed back on MPU calls Typical device drivers will call with
269 * unit=0, channel=1..(number of channels) and cookie=soft_c and won't care
270 * what unit number is used.
271 *
272 * It is an error to call midi_init with an already used unit/channel combo.
273 *
274 * Returns NULL on error
275 *
276 */
277 struct snd_midi *
midi_init(kobj_class_t cls,int unit,int channel,void * cookie)278 midi_init(kobj_class_t cls, int unit, int channel, void *cookie)
279 {
280 struct snd_midi *m;
281 int i;
282 int inqsize, outqsize;
283 MIDI_TYPE *buf;
284
285 MIDI_DEBUG(1, printf("midiinit: unit %d/%d.\n", unit, channel));
286 sx_xlock(&midistat_lock);
287 /*
288 * Protect against call with existing unit/channel or auto-allocate a
289 * new unit number.
290 */
291 i = -1;
292 TAILQ_FOREACH(m, &midi_devs, link) {
293 mtx_lock(&m->lock);
294 if (unit != 0) {
295 if (m->unit == unit && m->channel == channel) {
296 mtx_unlock(&m->lock);
297 goto err0;
298 }
299 } else {
300 /*
301 * Find a better unit number
302 */
303 if (m->unit > i)
304 i = m->unit;
305 }
306 mtx_unlock(&m->lock);
307 }
308
309 if (unit == 0)
310 unit = i + 1;
311
312 MIDI_DEBUG(1, printf("midiinit #2: unit %d/%d.\n", unit, channel));
313 m = malloc(sizeof(*m), M_MIDI, M_WAITOK | M_ZERO);
314 m->synth = malloc(sizeof(*m->synth), M_MIDI, M_WAITOK | M_ZERO);
315 kobj_init((kobj_t)m->synth, &midisynth_class);
316 m->synth->m = m;
317 kobj_init((kobj_t)m, cls);
318 inqsize = MPU_INQSIZE(m, cookie);
319 outqsize = MPU_OUTQSIZE(m, cookie);
320
321 MIDI_DEBUG(1, printf("midiinit queues %d/%d.\n", inqsize, outqsize));
322 if (!inqsize && !outqsize)
323 goto err1;
324
325 mtx_init(&m->lock, "raw midi", NULL, 0);
326 mtx_init(&m->qlock, "q raw midi", NULL, 0);
327
328 mtx_lock(&m->lock);
329 mtx_lock(&m->qlock);
330
331 if (inqsize)
332 buf = malloc(sizeof(MIDI_TYPE) * inqsize, M_MIDI, M_NOWAIT);
333 else
334 buf = NULL;
335
336 MIDIQ_INIT(m->inq, buf, inqsize);
337
338 if (outqsize)
339 buf = malloc(sizeof(MIDI_TYPE) * outqsize, M_MIDI, M_NOWAIT);
340 else
341 buf = NULL;
342 m->hiwat = outqsize / 2;
343
344 MIDIQ_INIT(m->outq, buf, outqsize);
345
346 if ((inqsize && !MIDIQ_BUF(m->inq)) ||
347 (outqsize && !MIDIQ_BUF(m->outq)))
348 goto err2;
349
350 m->busy = 0;
351 m->flags = 0;
352 m->unit = unit;
353 m->channel = channel;
354 m->cookie = cookie;
355
356 if (MPU_INIT(m, cookie))
357 goto err2;
358
359 mtx_unlock(&m->lock);
360 mtx_unlock(&m->qlock);
361
362 TAILQ_INSERT_TAIL(&midi_devs, m, link);
363
364 sx_xunlock(&midistat_lock);
365
366 m->dev = make_dev(&midi_cdevsw,
367 MIDIMKMINOR(unit, MIDI_DEV_RAW, channel),
368 UID_ROOT, GID_WHEEL, 0666, "midi%d.%d", unit, channel);
369 m->dev->si_drv1 = m;
370
371 return m;
372
373 err2:
374 mtx_destroy(&m->qlock);
375 mtx_destroy(&m->lock);
376
377 if (MIDIQ_BUF(m->inq))
378 free(MIDIQ_BUF(m->inq), M_MIDI);
379 if (MIDIQ_BUF(m->outq))
380 free(MIDIQ_BUF(m->outq), M_MIDI);
381 err1:
382 free(m->synth, M_MIDI);
383 free(m, M_MIDI);
384 err0:
385 sx_xunlock(&midistat_lock);
386 MIDI_DEBUG(1, printf("midi_init ended in error\n"));
387 return NULL;
388 }
389
390 /*
391 * midi_uninit does not call MIDI_UNINIT, as since this is the implementors
392 * entry point. midi_uninit if fact, does not send any methods. A call to
393 * midi_uninit is a defacto promise that you won't manipulate ch anymore
394 *
395 */
396
397 int
midi_uninit(struct snd_midi * m)398 midi_uninit(struct snd_midi *m)
399 {
400 int err;
401
402 err = EBUSY;
403 sx_xlock(&midistat_lock);
404 mtx_lock(&m->lock);
405 if (m->busy) {
406 if (!(m->rchan || m->wchan))
407 goto err;
408
409 if (m->rchan) {
410 wakeup(&m->rchan);
411 m->rchan = 0;
412 }
413 if (m->wchan) {
414 wakeup(&m->wchan);
415 m->wchan = 0;
416 }
417 }
418 err = midi_destroy(m, 0);
419 if (!err)
420 goto exit;
421
422 err:
423 mtx_unlock(&m->lock);
424 exit:
425 sx_xunlock(&midistat_lock);
426 return err;
427 }
428
429 /*
430 * midi_in: process all data until the queue is full, then discards the rest.
431 * Since midi_in is a state machine, data discards can cause it to get out of
432 * whack. Process as much as possible. It calls, wakeup, selnotify and
433 * psignal at most once.
434 */
435
436 #ifdef notdef
437 static int midi_lengths[] = {2, 2, 2, 2, 1, 1, 2, 0};
438
439 #endif /* notdef */
440 /* Number of bytes in a MIDI command */
441 #define MIDI_LENGTH(d) (midi_lengths[((d) >> 4) & 7])
442 #define MIDI_ACK 0xfe
443 #define MIDI_IS_STATUS(d) ((d) >= 0x80)
444 #define MIDI_IS_COMMON(d) ((d) >= 0xf0)
445
446 #define MIDI_SYSEX_START 0xF0
447 #define MIDI_SYSEX_END 0xF7
448
449 int
midi_in(struct snd_midi * m,MIDI_TYPE * buf,int size)450 midi_in(struct snd_midi *m, MIDI_TYPE *buf, int size)
451 {
452 /* int i, sig, enq; */
453 int used;
454
455 /* MIDI_TYPE data; */
456 MIDI_DEBUG(5, printf("midi_in: m=%p size=%d\n", m, size));
457
458 /*
459 * XXX: locking flub
460 */
461 if (!(m->flags & M_RX))
462 return size;
463
464 used = 0;
465
466 mtx_lock(&m->qlock);
467 #if 0
468 /*
469 * Don't bother queuing if not in read mode. Discard everything and
470 * return size so the caller doesn't freak out.
471 */
472
473 if (!(m->flags & M_RX))
474 return size;
475
476 for (i = sig = 0; i < size; i++) {
477 data = buf[i];
478 enq = 0;
479 if (data == MIDI_ACK)
480 continue;
481
482 switch (m->inq_state) {
483 case MIDI_IN_START:
484 if (MIDI_IS_STATUS(data)) {
485 switch (data) {
486 case 0xf0: /* Sysex */
487 m->inq_state = MIDI_IN_SYSEX;
488 break;
489 case 0xf1: /* MTC quarter frame */
490 case 0xf3: /* Song select */
491 m->inq_state = MIDI_IN_DATA;
492 enq = 1;
493 m->inq_left = 1;
494 break;
495 case 0xf2: /* Song position pointer */
496 m->inq_state = MIDI_IN_DATA;
497 enq = 1;
498 m->inq_left = 2;
499 break;
500 default:
501 if (MIDI_IS_COMMON(data)) {
502 enq = 1;
503 sig = 1;
504 } else {
505 m->inq_state = MIDI_IN_DATA;
506 enq = 1;
507 m->inq_status = data;
508 m->inq_left = MIDI_LENGTH(data);
509 }
510 break;
511 }
512 } else if (MIDI_IS_STATUS(m->inq_status)) {
513 m->inq_state = MIDI_IN_DATA;
514 if (!MIDIQ_FULL(m->inq)) {
515 used++;
516 MIDIQ_ENQ(m->inq, &m->inq_status, 1);
517 }
518 enq = 1;
519 m->inq_left = MIDI_LENGTH(m->inq_status) - 1;
520 }
521 break;
522 /*
523 * End of case MIDI_IN_START:
524 */
525
526 case MIDI_IN_DATA:
527 enq = 1;
528 if (--m->inq_left <= 0)
529 sig = 1;/* deliver data */
530 break;
531 case MIDI_IN_SYSEX:
532 if (data == MIDI_SYSEX_END)
533 m->inq_state = MIDI_IN_START;
534 break;
535 }
536
537 if (enq)
538 if (!MIDIQ_FULL(m->inq)) {
539 MIDIQ_ENQ(m->inq, &data, 1);
540 used++;
541 }
542 /*
543 * End of the state machines main "for loop"
544 */
545 }
546 if (sig) {
547 #endif
548 MIDI_DEBUG(6, printf("midi_in: len %jd avail %jd\n",
549 (intmax_t)MIDIQ_LEN(m->inq),
550 (intmax_t)MIDIQ_AVAIL(m->inq)));
551 if (MIDIQ_AVAIL(m->inq) > size) {
552 used = size;
553 MIDIQ_ENQ(m->inq, buf, size);
554 } else {
555 MIDI_DEBUG(4, printf("midi_in: Discarding data qu\n"));
556 mtx_unlock(&m->qlock);
557 return 0;
558 }
559 if (m->rchan) {
560 wakeup(&m->rchan);
561 m->rchan = 0;
562 }
563 selwakeup(&m->rsel);
564 if (m->async) {
565 PROC_LOCK(m->async);
566 kern_psignal(m->async, SIGIO);
567 PROC_UNLOCK(m->async);
568 }
569 #if 0
570 }
571 #endif
572 mtx_unlock(&m->qlock);
573 return used;
574 }
575
576 /*
577 * midi_out: The only clearer of the M_TXEN flag.
578 */
579 int
midi_out(struct snd_midi * m,MIDI_TYPE * buf,int size)580 midi_out(struct snd_midi *m, MIDI_TYPE *buf, int size)
581 {
582 int used;
583
584 /*
585 * XXX: locking flub
586 */
587 if (!(m->flags & M_TXEN))
588 return 0;
589
590 MIDI_DEBUG(2, printf("midi_out: %p\n", m));
591 mtx_lock(&m->qlock);
592 used = MIN(size, MIDIQ_LEN(m->outq));
593 MIDI_DEBUG(3, printf("midi_out: used %d\n", used));
594 if (used)
595 MIDIQ_DEQ(m->outq, buf, used);
596 if (MIDIQ_EMPTY(m->outq)) {
597 m->flags &= ~M_TXEN;
598 MPU_CALLBACKP(m, m->cookie, m->flags);
599 }
600 if (used && MIDIQ_AVAIL(m->outq) > m->hiwat) {
601 if (m->wchan) {
602 wakeup(&m->wchan);
603 m->wchan = 0;
604 }
605 selwakeup(&m->wsel);
606 if (m->async) {
607 PROC_LOCK(m->async);
608 kern_psignal(m->async, SIGIO);
609 PROC_UNLOCK(m->async);
610 }
611 }
612 mtx_unlock(&m->qlock);
613 return used;
614 }
615
616 /*
617 * /dev/rmidi#.# device access functions
618 */
619 int
midi_open(struct cdev * i_dev,int flags,int mode,struct thread * td)620 midi_open(struct cdev *i_dev, int flags, int mode, struct thread *td)
621 {
622 struct snd_midi *m = i_dev->si_drv1;
623 int retval;
624
625 MIDI_DEBUG(1, printf("midiopen %p %s %s\n", td,
626 flags & FREAD ? "M_RX" : "", flags & FWRITE ? "M_TX" : ""));
627 if (m == NULL)
628 return ENXIO;
629
630 mtx_lock(&m->lock);
631 mtx_lock(&m->qlock);
632
633 retval = 0;
634
635 if (flags & FREAD) {
636 if (MIDIQ_SIZE(m->inq) == 0)
637 retval = ENXIO;
638 else if (m->flags & M_RX)
639 retval = EBUSY;
640 if (retval)
641 goto err;
642 }
643 if (flags & FWRITE) {
644 if (MIDIQ_SIZE(m->outq) == 0)
645 retval = ENXIO;
646 else if (m->flags & M_TX)
647 retval = EBUSY;
648 if (retval)
649 goto err;
650 }
651 m->busy++;
652
653 m->rchan = 0;
654 m->wchan = 0;
655 m->async = 0;
656
657 if (flags & FREAD) {
658 m->flags |= M_RX | M_RXEN;
659 /*
660 * Only clear the inq, the outq might still have data to drain
661 * from a previous session
662 */
663 MIDIQ_CLEAR(m->inq);
664 }
665
666 if (flags & FWRITE)
667 m->flags |= M_TX;
668
669 MPU_CALLBACK(m, m->cookie, m->flags);
670
671 MIDI_DEBUG(2, printf("midi_open: opened.\n"));
672
673 err: mtx_unlock(&m->qlock);
674 mtx_unlock(&m->lock);
675 return retval;
676 }
677
678 int
midi_close(struct cdev * i_dev,int flags,int mode,struct thread * td)679 midi_close(struct cdev *i_dev, int flags, int mode, struct thread *td)
680 {
681 struct snd_midi *m = i_dev->si_drv1;
682 int retval;
683 int oldflags;
684
685 MIDI_DEBUG(1, printf("midi_close %p %s %s\n", td,
686 flags & FREAD ? "M_RX" : "", flags & FWRITE ? "M_TX" : ""));
687
688 if (m == NULL)
689 return ENXIO;
690
691 mtx_lock(&m->lock);
692 mtx_lock(&m->qlock);
693
694 if ((flags & FREAD && !(m->flags & M_RX)) ||
695 (flags & FWRITE && !(m->flags & M_TX))) {
696 retval = ENXIO;
697 goto err;
698 }
699 m->busy--;
700
701 oldflags = m->flags;
702
703 if (flags & FREAD)
704 m->flags &= ~(M_RX | M_RXEN);
705 if (flags & FWRITE)
706 m->flags &= ~M_TX;
707
708 if ((m->flags & (M_TXEN | M_RXEN)) != (oldflags & (M_RXEN | M_TXEN)))
709 MPU_CALLBACK(m, m->cookie, m->flags);
710
711 MIDI_DEBUG(1, printf("midi_close: closed, busy = %d.\n", m->busy));
712
713 mtx_unlock(&m->qlock);
714 mtx_unlock(&m->lock);
715 retval = 0;
716 err: return retval;
717 }
718
719 /*
720 * TODO: midi_read, per oss programmer's guide pg. 42 should return as soon
721 * as data is available.
722 */
723 int
midi_read(struct cdev * i_dev,struct uio * uio,int ioflag)724 midi_read(struct cdev *i_dev, struct uio *uio, int ioflag)
725 {
726 #define MIDI_RSIZE 32
727 struct snd_midi *m = i_dev->si_drv1;
728 int retval;
729 int used;
730 char buf[MIDI_RSIZE];
731
732 MIDI_DEBUG(5, printf("midiread: count=%lu\n",
733 (unsigned long)uio->uio_resid));
734
735 retval = EIO;
736
737 if (m == NULL)
738 goto err0;
739
740 mtx_lock(&m->lock);
741 mtx_lock(&m->qlock);
742
743 if (!(m->flags & M_RX))
744 goto err1;
745
746 while (uio->uio_resid > 0) {
747 while (MIDIQ_EMPTY(m->inq)) {
748 retval = EWOULDBLOCK;
749 if (ioflag & O_NONBLOCK)
750 goto err1;
751 mtx_unlock(&m->lock);
752 m->rchan = 1;
753 retval = msleep(&m->rchan, &m->qlock,
754 PCATCH | PDROP, "midi RX", 0);
755 /*
756 * We slept, maybe things have changed since last
757 * dying check
758 */
759 if (retval == EINTR)
760 goto err0;
761 if (m != i_dev->si_drv1)
762 retval = ENXIO;
763 /* if (retval && retval != ERESTART) */
764 if (retval)
765 goto err0;
766 mtx_lock(&m->lock);
767 mtx_lock(&m->qlock);
768 m->rchan = 0;
769 if (!m->busy)
770 goto err1;
771 }
772 MIDI_DEBUG(6, printf("midi_read start\n"));
773 /*
774 * At this point, it is certain that m->inq has data
775 */
776
777 used = MIN(MIDIQ_LEN(m->inq), uio->uio_resid);
778 used = MIN(used, MIDI_RSIZE);
779
780 MIDI_DEBUG(6, printf("midiread: uiomove cc=%d\n", used));
781 MIDIQ_DEQ(m->inq, buf, used);
782 retval = uiomove(buf, used, uio);
783 if (retval)
784 goto err1;
785 }
786
787 /*
788 * If we Made it here then transfer is good
789 */
790 retval = 0;
791 err1: mtx_unlock(&m->qlock);
792 mtx_unlock(&m->lock);
793 err0: MIDI_DEBUG(4, printf("midi_read: ret %d\n", retval));
794 return retval;
795 }
796
797 /*
798 * midi_write: The only setter of M_TXEN
799 */
800
801 int
midi_write(struct cdev * i_dev,struct uio * uio,int ioflag)802 midi_write(struct cdev *i_dev, struct uio *uio, int ioflag)
803 {
804 #define MIDI_WSIZE 32
805 struct snd_midi *m = i_dev->si_drv1;
806 int retval;
807 int used;
808 char buf[MIDI_WSIZE];
809
810 MIDI_DEBUG(4, printf("midi_write\n"));
811 retval = 0;
812 if (m == NULL)
813 goto err0;
814
815 mtx_lock(&m->lock);
816 mtx_lock(&m->qlock);
817
818 if (!(m->flags & M_TX))
819 goto err1;
820
821 while (uio->uio_resid > 0) {
822 while (MIDIQ_AVAIL(m->outq) == 0) {
823 retval = EWOULDBLOCK;
824 if (ioflag & O_NONBLOCK)
825 goto err1;
826 mtx_unlock(&m->lock);
827 m->wchan = 1;
828 MIDI_DEBUG(3, printf("midi_write msleep\n"));
829 retval = msleep(&m->wchan, &m->qlock,
830 PCATCH | PDROP, "midi TX", 0);
831 /*
832 * We slept, maybe things have changed since last
833 * dying check
834 */
835 if (retval == EINTR)
836 goto err0;
837 if (m != i_dev->si_drv1)
838 retval = ENXIO;
839 if (retval)
840 goto err0;
841 mtx_lock(&m->lock);
842 mtx_lock(&m->qlock);
843 m->wchan = 0;
844 if (!m->busy)
845 goto err1;
846 }
847
848 /*
849 * We are certain than data can be placed on the queue
850 */
851
852 used = MIN(MIDIQ_AVAIL(m->outq), uio->uio_resid);
853 used = MIN(used, MIDI_WSIZE);
854 MIDI_DEBUG(5, printf("midiout: resid %zd len %jd avail %jd\n",
855 uio->uio_resid, (intmax_t)MIDIQ_LEN(m->outq),
856 (intmax_t)MIDIQ_AVAIL(m->outq)));
857
858 MIDI_DEBUG(5, printf("midi_write: uiomove cc=%d\n", used));
859 retval = uiomove(buf, used, uio);
860 if (retval)
861 goto err1;
862 MIDIQ_ENQ(m->outq, buf, used);
863 /*
864 * Inform the bottom half that data can be written
865 */
866 if (!(m->flags & M_TXEN)) {
867 m->flags |= M_TXEN;
868 MPU_CALLBACK(m, m->cookie, m->flags);
869 }
870 }
871 /*
872 * If we Made it here then transfer is good
873 */
874 retval = 0;
875 err1: mtx_unlock(&m->qlock);
876 mtx_unlock(&m->lock);
877 err0: return retval;
878 }
879
880 int
midi_ioctl(struct cdev * i_dev,u_long cmd,caddr_t arg,int mode,struct thread * td)881 midi_ioctl(struct cdev *i_dev, u_long cmd, caddr_t arg, int mode,
882 struct thread *td)
883 {
884 return ENXIO;
885 }
886
887 int
midi_poll(struct cdev * i_dev,int events,struct thread * td)888 midi_poll(struct cdev *i_dev, int events, struct thread *td)
889 {
890 struct snd_midi *m = i_dev->si_drv1;
891 int revents;
892
893 if (m == NULL)
894 return 0;
895
896 revents = 0;
897
898 mtx_lock(&m->lock);
899 mtx_lock(&m->qlock);
900
901 if (events & (POLLIN | POLLRDNORM))
902 if (!MIDIQ_EMPTY(m->inq))
903 events |= events & (POLLIN | POLLRDNORM);
904
905 if (events & (POLLOUT | POLLWRNORM))
906 if (MIDIQ_AVAIL(m->outq) < m->hiwat)
907 events |= events & (POLLOUT | POLLWRNORM);
908
909 if (revents == 0) {
910 if (events & (POLLIN | POLLRDNORM))
911 selrecord(td, &m->rsel);
912
913 if (events & (POLLOUT | POLLWRNORM))
914 selrecord(td, &m->wsel);
915 }
916 mtx_unlock(&m->lock);
917 mtx_unlock(&m->qlock);
918
919 return (revents);
920 }
921
922 /*
923 * /dev/midistat device functions
924 *
925 */
926 static int
midistat_open(struct cdev * i_dev,int flags,int mode,struct thread * td)927 midistat_open(struct cdev *i_dev, int flags, int mode, struct thread *td)
928 {
929 int error;
930
931 MIDI_DEBUG(1, printf("midistat_open\n"));
932
933 sx_xlock(&midistat_lock);
934 if (midistat_isopen) {
935 sx_xunlock(&midistat_lock);
936 return EBUSY;
937 }
938 midistat_isopen = 1;
939 if (sbuf_new(&midistat_sbuf, NULL, 4096, SBUF_AUTOEXTEND) == NULL) {
940 error = ENXIO;
941 goto out;
942 }
943 error = (midistat_prepare(&midistat_sbuf) > 0) ? 0 : ENOMEM;
944 out:
945 if (error)
946 midistat_isopen = 0;
947 sx_xunlock(&midistat_lock);
948 return error;
949 }
950
951 static int
midistat_close(struct cdev * i_dev,int flags,int mode,struct thread * td)952 midistat_close(struct cdev *i_dev, int flags, int mode, struct thread *td)
953 {
954 MIDI_DEBUG(1, printf("midistat_close\n"));
955 sx_xlock(&midistat_lock);
956 if (!midistat_isopen) {
957 sx_xunlock(&midistat_lock);
958 return EBADF;
959 }
960 sbuf_delete(&midistat_sbuf);
961 midistat_isopen = 0;
962 sx_xunlock(&midistat_lock);
963 return 0;
964 }
965
966 static int
midistat_read(struct cdev * i_dev,struct uio * uio,int flag)967 midistat_read(struct cdev *i_dev, struct uio *uio, int flag)
968 {
969 long l;
970 int err;
971
972 MIDI_DEBUG(4, printf("midistat_read\n"));
973 sx_xlock(&midistat_lock);
974 if (!midistat_isopen) {
975 sx_xunlock(&midistat_lock);
976 return EBADF;
977 }
978 if (uio->uio_offset < 0 || uio->uio_offset > sbuf_len(&midistat_sbuf)) {
979 sx_xunlock(&midistat_lock);
980 return EINVAL;
981 }
982 err = 0;
983 l = lmin(uio->uio_resid, sbuf_len(&midistat_sbuf) - uio->uio_offset);
984 if (l > 0) {
985 err = uiomove(sbuf_data(&midistat_sbuf) + uio->uio_offset, l,
986 uio);
987 }
988 sx_xunlock(&midistat_lock);
989 return err;
990 }
991
992 /*
993 * Module library functions
994 */
995
996 static int
midistat_prepare(struct sbuf * s)997 midistat_prepare(struct sbuf *s)
998 {
999 struct snd_midi *m;
1000
1001 sx_assert(&midistat_lock, SA_XLOCKED);
1002
1003 sbuf_printf(s, "FreeBSD Midi Driver (midi2)\n");
1004 if (TAILQ_EMPTY(&midi_devs)) {
1005 sbuf_printf(s, "No devices installed.\n");
1006 sbuf_finish(s);
1007 return sbuf_len(s);
1008 }
1009 sbuf_printf(s, "Installed devices:\n");
1010
1011 TAILQ_FOREACH(m, &midi_devs, link) {
1012 mtx_lock(&m->lock);
1013 sbuf_printf(s, "%s [%d/%d:%s]", m->name, m->unit, m->channel,
1014 MPU_PROVIDER(m, m->cookie));
1015 sbuf_printf(s, "%s", MPU_DESCR(m, m->cookie, midistat_verbose));
1016 sbuf_printf(s, "\n");
1017 mtx_unlock(&m->lock);
1018 }
1019
1020 sbuf_finish(s);
1021 return sbuf_len(s);
1022 }
1023
1024 #ifdef notdef
1025 /*
1026 * Convert IOCTL command to string for debugging
1027 */
1028
1029 static char *
midi_cmdname(int cmd)1030 midi_cmdname(int cmd)
1031 {
1032 static struct {
1033 int cmd;
1034 char *name;
1035 } *tab, cmdtab_midiioctl[] = {
1036 #define A(x) {x, ## x}
1037 /*
1038 * Once we have some real IOCTLs define, the following will
1039 * be relavant.
1040 *
1041 * A(SNDCTL_MIDI_PRETIME), A(SNDCTL_MIDI_MPUMODE),
1042 * A(SNDCTL_MIDI_MPUCMD), A(SNDCTL_SYNTH_INFO),
1043 * A(SNDCTL_MIDI_INFO), A(SNDCTL_SYNTH_MEMAVL),
1044 * A(SNDCTL_FM_LOAD_INSTR), A(SNDCTL_FM_4OP_ENABLE),
1045 * A(MIOSPASSTHRU), A(MIOGPASSTHRU), A(AIONWRITE),
1046 * A(AIOGSIZE), A(AIOSSIZE), A(AIOGFMT), A(AIOSFMT),
1047 * A(AIOGMIX), A(AIOSMIX), A(AIOSTOP), A(AIOSYNC),
1048 * A(AIOGCAP),
1049 */
1050 #undef A
1051 {
1052 -1, "unknown"
1053 },
1054 };
1055
1056 for (tab = cmdtab_midiioctl; tab->cmd != cmd && tab->cmd != -1; tab++);
1057 return tab->name;
1058 }
1059
1060 #endif /* notdef */
1061
1062 /*
1063 * midisynth
1064 */
1065
1066 int
midisynth_open(void * n,void * arg,int flags)1067 midisynth_open(void *n, void *arg, int flags)
1068 {
1069 struct snd_midi *m = ((struct synth_midi *)n)->m;
1070 int retval;
1071
1072 MIDI_DEBUG(1, printf("midisynth_open %s %s\n",
1073 flags & FREAD ? "M_RX" : "", flags & FWRITE ? "M_TX" : ""));
1074
1075 if (m == NULL)
1076 return ENXIO;
1077
1078 mtx_lock(&m->lock);
1079 mtx_lock(&m->qlock);
1080
1081 retval = 0;
1082
1083 if (flags & FREAD) {
1084 if (MIDIQ_SIZE(m->inq) == 0)
1085 retval = ENXIO;
1086 else if (m->flags & M_RX)
1087 retval = EBUSY;
1088 if (retval)
1089 goto err;
1090 }
1091 if (flags & FWRITE) {
1092 if (MIDIQ_SIZE(m->outq) == 0)
1093 retval = ENXIO;
1094 else if (m->flags & M_TX)
1095 retval = EBUSY;
1096 if (retval)
1097 goto err;
1098 }
1099 m->busy++;
1100
1101 /*
1102 * TODO: Consider m->async = 0;
1103 */
1104
1105 if (flags & FREAD) {
1106 m->flags |= M_RX | M_RXEN;
1107 /*
1108 * Only clear the inq, the outq might still have data to drain
1109 * from a previous session
1110 */
1111 MIDIQ_CLEAR(m->inq);
1112 m->rchan = 0;
1113 }
1114
1115 if (flags & FWRITE) {
1116 m->flags |= M_TX;
1117 m->wchan = 0;
1118 }
1119 m->synth_flags = flags & (FREAD | FWRITE);
1120
1121 MPU_CALLBACK(m, m->cookie, m->flags);
1122
1123 err: mtx_unlock(&m->qlock);
1124 mtx_unlock(&m->lock);
1125 MIDI_DEBUG(2, printf("midisynth_open: return %d.\n", retval));
1126 return retval;
1127 }
1128
1129 int
midisynth_close(void * n)1130 midisynth_close(void *n)
1131 {
1132 struct snd_midi *m = ((struct synth_midi *)n)->m;
1133 int retval;
1134 int oldflags;
1135
1136 MIDI_DEBUG(1, printf("midisynth_close %s %s\n",
1137 m->synth_flags & FREAD ? "M_RX" : "",
1138 m->synth_flags & FWRITE ? "M_TX" : ""));
1139
1140 if (m == NULL)
1141 return ENXIO;
1142
1143 mtx_lock(&m->lock);
1144 mtx_lock(&m->qlock);
1145
1146 if ((m->synth_flags & FREAD && !(m->flags & M_RX)) ||
1147 (m->synth_flags & FWRITE && !(m->flags & M_TX))) {
1148 retval = ENXIO;
1149 goto err;
1150 }
1151 m->busy--;
1152
1153 oldflags = m->flags;
1154
1155 if (m->synth_flags & FREAD)
1156 m->flags &= ~(M_RX | M_RXEN);
1157 if (m->synth_flags & FWRITE)
1158 m->flags &= ~M_TX;
1159
1160 if ((m->flags & (M_TXEN | M_RXEN)) != (oldflags & (M_RXEN | M_TXEN)))
1161 MPU_CALLBACK(m, m->cookie, m->flags);
1162
1163 MIDI_DEBUG(1, printf("midi_close: closed, busy = %d.\n", m->busy));
1164
1165 mtx_unlock(&m->qlock);
1166 mtx_unlock(&m->lock);
1167 retval = 0;
1168 err: return retval;
1169 }
1170
1171 /*
1172 * Always blocking.
1173 */
1174
1175 int
midisynth_writeraw(void * n,uint8_t * buf,size_t len)1176 midisynth_writeraw(void *n, uint8_t *buf, size_t len)
1177 {
1178 struct snd_midi *m = ((struct synth_midi *)n)->m;
1179 int retval;
1180 int used;
1181 int i;
1182
1183 MIDI_DEBUG(4, printf("midisynth_writeraw\n"));
1184
1185 retval = 0;
1186
1187 if (m == NULL)
1188 return ENXIO;
1189
1190 mtx_lock(&m->lock);
1191 mtx_lock(&m->qlock);
1192
1193 if (!(m->flags & M_TX))
1194 goto err1;
1195
1196 if (midi_dumpraw)
1197 printf("midi dump: ");
1198
1199 while (len > 0) {
1200 while (MIDIQ_AVAIL(m->outq) == 0) {
1201 if (!(m->flags & M_TXEN)) {
1202 m->flags |= M_TXEN;
1203 MPU_CALLBACK(m, m->cookie, m->flags);
1204 }
1205 mtx_unlock(&m->lock);
1206 m->wchan = 1;
1207 MIDI_DEBUG(3, printf("midisynth_writeraw msleep\n"));
1208 retval = msleep(&m->wchan, &m->qlock,
1209 PCATCH | PDROP, "midi TX", 0);
1210 /*
1211 * We slept, maybe things have changed since last
1212 * dying check
1213 */
1214 if (retval == EINTR)
1215 goto err0;
1216
1217 if (retval)
1218 goto err0;
1219 mtx_lock(&m->lock);
1220 mtx_lock(&m->qlock);
1221 m->wchan = 0;
1222 if (!m->busy)
1223 goto err1;
1224 }
1225
1226 /*
1227 * We are certain than data can be placed on the queue
1228 */
1229
1230 used = MIN(MIDIQ_AVAIL(m->outq), len);
1231 used = MIN(used, MIDI_WSIZE);
1232 MIDI_DEBUG(5,
1233 printf("midi_synth: resid %zu len %jd avail %jd\n",
1234 len, (intmax_t)MIDIQ_LEN(m->outq),
1235 (intmax_t)MIDIQ_AVAIL(m->outq)));
1236
1237 if (midi_dumpraw)
1238 for (i = 0; i < used; i++)
1239 printf("%x ", buf[i]);
1240
1241 MIDIQ_ENQ(m->outq, buf, used);
1242 len -= used;
1243
1244 /*
1245 * Inform the bottom half that data can be written
1246 */
1247 if (!(m->flags & M_TXEN)) {
1248 m->flags |= M_TXEN;
1249 MPU_CALLBACK(m, m->cookie, m->flags);
1250 }
1251 }
1252 /*
1253 * If we Made it here then transfer is good
1254 */
1255 if (midi_dumpraw)
1256 printf("\n");
1257
1258 retval = 0;
1259 err1: mtx_unlock(&m->qlock);
1260 mtx_unlock(&m->lock);
1261 err0: return retval;
1262 }
1263
1264 static int
midisynth_killnote(void * n,uint8_t chn,uint8_t note,uint8_t vel)1265 midisynth_killnote(void *n, uint8_t chn, uint8_t note, uint8_t vel)
1266 {
1267 u_char c[3];
1268
1269 if (note > 127 || chn > 15)
1270 return (EINVAL);
1271
1272 if (vel > 127)
1273 vel = 127;
1274
1275 if (vel == 64) {
1276 c[0] = 0x90 | (chn & 0x0f); /* Note on. */
1277 c[1] = (u_char)note;
1278 c[2] = 0;
1279 } else {
1280 c[0] = 0x80 | (chn & 0x0f); /* Note off. */
1281 c[1] = (u_char)note;
1282 c[2] = (u_char)vel;
1283 }
1284
1285 return midisynth_writeraw(n, c, 3);
1286 }
1287
1288 static int
midisynth_setinstr(void * n,uint8_t chn,uint16_t instr)1289 midisynth_setinstr(void *n, uint8_t chn, uint16_t instr)
1290 {
1291 u_char c[2];
1292
1293 if (instr > 127 || chn > 15)
1294 return EINVAL;
1295
1296 c[0] = 0xc0 | (chn & 0x0f); /* Progamme change. */
1297 c[1] = instr + midi_instroff;
1298
1299 return midisynth_writeraw(n, c, 2);
1300 }
1301
1302 static int
midisynth_startnote(void * n,uint8_t chn,uint8_t note,uint8_t vel)1303 midisynth_startnote(void *n, uint8_t chn, uint8_t note, uint8_t vel)
1304 {
1305 u_char c[3];
1306
1307 if (note > 127 || chn > 15)
1308 return EINVAL;
1309
1310 if (vel > 127)
1311 vel = 127;
1312
1313 c[0] = 0x90 | (chn & 0x0f); /* Note on. */
1314 c[1] = (u_char)note;
1315 c[2] = (u_char)vel;
1316
1317 return midisynth_writeraw(n, c, 3);
1318 }
1319 static int
midisynth_alloc(void * n,uint8_t chan,uint8_t note)1320 midisynth_alloc(void *n, uint8_t chan, uint8_t note)
1321 {
1322 return chan;
1323 }
1324
1325 static int
midisynth_controller(void * n,uint8_t chn,uint8_t ctrlnum,uint16_t val)1326 midisynth_controller(void *n, uint8_t chn, uint8_t ctrlnum, uint16_t val)
1327 {
1328 u_char c[3];
1329
1330 if (ctrlnum > 127 || chn > 15)
1331 return EINVAL;
1332
1333 c[0] = 0xb0 | (chn & 0x0f); /* Control Message. */
1334 c[1] = ctrlnum;
1335 c[2] = val;
1336 return midisynth_writeraw(n, c, 3);
1337 }
1338
1339 static int
midisynth_bender(void * n,uint8_t chn,uint16_t val)1340 midisynth_bender(void *n, uint8_t chn, uint16_t val)
1341 {
1342 u_char c[3];
1343
1344 if (val > 16383 || chn > 15)
1345 return EINVAL;
1346
1347 c[0] = 0xe0 | (chn & 0x0f); /* Pitch bend. */
1348 c[1] = (u_char)val & 0x7f;
1349 c[2] = (u_char)(val >> 7) & 0x7f;
1350
1351 return midisynth_writeraw(n, c, 3);
1352 }
1353
1354 /*
1355 * Single point of midi destructions.
1356 */
1357 static int
midi_destroy(struct snd_midi * m,int midiuninit)1358 midi_destroy(struct snd_midi *m, int midiuninit)
1359 {
1360 sx_assert(&midistat_lock, SA_XLOCKED);
1361 mtx_assert(&m->lock, MA_OWNED);
1362
1363 MIDI_DEBUG(3, printf("midi_destroy\n"));
1364 m->dev->si_drv1 = NULL;
1365 mtx_unlock(&m->lock); /* XXX */
1366 destroy_dev(m->dev);
1367 TAILQ_REMOVE(&midi_devs, m, link);
1368 if (midiuninit)
1369 MPU_UNINIT(m, m->cookie);
1370 free(MIDIQ_BUF(m->inq), M_MIDI);
1371 free(MIDIQ_BUF(m->outq), M_MIDI);
1372 mtx_destroy(&m->qlock);
1373 mtx_destroy(&m->lock);
1374 free(m->synth, M_MIDI);
1375 free(m, M_MIDI);
1376 return 0;
1377 }
1378
1379 /*
1380 * Load and unload functions, creates the /dev/midistat device
1381 */
1382
1383 static int
midi_load(void)1384 midi_load(void)
1385 {
1386 sx_init(&midistat_lock, "midistat lock");
1387 TAILQ_INIT(&midi_devs);
1388
1389 midistat_dev = make_dev(&midistat_cdevsw,
1390 MIDIMKMINOR(0, MIDI_DEV_MIDICTL, 0),
1391 UID_ROOT, GID_WHEEL, 0666, "midistat");
1392
1393 return 0;
1394 }
1395
1396 static int
midi_unload(void)1397 midi_unload(void)
1398 {
1399 struct snd_midi *m, *tmp;
1400 int retval;
1401
1402 MIDI_DEBUG(1, printf("midi_unload()\n"));
1403 retval = EBUSY;
1404 sx_xlock(&midistat_lock);
1405 if (midistat_isopen)
1406 goto exit0;
1407
1408 TAILQ_FOREACH_SAFE(m, &midi_devs, link, tmp) {
1409 mtx_lock(&m->lock);
1410 if (m->busy)
1411 retval = EBUSY;
1412 else
1413 retval = midi_destroy(m, 1);
1414 if (retval)
1415 goto exit1;
1416 }
1417 sx_xunlock(&midistat_lock);
1418 destroy_dev(midistat_dev);
1419
1420 /*
1421 * Made it here then unload is complete
1422 */
1423 sx_destroy(&midistat_lock);
1424 return 0;
1425
1426 exit1:
1427 mtx_unlock(&m->lock);
1428 exit0:
1429 sx_xunlock(&midistat_lock);
1430 if (retval)
1431 MIDI_DEBUG(2, printf("midi_unload: failed\n"));
1432 return retval;
1433 }
1434
1435 extern int seq_modevent(module_t mod, int type, void *data);
1436
1437 static int
midi_modevent(module_t mod,int type,void * data)1438 midi_modevent(module_t mod, int type, void *data)
1439 {
1440 int retval;
1441
1442 retval = 0;
1443
1444 switch (type) {
1445 case MOD_LOAD:
1446 retval = midi_load();
1447 if (retval == 0)
1448 retval = seq_modevent(mod, type, data);
1449 break;
1450
1451 case MOD_UNLOAD:
1452 retval = midi_unload();
1453 if (retval == 0)
1454 retval = seq_modevent(mod, type, data);
1455 break;
1456
1457 default:
1458 break;
1459 }
1460
1461 return retval;
1462 }
1463
1464 kobj_t
midimapper_addseq(void * arg1,int * unit,void ** cookie)1465 midimapper_addseq(void *arg1, int *unit, void **cookie)
1466 {
1467 unit = NULL;
1468
1469 return (kobj_t)arg1;
1470 }
1471
1472 int
midimapper_open(void * arg1,void ** cookie)1473 midimapper_open(void *arg1, void **cookie)
1474 {
1475 int retval = 0;
1476 struct snd_midi *m;
1477
1478 sx_xlock(&midistat_lock);
1479 TAILQ_FOREACH(m, &midi_devs, link) {
1480 retval++;
1481 }
1482 sx_xunlock(&midistat_lock);
1483 return retval;
1484 }
1485
1486 int
midimapper_close(void * arg1,void * cookie)1487 midimapper_close(void *arg1, void *cookie)
1488 {
1489 return 0;
1490 }
1491
1492 kobj_t
midimapper_fetch_synth(void * arg,void * cookie,int unit)1493 midimapper_fetch_synth(void *arg, void *cookie, int unit)
1494 {
1495 struct snd_midi *m;
1496 int retval = 0;
1497
1498 sx_xlock(&midistat_lock);
1499 TAILQ_FOREACH(m, &midi_devs, link) {
1500 if (unit == retval) {
1501 sx_xunlock(&midistat_lock);
1502 return (kobj_t)m->synth;
1503 }
1504 retval++;
1505 }
1506 sx_xunlock(&midistat_lock);
1507 return NULL;
1508 }
1509
1510 DEV_MODULE(midi, midi_modevent, NULL);
1511 MODULE_VERSION(midi, 1);
1512