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/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 /*      $NetBSD: midi.c,v 1.68 2008/06/12 22:29:41 cegger Exp $ */
    2 
    3 /*
    4  * Copyright (c) 1998 The NetBSD Foundation, Inc.
    5  * All rights reserved.
    6  *
    7  * This code is derived from software contributed to The NetBSD Foundation
    8  * by Lennart Augustsson (augustss@NetBSD.org) and (MIDI FST and Active
    9  * Sense handling) Chapman Flack (chap@NetBSD.org).
   10  *
   11  * Redistribution and use in source and binary forms, with or without
   12  * modification, are permitted provided that the following conditions
   13  * are met:
   14  * 1. Redistributions of source code must retain the above copyright
   15  *    notice, this list of conditions and the following disclaimer.
   16  * 2. Redistributions in binary form must reproduce the above copyright
   17  *    notice, this list of conditions and the following disclaimer in the
   18  *    documentation and/or other materials provided with the distribution.
   19  *
   20  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
   21  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
   22  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   23  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
   24  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   25  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   26  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   27  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   28  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   29  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   30  * POSSIBILITY OF SUCH DAMAGE.
   31  */
   32 
   33 #include <sys/cdefs.h>
   34 __KERNEL_RCSID(0, "$NetBSD: midi.c,v 1.68 2008/06/12 22:29:41 cegger Exp $");
   35 
   36 #include "midi.h"
   37 #include "sequencer.h"
   38 
   39 #include <sys/param.h>
   40 #include <sys/ioctl.h>
   41 #include <sys/fcntl.h>
   42 #include <sys/vnode.h>
   43 #include <sys/select.h>
   44 #include <sys/poll.h>
   45 #include <sys/malloc.h>
   46 #include <sys/proc.h>
   47 #include <sys/systm.h>
   48 #include <sys/callout.h>
   49 #include <sys/syslog.h>
   50 #include <sys/kernel.h>
   51 #include <sys/signalvar.h>
   52 #include <sys/conf.h>
   53 #include <sys/audioio.h>
   54 #include <sys/midiio.h>
   55 #include <sys/device.h>
   56 #include <sys/intr.h>
   57 
   58 #include <dev/audio_if.h>
   59 #include <dev/midi_if.h>
   60 #include <dev/midivar.h>
   61 
   62 #if NMIDI > 0
   63 
   64 #ifdef AUDIO_DEBUG
   65 #define DPRINTF(x)      if (mididebug) printf x
   66 #define DPRINTFN(n,x)   if (mididebug >= (n)) printf x
   67 int     mididebug = 0;
   68 /*
   69  *      1: detected protocol errors and buffer overflows
   70  *      2: probe, attach, detach
   71  *      3: open, close
   72  *      4: data received except realtime
   73  *      5: ioctl
   74  *      6: read, write, poll
   75  *      7: data transmitted
   76  *      8: uiomoves, synchronization
   77  *      9: realtime data received
   78  */
   79 #else
   80 #define DPRINTF(x)
   81 #define DPRINTFN(n,x)
   82 #endif
   83 
   84 static  struct simplelock hwif_register_lock = SIMPLELOCK_INITIALIZER;
   85 static  struct midi_softc *hwif_softc = NULL;
   86 
   87 void    midi_in(void *, int);
   88 void    midi_out(void *);
   89 int     midi_poll_out(struct midi_softc *);
   90 int     midi_intr_out(struct midi_softc *);
   91 int     midi_msg_out(struct midi_softc *,
   92                  u_char **, u_char **, u_char **, u_char **);
   93 int     midi_start_output(struct midi_softc *);
   94 int     midi_sleep_timo(int *, const char *, int, struct simplelock *);
   95 int     midi_sleep(int *, const char *, struct simplelock *);
   96 void    midi_wakeup(int *);
   97 void    midi_initbuf(struct midi_buffer *);
   98 void    midi_xmt_asense(void *);
   99 void    midi_rcv_asense(void *);
  100 void    midi_softintr_rd(void *);
  101 void    midi_softintr_wr(void *);
  102 
  103 int     midiprobe(device_t, cfdata_t, void *);
  104 void    midiattach(device_t, device_t, void *);
  105 int     mididetach(device_t, int);
  106 int     midiactivate(device_t, enum devact);
  107 
  108 dev_type_open(midiopen);
  109 dev_type_close(midiclose);
  110 dev_type_read(midiread);
  111 dev_type_write(midiwrite);
  112 dev_type_ioctl(midiioctl);
  113 dev_type_poll(midipoll);
  114 dev_type_kqfilter(midikqfilter);
  115 
  116 const struct cdevsw midi_cdevsw = {
  117         midiopen, midiclose, midiread, midiwrite, midiioctl,
  118         nostop, notty, midipoll, nommap, midikqfilter, D_OTHER,
  119 };
  120 
  121 CFATTACH_DECL_NEW(midi, sizeof(struct midi_softc),
  122     midiprobe, midiattach, mididetach, midiactivate);
  123 
  124 #define MIDI_XMT_ASENSE_PERIOD mstohz(275)
  125 #define MIDI_RCV_ASENSE_PERIOD mstohz(300)
  126 
  127 extern struct cfdriver midi_cd;
  128 
  129 int
  130 midiprobe(device_t parent, cfdata_t match, void *aux)
  131 {
  132         struct audio_attach_args *sa = aux;
  133 
  134         DPRINTFN(2,("midiprobe: type=%d sa=%p hw=%p\n",
  135                  sa->type, sa, sa->hwif));
  136         return (sa->type == AUDIODEV_TYPE_MIDI);
  137 }
  138 
  139 void
  140 midiattach(device_t parent, device_t self, void *aux)
  141 {
  142         struct midi_softc *sc = device_private(self);
  143         struct audio_attach_args *sa = aux;
  144         const struct midi_hw_if *hwp = sa->hwif;
  145         void *hdlp = sa->hdl;
  146 
  147         aprint_naive("\n");
  148 
  149         DPRINTFN(2, ("MIDI attach\n"));
  150 
  151 #ifdef DIAGNOSTIC
  152         if (hwp == 0 ||
  153             hwp->open == 0 ||
  154             hwp->close == 0 ||
  155             hwp->output == 0 ||
  156             hwp->getinfo == 0) {
  157                 printf("midi: missing method\n");
  158                 return;
  159         }
  160 #endif
  161 
  162         sc->dev = self;
  163         sc->hw_if = hwp;
  164         sc->hw_hdl = hdlp;
  165         midi_attach(sc, parent);
  166         if (!device_pmf_is_registered(self))
  167                 if (!pmf_device_register(self, NULL, NULL))
  168                         aprint_error_dev(self,
  169                             "couldn't establish power handler\n"); 
  170 }
  171 
  172 int
  173 midiactivate(device_t self, enum devact act)
  174 {
  175         struct midi_softc *sc = device_private(self);
  176 
  177         switch (act) {
  178         case DVACT_ACTIVATE:
  179                 return (EOPNOTSUPP);
  180 
  181         case DVACT_DEACTIVATE:
  182                 sc->dying = 1;
  183                 break;
  184         }
  185         return (0);
  186 }
  187 
  188 int
  189 mididetach(device_t self, int flags)
  190 {
  191         struct midi_softc *sc = device_private(self);
  192         int maj, mn;
  193 
  194         DPRINTFN(2,("midi_detach: sc=%p flags=%d\n", sc, flags));
  195 
  196         pmf_device_deregister(self);
  197 
  198         sc->dying = 1;
  199 
  200         wakeup(&sc->wchan);
  201         wakeup(&sc->rchan);
  202 
  203         /* locate the major number */
  204         maj = cdevsw_lookup_major(&midi_cdevsw);
  205 
  206         /* Nuke the vnodes for any open instances (calls close). */
  207         mn = device_unit(self);
  208         vdevgone(maj, mn, mn, VCHR);
  209         
  210         if ( !(sc->props & MIDI_PROP_NO_OUTPUT) ) {
  211                 evcnt_detach(&sc->xmt.bytesDiscarded);
  212                 evcnt_detach(&sc->xmt.incompleteMessages);
  213         }
  214         if ( sc->props & MIDI_PROP_CAN_INPUT ) {
  215                 evcnt_detach(&sc->rcv.bytesDiscarded);
  216                 evcnt_detach(&sc->rcv.incompleteMessages);
  217         }
  218 
  219         if (sc->sih_rd != NULL) {
  220                 softint_disestablish(sc->sih_rd);
  221                 sc->sih_rd = NULL;
  222         }
  223         if (sc->sih_wr != NULL) {
  224                 softint_disestablish(sc->sih_wr);
  225                 sc->sih_wr = NULL;
  226         }
  227 
  228         return (0);
  229 }
  230 
  231 void
  232 midi_attach(struct midi_softc *sc, device_t parent)
  233 {
  234         struct midi_info mi;
  235         int s;
  236 
  237         callout_init(&sc->xmt_asense_co, 0);
  238         callout_init(&sc->rcv_asense_co, 0);
  239         callout_setfunc(&sc->xmt_asense_co, midi_xmt_asense, sc);
  240         callout_setfunc(&sc->rcv_asense_co, midi_rcv_asense, sc);
  241         simple_lock_init(&sc->out_lock);
  242         simple_lock_init(&sc->in_lock);
  243         sc->dying = 0;
  244         sc->isopen = 0;
  245 
  246         sc->sc_dev = parent;
  247 
  248         sc->sih_rd = softint_establish(SOFTINT_SERIAL, midi_softintr_rd, sc);
  249         sc->sih_wr = softint_establish(SOFTINT_SERIAL, midi_softintr_wr, sc);
  250 
  251         s = splaudio();
  252         simple_lock(&hwif_register_lock);
  253         hwif_softc = sc;
  254         sc->hw_if->getinfo(sc->hw_hdl, &mi);
  255         hwif_softc = NULL;
  256         simple_unlock(&hwif_register_lock);
  257         splx(s);
  258         
  259         sc->props = mi.props;
  260         
  261         if ( !(sc->props & MIDI_PROP_NO_OUTPUT) ) {
  262                 evcnt_attach_dynamic(&sc->xmt.bytesDiscarded,
  263                         EVCNT_TYPE_MISC, NULL,
  264                         device_xname(sc->dev), "xmt bytes discarded");
  265                 evcnt_attach_dynamic(&sc->xmt.incompleteMessages,
  266                         EVCNT_TYPE_MISC, NULL,
  267                         device_xname(sc->dev), "xmt incomplete msgs");
  268         }
  269         if ( sc->props & MIDI_PROP_CAN_INPUT ) {
  270                 evcnt_attach_dynamic(&sc->rcv.bytesDiscarded,
  271                         EVCNT_TYPE_MISC, NULL,
  272                         device_xname(sc->dev), "rcv bytes discarded");
  273                 evcnt_attach_dynamic(&sc->rcv.incompleteMessages,
  274                         EVCNT_TYPE_MISC, NULL,
  275                         device_xname(sc->dev), "rcv incomplete msgs");
  276         }
  277         
  278         aprint_normal(": %s%s\n", mi.name,
  279             (sc->props & (MIDI_PROP_OUT_INTR|MIDI_PROP_NO_OUTPUT)) ?
  280             "" : " (CPU-intensive output)");
  281 }
  282 
  283 void midi_register_hw_if_ext(struct midi_hw_if_ext *exthw) {
  284         if ( hwif_softc != NULL ) /* ignore calls resulting from non-init */
  285                 hwif_softc->hw_if_ext = exthw; /* uses of getinfo */
  286 }
  287 
  288 int
  289 midi_unit_count(void)
  290 {
  291         int i;
  292         for ( i = 0; i < midi_cd.cd_ndevs; ++i )
  293                 if ( NULL == device_lookup(&midi_cd, i) )
  294                         break;
  295         return i;
  296 }
  297 
  298 void
  299 midi_initbuf(struct midi_buffer *mb)
  300 {
  301         mb->idx_producerp = mb->idx_consumerp = mb->idx;
  302         mb->buf_producerp = mb->buf_consumerp = mb->buf;
  303 }
  304 #define PACK_MB_IDX(cat,len) (((cat)<<4)|(len))
  305 #define MB_IDX_CAT(idx) ((idx)>>4)
  306 #define MB_IDX_LEN(idx) ((idx)&0xf)
  307 
  308 int
  309 midi_sleep_timo(int *chan, const char *label, int timo, struct simplelock *lk)
  310 {
  311         int st;
  312 
  313         if (!label)
  314                 label = "midi";
  315 
  316         DPRINTFN(8, ("midi_sleep_timo: %p %s %d\n", chan, label, timo));
  317         *chan = 1;
  318         st = ltsleep(chan, PWAIT | PCATCH, label, timo, lk);
  319         *chan = 0;
  320 #ifdef MIDI_DEBUG
  321         if (st != 0)
  322                 printf("midi_sleep: %d\n", st);
  323 #endif
  324         return st;
  325 }
  326 
  327 int
  328 midi_sleep(int *chan, const char *label, struct simplelock *lk)
  329 {
  330         return midi_sleep_timo(chan, label, 0, lk);
  331 }
  332 
  333 void
  334 midi_wakeup(int *chan)
  335 {
  336         if (*chan) {
  337                 DPRINTFN(8, ("midi_wakeup: %p\n", chan));
  338                 wakeup(chan);
  339                 *chan = 0;
  340         }
  341 }
  342 
  343 /* in midivar.h:
  344 #define MIDI_CAT_DATA 0
  345 #define MIDI_CAT_STATUS1 1
  346 #define MIDI_CAT_STATUS2 2
  347 #define MIDI_CAT_COMMON 3
  348 */
  349 static char const midi_cats[] = "\0\0\0\0\0\0\0\0\2\2\2\2\1\1\2\3";
  350 #define MIDI_CAT(d) (midi_cats[((d)>>4)&15])
  351 #define FST_RETURN(offp,endp,ret) \
  352         return (s->pos=s->msg+(offp)), (s->end=s->msg+(endp)), (ret)
  353 
  354 enum fst_ret { FST_CHN, FST_CHV, FST_COM, FST_SYX, FST_RT, FST_MORE, FST_ERR,
  355                FST_HUH, FST_SXP };
  356 enum fst_form { FST_CANON, FST_COMPR, FST_VCOMP };
  357 static struct {
  358         int off;
  359         enum fst_ret tag;
  360 } const midi_forms[] = {
  361         [FST_CANON] = { .off=0, .tag=FST_CHN },
  362         [FST_COMPR] = { .off=1, .tag=FST_CHN },
  363         [FST_VCOMP] = { .off=0, .tag=FST_CHV }
  364 };
  365 #define FST_CRETURN(endp) \
  366         FST_RETURN(midi_forms[form].off,endp,midi_forms[form].tag)
  367 
  368 /*
  369  * A MIDI finite state transducer suitable for receiving or transmitting. It
  370  * will accept correct MIDI input that uses, doesn't use, or sometimes uses the
  371  * 'running status' compression technique, and transduce it to fully expanded
  372  * (form=FST_CANON) or fully compressed (form=FST_COMPR or FST_VCOMP) form.
  373  *
  374  * Returns FST_MORE if a complete message has not been parsed yet (SysEx
  375  * messages are the exception), FST_ERR or FST_HUH if the input does not
  376  * conform to the protocol, or FST_CHN (channel messages), FST_COM (System
  377  * Common messages), FST_RT (System Real-Time messages), or FST_SYX (System
  378  * Exclusive) to broadly categorize the message parsed. s->pos and s->end
  379  * locate the parsed message; while (s->pos<s->end) putchar(*(s->pos++));
  380  * would output it.
  381  *
  382  * FST_HUH means the character c wasn't valid in the original state, but the
  383  * state has now been reset to START and the caller should try again passing
  384  * the same c. FST_ERR means c isn't valid in the start state; the caller
  385  * should kiss it goodbye and continue to try successive characters from the
  386  * input until something other than FST_ERR or FST_HUH is returned, at which
  387  * point things are resynchronized.
  388  *
  389  * A FST_SYX return means that between pos and end are from 1 to 3
  390  * bytes of a system exclusive message. A SysEx message will be delivered in
  391  * one or more chunks of that form, where the first begins with 0xf0 and the
  392  * last (which is the only one that might have length < 3) ends with 0xf7.
  393  *
  394  * Messages corrupted by a protocol error are discarded and won't be seen at
  395  * all; again SysEx is the exception, as one or more chunks of it may already
  396  * have been parsed.
  397  *
  398  * For FST_CHN messages, s->msg[0] always contains the status byte even if
  399  * FST_COMPR form was requested (pos then points to msg[1]). That way, the
  400  * caller can always identify the exact message if there is a need to do so.
  401  * For all other message types except FST_SYX, the status byte is at *pos
  402  * (which may not necessarily be msg[0]!). There is only one SysEx status
  403  * byte, so the return value FST_SYX is sufficient to identify it.
  404  *
  405  * To simplify some use cases, compression can also be requested with
  406  * form=FST_VCOMP. In this form a compressible channel message is indicated
  407  * by returning a classification of FST_CHV instead of FST_CHN, and pos points
  408  * to the status byte rather than being advanced past it. If the caller in this
  409  * case saves the bytes from pos to end, it will have saved the entire message,
  410  * and can act on the FST_CHV tag to drop the first byte later. In this form,
  411  * unlike FST_CANON, hidden note-off (i.e. note-on with velocity 0) may occur.
  412  *
  413  * Two obscure points in the MIDI protocol complicate things further, both to
  414  * do with the EndSysEx code, 0xf7. First, this code is permitted (and
  415  * meaningless) outside of a System Exclusive message, anywhere a status byte
  416  * could appear. Second, it is allowed to be absent at the end of a System
  417  * Exclusive message (!) - any status byte at all (non-realtime) is allowed to
  418  * terminate the message. Both require accomodation in the interface to
  419  * midi_fst's caller. A stray 0xf7 should be ignored BUT should count as a
  420  * message received for purposes of Active Sense timeout; the case is
  421  * represented by a return of FST_COM with a length of zero (pos == end). A
  422  * status byte other than 0xf7 during a system exclusive message will cause an
  423  * FST_SXP (sysex plus) return; the bytes from pos to end are the end of the
  424  * system exclusive message, and after handling those the caller should call
  425  * midi_fst again with the same input byte.
  426  *
  427  * midi(4) will never produce either such form of rubbish.
  428  */
  429 static enum fst_ret
  430 midi_fst(struct midi_state *s, u_char c, enum fst_form form)
  431 {
  432         int syxpos = 0;
  433 
  434         if ( c >= 0xf8 ) { /* All realtime messages bypass state machine */
  435                 if ( c == 0xf9  ||  c == 0xfd ) {
  436                         DPRINTF( ("midi_fst: s=%p c=0x%02x undefined\n", 
  437                                   s, c));
  438                         s->bytesDiscarded.ev_count++;
  439                         return FST_ERR;
  440                 }
  441                 DPRINTFN(9, ("midi_fst: s=%p System Real-Time data=0x%02x\n", 
  442                              s, c));
  443                 s->msg[2] = c;
  444                 FST_RETURN(2,3,FST_RT);
  445         }
  446 
  447         DPRINTFN(4, ("midi_fst: s=%p data=0x%02x state=%d\n", 
  448                      s, c, s->state));
  449 
  450         switch ( s->state   | MIDI_CAT(c) ) { /* break ==> return FST_MORE */
  451 
  452         case MIDI_IN_START  | MIDI_CAT_COMMON:
  453         case MIDI_IN_RUN1_1 | MIDI_CAT_COMMON:
  454         case MIDI_IN_RUN2_2 | MIDI_CAT_COMMON:
  455         case MIDI_IN_RXX2_2 | MIDI_CAT_COMMON:
  456                 s->msg[0] = c;
  457                 switch ( c ) {
  458                 case 0xf0: s->state = MIDI_IN_SYX1_3; break;
  459                 case 0xf1: s->state = MIDI_IN_COM0_1; break;
  460                 case 0xf2: s->state = MIDI_IN_COM0_2; break;
  461                 case 0xf3: s->state = MIDI_IN_COM0_1; break;
  462                 case 0xf6: s->state = MIDI_IN_START;  FST_RETURN(0,1,FST_COM);
  463                 case 0xf7: s->state = MIDI_IN_START;  FST_RETURN(0,0,FST_COM);
  464                 default: goto protocol_violation;
  465                 }
  466                 break;
  467         
  468         case MIDI_IN_RUN1_1 | MIDI_CAT_STATUS1:
  469                 if ( c == s->msg[0] ) {
  470                         s->state = MIDI_IN_RNX0_1;
  471                         break;
  472                 }
  473                 /* FALLTHROUGH */
  474         case MIDI_IN_RUN2_2 | MIDI_CAT_STATUS1:
  475         case MIDI_IN_RXX2_2 | MIDI_CAT_STATUS1:
  476         case MIDI_IN_START  | MIDI_CAT_STATUS1:
  477                 s->state = MIDI_IN_RUN0_1;
  478                 s->msg[0] = c;
  479                 break;
  480         
  481         case MIDI_IN_RUN2_2 | MIDI_CAT_STATUS2:
  482         case MIDI_IN_RXX2_2 | MIDI_CAT_STATUS2:
  483                 if ( c == s->msg[0] ) {
  484                         s->state = MIDI_IN_RNX0_2;
  485                         break;
  486                 }
  487                 if ( (c ^ s->msg[0]) == 0x10 && (c & 0xe0) == 0x80 ) {
  488                         s->state = MIDI_IN_RXX0_2;
  489                         s->msg[0] = c;
  490                         break;
  491                 }
  492                 /* FALLTHROUGH */
  493         case MIDI_IN_RUN1_1 | MIDI_CAT_STATUS2:
  494         case MIDI_IN_START  | MIDI_CAT_STATUS2:
  495                 s->state = MIDI_IN_RUN0_2;
  496                 s->msg[0] = c;
  497                 break;
  498 
  499         case MIDI_IN_COM0_1 | MIDI_CAT_DATA:
  500                 s->state = MIDI_IN_START;
  501                 s->msg[1] = c;
  502                 FST_RETURN(0,2,FST_COM);
  503 
  504         case MIDI_IN_COM0_2 | MIDI_CAT_DATA:
  505                 s->state = MIDI_IN_COM1_2;
  506                 s->msg[1] = c;
  507                 break;
  508 
  509         case MIDI_IN_COM1_2 | MIDI_CAT_DATA:
  510                 s->state = MIDI_IN_START;
  511                 s->msg[2] = c;
  512                 FST_RETURN(0,3,FST_COM);
  513 
  514         case MIDI_IN_RUN0_1 | MIDI_CAT_DATA:
  515                 s->state = MIDI_IN_RUN1_1;
  516                 s->msg[1] = c;
  517                 FST_RETURN(0,2,FST_CHN);
  518 
  519         case MIDI_IN_RUN1_1 | MIDI_CAT_DATA:
  520         case MIDI_IN_RNX0_1 | MIDI_CAT_DATA:
  521                 s->state = MIDI_IN_RUN1_1;
  522                 s->msg[1] = c;
  523                 FST_CRETURN(2);
  524 
  525         case MIDI_IN_RUN0_2 | MIDI_CAT_DATA:
  526                 s->state = MIDI_IN_RUN1_2;
  527                 s->msg[1] = c;
  528                 break;
  529 
  530         case MIDI_IN_RUN1_2 | MIDI_CAT_DATA:
  531                 if ( FST_CANON == form && 0 == c && (s->msg[0]&0xf0) == 0x90 ) {
  532                         s->state = MIDI_IN_RXX2_2;
  533                         s->msg[0] ^= 0x10;
  534                         s->msg[2] = 64;
  535                 } else {
  536                         s->state = MIDI_IN_RUN2_2;
  537                         s->msg[2] = c;
  538                 }
  539                 FST_RETURN(0,3,FST_CHN);
  540 
  541         case MIDI_IN_RUN2_2 | MIDI_CAT_DATA:
  542                 s->state = MIDI_IN_RNX1_2;
  543                 s->msg[1] = c;
  544                 break;
  545 
  546         case MIDI_IN_RXX2_2 | MIDI_CAT_DATA:
  547                 s->state = MIDI_IN_RXX1_2;
  548                 s->msg[0] ^= 0x10;
  549                 s->msg[1] = c;
  550                 break;
  551 
  552         case MIDI_IN_RNX0_2 | MIDI_CAT_DATA:
  553                 s->state = MIDI_IN_RNY1_2;
  554                 s->msg[1] = c;
  555                 break;
  556 
  557         case MIDI_IN_RXX0_2 | MIDI_CAT_DATA:
  558                 s->state = MIDI_IN_RXY1_2;
  559                 s->msg[1] = c;
  560                 break;
  561 
  562         case MIDI_IN_RNX1_2 | MIDI_CAT_DATA:
  563         case MIDI_IN_RNY1_2 | MIDI_CAT_DATA:
  564                 if ( FST_CANON == form && 0 == c && (s->msg[0]&0xf0) == 0x90 ) {
  565                         s->state = MIDI_IN_RXX2_2;
  566                         s->msg[0] ^= 0x10;
  567                         s->msg[2] = 64;
  568                         FST_RETURN(0,3,FST_CHN);
  569                 }
  570                 s->state = MIDI_IN_RUN2_2;
  571                 s->msg[2] = c;
  572                 FST_CRETURN(3);
  573 
  574         case MIDI_IN_RXX1_2 | MIDI_CAT_DATA:
  575         case MIDI_IN_RXY1_2 | MIDI_CAT_DATA:
  576                 if ( ( 0 == c && (s->msg[0]&0xf0) == 0x90)
  577                   || (64 == c && (s->msg[0]&0xf0) == 0x80
  578                       && FST_CANON != form) ) {
  579                         s->state = MIDI_IN_RXX2_2;
  580                         s->msg[0] ^= 0x10;
  581                         s->msg[2] = 64 - c;
  582                         FST_CRETURN(3);
  583                 }
  584                 s->state = MIDI_IN_RUN2_2;
  585                 s->msg[2] = c;
  586                 FST_RETURN(0,3,FST_CHN);
  587 
  588         case MIDI_IN_SYX1_3 | MIDI_CAT_DATA:
  589                 s->state = MIDI_IN_SYX2_3;
  590                 s->msg[1] = c;
  591                 break;
  592 
  593         case MIDI_IN_SYX2_3 | MIDI_CAT_DATA:
  594                 s->state = MIDI_IN_SYX0_3;
  595                 s->msg[2] = c;
  596                 FST_RETURN(0,3,FST_SYX);
  597 
  598         case MIDI_IN_SYX0_3 | MIDI_CAT_DATA:
  599                 s->state = MIDI_IN_SYX1_3;
  600                 s->msg[0] = c;
  601                 break;
  602 
  603         case MIDI_IN_SYX2_3 | MIDI_CAT_COMMON:
  604         case MIDI_IN_SYX2_3 | MIDI_CAT_STATUS1:
  605         case MIDI_IN_SYX2_3 | MIDI_CAT_STATUS2:
  606                 ++ syxpos;
  607                 /* FALLTHROUGH */
  608         case MIDI_IN_SYX1_3 | MIDI_CAT_COMMON:
  609         case MIDI_IN_SYX1_3 | MIDI_CAT_STATUS1:
  610         case MIDI_IN_SYX1_3 | MIDI_CAT_STATUS2:
  611                 ++ syxpos;
  612                 /* FALLTHROUGH */
  613         case MIDI_IN_SYX0_3 | MIDI_CAT_COMMON:
  614         case MIDI_IN_SYX0_3 | MIDI_CAT_STATUS1:
  615         case MIDI_IN_SYX0_3 | MIDI_CAT_STATUS2:
  616                 s->state = MIDI_IN_START;
  617                 if ( c == 0xf7 ) {
  618                         s->msg[syxpos] = c;
  619                         FST_RETURN(0,1+syxpos,FST_SYX);
  620                 }
  621                 s->msg[syxpos] = 0xf7;
  622                 FST_RETURN(0,1+syxpos,FST_SXP);
  623 
  624         default:
  625 protocol_violation:
  626                 DPRINTF(("midi_fst: unexpected %#02x in state %u\n",
  627                         c, s->state));
  628                 switch ( s->state ) {
  629                 case MIDI_IN_RUN1_1: /* can only get here by seeing an */
  630                 case MIDI_IN_RUN2_2: /* INVALID System Common message */
  631                 case MIDI_IN_RXX2_2:
  632                         s->state = MIDI_IN_START;
  633                         /* FALLTHROUGH */
  634                 case MIDI_IN_START:
  635                         s->bytesDiscarded.ev_count++;
  636                         return FST_ERR;
  637                 case MIDI_IN_COM1_2:
  638                 case MIDI_IN_RUN1_2:
  639                 case MIDI_IN_RNY1_2:
  640                 case MIDI_IN_RXY1_2:
  641                         s->bytesDiscarded.ev_count++;
  642                         /* FALLTHROUGH */
  643                 case MIDI_IN_COM0_1:
  644                 case MIDI_IN_RUN0_1:
  645                 case MIDI_IN_RNX0_1:
  646                 case MIDI_IN_COM0_2:
  647                 case MIDI_IN_RUN0_2:
  648                 case MIDI_IN_RNX0_2:
  649                 case MIDI_IN_RXX0_2:
  650                 case MIDI_IN_RNX1_2:
  651                 case MIDI_IN_RXX1_2:
  652                         s->bytesDiscarded.ev_count++;
  653                         s->incompleteMessages.ev_count++;
  654                         break;
  655 #if defined(AUDIO_DEBUG) || defined(DIAGNOSTIC)
  656                 default:
  657                         printf("midi_fst: mishandled %#02x(%u) in state %u?!\n",
  658                               c, MIDI_CAT(c), s->state);
  659 #endif
  660                 }
  661                 s->state = MIDI_IN_START;
  662                 return FST_HUH;
  663         }
  664         return FST_MORE;
  665 }
  666 
  667 void
  668 midi_softintr_rd(void *cookie)
  669 {
  670         struct midi_softc *sc = cookie;
  671         struct proc *p;
  672 
  673         if (sc->async != NULL) {
  674                 mutex_enter(proc_lock);
  675                 if ((p = sc->async) != NULL)
  676                         psignal(p, SIGIO);
  677                 mutex_exit(proc_lock);
  678         }
  679         midi_wakeup(&sc->rchan);
  680         selnotify(&sc->rsel, 0, 0); /* filter will spin if locked */
  681 }
  682 
  683 void
  684 midi_softintr_wr(void *cookie)
  685 {
  686         struct midi_softc *sc = cookie;
  687         struct proc *p;
  688 
  689         if (sc->async != NULL) {
  690                 mutex_enter(proc_lock);
  691                 if ((p = sc->async) != NULL)
  692                         psignal(p, SIGIO);
  693                 mutex_exit(proc_lock);
  694         }
  695         midi_wakeup(&sc->wchan);
  696         selnotify(&sc->wsel, 0, 0); /* filter will spin if locked */
  697 }
  698 
  699 void
  700 midi_in(void *addr, int data)
  701 {
  702         struct midi_softc *sc = addr;
  703         struct midi_buffer *mb = &sc->inbuf;
  704         int i;
  705         int count;
  706         enum fst_ret got;
  707         int s; /* hw may have various spls so impose our own */
  708         MIDI_BUF_DECLARE(idx);
  709         MIDI_BUF_DECLARE(buf);
  710 
  711         if (!sc->isopen)
  712                 return;
  713 
  714         if (!(sc->flags & FREAD))
  715                 return;         /* discard data if not reading */
  716         
  717 sxp_again:
  718         do
  719                 got = midi_fst(&sc->rcv, data, FST_CANON);
  720         while ( got == FST_HUH );
  721         
  722         switch ( got ) {
  723         case FST_MORE:
  724         case FST_ERR:
  725                 return;
  726         case FST_CHN:
  727         case FST_COM:
  728         case FST_RT:
  729 #if NSEQUENCER > 0
  730                 if (sc->seqopen) {
  731                         extern void midiseq_in(struct midi_dev *,u_char *,int);
  732                         count = sc->rcv.end - sc->rcv.pos;
  733                         midiseq_in(sc->seq_md, sc->rcv.pos, count);
  734                         return;
  735                 }
  736 #endif
  737                 /*
  738                  * Pass Active Sense to the sequencer if it's open, but not to
  739                  * a raw reader. (Really should do something intelligent with
  740                  * it then, though....)
  741                  */
  742                 if ( got == FST_RT && MIDI_ACK == sc->rcv.pos[0] ) {
  743                         if ( !sc->rcv_expect_asense ) {
  744                                 sc->rcv_expect_asense = 1;
  745                                 callout_schedule(&sc->rcv_asense_co,
  746                                                  MIDI_RCV_ASENSE_PERIOD);
  747                         }
  748                         sc->rcv_quiescent = 0;
  749                         sc->rcv_eof = 0;
  750                         return;
  751                 }
  752                 /* FALLTHROUGH */
  753         /*
  754          * Ultimately SysEx msgs should be offered to the sequencer also; the
  755          * sequencer API addresses them - but maybe our sequencer can't handle
  756          * them yet, so offer only to raw reader. (Which means, ultimately,
  757          * discard them if the sequencer's open, as it's not doing reads!)
  758          * -> When SysEx support is added to the sequencer, be sure to handle
  759          *    FST_SXP there too.
  760          */
  761         case FST_SYX:
  762         case FST_SXP:
  763                 count = sc->rcv.end - sc->rcv.pos;
  764                 MIDI_IN_LOCK(sc,s);
  765                 sc->rcv_quiescent = 0;
  766                 sc->rcv_eof = 0;
  767                 if ( 0 == count ) {
  768                         MIDI_IN_UNLOCK(sc,s);
  769                         break;
  770                 }
  771                 MIDI_BUF_PRODUCER_INIT(mb,idx);
  772                 MIDI_BUF_PRODUCER_INIT(mb,buf);
  773                 if (count > buf_lim - buf_cur
  774                      || 1 > idx_lim - idx_cur) {
  775                         sc->rcv.bytesDiscarded.ev_count += count;
  776                         MIDI_IN_UNLOCK(sc,s);
  777                         DPRINTF(("midi_in: buffer full, discard data=0x%02x\n", 
  778                                  sc->rcv.pos[0]));
  779                         return;
  780                 }
  781                 for (i = 0; i < count; i++) {
  782                         *buf_cur++ = sc->rcv.pos[i];
  783                         MIDI_BUF_WRAP(buf);
  784                 }
  785                 *idx_cur++ = PACK_MB_IDX(got,count);
  786                 MIDI_BUF_WRAP(idx);
  787                 MIDI_BUF_PRODUCER_WBACK(mb,buf);
  788                 MIDI_BUF_PRODUCER_WBACK(mb,idx);
  789                 MIDI_IN_UNLOCK(sc,s);
  790                 softint_schedule(sc->sih_rd);
  791                 break;
  792         default: /* don't #ifdef this away, gcc will say FST_HUH not handled */
  793                 printf("midi_in: midi_fst returned %d?!\n", got);
  794         }
  795         if ( FST_SXP == got )
  796                 goto sxp_again;
  797 }
  798 
  799 void
  800 midi_out(void *addr)
  801 {
  802         struct midi_softc *sc = addr;
  803 
  804         if (!sc->isopen)
  805                 return;
  806         DPRINTFN(8, ("midi_out: %p\n", sc));
  807         midi_intr_out(sc);
  808 }
  809 
  810 int
  811 midiopen(dev_t dev, int flags, int ifmt, struct lwp *l)
  812 {
  813         struct midi_softc *sc;
  814         const struct midi_hw_if *hw;
  815         int error;
  816 
  817         sc = device_lookup_private(&midi_cd, MIDIUNIT(dev));
  818         if (sc == NULL)
  819                 return (ENXIO);
  820         if (sc->dying)
  821                 return (EIO);
  822 
  823         DPRINTFN(3,("midiopen %p\n", sc));
  824 
  825         hw = sc->hw_if;
  826         if (!hw)
  827                 return ENXIO;
  828         if (sc->isopen)
  829                 return EBUSY;
  830 
  831         /* put both state machines into known states */
  832         sc->rcv.state = MIDI_IN_START;
  833         sc->rcv.pos = sc->rcv.msg;
  834         sc->rcv.end = sc->rcv.msg;
  835         sc->xmt.state = MIDI_IN_START;
  836         sc->xmt.pos = sc->xmt.msg;
  837         sc->xmt.end = sc->xmt.msg;
  838         
  839         /* copy error counters so an ioctl (TBA) can give since-open stats */
  840         sc->rcv.atOpen.bytesDiscarded  = sc->rcv.bytesDiscarded.ev_count;
  841         sc->rcv.atQuery.bytesDiscarded = sc->rcv.bytesDiscarded.ev_count;
  842         
  843         sc->xmt.atOpen.bytesDiscarded  = sc->xmt.bytesDiscarded.ev_count;
  844         sc->xmt.atQuery.bytesDiscarded = sc->xmt.bytesDiscarded.ev_count;
  845         
  846         /* and the buffers */
  847         midi_initbuf(&sc->outbuf);
  848         midi_initbuf(&sc->inbuf);
  849         
  850         /* and the receive flags */
  851         sc->rcv_expect_asense = 0;
  852         sc->rcv_quiescent = 0;
  853         sc->rcv_eof = 0;
  854 
  855         error = hw->open(sc->hw_hdl, flags, midi_in, midi_out, sc);
  856         if (error)
  857                 return error;
  858         sc->isopen++;
  859         sc->flags = flags;
  860         sc->rchan = 0;
  861         sc->wchan = 0;
  862         sc->pbus = 0;
  863         sc->async = 0;
  864 
  865 #ifdef MIDI_SAVE
  866         if (midicnt != 0) {
  867                 midisave.cnt = midicnt;
  868                 midicnt = 0;
  869         }
  870 #endif
  871 
  872         return 0;
  873 }
  874 
  875 int
  876 midiclose(dev_t dev, int flags, int ifmt,
  877     struct lwp *l)
  878 {
  879         struct midi_softc *sc =
  880             device_lookup_private(&midi_cd, MIDIUNIT(dev));
  881         const struct midi_hw_if *hw = sc->hw_if;
  882         int s, error;
  883 
  884         DPRINTFN(3,("midiclose %p\n", sc));
  885 
  886         /* midi_start_output(sc); anything buffered => pbus already set! */
  887         error = 0;
  888         MIDI_OUT_LOCK(sc,s);
  889         while (sc->pbus) {
  890                 DPRINTFN(8,("midiclose sleep ...\n"));
  891                 error =
  892                 midi_sleep_timo(&sc->wchan, "mid_dr", 30*hz, &sc->out_lock);
  893         }
  894         sc->isopen = 0;
  895         MIDI_OUT_UNLOCK(sc,s);
  896         callout_stop(&sc->xmt_asense_co); /* xxx fix this - sleep? */
  897         callout_stop(&sc->rcv_asense_co);
  898         hw->close(sc->hw_hdl);
  899 #if NSEQUENCER > 0
  900         sc->seqopen = 0;
  901         sc->seq_md = 0;
  902 #endif
  903         return 0;
  904 }
  905 
  906 int
  907 midiread(dev_t dev, struct uio *uio, int ioflag)
  908 {
  909         struct midi_softc *sc =
  910             device_lookup_private(&midi_cd, MIDIUNIT(dev));
  911         struct midi_buffer *mb = &sc->inbuf;
  912         int error;
  913         int s;
  914         MIDI_BUF_DECLARE(idx);
  915         MIDI_BUF_DECLARE(buf);
  916         int appetite;
  917         int first = 1;
  918 
  919         DPRINTFN(6,("midiread: %p, count=%lu\n", sc,
  920                  (unsigned long)uio->uio_resid));
  921 
  922         if (sc->dying)
  923                 return EIO;
  924         if ( !(sc->props & MIDI_PROP_CAN_INPUT) )
  925                 return ENXIO;
  926 
  927         MIDI_IN_LOCK(sc,s);
  928         MIDI_BUF_CONSUMER_INIT(mb,idx);
  929         MIDI_BUF_CONSUMER_INIT(mb,buf);
  930         MIDI_IN_UNLOCK(sc,s);
  931         
  932         error = 0;
  933         for ( ;; ) {
  934                 /*
  935                  * If the used portion of idx wraps around the end, just take
  936                  * the first part on this iteration, and we'll get the rest on
  937                  * the next.
  938                  */
  939                 if ( idx_lim > idx_end )
  940                         idx_lim = idx_end;
  941                 /*
  942                  * Count bytes through the last complete message that will
  943                  * fit in the requested read.
  944                  */
  945                 for (appetite = uio->uio_resid; idx_cur < idx_lim; ++idx_cur) {
  946                         if ( appetite < MB_IDX_LEN(*idx_cur) )
  947                                 break;
  948                         appetite -= MB_IDX_LEN(*idx_cur);
  949                 }
  950                 appetite = uio->uio_resid - appetite;
  951                 /*
  952                  * Only if the read is too small to hold even the first
  953                  * complete message will we return a partial one (updating idx
  954                  * to reflect the remaining length of the message).
  955                  */
  956                 if ( appetite == 0 && idx_cur < idx_lim ) {
  957                         if ( !first )
  958                                 goto unlocked_exit; /* idx_cur not advanced */
  959                         appetite = uio->uio_resid;
  960                         *idx_cur = PACK_MB_IDX(MB_IDX_CAT(*idx_cur),
  961                                                MB_IDX_LEN(*idx_cur) - appetite);
  962                 }
  963                 KASSERT(buf_cur + appetite <= buf_lim);
  964                 
  965                 /* move the bytes */
  966                 if ( appetite > 0 ) {           
  967                         first = 0;  /* we know we won't return empty-handed */
  968                         /* do two uiomoves if data wrap around end of buf */
  969                         if ( buf_cur + appetite > buf_end ) {
  970                                 DPRINTFN(8,
  971                                         ("midiread: uiomove cc=%td (prewrap)\n",
  972                                         buf_end - buf_cur));
  973                                 error = uiomove(buf_cur, buf_end-buf_cur, uio);
  974                                 if ( error )
  975                                         goto unlocked_exit;
  976                                 appetite -= buf_end - buf_cur;
  977                                 buf_cur = mb->buf;
  978                         }
  979                         DPRINTFN(8, ("midiread: uiomove cc=%d\n", appetite));
  980                         error = uiomove(buf_cur, appetite, uio);
  981                         if ( error )
  982                                 goto unlocked_exit;
  983                         buf_cur += appetite;
  984                 }
  985                 
  986                 MIDI_BUF_WRAP(idx);
  987                 MIDI_BUF_WRAP(buf);
  988 
  989                 MIDI_IN_LOCK(sc,s);
  990                 MIDI_BUF_CONSUMER_WBACK(mb,idx);
  991                 MIDI_BUF_CONSUMER_WBACK(mb,buf);
  992                 if ( 0 == uio->uio_resid ) /* if read satisfied, we're done */
  993                         break;
  994                 MIDI_BUF_CONSUMER_REFRESH(mb,idx);
  995                 if ( idx_cur == idx_lim ) { /* need to wait for data? */
  996                         if ( !first || sc->rcv_eof ) /* never block reader if */
  997                                 break;            /* any data already in hand */
  998                         if (ioflag & IO_NDELAY) {
  999                                 error = EWOULDBLOCK;
 1000                                 break;
 1001                         }
 1002                         error = midi_sleep(&sc->rchan, "mid rd", &sc->in_lock);
 1003                         if ( error )
 1004                                 break;
 1005                         MIDI_BUF_CONSUMER_REFRESH(mb,idx); /* what'd we get? */
 1006                 }
 1007                 MIDI_BUF_CONSUMER_REFRESH(mb,buf);
 1008                 MIDI_IN_UNLOCK(sc,s);
 1009                 if ( sc->dying )
 1010                         return EIO;
 1011         }
 1012         MIDI_IN_UNLOCK(sc,s);
 1013 
 1014 unlocked_exit:
 1015         return error;
 1016 }
 1017 
 1018 void
 1019 midi_rcv_asense(void *arg)
 1020 {
 1021         struct midi_softc *sc = arg;
 1022         int s;
 1023         
 1024         if ( sc->dying || !sc->isopen )
 1025                 return;
 1026 
 1027         if ( sc->rcv_quiescent ) {
 1028                 MIDI_IN_LOCK(sc,s);
 1029                 sc->rcv_eof = 1;
 1030                 sc->rcv_quiescent = 0;
 1031                 sc->rcv_expect_asense = 0;
 1032                 MIDI_IN_UNLOCK(sc,s);
 1033                 softint_schedule(sc->sih_rd);
 1034                 return;
 1035         }
 1036         
 1037         sc->rcv_quiescent = 1;
 1038         callout_schedule(&sc->rcv_asense_co, MIDI_RCV_ASENSE_PERIOD);
 1039 }
 1040 
 1041 void
 1042 midi_xmt_asense(void *arg)
 1043 {
 1044         struct midi_softc *sc = arg;
 1045         int s;
 1046         int error;
 1047         int armed;
 1048         
 1049         if ( sc->dying || !sc->isopen )
 1050                 return;
 1051 
 1052         MIDI_OUT_LOCK(sc,s);
 1053         if ( sc->pbus || sc->dying || !sc->isopen ) {
 1054                 MIDI_OUT_UNLOCK(sc,s);
 1055                 return;
 1056         }
 1057         sc->pbus = 1;
 1058         DPRINTFN(8,("midi_xmt_asense: %p\n", sc));
 1059 
 1060         if ( sc->props & MIDI_PROP_OUT_INTR ) {
 1061                 error = sc->hw_if->output(sc->hw_hdl, MIDI_ACK);
 1062                 armed = (error == 0);
 1063         } else { /* polled output, do with interrupts unmasked */
 1064                 MIDI_OUT_UNLOCK(sc,s);
 1065                 /* running from softclock, so top half won't sneak in here */
 1066                 error = sc->hw_if->output(sc->hw_hdl, MIDI_ACK);
 1067                 MIDI_OUT_LOCK(sc,s);
 1068                 armed = 0;
 1069         }
 1070 
 1071         if ( !armed ) {
 1072                 sc->pbus = 0;
 1073                 callout_schedule(&sc->xmt_asense_co, MIDI_XMT_ASENSE_PERIOD);
 1074         }
 1075 
 1076         MIDI_OUT_UNLOCK(sc,s);
 1077 }
 1078 
 1079 /*
 1080  * The way this function was hacked up to plug into poll_out and intr_out
 1081  * after they were written won't win it any beauty contests, but it'll work
 1082  * (code in haste, refactor at leisure). This may be called with the lock
 1083  * (by intr_out) or without the lock (by poll_out) so it only does what could
 1084  * be safe either way.
 1085  */
 1086 int midi_msg_out(struct midi_softc *sc,
 1087                  u_char **idx, u_char **idxl, u_char **buf, u_char **bufl) {
 1088         MIDI_BUF_DECLARE(idx);
 1089         MIDI_BUF_DECLARE(buf);
 1090         MIDI_BUF_EXTENT_INIT(&sc->outbuf,idx);
 1091         MIDI_BUF_EXTENT_INIT(&sc->outbuf,buf);
 1092         int length;
 1093         int error;
 1094         u_char contig[3];
 1095         u_char *cp;
 1096         u_char *ep;
 1097         
 1098         idx_cur = *idx;
 1099         idx_lim = *idxl;
 1100         buf_cur = *buf;
 1101         buf_lim = *bufl;
 1102         
 1103         length = MB_IDX_LEN(*idx_cur);
 1104         
 1105         for ( cp = contig, ep = cp + length; cp < ep; ) {
 1106                 *cp++ = *buf_cur++;
 1107                 MIDI_BUF_WRAP(buf);
 1108         }
 1109         cp = contig;
 1110 
 1111         switch ( MB_IDX_CAT(*idx_cur) ) {
 1112         case FST_CHV: /* chnmsg to be compressed (for device that wants it) */
 1113                 ++ cp;
 1114                 -- length;
 1115                 /* FALLTHROUGH */
 1116         case FST_CHN:
 1117                 error = sc->hw_if_ext->channel(sc->hw_hdl,
 1118                                                MIDI_GET_STATUS(contig[0]),
 1119                                                MIDI_GET_CHAN(contig[0]),
 1120                                                cp, length);
 1121                 break;
 1122         case FST_COM:
 1123                 error = sc->hw_if_ext->common(sc->hw_hdl,
 1124                                               MIDI_GET_STATUS(contig[0]),
 1125                                               cp, length);
 1126                 break;
 1127         case FST_SYX:
 1128         case FST_SXP:
 1129                 error = sc->hw_if_ext->sysex(sc->hw_hdl,
 1130                                              cp, length);
 1131                 break;
 1132         case FST_RT:
 1133                 error = sc->hw_if->output(sc->hw_hdl, *cp);
 1134                 break;
 1135         default:
 1136                 error = EIO;
 1137         }
 1138         
 1139         if ( !error ) {
 1140                 ++ idx_cur;
 1141                 MIDI_BUF_WRAP(idx);
 1142                 *idx  = idx_cur;
 1143                 *idxl = idx_lim;
 1144                 *buf  = buf_cur;
 1145                 *bufl = buf_lim;
 1146         }
 1147         
 1148         return error;
 1149 }
 1150 
 1151 /*
 1152  * midi_poll_out is intended for the midi hw (the vast majority of MIDI UARTs
 1153  * on sound cards, apparently) that _do not have transmit-ready interrupts_.
 1154  * Every call to hw_if->output for one of these may busy-wait to output the
 1155  * byte; at the standard midi data rate that'll be 320us per byte. The
 1156  * technique of writing only MIDI_MAX_WRITE bytes in a row and then waiting
 1157  * for MIDI_WAIT does not reduce the total time spent busy-waiting, and it
 1158  * adds arbitrary delays in transmission (and, since MIDI_WAIT is roughly the
 1159  * same as the time to send MIDI_MAX_WRITE bytes, it effectively halves the
 1160  * data rate). Here, a somewhat bolder approach is taken. Since midi traffic
 1161  * is bursty but time-sensitive--most of the time there will be none at all,
 1162  * but when there is it should go out ASAP--the strategy is to just get it
 1163  * over with, and empty the buffer in one go. The effect this can have on
 1164  * the rest of the system will be limited by the size of the buffer and the
 1165  * sparseness of the traffic. But some precautions are in order. Interrupts
 1166  * should all be unmasked when this is called, and midiwrite should not fill
 1167  * the buffer more than once (when MIDI_PROP_CAN_INTR is false) without a
 1168  * yield() so some other process can get scheduled. If the write is nonblocking,
 1169  * midiwrite should return a short count rather than yield.
 1170  *
 1171  * Someday when there is fine-grained MP support, this should be reworked to
 1172  * run in a callout so the writing process really could proceed concurrently.
 1173  * But obviously where performance is a concern, interrupt-driven hardware
 1174  * such as USB midi or (apparently) clcs will always be preferable. And it
 1175  * seems (kern/32651) that many of the devices currently working in poll mode
 1176  * may really have tx interrupt capability and want only implementation; that
 1177  * ought to happen.
 1178  */
 1179 int
 1180 midi_poll_out(struct midi_softc *sc)
 1181 {
 1182         struct midi_buffer *mb = &sc->outbuf;
 1183         int error;
 1184         int msglen;
 1185         int s;
 1186         MIDI_BUF_DECLARE(idx);
 1187         MIDI_BUF_DECLARE(buf);
 1188 
 1189         error = 0;
 1190 
 1191         MIDI_OUT_LOCK(sc,s);
 1192         MIDI_BUF_CONSUMER_INIT(mb,idx);
 1193         MIDI_BUF_CONSUMER_INIT(mb,buf);
 1194         MIDI_OUT_UNLOCK(sc,s);
 1195 
 1196         for ( ;; ) {
 1197                 while ( idx_cur != idx_lim ) {
 1198                         if ( sc->hw_if_ext ) {
 1199                                 error = midi_msg_out(sc, &idx_cur, &idx_lim,
 1200                                                          &buf_cur, &buf_lim);
 1201                                 if ( error )
 1202                                         goto ioerror;
 1203                                 continue;
 1204                         }
 1205                         /* or, lacking hw_if_ext ... */
 1206                         msglen = MB_IDX_LEN(*idx_cur);
 1207                         DPRINTFN(7,("midi_poll_out: %p <- %#02x\n",
 1208                                    sc->hw_hdl, *buf_cur));
 1209                         error = sc->hw_if->output(sc->hw_hdl, *buf_cur);
 1210                         if ( error )
 1211                                 goto ioerror;
 1212                         ++ buf_cur;
 1213                         MIDI_BUF_WRAP(buf);
 1214                         -- msglen;
 1215                         if ( msglen )
 1216                                 *idx_cur = PACK_MB_IDX(MB_IDX_CAT(*idx_cur),
 1217                                                        msglen);
 1218                         else {
 1219                                 ++ idx_cur;
 1220                                 MIDI_BUF_WRAP(idx);
 1221                         }
 1222                 }
 1223                 KASSERT(buf_cur == buf_lim);
 1224                 MIDI_OUT_LOCK(sc,s);
 1225                 MIDI_BUF_CONSUMER_WBACK(mb,idx);
 1226                 MIDI_BUF_CONSUMER_WBACK(mb,buf);
 1227                 MIDI_BUF_CONSUMER_REFRESH(mb,idx); /* any more to transmit? */
 1228                 MIDI_BUF_CONSUMER_REFRESH(mb,buf);
 1229                 if ( idx_lim == idx_cur )
 1230                         break; /* still holding lock */
 1231                 MIDI_OUT_UNLOCK(sc,s);
 1232         }
 1233         goto disarm; /* lock held */
 1234 
 1235 ioerror:
 1236 #if defined(AUDIO_DEBUG) || defined(DIAGNOSTIC)
 1237         aprint_error_dev(sc->dev, "midi_poll_output error %d\n", error);
 1238 #endif
 1239         MIDI_OUT_LOCK(sc,s);
 1240         MIDI_BUF_CONSUMER_WBACK(mb,idx);
 1241         MIDI_BUF_CONSUMER_WBACK(mb,buf);
 1242 
 1243 disarm: 
 1244         sc->pbus = 0;
 1245         callout_schedule(&sc->xmt_asense_co, MIDI_XMT_ASENSE_PERIOD);
 1246         MIDI_OUT_UNLOCK(sc,s);
 1247         return error;
 1248 }
 1249 
 1250 /*
 1251  * The interrupt flavor acquires spl and lock once and releases at the end,
 1252  * as it expects to write only one byte or message. The interface convention
 1253  * is that if hw_if->output returns 0, it has initiated transmission and the
 1254  * completion interrupt WILL be forthcoming; if it has not returned 0, NO
 1255  * interrupt will be forthcoming, and if it returns EINPROGRESS it wants
 1256  * another byte right away.
 1257  */
 1258 int
 1259 midi_intr_out(struct midi_softc *sc)
 1260 {
 1261         struct midi_buffer *mb = &sc->outbuf;
 1262         int error;
 1263         int msglen;
 1264         int s;
 1265         MIDI_BUF_DECLARE(idx);
 1266         MIDI_BUF_DECLARE(buf);
 1267         int armed = 0;
 1268 
 1269         error = 0;
 1270 
 1271         MIDI_OUT_LOCK(sc,s);
 1272         MIDI_BUF_CONSUMER_INIT(mb,idx);
 1273         MIDI_BUF_CONSUMER_INIT(mb,buf);
 1274         
 1275         while ( idx_cur != idx_lim ) {
 1276                 if ( sc->hw_if_ext ) {
 1277                         error = midi_msg_out(sc, &idx_cur, &idx_lim,
 1278                                                  &buf_cur, &buf_lim);
 1279                         if ( !error ) /* no EINPROGRESS from extended hw_if */
 1280                                 armed = 1;
 1281                         break;
 1282                 }
 1283                 /* or, lacking hw_if_ext ... */
 1284                 msglen = MB_IDX_LEN(*idx_cur);
 1285                 error = sc->hw_if->output(sc->hw_hdl, *buf_cur);
 1286                 if ( error  &&  error != EINPROGRESS )
 1287                         break;
 1288                 ++ buf_cur;
 1289                 MIDI_BUF_WRAP(buf);
 1290                 -- msglen;
 1291                 if ( msglen )
 1292                         *idx_cur = PACK_MB_IDX(MB_IDX_CAT(*idx_cur),msglen);
 1293                 else {
 1294                         ++ idx_cur;
 1295                         MIDI_BUF_WRAP(idx);
 1296                 }
 1297                 if ( !error ) {
 1298                         armed = 1;
 1299                         break;
 1300                 }
 1301         }
 1302         MIDI_BUF_CONSUMER_WBACK(mb,idx);
 1303         MIDI_BUF_CONSUMER_WBACK(mb,buf);
 1304         if ( !armed ) {
 1305                 sc->pbus = 0;
 1306                 callout_schedule(&sc->xmt_asense_co, MIDI_XMT_ASENSE_PERIOD);
 1307         }
 1308         MIDI_OUT_UNLOCK(sc,s);
 1309         softint_schedule(sc->sih_wr);
 1310 
 1311 #if defined(AUDIO_DEBUG) || defined(DIAGNOSTIC)
 1312         if ( error )
 1313                 aprint_error_dev(sc->dev, "midi_intr_output error %d\n",
 1314                     error);
 1315 #endif
 1316         return error;
 1317 }
 1318 
 1319 int
 1320 midi_start_output(struct midi_softc *sc)
 1321 {
 1322         if (sc->dying)
 1323                 return EIO;
 1324 
 1325         if ( sc->props & MIDI_PROP_OUT_INTR )
 1326                 return midi_intr_out(sc);
 1327         return midi_poll_out(sc);
 1328 }
 1329 
 1330 static int
 1331 real_writebytes(struct midi_softc *sc, u_char *ibuf, int cc)
 1332 {
 1333         u_char *iend = ibuf + cc;
 1334         struct midi_buffer *mb = &sc->outbuf;
 1335         int arming = 0;
 1336         int count;
 1337         int s;
 1338         int got;
 1339         enum fst_form form;
 1340         MIDI_BUF_DECLARE(idx);
 1341         MIDI_BUF_DECLARE(buf);
 1342         
 1343         /*
 1344          * If the hardware uses the extended hw_if, pass it canonicalized
 1345          * messages (or compressed ones if it specifically requests, using
 1346          * VCOMP form so the bottom half can still pass the op and chan along);
 1347          * if it does not, send it compressed messages (using COMPR form as
 1348          * there is no need to preserve the status for the bottom half).
 1349          */
 1350         if ( NULL == sc->hw_if_ext )
 1351                 form = FST_COMPR;
 1352         else if ( sc->hw_if_ext->compress )
 1353                 form = FST_VCOMP;
 1354         else
 1355                 form = FST_CANON;
 1356 
 1357         MIDI_OUT_LOCK(sc,s);
 1358         MIDI_BUF_PRODUCER_INIT(mb,idx);
 1359         MIDI_BUF_PRODUCER_INIT(mb,buf);
 1360         MIDI_OUT_UNLOCK(sc,s);
 1361 
 1362         if (sc->dying)
 1363                 return EIO;
 1364         
 1365         while ( ibuf < iend ) {
 1366                 got = midi_fst(&sc->xmt, *ibuf, form);
 1367                 ++ ibuf;
 1368                 switch ( got ) {
 1369                 case FST_MORE:
 1370                         continue;
 1371                 case FST_ERR:
 1372                 case FST_HUH:
 1373                         return EPROTO;
 1374                 case FST_CHN:
 1375                 case FST_CHV: /* only occurs in VCOMP form */
 1376                 case FST_COM:
 1377                 case FST_RT:
 1378                 case FST_SYX:
 1379                 case FST_SXP:
 1380                         break; /* go add to buffer */
 1381 #if defined(AUDIO_DEBUG) || defined(DIAGNOSTIC)
 1382                 default:
 1383                         printf("midi_wr: midi_fst returned %d?!\n", got);
 1384 #endif
 1385                 }
 1386                 count = sc->xmt.end - sc->xmt.pos;
 1387                 if ( 0 == count ) /* can happen with stray 0xf7; see midi_fst */
 1388                         continue;
 1389                 /*
 1390                  * return EWOULDBLOCK if the data passed will not fit in
 1391                  * the buffer; the caller should have taken steps to avoid that.
 1392                  * If got==FST_SXP we lose the new status byte, but we're losing
 1393                  * anyway, so c'est la vie.
 1394                  */
 1395                 if ( idx_cur == idx_lim || count > buf_lim - buf_cur ) {
 1396                         MIDI_OUT_LOCK(sc,s);
 1397                         MIDI_BUF_PRODUCER_REFRESH(mb,idx); /* get the most */
 1398                         MIDI_BUF_PRODUCER_REFRESH(mb,buf); /*  current facts */
 1399                         MIDI_OUT_UNLOCK(sc,s);
 1400                         if ( idx_cur == idx_lim || count > buf_lim - buf_cur )
 1401                                 return EWOULDBLOCK; /* caller's problem */
 1402                 }
 1403                 *idx_cur++ = PACK_MB_IDX(got,count);
 1404                 MIDI_BUF_WRAP(idx);
 1405                 while ( count ) {
 1406                         *buf_cur++ = *(sc->xmt.pos)++;
 1407                         MIDI_BUF_WRAP(buf);
 1408                         -- count;
 1409                 }
 1410                 if ( FST_SXP == got )
 1411                         -- ibuf; /* again with same status byte */
 1412         }
 1413         MIDI_OUT_LOCK(sc,s);
 1414         MIDI_BUF_PRODUCER_WBACK(mb,buf);
 1415         MIDI_BUF_PRODUCER_WBACK(mb,idx);
 1416         /*
 1417          * If the output transfer is not already busy, and there is a message
 1418          * buffered, mark it busy, stop the Active Sense callout (what if we're
 1419          * too late and it's expired already? No big deal, an extra Active Sense
 1420          * never hurt anybody) and start the output transfer once we're out of
 1421          * the critical section (pbus==1 will stop anyone else doing the same).
 1422          */
 1423         MIDI_BUF_CONSUMER_INIT(mb,idx); /* check what consumer's got to read */
 1424         if ( !sc->pbus && idx_cur < idx_lim ) {
 1425                 sc->pbus = 1;
 1426                 callout_stop(&sc->xmt_asense_co);
 1427                 arming = 1;
 1428         }
 1429         MIDI_OUT_UNLOCK(sc,s);
 1430         return arming ? midi_start_output(sc) : 0;
 1431 }
 1432 
 1433 int
 1434 midiwrite(dev_t dev, struct uio *uio, int ioflag)
 1435 {
 1436         struct midi_softc *sc =
 1437             device_lookup_private(&midi_cd, MIDIUNIT(dev));
 1438         struct midi_buffer *mb = &sc->outbuf;
 1439         int error;
 1440         u_char inp[256];
 1441         int s;
 1442         MIDI_BUF_DECLARE(idx);
 1443         MIDI_BUF_DECLARE(buf);
 1444         size_t idxspace;
 1445         size_t bufspace;
 1446         size_t xfrcount;
 1447         int pollout = 0;
 1448 
 1449         DPRINTFN(6, ("midiwrite: %p, unit=%d, count=%lu\n", sc, (int)minor(dev),
 1450                      (unsigned long)uio->uio_resid));
 1451 
 1452         if (sc->dying)
 1453                 return EIO;
 1454 
 1455         error = 0;
 1456         while (uio->uio_resid > 0 && !error) {
 1457 
 1458                 /*
 1459                  * block if necessary for the minimum buffer space to guarantee
 1460                  * we can write something.
 1461                  */
 1462                 MIDI_OUT_LOCK(sc,s);
 1463                 MIDI_BUF_PRODUCER_INIT(mb,idx); /* init can't go above loop; */
 1464                 MIDI_BUF_PRODUCER_INIT(mb,buf); /* real_writebytes moves cur */
 1465                 for ( ;; ) {
 1466                         idxspace = MIDI_BUF_PRODUCER_REFRESH(mb,idx) - idx_cur;
 1467                         bufspace = MIDI_BUF_PRODUCER_REFRESH(mb,buf) - buf_cur;
 1468                         if ( idxspace >= 1  &&  bufspace >= 3  && !pollout )
 1469                                 break;
 1470                         DPRINTFN(8,("midi_write: sleep idx=%zd buf=%zd\n", 
 1471                                  idxspace, bufspace));
 1472                         if (ioflag & IO_NDELAY) {
 1473                                 error = EWOULDBLOCK;
 1474                                 /*
 1475                                  * If some amount has already been transferred,
 1476                                  * the common syscall code will automagically
 1477                                  * convert this to success with a short count.
 1478                                  */
 1479                                 goto locked_exit;
 1480                         }
 1481                         if ( pollout ) {
 1482                                 preempt(); /* see midi_poll_output */
 1483                                 pollout = 0;
 1484                         } else
 1485                                 error = midi_sleep(&sc->wchan, "mid wr",
 1486                                                    &sc->out_lock);
 1487                         if (error)
 1488                                 /*
 1489                                  * Similarly, the common code will handle
 1490                                  * EINTR and ERESTART properly here, changing to
 1491                                  * a short count if something transferred.
 1492                                  */
 1493                                 goto locked_exit;
 1494                 }
 1495                 MIDI_OUT_UNLOCK(sc,s);                  
 1496 
 1497                 /*
 1498                  * The number of bytes we can safely extract from the uio
 1499                  * depends on the available idx and buf space. Worst case,
 1500                  * every byte is a message so 1 idx is required per byte.
 1501                  * Worst case, the first byte completes a 3-byte msg in prior
 1502                  * state, and every subsequent byte is a Program Change or
 1503                  * Channel Pressure msg with running status and expands to 2
 1504                  * bytes, so the buf space reqd is 3+2(n-1) or 2n+1. So limit
 1505                  * the transfer to the min of idxspace and (bufspace-1)>>1.
 1506                  */
 1507                 xfrcount = (bufspace - 1) >> 1;
 1508                 if ( xfrcount > idxspace )
 1509                         xfrcount = idxspace;
 1510                 if ( xfrcount > sizeof inp )
 1511                         xfrcount = sizeof inp;
 1512                 if ( xfrcount > uio->uio_resid )
 1513                         xfrcount = uio->uio_resid;
 1514 
 1515                 error = uiomove(inp, xfrcount, uio);
 1516 #ifdef MIDI_DEBUG
 1517                 if (error)
 1518                         printf("midi_write:(1) uiomove failed %d; "
 1519                                "xfrcount=%d inp=%p\n",
 1520                                error, xfrcount, inp);
 1521 #endif
 1522                 if ( error )
 1523                         break;
 1524                 
 1525                 /*
 1526                  * The number of bytes we extracted being calculated to
 1527                  * definitely fit in the buffer even with canonicalization,
 1528                  * there is no excuse for real_writebytes to return EWOULDBLOCK.
 1529                  */
 1530                 error = real_writebytes(sc, inp, xfrcount);
 1531                 KASSERT(error != EWOULDBLOCK);
 1532                 
 1533                 if ( error )
 1534                         break;
 1535                 /*
 1536                  * If this is a polling device and we just sent a buffer, let's
 1537                  * not send another without giving some other process a chance.
 1538                  */
 1539                 if ( ! (sc->props & MIDI_PROP_OUT_INTR) )
 1540                         pollout = 1;
 1541                 DPRINTFN(8,("midiwrite: uio_resid now %zu, props=%d\n",
 1542                         uio->uio_resid, sc->props));
 1543         }
 1544         return error;
 1545 
 1546 locked_exit:
 1547         MIDI_OUT_UNLOCK(sc,s);
 1548         return error;
 1549 }
 1550 
 1551 /*
 1552  * This write routine is only called from sequencer code and expects
 1553  * a write that is smaller than the MIDI buffer.
 1554  */
 1555 int
 1556 midi_writebytes(int unit, u_char *bf, int cc)
 1557 {
 1558         struct midi_softc *sc =
 1559             device_lookup_private(&midi_cd, unit);
 1560 
 1561         DPRINTFN(7, ("midi_writebytes: %p, unit=%d, cc=%d %#02x %#02x %#02x\n",
 1562                     sc, unit, cc, bf[0], bf[1], bf[2]));
 1563         return real_writebytes(sc, bf, cc);
 1564 }
 1565 
 1566 int
 1567 midiioctl(dev_t dev, u_long cmd, void *addr, int flag, struct lwp *l)
 1568 {
 1569         struct midi_softc *sc =
 1570             device_lookup_private(&midi_cd, MIDIUNIT(dev));
 1571         const struct midi_hw_if *hw = sc->hw_if;
 1572         int error;
 1573         int s;
 1574         MIDI_BUF_DECLARE(buf);
 1575 
 1576         DPRINTFN(5,("midiioctl: %p cmd=0x%08lx\n", sc, cmd));
 1577 
 1578         if (sc->dying)
 1579                 return EIO;
 1580 
 1581         error = 0;
 1582         switch (cmd) {
 1583         case FIONBIO:
 1584                 /* All handled in the upper FS layer. */
 1585                 break;
 1586         
 1587         case FIONREAD:
 1588                 /*
 1589                  * This code relies on the current implementation of midi_in
 1590                  * always updating buf and idx together in a critical section,
 1591                  * so buf always ends at a message boundary. Document this
 1592                  * ioctl as always returning a value such that the last message
 1593                  * included is complete (SysEx the only exception), and then
 1594                  * make sure the implementation doesn't regress.  NB that
 1595                  * means if this ioctl returns n and the proc then issues a
 1596                  * read of n, n bytes will be read, but if the proc issues a
 1597                  * read of m < n, fewer than m bytes may be read to ensure the
 1598                  * read ends at a message boundary.
 1599                  */
 1600                 MIDI_IN_LOCK(sc,s);
 1601                 MIDI_BUF_CONSUMER_INIT(&sc->inbuf,buf);
 1602                 MIDI_IN_UNLOCK(sc,s);
 1603                 *(int *)addr = buf_lim - buf_cur;
 1604                 break;
 1605 
 1606         case FIOASYNC:
 1607                 if (*(int *)addr) {
 1608                         if (sc->async)
 1609                                 return EBUSY;
 1610                         sc->async = l->l_proc;
 1611                         DPRINTFN(5,("midi_ioctl: FIOASYNC %p\n", l->l_proc));
 1612                 } else
 1613                         sc->async = 0;
 1614                 break;
 1615 
 1616 #if 0
 1617         case MIDI_PRETIME:
 1618                 /* XXX OSS
 1619                  * This should set up a read timeout, but that's
 1620                  * why we have poll(), so there's nothing yet. */
 1621                 error = EINVAL;
 1622                 break;
 1623 #endif
 1624 
 1625 #ifdef MIDI_SAVE
 1626         case MIDI_GETSAVE:
 1627                 error = copyout(&midisave, *(void **)addr, sizeof midisave);
 1628                 break;
 1629 #endif
 1630 
 1631         default:
 1632                 if (hw->ioctl)
 1633                         error = hw->ioctl(sc->hw_hdl, cmd, addr, flag, l);
 1634                 else
 1635                         error = EINVAL;
 1636                 break;
 1637         }
 1638         return error;
 1639 }
 1640 
 1641 int
 1642 midipoll(dev_t dev, int events, struct lwp *l)
 1643 {
 1644         struct midi_softc *sc =
 1645             device_lookup_private(&midi_cd, MIDIUNIT(dev));
 1646         int revents = 0;
 1647         int s;
 1648         MIDI_BUF_DECLARE(idx);
 1649         MIDI_BUF_DECLARE(buf);
 1650 
 1651         DPRINTFN(6,("midipoll: %p events=0x%x\n", sc, events));
 1652 
 1653         if (sc->dying)
 1654                 return POLLHUP;
 1655 
 1656         s = splaudio();
 1657 
 1658         if ((sc->flags&FREAD) && (events & (POLLIN | POLLRDNORM))) {
 1659                 simple_lock(&sc->in_lock);
 1660                 MIDI_BUF_CONSUMER_INIT(&sc->inbuf,idx);
 1661                 if (idx_cur < idx_lim)
 1662                         revents |= events & (POLLIN | POLLRDNORM);
 1663                 else
 1664                         selrecord(l, &sc->rsel);
 1665                 simple_unlock(&sc->in_lock);
 1666         }
 1667 
 1668         if ((sc->flags&FWRITE) && (events & (POLLOUT | POLLWRNORM))) {
 1669                 simple_lock(&sc->out_lock);
 1670                 MIDI_BUF_PRODUCER_INIT(&sc->outbuf,idx);
 1671                 MIDI_BUF_PRODUCER_INIT(&sc->outbuf,buf);
 1672                 if ( idx_lim - idx_cur >= 1  &&  buf_lim - buf_cur >= 3 )
 1673                         revents |= events & (POLLOUT | POLLWRNORM);
 1674                 else
 1675                         selrecord(l, &sc->wsel);
 1676                 simple_unlock(&sc->out_lock);
 1677         }
 1678 
 1679         splx(s);
 1680         return revents;
 1681 }
 1682 
 1683 static void
 1684 filt_midirdetach(struct knote *kn)
 1685 {
 1686         struct midi_softc *sc = kn->kn_hook;
 1687         int s;
 1688 
 1689         s = splaudio();
 1690         SLIST_REMOVE(&sc->rsel.sel_klist, kn, knote, kn_selnext);
 1691         splx(s);
 1692 }
 1693 
 1694 static int
 1695 filt_midiread(struct knote *kn, long hint)
 1696 {
 1697         struct midi_softc *sc = kn->kn_hook;
 1698         int s;
 1699         MIDI_BUF_DECLARE(buf);
 1700 
 1701         /* XXXLUKEM (thorpej): please make sure this is correct. */
 1702 
 1703         MIDI_IN_LOCK(sc,s);
 1704         MIDI_BUF_CONSUMER_INIT(&sc->inbuf,buf);
 1705         kn->kn_data = buf_lim - buf_cur;
 1706         MIDI_IN_UNLOCK(sc,s);
 1707         return (kn->kn_data > 0);
 1708 }
 1709 
 1710 static const struct filterops midiread_filtops =
 1711         { 1, NULL, filt_midirdetach, filt_midiread };
 1712 
 1713 static void
 1714 filt_midiwdetach(struct knote *kn)
 1715 {
 1716         struct midi_softc *sc = kn->kn_hook;
 1717         int s;
 1718 
 1719         s = splaudio();
 1720         SLIST_REMOVE(&sc->wsel.sel_klist, kn, knote, kn_selnext);
 1721         splx(s);
 1722 }
 1723 
 1724 static int
 1725 filt_midiwrite(struct knote *kn, long hint)
 1726 {
 1727         struct midi_softc *sc = kn->kn_hook;
 1728         int s;
 1729         MIDI_BUF_DECLARE(idx);
 1730         MIDI_BUF_DECLARE(buf);
 1731 
 1732         /* XXXLUKEM (thorpej): please make sure this is correct. */
 1733 
 1734         MIDI_OUT_LOCK(sc,s);
 1735         MIDI_BUF_PRODUCER_INIT(&sc->outbuf,idx);
 1736         MIDI_BUF_PRODUCER_INIT(&sc->outbuf,buf);
 1737         kn->kn_data = ((buf_lim - buf_cur)-1)>>1;
 1738         if ( kn->kn_data > idx_lim - idx_cur )
 1739                 kn->kn_data = idx_lim - idx_cur;
 1740         MIDI_OUT_UNLOCK(sc,s);
 1741         return (kn->kn_data > 0);
 1742 }
 1743 
 1744 static const struct filterops midiwrite_filtops =
 1745         { 1, NULL, filt_midiwdetach, filt_midiwrite };
 1746 
 1747 int
 1748 midikqfilter(dev_t dev, struct knote *kn)
 1749 {
 1750         struct midi_softc *sc =
 1751             device_lookup_private(&midi_cd, MIDIUNIT(dev));
 1752         struct klist *klist;
 1753         int s;
 1754 
 1755         switch (kn->kn_filter) {
 1756         case EVFILT_READ:
 1757                 klist = &sc->rsel.sel_klist;
 1758                 kn->kn_fop = &midiread_filtops;
 1759                 break;
 1760 
 1761         case EVFILT_WRITE:
 1762                 klist = &sc->wsel.sel_klist;
 1763                 kn->kn_fop = &midiwrite_filtops;
 1764                 break;
 1765 
 1766         default:
 1767                 return (EINVAL);
 1768         }
 1769 
 1770         kn->kn_hook = sc;
 1771 
 1772         s = splaudio();
 1773         SLIST_INSERT_HEAD(klist, kn, kn_selnext);
 1774         splx(s);
 1775 
 1776         return (0);
 1777 }
 1778 
 1779 void
 1780 midi_getinfo(dev_t dev, struct midi_info *mi)
 1781 {
 1782         struct midi_softc *sc;
 1783 
 1784         sc = device_lookup_private(&midi_cd, MIDIUNIT(dev));
 1785         if (sc == NULL)
 1786                 return;
 1787         if (sc->dying)
 1788                 return;
 1789 
 1790         sc->hw_if->getinfo(sc->hw_hdl, mi);
 1791 }
 1792 
 1793 #elif NMIDIBUS > 0 /* but NMIDI == 0 */
 1794 
 1795 void midi_register_hw_if_ext(struct midi_hw_if_ext *exthw) { /* stub */
 1796 }
 1797 
 1798 #endif /* NMIDI > 0 */
 1799 
 1800 #if NMIDI > 0 || NMIDIBUS > 0
 1801 
 1802 int     audioprint(void *, const char *);
 1803 
 1804 device_t
 1805 midi_attach_mi(const struct midi_hw_if *mhwp, void *hdlp, device_t dev)
 1806 {
 1807         struct audio_attach_args arg;
 1808 
 1809 #ifdef DIAGNOSTIC
 1810         if (mhwp == NULL) {
 1811                 aprint_error("midi_attach_mi: NULL\n");
 1812                 return (0);
 1813         }
 1814 #endif
 1815         arg.type = AUDIODEV_TYPE_MIDI;
 1816         arg.hwif = mhwp;
 1817         arg.hdl = hdlp;
 1818         return (config_found(dev, &arg, audioprint));
 1819 }
 1820 
 1821 #endif /* NMIDI > 0 || NMIDIBUS > 0 */

Cache object: fee6250ae13f11dca8c0dcf56ada93d6


[ 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.