From 7ce5c9268bacbe5ceca7849450c80e280aacd4c0 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Sun, 26 Oct 2014 22:49:45 +0900 Subject: ALSA: bebob: fix wrong decoding of clock information for Terratec PHASE 88 Rack FW MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Terratec PHASE 88 rack fw has two registers for source of clock, one is for internal/external, and another is for wordclock/spdif for external. When clock source is internal, information in another register has no meaning. Thus it must be ignored, but current implementation decodes it. This causes over-indexing reference to labels. Reported-by: András Murányi Tested-by: András Murányi Signed-off-by: Takashi Sakamoto Acked-by: Clemens Ladisch Signed-off-by: Takashi Iwai --- sound/firewire/bebob/bebob_terratec.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'sound/firewire/bebob') diff --git a/sound/firewire/bebob/bebob_terratec.c b/sound/firewire/bebob/bebob_terratec.c index 0e4c0bfc463b..9940611f2e1b 100644 --- a/sound/firewire/bebob/bebob_terratec.c +++ b/sound/firewire/bebob/bebob_terratec.c @@ -24,7 +24,12 @@ phase88_rack_clk_src_get(struct snd_bebob *bebob, unsigned int *id) if (err < 0) goto end; - *id = (enable_ext & 0x01) | ((enable_word & 0x01) << 1); + if (enable_ext == 0) + *id = 0; + else if (enable_word == 0) + *id = 1; + else + *id = 2; end: return err; } -- cgit v1.2.1 From d1d0b6b668818571122d30d68a0b3f768bd83a52 Mon Sep 17 00:00:00 2001 From: Christian Vogel Date: Sat, 25 Oct 2014 13:40:41 +0200 Subject: ALSA: bebob: Uninitialized id returned by saffirepro_both_clk_src_get snd_bebob_stream_check_internal_clock() may get an id from saffirepro_both_clk_src_get (via clk_src->get()) that was uninitialized. a) make logic in saffirepro_both_clk_src_get explicit b) test if id used in snd_bebob_stream_check_internal_clock matches array size [fixed missing signed prefix to *_maps[] by tiwai] Signed-off-by: Christian Vogel Reviewed-by: Takashi Sakamoto Cc: Signed-off-by: Takashi Iwai --- sound/firewire/bebob/bebob_focusrite.c | 62 ++++++++++++++++++++++++++-------- sound/firewire/bebob/bebob_stream.c | 18 ++++++++-- 2 files changed, 63 insertions(+), 17 deletions(-) (limited to 'sound/firewire/bebob') diff --git a/sound/firewire/bebob/bebob_focusrite.c b/sound/firewire/bebob/bebob_focusrite.c index 45a0eed6d5b1..3b052ed0fbf5 100644 --- a/sound/firewire/bebob/bebob_focusrite.c +++ b/sound/firewire/bebob/bebob_focusrite.c @@ -27,12 +27,14 @@ #define SAFFIRE_CLOCK_SOURCE_INTERNAL 0 #define SAFFIRE_CLOCK_SOURCE_SPDIF 1 -/* '1' is absent, why... */ +/* clock sources as returned from register of Saffire Pro 10 and 26 */ #define SAFFIREPRO_CLOCK_SOURCE_INTERNAL 0 +#define SAFFIREPRO_CLOCK_SOURCE_SKIP 1 /* never used on hardware */ #define SAFFIREPRO_CLOCK_SOURCE_SPDIF 2 -#define SAFFIREPRO_CLOCK_SOURCE_ADAT1 3 -#define SAFFIREPRO_CLOCK_SOURCE_ADAT2 4 +#define SAFFIREPRO_CLOCK_SOURCE_ADAT1 3 /* not used on s.pro. 10 */ +#define SAFFIREPRO_CLOCK_SOURCE_ADAT2 4 /* not used on s.pro. 10 */ #define SAFFIREPRO_CLOCK_SOURCE_WORDCLOCK 5 +#define SAFFIREPRO_CLOCK_SOURCE_COUNT 6 /* S/PDIF, ADAT1, ADAT2 is enabled or not. three quadlets */ #define SAFFIREPRO_ENABLE_DIG_IFACES 0x01a4 @@ -101,13 +103,34 @@ saffire_write_quad(struct snd_bebob *bebob, u64 offset, u32 value) &data, sizeof(__be32), 0); } +static char *const saffirepro_10_clk_src_labels[] = { + SND_BEBOB_CLOCK_INTERNAL, "S/PDIF", "Word Clock" +}; static char *const saffirepro_26_clk_src_labels[] = { SND_BEBOB_CLOCK_INTERNAL, "S/PDIF", "ADAT1", "ADAT2", "Word Clock" }; - -static char *const saffirepro_10_clk_src_labels[] = { - SND_BEBOB_CLOCK_INTERNAL, "S/PDIF", "Word Clock" +/* Value maps between registers and labels for SaffirePro 10/26. */ +static const signed char saffirepro_clk_maps[][SAFFIREPRO_CLOCK_SOURCE_COUNT] = { + /* SaffirePro 10 */ + [0] = { + [SAFFIREPRO_CLOCK_SOURCE_INTERNAL] = 0, + [SAFFIREPRO_CLOCK_SOURCE_SKIP] = -1, /* not supported */ + [SAFFIREPRO_CLOCK_SOURCE_SPDIF] = 1, + [SAFFIREPRO_CLOCK_SOURCE_ADAT1] = -1, /* not supported */ + [SAFFIREPRO_CLOCK_SOURCE_ADAT2] = -1, /* not supported */ + [SAFFIREPRO_CLOCK_SOURCE_WORDCLOCK] = 2, + }, + /* SaffirePro 26 */ + [1] = { + [SAFFIREPRO_CLOCK_SOURCE_INTERNAL] = 0, + [SAFFIREPRO_CLOCK_SOURCE_SKIP] = -1, /* not supported */ + [SAFFIREPRO_CLOCK_SOURCE_SPDIF] = 1, + [SAFFIREPRO_CLOCK_SOURCE_ADAT1] = 2, + [SAFFIREPRO_CLOCK_SOURCE_ADAT2] = 3, + [SAFFIREPRO_CLOCK_SOURCE_WORDCLOCK] = 4, + } }; + static int saffirepro_both_clk_freq_get(struct snd_bebob *bebob, unsigned int *rate) { @@ -138,24 +161,35 @@ saffirepro_both_clk_freq_set(struct snd_bebob *bebob, unsigned int rate) return saffire_write_quad(bebob, SAFFIREPRO_RATE_NOREBOOT, id); } + +/* + * query hardware for current clock source, return our internally + * used clock index in *id, depending on hardware. + */ static int saffirepro_both_clk_src_get(struct snd_bebob *bebob, unsigned int *id) { int err; - u32 value; + u32 value; /* clock source read from hw register */ + const signed char *map; err = saffire_read_quad(bebob, SAFFIREPRO_OFFSET_CLOCK_SOURCE, &value); if (err < 0) goto end; - if (bebob->spec->clock->labels == saffirepro_10_clk_src_labels) { - if (value == SAFFIREPRO_CLOCK_SOURCE_WORDCLOCK) - *id = 2; - else if (value == SAFFIREPRO_CLOCK_SOURCE_SPDIF) - *id = 1; - } else if (value > 1) { - *id = value - 1; + /* depending on hardware, use a different mapping */ + if (bebob->spec->clock->labels == saffirepro_10_clk_src_labels) + map = saffirepro_clk_maps[0]; + else + map = saffirepro_clk_maps[1]; + + /* In a case that this driver cannot handle the value of register. */ + if (value >= SAFFIREPRO_CLOCK_SOURCE_COUNT || map[value] < 0) { + err = -EIO; + goto end; } + + *id = (unsigned int)map[value]; end: return err; } diff --git a/sound/firewire/bebob/bebob_stream.c b/sound/firewire/bebob/bebob_stream.c index ef4d0c9f6578..1aab0a32870c 100644 --- a/sound/firewire/bebob/bebob_stream.c +++ b/sound/firewire/bebob/bebob_stream.c @@ -129,12 +129,24 @@ snd_bebob_stream_check_internal_clock(struct snd_bebob *bebob, bool *internal) /* 1.The device has its own operation to switch source of clock */ if (clk_spec) { err = clk_spec->get(bebob, &id); - if (err < 0) + if (err < 0) { dev_err(&bebob->unit->device, "fail to get clock source: %d\n", err); - else if (strncmp(clk_spec->labels[id], SND_BEBOB_CLOCK_INTERNAL, - strlen(SND_BEBOB_CLOCK_INTERNAL)) == 0) + goto end; + } + + if (id >= clk_spec->num) { + dev_err(&bebob->unit->device, + "clock source %d out of range 0..%d\n", + id, clk_spec->num - 1); + err = -EIO; + goto end; + } + + if (strncmp(clk_spec->labels[id], SND_BEBOB_CLOCK_INTERNAL, + strlen(SND_BEBOB_CLOCK_INTERNAL)) == 0) *internal = true; + goto end; } -- cgit v1.2.1