All of lore.kernel.org
 help / color / mirror / Atom feed
From: mengdong.lin@linux.intel.com
To: alsa-devel@alsa-project.org
Cc: tiwai@suse.de, liam.r.girdwood@linux.intel.com,
	Mengdong Lin <mengdong.lin@linux.intel.com>,
	mengdong.lin@intel.com
Subject: [PATCH v6 2/3] ucm: Load device-specific configuration file based on the card long name
Date: Wed, 18 Jan 2017 11:53:35 +0800	[thread overview]
Message-ID: <0901283dcf9b09233e32ef40f880bca92fa9aadf.1484710888.git.mengdong.lin@linux.intel.com> (raw)
In-Reply-To: <cover.1484710888.git.mengdong.lin@linux.intel.com>

From: Mengdong Lin <mengdong.lin@linux.intel.com>

Intel DSP platform drivers are used by many different devices. For user
space to differentiate them, ASoC machine drivers may use the DMI info
(vendor-product-version-board) as card long name. Possible card long names
are:
DellInc.-XPS139343-01-0310JH
ASUSTeKCOMPUTERINC.-T100TA-1.0-T100TA
Circuitco-MinnowboardMaxD0PLATFORM-D0-MinnowBoardMAX
...

If we want to define a device-specific UCM config file for a card, we
need to use the card long name as the name of both the directory that
contains the UCM config file and the UCM config file itself, like
longname/longname.conf

When being asked to load configuration file of a card, UCM will try to
find the card in the local machine and get its long name. If the card
long name is available, try to load the file longname/longname.conf to
get the best device-specific configuration; if this file is not available,
fall back to load the default configuration file shortname/shortname.conf
as before.

This update is backward compatible, because if ASoC machine drivers don't
explicity use DMI or other means to set the card long name, ASoC core
will use the card short name as the long name. And so UCM will load the
config file that matches both the card short name and the long name.

Signed-off-by: Mengdong Lin <mengdong.lin@linux.intel.com>

diff --git a/src/ucm/parser.c b/src/ucm/parser.c
index 3b42e31..ab412d5 100644
--- a/src/ucm/parser.c
+++ b/src/ucm/parser.c
@@ -55,6 +55,9 @@ static const char * const component_dir[] = {
 	NULL,		/* terminator */
 };
 
+static int filename_filter(const struct dirent *dirent);
+static int is_component_directory(const char *dir);
+
 static int parse_sequence(snd_use_case_mgr_t *uc_mgr,
 			  struct list_head *base,
 			  snd_config_t *cfg);
@@ -1328,6 +1331,66 @@ static int parse_master_file(snd_use_case_mgr_t *uc_mgr, snd_config_t *cfg)
 	return 0;
 }
 
+/* find the card in the local machine and store the card long name */
+static int get_card_long_name(snd_use_case_mgr_t *mgr)
+{
+	const char *card_name = mgr->card_name;
+	snd_ctl_t *handle;
+	int card, err;
+	snd_ctl_card_info_t *info;
+	const char *_name, *_long_name;
+
+	snd_ctl_card_info_alloca(&info);
+
+	card = -1;
+	if (snd_card_next(&card) < 0 || card < 0) {
+		uc_error("no soundcards found...");
+		return -1;
+	}
+
+	while (card >= 0) {
+		char name[32];
+
+		sprintf(name, "hw:%d", card);
+		err = snd_ctl_open(&handle, name, 0);
+		if (err < 0) {
+			uc_error("control open (%i): %s", card,
+				 snd_strerror(err));
+			goto next_card;
+		}
+
+		err = snd_ctl_card_info(handle, info);
+		if (err < 0) {
+			uc_error("control hardware info (%i): %s", card,
+				 snd_strerror(err));
+			snd_ctl_close(handle);
+			goto next_card;
+		}
+
+		/* Find the local card by comparing the given name with the
+		 * card short name and long name. The given card name may be
+		 * either a short name or long name, because users may open
+		 * the card by either of the two names.
+		 */
+		_name = snd_ctl_card_info_get_name(info);
+		_long_name = snd_ctl_card_info_get_longname(info);
+		if (!strcmp(card_name, _name)
+		    || !strcmp(card_name, _long_name)) {
+			strcpy(mgr->card_long_name, _long_name);
+			snd_ctl_close(handle);
+			return 0;
+		}
+
+		snd_ctl_close(handle);
+next_card:
+		if (snd_card_next(&card) < 0) {
+			uc_error("snd_card_next");
+			break;
+		}
+	}
+
+	return -1;
+}
 static int load_master_config(const char *card_name, snd_config_t **cfg)
 {
 	char filename[MAX_FILE];
@@ -1355,15 +1418,43 @@ static int load_master_config(const char *card_name, snd_config_t **cfg)
 	return 0;
 }
 
