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

Cache object: cb9810c36836c36034890c6d53067130


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