From: Takashi Iwai Date: Mon, 4 Jul 2011 14:23:26 +0000 (+0200) Subject: ALSA: hda - Add snd_hda_override_conn_list() helper function X-Git-Url: http://drtracing.org/?a=commitdiff_plain;h=b2f934a0dffd4153e9447ee9e0090e357a3d8b3b;p=deliverable%2Flinux.git 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 --- 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); @@ -502,6 +504,43 @@ static bool add_conn_list(struct snd_array *array, hda_nid_t nid) return true; } +/** + * 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 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,