ChangeSet 1.2181.25.27, 2005/03/22 09:12:31+01:00, [EMAIL PROTECTED]

        [ALSA] rawmidi - move output trigger into a tasklet
        
        Documentation,RawMidi Midlevel
        Calling the output trigger callback from another interrupt handler
        can lead to unintuitive locking requirements (i.e., spin_lock_irqsave)
        in the sound card interrupt handler.  Moving the call to the callback
        into a tasklet cures this, and has the added benefit that the callback
        is called only once if more that one sequencer event has been
        delivered in one timer interrupt tick.
        
        Signed-off-by: Clemens Ladisch <[EMAIL PROTECTED]>



 Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl |    9 -
 include/sound/rawmidi.h                                      |    5 -
 sound/core/rawmidi.c                                         |   55 +++++++----
 3 files changed, 40 insertions(+), 29 deletions(-)


diff -Nru a/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl 
b/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl
--- a/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl      
2005-03-30 16:14:56 -08:00
+++ b/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl      
2005-03-30 16:14:56 -08:00
@@ -4604,15 +4604,6 @@
         zero <parameter>up</parameter> parameter when the transmission
         of data should be aborted.
         </para>
-
-        <para>
-        The <function>trigger</function> callback with nonzero
-        <paramater>up</parameter> parameter may be called from another
-        hardware interrupt handler.  This means that all spinlocks
-        taken in the <function>trigger</function> callback must be
-        taken with <function>spin_lock_irqsave</function> even when
-        you are in your own interrupt handler.
-        </para>
       </section>
 
       <section id="rawmidi-interface-op-trigger-in">
diff -Nru a/include/sound/rawmidi.h b/include/sound/rawmidi.h
--- a/include/sound/rawmidi.h   2005-03-30 16:14:56 -08:00
+++ b/include/sound/rawmidi.h   2005-03-30 16:14:56 -08:00
@@ -79,9 +79,10 @@
        /* misc */
        spinlock_t lock;
        wait_queue_head_t sleep;
-       /* event handler (room [output] or new bytes [input]) */
-       struct tasklet_struct event_tasklet;
+       /* event handler (new bytes, input only) */
        void (*event)(snd_rawmidi_substream_t *substream);
+       /* defers calls to event [input] or ops->trigger [output] */
+       struct tasklet_struct tasklet;
        /* private data */
        void *private_data;
        void (*private_free)(snd_rawmidi_substream_t *substream);
diff -Nru a/sound/core/rawmidi.c b/sound/core/rawmidi.c
--- a/sound/core/rawmidi.c      2005-03-30 16:14:56 -08:00
+++ b/sound/core/rawmidi.c      2005-03-30 16:14:56 -08:00
@@ -85,12 +85,18 @@
               (!substream->append || runtime->avail >= count);
 }
 
-static void snd_rawmidi_event_tasklet(unsigned long data)
+static void snd_rawmidi_input_event_tasklet(unsigned long data)
 {
        snd_rawmidi_substream_t *substream = (snd_rawmidi_substream_t *)data;
        substream->runtime->event(substream);
 }
 
+static void snd_rawmidi_output_trigger_tasklet(unsigned long data)
+{
+       snd_rawmidi_substream_t *substream = (snd_rawmidi_substream_t *)data;
+       substream->ops->trigger(substream, 1);
+}
+
 static int snd_rawmidi_runtime_create(snd_rawmidi_substream_t * substream)
 {
        snd_rawmidi_runtime_t *runtime;
@@ -99,8 +105,14 @@
                return -ENOMEM;
        spin_lock_init(&runtime->lock);
        init_waitqueue_head(&runtime->sleep);
-       tasklet_init(&runtime->event_tasklet, snd_rawmidi_event_tasklet,
-                    (unsigned long)substream);
+       if (substream->stream == SNDRV_RAWMIDI_STREAM_INPUT)
+               tasklet_init(&runtime->tasklet,
+                            snd_rawmidi_input_event_tasklet,
+                            (unsigned long)substream);
+       else
+               tasklet_init(&runtime->tasklet,
+                            snd_rawmidi_output_trigger_tasklet,
+                            (unsigned long)substream);
        runtime->event = NULL;
        runtime->buffer_size = PAGE_SIZE;
        runtime->avail_min = 1;
@@ -127,11 +139,21 @@
        return 0;
 }
 
