Certain midi uarts don't have interrupts, so when data is sent, the
driver spins (at IPL_AUDIO) until the uart becomes ready. This is not
a big problem because uarts have ~16-32 byte fifos, and programs don't
send large chunks of data, so uarts always appear ready. Except for
large messages, which cause spinning.

This diff is to avoid spinning and to make midi output code simpler.
On my system, interrupt time during a large transfer drops from 5%
to ~0%.

If you use external midi synths connected to umidi, eap, autri, and/or
mpu, I'd like to know if this diff causes any regression. To test,
just do your usual stuff involving midi output.

thanks

-- Alexandre

Index: midi.c
===================================================================
RCS file: /cvs/src/sys/dev/midi.c,v
retrieving revision 1.26
diff -u -p -r1.26 midi.c
--- midi.c      2 Jul 2011 22:20:07 -0000       1.26
+++ midi.c      7 Mar 2012 20:50:43 -0000
@@ -232,51 +232,14 @@ void
 midi_out_do(struct midi_softc *sc)
 {
        struct midi_buffer *mb = &sc->outbuf;
-       unsigned            i;
-       int                 error;
 
-       /*
-        * If output interrupts are not supported then we write MIDI_MAXWRITE
-        * bytes instead of 1, and then we wait sc->wait
-        */
-
-       i = sc->props & MIDI_PROP_OUT_INTR ? 1 : MIDI_MAXWRITE;
-       while (i != 0) {
-               if (mb->used == 0)
+       while (mb->used > 0) {
+               if (!sc->hw_if->output(sc->hw_hdl, mb->data[mb->start]))
                        break;
-               error = sc->hw_if->output(sc->hw_hdl, mb->data[mb->start]);
-               /*
-                * 0 means that data is being sent, an interrupt will
-                * be generated when the interface becomes ready again
-                *
-                * EINPROGRESS means that data has been queued, but
-                * will not be sent immediately and thus will not
-                * generate interrupt, in this case we can send
-                * another byte. The flush() method can be called
-                * to force the transfer.
-                *
-                * EAGAIN means that data cannot be queued or sent;
-                * because the interface isn't ready. An interrupt
-                * will be generated once the interface is ready again
-                *
-                * any other (fatal) error code means that data couldn't
-                * be sent and was lost, interrupt will not be generated
-                */
-               if (error == EINPROGRESS) {
-                       MIDIBUF_REMOVE(mb, 1);
-                       if (MIDIBUF_ISEMPTY(mb)) {
-                               if (sc->hw_if->flush != NULL)
-                                       sc->hw_if->flush(sc->hw_hdl);
-                               midi_out_stop(sc);
-                               return;
-                       }
-               } else if (error == 0) {
-                       MIDIBUF_REMOVE(mb, 1);
-                       i--;
-               } else if (error == EAGAIN) {
-                       break;
-               } else {
-                       MIDIBUF_INIT(mb);
+               MIDIBUF_REMOVE(mb, 1);
+               if (MIDIBUF_ISEMPTY(mb)) {
+                       if (sc->hw_if->flush != NULL)
+                               sc->hw_if->flush(sc->hw_hdl);
                        midi_out_stop(sc);
                        return;
                }
@@ -286,7 +249,7 @@ midi_out_do(struct midi_softc *sc)
                if (MIDIBUF_ISEMPTY(mb))
                        midi_out_stop(sc);
                else
-                       timeout_add(&sc->timeo, sc->wait);
+                       timeout_add(&sc->timeo, 1);
        }
 }
 
@@ -554,13 +517,11 @@ midiclose(dev_t dev, int fflag, int devt
        /*
         * some hw_if->close() reset immediately the midi uart
         * which flushes the internal buffer of the uart device,
-        * so we may lose some (important) data. To avoid this, we sleep 2*wait,
-        * which gives the time to the uart to drain its internal buffers.
-        *
-        * Note: we'd better sleep in the corresponding hw_if->close()
+        * so we may lose some (important) data. To avoid this,
+        * sleep 20ms (around 64 bytes) to give the time to the
+        * uart to drain its internal buffers.
         */
-
-       tsleep(&sc->wchan, PWAIT, "mid_cl", 2 * sc->wait);
+       tsleep(&sc->wchan, PWAIT, "mid_cl", hz * MIDI_MAXWRITE / MIDI_RATE);
        sc->hw_if->close(sc->hw_hdl);
        sc->isopen = 0;
        return 0;
@@ -582,9 +543,6 @@ midi_attach(struct midi_softc *sc, struc
        struct midi_info          mi;
 
        sc->isdying = 0;
-       sc->wait = (hz * MIDI_MAXWRITE) /  MIDI_RATE;
-       if (sc->wait == 0)
-               sc->wait = 1;
        sc->hw_if->getinfo(sc->hw_hdl, &mi);
        sc->props = mi.props;
        sc->isopen = 0;
Index: midivar.h
===================================================================
RCS file: /cvs/src/sys/dev/midivar.h,v
retrieving revision 1.5
diff -u -p -r1.5 midivar.h
--- midivar.h   21 Nov 2005 18:16:38 -0000      1.5
+++ midivar.h   7 Mar 2012 20:50:44 -0000
@@ -85,7 +85,6 @@ struct midi_softc {
        int                 props;              /* midi hw proprieties */
        int                 rchan;
        int                 wchan;
-       unsigned            wait;               /* see midi_out_do */
        struct selinfo      rsel;
        struct selinfo      wsel;
        struct proc        *async;
Index: isa/mpu401.c
===================================================================
RCS file: /cvs/src/sys/dev/isa/mpu401.c,v
retrieving revision 1.11
diff -u -p -r1.11 mpu401.c
--- isa/mpu401.c        26 Jun 2008 05:42:16 -0000      1.11
+++ isa/mpu401.c        7 Mar 2012 20:50:45 -0000
@@ -208,12 +208,12 @@ mpu_output(v, d)
                mpu_readinput(sc);
                splx(s);
        }
-       if (mpu_waitready(sc)) {
-               DPRINTF(("mpu_output: not ready\n"));
-               return EIO;
-       }
+       if (MPU_GETSTATUS(sc->iot, sc->ioh) & MPU_OUTPUT_BUSY)
+               delay(10);
+       if (MPU_GETSTATUS(sc->iot, sc->ioh) & MPU_OUTPUT_BUSY)
+               return 0;
        bus_space_write_1(sc->iot, sc->ioh, MPU_DATA, d);
-       return 0;
+       return 1;
 }
 
 void
Index: isa/sbdsp.c
===================================================================
RCS file: /cvs/src/sys/dev/isa/sbdsp.c,v
retrieving revision 1.31
diff -u -p -r1.31 sbdsp.c
--- isa/sbdsp.c 15 Jul 2010 03:43:11 -0000      1.31
+++ isa/sbdsp.c 7 Mar 2012 20:50:47 -0000
@@ -2385,10 +2385,9 @@ sbdsp_midi_output(addr, d)
        struct sbdsp_softc *sc = addr;
 
        if (sc->sc_model < SB_20 && sbdsp_wdsp(sc, SB_MIDI_WRITE))
-               return EIO;
-       if (sbdsp_wdsp(sc, d))
-               return EIO;
-       return 0;
+               return 1;
+       (void)sbdsp_wdsp(sc, d);
+       return 1;
 }
 
 void
Index: pci/autri.c
===================================================================
RCS file: /cvs/src/sys/dev/pci/autri.c,v
retrieving revision 1.30
diff -u -p -r1.30 autri.c
--- pci/autri.c 3 Jul 2011 15:47:16 -0000       1.30
+++ pci/autri.c 7 Mar 2012 20:50:48 -0000
@@ -1612,16 +1612,12 @@ int
 autri_midi_output(void *addr, int d)
 {
        struct autri_softc *sc = addr;
-       int x;
 
-       for (x = 0; x != MIDI_BUSY_WAIT; x++) {
-               if ((TREAD1(sc, AUTRI_MPUR1) & AUTRI_MIDIOUT_READY) == 0) {
-                       TWRITE1(sc, AUTRI_MPUR0, d);
-                       return (0);
-               }
-               delay(MIDI_BUSY_DELAY);
+       if ((TREAD1(sc, AUTRI_MPUR1) & AUTRI_MIDIOUT_READY) != 0) {
+               TWRITE1(sc, AUTRI_MPUR0, d);
+               return 0;
        }
-       return (EIO);
+       return 1;
 }
 
 void
Index: pci/eap.c
===================================================================
RCS file: /cvs/src/sys/dev/pci/eap.c,v
retrieving revision 1.43
diff -u -p -r1.43 eap.c
--- pci/eap.c   3 Jul 2011 15:47:17 -0000       1.43
+++ pci/eap.c   7 Mar 2012 20:50:50 -0000
@@ -1707,16 +1707,11 @@ int
 eap_midi_output(void *addr, int d)
 {
        struct eap_softc *sc = addr;
-       int x;
 
-       for (x = 0; x != MIDI_BUSY_WAIT; x++) {
-               if (EREAD1(sc, EAP_UART_STATUS) & EAP_US_TXRDY) {
-                       EWRITE1(sc, EAP_UART_DATA, d);
-                       return (0);
-               }
-               delay(MIDI_BUSY_DELAY);
-       }
-       return (EIO);
+       if (!(EREAD1(sc, EAP_UART_STATUS) & EAP_US_TXRDY))
+               return 0;
+       EWRITE1(sc, EAP_UART_DATA, d);
+       return 1;
 }
 
 void
Index: pci/eapreg.h
===================================================================
RCS file: /cvs/src/sys/dev/pci/eapreg.h,v
retrieving revision 1.3
diff -u -p -r1.3 eapreg.h
--- pci/eapreg.h        26 Jun 2008 05:42:17 -0000      1.3
+++ pci/eapreg.h        7 Mar 2012 20:50:50 -0000
@@ -263,9 +263,6 @@
 #define EAP_RECORD_CLASS       11
 #define EAP_INPUT_CLASS                12
 
-#define MIDI_BUSY_WAIT         100
-#define MIDI_BUSY_DELAY                100     /* Delay when UART is busy */
-
 #define EAP_EV1938_A  0x00
 #define EAP_ES1371_A  0x02
 #define EAP_CT5880_C  0x02
Index: pci/envy.c
===================================================================
RCS file: /cvs/src/sys/dev/pci/envy.c,v
retrieving revision 1.50
diff -u -p -r1.50 envy.c
--- pci/envy.c  27 Apr 2011 07:01:33 -0000      1.50
+++ pci/envy.c  7 Mar 2012 20:50:52 -0000
@@ -2390,10 +2390,13 @@ int
 envy_midi_output(void *self, int data)
 {
        struct envy_softc *sc = (struct envy_softc *)self;
+       int st;
        
-       envy_midi_wait(sc);
+       st = envy_ccs_read(sc, ENVY_CCS_MIDISTAT0);
+       if (st & ENVY_MIDISTAT_OBUSY(sc))
+               return 0;
        envy_ccs_write(sc, ENVY_CCS_MIDIDATA0, data);
-       return 0;
+       return 1;
 }
 
 void
Index: usb/umidi.c
===================================================================
RCS file: /cvs/src/sys/dev/usb/umidi.c,v
retrieving revision 1.32
diff -u -p -r1.32 umidi.c
--- usb/umidi.c 3 Jul 2011 15:47:17 -0000       1.32
+++ usb/umidi.c 7 Mar 2012 20:50:54 -0000
@@ -313,7 +313,7 @@ umidi_output(void *addr, int d)
        struct umidi_mididev *mididev = addr;
 
        if (!mididev->out_jack || !mididev->opened)
-               return EIO;
+               return 1;
 
        return out_jack_output(mididev->out_jack, d);
 }
@@ -745,9 +745,7 @@ alloc_all_jacks(struct umidi_softc *sc)
                jack->binded = 0;
                jack->arg = NULL;
                jack->u.out.intr = NULL;
-#ifdef DIAGNOSTIC
-               jack->wait = 0;
-#endif
+               jack->intr = 0;
                jack->cable_number = i;
                jack++;
        }
@@ -1165,56 +1163,31 @@ out_jack_output(struct umidi_jack *j, in
        int s;
 
        if (sc->sc_dying)
-               return EIO;
+               return 1;
        if (!j->opened)
-               return ENODEV;
-               
+               return 1;
        s = splusb();
-       if (ep->used == ep->packetsize) {
-#ifdef DIAGNOSTIC
-               if (j->wait == 0) {
-                       j->wait = 1;
-#endif
+       if (ep->busy) {
+               if (!j->intr) {
                        SIMPLEQ_INSERT_TAIL(&ep->intrq, j, intrq_entry);
                        ep->pending++;
-#ifdef DIAGNOSTIC
-               } else {
-                       printf("umidi: (again) %d: already on intrq\n", 
-                           j->cable_number);
-               }
-#endif
+                       j->intr = 1;
+               }               
                splx(s);
-               return EAGAIN;
+               return 0;
        }
-       
-       if (!out_build_packet(j->cable_number, &j->packet, d, 
-           ep->buffer + ep->used)) {
+       if (!out_build_packet(j->cable_number, &j->packet, d,
+               ep->buffer + ep->used)) {
                splx(s);
-               return EINPROGRESS;
+               return 1;
        }
        ep->used += UMIDI_PACKET_SIZE;
-       if (ep->used < ep->packetsize) {
-               splx(s);
-               return EINPROGRESS;
-       }
-#ifdef DIAGNOSTIC
-       if (j->wait == 0) {
-               j->wait = 1;            
-#endif
-               SIMPLEQ_INSERT_TAIL(&ep->intrq, j, intrq_entry);
-               ep->pending++;
-#ifdef DIAGNOSTIC
-       } else {
-               printf("umidi: (ok) %d: already on intrq\n", 
-                   j->cable_number);
-       }
-#endif
-       if (!ep->busy) {
+       if (ep->used == ep->packetsize) {
                ep->busy = 1;
                start_output_transfer(ep);
        }
        splx(s);
-       return 0;
+       return 1;
 }
 
 static void
@@ -1278,6 +1251,7 @@ out_intr(usbd_xfer_handle xfer, usbd_pri
                return;
 
        ep->used = 0;
+       ep->busy = 0;
        for (pending = ep->pending; pending > 0; pending--) {
                j = SIMPLEQ_FIRST(&ep->intrq);
 #ifdef DIAGNOSTIC
@@ -1288,17 +1262,9 @@ out_intr(usbd_xfer_handle xfer, usbd_pri
 #endif
                SIMPLEQ_REMOVE_HEAD(&ep->intrq, intrq_entry);
                ep->pending--;
-#ifdef DIAGNOSTIC
-               j->wait = 0;
-#endif
+               j->intr = 0;
                if (j->opened && j->u.out.intr)
                        (*j->u.out.intr)(j->arg);
-       }
-
-       if (ep->used == 0) {
-               ep->busy = 0;
-       } else {
-               start_output_transfer(ep);
        }
 }
 
Index: usb/umidivar.h
===================================================================
RCS file: /cvs/src/sys/dev/usb/umidivar.h,v
retrieving revision 1.12
diff -u -p -r1.12 umidivar.h
--- usb/umidivar.h      26 Jun 2008 05:42:19 -0000      1.12
+++ usb/umidivar.h      7 Mar 2012 20:50:54 -0000
@@ -69,7 +69,7 @@ struct umidi_jack {
        int                     opened;
        SIMPLEQ_ENTRY(umidi_jack) intrq_entry;  
 #ifdef DIAGNOSTIC
-       unsigned                wait;
+       unsigned                intr;
 #endif
        union {
                struct {

Reply via email to