]> git.alsa-project.org Git - alsa-lib.git/commitdiff
ucm: implement enadev2 and disdev2 sequence commands
authorJaroslav Kysela <perex@perex.cz>
Thu, 19 May 2022 08:08:48 +0000 (10:08 +0200)
committerJaroslav Kysela <perex@perex.cz>
Thu, 19 May 2022 08:08:50 +0000 (10:08 +0200)
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>
src/ucm/main.c
src/ucm/parser.c
src/ucm/ucm_confdoc.h
src/ucm/ucm_local.h
src/ucm/utils.c

index ccae43f63d2d5458c6a2a4ac1d9e9d561c935671..8afc72d08628b9218cdd1f066103d64327b0797d 100644 (file)
@@ -59,6 +59,13 @@ static int get_value3(snd_use_case_mgr_t *uc_mgr,
                      struct list_head *value_list2,
                      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,
                                 struct component_sequence *cmpt_seq,
                                 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,
                                 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)
 {
        int len;
@@ -660,6 +671,29 @@ static int rewrite_device_value(snd_use_case_mgr_t *uc_mgr, const char *name, ch
        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
  * \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
  */
 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,
@@ -680,6 +715,11 @@ static int execute_sequence(snd_use_case_mgr_t *uc_mgr,
        bool ignore_error;
        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) {
                s = list_entry(pos, struct sequence_element, list);
                switch (s->type) {
@@ -819,17 +859,26 @@ shell_retry:
                        if (err < 0)
                                goto __fail;
                        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:
                        uc_error("unknown sequence command %i", s->type);
                        break;
                }
        }
        free(cdev);
+       uc_mgr->sequence_hops--;
        return 0;
       __fail_nomem:
        err = -ENOMEM;
       __fail:
        free(cdev);
+       uc_mgr->sequence_hops--;
        return err;
 
 }
@@ -865,7 +914,7 @@ static int execute_component_seq(snd_use_case_mgr_t *uc_mgr,
                seq = &device->disable_list;
 
        /* 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,
                               &uc_mgr->active_verb->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)
                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);
        if (err < 0) {
                uc_error("Unable to execute default sequence");
@@ -1279,7 +1328,7 @@ static int set_verb(snd_use_case_mgr_t *uc_mgr,
        } else {
                seq = &verb->disable_list;
        }
-       err = execute_sequence(uc_mgr, seq,
+       err = execute_sequence(uc_mgr, verb, seq,
                               &verb->value_list,
                               &uc_mgr->value_list,
                               NULL);
@@ -1310,7 +1359,7 @@ static int set_modifier(snd_use_case_mgr_t *uc_mgr,
        } else {
                seq = &modifier->disable_list;
        }
-       err = execute_sequence(uc_mgr, seq,
+       err = execute_sequence(uc_mgr, uc_mgr->active_verb, seq,
                               &modifier->value_list,
                               &uc_mgr->active_verb->value_list,
                               &uc_mgr->value_list);
@@ -1344,7 +1393,7 @@ static int set_device(snd_use_case_mgr_t *uc_mgr,
        } else {
                seq = &device->disable_list;
        }
-       err = execute_sequence(uc_mgr, seq,
+       err = execute_sequence(uc_mgr, uc_mgr->active_verb, seq,
                               &device->value_list,
                               &uc_mgr->active_verb->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;
 
-       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);
        
        return err;
@@ -1578,7 +1627,7 @@ int snd_use_case_mgr_reset(snd_use_case_mgr_t *uc_mgr)
        int err;
 
        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);
        INIT_LIST_HEAD(&uc_mgr->active_modifiers);
        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))
                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);
        if (err < 0) {
                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))
                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);
        if (err < 0) {
                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) {
                trans = list_entry(pos, struct transition_sequence, list);
                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->value_list,
                                               NULL);
@@ -2565,7 +2615,8 @@ static int switch_device(snd_use_case_mgr_t *uc_mgr,
        list_for_each(pos, &xold->transition_list) {
                trans = list_entry(pos, struct transition_sequence, list);
                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,
                                               &uc_mgr->active_verb->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) {
                trans = list_entry(pos, struct transition_sequence, list);
                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,
                                               &uc_mgr->active_verb->value_list,
                                               &uc_mgr->value_list);
index cbefbd13696ef2d6e5848809b62985ec35648fc0..b77544ba88f764f7789fd3ec0dba1e4fae42b40a 100644 (file)
@@ -1076,25 +1076,31 @@ cset:
                        continue;
                }
 
-               if (strcmp(cmd, "enadev") == 0) {
-                       /* need to enable a component device */
+               if (strcmp(cmd, "enadev") == 0 ||
+                   strcmp(cmd, "disdev") == 0) {
+                       /* need to enable or disable a component device */
                        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);
                        if (err < 0) {
-                               uc_error("error: enadev requires a valid device!");
+                               uc_error("error: %s requires a valid device!", cmd);
                                return err;
                        }
                        continue;
                }
 
-               if (strcmp(cmd, "disdev") == 0) {
-                       /* need to disable a component device */
-                       curr->type = SEQUENCE_ELEMENT_TYPE_CMPT_SEQ;
-                       err = parse_component_seq(uc_mgr, n, 0,
-                                               &curr->data.cmpt_seq);
+               if (strcmp(cmd, "enadev2") == 0) {
+                       curr->type = SEQUENCE_ELEMENT_TYPE_DEV_ENABLE_SEQ;
+                       goto device;
+               }
+
+               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) {
-                               uc_error("error: disdev requires a valid device!");
+                               uc_error("error: %s requires a valid device!", cmd);
                                return err;
                        }
                        continue;
index 090bd86c72cd99102e69e433475e52159f1b1293..31ec0c59ed49b1a783d1fae66cc6a2aee977bb2c 100644 (file)
@@ -222,6 +222,8 @@ SectionModifier."Capture Voice" {
 
 Command name   | Description
 ---------------|----------------------------------------------
+enadev2        | execute device enable sequence
+disdev2        | execute device disable sequence
 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-new ARG   | Create new ALSA user control element - snd_ctl_ascii_elem_id_parse() + description
index 15fbc1b5fd42ca10c0584b815996771818cb19bc..8c36e8b990b2b42644ad9593ccce6bed02fe308c 100644 (file)
@@ -57,6 +57,8 @@
 #define SEQUENCE_ELEMENT_TYPE_CMPT_SEQ         10
 #define SEQUENCE_ELEMENT_TYPE_SYSSET           11
 #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 list_head list;
@@ -80,6 +82,7 @@ struct sequence_element {
                char *exec;
                char *sysw;
                char *cfgsave;
+               char *device;
                struct component_sequence cmpt_seq; /* component sequence */
        } data;
 };
@@ -230,6 +233,7 @@ struct snd_use_case_mgr {
        int suppress_nodev_errors;
        const char *parse_variant;
        int parse_master_section;
+       int sequence_hops;
 
        /* UCM cards list */
        struct list_head cards_list;
index 13e084f2e4045d3a02b9c16401da66195a3ddac6..8123fc67eced223ce1d85d9ab50fe31ba4d085d0 100644 (file)
@@ -520,6 +520,10 @@ void uc_mgr_free_sequence_element(struct sequence_element *seq)
        case SEQUENCE_ELEMENT_TYPE_CFGSAVE:
                free(seq->data.cfgsave);
                break;
+       case SEQUENCE_ELEMENT_TYPE_DEV_ENABLE_SEQ:
+       case SEQUENCE_ELEMENT_TYPE_DEV_DISABLE_SEQ:
+               free(seq->data.device);
+               break;
        default:
                break;
        }