diff options
-rw-r--r-- | sound/firewire/amdtp.c | 33 | ||||
-rw-r--r-- | sound/firewire/amdtp.h | 14 | ||||
-rw-r--r-- | sound/firewire/speakers.c | 3 |
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, | |||
316 | static void queue_out_packet(struct amdtp_out_stream *s, unsigned int cycle) | 317 | static 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 | */ | ||
120 | static 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)); |