aboutsummaryrefslogtreecommitdiffstats
path: root/sound/firewire
diff options
context:
space:
mode:
authorTakashi Sakamoto <o-takashi@sakamocchi.jp>2014-04-25 09:45:16 -0400
committerTakashi Iwai <tiwai@suse.de>2014-05-26 08:29:44 -0400
commitb6bc812327aa6961d783e81961273ebf2a304964 (patch)
treef200e026bd6383613d4a9e98e7234cc1e44dea90 /sound/firewire
parenteb7b3a056cd8130e45c4494fb27de54d53ce9f31 (diff)
ALSA: bebob/firewire-lib: Add a quirk for discontinuity at bus reset
Normal BeBoB firmware has a quirk. When receiving bus reset, it transmits packets with discontinuous value in dbc field. This causes two situation, one is to abort streaming by firewire-lib as a result of detecting the discontinuity. Another is to call driver's .update() because of bus reset. These two is generated independently. (The former depends on isochronous stream and the latter depends on IEEE1394 bus driver.) When BeBoB driver works with XRUN-recoverable applications, this situation looks like stream_start_duplex() call followed by stream_update_duplex() call because applications will call snd_pcm_prepare() immediately at XRUN. To update connections and streams at first, this commit use completion. When queueing error occurs, stream_start_duplex() is forced to wait maximum 1000msec. During this, when .update() is called, the completion is waken and stream_start_duplex() is processed without breaking connections. At bus reset, stream_start_duplex() shouldn't break/establish connections and stream_update_duplex() should update connections because a caller of fw_iso_resources_allocate() is responsible for calling fw_iso_resources_update() on bus reset. This commit also adds a flag, which has an effect to skip checking continuity for first packet. This flag is useful for BeBoB quirk to start handling packets during streaming. Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp> Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/firewire')
-rw-r--r--sound/firewire/amdtp.c9
-rw-r--r--sound/firewire/amdtp.h3
-rw-r--r--sound/firewire/bebob/bebob.h4
-rw-r--r--sound/firewire/bebob/bebob_stream.c52
4 files changed, 60 insertions, 8 deletions
diff --git a/sound/firewire/amdtp.c b/sound/firewire/amdtp.c
index 28ee3d86164d..690c60828872 100644
--- a/sound/firewire/amdtp.c
+++ b/sound/firewire/amdtp.c
@@ -665,7 +665,8 @@ static void handle_in_packet(struct amdtp_stream *s,
665 665
666 /* Check data block counter continuity */ 666 /* Check data block counter continuity */
667 data_block_counter = cip_header[0] & AMDTP_DBC_MASK; 667 data_block_counter = cip_header[0] & AMDTP_DBC_MASK;
668 if ((s->flags & CIP_SKIP_DBC_ZERO_CHECK) && data_block_counter == 0) { 668 if (((s->flags & CIP_SKIP_DBC_ZERO_CHECK) && data_block_counter == 0) ||
669 (s->data_block_counter == UINT_MAX)) {
669 lost = false; 670 lost = false;
670 } else if (!(s->flags & CIP_DBC_IS_END_EVENT)) { 671 } else if (!(s->flags & CIP_DBC_IS_END_EVENT)) {
671 lost = data_block_counter != s->data_block_counter; 672 lost = data_block_counter != s->data_block_counter;
@@ -850,7 +851,11 @@ int amdtp_stream_start(struct amdtp_stream *s, int channel, int speed)
850 goto err_unlock; 851 goto err_unlock;
851 } 852 }
852 853
853 s->data_block_counter = 0; 854 if (s->direction == AMDTP_IN_STREAM &&
855 s->flags & CIP_SKIP_INIT_DBC_CHECK)
856 s->data_block_counter = UINT_MAX;
857 else
858 s->data_block_counter = 0;
854 s->data_block_state = initial_state[s->sfc].data_block; 859 s->data_block_state = initial_state[s->sfc].data_block;
855 s->syt_offset_state = initial_state[s->sfc].syt_offset; 860 s->syt_offset_state = initial_state[s->sfc].syt_offset;
856 s->last_syt_offset = TICKS_PER_CYCLE; 861 s->last_syt_offset = TICKS_PER_CYCLE;
diff --git a/sound/firewire/amdtp.h b/sound/firewire/amdtp.h
index fb5934cc01aa..c79f058f1621 100644
--- a/sound/firewire/amdtp.h
+++ b/sound/firewire/amdtp.h
@@ -25,6 +25,8 @@
25 * The value of data_block_quadlets is used instead of reported value. 25 * The value of data_block_quadlets is used instead of reported value.
26 * @SKIP_DBC_ZERO_CHECK: Only for in-stream. Packets with zero in dbc is 26 * @SKIP_DBC_ZERO_CHECK: Only for in-stream. Packets with zero in dbc is
27 * skipped for detecting discontinuity. 27 * skipped for detecting discontinuity.
28 * @CIP_SKIP_INIT_DBC_CHECK: Only for in-stream. The value of dbc in first
29 * packet is not continuous from an initial value.
28 */ 30 */
29enum cip_flags { 31enum cip_flags {
30 CIP_NONBLOCKING = 0x00, 32 CIP_NONBLOCKING = 0x00,
@@ -34,6 +36,7 @@ enum cip_flags {
34 CIP_DBC_IS_END_EVENT = 0x08, 36 CIP_DBC_IS_END_EVENT = 0x08,
35 CIP_WRONG_DBS = 0x10, 37 CIP_WRONG_DBS = 0x10,
36 CIP_SKIP_DBC_ZERO_CHECK = 0x20, 38 CIP_SKIP_DBC_ZERO_CHECK = 0x20,
39 CIP_SKIP_INIT_DBC_CHECK = 0x40,
37}; 40};
38 41
39/** 42/**
diff --git a/sound/firewire/bebob/bebob.h b/sound/firewire/bebob/bebob.h
index a195c16da41e..031ca78096d2 100644
--- a/sound/firewire/bebob/bebob.h
+++ b/sound/firewire/bebob/bebob.h
@@ -53,6 +53,10 @@ struct snd_bebob {
53 unsigned int midi_input_ports; 53 unsigned int midi_input_ports;
54 unsigned int midi_output_ports; 54 unsigned int midi_output_ports;
55 55
56 /* for bus reset quirk */
57 struct completion bus_reset;
58 bool connected;
59
56 struct amdtp_stream *master; 60 struct amdtp_stream *master;
57 struct amdtp_stream tx_stream; 61 struct amdtp_stream tx_stream;
58 struct amdtp_stream rx_stream; 62 struct amdtp_stream rx_stream;
diff --git a/sound/firewire/bebob/bebob_stream.c b/sound/firewire/bebob/bebob_stream.c
index c868c17c6fc4..46b056c8f2a8 100644
--- a/sound/firewire/bebob/bebob_stream.c
+++ b/sound/firewire/bebob/bebob_stream.c
@@ -9,6 +9,7 @@
9#include "./bebob.h" 9#include "./bebob.h"
10 10
11#define CALLBACK_TIMEOUT 1000 11#define CALLBACK_TIMEOUT 1000
12#define FW_ISO_RESOURCE_DELAY 1000
12 13
13/* 14/*
14 * NOTE; 15 * NOTE;
@@ -325,7 +326,10 @@ check_connection_used_by_others(struct snd_bebob *bebob, struct amdtp_stream *s)
325static int 326static int
326make_both_connections(struct snd_bebob *bebob, unsigned int rate) 327make_both_connections(struct snd_bebob *bebob, unsigned int rate)
327{ 328{
328 int index, pcm_channels, midi_channels, err; 329 int index, pcm_channels, midi_channels, err = 0;
330
331 if (bebob->connected)
332 goto end;
329 333
330 /* confirm params for both streams */ 334 /* confirm params for both streams */
331 index = get_formation_index(rate); 335 index = get_formation_index(rate);
@@ -345,8 +349,12 @@ make_both_connections(struct snd_bebob *bebob, unsigned int rate)
345 goto end; 349 goto end;
346 err = cmp_connection_establish(&bebob->in_conn, 350 err = cmp_connection_establish(&bebob->in_conn,
347 amdtp_stream_get_max_payload(&bebob->rx_stream)); 351 amdtp_stream_get_max_payload(&bebob->rx_stream));
348 if (err < 0) 352 if (err < 0) {
349 cmp_connection_break(&bebob->out_conn); 353 cmp_connection_break(&bebob->out_conn);
354 goto end;
355 }
356
357 bebob->connected = true;
350end: 358end:
351 return err; 359 return err;
352} 360}
@@ -356,6 +364,8 @@ break_both_connections(struct snd_bebob *bebob)
356{ 364{
357 cmp_connection_break(&bebob->in_conn); 365 cmp_connection_break(&bebob->in_conn);
358 cmp_connection_break(&bebob->out_conn); 366 cmp_connection_break(&bebob->out_conn);
367
368 bebob->connected = false;
359} 369}
360 370
361static void 371static void
@@ -415,6 +425,9 @@ int snd_bebob_stream_init_duplex(struct snd_bebob *bebob)
415 destroy_both_connections(bebob); 425 destroy_both_connections(bebob);
416 goto end; 426 goto end;
417 } 427 }
428 /* See comments in next function */
429 init_completion(&bebob->bus_reset);
430 bebob->tx_stream.flags |= CIP_SKIP_INIT_DBC_CHECK;
418 431
419 err = amdtp_stream_init(&bebob->rx_stream, bebob->unit, 432 err = amdtp_stream_init(&bebob->rx_stream, bebob->unit,
420 AMDTP_OUT_STREAM, CIP_BLOCKING); 433 AMDTP_OUT_STREAM, CIP_BLOCKING);
@@ -433,8 +446,25 @@ int snd_bebob_stream_start_duplex(struct snd_bebob *bebob, int rate)
433 atomic_t *slave_substreams; 446 atomic_t *slave_substreams;
434 enum cip_flags sync_mode; 447 enum cip_flags sync_mode;
435 unsigned int curr_rate; 448 unsigned int curr_rate;
449 bool updated = false;
436 int err = 0; 450 int err = 0;
437 451
452 /*
453 * Normal BeBoB firmware has a quirk at bus reset to transmits packets
454 * with discontinuous value in dbc field.
455 *
456 * This 'struct completion' is used to call .update() at first to update
457 * connections/streams. Next following codes handle streaming error.
458 */
459 if (amdtp_streaming_error(&bebob->tx_stream)) {
460 if (completion_done(&bebob->bus_reset))
461 reinit_completion(&bebob->bus_reset);
462
463 updated = (wait_for_completion_interruptible_timeout(
464 &bebob->bus_reset,
465 msecs_to_jiffies(FW_ISO_RESOURCE_DELAY)) > 0);
466 }
467
438 mutex_lock(&bebob->mutex); 468 mutex_lock(&bebob->mutex);
439 469
440 /* Need no substreams */ 470 /* Need no substreams */
@@ -463,13 +493,19 @@ int snd_bebob_stream_start_duplex(struct snd_bebob *bebob, int rate)
463 if (err < 0) 493 if (err < 0)
464 goto end; 494 goto end;
465 495
466 /* packet queueing error */ 496 /*
467 if (amdtp_streaming_error(master)) { 497 * packet queueing error or detecting discontinuity
498 *
499 * At bus reset, connections should not be broken here. So streams need
500 * to be re-started. This is a reason to use SKIP_INIT_DBC_CHECK flag.
501 */
502 if (amdtp_streaming_error(master))
468 amdtp_stream_stop(master); 503 amdtp_stream_stop(master);
469 amdtp_stream_stop(slave);
470 }
471 if (amdtp_streaming_error(slave)) 504 if (amdtp_streaming_error(slave))
472 amdtp_stream_stop(slave); 505 amdtp_stream_stop(slave);
506 if (!updated &&
507 !amdtp_stream_running(master) && !amdtp_stream_running(slave))
508 break_both_connections(bebob);
473 509
474 /* stop streams if rate is different */ 510 /* stop streams if rate is different */
475 err = snd_bebob_stream_get_rate(bebob, &curr_rate); 511 err = snd_bebob_stream_get_rate(bebob, &curr_rate);
@@ -599,6 +635,10 @@ void snd_bebob_stream_update_duplex(struct snd_bebob *bebob)
599 amdtp_stream_update(&bebob->tx_stream); 635 amdtp_stream_update(&bebob->tx_stream);
600 } 636 }
601 637
638 /* wake up stream_start_duplex() */
639 if (!completion_done(&bebob->bus_reset))
640 complete_all(&bebob->bus_reset);
641
602 mutex_unlock(&bebob->mutex); 642 mutex_unlock(&bebob->mutex);
603} 643}
604 644