diff options
author | Clemens Ladisch <clemens@ladisch.de> | 2011-03-15 09:57:24 +0300 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2011-03-15 10:42:30 +0300 |
commit | ec00f5e444706cb1902731655f3dcd04fc3df7b0 (patch) | |
tree | f4fea4c46fa68308f401579ba93dc2c575157ba7 /sound/firewire/amdtp.c | |
parent | 5b2599a07eaee53d713fb68f5343eba88fa249c0 (diff) | |
download | linux-ec00f5e444706cb1902731655f3dcd04fc3df7b0.tar.xz |
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 <clemens@ladisch.de>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/firewire/amdtp.c')
-rw-r--r-- | sound/firewire/amdtp.c | 33 |
1 files changed, 21 insertions, 12 deletions
diff --git a/sound/firewire/amdtp.c b/sound/firewire/amdtp.c index 046007ddbcae..b18140ff2b93 100644 --- a/sound/firewire/amdtp.c +++ b/sound/firewire/amdtp.c @@ -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; } @@ -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); @@ -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; @@ -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; @@ -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) |