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>
diff --git a/sound/firewire/amdtp.c b/sound/firewire/amdtp.c
index 046007d..b18140f 100644
--- a/sound/firewire/amdtp.c
+++ b/sound/firewire/amdtp.c
@@ -47,6 +47,7 @@
 	s->flags = flags;
 	s->context = ERR_PTR(-1);
 	mutex_init(&s->mutex);
+	s->packet_index = 0;
 
 	return 0;
 }
@@ -316,15 +317,19 @@
 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 @@
 	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 @@
 	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 @@
 
 	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)