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