ALSA: hda - Remember connection lists
The connection lists are static and we can reuse the previous results instead of querying via verb at each time. This will reduce the I/O in the runtime especially for some codec auto-parsers. Signed-off-by: Takashi Iwai <tiwai@suse.de>
This commit is contained in:
Родитель
8e28e3b29f
Коммит
a12d3e1e1c
|
@ -307,6 +307,12 @@ int snd_hda_get_sub_nodes(struct hda_codec *codec, hda_nid_t nid,
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_HDA(snd_hda_get_sub_nodes);
|
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);
|
||||||
|
static int copy_conn_list(hda_nid_t nid, hda_nid_t *dst, int max_dst,
|
||||||
|
hda_nid_t *src, int len);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* snd_hda_get_connections - get connection list
|
* snd_hda_get_connections - get connection list
|
||||||
* @codec: the HDA codec
|
* @codec: the HDA codec
|
||||||
|
@ -320,7 +326,44 @@ EXPORT_SYMBOL_HDA(snd_hda_get_sub_nodes);
|
||||||
* Returns the number of connections, or a negative error code.
|
* Returns the number of connections, or a negative error code.
|
||||||
*/
|
*/
|
||||||
int snd_hda_get_connections(struct hda_codec *codec, hda_nid_t nid,
|
int snd_hda_get_connections(struct hda_codec *codec, hda_nid_t nid,
|
||||||
hda_nid_t *conn_list, int max_conns)
|
hda_nid_t *conn_list, int max_conns)
|
||||||
|
{
|
||||||
|
struct snd_array *array = &codec->conn_lists;
|
||||||
|
int i, j, len, old_used;
|
||||||
|
hda_nid_t list[HDA_MAX_CONNECTIONS];
|
||||||
|
|
||||||
|
/* look up the cached results */
|
||||||
|
for (i = 0; i < array->used; ) {
|
||||||
|
hda_nid_t *p = snd_array_elem(array, i);
|
||||||
|
len = p[1];
|
||||||
|
if (nid == *p)
|
||||||
|
return copy_conn_list(nid, conn_list, max_conns,
|
||||||
|
p + 2, len);
|
||||||
|
i += len + 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
return copy_conn_list(nid, conn_list, max_conns, list, len);
|
||||||
|
|
||||||
|
error_add:
|
||||||
|
array->used = old_used;
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_HDA(snd_hda_get_connections);
|
||||||
|
|
||||||
|
static int _hda_get_connections(struct hda_codec *codec, hda_nid_t nid,
|
||||||
|
hda_nid_t *conn_list, int max_conns)
|
||||||
{
|
{
|
||||||
unsigned int parm;
|
unsigned int parm;
|
||||||
int i, conn_len, conns;
|
int i, conn_len, conns;
|
||||||
|
@ -417,8 +460,28 @@ int snd_hda_get_connections(struct hda_codec *codec, hda_nid_t nid,
|
||||||
}
|
}
|
||||||
return conns;
|
return conns;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_HDA(snd_hda_get_connections);
|
|
||||||
|
|
||||||
|
static bool add_conn_list(struct snd_array *array, hda_nid_t nid)
|
||||||
|
{
|
||||||
|
hda_nid_t *p = snd_array_new(array);
|
||||||
|
if (!p)
|
||||||
|
return false;
|
||||||
|
*p = nid;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int copy_conn_list(hda_nid_t nid, hda_nid_t *dst, int max_dst,
|
||||||
|
hda_nid_t *src, int len)
|
||||||
|
{
|
||||||
|
if (len > max_dst) {
|
||||||
|
snd_printk(KERN_ERR "hda_codec: "
|
||||||
|
"Too many connections %d for NID 0x%x\n",
|
||||||
|
len, nid);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
memcpy(dst, src, len * sizeof(hda_nid_t));
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* snd_hda_queue_unsol_event - add an unsolicited event to queue
|
* snd_hda_queue_unsol_event - add an unsolicited event to queue
|
||||||
|
@ -1017,6 +1080,7 @@ static void snd_hda_codec_free(struct hda_codec *codec)
|
||||||
list_del(&codec->list);
|
list_del(&codec->list);
|
||||||
snd_array_free(&codec->mixers);
|
snd_array_free(&codec->mixers);
|
||||||
snd_array_free(&codec->nids);
|
snd_array_free(&codec->nids);
|
||||||
|
snd_array_free(&codec->conn_lists);
|
||||||
codec->bus->caddr_tbl[codec->addr] = NULL;
|
codec->bus->caddr_tbl[codec->addr] = NULL;
|
||||||
if (codec->patch_ops.free)
|
if (codec->patch_ops.free)
|
||||||
codec->patch_ops.free(codec);
|
codec->patch_ops.free(codec);
|
||||||
|
@ -1077,6 +1141,7 @@ int /*__devinit*/ snd_hda_codec_new(struct hda_bus *bus,
|
||||||
snd_array_init(&codec->init_pins, sizeof(struct hda_pincfg), 16);
|
snd_array_init(&codec->init_pins, sizeof(struct hda_pincfg), 16);
|
||||||
snd_array_init(&codec->driver_pins, sizeof(struct hda_pincfg), 16);
|
snd_array_init(&codec->driver_pins, sizeof(struct hda_pincfg), 16);
|
||||||
snd_array_init(&codec->cvt_setups, sizeof(struct hda_cvt_setup), 8);
|
snd_array_init(&codec->cvt_setups, sizeof(struct hda_cvt_setup), 8);
|
||||||
|
snd_array_init(&codec->conn_lists, sizeof(hda_nid_t), 64);
|
||||||
if (codec->bus->modelname) {
|
if (codec->bus->modelname) {
|
||||||
codec->modelname = kstrdup(codec->bus->modelname, GFP_KERNEL);
|
codec->modelname = kstrdup(codec->bus->modelname, GFP_KERNEL);
|
||||||
if (!codec->modelname) {
|
if (!codec->modelname) {
|
||||||
|
|
|
@ -825,6 +825,8 @@ struct hda_codec {
|
||||||
struct hda_cache_rec amp_cache; /* cache for amp access */
|
struct hda_cache_rec amp_cache; /* cache for amp access */
|
||||||
struct hda_cache_rec cmd_cache; /* cache for other commands */
|
struct hda_cache_rec cmd_cache; /* cache for other commands */
|
||||||
|
|
||||||
|
struct snd_array conn_lists; /* connection-list array */
|
||||||
|
|
||||||
struct mutex spdif_mutex;
|
struct mutex spdif_mutex;
|
||||||
struct mutex control_mutex;
|
struct mutex control_mutex;
|
||||||
unsigned int spdif_status; /* IEC958 status bits */
|
unsigned int spdif_status; /* IEC958 status bits */
|
||||||
|
|
Загрузка…
Ссылка в новой задаче