[RFC,2/3] ucm: Parse sequence of component devices
diff mbox

Message ID 9baaf7a3d55a86e417826715e8e63d1a76582156.1479195801.git.mengdong.lin@linux.intel.com
State New
Headers show

Commit Message

mengdong.lin@linux.intel.com Nov. 15, 2016, 8:02 a.m. UTC
From: Mengdong Lin <mengdong.lin@linux.intel.com>

A machine device's verb file (e.g.HiFi) can include configuration files
of component devices via alsaconf syntax <searchdir:xxx> and <file_name>.
Then the machine device's sequence can enable or disable a component
device by keyword 'enadev' and 'disdev' followed the name of the component
device.

UCM sequence parser will find the component device and mark if its enable
or disable sequence is needed by the parent, the machine device.

New element type and struct are defined for the sequence of a component
device. Component devices will be removed from the machine device list
'device_list' of a verb, since we don't want to expose them to audio
servers with original API to list devices for backward compatibility.
A new list 'cmpt_device_list' is used for the component devices of a verb.

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

Comments

Liam Girdwood Nov. 15, 2016, 8:45 a.m. UTC | #1
On Tue, 2016-11-15 at 16:02 +0800, mengdong.lin@linux.intel.com wrote:
> From: Mengdong Lin <mengdong.lin@linux.intel.com>
> 
> A machine device's verb file (e.g.HiFi) can include configuration files
> of component devices via alsaconf syntax <searchdir:xxx> and <file_name>.
> Then the machine device's sequence can enable or disable a component
> device by keyword 'enadev' and 'disdev' followed the name of the component
> device.
> 
> UCM sequence parser will find the component device and mark if its enable
> or disable sequence is needed by the parent, the machine device.
> 
> New element type and struct are defined for the sequence of a component
> device. Component devices will be removed from the machine device list
> 'device_list' of a verb, since we don't want to expose them to audio
> servers with original API to list devices for backward compatibility.
> A new list 'cmpt_device_list' is used for the component devices of a verb.
> 
> Signed-off-by: Mengdong Lin <mengdong.lin@linux.intel.com>
> 



