[alsa-devel] [RFC PATCH 1/4] ALSA: hda - codec add DP MST support for connection list

libin.yang at linux.intel.com libin.yang at linux.intel.com
Mon Mar 7 15:57:43 CET 2016


From: Libin Yang <libin.yang at linux.intel.com>

This patches adds the support of connection list for DP MST.
With this, hdmi driver in DP MST mode can easily reuse
the connection list mechanism.

Signed-off-by: Libin Yang <libin.yang at linux.intel.com>
---
 sound/pci/hda/hda_codec.c | 134 ++++++++++++++++++++++++++++++++++++++++++----
 sound/pci/hda/hda_codec.h |   5 ++
 2 files changed, 128 insertions(+), 11 deletions(-)

diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c
index 8374188..d4c81f7 100644
--- a/sound/pci/hda/hda_codec.c
+++ b/sound/pci/hda/hda_codec.c
@@ -110,23 +110,24 @@ struct hda_conn_list {
 	struct list_head list;
 	int len;
 	hda_nid_t nid;
+	int dev_id;
 	hda_nid_t conns[0];
 };
 
 /* look up the cached results */
 static struct hda_conn_list *
-lookup_conn_list(struct hda_codec *codec, hda_nid_t nid)
+lookup_conn_list(struct hda_codec *codec, hda_nid_t nid, int dev_id)
 {
 	struct hda_conn_list *p;
 	list_for_each_entry(p, &codec->conn_list, list) {
-		if (p->nid == nid)
+		if ((p->nid == nid) && (p->dev_id == dev_id))
 			return p;
 	}
 	return NULL;
 }
 
-static int add_conn_list(struct hda_codec *codec, hda_nid_t nid, int len,
-			 const hda_nid_t *list)
+static int add_conn_list(struct hda_codec *codec, hda_nid_t nid,
+			 int dev_id, int len, const hda_nid_t *list)
 {
 	struct hda_conn_list *p;
 
@@ -135,6 +136,7 @@ static int add_conn_list(struct hda_codec *codec, hda_nid_t nid, int len,
 		return -ENOMEM;
 	p->len = len;
 	p->nid = nid;
+	p->dev_id = dev_id;
 	memcpy(p->conns, list, len * sizeof(hda_nid_t));
 	list_add(&p->list, &codec->conn_list);
 	return 0;
@@ -150,8 +152,13 @@ static void remove_conn_list(struct hda_codec *codec)
 	}
 }
 
-/* read the connection and add to the cache */
-static int read_and_add_raw_conns(struct hda_codec *codec, hda_nid_t nid)
+/*
+ * read the connection and add to the cache
+ * the caller should select the device entry by sending the
+ * corresponding verb if necessary before calling this function
+ */
+static int read_and_add_raw_conns(struct hda_codec *codec, hda_nid_t nid,
+				  int dev_id)
 {
 	hda_nid_t list[32];
 	hda_nid_t *result = list;
@@ -166,7 +173,8 @@ static int read_and_add_raw_conns(struct hda_codec *codec, hda_nid_t nid)
 		len = snd_hda_get_raw_connections(codec, nid, result, len);
 	}
 	if (len >= 0)
-		len = snd_hda_override_conn_list(codec, nid, len, result);
+		len = snd_hda_override_conn_list_mst(codec, nid,
+					     dev_id, len, result);
 	if (result != list)
 		kfree(result);
 	return len;
