Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a12d3e1e authored by Takashi Iwai's avatar Takashi Iwai
Browse files

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: default avatarTakashi Iwai <tiwai@suse.de>
parent 8e28e3b2
Loading
Loading
Loading
Loading
+67 −2
Original line number Diff line number Diff line
@@ -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);

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
 * @codec: the HDA codec
@@ -321,6 +327,43 @@ EXPORT_SYMBOL_HDA(snd_hda_get_sub_nodes);
 */
int snd_hda_get_connections(struct hda_codec *codec, hda_nid_t nid,
			     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;
	int i, conn_len, conns;
@@ -417,8 +460,28 @@ int snd_hda_get_connections(struct hda_codec *codec, hda_nid_t nid,
	}
	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
@@ -1017,6 +1080,7 @@ static void snd_hda_codec_free(struct hda_codec *codec)
	list_del(&codec->list);
	snd_array_free(&codec->mixers);
	snd_array_free(&codec->nids);
	snd_array_free(&codec->conn_lists);
	codec->bus->caddr_tbl[codec->addr] = NULL;
	if (codec->patch_ops.free)
		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->driver_pins, sizeof(struct hda_pincfg), 16);
	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) {
		codec->modelname = kstrdup(codec->bus->modelname, GFP_KERNEL);
		if (!codec->modelname) {
+2 −0
Original line number Diff line number Diff line
@@ -825,6 +825,8 @@ struct hda_codec {
	struct hda_cache_rec amp_cache;	/* cache for amp access */
	struct hda_cache_rec cmd_cache;	/* cache for other commands */

	struct snd_array conn_lists;	/* connection-list array */

	struct mutex spdif_mutex;
	struct mutex control_mutex;
	unsigned int spdif_status;	/* IEC958 status bits */