> @@ -306,6 +381,30 @@ static int parse_sequence(snd_use_case_mgr_t *uc_mgr ATTRIBUTE_UNUSED,
>  			continue;
>  		}
>  
> +		if (strcmp(cmd, "enadev") == 0) {
> +			/* need to enable a component device */
> +			curr->type = SEQUENCE_ELEMENT_TYPE_CMPT_SEQ;
> +			err = parse_component_seq(uc_mgr, n, 1,
> +						&curr->data.cmpt_seq);
> +			if (err < 0) {
> +				uc_error("error: enadev requires a valid device!");
> +				return err;
> +			}
> +			continue;
> +		}
> +
> +		if (strcmp(cmd, "disdev") == 0) {

Do we need to document enadev and disdev anywhere ?

Liam
Lin, Mengdong Nov. 16, 2016, 7:16 a.m. UTC | #2
> -----Original Message-----
> From: Liam Girdwood [mailto:liam.r.girdwood@linux.intel.com]
> Sent: Tuesday, November 15, 2016 4:46 PM
 
> > @@ -306,6 +381,30 @@ static int parse_sequence(snd_use_case_mgr_t
> *uc_mgr ATTRIBUTE_UNUSED,
> >  			continue;
> >  		}
> >
> > +		if (strcmp(cmd, "enadev") == 0) {
> > +			/* need to enable a component device */
> > +			curr->type = SEQUENCE_ELEMENT_TYPE_CMPT_SEQ;
> > +			err = parse_component_seq(uc_mgr, n, 1,
> > +						&curr->data.cmpt_seq);
> > +			if (err < 0) {
> > +				uc_error("error: enadev requires a valid
> device!");
> > +				return err;
> > +			}
> > +			continue;
> > +		}
> > +
> > +		if (strcmp(cmd, "disdev") == 0) {
> 
> Do we need to document enadev and disdev anywhere ?
> 
> Liam

Maybe we could document this in the description of function parse_sequence() and parse_verb()?
parse_verb() has an example of EnableSequence and DisableSequence.

Thanks
Mengdong

Patch
diff mbox

diff --git a/src/ucm/parser.c b/src/ucm/parser.c
index 5fc98a1..fe1dfbc 100644
--- a/src/ucm/parser.c
+++ b/src/ucm/parser.c
@@ -235,6 +235,81 @@  static int parse_device_list(snd_use_case_mgr_t *uc_mgr ATTRIBUTE_UNUSED,
 	return 0;
 }
 
+/* find a component device by its name
+ *
+ * Component devices are defined by machine components (usually off-soc
+ * codes or DSP embeded in SoC). Since alsaconf imports their configuration
+ * files automatically, we don't know which devices are component devices
+ * until they are referenced by a machine device sequence. So here when we
+ * find a referenced device, we move it from the machine device list to the
+ * component device list. Component devices will not be exposed to applications
+ * by the original API to list devices for backward compatibility. So audio
+ * servers can only see the machine devices.
+ */
+struct use_case_device *find_component_dev(snd_use_case_mgr_t *uc_mgr,
+	const char *name)
+{
+	struct list_head *pos, *posdev, *_posdev;
+	struct use_case_verb *verb;
+	struct use_case_device *dev;
+
+	list_for_each(pos, &uc_mgr->verb_list) {
+		verb = list_entry(pos, struct use_case_verb, list);
+
+		/* search in the component device list */
+		list_for_each(posdev, &verb->cmpt_device_list) {
+			dev = list_entry(posdev, struct use_case_device, list);
+			if (!strcmp(dev->name, name))
+				return dev;
+		}
+
+		/* search the machine device list */
+		list_for_each_safe(posdev, _posdev, &verb->device_list) {
+			dev = list_entry(posdev, struct use_case_device, list);
+			if (!strcmp(dev->name, name)) {
+				/* find the component device, move it from the
+				 * machine device list to the component device
+				 * list.
+				 */
+				list_del(&dev->list);
+				list_add_tail(&dev->list,
+					      &verb->cmpt_device_list);
+				return dev;
+			}
+		}
+	}
+
+	return NULL;
+}
+
+/* parse sequence of a component device
+ *
+ * This function will find the component device and mark if its enable or
+ * disable sequence is needed by its parenet device.
+ */
+static int parse_component_seq(snd_use_case_mgr_t *uc_mgr,
+			  snd_config_t *n, int enable,
+			  struct component_sequence *cmpt_seq)
+{
+	const char *val;
+	int err;
+
+	err = snd_config_get_string(n, &val);
+	if (err < 0)
+		return err;
+
+	cmpt_seq->device = find_component_dev(uc_mgr, val);
+	if (!cmpt_seq->device) {
+		uc_error("error: Cannot find component device %s", val);
+		return -EINVAL;
+	}
+
+	/* Parent needs its enable or disable sequence */
+	cmpt_seq->enable = enable;
+
+	return 0;
+}
+
 /*
  * Parse sequences.
  *
@@ -249,7 +324,7 @@  static int parse_device_list(snd_use_case_mgr_t *uc_mgr ATTRIBUTE_UNUSED,
  *	cset "name='Master Playback Switch' 0,0"
  *      cset "iface=PCM,name='Disable HDMI',index=1 0"
  */
-static int parse_sequence(snd_use_case_mgr_t *uc_mgr ATTRIBUTE_UNUSED,
+static int parse_sequence(snd_use_case_mgr_t *uc_mgr,
 			  struct list_head *base,
 			  snd_config_t *cfg)
 {
@@ -306,6 +381,30 @@  static int parse_sequence(snd_use_case_mgr_t *uc_mgr ATTRIBUTE_UNUSED,
 			continue;
 		}
 
+		if (strcmp(cmd, "enadev") == 0) {
+			/* need to enable a component device */
+			curr->type = SEQUENCE_ELEMENT_TYPE_CMPT_SEQ;
+			err = parse_component_seq(uc_mgr, n, 1,
+						&curr->data.cmpt_seq);
+			if (err < 0) {
+				uc_error("error: enadev requires a valid device!");
+				return err;
+			}
+			continue;
+		}
+
+		if (strcmp(cmd, "disdev") == 0) {
+			/* need to disable a component device */
+			curr->type = SEQUENCE_ELEMENT_TYPE_CMPT_SEQ;
+			err = parse_component_seq(uc_mgr, n, 0,
+						&curr->data.cmpt_seq);
+			if (err < 0) {
+				uc_error("error: disdev requires a valid device!");
+				return err;
+			}
+			continue;
+		}
+
 		if (strcmp(cmd, "cset-bin-file") == 0) {
 			curr->type = SEQUENCE_ELEMENT_TYPE_CSET_BIN_FILE;
 			err = parse_string(n, &curr->data.cset);
@@ -938,6 +1037,7 @@  static int parse_verb_file(snd_use_case_mgr_t *uc_mgr,
 	INIT_LIST_HEAD(&verb->disable_list);
 	INIT_LIST_HEAD(&verb->transition_list);
 	INIT_LIST_HEAD(&verb->device_list);
+	INIT_LIST_HEAD(&verb->cmpt_device_list);
 	INIT_LIST_HEAD(&verb->modifier_list);
 	INIT_LIST_HEAD(&verb->value_list);
 	list_add_tail(&verb->list, &uc_mgr->verb_list);
diff --git a/src/ucm/ucm_local.h b/src/ucm/ucm_local.h
index b89de2a..3bfdd67 100644
--- a/src/ucm/ucm_local.h
+++ b/src/ucm/ucm_local.h
@@ -49,6 +49,7 @@ 
 #define SEQUENCE_ELEMENT_TYPE_EXEC	4
 #define SEQUENCE_ELEMENT_TYPE_CSET_BIN_FILE	5
 #define SEQUENCE_ELEMENT_TYPE_CSET_TLV	6
+#define SEQUENCE_ELEMENT_TYPE_CMPT_SEQ	7
 
 struct ucm_value {
         struct list_head list;
@@ -56,6 +57,12 @@  struct ucm_value {
         char *data;
 };
 
+/* sequence of a component device */
+struct component_sequence {
+	struct use_case_device *device; /* component device */
+	int enable; /* flag to choose enable or disable list of the device */
+};
+
 struct sequence_element {
 	struct list_head list;
 	unsigned int type;
@@ -64,6 +71,7 @@  struct sequence_element {
 		char *cdev;
 		char *cset;
 		char *exec;
+		struct component_sequence cmpt_seq; /* component sequence */
 	} data;
 };
 
@@ -167,6 +175,9 @@  struct use_case_verb {
 	/* hardware devices that can be used with this use case */
 	struct list_head device_list;
 
+	/* component device list */
+	struct list_head cmpt_device_list;
+
 	/* modifiers that can be used with this use case */
 	struct list_head modifier_list;
 
diff --git a/src/ucm/utils.c b/src/ucm/utils.c
index 45307b0..0fba85a 100644
--- a/src/ucm/utils.c
+++ b/src/ucm/utils.c
@@ -210,6 +210,7 @@  void uc_mgr_free_verb(snd_use_case_mgr_t *uc_mgr)
 		uc_mgr_free_transition(&verb->transition_list);
 		uc_mgr_free_value(&verb->value_list);
 		uc_mgr_free_device(&verb->device_list);
+		uc_mgr_free_device(&verb->cmpt_device_list);
 		uc_mgr_free_modifier(&verb->modifier_list);
 		list_del(&verb->list);
 		free(verb);