ucm: implement sysset sequence command

Signed-off-by: Jaroslav Kysela <perex@perex.cz>
This commit is contained in:
Jaroslav Kysela 2021-03-05 19:55:06 +01:00
parent 2b418648cf
commit 1c6fb20232
5 changed files with 107 additions and 9 deletions

View file

@ -31,6 +31,7 @@
*/
#include "ucm_local.h"
#include <stdbool.h>
#include <ctype.h>
#include <stdarg.h>
#include <pthread.h>
@ -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;

View file

@ -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);

View file

@ -52,6 +52,7 @@
#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_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);

View file

@ -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);

View file

@ -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;