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