-static void snd_rawmidi_trigger(snd_rawmidi_substream_t * substream, int up)
+static inline void snd_rawmidi_output_trigger(snd_rawmidi_substream_t * 
substream, int up)
+{
+       if (up) {
+               tasklet_hi_schedule(&substream->runtime->tasklet);
+       } else {
+               tasklet_kill(&substream->runtime->tasklet);
+               substream->ops->trigger(substream, 0);
+       }
+}
+
+static void snd_rawmidi_input_trigger(snd_rawmidi_substream_t * substream, int 
up)
 {
        substream->ops->trigger(substream, up);
        if (!up && substream->runtime->event)
-               tasklet_kill(&substream->runtime->event_tasklet);
+               tasklet_kill(&substream->runtime->tasklet);
 }
 
 int snd_rawmidi_drop_output(snd_rawmidi_substream_t * substream)
@@ -139,7 +161,7 @@
        unsigned long flags;
        snd_rawmidi_runtime_t *runtime = substream->runtime;
 
-       snd_rawmidi_trigger(substream, 0);
+       snd_rawmidi_output_trigger(substream, 0);
        runtime->drain = 0;
        spin_lock_irqsave(&runtime->lock, flags);
        runtime->appl_ptr = runtime->hw_ptr = 0;
@@ -182,7 +204,7 @@
        unsigned long flags;
        snd_rawmidi_runtime_t *runtime = substream->runtime;
 
-       snd_rawmidi_trigger(substream, 0);
+       snd_rawmidi_input_trigger(substream, 0);
        runtime->drain = 0;
        spin_lock_irqsave(&runtime->lock, flags);
        runtime->appl_ptr = runtime->hw_ptr = 0;
@@ -461,7 +483,7 @@
                substream = rfile->input;
                rfile->input = NULL;
                runtime = substream->runtime;
-               snd_rawmidi_trigger(substream, 0);
+               snd_rawmidi_input_trigger(substream, 0);
                substream->ops->close(substream);
                if (runtime->private_free != NULL)
                        runtime->private_free(substream);
@@ -480,7 +502,7 @@
                                snd_rawmidi_kernel_write(substream, &buf, 1);
                        }
                        if (snd_rawmidi_drain_output(substream) == -ERESTARTSYS)
-                               snd_rawmidi_trigger(substream, 0);
+                               snd_rawmidi_output_trigger(substream, 0);
                        substream->ops->close(substream);
                        if (runtime->private_free != NULL)
                                runtime->private_free(substream);
@@ -878,7 +900,7 @@
        }
        if (result > 0) {
                if (runtime->event)
-                       tasklet_hi_schedule(&runtime->event_tasklet);
+                       tasklet_hi_schedule(&runtime->tasklet);
                else if (snd_rawmidi_ready(substream))
                        wake_up(&runtime->sleep);
        }
@@ -922,7 +944,7 @@
 
 long snd_rawmidi_kernel_read(snd_rawmidi_substream_t *substream, unsigned char 
*buf, long count)
 {
-       snd_rawmidi_trigger(substream, 1);
+       snd_rawmidi_input_trigger(substream, 1);
        return snd_rawmidi_kernel_read1(substream, buf, count, 1);
 }
 
@@ -939,7 +961,7 @@
        if (substream == NULL)
                return -EIO;
        runtime = substream->runtime;
-       snd_rawmidi_trigger(substream, 1);
+       snd_rawmidi_input_trigger(substream, 1);
        result = 0;
        while (count > 0) {
                spin_lock_irq(&runtime->lock);
@@ -1075,11 +1097,8 @@
        runtime->avail += count;
        substream->bytes += count;
        if (count > 0) {
-               if (runtime->drain ||
-                   (runtime->event == NULL && snd_rawmidi_ready(substream)))
+               if (runtime->drain || snd_rawmidi_ready(substream))
                        wake_up(&runtime->sleep);
-               if (runtime->event)
-                       tasklet_hi_schedule(&runtime->event_tasklet);
        }
        spin_unlock_irqrestore(&runtime->lock, flags);
        return count;
@@ -1149,7 +1168,7 @@
        count1 = runtime->avail < runtime->buffer_size;
        spin_unlock_irqrestore(&runtime->lock, flags);
        if (count1)
-               snd_rawmidi_trigger(substream, 1);
+               snd_rawmidi_output_trigger(substream, 1);
        return result;
 }
 
@@ -1234,7 +1253,7 @@
        rfile = file->private_data;
        if (rfile->input != NULL) {
                runtime = rfile->input->runtime;
-               snd_rawmidi_trigger(rfile->input, 1);
+               snd_rawmidi_input_trigger(rfile->input, 1);
                poll_wait(file, &runtime->sleep, wait);
        }
        if (rfile->output != NULL) {
-
To unsubscribe from this list: send the line "unsubscribe bk-commits-head" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to