From ec00f5e444706cb1902731655f3dcd04fc3df7b0 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Tue, 15 Mar 2011 07:57:24 +0100 Subject: ALSA: firewire-lib, firewire-speakers: handle packet queueing errors 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 Signed-off-by: Takashi Iwai --- sound/firewire/amdtp.c | 33 +++++++++++++++++++++------------ sound/firewire/amdtp.h | 14 +++++++++++++- sound/firewire/speakers.c | 3 +++ 3 files changed, 37 insertions(+), 13 deletions(-) Index: b/sound/firewire/amdtp.c =================================================================== --- a/sound/firewire/amdtp.c +++ b/sound/firewire/amdtp.c @@ -47,6 +47,7 @@ int amdtp_out_stream_init(struct amdtp_o s->flags = flags; s->context = ERR_PTR(-1); mutex_init(&s->mutex); + s->packet_index = 0; return 0; } @@ -316,15 +317,19 @@ static void amdtp_fill_midi(struct amdtp 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); @@ -343,20 +348,24 @@ static void queue_out_packet(struct amdt 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; @@ -398,13 +407,13 @@ static int queue_initial_skip_packets(st 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; @@ -469,7 +478,7 @@ int amdtp_out_stream_start(struct amdtp_ 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) Index: b/sound/firewire/amdtp.h =================================================================== --- a/sound/firewire/amdtp.h +++ b/sound/firewire/amdtp.h @@ -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; @@ -111,6 +111,18 @@ static inline void amdtp_out_stream_set_ } /** + * 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 * Index: b/sound/firewire/speakers.c =================================================================== --- a/sound/firewire/speakers.c +++ b/sound/firewire/speakers.c @@ -283,6 +283,9 @@ static int fwspk_prepare(struct snd_pcm_ 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));