ncurses: Hook in fully bootstrapped tic_next.
[dragonfly.git] / sys / dev / sound / midi / midi.c
bloba54d66dca03e62ffaf057d60b8aa0d645ebc1aa1
1 /*-
2 * Copyright (c) 2003 Mathew Kanner
3 * Copyright (c) 1998 The NetBSD Foundation, Inc.
4 * All rights reserved.
6 * This code is derived from software contributed to The NetBSD Foundation
7 * by Lennart Augustsson (augustss@netbsd.org).
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
18 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
19 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
20 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
21 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
22 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 * POSSIBILITY OF SUCH DAMAGE.
32 * Parts of this file started out as NetBSD: midi.c 1.31
33 * They are mostly gone. Still the most obvious will be the state
34 * machine midi_in
37 #include <sys/cdefs.h>
38 __FBSDID("$FreeBSD: head/sys/dev/sound/midi/midi.c 227309 2011-11-07 15:43:11Z ed $");
40 #include <sys/param.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/sysctl.h>
49 #include <sys/types.h>
50 #include <sys/malloc.h>
51 #include <sys/param.h>
52 #include <sys/systm.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 #include <sys/device.h>
63 #ifdef HAVE_KERNEL_OPTION_HEADERS
64 #include "opt_snd.h"
65 #endif
67 #include <dev/sound/midi/midi.h>
68 #include "mpu_if.h"
70 #include <dev/sound/midi/midiq.h>
71 #include "synth_if.h"
72 MALLOC_DEFINE(M_MIDI, "midi buffers", "Midi data allocation area");
74 #ifndef KOBJMETHOD_END
75 #define KOBJMETHOD_END { NULL, NULL }
76 #endif
78 #define PCMMKMINOR(u, d, c) ((((c) & 0xff) << 16) | (((u) & 0x0f) << 4) | ((d) & 0x0f))
79 #define MIDIMKMINOR(u, d, c) PCMMKMINOR(u, d, c)
81 #define MIDI_DEV_RAW 2
82 #define MIDI_DEV_MIDICTL 12
84 enum midi_states {
85 MIDI_IN_START, MIDI_IN_SYSEX, MIDI_IN_DATA
89 * The MPU interface current has init() uninit() inqsize(( outqsize()
90 * callback() : fiddle with the tx|rx status.
93 #include "mpu_if.h"
96 * /dev/rmidi Structure definitions
99 #define MIDI_NAMELEN 16
100 struct snd_midi {
101 KOBJ_FIELDS;
102 struct lock lock; /* Protects all but queues */
103 void *cookie;
105 int unit; /* Should only be used in midistat */
106 int channel; /* Should only be used in midistat */
108 int busy;
109 int flags; /* File flags */
110 char name[MIDI_NAMELEN];
111 struct lock qlock; /* Protects inq, outq and flags */
112 MIDIQ_HEAD(, char) inq, outq;
113 int rchan, wchan;
114 struct kqinfo rkq, wkq;
115 int hiwat; /* QLEN(outq)>High-water -> disable
116 * writes from userland */
117 enum midi_states inq_state;
118 int inq_status, inq_left; /* Variables for the state machine in
119 * Midi_in, this is to provide that
120 * signals only get issued only
121 * complete command packets. */
122 struct proc *async;
123 struct cdev *dev;
124 struct synth_midi *synth;
125 int synth_flags;
126 TAILQ_ENTRY(snd_midi) link;
129 struct synth_midi {
130 KOBJ_FIELDS;
131 struct snd_midi *m;
134 static synth_open_t midisynth_open;
135 static synth_close_t midisynth_close;
136 static synth_writeraw_t midisynth_writeraw;
137 static synth_killnote_t midisynth_killnote;
138 static synth_startnote_t midisynth_startnote;
139 static synth_setinstr_t midisynth_setinstr;
140 static synth_alloc_t midisynth_alloc;
141 static synth_controller_t midisynth_controller;
142 static synth_bender_t midisynth_bender;
145 static kobj_method_t midisynth_methods[] = {
146 KOBJMETHOD(synth_open, midisynth_open),
147 KOBJMETHOD(synth_close, midisynth_close),
148 KOBJMETHOD(synth_writeraw, midisynth_writeraw),
149 KOBJMETHOD(synth_setinstr, midisynth_setinstr),
150 KOBJMETHOD(synth_startnote, midisynth_startnote),
151 KOBJMETHOD(synth_killnote, midisynth_killnote),
152 KOBJMETHOD(synth_alloc, midisynth_alloc),
153 KOBJMETHOD(synth_controller, midisynth_controller),
154 KOBJMETHOD(synth_bender, midisynth_bender),
155 KOBJMETHOD_END
158 DEFINE_CLASS(midisynth, midisynth_methods, 0);
161 * Module Exports & Interface
163 * struct midi_chan *midi_init(MPU_CLASS cls, int unit, int chan) int
164 * midi_uninit(struct snd_midi *) 0 == no error EBUSY or other error int
165 * Midi_in(struct midi_chan *, char *buf, int count) int Midi_out(struct
166 * midi_chan *, char *buf, int count)
168 * midi_{in,out} return actual size transfered
174 * midi_devs tailq, holder of all rmidi instances protected by midistat_lock
177 TAILQ_HEAD(, snd_midi) midi_devs;
180 * /dev/midistat variables and declarations, protected by midistat_lock
183 static struct lock midistat_lock;
184 static int midistat_isopen = 0;
185 static struct sbuf midistat_sbuf;
186 static int midistat_bufptr;
187 static struct cdev *midistat_dev;
190 * /dev/midistat dev_t declarations
193 static d_open_t midistat_open;
194 static d_close_t midistat_close;
195 static d_read_t midistat_read;
197 static void midi_filter_detach(struct knote *);
198 static int midi_filter_read(struct knote *, long);
199 static int midi_filter_write(struct knote *, long);
201 static struct dev_ops midistat_ops = {
202 { "midistat", 0, D_MPSAFE },
203 .d_open = midistat_open,
204 .d_close = midistat_close,
205 .d_read = midistat_read,
208 static struct filterops midi_read_filterops =
209 { FILTEROP_ISFD, NULL, midi_filter_detach, midi_filter_read };
210 static struct filterops midi_write_filterops =
211 { FILTEROP_ISFD, NULL, midi_filter_detach, midi_filter_write };
214 * /dev/rmidi dev_t declarations, struct variable access is protected by
215 * locks contained within the structure.
218 static d_open_t midi_open;
219 static d_close_t midi_close;
220 static d_ioctl_t midi_ioctl;
221 static d_read_t midi_read;
222 static d_write_t midi_write;
223 static d_kqfilter_t midi_kqfilter;
225 static struct dev_ops midi_ops = {
226 { "rmidi", 0, D_MPSAFE },
227 .d_open = midi_open,
228 .d_close = midi_close,
229 .d_read = midi_read,
230 .d_write = midi_write,
231 .d_ioctl = midi_ioctl,
232 .d_kqfilter = midi_kqfilter,
236 * Prototypes of library functions
239 static int midi_destroy(struct snd_midi *, int);
240 static int midistat_prepare(struct sbuf * s);
241 static int midi_load(void);
242 static int midi_unload(void);
245 * Misc declr.
247 SYSCTL_NODE(_hw, OID_AUTO, midi, CTLFLAG_RD, 0, "Midi driver");
248 static SYSCTL_NODE(_hw_midi, OID_AUTO, stat, CTLFLAG_RD, 0, "Status device");
250 int midi_debug;
251 /* XXX: should this be moved into debug.midi? */
252 SYSCTL_INT(_hw_midi, OID_AUTO, debug, CTLFLAG_RW, &midi_debug, 0, "");
254 int midi_dumpraw;
255 SYSCTL_INT(_hw_midi, OID_AUTO, dumpraw, CTLFLAG_RW, &midi_dumpraw, 0, "");
257 int midi_instroff;
258 SYSCTL_INT(_hw_midi, OID_AUTO, instroff, CTLFLAG_RW, &midi_instroff, 0, "");
260 int midistat_verbose;
261 SYSCTL_INT(_hw_midi_stat, OID_AUTO, verbose, CTLFLAG_RW,
262 &midistat_verbose, 0, "");
264 #define MIDI_DEBUG(l,a) if(midi_debug>=l) a
266 * CODE START
270 * Register a new rmidi device. cls midi_if interface unit == 0 means
271 * auto-assign new unit number unit != 0 already assigned a unit number, eg.
272 * not the first channel provided by this device. channel, sub-unit
273 * cookie is passed back on MPU calls Typical device drivers will call with
274 * unit=0, channel=1..(number of channels) and cookie=soft_c and won't care
275 * what unit number is used.
277 * It is an error to call midi_init with an already used unit/channel combo.
279 * Returns NULL on error
282 struct snd_midi *
283 midi_init(kobj_class_t cls, int unit, int channel, void *cookie)
285 struct snd_midi *m;
286 int i;
287 int inqsize, outqsize;
288 MIDI_TYPE *buf;
290 MIDI_DEBUG(1, kprintf("midiinit: unit %d/%d.\n", unit, channel));
291 lockmgr(&midistat_lock, LK_EXCLUSIVE);
293 * Protect against call with existing unit/channel or auto-allocate a
294 * new unit number.
296 i = -1;
297 TAILQ_FOREACH(m, &midi_devs, link) {
298 lockmgr(&m->lock, LK_EXCLUSIVE);
299 if (unit != 0) {
300 if (m->unit == unit && m->channel == channel) {
301 lockmgr(&m->lock, LK_RELEASE);
302 goto err0;
304 } else {
306 * Find a better unit number
308 if (m->unit > i)
309 i = m->unit;
311 lockmgr(&m->lock, LK_RELEASE);
314 if (unit == 0)
315 unit = i + 1;
317 MIDI_DEBUG(1, kprintf("midiinit #2: unit %d/%d.\n", unit, channel));
318 m = kmalloc(sizeof(*m), M_MIDI, M_WAITOK | M_ZERO);
320 m->synth = kmalloc(sizeof(*m->synth), M_MIDI, M_WAITOK | M_ZERO);
321 kobj_init((kobj_t)m->synth, &midisynth_class);
322 m->synth->m = m;
323 kobj_init((kobj_t)m, cls);
324 inqsize = MPU_INQSIZE(m, cookie);
325 outqsize = MPU_OUTQSIZE(m, cookie);
327 MIDI_DEBUG(1, kprintf("midiinit queues %d/%d.\n", inqsize, outqsize));
328 if (!inqsize && !outqsize)
329 goto err1;
331 lockinit(&m->lock, "raw midi", 0, LK_CANRECURSE);
332 lockinit(&m->qlock, "q raw midi", 0, LK_CANRECURSE);
334 lockmgr(&m->lock, LK_EXCLUSIVE);
335 lockmgr(&m->qlock, LK_EXCLUSIVE);
337 if (inqsize)
338 buf = kmalloc(sizeof(MIDI_TYPE) * inqsize, M_MIDI, M_WAITOK);
339 else
340 buf = NULL;
342 MIDIQ_INIT(m->inq, buf, inqsize);
344 if (outqsize)
345 buf = kmalloc(sizeof(MIDI_TYPE) * outqsize, M_MIDI, M_WAITOK);
346 else
347 buf = NULL;
348 m->hiwat = outqsize / 2;
350 MIDIQ_INIT(m->outq, buf, outqsize);
352 if ((inqsize && !MIDIQ_BUF(m->inq)) ||
353 (outqsize && !MIDIQ_BUF(m->outq)))
354 goto err2;
357 m->busy = 0;
358 m->flags = 0;
359 m->unit = unit;
360 m->channel = channel;
361 m->cookie = cookie;
363 if (MPU_INIT(m, cookie))
364 goto err2;
366 lockmgr(&m->lock, LK_RELEASE);
367 lockmgr(&m->qlock, LK_RELEASE);
369 TAILQ_INSERT_TAIL(&midi_devs, m, link);
371 lockmgr(&midistat_lock, LK_RELEASE);
373 m->dev = make_dev(&midi_ops,
374 MIDIMKMINOR(unit, MIDI_DEV_RAW, channel),
375 UID_ROOT, GID_WHEEL, 0666, "midi%d.%d", unit, channel);
376 m->dev->si_drv1 = m;
378 return m;
380 err2: lockuninit(&m->qlock);
381 lockuninit(&m->lock);
383 if (MIDIQ_BUF(m->inq))
384 kfree(MIDIQ_BUF(m->inq), M_MIDI);
385 if (MIDIQ_BUF(m->outq))
386 kfree(MIDIQ_BUF(m->outq), M_MIDI);
387 err1: kfree(m, M_MIDI);
388 err0: lockmgr(&midistat_lock, LK_RELEASE);
389 MIDI_DEBUG(1, kprintf("midi_init ended in error\n"));
390 return NULL;
394 * midi_uninit does not call MIDI_UNINIT, as since this is the implementors
395 * entry point. midi_unint if fact, does not send any methods. A call to
396 * midi_uninit is a defacto promise that you won't manipulate ch anymore
401 midi_uninit(struct snd_midi *m)
403 int err;
405 err = ENXIO;
406 lockmgr(&midistat_lock, LK_EXCLUSIVE);
407 lockmgr(&m->lock, LK_EXCLUSIVE);
408 if (m->busy) {
409 if (!(m->rchan || m->wchan))
410 goto err;
412 if (m->rchan) {
413 wakeup(&m->rchan);
414 m->rchan = 0;
416 if (m->wchan) {
417 wakeup(&m->wchan);
418 m->wchan = 0;
421 err = midi_destroy(m, 0);
422 if (!err)
423 goto exit;
425 err: lockmgr(&m->lock, LK_RELEASE);
426 exit: lockmgr(&midistat_lock, LK_RELEASE);
427 return err;
431 * midi_in: process all data until the queue is full, then discards the rest.
432 * Since midi_in is a state machine, data discards can cause it to get out of
433 * whack. Process as much as possible. It calls, wakeup, selnotify and
434 * psignal at most once.
437 #ifdef notdef
438 static int midi_lengths[] = {2, 2, 2, 2, 1, 1, 2, 0};
440 #endif /* notdef */
441 /* Number of bytes in a MIDI command */
442 #define MIDI_LENGTH(d) (midi_lengths[((d) >> 4) & 7])
443 #define MIDI_ACK 0xfe
444 #define MIDI_IS_STATUS(d) ((d) >= 0x80)
445 #define MIDI_IS_COMMON(d) ((d) >= 0xf0)
447 #define MIDI_SYSEX_START 0xF0
448 #define MIDI_SYSEX_END 0xF7
452 midi_in(struct snd_midi *m, MIDI_TYPE *buf, int size)
454 /* int i, sig, enq; */
455 int used;
457 /* MIDI_TYPE data; */
458 MIDI_DEBUG(5, kprintf("midi_in: m=%p size=%d\n", m, size));
461 * XXX: locking flub
463 if (!(m->flags & M_RX))
464 return size;
466 used = 0;
468 lockmgr(&m->qlock, LK_EXCLUSIVE);
469 #if 0
471 * Don't bother queuing if not in read mode. Discard everything and
472 * return size so the caller doesn't freak out.
475 if (!(m->flags & M_RX))
476 return size;
478 for (i = sig = 0; i < size; i++) {
480 data = buf[i];
481 enq = 0;
482 if (data == MIDI_ACK)
483 continue;
485 switch (m->inq_state) {
486 case MIDI_IN_START:
487 if (MIDI_IS_STATUS(data)) {
488 switch (data) {
489 case 0xf0: /* Sysex */
490 m->inq_state = MIDI_IN_SYSEX;
491 break;
492 case 0xf1: /* MTC quarter frame */
493 case 0xf3: /* Song select */
494 m->inq_state = MIDI_IN_DATA;
495 enq = 1;
496 m->inq_left = 1;
497 break;
498 case 0xf2: /* Song position pointer */
499 m->inq_state = MIDI_IN_DATA;
500 enq = 1;
501 m->inq_left = 2;
502 break;
503 default:
504 if (MIDI_IS_COMMON(data)) {
505 enq = 1;
506 sig = 1;
507 } else {
508 m->inq_state = MIDI_IN_DATA;
509 enq = 1;
510 m->inq_status = data;
511 m->inq_left = MIDI_LENGTH(data);
513 break;
515 } else if (MIDI_IS_STATUS(m->inq_status)) {
516 m->inq_state = MIDI_IN_DATA;
517 if (!MIDIQ_FULL(m->inq)) {
518 used++;
519 MIDIQ_ENQ(m->inq, &m->inq_status, 1);
521 enq = 1;
522 m->inq_left = MIDI_LENGTH(m->inq_status) - 1;
524 break;
526 * End of case MIDI_IN_START:
529 case MIDI_IN_DATA:
530 enq = 1;
531 if (--m->inq_left <= 0)
532 sig = 1;/* deliver data */
533 break;
534 case MIDI_IN_SYSEX:
535 if (data == MIDI_SYSEX_END)
536 m->inq_state = MIDI_IN_START;
537 break;
540 if (enq)
541 if (!MIDIQ_FULL(m->inq)) {
542 MIDIQ_ENQ(m->inq, &data, 1);
543 used++;
546 * End of the state machines main "for loop"
549 if (sig) {
550 #endif
551 MIDI_DEBUG(6, kprintf("midi_in: len %jd avail %jd\n",
552 (intmax_t)MIDIQ_LEN(m->inq),
553 (intmax_t)MIDIQ_AVAIL(m->inq)));
554 if (MIDIQ_AVAIL(m->inq) > size) {
555 used = size;
556 MIDIQ_ENQ(m->inq, buf, size);
557 } else {
558 MIDI_DEBUG(4, kprintf("midi_in: Discarding data qu\n"));
559 lockmgr(&m->qlock, LK_RELEASE);
560 return 0;
562 if (m->rchan) {
563 wakeup(&m->rchan);
564 m->rchan = 0;
566 KNOTE(&m->rkq.ki_note, 0);
567 if (m->async) {
568 PHOLD(m->async);
569 ksignal(m->async, SIGIO);
570 PRELE(m->async);
572 #if 0
574 #endif
575 lockmgr(&m->qlock, LK_RELEASE);
576 return used;
580 * midi_out: The only clearer of the M_TXEN flag.
583 midi_out(struct snd_midi *m, MIDI_TYPE *buf, int size)
585 int used;
588 * XXX: locking flub
590 if (!(m->flags & M_TXEN))
591 return 0;
593 MIDI_DEBUG(2, kprintf("midi_out: %p\n", m));
594 lockmgr(&m->qlock, LK_EXCLUSIVE);
595 used = MIN(size, MIDIQ_LEN(m->outq));
596 MIDI_DEBUG(3, kprintf("midi_out: used %d\n", used));
597 if (used)
598 MIDIQ_DEQ(m->outq, buf, used);
599 if (MIDIQ_EMPTY(m->outq)) {
600 m->flags &= ~M_TXEN;
601 MPU_CALLBACKP(m, m->cookie, m->flags);
603 if (used && MIDIQ_AVAIL(m->outq) > m->hiwat) {
604 if (m->wchan) {
605 wakeup(&m->wchan);
606 m->wchan = 0;
608 KNOTE(&m->wkq.ki_note, 0);
609 if (m->async) {
610 PHOLD(m->async);
611 ksignal(m->async, SIGIO);
612 PRELE(m->async);
615 lockmgr(&m->qlock, LK_RELEASE);
616 return used;
621 * /dev/rmidi#.# device access functions
624 midi_open(struct dev_open_args *ap)
626 cdev_t i_dev = ap->a_head.a_dev;
627 int flags = ap->a_oflags;
628 struct snd_midi *m = i_dev->si_drv1;
629 int retval;
631 #if 0 /* XXX */
632 MIDI_DEBUG(1, kprintf("midiopen %p %s %s\n", td,
633 flags & FREAD ? "M_RX" : "", flags & FWRITE ? "M_TX" : ""));
634 #endif
635 if (m == NULL)
636 return ENXIO;
638 lockmgr(&m->lock, LK_EXCLUSIVE);
639 lockmgr(&m->qlock, LK_EXCLUSIVE);
641 retval = 0;
643 if (flags & FREAD) {
644 if (MIDIQ_SIZE(m->inq) == 0)
645 retval = ENXIO;
646 else if (m->flags & M_RX)
647 retval = EBUSY;
648 if (retval)
649 goto err;
651 if (flags & FWRITE) {
652 if (MIDIQ_SIZE(m->outq) == 0)
653 retval = ENXIO;
654 else if (m->flags & M_TX)
655 retval = EBUSY;
656 if (retval)
657 goto err;
659 m->busy++;
661 m->rchan = 0;
662 m->wchan = 0;
663 m->async = 0;
665 if (flags & FREAD) {
666 m->flags |= M_RX | M_RXEN;
668 * Only clear the inq, the outq might still have data to drain
669 * from a previous session
671 MIDIQ_CLEAR(m->inq);
674 if (flags & FWRITE)
675 m->flags |= M_TX;
677 MPU_CALLBACK(m, m->cookie, m->flags);
679 MIDI_DEBUG(2, kprintf("midi_open: opened.\n"));
681 err: lockmgr(&m->qlock, LK_RELEASE);
682 lockmgr(&m->lock, LK_RELEASE);
683 return retval;
687 midi_close(struct dev_close_args *ap)
689 cdev_t i_dev = ap->a_head.a_dev;
690 int flags = ap->a_fflag;
691 struct snd_midi *m = i_dev->si_drv1;
692 int retval;
693 int oldflags;
695 #if 0 /* XXX */
696 MIDI_DEBUG(1, kprintf("midi_close %p %s %s\n", td,
697 flags & FREAD ? "M_RX" : "", flags & FWRITE ? "M_TX" : ""));
698 #endif
700 if (m == NULL)
701 return ENXIO;
703 lockmgr(&m->lock, LK_EXCLUSIVE);
704 lockmgr(&m->qlock, LK_EXCLUSIVE);
706 if ((flags & FREAD && !(m->flags & M_RX)) ||
707 (flags & FWRITE && !(m->flags & M_TX))) {
708 retval = ENXIO;
709 goto err;
711 m->busy--;
713 oldflags = m->flags;
715 if (flags & FREAD)
716 m->flags &= ~(M_RX | M_RXEN);
717 if (flags & FWRITE)
718 m->flags &= ~M_TX;
720 if ((m->flags & (M_TXEN | M_RXEN)) != (oldflags & (M_RXEN | M_TXEN)))
721 MPU_CALLBACK(m, m->cookie, m->flags);
723 MIDI_DEBUG(1, kprintf("midi_close: closed, busy = %d.\n", m->busy));
725 lockmgr(&m->qlock, LK_RELEASE);
726 lockmgr(&m->lock, LK_RELEASE);
727 retval = 0;
728 err: return retval;
732 * TODO: midi_read, per oss programmer's guide pg. 42 should return as soon
733 * as data is available.
736 midi_read(struct dev_read_args *ap)
738 cdev_t i_dev = ap->a_head.a_dev;
739 struct uio *uio = ap->a_uio;
740 int ioflag = ap->a_ioflag;
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];
747 MIDI_DEBUG(5, kprintf("midiread: count=%lu\n",
748 (unsigned long)uio->uio_resid));
750 retval = EIO;
752 if (m == NULL)
753 goto err0;
755 lockmgr(&m->lock, LK_EXCLUSIVE);
756 lockmgr(&m->qlock, LK_EXCLUSIVE);
758 if (!(m->flags & M_RX))
759 goto err1;
761 while (uio->uio_resid > 0) {
762 while (MIDIQ_EMPTY(m->inq)) {
763 retval = EWOULDBLOCK;
764 if (ioflag & O_NONBLOCK)
765 goto err1;
766 lockmgr(&m->lock, LK_RELEASE);
767 m->rchan = 1;
768 retval = lksleep(&m->rchan, &m->qlock,
769 PCATCH, "midi RX", 0);
771 * We slept, maybe things have changed since last
772 * dying check
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 lockmgr(&m->lock, LK_EXCLUSIVE);
782 lockmgr(&m->qlock, LK_EXCLUSIVE);
783 m->rchan = 0;
784 if (!m->busy)
785 goto err1;
787 MIDI_DEBUG(6, kprintf("midi_read start\n"));
789 * At this point, it is certain that m->inq has data
792 used = MIN(MIDIQ_LEN(m->inq), uio->uio_resid);
793 used = MIN(used, MIDI_RSIZE);
795 MIDI_DEBUG(6, kprintf("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;
803 * If we Made it here then transfer is good
805 retval = 0;
806 err1: lockmgr(&m->qlock, LK_RELEASE);
807 lockmgr(&m->lock, LK_RELEASE);
808 err0: MIDI_DEBUG(4, kprintf("midi_read: ret %d\n", retval));
809 return retval;
813 * midi_write: The only setter of M_TXEN
817 midi_write(struct dev_write_args *ap)
819 cdev_t i_dev = ap->a_head.a_dev;
820 struct uio *uio = ap->a_uio;
821 int ioflag = ap->a_ioflag;
822 #define MIDI_WSIZE 32
823 struct snd_midi *m = i_dev->si_drv1;
824 int retval;
825 int used;
826 char buf[MIDI_WSIZE];
829 MIDI_DEBUG(4, kprintf("midi_write\n"));
830 retval = 0;
831 if (m == NULL)
832 goto err0;
834 lockmgr(&m->lock, LK_EXCLUSIVE);
835 lockmgr(&m->qlock, LK_EXCLUSIVE);
837 if (!(m->flags & M_TX))
838 goto err1;
840 while (uio->uio_resid > 0) {
841 while (MIDIQ_AVAIL(m->outq) == 0) {
842 retval = EWOULDBLOCK;
843 if (ioflag & O_NONBLOCK)
844 goto err1;
845 lockmgr(&m->lock, LK_RELEASE);
846 m->wchan = 1;
847 MIDI_DEBUG(3, kprintf("midi_write lksleep\n"));
848 retval = lksleep(&m->wchan, &m->qlock,
849 PCATCH, "midi TX", 0);
851 * We slept, maybe things have changed since last
852 * dying check
854 if (retval == EINTR)
855 goto err0;
856 if (m != i_dev->si_drv1)
857 retval = ENXIO;
858 if (retval)
859 goto err0;
860 lockmgr(&m->lock, LK_EXCLUSIVE);
861 lockmgr(&m->qlock, LK_EXCLUSIVE);
862 m->wchan = 0;
863 if (!m->busy)
864 goto err1;
868 * We are certain than data can be placed on the queue
871 used = MIN(MIDIQ_AVAIL(m->outq), uio->uio_resid);
872 used = MIN(used, MIDI_WSIZE);
873 MIDI_DEBUG(5, kprintf("midiout: resid %zd len %jd avail %jd\n",
874 uio->uio_resid, (intmax_t)MIDIQ_LEN(m->outq),
875 (intmax_t)MIDIQ_AVAIL(m->outq)));
878 MIDI_DEBUG(5, kprintf("midi_write: uiomove cc=%d\n", used));
879 retval = uiomove(buf, used, uio);
880 if (retval)
881 goto err1;
882 MIDIQ_ENQ(m->outq, buf, used);
884 * Inform the bottom half that data can be written
886 if (!(m->flags & M_TXEN)) {
887 m->flags |= M_TXEN;
888 MPU_CALLBACK(m, m->cookie, m->flags);
892 * If we Made it here then transfer is good
894 retval = 0;
895 err1: lockmgr(&m->qlock, LK_RELEASE);
896 lockmgr(&m->lock, LK_RELEASE);
897 err0: return retval;
901 midi_ioctl(struct dev_ioctl_args *ap)
903 return ENXIO;
907 midi_kqfilter(struct dev_kqfilter_args *ap)
909 cdev_t dev = ap->a_head.a_dev;
910 struct knote *kn = ap->a_kn;
911 struct snd_midi *m;
912 struct klist *klist;
914 ap->a_result = 0;
915 m = dev->si_drv1;
917 switch (kn->kn_filter) {
918 case EVFILT_READ:
919 kn->kn_fop = &midi_read_filterops;
920 kn->kn_hook = (caddr_t)m;
921 klist = &m->rkq.ki_note;
922 break;
923 case EVFILT_WRITE:
924 kn->kn_fop = &midi_write_filterops;
925 kn->kn_hook = (caddr_t)m;
926 klist = &m->wkq.ki_note;
927 break;
928 default:
929 ap->a_result = EOPNOTSUPP;
930 return (0);
933 knote_insert(klist, kn);
935 return(0);
938 static void
939 midi_filter_detach(struct knote *kn)
941 struct snd_midi *m = (struct snd_midi *)kn->kn_hook;
942 struct klist *rklist = &m->rkq.ki_note;
943 struct klist *wklist = &m->wkq.ki_note;
945 knote_remove(rklist, kn);
946 knote_remove(wklist, kn);
949 static int
950 midi_filter_read(struct knote *kn, long hint)
952 struct snd_midi *m = (struct snd_midi *)kn->kn_hook;
953 int ready = 0;
955 lockmgr(&m->lock, LK_EXCLUSIVE);
956 lockmgr(&m->qlock, LK_EXCLUSIVE);
958 if (!MIDIQ_EMPTY(m->inq))
959 ready = 1;
961 lockmgr(&m->lock, LK_RELEASE);
962 lockmgr(&m->qlock, LK_RELEASE);
964 return (ready);
967 static int
968 midi_filter_write(struct knote *kn, long hint)
970 struct snd_midi *m = (struct snd_midi *)kn->kn_hook;
971 int ready = 0;
973 lockmgr(&m->lock, LK_EXCLUSIVE);
974 lockmgr(&m->qlock, LK_EXCLUSIVE);
976 if (MIDIQ_AVAIL(m->outq) < m->hiwat)
977 ready = 1;
979 lockmgr(&m->lock, LK_RELEASE);
980 lockmgr(&m->qlock, LK_RELEASE);
982 return (ready);
986 * /dev/midistat device functions
989 static int
990 midistat_open(struct dev_open_args *ap)
992 int error;
994 MIDI_DEBUG(1, kprintf("midistat_open\n"));
995 lockmgr(&midistat_lock, LK_EXCLUSIVE);
997 if (midistat_isopen) {
998 lockmgr(&midistat_lock, LK_RELEASE);
999 return EBUSY;
1001 midistat_isopen = 1;
1002 lockmgr(&midistat_lock, LK_RELEASE);
1004 if (sbuf_new(&midistat_sbuf, NULL, 4096, SBUF_AUTOEXTEND) == NULL) {
1005 error = ENXIO;
1006 lockmgr(&midistat_lock, LK_EXCLUSIVE);
1007 goto out;
1009 lockmgr(&midistat_lock, LK_EXCLUSIVE);
1010 midistat_bufptr = 0;
1011 error = (midistat_prepare(&midistat_sbuf) > 0) ? 0 : ENOMEM;
1013 out: if (error)
1014 midistat_isopen = 0;
1015 lockmgr(&midistat_lock, LK_RELEASE);
1016 return error;
1019 static int
1020 midistat_close(struct dev_close_args *ap)
1022 MIDI_DEBUG(1, kprintf("midistat_close\n"));
1023 lockmgr(&midistat_lock, LK_EXCLUSIVE);
1024 if (!midistat_isopen) {
1025 lockmgr(&midistat_lock, LK_RELEASE);
1026 return EBADF;
1028 sbuf_delete(&midistat_sbuf);
1029 midistat_isopen = 0;
1031 lockmgr(&midistat_lock, LK_RELEASE);
1032 return 0;
1035 static int
1036 midistat_read(struct dev_read_args *ap)
1038 struct uio *buf = ap->a_uio;
1039 int l, err;
1041 MIDI_DEBUG(4, kprintf("midistat_read\n"));
1042 lockmgr(&midistat_lock, LK_EXCLUSIVE);
1043 if (!midistat_isopen) {
1044 lockmgr(&midistat_lock, LK_RELEASE);
1045 return EBADF;
1047 l = min(buf->uio_resid, sbuf_len(&midistat_sbuf) - midistat_bufptr);
1048 err = 0;
1049 if (l > 0) {
1050 lockmgr(&midistat_lock, LK_RELEASE);
1051 err = uiomove(sbuf_data(&midistat_sbuf) + midistat_bufptr, l,
1052 buf);
1053 lockmgr(&midistat_lock, LK_EXCLUSIVE);
1054 } else
1055 l = 0;
1056 midistat_bufptr += l;
1057 lockmgr(&midistat_lock, LK_RELEASE);
1058 return err;
1062 * Module library functions
1065 static int
1066 midistat_prepare(struct sbuf *s)
1068 struct snd_midi *m;
1070 KKASSERT(lockowned(&midistat_lock));
1072 sbuf_printf(s, "FreeBSD Midi Driver (midi2)\n");
1073 if (TAILQ_EMPTY(&midi_devs)) {
1074 sbuf_printf(s, "No devices installed.\n");
1075 sbuf_finish(s);
1076 return sbuf_len(s);
1078 sbuf_printf(s, "Installed devices:\n");
1080 TAILQ_FOREACH(m, &midi_devs, link) {
1081 lockmgr(&m->lock, LK_EXCLUSIVE);
1082 sbuf_printf(s, "%s [%d/%d:%s]", m->name, m->unit, m->channel,
1083 MPU_PROVIDER(m, m->cookie));
1084 sbuf_printf(s, "%s", MPU_DESCR(m, m->cookie, midistat_verbose));
1085 sbuf_printf(s, "\n");
1086 lockmgr(&m->lock, LK_RELEASE);
1089 sbuf_finish(s);
1090 return sbuf_len(s);
1093 #ifdef notdef
1095 * Convert IOCTL command to string for debugging
1098 static char *
1099 midi_cmdname(int cmd)
1101 static struct {
1102 int cmd;
1103 char *name;
1104 } *tab, cmdtab_midiioctl[] = {
1105 #define A(x) {x, ## x}
1107 * Once we have some real IOCTLs define, the following will
1108 * be relavant.
1110 * A(SNDCTL_MIDI_PRETIME), A(SNDCTL_MIDI_MPUMODE),
1111 * A(SNDCTL_MIDI_MPUCMD), A(SNDCTL_SYNTH_INFO),
1112 * A(SNDCTL_MIDI_INFO), A(SNDCTL_SYNTH_MEMAVL),
1113 * A(SNDCTL_FM_LOAD_INSTR), A(SNDCTL_FM_4OP_ENABLE),
1114 * A(MIOSPASSTHRU), A(MIOGPASSTHRU), A(AIONWRITE),
1115 * A(AIOGSIZE), A(AIOSSIZE), A(AIOGFMT), A(AIOSFMT),
1116 * A(AIOGMIX), A(AIOSMIX), A(AIOSTOP), A(AIOSYNC),
1117 * A(AIOGCAP),
1119 #undef A
1121 -1, "unknown"
1125 for (tab = cmdtab_midiioctl; tab->cmd != cmd && tab->cmd != -1; tab++);
1126 return tab->name;
1129 #endif /* notdef */
1132 * midisynth
1137 midisynth_open(void *n, void *arg, int flags)
1139 struct snd_midi *m = ((struct synth_midi *)n)->m;
1140 int retval;
1142 MIDI_DEBUG(1, kprintf("midisynth_open %s %s\n",
1143 flags & FREAD ? "M_RX" : "", flags & FWRITE ? "M_TX" : ""));
1145 if (m == NULL)
1146 return ENXIO;
1148 lockmgr(&m->lock, LK_EXCLUSIVE);
1149 lockmgr(&m->qlock, LK_EXCLUSIVE);
1151 retval = 0;
1153 if (flags & FREAD) {
1154 if (MIDIQ_SIZE(m->inq) == 0)
1155 retval = ENXIO;
1156 else if (m->flags & M_RX)
1157 retval = EBUSY;
1158 if (retval)
1159 goto err;
1161 if (flags & FWRITE) {
1162 if (MIDIQ_SIZE(m->outq) == 0)
1163 retval = ENXIO;
1164 else if (m->flags & M_TX)
1165 retval = EBUSY;
1166 if (retval)
1167 goto err;
1169 m->busy++;
1172 * TODO: Consider m->async = 0;
1175 if (flags & FREAD) {
1176 m->flags |= M_RX | M_RXEN;
1178 * Only clear the inq, the outq might still have data to drain
1179 * from a previous session
1181 MIDIQ_CLEAR(m->inq);
1182 m->rchan = 0;
1185 if (flags & FWRITE) {
1186 m->flags |= M_TX;
1187 m->wchan = 0;
1189 m->synth_flags = flags & (FREAD | FWRITE);
1191 MPU_CALLBACK(m, m->cookie, m->flags);
1194 err: lockmgr(&m->qlock, LK_RELEASE);
1195 lockmgr(&m->lock, LK_RELEASE);
1196 MIDI_DEBUG(2, kprintf("midisynth_open: return %d.\n", retval));
1197 return retval;
1201 midisynth_close(void *n)
1203 struct snd_midi *m = ((struct synth_midi *)n)->m;
1204 int retval;
1205 int oldflags;
1207 MIDI_DEBUG(1, kprintf("midisynth_close %s %s\n",
1208 m->synth_flags & FREAD ? "M_RX" : "",
1209 m->synth_flags & FWRITE ? "M_TX" : ""));
1211 if (m == NULL)
1212 return ENXIO;
1214 lockmgr(&m->lock, LK_EXCLUSIVE);
1215 lockmgr(&m->qlock, LK_EXCLUSIVE);
1217 if ((m->synth_flags & FREAD && !(m->flags & M_RX)) ||
1218 (m->synth_flags & FWRITE && !(m->flags & M_TX))) {
1219 retval = ENXIO;
1220 goto err;
1222 m->busy--;
1224 oldflags = m->flags;
1226 if (m->synth_flags & FREAD)
1227 m->flags &= ~(M_RX | M_RXEN);
1228 if (m->synth_flags & FWRITE)
1229 m->flags &= ~M_TX;
1231 if ((m->flags & (M_TXEN | M_RXEN)) != (oldflags & (M_RXEN | M_TXEN)))
1232 MPU_CALLBACK(m, m->cookie, m->flags);
1234 MIDI_DEBUG(1, kprintf("midi_close: closed, busy = %d.\n", m->busy));
1236 lockmgr(&m->qlock, LK_RELEASE);
1237 lockmgr(&m->lock, LK_RELEASE);
1238 retval = 0;
1239 err: return retval;
1243 * Always blocking.
1247 midisynth_writeraw(void *n, uint8_t *buf, size_t len)
1249 struct snd_midi *m = ((struct synth_midi *)n)->m;
1250 int retval;
1251 int used;
1252 int i;
1254 MIDI_DEBUG(4, kprintf("midisynth_writeraw\n"));
1256 retval = 0;
1258 if (m == NULL)
1259 return ENXIO;
1261 lockmgr(&m->lock, LK_EXCLUSIVE);
1262 lockmgr(&m->qlock, LK_EXCLUSIVE);
1264 if (!(m->flags & M_TX))
1265 goto err1;
1267 if (midi_dumpraw)
1268 kprintf("midi dump: ");
1270 while (len > 0) {
1271 while (MIDIQ_AVAIL(m->outq) == 0) {
1272 if (!(m->flags & M_TXEN)) {
1273 m->flags |= M_TXEN;
1274 MPU_CALLBACK(m, m->cookie, m->flags);
1276 lockmgr(&m->lock, LK_RELEASE);
1277 m->wchan = 1;
1278 MIDI_DEBUG(3, kprintf("midisynth_writeraw lksleep\n"));
1279 retval = lksleep(&m->wchan, &m->qlock,
1280 PCATCH, "midi TX", 0);
1282 * We slept, maybe things have changed since last
1283 * dying check
1285 if (retval == EINTR)
1286 goto err0;
1288 if (retval)
1289 goto err0;
1290 lockmgr(&m->lock, LK_EXCLUSIVE);
1291 lockmgr(&m->qlock, LK_EXCLUSIVE);
1292 m->wchan = 0;
1293 if (!m->busy)
1294 goto err1;
1298 * We are certain than data can be placed on the queue
1301 used = MIN(MIDIQ_AVAIL(m->outq), len);
1302 used = MIN(used, MIDI_WSIZE);
1303 MIDI_DEBUG(5,
1304 kprintf("midi_synth: resid %zu len %jd avail %jd\n",
1305 len, (intmax_t)MIDIQ_LEN(m->outq),
1306 (intmax_t)MIDIQ_AVAIL(m->outq)));
1308 if (midi_dumpraw)
1309 for (i = 0; i < used; i++)
1310 kprintf("%x ", buf[i]);
1312 MIDIQ_ENQ(m->outq, buf, used);
1313 len -= used;
1316 * Inform the bottom half that data can be written
1318 if (!(m->flags & M_TXEN)) {
1319 m->flags |= M_TXEN;
1320 MPU_CALLBACK(m, m->cookie, m->flags);
1324 * If we Made it here then transfer is good
1326 if (midi_dumpraw)
1327 kprintf("\n");
1329 retval = 0;
1330 err1: lockmgr(&m->qlock, LK_RELEASE);
1331 lockmgr(&m->lock, LK_RELEASE);
1332 err0: return retval;
1335 static int
1336 midisynth_killnote(void *n, uint8_t chn, uint8_t note, uint8_t vel)
1338 u_char c[3];
1341 if (note > 127 || chn > 15)
1342 return (EINVAL);
1344 if (vel > 127)
1345 vel = 127;
1347 if (vel == 64) {
1348 c[0] = 0x90 | (chn & 0x0f); /* Note on. */
1349 c[1] = (u_char)note;
1350 c[2] = 0;
1351 } else {
1352 c[0] = 0x80 | (chn & 0x0f); /* Note off. */
1353 c[1] = (u_char)note;
1354 c[2] = (u_char)vel;
1357 return midisynth_writeraw(n, c, 3);
1360 static int
1361 midisynth_setinstr(void *n, uint8_t chn, uint16_t instr)
1363 u_char c[2];
1365 if (instr > 127 || chn > 15)
1366 return EINVAL;
1368 c[0] = 0xc0 | (chn & 0x0f); /* Progamme change. */
1369 c[1] = instr + midi_instroff;
1371 return midisynth_writeraw(n, c, 2);
1374 static int
1375 midisynth_startnote(void *n, uint8_t chn, uint8_t note, uint8_t vel)
1377 u_char c[3];
1379 if (note > 127 || chn > 15)
1380 return EINVAL;
1382 if (vel > 127)
1383 vel = 127;
1385 c[0] = 0x90 | (chn & 0x0f); /* Note on. */
1386 c[1] = (u_char)note;
1387 c[2] = (u_char)vel;
1389 return midisynth_writeraw(n, c, 3);
1391 static int
1392 midisynth_alloc(void *n, uint8_t chan, uint8_t note)
1394 return chan;
1397 static int
1398 midisynth_controller(void *n, uint8_t chn, uint8_t ctrlnum, uint16_t val)
1400 u_char c[3];
1402 if (ctrlnum > 127 || chn > 15)
1403 return EINVAL;
1405 c[0] = 0xb0 | (chn & 0x0f); /* Control Message. */
1406 c[1] = ctrlnum;
1407 c[2] = val;
1408 return midisynth_writeraw(n, c, 3);
1411 static int
1412 midisynth_bender(void *n, uint8_t chn, uint16_t val)
1414 u_char c[3];
1417 if (val > 16383 || chn > 15)
1418 return EINVAL;
1420 c[0] = 0xe0 | (chn & 0x0f); /* Pitch bend. */
1421 c[1] = (u_char)val & 0x7f;
1422 c[2] = (u_char)(val >> 7) & 0x7f;
1424 return midisynth_writeraw(n, c, 3);
1428 * Single point of midi destructions.
1430 static int
1431 midi_destroy(struct snd_midi *m, int midiuninit)
1434 KKASSERT(lockowned(&midistat_lock));
1435 KKASSERT(lockowned(&m->lock));
1437 MIDI_DEBUG(3, kprintf("midi_destroy\n"));
1438 m->dev->si_drv1 = NULL;
1439 lockmgr(&m->lock, LK_RELEASE); /* XXX */
1440 destroy_dev(m->dev);
1441 TAILQ_REMOVE(&midi_devs, m, link);
1442 if (midiuninit)
1443 MPU_UNINIT(m, m->cookie);
1444 kfree(MIDIQ_BUF(m->inq), M_MIDI);
1445 kfree(MIDIQ_BUF(m->outq), M_MIDI);
1446 lockuninit(&m->qlock);
1447 lockuninit(&m->lock);
1448 kfree(m, M_MIDI);
1449 return 0;
1453 * Load and unload functions, creates the /dev/midistat device
1456 static int
1457 midi_load(void)
1459 lockinit(&midistat_lock, "midistat lock", 0, LK_CANRECURSE);
1460 TAILQ_INIT(&midi_devs); /* Initialize the queue. */
1462 midistat_dev = make_dev(&midistat_ops,
1463 MIDIMKMINOR(0, MIDI_DEV_MIDICTL, 0),
1464 UID_ROOT, GID_WHEEL, 0666, "midistat");
1466 return 0;
1469 static int
1470 midi_unload(void)
1472 struct snd_midi *m;
1473 int retval;
1475 MIDI_DEBUG(1, kprintf("midi_unload()\n"));
1476 retval = EBUSY;
1477 lockmgr(&midistat_lock, LK_EXCLUSIVE);
1478 if (midistat_isopen)
1479 goto exit0;
1481 TAILQ_FOREACH(m, &midi_devs, link) {
1482 lockmgr(&m->lock, LK_EXCLUSIVE);
1483 if (m->busy)
1484 retval = EBUSY;
1485 else
1486 retval = midi_destroy(m, 1);
1487 if (retval)
1488 goto exit1;
1491 lockmgr(&midistat_lock, LK_RELEASE); /* XXX */
1493 destroy_dev(midistat_dev);
1495 * Made it here then unload is complete
1497 lockuninit(&midistat_lock);
1498 return 0;
1500 exit1:
1501 lockmgr(&m->lock, LK_RELEASE);
1502 exit0:
1503 lockmgr(&midistat_lock, LK_RELEASE);
1504 if (retval)
1505 MIDI_DEBUG(2, kprintf("midi_unload: failed\n"));
1506 return retval;
1509 extern int seq_modevent(module_t mod, int type, void *data);
1511 static int
1512 midi_modevent(module_t mod, int type, void *data)
1514 int retval;
1516 retval = 0;
1518 switch (type) {
1519 case MOD_LOAD:
1520 retval = midi_load();
1521 #if 0
1522 if (retval == 0)
1523 retval = seq_modevent(mod, type, data);
1524 #endif
1525 break;
1527 case MOD_UNLOAD:
1528 retval = midi_unload();
1529 #if 0
1530 if (retval == 0)
1531 retval = seq_modevent(mod, type, data);
1532 #endif
1533 break;
1535 default:
1536 break;
1539 return retval;
1542 kobj_t
1543 midimapper_addseq(void *arg1, int *unit, void **cookie)
1545 unit = 0;
1547 return (kobj_t)arg1;
1551 midimapper_open(void *arg1, void **cookie)
1553 int retval = 0;
1554 struct snd_midi *m;
1556 lockmgr(&midistat_lock, LK_EXCLUSIVE);
1558 TAILQ_FOREACH(m, &midi_devs, link) {
1559 retval++;
1562 lockmgr(&midistat_lock, LK_RELEASE);
1563 return retval;
1567 midimapper_close(void *arg1, void *cookie)
1569 return 0;
1572 kobj_t
1573 midimapper_fetch_synth(void *arg, void *cookie, int unit)
1575 struct snd_midi *m;
1576 int retval = 0;
1578 lockmgr(&midistat_lock, LK_EXCLUSIVE);
1580 TAILQ_FOREACH(m, &midi_devs, link) {
1581 if (unit == retval) {
1582 lockmgr(&midistat_lock, LK_RELEASE);
1583 return (kobj_t)m->synth;
1585 retval++;
1588 lockmgr(&midistat_lock, LK_RELEASE);
1589 return NULL;
1592 DEV_MODULE(midi, midi_modevent, NULL);
1593 MODULE_VERSION(midi, 1);