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