summaryrefslogtreecommitdiffstats
path: root/sound
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2011-07-04 16:23:26 +0200
committerTakashi Iwai <tiwai@suse.de>2011-07-12 07:44:46 +0200
commitb2f934a0dffd4153e9447ee9e0090e357a3d8b3b (patch)
tree88237adf2e9523f3f955b7f79c9a47061dc044c6 /sound
parent19110595c89b2d606883b7cb99260c7e47fd2143 (diff)
downloadlinux-b2f934a0dffd4153e9447ee9e0090e357a3d8b3b.tar.gz
linux-b2f934a0dffd4153e9447ee9e0090e357a3d8b3b.tar.bz2
linux-b2f934a0dffd4153e9447ee9e0090e357a3d8b3b.zip
ALSA: hda - Add snd_hda_override_conn_list() helper function
Add a function to add/modify the connection-list cache entry. It'll be useful to fix a buggy hardware result. Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound')
-rw-r--r--sound/pci/hda/hda_codec.c99
-rw-r--r--sound/pci/hda/hda_codec.h2
2 files changed, 71 insertions, 30 deletions
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c
index 7f8502388a82..d0deab1ed510 100644
--- a/sound/pci/hda/hda_codec.c
+++ b/sound/pci/hda/hda_codec.c
@@ -310,10 +310,23 @@ EXPORT_SYMBOL_HDA(snd_hda_get_sub_nodes);
static int _hda_get_connections(struct hda_codec *codec, hda_nid_t nid,
hda_nid_t *conn_list, int max_conns);
-static bool add_conn_list(struct snd_array *array, hda_nid_t nid);
+
+/* look up the cached results */
+static hda_nid_t *lookup_conn_list(struct snd_array *array, hda_nid_t nid)
+{
+ int i, len;
+ for (i = 0; i < array->used; ) {
+ hda_nid_t *p = snd_array_elem(array, i);
+ if (nid == *p)
+ return p;
+ len = p[1];
+ i += len + 2;
+ }
+ return NULL;
+}
/**
- * snd_hda_get_connections - get connection list
+ * snd_hda_get_conn_list - get connection list
* @codec: the HDA codec
* @nid: NID to parse
* @listp: the pointer to store NID list
@@ -327,42 +340,31 @@ int snd_hda_get_conn_list(struct hda_codec *codec, hda_nid_t nid,
const hda_nid_t **listp)
{
struct snd_array *array = &codec->conn_lists;
- int i, len, old_used;
+ int len, err;
hda_nid_t list[HDA_MAX_CONNECTIONS];
hda_nid_t *p;
+ bool added = false;
- /* look up the cached results */
- for (i = 0; i < array->used; ) {
- p = snd_array_elem(array, i);
- len = p[1];
- if (nid == *p) {
- if (listp)
- *listp = p + 2;
- return len;
- }
- i += len + 2;
+ again:
+ /* if the connection-list is already cached, read it */
+ p = lookup_conn_list(array, nid);
+ if (p) {
+ if (listp)
+ *listp = p + 2;
+ return p[1];
}
+ if (snd_BUG_ON(added))
+ return -EINVAL;
+ /* read the connection and add to the cache */
len = _hda_get_connections(codec, nid, list, HDA_MAX_CONNECTIONS);
if (len < 0)
return len;
-
- /* add to the cache */
- old_used = array->used;
- if (!add_conn_list(array, nid) || !add_conn_list(array, len))
- goto error_add;
- for (i = 0; i < len; i++)
- if (!add_conn_list(array, list[i]))
- goto error_add;
-
- p = snd_array_elem(array, old_used);
- if (listp)
- *listp = p + 2;
- return len;
-
- error_add:
- array->used = old_used;
- return -ENOMEM;
+ err = snd_hda_override_conn_list(codec, nid, len, list);
+ if (err < 0)
+ return err;
+ added = true;
+ goto again;
}
EXPORT_SYMBOL_HDA(snd_hda_get_conn_list);
@@ -503,6 +505,43 @@ static bool add_conn_list(struct snd_array *array, hda_nid_t nid)
}
/**
+ * snd_hda_override_conn_list - add/modify the connection-list to cache
+ * @codec: the HDA codec
+ * @nid: NID to parse
+ * @len: number of connection list entries
+ * @list: the list of connection entries
+ *
+ * Add or modify the given connection-list to the cache. If the corresponding
+ * cache already exists, invalidate it and append a new one.
+ *
+ * Returns zero or a negative error code.
+ */
+int snd_hda_override_conn_list(struct hda_codec *codec, hda_nid_t nid, int len,
+ const hda_nid_t *list)
+{
+ struct snd_array *array = &codec->conn_lists;
+ hda_nid_t *p;
+ int i, old_used;
+
+ p = lookup_conn_list(array, nid);
+ if (p)
+ *p = -1; /* invalidate the old entry */
+
+ old_used = array->used;
+ if (!add_conn_list(array, nid) || !add_conn_list(array, len))
+ goto error_add;
+ for (i = 0; i < len; i++)
+ if (!add_conn_list(array, list[i]))
+ goto error_add;
+ return 0;
+
+ error_add:
+ array->used = old_used;
+ return -ENOMEM;
+}
+EXPORT_SYMBOL_HDA(snd_hda_override_conn_list);
+
+/**
* snd_hda_get_conn_index - get the connection index of the given NID
* @codec: the HDA codec
* @mux: NID containing the list
diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h
index 10d500d2ba33..e6bc16f66bce 100644
--- a/sound/pci/hda/hda_codec.h
+++ b/sound/pci/hda/hda_codec.h
@@ -905,6 +905,8 @@ int snd_hda_get_connections(struct hda_codec *codec, hda_nid_t nid,
hda_nid_t *conn_list, int max_conns);
int snd_hda_get_conn_list(struct hda_codec *codec, hda_nid_t nid,
const hda_nid_t **listp);
+int snd_hda_override_conn_list(struct hda_codec *codec, hda_nid_t nid, int nums,
+ const hda_nid_t *list);
int snd_hda_get_conn_index(struct hda_codec *codec, hda_nid_t mux,
hda_nid_t nid, int recursive);
int snd_hda_query_supported_pcm(struct hda_codec *codec, hda_nid_t nid,