summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2010-08-20 09:44:36 +0200
committerTakashi Iwai <tiwai@suse.de>2010-08-20 09:49:42 +0200
commit3f50ac6a0ec80a83a1a033fe5004fb319ad72db7 (patch)
tree8e48910834056f4a7ef7219ad6a0741e5d8294fb
parent4f34760787c3751a3146f0eecdc79c3e97b94962 (diff)
downloadlinux-3f50ac6a0ec80a83a1a033fe5004fb319ad72db7.tar.gz
linux-3f50ac6a0ec80a83a1a033fe5004fb319ad72db7.tar.bz2
linux-3f50ac6a0ec80a83a1a033fe5004fb319ad72db7.zip
ALSA: hda - Fix stream and channel-ids codec-bus wide
The new sticky PCM parameter introduced the delayed clean-ups of stream- and channel-id tags. In the current implementation, this check (adding dirty flag) and actual clean-ups are done only for the codec chip. However, with HD-audio architecture, multiple codecs can be on a single bus, and the controller assign stream- and channel-ids in the bus-wide. In this patch, the stream-id and channel-id are checked over all codecs connected to the corresponding bus. Together with it, the mutex is moved to struct hda_bus, as this becomes also bus-wide. Reported-and-tested-by: Stephen Warren <swarren@nvidia.com> Signed-off-by: Takashi Iwai <tiwai@suse.de>
-rw-r--r--sound/pci/hda/hda_codec.c33
-rw-r--r--sound/pci/hda/hda_codec.h2
2 files changed, 21 insertions, 14 deletions
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c
index dd8fb86c842b..3827092cc1d2 100644
--- a/sound/pci/hda/hda_codec.c
+++ b/sound/pci/hda/hda_codec.c
@@ -589,6 +589,7 @@ int /*__devinit*/ snd_hda_bus_new(struct snd_card *card,
bus->ops = temp->ops;
mutex_init(&bus->cmd_mutex);
+ mutex_init(&bus->prepare_mutex);
INIT_LIST_HEAD(&bus->codec_list);
snprintf(bus->workq_name, sizeof(bus->workq_name),
@@ -1068,7 +1069,6 @@ int /*__devinit*/ snd_hda_codec_new(struct hda_bus *bus,
codec->addr = codec_addr;
mutex_init(&codec->spdif_mutex);
mutex_init(&codec->control_mutex);
- mutex_init(&codec->prepare_mutex);
init_hda_cache(&codec->amp_cache, sizeof(struct hda_amp_info));
init_hda_cache(&codec->cmd_cache, sizeof(struct hda_cache_head));
snd_array_init(&codec->mixers, sizeof(struct hda_nid_item), 32);
@@ -1213,6 +1213,7 @@ void snd_hda_codec_setup_stream(struct hda_codec *codec, hda_nid_t nid,
u32 stream_tag,
int channel_id, int format)
{
+ struct hda_codec *c;
struct hda_cvt_setup *p;
unsigned int oldval, newval;
int i;
@@ -1253,10 +1254,12 @@ void snd_hda_codec_setup_stream(struct hda_codec *codec, hda_nid_t nid,
p->dirty = 0;
/* make other inactive cvts with the same stream-tag dirty */
- for (i = 0; i < codec->cvt_setups.used; i++) {
- p = snd_array_elem(&codec->cvt_setups, i);
- if (!p->active && p->stream_tag == stream_tag)
- p->dirty = 1;
+ list_for_each_entry(c, &codec->bus->codec_list, list) {
+ for (i = 0; i < c->cvt_setups.used; i++) {
+ p = snd_array_elem(&c->cvt_setups, i);
+ if (!p->active && p->stream_tag == stream_tag)
+ p->dirty = 1;
+ }
}
}
EXPORT_SYMBOL_HDA(snd_hda_codec_setup_stream);
@@ -1306,12 +1309,16 @@ static void really_cleanup_stream(struct hda_codec *codec,
/* clean up the all conflicting obsolete streams */
static void purify_inactive_streams(struct hda_codec *codec)
{
+ struct hda_codec *c;
int i;
- for (i = 0; i < codec->cvt_setups.used; i++) {
- struct hda_cvt_setup *p = snd_array_elem(&codec->cvt_setups, i);
- if (p->dirty)
- really_cleanup_stream(codec, p);
+ list_for_each_entry(c, &codec->bus->codec_list, list) {
+ for (i = 0; i < c->cvt_setups.used; i++) {
+ struct hda_cvt_setup *p;
+ p = snd_array_elem(&c->cvt_setups, i);
+ if (p->dirty)
+ really_cleanup_stream(c, p);
+ }
}
}
@@ -3502,11 +3509,11 @@ int snd_hda_codec_prepare(struct hda_codec *codec,
struct snd_pcm_substream *substream)
{
int ret;
- mutex_lock(&codec->prepare_mutex);
+ mutex_lock(&codec->bus->prepare_mutex);
ret = hinfo->ops.prepare(hinfo, codec, stream, format, substream);
if (ret >= 0)
purify_inactive_streams(codec);
- mutex_unlock(&codec->prepare_mutex);
+ mutex_unlock(&codec->bus->prepare_mutex);
return ret;
}
EXPORT_SYMBOL_HDA(snd_hda_codec_prepare);
@@ -3515,9 +3522,9 @@ void snd_hda_codec_cleanup(struct hda_codec *codec,
struct hda_pcm_stream *hinfo,
struct snd_pcm_substream *substream)
{
- mutex_lock(&codec->prepare_mutex);
+ mutex_lock(&codec->bus->prepare_mutex);
hinfo->ops.cleanup(hinfo, codec, substream);
- mutex_unlock(&codec->prepare_mutex);
+ mutex_unlock(&codec->bus->prepare_mutex);
}
EXPORT_SYMBOL_HDA(snd_hda_codec_cleanup);
diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h
index 4303353feda9..62c702240108 100644
--- a/sound/pci/hda/hda_codec.h
+++ b/sound/pci/hda/hda_codec.h
@@ -648,6 +648,7 @@ struct hda_bus {
struct hda_codec *caddr_tbl[HDA_MAX_CODEC_ADDRESS + 1];
struct mutex cmd_mutex;
+ struct mutex prepare_mutex;
/* unsolicited event queue */
struct hda_bus_unsolicited *unsol;
@@ -826,7 +827,6 @@ struct hda_codec {
struct mutex spdif_mutex;
struct mutex control_mutex;
- struct mutex prepare_mutex;
unsigned int spdif_status; /* IEC958 status bits */
unsigned short spdif_ctls; /* SPDIF control bits */
unsigned int spdif_in_enable; /* SPDIF input enable? */