diff mbox

[-,UCM,1/1] ucm: add binary configure file parse

Message ID 1421652670-4989-1-git-send-email-han.lu@intel.com (mailing list archive)
State New, archived
Headers show

Commit Message

han.lu@intel.com Jan. 19, 2015, 7:31 a.m. UTC
From: "Lu, Han" <han.lu@intel.com>

with cset command, UCM set kcontrol parameters directly:
    cset "name='<KCONTROL_NAME>' 1<,2,3,...>"
This patch enables UCM to set kcontrol with parameters from
configure file:
    cset-bin-file "name='<KCONTROL_NAME>' <path/to/file>"
where "cset-bin-file" is a newly added keyword alongside of "cset",
to indicate cset with binary data in file.
The binary data in file is parameter for audio DSPs, and it's just
passed by UCM/ALSA as raw data. The data type of the parameter
element must be byte, and the count is limited by the size of
struct snd_ctl_elem_value and driver definition.

Signed-off-by: Lu, Han <han.lu@intel.com>

Comments

Takashi Iwai Jan. 19, 2015, 9:01 a.m. UTC | #1
At Mon, 19 Jan 2015 15:31:10 +0800,
han.lu@intel.com wrote:
> 
> From: "Lu, Han" <han.lu@intel.com>
> 
> with cset command, UCM set kcontrol parameters directly:
>     cset "name='<KCONTROL_NAME>' 1<,2,3,...>"
> This patch enables UCM to set kcontrol with parameters from
> configure file:
>     cset-bin-file "name='<KCONTROL_NAME>' <path/to/file>"
> where "cset-bin-file" is a newly added keyword alongside of "cset",
> to indicate cset with binary data in file.
> The binary data in file is parameter for audio DSPs, and it's just
> passed by UCM/ALSA as raw data. The data type of the parameter
> element must be byte, and the count is limited by the size of
> struct snd_ctl_elem_value and driver definition.
> 
> Signed-off-by: Lu, Han <han.lu@intel.com>

The patch looks now much better, but...

