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