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