The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/sound/midi/midi.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

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

Cache object: f6be434bc1e98de1374da6f013ae3b71


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.