Skip to content

Commit

Permalink
ALSA: firewire-lib, firewire-speakers: handle packet queueing errors
Browse files Browse the repository at this point in the history
Add an AMDTP stream error state that occurs when we fail to queue
another packet.  In this case, the stream is stopped, and the error can
be reported when the application tries to restart the PCM stream.

Signed-off-by: Clemens Ladisch <[email protected]>
Signed-off-by: Takashi Iwai <[email protected]>
  • Loading branch information
cladisch authored and tiwai committed Mar 15, 2011
1 parent 5b2599a commit ec00f5e
Show file tree
Hide file tree
Showing 3 changed files with 37 additions and 13 deletions.
33 changes: 21 additions & 12 deletions sound/firewire/amdtp.c
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ int amdtp_out_stream_init(struct amdtp_out_stream *s, struct fw_unit *unit,
s->flags = flags;
s->context = ERR_PTR(-1);
mutex_init(&s->mutex);
s->packet_index = 0;

return 0;
}
Expand Down Expand Up @@ -316,15 +317,19 @@ static void amdtp_fill_midi(struct amdtp_out_stream *s,
static void queue_out_packet(struct amdtp_out_stream *s, unsigned int cycle)
{
__be32 *buffer;
unsigned int data_blocks, syt, ptr;
unsigned int index, data_blocks, syt, ptr;
struct snd_pcm_substream *pcm;
struct fw_iso_packet packet;
int err;

if (s->packet_index < 0)
return;
index = s->packet_index;

data_blocks = calculate_data_blocks(s);
syt = calculate_syt(s, cycle);

buffer = s->buffer.packets[s->packet_counter].buffer;
buffer = s->buffer.packets[index].buffer;
buffer[0] = cpu_to_be32(ACCESS_ONCE(s->source_node_id_field) |
(s->data_block_quadlets << 16) |
s->data_block_counter);
Expand All @@ -343,20 +348,24 @@ static void queue_out_packet(struct amdtp_out_stream *s, unsigned int cycle)
s->data_block_counter = (s->data_block_counter + data_blocks) & 0xff;

packet.payload_length = 8 + data_blocks * 4 * s->data_block_quadlets;
packet.interrupt = IS_ALIGNED(s->packet_counter + 1,
INTERRUPT_INTERVAL);
packet.interrupt = IS_ALIGNED(index + 1, INTERRUPT_INTERVAL);
packet.skip = 0;
packet.tag = TAG_CIP;
packet.sy = 0;
packet.header_length = 0;

err = fw_iso_context_queue(s->context, &packet, &s->buffer.iso_buffer,
s->buffer.packets[s->packet_counter].offset);
if (err < 0)
s->buffer.packets[index].offset);
if (err < 0) {
dev_err(&s->unit->device, "queueing error: %d\n", err);
s->packet_index = -1;
amdtp_out_stream_pcm_abort(s);
return;
}

if (++s->packet_counter >= QUEUE_LENGTH)
s->packet_counter = 0;
if (++index >= QUEUE_LENGTH)
index = 0;
s->packet_index = index;

if (pcm) {
ptr = s->pcm_buffer_pointer + data_blocks;
Expand Down Expand Up @@ -398,13 +407,13 @@ static int queue_initial_skip_packets(struct amdtp_out_stream *s)
int err;

for (i = 0; i < QUEUE_LENGTH; ++i) {
skip_packet.interrupt = IS_ALIGNED(s->packet_counter + 1,
skip_packet.interrupt = IS_ALIGNED(s->packet_index + 1,
INTERRUPT_INTERVAL);
err = fw_iso_context_queue(s->context, &skip_packet, NULL, 0);
if (err < 0)
return err;
if (++s->packet_counter >= QUEUE_LENGTH)
s->packet_counter = 0;
if (++s->packet_index >= QUEUE_LENGTH)
s->packet_index = 0;
}

return 0;
Expand Down Expand Up @@ -469,7 +478,7 @@ int amdtp_out_stream_start(struct amdtp_out_stream *s, int channel, int speed)

amdtp_out_stream_update(s);

s->packet_counter = 0;
s->packet_index = 0;
s->data_block_counter = 0;
err = queue_initial_skip_packets(s);
if (err < 0)
Expand Down
14 changes: 13 additions & 1 deletion sound/firewire/amdtp.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ struct amdtp_out_stream {

struct snd_pcm_substream *pcm;

unsigned int packet_counter;
int packet_index;
unsigned int data_block_counter;

unsigned int data_block_state;
Expand Down Expand Up @@ -110,6 +110,18 @@ static inline void amdtp_out_stream_set_midi(struct amdtp_out_stream *s,
s->midi_ports = midi_ports;
}

/**
* amdtp_out_streaming_error - check for streaming error
* @s: the AMDTP output stream
*
* If this function returns true, the stream's packet queue has stopped due to
* an asynchronous error.
*/
static inline bool amdtp_out_streaming_error(struct amdtp_out_stream *s)
{
return s->packet_index < 0;
}

/**
* amdtp_out_stream_pcm_prepare - prepare PCM device for running
* @s: the AMDTP output stream
Expand Down
3 changes: 3 additions & 0 deletions sound/firewire/speakers.c
Original file line number Diff line number Diff line change
Expand Up @@ -283,6 +283,9 @@ static int fwspk_prepare(struct snd_pcm_substream *substream)

mutex_lock(&fwspk->mutex);

if (amdtp_out_streaming_error(&fwspk->stream))
fwspk_stop_stream(fwspk);

if (!fwspk->stream_running) {
err = cmp_connection_establish(&fwspk->connection,
amdtp_out_stream_get_max_payload(&fwspk->stream));
Expand Down

0 comments on commit ec00f5e

Please sign in to comment.