mirror of
https://github.com/alsa-project/alsa-lib.git
synced 2025-11-02 09:01:48 -05:00
ucm: implement enadev2 and disdev2 sequence commands
It may be useful to call the sequences from devices from the verb sequences or another device sequences. Signed-off-by: Jaroslav Kysela <perex@perex.cz>
This commit is contained in:
parent
c3a5d32ac3
commit
4b66e5fbce
5 changed files with 90 additions and 22 deletions
|
|
@ -59,6 +59,13 @@ static int get_value3(snd_use_case_mgr_t *uc_mgr,
|
||||||
struct list_head *value_list2,
|
struct list_head *value_list2,
|
||||||
struct list_head *value_list3);
|
struct list_head *value_list3);
|
||||||
|
|
||||||
|
static int execute_sequence(snd_use_case_mgr_t *uc_mgr,
|
||||||
|
struct use_case_verb *verb,
|
||||||
|
struct list_head *seq,
|
||||||
|
struct list_head *value_list1,
|
||||||
|
struct list_head *value_list2,
|
||||||
|
struct list_head *value_list3);
|
||||||
|
|
||||||
static int execute_component_seq(snd_use_case_mgr_t *uc_mgr,
|
static int execute_component_seq(snd_use_case_mgr_t *uc_mgr,
|
||||||
struct component_sequence *cmpt_seq,
|
struct component_sequence *cmpt_seq,
|
||||||
struct list_head *value_list1,
|
struct list_head *value_list1,
|
||||||
|
|
@ -66,6 +73,10 @@ static int execute_component_seq(snd_use_case_mgr_t *uc_mgr,
|
||||||
struct list_head *value_list3,
|
struct list_head *value_list3,
|
||||||
char *cdev);
|
char *cdev);
|
||||||
|
|
||||||
|
static inline struct use_case_device *
|
||||||
|
find_device(snd_use_case_mgr_t *uc_mgr, struct use_case_verb *verb,
|
||||||
|
const char *device_name, int check_supported);
|
||||||
|
|
||||||
static int check_identifier(const char *identifier, const char *prefix)
|
static int check_identifier(const char *identifier, const char *prefix)
|
||||||
{
|
{
|
||||||
int len;
|
int len;
|
||||||
|
|
@ -660,6 +671,29 @@ static int rewrite_device_value(snd_use_case_mgr_t *uc_mgr, const char *name, ch
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int run_device_sequence(snd_use_case_mgr_t *uc_mgr, struct use_case_verb *verb,
|
||||||
|
const char *name, bool enable)
|
||||||
|
{
|
||||||
|
struct use_case_device *device;
|
||||||
|
|
||||||
|
if (verb == NULL) {
|
||||||
|
uc_error("error: enadev2 / disdev2 must be executed inside the verb context");
|
||||||
|
return -ENOENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
device = find_device(uc_mgr, verb, name, 0);
|
||||||
|
if (device == NULL) {
|
||||||
|
uc_error("error: unable to find device '%s'\n", name);
|
||||||
|
return -ENOENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
return execute_sequence(uc_mgr, verb,
|
||||||
|
enable ? &device->enable_list : &device->disable_list,
|
||||||
|
&device->value_list,
|
||||||
|
&verb->value_list,
|
||||||
|
&uc_mgr->value_list);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Execute the sequence
|
* \brief Execute the sequence
|
||||||
* \param uc_mgr Use case manager
|
* \param uc_mgr Use case manager
|
||||||
|
|
@ -667,6 +701,7 @@ static int rewrite_device_value(snd_use_case_mgr_t *uc_mgr, const char *name, ch
|
||||||
* \return zero on success, otherwise a negative error code
|
* \return zero on success, otherwise a negative error code
|
||||||
*/
|
*/
|
||||||
static int execute_sequence(snd_use_case_mgr_t *uc_mgr,
|
static int execute_sequence(snd_use_case_mgr_t *uc_mgr,
|
||||||
|
struct use_case_verb *verb,
|
||||||
struct list_head *seq,
|
struct list_head *seq,
|
||||||
struct list_head *value_list1,
|
struct list_head *value_list1,
|
||||||
struct list_head *value_list2,
|
struct list_head *value_list2,
|
||||||
|
|
@ -680,6 +715,11 @@ static int execute_sequence(snd_use_case_mgr_t *uc_mgr,
|
||||||
bool ignore_error;
|
bool ignore_error;
|
||||||
int err = 0;
|
int err = 0;
|
||||||
|
|
||||||
|
if (uc_mgr->sequence_hops > 100) {
|
||||||
|
uc_error("error: too many inner sequences!");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
uc_mgr->sequence_hops++;
|
||||||
list_for_each(pos, seq) {
|
list_for_each(pos, seq) {
|
||||||
s = list_entry(pos, struct sequence_element, list);
|
s = list_entry(pos, struct sequence_element, list);
|
||||||
switch (s->type) {
|
switch (s->type) {
|
||||||
|
|
@ -819,17 +859,26 @@ shell_retry:
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
goto __fail;
|
goto __fail;
|
||||||
break;
|
break;
|
||||||
|
case SEQUENCE_ELEMENT_TYPE_DEV_ENABLE_SEQ:
|
||||||
|
case SEQUENCE_ELEMENT_TYPE_DEV_DISABLE_SEQ:
|
||||||
|
err = run_device_sequence(uc_mgr, verb, s->data.device,
|
||||||
|
s->type == SEQUENCE_ELEMENT_TYPE_DEV_ENABLE_SEQ);
|
||||||
|
if (err < 0)
|
||||||
|
goto __fail;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
uc_error("unknown sequence command %i", s->type);
|
uc_error("unknown sequence command %i", s->type);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
free(cdev);
|
free(cdev);
|
||||||
|
uc_mgr->sequence_hops--;
|
||||||
return 0;
|
return 0;
|
||||||
__fail_nomem:
|
__fail_nomem:
|
||||||
err = -ENOMEM;
|
err = -ENOMEM;
|
||||||
__fail:
|
__fail:
|
||||||
free(cdev);
|
free(cdev);
|
||||||
|
uc_mgr->sequence_hops--;
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -865,7 +914,7 @@ static int execute_component_seq(snd_use_case_mgr_t *uc_mgr,
|
||||||
seq = &device->disable_list;
|
seq = &device->disable_list;
|
||||||
|
|
||||||
/* excecute the sequence of the component dev */
|
/* excecute the sequence of the component dev */
|
||||||
err = execute_sequence(uc_mgr, seq,
|
err = execute_sequence(uc_mgr, uc_mgr->active_verb, seq,
|
||||||
&device->value_list,
|
&device->value_list,
|
||||||
&uc_mgr->active_verb->value_list,
|
&uc_mgr->active_verb->value_list,
|
||||||
&uc_mgr->value_list);
|
&uc_mgr->value_list);
|
||||||
|
|
@ -927,7 +976,7 @@ static int set_defaults(snd_use_case_mgr_t *uc_mgr)
|
||||||
|
|
||||||
if (uc_mgr->default_list_executed)
|
if (uc_mgr->default_list_executed)
|
||||||
return 0;
|
return 0;
|
||||||
err = execute_sequence(uc_mgr, &uc_mgr->default_list,
|
err = execute_sequence(uc_mgr, NULL, &uc_mgr->default_list,
|
||||||
&uc_mgr->value_list, NULL, NULL);
|
&uc_mgr->value_list, NULL, NULL);
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
uc_error("Unable to execute default sequence");
|
uc_error("Unable to execute default sequence");
|
||||||
|
|
@ -1279,7 +1328,7 @@ static int set_verb(snd_use_case_mgr_t *uc_mgr,
|
||||||
} else {
|
} else {
|
||||||
seq = &verb->disable_list;
|
seq = &verb->disable_list;
|
||||||
}
|
}
|
||||||
err = execute_sequence(uc_mgr, seq,
|
err = execute_sequence(uc_mgr, verb, seq,
|
||||||
&verb->value_list,
|
&verb->value_list,
|
||||||
&uc_mgr->value_list,
|
&uc_mgr->value_list,
|
||||||
NULL);
|
NULL);
|
||||||
|
|
@ -1310,7 +1359,7 @@ static int set_modifier(snd_use_case_mgr_t *uc_mgr,
|
||||||
} else {
|
} else {
|
||||||
seq = &modifier->disable_list;
|
seq = &modifier->disable_list;
|
||||||
}
|
}
|
||||||
err = execute_sequence(uc_mgr, seq,
|
err = execute_sequence(uc_mgr, uc_mgr->active_verb, seq,
|
||||||
&modifier->value_list,
|
&modifier->value_list,
|
||||||
&uc_mgr->active_verb->value_list,
|
&uc_mgr->active_verb->value_list,
|
||||||
&uc_mgr->value_list);
|
&uc_mgr->value_list);
|
||||||
|
|
@ -1344,7 +1393,7 @@ static int set_device(snd_use_case_mgr_t *uc_mgr,
|
||||||
} else {
|
} else {
|
||||||
seq = &device->disable_list;
|
seq = &device->disable_list;
|
||||||
}
|
}
|
||||||
err = execute_sequence(uc_mgr, seq,
|
err = execute_sequence(uc_mgr, uc_mgr->active_verb, seq,
|
||||||
&device->value_list,
|
&device->value_list,
|
||||||
&uc_mgr->active_verb->value_list,
|
&uc_mgr->active_verb->value_list,
|
||||||
&uc_mgr->value_list);
|
&uc_mgr->value_list);
|
||||||
|
|
@ -1562,7 +1611,7 @@ static int dismantle_use_case(snd_use_case_mgr_t *uc_mgr)
|
||||||
}
|
}
|
||||||
uc_mgr->active_verb = NULL;
|
uc_mgr->active_verb = NULL;
|
||||||
|
|
||||||
err = execute_sequence(uc_mgr, &uc_mgr->default_list,
|
err = execute_sequence(uc_mgr, NULL, &uc_mgr->default_list,
|
||||||
&uc_mgr->value_list, NULL, NULL);
|
&uc_mgr->value_list, NULL, NULL);
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
|
|
@ -1578,7 +1627,7 @@ int snd_use_case_mgr_reset(snd_use_case_mgr_t *uc_mgr)
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
pthread_mutex_lock(&uc_mgr->mutex);
|
pthread_mutex_lock(&uc_mgr->mutex);
|
||||||
err = execute_sequence(uc_mgr, &uc_mgr->default_list,
|
err = execute_sequence(uc_mgr, NULL, &uc_mgr->default_list,
|
||||||
&uc_mgr->value_list, NULL, NULL);
|
&uc_mgr->value_list, NULL, NULL);
|
||||||
INIT_LIST_HEAD(&uc_mgr->active_modifiers);
|
INIT_LIST_HEAD(&uc_mgr->active_modifiers);
|
||||||
INIT_LIST_HEAD(&uc_mgr->active_devices);
|
INIT_LIST_HEAD(&uc_mgr->active_devices);
|
||||||
|
|
@ -2405,7 +2454,7 @@ static int set_fixedboot_user(snd_use_case_mgr_t *uc_mgr,
|
||||||
}
|
}
|
||||||
if (list_empty(&uc_mgr->fixedboot_list))
|
if (list_empty(&uc_mgr->fixedboot_list))
|
||||||
return -ENOENT;
|
return -ENOENT;
|
||||||
err = execute_sequence(uc_mgr, &uc_mgr->fixedboot_list,
|
err = execute_sequence(uc_mgr, NULL, &uc_mgr->fixedboot_list,
|
||||||
&uc_mgr->value_list, NULL, NULL);
|
&uc_mgr->value_list, NULL, NULL);
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
uc_error("Unable to execute force boot sequence");
|
uc_error("Unable to execute force boot sequence");
|
||||||
|
|
@ -2425,7 +2474,7 @@ static int set_boot_user(snd_use_case_mgr_t *uc_mgr,
|
||||||
}
|
}
|
||||||
if (list_empty(&uc_mgr->boot_list))
|
if (list_empty(&uc_mgr->boot_list))
|
||||||
return -ENOENT;
|
return -ENOENT;
|
||||||
err = execute_sequence(uc_mgr, &uc_mgr->boot_list,
|
err = execute_sequence(uc_mgr, NULL, &uc_mgr->boot_list,
|
||||||
&uc_mgr->value_list, NULL, NULL);
|
&uc_mgr->value_list, NULL, NULL);
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
uc_error("Unable to execute boot sequence");
|
uc_error("Unable to execute boot sequence");
|
||||||
|
|
@ -2454,7 +2503,8 @@ static int handle_transition_verb(snd_use_case_mgr_t *uc_mgr,
|
||||||
list_for_each(pos, &uc_mgr->active_verb->transition_list) {
|
list_for_each(pos, &uc_mgr->active_verb->transition_list) {
|
||||||
trans = list_entry(pos, struct transition_sequence, list);
|
trans = list_entry(pos, struct transition_sequence, list);
|
||||||
if (strcmp(trans->name, new_verb->name) == 0) {
|
if (strcmp(trans->name, new_verb->name) == 0) {
|
||||||
err = execute_sequence(uc_mgr, &trans->transition_list,
|
err = execute_sequence(uc_mgr, uc_mgr->active_verb,
|
||||||
|
&trans->transition_list,
|
||||||
&uc_mgr->active_verb->value_list,
|
&uc_mgr->active_verb->value_list,
|
||||||
&uc_mgr->value_list,
|
&uc_mgr->value_list,
|
||||||
NULL);
|
NULL);
|
||||||
|
|
@ -2565,7 +2615,8 @@ static int switch_device(snd_use_case_mgr_t *uc_mgr,
|
||||||
list_for_each(pos, &xold->transition_list) {
|
list_for_each(pos, &xold->transition_list) {
|
||||||
trans = list_entry(pos, struct transition_sequence, list);
|
trans = list_entry(pos, struct transition_sequence, list);
|
||||||
if (strcmp(trans->name, new_device) == 0) {
|
if (strcmp(trans->name, new_device) == 0) {
|
||||||
err = execute_sequence(uc_mgr, &trans->transition_list,
|
err = execute_sequence(uc_mgr, uc_mgr->active_verb,
|
||||||
|
&trans->transition_list,
|
||||||
&xold->value_list,
|
&xold->value_list,
|
||||||
&uc_mgr->active_verb->value_list,
|
&uc_mgr->active_verb->value_list,
|
||||||
&uc_mgr->value_list);
|
&uc_mgr->value_list);
|
||||||
|
|
@ -2617,7 +2668,8 @@ static int switch_modifier(snd_use_case_mgr_t *uc_mgr,
|
||||||
list_for_each(pos, &xold->transition_list) {
|
list_for_each(pos, &xold->transition_list) {
|
||||||
trans = list_entry(pos, struct transition_sequence, list);
|
trans = list_entry(pos, struct transition_sequence, list);
|
||||||
if (strcmp(trans->name, new_modifier) == 0) {
|
if (strcmp(trans->name, new_modifier) == 0) {
|
||||||
err = execute_sequence(uc_mgr, &trans->transition_list,
|
err = execute_sequence(uc_mgr, uc_mgr->active_verb,
|
||||||
|
&trans->transition_list,
|
||||||
&xold->value_list,
|
&xold->value_list,
|
||||||
&uc_mgr->active_verb->value_list,
|
&uc_mgr->active_verb->value_list,
|
||||||
&uc_mgr->value_list);
|
&uc_mgr->value_list);
|
||||||
|
|
|
||||||
|
|
@ -1076,25 +1076,31 @@ cset:
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strcmp(cmd, "enadev") == 0) {
|
if (strcmp(cmd, "enadev") == 0 ||
|
||||||
/* need to enable a component device */
|
strcmp(cmd, "disdev") == 0) {
|
||||||
|
/* need to enable or disable a component device */
|
||||||
curr->type = SEQUENCE_ELEMENT_TYPE_CMPT_SEQ;
|
curr->type = SEQUENCE_ELEMENT_TYPE_CMPT_SEQ;
|
||||||
err = parse_component_seq(uc_mgr, n, 1,
|
err = parse_component_seq(uc_mgr, n,
|
||||||
|
strcmp(cmd, "enadev") == 0,
|
||||||
&curr->data.cmpt_seq);
|
&curr->data.cmpt_seq);
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
uc_error("error: enadev requires a valid device!");
|
uc_error("error: %s requires a valid device!", cmd);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strcmp(cmd, "disdev") == 0) {
|
if (strcmp(cmd, "enadev2") == 0) {
|
||||||
/* need to disable a component device */
|
curr->type = SEQUENCE_ELEMENT_TYPE_DEV_ENABLE_SEQ;
|
||||||
curr->type = SEQUENCE_ELEMENT_TYPE_CMPT_SEQ;
|
goto device;
|
||||||
err = parse_component_seq(uc_mgr, n, 0,
|
}
|
||||||
&curr->data.cmpt_seq);
|
|
||||||
|
if (strcmp(cmd, "disdev2") == 0) {
|
||||||
|
curr->type = SEQUENCE_ELEMENT_TYPE_DEV_DISABLE_SEQ;
|
||||||
|
device:
|
||||||
|
err = parse_string_substitute3(uc_mgr, n, &curr->data.device);
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
uc_error("error: disdev requires a valid device!");
|
uc_error("error: %s requires a valid device!", cmd);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
|
|
|
||||||
|
|
@ -222,6 +222,8 @@ SectionModifier."Capture Voice" {
|
||||||
|
|
||||||
Command name | Description
|
Command name | Description
|
||||||
---------------|----------------------------------------------
|
---------------|----------------------------------------------
|
||||||
|
enadev2 | execute device enable sequence
|
||||||
|
disdev2 | execute device disable sequence
|
||||||
cdev ARG | ALSA control device name for snd_ctl_open()
|
cdev ARG | ALSA control device name for snd_ctl_open()
|
||||||
cset ARG | ALSA control set - snd_ctl_ascii_elem_id_parse() + snd_ctl_ascii_value_parse()
|
cset ARG | ALSA control set - snd_ctl_ascii_elem_id_parse() + snd_ctl_ascii_value_parse()
|
||||||
cset-new ARG | Create new ALSA user control element - snd_ctl_ascii_elem_id_parse() + description
|
cset-new ARG | Create new ALSA user control element - snd_ctl_ascii_elem_id_parse() + description
|
||||||
|
|
|
||||||
|
|
@ -57,6 +57,8 @@
|
||||||
#define SEQUENCE_ELEMENT_TYPE_CMPT_SEQ 10
|
#define SEQUENCE_ELEMENT_TYPE_CMPT_SEQ 10
|
||||||
#define SEQUENCE_ELEMENT_TYPE_SYSSET 11
|
#define SEQUENCE_ELEMENT_TYPE_SYSSET 11
|
||||||
#define SEQUENCE_ELEMENT_TYPE_CFGSAVE 12
|
#define SEQUENCE_ELEMENT_TYPE_CFGSAVE 12
|
||||||
|
#define SEQUENCE_ELEMENT_TYPE_DEV_ENABLE_SEQ 13
|
||||||
|
#define SEQUENCE_ELEMENT_TYPE_DEV_DISABLE_SEQ 14
|
||||||
|
|
||||||
struct ucm_value {
|
struct ucm_value {
|
||||||
struct list_head list;
|
struct list_head list;
|
||||||
|
|
@ -80,6 +82,7 @@ struct sequence_element {
|
||||||
char *exec;
|
char *exec;
|
||||||
char *sysw;
|
char *sysw;
|
||||||
char *cfgsave;
|
char *cfgsave;
|
||||||
|
char *device;
|
||||||
struct component_sequence cmpt_seq; /* component sequence */
|
struct component_sequence cmpt_seq; /* component sequence */
|
||||||
} data;
|
} data;
|
||||||
};
|
};
|
||||||
|
|
@ -230,6 +233,7 @@ struct snd_use_case_mgr {
|
||||||
int suppress_nodev_errors;
|
int suppress_nodev_errors;
|
||||||
const char *parse_variant;
|
const char *parse_variant;
|
||||||
int parse_master_section;
|
int parse_master_section;
|
||||||
|
int sequence_hops;
|
||||||
|
|
||||||
/* UCM cards list */
|
/* UCM cards list */
|
||||||
struct list_head cards_list;
|
struct list_head cards_list;
|
||||||
|
|
|
||||||
|
|
@ -520,6 +520,10 @@ void uc_mgr_free_sequence_element(struct sequence_element *seq)
|
||||||
case SEQUENCE_ELEMENT_TYPE_CFGSAVE:
|
case SEQUENCE_ELEMENT_TYPE_CFGSAVE:
|
||||||
free(seq->data.cfgsave);
|
free(seq->data.cfgsave);
|
||||||
break;
|
break;
|
||||||
|
case SEQUENCE_ELEMENT_TYPE_DEV_ENABLE_SEQ:
|
||||||
|
case SEQUENCE_ELEMENT_TYPE_DEV_DISABLE_SEQ:
|
||||||
|
free(seq->data.device);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue