summaryrefslogtreecommitdiff
path: root/sound/firewire/oxfw/oxfw-scs1x.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/firewire/oxfw/oxfw-scs1x.c')
-rw-r--r--sound/firewire/oxfw/oxfw-scs1x.c35
1 files changed, 25 insertions, 10 deletions
diff --git a/sound/firewire/oxfw/oxfw-scs1x.c b/sound/firewire/oxfw/oxfw-scs1x.c
index bb53eb35721b..f897c9831077 100644
--- a/sound/firewire/oxfw/oxfw-scs1x.c
+++ b/sound/firewire/oxfw/oxfw-scs1x.c
@@ -26,11 +26,13 @@ struct fw_scs1x {
u8 output_bytes;
bool output_escaped;
bool output_escape_high_nibble;
- struct tasklet_struct tasklet;
+ struct work_struct work;
wait_queue_head_t idle_wait;
u8 buffer[HSS1394_MAX_PACKET_SIZE];
bool transaction_running;
struct fw_transaction transaction;
+ unsigned int transaction_bytes;
+ bool error;
struct fw_device *fw_dev;
};
@@ -125,11 +127,16 @@ static void scs_write_callback(struct fw_card *card, int rcode,
{
struct fw_scs1x *scs = callback_data;
- if (rcode == RCODE_GENERATION)
- ; /* TODO: retry this packet */
+ if (!rcode_is_permanent_error(rcode)) {
+ /* Don't retry for this data. */
+ if (rcode == RCODE_COMPLETE)
+ scs->transaction_bytes = 0;
+ } else {
+ scs->error = true;
+ }
scs->transaction_running = false;
- tasklet_schedule(&scs->tasklet);
+ schedule_work(&scs->work);
}
static bool is_valid_running_status(u8 status)
@@ -165,9 +172,9 @@ static bool is_invalid_cmd(u8 status)
status == 0xfd;
}
-static void scs_output_tasklet(unsigned long data)
+static void scs_output_work(struct work_struct *work)
{
- struct fw_scs1x *scs = (struct fw_scs1x *)data;
+ struct fw_scs1x *scs = container_of(work, struct fw_scs1x, work);
struct snd_rawmidi_substream *stream;
unsigned int i;
u8 byte;
@@ -177,12 +184,15 @@ static void scs_output_tasklet(unsigned long data)
return;
stream = ACCESS_ONCE(scs->output);
- if (!stream) {
+ if (!stream || scs->error) {
scs->output_idle = true;
wake_up(&scs->idle_wait);
return;
}
+ if (scs->transaction_bytes > 0)
+ goto retry;
+
i = scs->output_bytes;
for (;;) {
if (snd_rawmidi_transmit(stream, &byte, 1) != 1) {
@@ -253,13 +263,16 @@ static void scs_output_tasklet(unsigned long data)
scs->output_bytes = 1;
scs->output_escaped = false;
+ scs->transaction_bytes = i;
+retry:
scs->transaction_running = true;
generation = scs->fw_dev->generation;
smp_rmb(); /* node_id vs. generation */
fw_send_request(scs->fw_dev->card, &scs->transaction,
TCODE_WRITE_BLOCK_REQUEST, scs->fw_dev->node_id,
generation, scs->fw_dev->max_speed, HSS1394_ADDRESS,
- scs->buffer, i, scs_write_callback, scs);
+ scs->buffer, scs->transaction_bytes,
+ scs_write_callback, scs);
}
static int midi_capture_open(struct snd_rawmidi_substream *stream)
@@ -309,9 +322,11 @@ static void midi_playback_trigger(struct snd_rawmidi_substream *stream, int up)
scs->output_bytes = 1;
scs->output_escaped = false;
scs->output_idle = false;
+ scs->transaction_bytes = 0;
+ scs->error = false;
ACCESS_ONCE(scs->output) = stream;
- tasklet_schedule(&scs->tasklet);
+ schedule_work(&scs->work);
} else {
ACCESS_ONCE(scs->output) = NULL;
}
@@ -395,7 +410,7 @@ int snd_oxfw_scs1x_add(struct snd_oxfw *oxfw)
snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT,
&midi_playback_ops);
- tasklet_init(&scs->tasklet, scs_output_tasklet, (unsigned long)scs);
+ INIT_WORK(&scs->work, scs_output_work);
init_waitqueue_head(&scs->idle_wait);
scs->output_idle = true;