@@ -197,7 +205,7 @@ int snd_hda_get_conn_list(struct hda_codec *codec, hda_nid_t nid,
 		const struct hda_conn_list *p;
 
 		/* if the connection-list is already cached, read it */
-		p = lookup_conn_list(codec, nid);
+		p = lookup_conn_list(codec, nid, 0);
 		if (p) {
 			if (listp)
 				*listp = p->conns;
@@ -206,7 +214,7 @@ int snd_hda_get_conn_list(struct hda_codec *codec, hda_nid_t nid,
 		if (snd_BUG_ON(added))
 			return -EINVAL;
 
-		err = read_and_add_raw_conns(codec, nid);
+		err = read_and_add_raw_conns(codec, nid, 0);
 		if (err < 0)
 			return err;
 		added = true;
@@ -215,6 +223,49 @@ int snd_hda_get_conn_list(struct hda_codec *codec, hda_nid_t nid,
 EXPORT_SYMBOL_GPL(snd_hda_get_conn_list);
 
 /**
+ * snd_hda_get_conn_list_mst - get connection list in mst mode
+ * @codec: the HDA codec
+ * @nid: NID to parse
+ * @dev_id: device entry id
+ * @listp: the pointer to store NID list
+ *
+ * Parses the connection list of the given widget and stores the pointer
+ * to the list of NIDs.
+ *
+ * Returns the number of connections, or a negative error code.
+ *
+ * Note that the returned pointer isn't protected against the list
+ * modification.  If snd_hda_override_conn_list() might be called
+ * concurrently, protect with a mutex appropriately.
+ */
+int snd_hda_get_conn_list_mst(struct hda_codec *codec, hda_nid_t nid,
+			      int dev_id, const hda_nid_t **listp)
+{
+	bool added = false;
+
+	for (;;) {
+		int err;
+		const struct hda_conn_list *p;
+
+		/* if the connection-list is already cached, read it */
+		p = lookup_conn_list(codec, nid, dev_id);
+		if (p) {
+			if (listp)
+				*listp = p->conns;
+			return p->len;
+		}
+		if (snd_BUG_ON(added))
+			return -EINVAL;
+
+		err = read_and_add_raw_conns(codec, nid, dev_id);
+		if (err < 0)
+			return err;
+		added = true;
+	}
+}
+EXPORT_SYMBOL_GPL(snd_hda_get_conn_list_mst);
+
+/**
  * snd_hda_get_connections - copy connection list
  * @codec: the HDA codec
  * @nid: NID to parse
@@ -246,6 +297,39 @@ int snd_hda_get_connections(struct hda_codec *codec, hda_nid_t nid,
 EXPORT_SYMBOL_GPL(snd_hda_get_connections);
 
 /**
+ * snd_hda_get_connections_mst - copy connection list in mst mode
+ * @codec: the HDA codec
+ * @nid: NID to parse
+ * @dev_id: device entry id
+ * @conn_list: connection list array; when NULL, checks only the size
+ * @max_conns: max. number of connections to store
+ *
+ * Parses the connection list of the given widget and stores the list
+ * of NIDs.
+ *
+ * Returns the number of connections, or a negative error code.
+ */
+int snd_hda_get_connections_mst(struct hda_codec *codec, hda_nid_t nid,
+				int dev_id, hda_nid_t *conn_list,
+				int max_conns)
+{
+	const hda_nid_t *list;
+	int len = snd_hda_get_conn_list_mst(codec, nid, dev_id, &list);
+
+	if (len > 0 && conn_list) {
+		if (len > max_conns) {
+			codec_err(codec, "Too many connections %d for NID 0x%x\n",
+				   len, nid);
+			return -EINVAL;
+		}
+		memcpy(conn_list, list, len * sizeof(hda_nid_t));
+	}
+
+	return len;
+}
+EXPORT_SYMBOL_GPL(snd_hda_get_connections_mst);
+
+/**
  * snd_hda_override_conn_list - add/modify the connection-list to cache
  * @codec: the HDA codec
  * @nid: NID to parse
@@ -262,17 +346,45 @@ int snd_hda_override_conn_list(struct hda_codec *codec, hda_nid_t nid, int len,
 {
 	struct hda_conn_list *p;
 
-	p = lookup_conn_list(codec, nid);
+	p = lookup_conn_list(codec, nid, 0);
 	if (p) {
 		list_del(&p->list);
 		kfree(p);
 	}
 
-	return add_conn_list(codec, nid, len, list);
+	return add_conn_list(codec, nid, 0, len, list);
 }
 EXPORT_SYMBOL_GPL(snd_hda_override_conn_list);
 
 /**
+ * snd_hda_override_conn_list_mst - add/modify the connection-list to cache
+ * @codec: the HDA codec
+ * @nid: NID to parse
+ * @dev_id: device entry id
+ * @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_mst(struct hda_codec *codec, hda_nid_t nid,
+			   int dev_id, int len, const hda_nid_t *list)
+{
+	struct hda_conn_list *p;
+
+	p = lookup_conn_list(codec, nid, dev_id);
+	if (p) {
+		list_del(&p->list);
+		kfree(p);
+	}
+
+	return add_conn_list(codec, nid, dev_id, len, list);
+}
+EXPORT_SYMBOL_GPL(snd_hda_override_conn_list_mst);
+
+/**
  * 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 373fcad..deeed35 100644
--- a/sound/pci/hda/hda_codec.h
+++ b/sound/pci/hda/hda_codec.h
@@ -330,6 +330,9 @@ snd_hda_codec_write(struct hda_codec *codec, hda_nid_t nid, int flags,
 	snd_hdac_get_sub_nodes(&(codec)->core, nid, start_nid)
 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_connections_mst(struct hda_codec *codec, hda_nid_t nid,
+				int dev_id, hda_nid_t *conn_list,
+				int max_conns);
 static inline int
 snd_hda_get_num_conns(struct hda_codec *codec, hda_nid_t nid)
 {
@@ -345,6 +348,8 @@ 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_override_conn_list_mst(struct hda_codec *codec, hda_nid_t nid,
+			   int dev_id, int len, 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_get_devices(struct hda_codec *codec, hda_nid_t nid,
-- 
1.9.1



More information about the Alsa-devel mailing list