]> git.karo-electronics.de Git - linux-beck.git/commitdiff
ALSA: firewire-lib: avoid endless loop to transfer MIDI messages at fatal error
authorTakashi Sakamoto <o-takashi@sakamocchi.jp>
Thu, 8 Oct 2015 23:10:29 +0000 (08:10 +0900)
committerTakashi Iwai <tiwai@suse.de>
Fri, 9 Oct 2015 07:57:06 +0000 (09:57 +0200)
Currently, when asynchronous transactions finish in error state and
retries, work scheduling and work running also continues. This
should be canceled at fatal error because it can cause endless loop.

This commit enables to cancel transferring MIDI messages when transactions
encounter fatal errors. This is achieved by setting error state.

Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
sound/firewire/lib.c
sound/firewire/lib.h

index 9a98c7cd8744878cba39fcaf139b6d2ff1007646..edf1c8bd25a6600b67c3a3f3d697b3c1efb6c741 100644 (file)
@@ -79,6 +79,9 @@ static void async_midi_port_callback(struct fw_card *card, int rcode,
        else if (!rcode_is_permanent_error(rcode))
                /* To start next transaction immediately for recovery. */
                port->next_ktime = ktime_set(0, 0);
        else if (!rcode_is_permanent_error(rcode))
                /* To start next transaction immediately for recovery. */
                port->next_ktime = ktime_set(0, 0);
+       else
+               /* Don't continue processing. */
+               port->error = true;
 
        port->idling = true;
 
 
        port->idling = true;
 
@@ -94,8 +97,8 @@ static void midi_port_work(struct work_struct *work)
        int generation;
        int type;
 
        int generation;
        int type;
 
-       /* Under transacting. */
-       if (!port->idling)
+       /* Under transacting or error state. */
+       if (!port->idling || port->error)
                return;
 
        /* Nothing to do. */
                return;
 
        /* Nothing to do. */
@@ -119,6 +122,9 @@ static void midi_port_work(struct work_struct *work)
                if (port->consume_bytes == 0) {
                        port->next_ktime = ktime_set(0, 0);
                        schedule_work(&port->work);
                if (port->consume_bytes == 0) {
                        port->next_ktime = ktime_set(0, 0);
                        schedule_work(&port->work);
+               } else {
+                       /* Fatal error. */
+                       port->error = true;
                }
                return;
        }
                }
                return;
        }
@@ -178,6 +184,7 @@ int snd_fw_async_midi_port_init(struct snd_fw_async_midi_port *port,
        port->fill = fill;
        port->idling = true;
        port->next_ktime = ktime_set(0, 0);
        port->fill = fill;
        port->idling = true;
        port->next_ktime = ktime_set(0, 0);
+       port->error = false;
 
        INIT_WORK(&port->work, midi_port_work);
 
 
        INIT_WORK(&port->work, midi_port_work);
 
index 59e08658721268e24e17562b58f73a03f18ec060..f3f6f84c48d69747cc0fa3bd815d986c79ca0d78 100644 (file)
@@ -32,6 +32,7 @@ struct snd_fw_async_midi_port {
        struct work_struct work;
        bool idling;
        ktime_t next_ktime;
        struct work_struct work;
        bool idling;
        ktime_t next_ktime;
+       bool error;
 
        u64 addr;
        struct fw_transaction transaction;
 
        u64 addr;
        struct fw_transaction transaction;
@@ -58,8 +59,10 @@ static inline void
 snd_fw_async_midi_port_run(struct snd_fw_async_midi_port *port,
                           struct snd_rawmidi_substream *substream)
 {
 snd_fw_async_midi_port_run(struct snd_fw_async_midi_port *port,
                           struct snd_rawmidi_substream *substream)
 {
-       port->substream = substream;
-       schedule_work(&port->work);
+       if (!port->error) {
+               port->substream = substream;
+               schedule_work(&port->work);
+       }
 }
 
 /**
 }
 
 /**
@@ -70,6 +73,7 @@ static inline void
 snd_fw_async_midi_port_finish(struct snd_fw_async_midi_port *port)
 {
        port->substream = NULL;
 snd_fw_async_midi_port_finish(struct snd_fw_async_midi_port *port)
 {
        port->substream = NULL;
+       port->error = false;
 }
 
 #endif
 }
 
 #endif