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>
This commit is contained in:
Takashi Iwai 2011-07-04 16:23:26 +02:00
parent 19110595c8
commit b2f934a0df
2 changed files with 71 additions and 30 deletions

View File

@ -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

View File

@ -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,