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 "ucm_local.h"
#include <stdbool.h>
#include <ctype.h> #include <ctype.h>
#include <stdarg.h> #include <stdarg.h>
#include <pthread.h> #include <pthread.h>
@ -323,6 +324,72 @@ static int execute_cset(snd_ctl_t *ctl, const char *cset, unsigned int type)
return err; 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 * \brief Execute the sequence
* \param uc_mgr Use case manager * \param uc_mgr Use case manager
@ -420,6 +487,11 @@ static int execute_sequence(snd_use_case_mgr_t *uc_mgr,
goto __fail; goto __fail;
} }
break; break;
case SEQUENCE_ELEMENT_TYPE_SYSSET:
err = execute_sysset(s->data.sysset);
if (err < 0)
goto __fail;
break;
case SEQUENCE_ELEMENT_TYPE_SLEEP: case SEQUENCE_ELEMENT_TYPE_SLEEP:
usleep(s->data.sleep); usleep(s->data.sleep);
break; break;

View file

@ -772,6 +772,16 @@ static int parse_sequence(snd_use_case_mgr_t *uc_mgr,
continue; 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) { if (strcmp(cmd, "usleep") == 0) {
curr->type = SEQUENCE_ELEMENT_TYPE_SLEEP; curr->type = SEQUENCE_ELEMENT_TYPE_SLEEP;
err = parse_integer_substitute3(uc_mgr, n, &curr->data.sleep); err = parse_integer_substitute3(uc_mgr, n, &curr->data.sleep);

View file

@ -45,13 +45,14 @@
#define MAX_CARD_SHORT_NAME 32 #define MAX_CARD_SHORT_NAME 32
#define MAX_CARD_LONG_NAME 80 #define MAX_CARD_LONG_NAME 80
#define SEQUENCE_ELEMENT_TYPE_CDEV 1 #define SEQUENCE_ELEMENT_TYPE_CDEV 1
#define SEQUENCE_ELEMENT_TYPE_CSET 2 #define SEQUENCE_ELEMENT_TYPE_CSET 2
#define SEQUENCE_ELEMENT_TYPE_SLEEP 3 #define SEQUENCE_ELEMENT_TYPE_SLEEP 3
#define SEQUENCE_ELEMENT_TYPE_EXEC 4 #define SEQUENCE_ELEMENT_TYPE_EXEC 4
#define SEQUENCE_ELEMENT_TYPE_CSET_BIN_FILE 5 #define SEQUENCE_ELEMENT_TYPE_CSET_BIN_FILE 5
#define SEQUENCE_ELEMENT_TYPE_CSET_TLV 6 #define SEQUENCE_ELEMENT_TYPE_CSET_TLV 6
#define SEQUENCE_ELEMENT_TYPE_CMPT_SEQ 7 #define SEQUENCE_ELEMENT_TYPE_CMPT_SEQ 7
#define SEQUENCE_ELEMENT_TYPE_SYSSET 8
struct ucm_value { struct ucm_value {
struct list_head list; struct list_head list;
@ -73,6 +74,7 @@ struct sequence_element {
char *cdev; char *cdev;
char *cset; char *cset;
char *exec; char *exec;
char *sysset;
struct component_sequence cmpt_seq; /* component sequence */ struct component_sequence cmpt_seq; /* component sequence */
} data; } data;
}; };
@ -269,6 +271,7 @@ struct snd_use_case_mgr {
void uc_mgr_error(const char *fmt, ...); void uc_mgr_error(const char *fmt, ...);
void uc_mgr_stdout(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); 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(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); 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]; char path[PATH_MAX], link[PATH_MAX + 1];
struct stat sb; struct stat sb;
ssize_t len; ssize_t len;
char *e; const char *e;
int fd; int fd;
e = getenv("SYSFS_PATH"); e = uc_mgr_sysfs_root();
if (e == NULL) if (e == NULL)
e = "/sys"; return NULL;
if (id[0] == '/') if (id[0] == '/')
id++; id++;
snprintf(path, sizeof(path), "%s/%s", e, 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); 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 ctl_list *uc_mgr_get_master_ctl(snd_use_case_mgr_t *uc_mgr)
{ {
struct list_head *pos; struct list_head *pos;
@ -479,6 +489,9 @@ void uc_mgr_free_sequence_element(struct sequence_element *seq)
case SEQUENCE_ELEMENT_TYPE_CSET_TLV: case SEQUENCE_ELEMENT_TYPE_CSET_TLV:
free(seq->data.cset); free(seq->data.cset);
break; break;
case SEQUENCE_ELEMENT_TYPE_SYSSET:
free(seq->data.sysset);
break;
case SEQUENCE_ELEMENT_TYPE_EXEC: case SEQUENCE_ELEMENT_TYPE_EXEC:
free(seq->data.exec); free(seq->data.exec);
break; break;