aboutsummaryrefslogtreecommitdiffstats
path: root/sound/firewire
diff options
context:
space:
mode:
authorClemens Ladisch <clemens@ladisch.de>2011-03-15 02:57:24 -0400
committerTakashi Iwai <tiwai@suse.de>2011-03-15 03:42:30 -0400
commitec00f5e444706cb1902731655f3dcd04fc3df7b0 (patch)
treef4fea4c46fa68308f401579ba93dc2c575157ba7 /sound/firewire
parent5b2599a07eaee53d713fb68f5343eba88fa249c0 (diff)
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')
-rw-r--r--sound/firewire/amdtp.c33
-rw-r--r--sound/firewire/amdtp.h14
-rw-r--r--sound/firewire/speakers.c3
3 files changed, 37 insertions, 13 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,
47 s->flags = flags; 47 s->flags = flags;
48 s->context = ERR_PTR(-1); 48 s->context = ERR_PTR(-1);
49 mutex_init(&s->mutex); 49 mutex_init(&s->mutex);
50 s->packet_index = 0;
50 51
51 return 0; 52 return 0;
52} 53}
@@ -316,15 +317,19 @@ static void amdtp_fill_midi(struct amdtp_out_stream *s,
316static void queue_out_packet(struct amdtp_out_stream *s, unsigned int cycle) 317static void queue_out_packet(struct amdtp_out_stream *s, unsigned int cycle)
317{ 318{
318 __be32 *buffer; 319 __be32 *buffer;
319 unsigned int data_blocks, syt, ptr; 320 unsigned int index, data_blocks, syt, ptr;
320 struct snd_pcm_substream *pcm; 321 struct snd_pcm_substream *pcm;
321 struct fw_iso_packet packet; 322 struct fw_iso_packet packet;
322 int err; 323 int err;
323 324
325 if (s->packet_index < 0)
326 return;
327 index = s->packet_index;
328
324 data_blocks = calculate_data_blocks(s); 329 data_blocks = calculate_data_blocks(s);
325 syt = calculate_syt(s, cycle); 330 syt = calculate_syt(s, cycle);
326 331
327 buffer = s->buffer.packets[s->packet_counter].buffer; 332 buffer = s->buffer.packets[index].buffer;
328 buffer[0] = cpu_to_be32(ACCESS_ONCE(s->source_node_id_field) | 333 buffer[0] = cpu_to_be32(ACCESS_ONCE(s->source_node_id_field) |
329 (s->data_block_quadlets << 16) | 334 (s->data_block_quadlets << 16) |
330 s->data_block_counter); 335 s->data_block_counter);
@@ -343,20 +348,24 @@ static void queue_out_packet(struct amdtp_out_stream *s, unsigned int cycle)
343 s->data_block_counter = (s->data_block_counter + data_blocks) & 0xff; 348 s->data_block_counter = (s->data_block_counter + data_blocks) & 0xff;
344 349
345 packet.payload_length = 8 + data_blocks * 4 * s->data_block_quadlets; 350 packet.payload_length = 8 + data_blocks * 4 * s->data_block_quadlets;
346 packet.interrupt = IS_ALIGNED(s->packet_counter + 1, 351 packet.interrupt = IS_ALIGNED(index + 1, INTERRUPT_INTERVAL);
347 INTERRUPT_INTERVAL);
348 packet.skip = 0; 352 packet.skip = 0;
349 packet.tag = TAG_CIP; 353 packet.tag = TAG_CIP;
350 packet.sy = 0; 354 packet.sy = 0;
351 packet.header_length = 0; 355 packet.header_length = 0;
352 356
353 err = fw_iso_context_queue(s->context, &packet, &s->buffer.iso_buffer, 357 err = fw_iso_context_queue(s->context, &packet, &s->buffer.iso_buffer,
354 s->buffer.packets[s->packet_counter].offset); 358 s->buffer.packets[index].offset);
355 if (err < 0) 359 if (err < 0) {
356 dev_err(&s->unit->device, "queueing error: %d\n", err); 360 dev_err(&s->unit->device, "queueing error: %d\n", err);
361 s->packet_index = -1;
362 amdtp_out_stream_pcm_abort(s);
363 return;
364 }
357 365
358 if (++s->packet_counter >= QUEUE_LENGTH) 366 if (++index >= QUEUE_LENGTH)
359 s->packet_counter = 0; 367 index = 0;
368 s->packet_index = index;
360 369
361 if (pcm) { 370 if (pcm) {
362 ptr = s->pcm_buffer_pointer + data_blocks; 371 ptr = s->pcm_buffer_pointer + data_blocks;
@@ -398,13 +407,13 @@ static int queue_initial_skip_packets(struct amdtp_out_stream *s)
398 int err; 407 int err;
399 408
400 for (i = 0; i < QUEUE_LENGTH; ++i) { 409 for (i = 0; i < QUEUE_LENGTH; ++i) {
401 skip_packet.interrupt = IS_ALIGNED(s->packet_counter + 1, 410 skip_packet.interrupt = IS_ALIGNED(s->packet_index + 1,
402 INTERRUPT_INTERVAL); 411 INTERRUPT_INTERVAL);
403 err = fw_iso_context_queue(s->context, &skip_packet, NULL, 0); 412 err = fw_iso_context_queue(s->context, &skip_packet, NULL, 0);
404 if (err < 0) 413 if (err < 0)
405 return err; 414 return err;
406 if (++s->packet_counter >= QUEUE_LENGTH) 415 if (++s->packet_index >= QUEUE_LENGTH)
407 s->packet_counter = 0; 416 s->packet_index = 0;
408 } 417 }
409 418
410 return 0; 419 return 0;
@@ -469,7 +478,7 @@ int amdtp_out_stream_start(struct amdtp_out_stream *s, int channel, int speed)
469 478
470 amdtp_out_stream_update(s); 479 amdtp_out_stream_update(s);
471 480
472 s->packet_counter = 0; 481 s->packet_index = 0;
473 s->data_block_counter = 0; 482 s->data_block_counter = 0;
474 err = queue_initial_skip_packets(s); 483 err = queue_initial_skip_packets(s);
475 if (err < 0) 484 if (err < 0)
diff --git a/sound/firewire/amdtp.h b/sound/firewire/amdtp.h
index 02dc1a664b55..537a9cb83581 100644
--- a/sound/firewire/amdtp.h
+++ b/sound/firewire/amdtp.h
@@ -56,7 +56,7 @@ struct amdtp_out_stream {
56 56
57 struct snd_pcm_substream *pcm; 57 struct snd_pcm_substream *pcm;
58 58
59 unsigned int packet_counter; 59 int packet_index;
60 unsigned int data_block_counter; 60 unsigned int data_block_counter;
61 61
62 unsigned int data_block_state; 62 unsigned int data_block_state;
@@ -111,6 +111,18 @@ static inline void amdtp_out_stream_set_midi(struct amdtp_out_stream *s,
111} 111}
112 112
113/** 113/**
114 * amdtp_out_streaming_error - check for streaming error
115 * @s: the AMDTP output stream
116 *
117 * If this function returns true, the stream's packet queue has stopped due to
118 * an asynchronous error.
119 */
120static inline bool amdtp_out_streaming_error(struct amdtp_out_stream *s)
121{
122 return s->packet_index < 0;
123}
124
125/**
114 * amdtp_out_stream_pcm_prepare - prepare PCM device for running 126 * amdtp_out_stream_pcm_prepare - prepare PCM device for running
115 * @s: the AMDTP output stream 127 * @s: the AMDTP output stream
116 * 128 *
diff --git a/sound/firewire/speakers.c b/sound/firewire/speakers.c
index f6b095ef075a..0fce9218abb1 100644
--- a/sound/firewire/speakers.c
+++ b/sound/firewire/speakers.c
@@ -283,6 +283,9 @@ static int fwspk_prepare(struct snd_pcm_substream *substream)
283 283
284 mutex_lock(&fwspk->mutex); 284 mutex_lock(&fwspk->mutex);
285 285
286 if (amdtp_out_streaming_error(&fwspk->stream))
287 fwspk_stop_stream(fwspk);
288
286 if (!fwspk->stream_running) { 289 if (!fwspk->stream_running) {
287 err = cmp_connection_establish(&fwspk->connection, 290 err = cmp_connection_establish(&fwspk->connection,
288 amdtp_out_stream_get_max_payload(&fwspk->stream)); 291 amdtp_out_stream_get_max_payload(&fwspk->stream));