[alsa-devel] [PATCH 1/2] ALSA: hda/ca0132 - setup/cleanup streams
When a HDMI stream is opened with the same stream tag as a following opened stream to ca0132, audio will be heard from two ports simultaneously. Fix this issue by change to use snd_hda_codec_setup_stream and snd_hda_codec_cleanup_stream instead, so that an inactive stream can be marked as 'dirty' when found with a conflict stream tag, and then get purified.
Signed-off-by: Hsin-Yu Chao hychao@chromium.org Reviewed-by: Chih-Chung Chang chihchung@chromium.org --- sound/pci/hda/patch_ca0132.c | 68 ++++++-------------------------------------- 1 file changed, 9 insertions(+), 59 deletions(-)
diff --git a/sound/pci/hda/patch_ca0132.c b/sound/pci/hda/patch_ca0132.c index 54d1479..59104dc 100644 --- a/sound/pci/hda/patch_ca0132.c +++ b/sound/pci/hda/patch_ca0132.c @@ -2662,60 +2662,6 @@ static bool dspload_wait_loaded(struct hda_codec *codec) }
/* - * PCM stuffs - */ -static void ca0132_setup_stream(struct hda_codec *codec, hda_nid_t nid, - u32 stream_tag, - int channel_id, int format) -{ - unsigned int oldval, newval; - - if (!nid) - return; - - snd_printdd( - "ca0132_setup_stream: NID=0x%x, stream=0x%x, " - "channel=%d, format=0x%x\n", - nid, stream_tag, channel_id, format); - - /* update the format-id if changed */ - oldval = snd_hda_codec_read(codec, nid, 0, - AC_VERB_GET_STREAM_FORMAT, - 0); - if (oldval != format) { - msleep(20); - snd_hda_codec_write(codec, nid, 0, - AC_VERB_SET_STREAM_FORMAT, - format); - } - - oldval = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONV, 0); - newval = (stream_tag << 4) | channel_id; - if (oldval != newval) { - snd_hda_codec_write(codec, nid, 0, - AC_VERB_SET_CHANNEL_STREAMID, - newval); - } -} - -static void ca0132_cleanup_stream(struct hda_codec *codec, hda_nid_t nid) -{ - unsigned int val; - - if (!nid) - return; - - snd_printdd(KERN_INFO "ca0132_cleanup_stream: NID=0x%x\n", nid); - - val = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONV, 0); - if (!val) - return; - - snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_STREAM_FORMAT, 0); - snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CHANNEL_STREAMID, 0); -} - -/* * PCM callbacks */ static int ca0132_playback_pcm_prepare(struct hda_pcm_stream *hinfo, @@ -2726,7 +2672,9 @@ static int ca0132_playback_pcm_prepare(struct hda_pcm_stream *hinfo, { struct ca0132_spec *spec = codec->spec;
- ca0132_setup_stream(codec, spec->dacs[0], stream_tag, 0, format); + ca0132_toggle_dac_format(codec); + + snd_hda_codec_setup_stream(codec, spec->dacs[0], stream_tag, 0, format);
return 0; } @@ -2745,7 +2693,7 @@ static int ca0132_playback_pcm_cleanup(struct hda_pcm_stream *hinfo, if (spec->effects_switch[PLAY_ENHANCEMENT - EFFECT_START_NID]) msleep(50);
- ca0132_cleanup_stream(codec, spec->dacs[0]); + snd_hda_codec_cleanup_stream(codec, spec->dacs[0]);
return 0; } @@ -2824,8 +2772,8 @@ static int ca0132_capture_pcm_prepare(struct hda_pcm_stream *hinfo, { struct ca0132_spec *spec = codec->spec;
- ca0132_setup_stream(codec, spec->adcs[substream->number], - stream_tag, 0, format); + snd_hda_codec_setup_stream(codec, spec->adcs[substream->number], + stream_tag, 0, format);
return 0; } @@ -2839,7 +2787,7 @@ static int ca0132_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, if (spec->dsp_state == DSP_DOWNLOADING) return 0;
- ca0132_cleanup_stream(codec, hinfo->nid); + snd_hda_codec_cleanup_stream(codec, hinfo->nid); return 0; }
@@ -4742,6 +4690,8 @@ static int patch_ca0132(struct hda_codec *codec) return err;
codec->patch_ops = ca0132_patch_ops; + codec->pcm_format_first = 1; + codec->no_sticky_stream = 1;
return 0; }
The Chromebook Pixel has a microphone under the keyboard that is attached to node id 0x8. Before this fix, recording would always go to the main internal mic (node id 0x7).
Signed-off-by: Hsin-Yu Chao hychao@chromium.org Reviewed-by: Dylan Reid dgreid@chromium.org --- sound/pci/hda/patch_ca0132.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/sound/pci/hda/patch_ca0132.c b/sound/pci/hda/patch_ca0132.c index 59104dc..d5aabce 100644 --- a/sound/pci/hda/patch_ca0132.c +++ b/sound/pci/hda/patch_ca0132.c @@ -2770,9 +2770,7 @@ static int ca0132_capture_pcm_prepare(struct hda_pcm_stream *hinfo, unsigned int format, struct snd_pcm_substream *substream) { - struct ca0132_spec *spec = codec->spec; - - snd_hda_codec_setup_stream(codec, spec->adcs[substream->number], + snd_hda_codec_setup_stream(codec, hinfo->nid, stream_tag, 0, format);
return 0;
At Fri, 7 Feb 2014 11:35:30 +0800, Hsin-Yu Chao wrote:
The Chromebook Pixel has a microphone under the keyboard that is attached to node id 0x8. Before this fix, recording would always go to the main internal mic (node id 0x7).
Signed-off-by: Hsin-Yu Chao hychao@chromium.org Reviewed-by: Dylan Reid dgreid@chromium.org
The description doesn't state why it fixes what: the patch is actually a fix for the wrong ADC pickup in ca0132_capture_pcm_prepare() where it assumes wrongly the multiple streams although the driver implements one stream per ADC. (And, ca0132_capture_pcm_cleanup() already does the right thing.)
Could you rephrase the patch description and resend?
thanks,
Takashi
sound/pci/hda/patch_ca0132.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/sound/pci/hda/patch_ca0132.c b/sound/pci/hda/patch_ca0132.c index 59104dc..d5aabce 100644 --- a/sound/pci/hda/patch_ca0132.c +++ b/sound/pci/hda/patch_ca0132.c @@ -2770,9 +2770,7 @@ static int ca0132_capture_pcm_prepare(struct hda_pcm_stream *hinfo, unsigned int format, struct snd_pcm_substream *substream) {
- struct ca0132_spec *spec = codec->spec;
- snd_hda_codec_setup_stream(codec, spec->adcs[substream->number],
snd_hda_codec_setup_stream(codec, hinfo->nid, stream_tag, 0, format);
return 0;
-- 1.9.0.rc1.175.g0b1dcb5
Incorrect ADC is picked in ca0132_capture_pcm_prepare(), where it assumes multiple streams while there is one stream per ADC. Note that ca0132_capture_pcm_cleanup() already does the right thing.
The Chromebook Pixel has a microphone under the keyboard that is attached to node id 0x8. Before this fix, recording would always go to the main internal mic (node id 0x7).
Signed-off-by: Hsin-Yu Chao hychao@chromium.org Reviewed-by: Dylan Reid dgreid@chromium.org --- sound/pci/hda/patch_ca0132.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/sound/pci/hda/patch_ca0132.c b/sound/pci/hda/patch_ca0132.c index 0aa72ee..46ecdbb 100644 --- a/sound/pci/hda/patch_ca0132.c +++ b/sound/pci/hda/patch_ca0132.c @@ -2768,9 +2768,7 @@ static int ca0132_capture_pcm_prepare(struct hda_pcm_stream *hinfo, unsigned int format, struct snd_pcm_substream *substream) { - struct ca0132_spec *spec = codec->spec; - - snd_hda_codec_setup_stream(codec, spec->adcs[substream->number], + snd_hda_codec_setup_stream(codec, hinfo->nid, stream_tag, 0, format);
return 0;
At Fri, 7 Feb 2014 11:35:29 +0800, Hsin-Yu Chao wrote:
When a HDMI stream is opened with the same stream tag as a following opened stream to ca0132, audio will be heard from two ports simultaneously. Fix this issue by change to use snd_hda_codec_setup_stream and snd_hda_codec_cleanup_stream instead, so that an inactive stream can be marked as 'dirty' when found with a conflict stream tag, and then get purified.
Signed-off-by: Hsin-Yu Chao hychao@chromium.org Reviewed-by: Chih-Chung Chang chihchung@chromium.org
Thanks, applied this one.
Takashi
sound/pci/hda/patch_ca0132.c | 68 ++++++-------------------------------------- 1 file changed, 9 insertions(+), 59 deletions(-)
diff --git a/sound/pci/hda/patch_ca0132.c b/sound/pci/hda/patch_ca0132.c index 54d1479..59104dc 100644 --- a/sound/pci/hda/patch_ca0132.c +++ b/sound/pci/hda/patch_ca0132.c @@ -2662,60 +2662,6 @@ static bool dspload_wait_loaded(struct hda_codec *codec) }
/*
- PCM stuffs
- */
-static void ca0132_setup_stream(struct hda_codec *codec, hda_nid_t nid,
u32 stream_tag,
int channel_id, int format)
-{
- unsigned int oldval, newval;
- if (!nid)
return;
- snd_printdd(
"ca0132_setup_stream: NID=0x%x, stream=0x%x, "
"channel=%d, format=0x%x\n",
nid, stream_tag, channel_id, format);
- /* update the format-id if changed */
- oldval = snd_hda_codec_read(codec, nid, 0,
AC_VERB_GET_STREAM_FORMAT,
0);
- if (oldval != format) {
msleep(20);
snd_hda_codec_write(codec, nid, 0,
AC_VERB_SET_STREAM_FORMAT,
format);
- }
- oldval = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONV, 0);
- newval = (stream_tag << 4) | channel_id;
- if (oldval != newval) {
snd_hda_codec_write(codec, nid, 0,
AC_VERB_SET_CHANNEL_STREAMID,
newval);
- }
-}
-static void ca0132_cleanup_stream(struct hda_codec *codec, hda_nid_t nid) -{
- unsigned int val;
- if (!nid)
return;
- snd_printdd(KERN_INFO "ca0132_cleanup_stream: NID=0x%x\n", nid);
- val = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONV, 0);
- if (!val)
return;
- snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_STREAM_FORMAT, 0);
- snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CHANNEL_STREAMID, 0);
-}
-/*
- PCM callbacks
*/ static int ca0132_playback_pcm_prepare(struct hda_pcm_stream *hinfo, @@ -2726,7 +2672,9 @@ static int ca0132_playback_pcm_prepare(struct hda_pcm_stream *hinfo, { struct ca0132_spec *spec = codec->spec;
- ca0132_setup_stream(codec, spec->dacs[0], stream_tag, 0, format);
ca0132_toggle_dac_format(codec);
snd_hda_codec_setup_stream(codec, spec->dacs[0], stream_tag, 0, format);
return 0;
} @@ -2745,7 +2693,7 @@ static int ca0132_playback_pcm_cleanup(struct hda_pcm_stream *hinfo, if (spec->effects_switch[PLAY_ENHANCEMENT - EFFECT_START_NID]) msleep(50);
- ca0132_cleanup_stream(codec, spec->dacs[0]);
snd_hda_codec_cleanup_stream(codec, spec->dacs[0]);
return 0;
} @@ -2824,8 +2772,8 @@ static int ca0132_capture_pcm_prepare(struct hda_pcm_stream *hinfo, { struct ca0132_spec *spec = codec->spec;
- ca0132_setup_stream(codec, spec->adcs[substream->number],
stream_tag, 0, format);
snd_hda_codec_setup_stream(codec, spec->adcs[substream->number],
stream_tag, 0, format);
return 0;
} @@ -2839,7 +2787,7 @@ static int ca0132_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, if (spec->dsp_state == DSP_DOWNLOADING) return 0;
- ca0132_cleanup_stream(codec, hinfo->nid);
- snd_hda_codec_cleanup_stream(codec, hinfo->nid); return 0;
}
@@ -4742,6 +4690,8 @@ static int patch_ca0132(struct hda_codec *codec) return err;
codec->patch_ops = ca0132_patch_ops;
codec->pcm_format_first = 1;
codec->no_sticky_stream = 1;
return 0;
}
1.9.0.rc1.175.g0b1dcb5
At Fri, 07 Feb 2014 11:59:20 +0100, Takashi Iwai wrote:
At Fri, 7 Feb 2014 11:35:29 +0800, Hsin-Yu Chao wrote:
When a HDMI stream is opened with the same stream tag as a following opened stream to ca0132, audio will be heard from two ports simultaneously. Fix this issue by change to use snd_hda_codec_setup_stream and snd_hda_codec_cleanup_stream instead, so that an inactive stream can be marked as 'dirty' when found with a conflict stream tag, and then get purified.
Signed-off-by: Hsin-Yu Chao hychao@chromium.org Reviewed-by: Chih-Chung Chang chihchung@chromium.org
Thanks, applied this one.
Hrm, not good.
sound/pci/hda/patch_ca0132.c: In function ‘ca0132_playback_pcm_prepare’: sound/pci/hda/patch_ca0132.c:2675:2: error: implicit declaration of function ‘ca0132_toggle_dac_format’ [-Werror=implicit-function-declaration] ca0132_toggle_dac_format(codec); ^
Please give a patch that really builds and works cleanly with the upstream code!
thanks,
Takashi
When a HDMI stream is opened with the same stream tag as a following opened stream to ca0132, audio will be heard from two ports simultaneously. Fix this issue by change to use snd_hda_codec_setup_stream and snd_hda_codec_cleanup_stream instead, so that an inactive stream can be marked as 'dirty' when found with a conflict stream tag, and then get purified.
Signed-off-by: Hsin-Yu Chao hychao@chromium.org Reviewed-by: Chih-Chung Chang chihchung@chromium.org --- sound/pci/hda/patch_ca0132.c | 66 +++++--------------------------------------- 1 file changed, 7 insertions(+), 59 deletions(-)
diff --git a/sound/pci/hda/patch_ca0132.c b/sound/pci/hda/patch_ca0132.c index 54d1479..0aa72ee 100644 --- a/sound/pci/hda/patch_ca0132.c +++ b/sound/pci/hda/patch_ca0132.c @@ -2662,60 +2662,6 @@ static bool dspload_wait_loaded(struct hda_codec *codec) }
/* - * PCM stuffs - */ -static void ca0132_setup_stream(struct hda_codec *codec, hda_nid_t nid, - u32 stream_tag, - int channel_id, int format) -{ - unsigned int oldval, newval; - - if (!nid) - return; - - snd_printdd( - "ca0132_setup_stream: NID=0x%x, stream=0x%x, " - "channel=%d, format=0x%x\n", - nid, stream_tag, channel_id, format); - - /* update the format-id if changed */ - oldval = snd_hda_codec_read(codec, nid, 0, - AC_VERB_GET_STREAM_FORMAT, - 0); - if (oldval != format) { - msleep(20); - snd_hda_codec_write(codec, nid, 0, - AC_VERB_SET_STREAM_FORMAT, - format); - } - - oldval = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONV, 0); - newval = (stream_tag << 4) | channel_id; - if (oldval != newval) { - snd_hda_codec_write(codec, nid, 0, - AC_VERB_SET_CHANNEL_STREAMID, - newval); - } -} - -static void ca0132_cleanup_stream(struct hda_codec *codec, hda_nid_t nid) -{ - unsigned int val; - - if (!nid) - return; - - snd_printdd(KERN_INFO "ca0132_cleanup_stream: NID=0x%x\n", nid); - - val = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONV, 0); - if (!val) - return; - - snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_STREAM_FORMAT, 0); - snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CHANNEL_STREAMID, 0); -} - -/* * PCM callbacks */ static int ca0132_playback_pcm_prepare(struct hda_pcm_stream *hinfo, @@ -2726,7 +2672,7 @@ static int ca0132_playback_pcm_prepare(struct hda_pcm_stream *hinfo, { struct ca0132_spec *spec = codec->spec;
- ca0132_setup_stream(codec, spec->dacs[0], stream_tag, 0, format); + snd_hda_codec_setup_stream(codec, spec->dacs[0], stream_tag, 0, format);
return 0; } @@ -2745,7 +2691,7 @@ static int ca0132_playback_pcm_cleanup(struct hda_pcm_stream *hinfo, if (spec->effects_switch[PLAY_ENHANCEMENT - EFFECT_START_NID]) msleep(50);
- ca0132_cleanup_stream(codec, spec->dacs[0]); + snd_hda_codec_cleanup_stream(codec, spec->dacs[0]);
return 0; } @@ -2824,8 +2770,8 @@ static int ca0132_capture_pcm_prepare(struct hda_pcm_stream *hinfo, { struct ca0132_spec *spec = codec->spec;
- ca0132_setup_stream(codec, spec->adcs[substream->number], - stream_tag, 0, format); + snd_hda_codec_setup_stream(codec, spec->adcs[substream->number], + stream_tag, 0, format);
return 0; } @@ -2839,7 +2785,7 @@ static int ca0132_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, if (spec->dsp_state == DSP_DOWNLOADING) return 0;
- ca0132_cleanup_stream(codec, hinfo->nid); + snd_hda_codec_cleanup_stream(codec, hinfo->nid); return 0; }
@@ -4742,6 +4688,8 @@ static int patch_ca0132(struct hda_codec *codec) return err;
codec->patch_ops = ca0132_patch_ops; + codec->pcm_format_first = 1; + codec->no_sticky_stream = 1;
return 0; }
At Wed, 19 Feb 2014 14:27:07 +0800, Hsin-Yu Chao wrote:
When a HDMI stream is opened with the same stream tag as a following opened stream to ca0132, audio will be heard from two ports simultaneously. Fix this issue by change to use snd_hda_codec_setup_stream and snd_hda_codec_cleanup_stream instead, so that an inactive stream can be marked as 'dirty' when found with a conflict stream tag, and then get purified.
Signed-off-by: Hsin-Yu Chao hychao@chromium.org Reviewed-by: Chih-Chung Chang chihchung@chromium.org
Thanks, I applied both patches now with Cc to stable.
Takashi
sound/pci/hda/patch_ca0132.c | 66 +++++--------------------------------------- 1 file changed, 7 insertions(+), 59 deletions(-)
diff --git a/sound/pci/hda/patch_ca0132.c b/sound/pci/hda/patch_ca0132.c index 54d1479..0aa72ee 100644 --- a/sound/pci/hda/patch_ca0132.c +++ b/sound/pci/hda/patch_ca0132.c @@ -2662,60 +2662,6 @@ static bool dspload_wait_loaded(struct hda_codec *codec) }
/*
- PCM stuffs
- */
-static void ca0132_setup_stream(struct hda_codec *codec, hda_nid_t nid,
u32 stream_tag,
int channel_id, int format)
-{
- unsigned int oldval, newval;
- if (!nid)
return;
- snd_printdd(
"ca0132_setup_stream: NID=0x%x, stream=0x%x, "
"channel=%d, format=0x%x\n",
nid, stream_tag, channel_id, format);
- /* update the format-id if changed */
- oldval = snd_hda_codec_read(codec, nid, 0,
AC_VERB_GET_STREAM_FORMAT,
0);
- if (oldval != format) {
msleep(20);
snd_hda_codec_write(codec, nid, 0,
AC_VERB_SET_STREAM_FORMAT,
format);
- }
- oldval = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONV, 0);
- newval = (stream_tag << 4) | channel_id;
- if (oldval != newval) {
snd_hda_codec_write(codec, nid, 0,
AC_VERB_SET_CHANNEL_STREAMID,
newval);
- }
-}
-static void ca0132_cleanup_stream(struct hda_codec *codec, hda_nid_t nid) -{
- unsigned int val;
- if (!nid)
return;
- snd_printdd(KERN_INFO "ca0132_cleanup_stream: NID=0x%x\n", nid);
- val = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONV, 0);
- if (!val)
return;
- snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_STREAM_FORMAT, 0);
- snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CHANNEL_STREAMID, 0);
-}
-/*
- PCM callbacks
*/ static int ca0132_playback_pcm_prepare(struct hda_pcm_stream *hinfo, @@ -2726,7 +2672,7 @@ static int ca0132_playback_pcm_prepare(struct hda_pcm_stream *hinfo, { struct ca0132_spec *spec = codec->spec;
- ca0132_setup_stream(codec, spec->dacs[0], stream_tag, 0, format);
snd_hda_codec_setup_stream(codec, spec->dacs[0], stream_tag, 0, format);
return 0;
} @@ -2745,7 +2691,7 @@ static int ca0132_playback_pcm_cleanup(struct hda_pcm_stream *hinfo, if (spec->effects_switch[PLAY_ENHANCEMENT - EFFECT_START_NID]) msleep(50);
- ca0132_cleanup_stream(codec, spec->dacs[0]);
snd_hda_codec_cleanup_stream(codec, spec->dacs[0]);
return 0;
} @@ -2824,8 +2770,8 @@ static int ca0132_capture_pcm_prepare(struct hda_pcm_stream *hinfo, { struct ca0132_spec *spec = codec->spec;
- ca0132_setup_stream(codec, spec->adcs[substream->number],
stream_tag, 0, format);
snd_hda_codec_setup_stream(codec, spec->adcs[substream->number],
stream_tag, 0, format);
return 0;
} @@ -2839,7 +2785,7 @@ static int ca0132_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, if (spec->dsp_state == DSP_DOWNLOADING) return 0;
- ca0132_cleanup_stream(codec, hinfo->nid);
- snd_hda_codec_cleanup_stream(codec, hinfo->nid); return 0;
}
@@ -4742,6 +4688,8 @@ static int patch_ca0132(struct hda_codec *codec) return err;
codec->patch_ops = ca0132_patch_ops;
codec->pcm_format_first = 1;
codec->no_sticky_stream = 1;
return 0;
}
1.8.3.2
participants (2)
-
Hsin-Yu Chao
-
Takashi Iwai