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