-/* load master use case file for sound card */
+/* load master use case file for sound card
+ *
+ * The same ASoC machine driver can be shared by many different devices.
+ * For user space to differentiate them and get the best device-specific
+ * configuration, ASoC machine drivers may use the DMI info
+ * (vendor-product-version-board) as the card long name. And user space can
+ * define configuration files like longnamei/longname.conf for a specific device.
+ *
+ * This function will try to find the card in the local machine and get its
+ * long name, then load the file longname/longname.conf to get the best
+ * device-specific configuration. If the card is not found in the local
+ * machine or the device-specific file is not available, fall back to load
+ * the default configuration file name/name.conf.
+ */
 int uc_mgr_import_master_config(snd_use_case_mgr_t *uc_mgr)
 {
 	snd_config_t *cfg;
 	int err;
 
-	err = load_master_config(uc_mgr->card_name, &cfg);
-	if (err < 0)
-		return err;
+	err = get_card_long_name(uc_mgr);
+	if (err == 0)	/* load file that maches the card long name */
+		err = load_master_config(uc_mgr->card_long_name, &cfg);
+
+	if (err == 0) {
+		/* got device-specific file that matches the card long name */
+		strcpy(uc_mgr->conf_file_name, uc_mgr->card_long_name);
+	} else {
+		/* Fall back to the file that maches the given card name,
+		 * either short name or long name (users may open a card by
+		 * its name or long name).
+		 */
+		err = load_master_config(uc_mgr->card_name, &cfg);
+		if (err < 0)
+			return err;
+		strcpy(uc_mgr->conf_file_name, uc_mgr->card_name);
+	}
+
 	err = parse_master_file(uc_mgr, cfg);
 	snd_config_delete(cfg);
 	if (err < 0)
diff --git a/src/ucm/ucm_local.h b/src/ucm/ucm_local.h
index e41aafa..299a5b9 100644
--- a/src/ucm/ucm_local.h
+++ b/src/ucm/ucm_local.h
@@ -191,6 +191,8 @@ struct use_case_verb {
  */
 struct snd_use_case_mgr {
 	char *card_name;
+	char card_long_name[MAX_CARD_LONG_NAME];
+	char conf_file_name[MAX_CARD_LONG_NAME];
 	char *comment;
 
 	/* use case verb, devices and modifier configs parsed from files */
-- 
2.7.4

  parent reply	other threads:[~2017-01-18  3:50 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-01-18  3:52 [PATCH v6 0/3] ucm: Automatically load the best config file based on the card long name mengdong.lin
2017-01-18  3:52 ` [PATCH v6 1/3] ucm: Assure the user input card name not to exceed max size of " mengdong.lin
2017-01-18  3:53 ` mengdong.lin [this message]
2017-01-18  3:53 ` [PATCH v6 3/3] ucm: Add command 'get _file' to get the config file name of the opened card mengdong.lin
2017-01-18 10:56 ` [PATCH v6 0/3] ucm: Automatically load the best config file based on the card long name Takashi Iwai

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=0901283dcf9b09233e32ef40f880bca92fa9aadf.1484710888.git.mengdong.lin@linux.intel.com \
    --to=mengdong.lin@linux.intel.com \
    --cc=alsa-devel@alsa-project.org \
    --cc=liam.r.girdwood@linux.intel.com \
    --cc=mengdong.lin@intel.com \
    --cc=tiwai@suse.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.