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