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