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