> 
> diff --git a/src/ucm/main.c b/src/ucm/main.c
> index 37ae4c8..a1b1fb6 100644
> --- a/src/ucm/main.c
> +++ b/src/ucm/main.c
> @@ -160,11 +160,57 @@ static int open_ctl(snd_use_case_mgr_t *uc_mgr,
>  	return 0;
>  }
>  
> +static int binary_file_parse(snd_ctl_elem_value_t *dst,
> +			      snd_ctl_elem_info_t *info,
> +			      const char *filepath)
> +{
> +	int err, fd;
> +	struct stat st;
> +	size_t sz;
> +	char *res;
> +	snd_ctl_elem_type_t type;
> +	unsigned int idx, count;
> +
> +	type = snd_ctl_elem_info_get_type(info);
> +	if (type != SND_CTL_ELEM_TYPE_BYTES) {
> +		uc_error("only support byte type!");
> +		err = -EINVAL;
> +		return err;
> +	}
> +	fd = open(filepath, O_RDONLY);
> +	if (fd < 0) {
> +		err = -errno;
> +		return err;
> +	}
> +	if (stat(filepath, &st) == -1) {
> +		err = -errno;
> +		goto __fail;
> +	}
> +	sz = st.st_size;
> +	if (sz > sizeof(dst->value.bytes))
> +		sz = sizeof(dst->value.bytes);
> +	count = snd_ctl_elem_info_get_count(info);
> +	if (sz > count)
> +		sz = count;

Actually you have here both the expected data size and the actual data
size.  If the actual data size doesn't match with the expected size,
it means rather an error.  (Imagine to read an empty file, for
example.)  So, better to return an error instead of silently
truncating.

> +	res = calloc(sz, 1);
> +	if (res == NULL) {
> +		err = -ENOMEM;
> +		goto __fail;
> +	}
> +	read(fd, res, sz);

Don't forget to check the return value from read().

Also, I'd like to have an ack from Liam, at least, for UCM stuff, so
please add him to Cc (or put his ack tag if you already got it).


thanks,

Takashi

> +	for (idx = 0; idx < sz; idx++)
> +		snd_ctl_elem_value_set_byte(dst, idx, *(res + idx));
> +	free(res);
> +      __fail:
> +	close(fd);
> +	return err;
> +}
> +
>  extern int __snd_ctl_ascii_elem_id_parse(snd_ctl_elem_id_t *dst,
>  					 const char *str,
>  					 const char **ret_ptr);
>  
> -static int execute_cset(snd_ctl_t *ctl, const char *cset)
> +static int execute_cset(snd_ctl_t *ctl, const char *cset, unsigned int type)
>  {
>  	const char *pos;
>  	int err;
> @@ -194,7 +240,10 @@ static int execute_cset(snd_ctl_t *ctl, const char *cset)
>  	err = snd_ctl_elem_info(ctl, info);
>  	if (err < 0)
>  		goto __fail;
> -	err = snd_ctl_ascii_value_parse(ctl, value, info, pos);
> +	if (type == SEQUENCE_ELEMENT_TYPE_CSET_BIN_FILE)
> +		err = binary_file_parse(value, info, pos);
> +	else
> +		err = snd_ctl_ascii_value_parse(ctl, value, info, pos);
>  	if (err < 0)
>  		goto __fail;
>  	err = snd_ctl_elem_write(ctl, value);
> @@ -239,6 +288,7 @@ static int execute_sequence(snd_use_case_mgr_t *uc_mgr,
>  				goto __fail_nomem;
>  			break;
>  		case SEQUENCE_ELEMENT_TYPE_CSET:
> +		case SEQUENCE_ELEMENT_TYPE_CSET_BIN_FILE:
>  			if (cdev == NULL) {
>  				const char *cdev1 = NULL, *cdev2 = NULL;
>  				err = get_value3(&cdev1, "PlaybackCTL",
> @@ -274,7 +324,7 @@ static int execute_sequence(snd_use_case_mgr_t *uc_mgr,
>  					goto __fail;
>  				}
>  			}
> -			err = execute_cset(ctl, s->data.cset);
> +			err = execute_cset(ctl, s->data.cset, s->type);
>  			if (err < 0) {
>  				uc_error("unable to execute cset '%s'\n", s->data.cset);
>  				goto __fail;
> diff --git a/src/ucm/parser.c b/src/ucm/parser.c
> index d7517f6..9e1cb41 100644
> --- a/src/ucm/parser.c
> +++ b/src/ucm/parser.c
> @@ -306,6 +306,16 @@ static int parse_sequence(snd_use_case_mgr_t *uc_mgr ATTRIBUTE_UNUSED,
>  			continue;
>  		}
>  
> +		if (strcmp(cmd, "cset-bin-file") == 0) {
> +			curr->type = SEQUENCE_ELEMENT_TYPE_CSET_BIN_FILE;
> +			err = parse_string(n, &curr->data.cset);
> +			if (err < 0) {
> +				uc_error("error: cset-bin-file requires a string!");
> +				return err;
> +			}
> +			continue;
> +		}
> +
>  		if (strcmp(cmd, "usleep") == 0) {
>  			curr->type = SEQUENCE_ELEMENT_TYPE_SLEEP;
>  			err = snd_config_get_integer(n, &curr->data.sleep);
> diff --git a/src/ucm/ucm_local.h b/src/ucm/ucm_local.h
> index 87f14a2..c1655c7 100644
> --- a/src/ucm/ucm_local.h
> +++ b/src/ucm/ucm_local.h
> @@ -47,6 +47,7 @@
>  #define SEQUENCE_ELEMENT_TYPE_CSET	2
>  #define SEQUENCE_ELEMENT_TYPE_SLEEP	3
>  #define SEQUENCE_ELEMENT_TYPE_EXEC	4
> +#define SEQUENCE_ELEMENT_TYPE_CSET_BIN_FILE	5
>  
>  struct ucm_value {
>          struct list_head list;
> -- 
> 2.1.0
>
diff mbox

Patch

diff --git a/src/ucm/main.c b/src/ucm/main.c
index 37ae4c8..a1b1fb6 100644
--- a/src/ucm/main.c
+++ b/src/ucm/main.c
@@ -160,11 +160,57 @@  static int open_ctl(snd_use_case_mgr_t *uc_mgr,
 	return 0;
 }
 
+static int binary_file_parse(snd_ctl_elem_value_t *dst,
+			      snd_ctl_elem_info_t *info,
+			      const char *filepath)
+{
+	int err, fd;
+	struct stat st;
+	size_t sz;
+	char *res;
+	snd_ctl_elem_type_t type;
+	unsigned int idx, count;
+
+	type = snd_ctl_elem_info_get_type(info);
+	if (type != SND_CTL_ELEM_TYPE_BYTES) {
+		uc_error("only support byte type!");
+		err = -EINVAL;
+		return err;
+	}
+	fd = open(filepath, O_RDONLY);
+	if (fd < 0) {
+		err = -errno;
+		return err;
+	}
+	if (stat(filepath, &st) == -1) {
+		err = -errno;
+		goto __fail;
+	}
+	sz = st.st_size;
+	if (sz > sizeof(dst->value.bytes))
+		sz = sizeof(dst->value.bytes);
+	count = snd_ctl_elem_info_get_count(info);
+	if (sz > count)
+		sz = count;
+	res = calloc(sz, 1);
+	if (res == NULL) {
+		err = -ENOMEM;
+		goto __fail;
+	}
+	read(fd, res, sz);
+	for (idx = 0; idx < sz; idx++)
+		snd_ctl_elem_value_set_byte(dst, idx, *(res + idx));
+	free(res);
+      __fail:
+	close(fd);
+	return err;
+}
+
 extern int __snd_ctl_ascii_elem_id_parse(snd_ctl_elem_id_t *dst,
 					 const char *str,
 					 const char **ret_ptr);
 
-static int execute_cset(snd_ctl_t *ctl, const char *cset)
+static int execute_cset(snd_ctl_t *ctl, const char *cset, unsigned int type)
 {
 	const char *pos;
 	int err;
@@ -194,7 +240,10 @@  static int execute_cset(snd_ctl_t *ctl, const char *cset)
 	err = snd_ctl_elem_info(ctl, info);
 	if (err < 0)
 		goto __fail;
-	err = snd_ctl_ascii_value_parse(ctl, value, info, pos);
+	if (type == SEQUENCE_ELEMENT_TYPE_CSET_BIN_FILE)
+		err = binary_file_parse(value, info, pos);
+	else
+		err = snd_ctl_ascii_value_parse(ctl, value, info, pos);
 	if (err < 0)
 		goto __fail;
 	err = snd_ctl_elem_write(ctl, value);
@@ -239,6 +288,7 @@  static int execute_sequence(snd_use_case_mgr_t *uc_mgr,
 				goto __fail_nomem;
 			break;
 		case SEQUENCE_ELEMENT_TYPE_CSET:
+		case SEQUENCE_ELEMENT_TYPE_CSET_BIN_FILE:
 			if (cdev == NULL) {
 				const char *cdev1 = NULL, *cdev2 = NULL;
 				err = get_value3(&cdev1, "PlaybackCTL",
@@ -274,7 +324,7 @@  static int execute_sequence(snd_use_case_mgr_t *uc_mgr,
 					goto __fail;
 				}
 			}
-			err = execute_cset(ctl, s->data.cset);
+			err = execute_cset(ctl, s->data.cset, s->type);
 			if (err < 0) {
 				uc_error("unable to execute cset '%s'\n", s->data.cset);
 				goto __fail;
diff --git a/src/ucm/parser.c b/src/ucm/parser.c
index d7517f6..9e1cb41 100644
--- a/src/ucm/parser.c
+++ b/src/ucm/parser.c
@@ -306,6 +306,16 @@  static int parse_sequence(snd_use_case_mgr_t *uc_mgr ATTRIBUTE_UNUSED,
 			continue;
 		}
 
+		if (strcmp(cmd, "cset-bin-file") == 0) {
+			curr->type = SEQUENCE_ELEMENT_TYPE_CSET_BIN_FILE;
+			err = parse_string(n, &curr->data.cset);
+			if (err < 0) {
+				uc_error("error: cset-bin-file requires a string!");
+				return err;
+			}
+			continue;
+		}
+
 		if (strcmp(cmd, "usleep") == 0) {
 			curr->type = SEQUENCE_ELEMENT_TYPE_SLEEP;
 			err = snd_config_get_integer(n, &curr->data.sleep);
diff --git a/src/ucm/ucm_local.h b/src/ucm/ucm_local.h
index 87f14a2..c1655c7 100644
--- a/src/ucm/ucm_local.h
+++ b/src/ucm/ucm_local.h
@@ -47,6 +47,7 @@ 
 #define SEQUENCE_ELEMENT_TYPE_CSET	2
 #define SEQUENCE_ELEMENT_TYPE_SLEEP	3
 #define SEQUENCE_ELEMENT_TYPE_EXEC	4
+#define SEQUENCE_ELEMENT_TYPE_CSET_BIN_FILE	5
 
 struct ucm_value {
         struct list_head list;