From ef18beded8ddbaafdf4914bab209f77e60ae3a18 Mon Sep 17 00:00:00 2001 From: Wu Fengguang Date: Fri, 25 Dec 2009 13:14:27 +0800 Subject: ALSA: hda - HDMI sticky stream tag support When we run the following commands in turn (with CONFIG_SND_HDA_POWER_SAVE_DEFAULT=0), speaker-test -Dhw:0,3 -c2 -twav # HDMI speaker-test -Dhw:0,0 -c2 -twav # Analog The second command will produce sound in the analog lineout _as well as_ HDMI sink. The root cause is, device 0 "reuses" the same stream tag that was used by device 3, and the "intelhdmi - sticky stream id" patch leaves the HDMI codec in a functional state. So the HDMI codec happily accepts the audio samples which reuse its stream tag. The proposed solution is to remember the last device each azx_dev was assigned to, and prefer to 1) reuse the azx_dev (and hence the stream tag) the HDMI codec last used 2) or assign a never-used azx_dev for HDMI With this patch and the above two speaker-test commands, HDMI codec will use stream tag 8 and Analog codec will use 5. The stream tag used by HDMI codec won't be reused by others, as long as we don't run out of the 4 playback azx_dev's. The legacy Analog codec will continue to use stream tag 5 because its device id is 0 (this is a bit tricky). Signed-off-by: Wu Fengguang Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_intel.c | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index ff8ad46..ec9c348 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -356,6 +356,7 @@ struct azx_dev { */ unsigned char stream_tag; /* assigned stream */ unsigned char index; /* stream index */ + int device; /* last device number assigned to */ unsigned int opened :1; unsigned int running :1; @@ -1441,10 +1442,13 @@ static int __devinit azx_codec_configure(struct azx *chip) */ /* assign a stream for the PCM */ -static inline struct azx_dev *azx_assign_device(struct azx *chip, int stream) +static inline struct azx_dev * +azx_assign_device(struct azx *chip, struct snd_pcm_substream *substream) { int dev, i, nums; - if (stream == SNDRV_PCM_STREAM_PLAYBACK) { + struct azx_dev *res = NULL; + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { dev = chip->playback_index_offset; nums = chip->playback_streams; } else { @@ -1453,10 +1457,15 @@ static inline struct azx_dev *azx_assign_device(struct azx *chip, int stream) } for (i = 0; i < nums; i++, dev++) if (!chip->azx_dev[dev].opened) { - chip->azx_dev[dev].opened = 1; - return &chip->azx_dev[dev]; + res = &chip->azx_dev[dev]; + if (res->device == substream->pcm->device) + break; } - return NULL; + if (res) { + res->opened = 1; + res->device = substream->pcm->device; + } + return res; } /* release the assigned stream */ @@ -1505,7 +1514,7 @@ static int azx_pcm_open(struct snd_pcm_substream *substream) int err; mutex_lock(&chip->open_mutex); - azx_dev = azx_assign_device(chip, substream->stream); + azx_dev = azx_assign_device(chip, substream); if (azx_dev == NULL) { mutex_unlock(&chip->open_mutex); return -EBUSY; -- cgit v1.1 From 729d55ba972348234759f8e40abf8de020f0d505 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 25 Dec 2009 22:49:01 +0100 Subject: ALSA: hda - Disable tigger at pin-sensing on AD codecs Analog Device codecs seem to have problems with the triggering of pin-sensing although their pincaps give the trigger requirements. Some reported that constant CPU load on HP laptops with AD codecs. For avoiding this regression, add a flag to codec struct to notify explicitly that the codec doesn't suppot the trigger at pin-sensing. Tested-by: Maciej Rutecki Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_codec.c | 10 ++++++---- sound/pci/hda/hda_codec.h | 1 + sound/pci/hda/patch_analog.c | 16 ++++++++++++++++ 3 files changed, 23 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 950ee5cf..f98b47c 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -1327,11 +1327,13 @@ EXPORT_SYMBOL_HDA(snd_hda_query_pin_caps); */ u32 snd_hda_pin_sense(struct hda_codec *codec, hda_nid_t nid) { - u32 pincap = snd_hda_query_pin_caps(codec, nid); - - if (pincap & AC_PINCAP_TRIG_REQ) /* need trigger? */ - snd_hda_codec_read(codec, nid, 0, AC_VERB_SET_PIN_SENSE, 0); + u32 pincap; + if (!codec->no_trigger_sense) { + pincap = snd_hda_query_pin_caps(codec, nid); + if (pincap & AC_PINCAP_TRIG_REQ) /* need trigger? */ + snd_hda_codec_read(codec, nid, 0, AC_VERB_SET_PIN_SENSE, 0); + } return snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_PIN_SENSE, 0); } diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index 1d541b7..0a770a2 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h @@ -817,6 +817,7 @@ struct hda_codec { unsigned int pin_amp_workaround:1; /* pin out-amp takes index * (e.g. Conexant codecs) */ + unsigned int no_trigger_sense:1; /* don't trigger at pin-sensing */ #ifdef CONFIG_SND_HDA_POWER_SAVE unsigned int power_on :1; /* current (global) power-state */ unsigned int power_transition :1; /* power-state in transition */ diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c index 1a36137..69a941c 100644 --- a/sound/pci/hda/patch_analog.c +++ b/sound/pci/hda/patch_analog.c @@ -1186,6 +1186,8 @@ static int patch_ad1986a(struct hda_codec *codec) */ spec->multiout.no_share_stream = 1; + codec->no_trigger_sense = 1; + return 0; } @@ -1371,6 +1373,8 @@ static int patch_ad1983(struct hda_codec *codec) codec->patch_ops = ad198x_patch_ops; + codec->no_trigger_sense = 1; + return 0; } @@ -1813,6 +1817,9 @@ static int patch_ad1981(struct hda_codec *codec) codec->patch_ops.unsol_event = ad1981_hp_unsol_event; break; } + + codec->no_trigger_sense = 1; + return 0; } @@ -3118,6 +3125,8 @@ static int patch_ad1988(struct hda_codec *codec) #endif spec->vmaster_nid = 0x04; + codec->no_trigger_sense = 1; + return 0; } @@ -3330,6 +3339,8 @@ static int patch_ad1884(struct hda_codec *codec) codec->patch_ops = ad198x_patch_ops; + codec->no_trigger_sense = 1; + return 0; } @@ -4287,6 +4298,8 @@ static int patch_ad1884a(struct hda_codec *codec) break; } + codec->no_trigger_sense = 1; + return 0; } @@ -4623,6 +4636,9 @@ static int patch_ad1882(struct hda_codec *codec) spec->mixers[2] = ad1882_6stack_mixers; break; } + + codec->no_trigger_sense = 1; + return 0; } -- cgit v1.1 From a252c81a69c4f9a5a8782f33b91bd837e9dcd406 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 25 Dec 2009 22:56:20 +0100 Subject: ALSA: hda - use snd_hda_jack_detect() again in patch_sigmatel.c Use snd_hda_jack_detect() again for jack-sensing. The triggering problem can be worked around with codec->no_trigger_sense flag now. Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_sigmatel.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index eeda7be..2291a83 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -4453,14 +4453,7 @@ static inline int get_pin_presence(struct hda_codec *codec, hda_nid_t nid) { if (!nid) return 0; - /* NOTE: we can't use snd_hda_jack_detect() here because STAC/IDT - * codecs behave wrongly when SET_PIN_SENSE is triggered, although - * the pincap gives TRIG_REQ bit. - */ - if (snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_PIN_SENSE, 0) & - AC_PINSENSE_PRESENCE) - return 1; - return 0; + return snd_hda_jack_detect(codec, nid); } static void stac92xx_line_out_detect(struct hda_codec *codec, @@ -4962,6 +4955,7 @@ static int patch_stac9200(struct hda_codec *codec) if (spec == NULL) return -ENOMEM; + codec->no_trigger_sense = 1; codec->spec = spec; spec->num_pins = ARRAY_SIZE(stac9200_pin_nids); spec->pin_nids = stac9200_pin_nids; @@ -5024,6 +5018,7 @@ static int patch_stac925x(struct hda_codec *codec) if (spec == NULL) return -ENOMEM; + codec->no_trigger_sense = 1; codec->spec = spec; spec->num_pins = ARRAY_SIZE(stac925x_pin_nids); spec->pin_nids = stac925x_pin_nids; @@ -5108,6 +5103,7 @@ static int patch_stac92hd73xx(struct hda_codec *codec) if (spec == NULL) return -ENOMEM; + codec->no_trigger_sense = 1; codec->spec = spec; codec->slave_dig_outs = stac92hd73xx_slave_dig_outs; spec->num_pins = ARRAY_SIZE(stac92hd73xx_pin_nids); @@ -5255,6 +5251,7 @@ static int patch_stac92hd83xxx(struct hda_codec *codec) if (spec == NULL) return -ENOMEM; + codec->no_trigger_sense = 1; codec->spec = spec; codec->slave_dig_outs = stac92hd83xxx_slave_dig_outs; spec->digbeep_nid = 0x21; @@ -5418,6 +5415,7 @@ static int patch_stac92hd71bxx(struct hda_codec *codec) if (spec == NULL) return -ENOMEM; + codec->no_trigger_sense = 1; codec->spec = spec; codec->patch_ops = stac92xx_patch_ops; spec->num_pins = STAC92HD71BXX_NUM_PINS; @@ -5661,6 +5659,7 @@ static int patch_stac922x(struct hda_codec *codec) if (spec == NULL) return -ENOMEM; + codec->no_trigger_sense = 1; codec->spec = spec; spec->num_pins = ARRAY_SIZE(stac922x_pin_nids); spec->pin_nids = stac922x_pin_nids; @@ -5764,6 +5763,7 @@ static int patch_stac927x(struct hda_codec *codec) if (spec == NULL) return -ENOMEM; + codec->no_trigger_sense = 1; codec->spec = spec; codec->slave_dig_outs = stac927x_slave_dig_outs; spec->num_pins = ARRAY_SIZE(stac927x_pin_nids); @@ -5898,6 +5898,7 @@ static int patch_stac9205(struct hda_codec *codec) if (spec == NULL) return -ENOMEM; + codec->no_trigger_sense = 1; codec->spec = spec; spec->num_pins = ARRAY_SIZE(stac9205_pin_nids); spec->pin_nids = stac9205_pin_nids; @@ -6053,6 +6054,7 @@ static int patch_stac9872(struct hda_codec *codec) spec = kzalloc(sizeof(*spec), GFP_KERNEL); if (spec == NULL) return -ENOMEM; + codec->no_trigger_sense = 1; codec->spec = spec; spec->num_pins = ARRAY_SIZE(stac9872_pin_nids); spec->pin_nids = stac9872_pin_nids; -- cgit v1.1 From 411fe85c7653f51403c2a6fd9026b0db2ab19478 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Sun, 27 Dec 2009 10:25:58 +0100 Subject: ALSA: hda - Don't cache beep controls The beep control verbs don't need to be cached for resume. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_beep.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/hda_beep.c b/sound/pci/hda/hda_beep.c index 5fe34a8..ca3c57a 100644 --- a/sound/pci/hda/hda_beep.c +++ b/sound/pci/hda/hda_beep.c @@ -42,7 +42,7 @@ static void snd_hda_generate_beep(struct work_struct *work) return; /* generate tone */ - snd_hda_codec_write_cache(codec, beep->nid, 0, + snd_hda_codec_write(codec, beep->nid, 0, AC_VERB_SET_BEEP_CONTROL, beep->tone); } @@ -119,7 +119,7 @@ static void snd_hda_do_detach(struct hda_beep *beep) beep->dev = NULL; cancel_work_sync(&beep->beep_work); /* turn off beep for sure */ - snd_hda_codec_write_cache(beep->codec, beep->nid, 0, + snd_hda_codec_write(beep->codec, beep->nid, 0, AC_VERB_SET_BEEP_CONTROL, 0); } @@ -192,7 +192,7 @@ int snd_hda_enable_beep_device(struct hda_codec *codec, int enable) beep->enabled = enable; if (!enable) { /* turn off beep */ - snd_hda_codec_write_cache(beep->codec, beep->nid, 0, + snd_hda_codec_write(beep->codec, beep->nid, 0, AC_VERB_SET_BEEP_CONTROL, 0); } if (beep->mode == HDA_BEEP_MODE_SWREG) { -- cgit v1.1 From 54f7190b23080c7ac32078ed6a346bdc591ebef1 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Sun, 27 Dec 2009 13:27:39 +0100 Subject: ALSA: hda - Fix Oops at reloading beep devices The recent change for supporting dynamic beep device allocation caused a problem resulting in Oops at reloading the driver. Also, it ignores the error from input device registration. This patch fixes the wrong check in snd_hda_detach_beep_device(), and returns an error when the input device registration fails properly. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_beep.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/hda_beep.c b/sound/pci/hda/hda_beep.c index ca3c57a..e4581a42 100644 --- a/sound/pci/hda/hda_beep.c +++ b/sound/pci/hda/hda_beep.c @@ -239,8 +239,12 @@ int snd_hda_attach_beep_device(struct hda_codec *codec, int nid) mutex_init(&beep->mutex); if (beep->mode == HDA_BEEP_MODE_ON) { - beep->enabled = 1; - snd_hda_do_register(&beep->register_work); + int err = snd_hda_do_attach(beep); + if (err < 0) { + kfree(beep); + codec->beep = NULL; + return err; + } } return 0; @@ -253,7 +257,7 @@ void snd_hda_detach_beep_device(struct hda_codec *codec) if (beep) { cancel_work_sync(&beep->register_work); cancel_delayed_work(&beep->unregister_work); - if (beep->enabled) + if (beep->dev) snd_hda_do_detach(beep); codec->beep = NULL; kfree(beep); -- cgit v1.1