The helper functions for asynchronous MIDI port use 'tasklet' to run IEEE 1394 asynchronous transactions, while running transactions need to wait for response. In this reason, one transaction should be transferred at one tasklet scheduling, because tasklet runs one kernel thread available for the other tasks
For these reasons, this commit serialize request/response transactions, by adding one boolean member.
Signed-off-by: Takashi Sakamoto o-takashi@sakamocchi.jp --- sound/firewire/lib.c | 8 ++++++++ sound/firewire/lib.h | 1 + 2 files changed, 9 insertions(+)
diff --git a/sound/firewire/lib.c b/sound/firewire/lib.c index f5b5526..a66e011 100644 --- a/sound/firewire/lib.c +++ b/sound/firewire/lib.c @@ -76,6 +76,8 @@ static void async_midi_port_callback(struct fw_card *card, int rcode,
if (rcode == RCODE_COMPLETE && substream != NULL) snd_rawmidi_transmit_ack(substream, port->consume_bytes); + + port->idling = true; }
static void midi_port_tasklet(unsigned long data) @@ -86,6 +88,10 @@ static void midi_port_tasklet(unsigned long data) int generation; int type;
+ /* Under transacting. */ + if (!port->idling) + return; + /* Nothing to do. */ if (substream == NULL || snd_rawmidi_transmit_empty(substream)) return; @@ -110,6 +116,7 @@ static void midi_port_tasklet(unsigned long data) type = TCODE_WRITE_BLOCK_REQUEST;
/* Start this transaction. */ + port->idling = false; generation = port->parent->generation; smp_rmb(); /* node_id vs. generation */ fw_send_request(port->parent->card, &port->transaction, type, @@ -142,6 +149,7 @@ int snd_fw_async_midi_port_init(struct snd_fw_async_midi_port *port, port->parent = fw_parent_device(unit); port->addr = addr; port->packetize = packetize; + port->idling = true;
tasklet_init(&port->tasklet, midi_port_tasklet, (unsigned long)port);
diff --git a/sound/firewire/lib.h b/sound/firewire/lib.h index c662bf9..9d76f5c 100644 --- a/sound/firewire/lib.h +++ b/sound/firewire/lib.h @@ -25,6 +25,7 @@ static inline bool rcode_is_permanent_error(int rcode) struct snd_fw_async_midi_port { struct fw_device *parent; struct tasklet_struct tasklet; + bool idling;
__u64 addr; struct fw_transaction transaction;