From 1c6fb20232f790e9a71e818363a925a5c501acbf Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Fri, 5 Mar 2021 19:55:06 +0100 Subject: [PATCH] ucm: implement sysset sequence command Signed-off-by: Jaroslav Kysela --- src/ucm/main.c | 72 +++++++++++++++++++++++++++++++++++++++++++++++++++++ src/ucm/parser.c | 10 ++++++++ src/ucm/ucm_local.h | 15 ++++++----- src/ucm/ucm_subs.c | 6 ++--- src/ucm/utils.c | 13 ++++++++++ 5 files changed, 107 insertions(+), 9 deletions(-) diff --git a/src/ucm/main.c b/src/ucm/main.c index f9f78e02..e2a268d3 100644 --- a/src/ucm/main.c +++ b/src/ucm/main.c @@ -31,6 +31,7 @@ */ #include "ucm_local.h" +#include #include #include #include @@ -323,6 +324,72 @@ static int execute_cset(snd_ctl_t *ctl, const char *cset, unsigned int type) return err; } +static int execute_sysset(const char *sysset) +{ + char path[PATH_MAX]; + const char *e; + char *s, *value; + ssize_t wlen; + size_t len; + int fd, myerrno; + bool ignore_error = false; + + if (sysset == NULL || *sysset == '\0') + return 0; + + ignore_error = sysset[0] == '-'; + + if (sysset[0] == ':') + return -EINVAL; + + s = strdup(sysset[0] != '/' ? sysset : sysset + 1); + if (s == NULL) + return -ENOMEM; + + value = strchr(s, ':'); + if (!value) { + free(s); + return -EINVAL; + } + *value = '\0'; + value++; + len = strlen(value); + if (len < 1) { + free(s); + return -EINVAL; + } + + e = uc_mgr_sysfs_root(); + if (e == NULL) { + free(s); + return -EINVAL; + } + snprintf(path, sizeof(path), "%s/%s", e, s); + + fd = open(path, O_WRONLY|O_CLOEXEC); + if (fd < 0) { + free(s); + if (ignore_error) + return 0; + uc_error("unable to open '%s' for write", path); + return -EINVAL; + } + wlen = write(fd, value, len); + myerrno = errno; + close(fd); + free(s); + + if (ignore_error) + return 0; + + if (wlen != (ssize_t)len) { + uc_error("unable to write '%s' to '%s': %s", value, path, strerror(myerrno)); + return -EINVAL; + } + + return 0; +} + /** * \brief Execute the sequence * \param uc_mgr Use case manager @@ -420,6 +487,11 @@ static int execute_sequence(snd_use_case_mgr_t *uc_mgr, goto __fail; } break; + case SEQUENCE_ELEMENT_TYPE_SYSSET: + err = execute_sysset(s->data.sysset); + if (err < 0) + goto __fail; + break; case SEQUENCE_ELEMENT_TYPE_SLEEP: usleep(s->data.sleep); break; diff --git a/src/ucm/parser.c b/src/ucm/parser.c index 55781f87..e1ff1c18 100644 --- a/src/ucm/parser.c +++ b/src/ucm/parser.c @@ -772,6 +772,16 @@ static int parse_sequence(snd_use_case_mgr_t *uc_mgr, continue; } + if (strcmp(cmd, "sysset") == 0) { + curr->type = SEQUENCE_ELEMENT_TYPE_SYSSET; + err = parse_string_substitute3(uc_mgr, n, &curr->data.sysset); + if (err < 0) { + uc_error("error: sysset requires a string!"); + return err; + } + continue; + } + if (strcmp(cmd, "usleep") == 0) { curr->type = SEQUENCE_ELEMENT_TYPE_SLEEP; err = parse_integer_substitute3(uc_mgr, n, &curr->data.sleep); diff --git a/src/ucm/ucm_local.h b/src/ucm/ucm_local.h index c3e5a079..94749502 100644 --- a/src/ucm/ucm_local.h +++ b/src/ucm/ucm_local.h @@ -45,13 +45,14 @@ #define MAX_CARD_SHORT_NAME 32 #define MAX_CARD_LONG_NAME 80 -#define SEQUENCE_ELEMENT_TYPE_CDEV 1 -#define SEQUENCE_ELEMENT_TYPE_CSET 2 -#define SEQUENCE_ELEMENT_TYPE_SLEEP 3 -#define SEQUENCE_ELEMENT_TYPE_EXEC 4 +#define SEQUENCE_ELEMENT_TYPE_CDEV 1 +#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 -#define SEQUENCE_ELEMENT_TYPE_CSET_TLV 6 -#define SEQUENCE_ELEMENT_TYPE_CMPT_SEQ 7 +#define SEQUENCE_ELEMENT_TYPE_CSET_TLV 6 +#define SEQUENCE_ELEMENT_TYPE_CMPT_SEQ 7 +#define SEQUENCE_ELEMENT_TYPE_SYSSET 8 struct ucm_value { struct list_head list; @@ -73,6 +74,7 @@ struct sequence_element { char *cdev; char *cset; char *exec; + char *sysset; struct component_sequence cmpt_seq; /* component sequence */ } data; }; @@ -269,6 +271,7 @@ struct snd_use_case_mgr { void uc_mgr_error(const char *fmt, ...); void uc_mgr_stdout(const char *fmt, ...); +const char *uc_mgr_sysfs_root(void); const char *uc_mgr_config_dir(int format); int uc_mgr_config_load(int format, const char *file, snd_config_t **cfg); int uc_mgr_config_load_file(snd_use_case_mgr_t *uc_mgr, const char *file, snd_config_t **cfg); diff --git a/src/ucm/ucm_subs.c b/src/ucm/ucm_subs.c index 7e745bca..08de526c 100644 --- a/src/ucm/ucm_subs.c +++ b/src/ucm/ucm_subs.c @@ -508,12 +508,12 @@ static char *rval_sysfs(snd_use_case_mgr_t *uc_mgr ATTRIBUTE_UNUSED, const char char path[PATH_MAX], link[PATH_MAX + 1]; struct stat sb; ssize_t len; - char *e; + const char *e; int fd; - e = getenv("SYSFS_PATH"); + e = uc_mgr_sysfs_root(); if (e == NULL) - e = "/sys"; + return NULL; if (id[0] == '/') id++; snprintf(path, sizeof(path), "%s/%s", e, id); diff --git a/src/ucm/utils.c b/src/ucm/utils.c index 24d06310..e5fbb428 100644 --- a/src/ucm/utils.c +++ b/src/ucm/utils.c @@ -49,6 +49,16 @@ void uc_mgr_stdout(const char *fmt,...) va_end(va); } +const char *uc_mgr_sysfs_root(void) +{ + const char *e = getenv("SYSFS_PATH"); + if (e == NULL) + return "/sys"; + if (*e == '\0') + uc_error("no sysfs root!"); + return e; +} + struct ctl_list *uc_mgr_get_master_ctl(snd_use_case_mgr_t *uc_mgr) { struct list_head *pos; @@ -479,6 +489,9 @@ void uc_mgr_free_sequence_element(struct sequence_element *seq) case SEQUENCE_ELEMENT_TYPE_CSET_TLV: free(seq->data.cset); break; + case SEQUENCE_ELEMENT_TYPE_SYSSET: + free(seq->data.sysset); + break; case SEQUENCE_ELEMENT_TYPE_EXEC: free(seq->data.exec); break; -- 2.11.0