diff options
author | Jaroslav Kysela <perex@perex.cz> | 2010-10-26 14:26:46 +0200 |
---|---|---|
committer | Jaroslav Kysela <perex@perex.cz> | 2010-10-26 14:26:46 +0200 |
commit | e4083a1182de660960afba5438a4dad47cbeac2e (patch) | |
tree | 72b87bd900ba02ddc032398d7b04604751a5b7ce | |
parent | e8208666379e10bbd56365b0a6d17f3daab730e3 (diff) | |
download | alsa-lib-e4083a1182de660960afba5438a4dad47cbeac2e.tar.gz |
ucm: debug parser
Signed-off-by: Jaroslav Kysela <perex@perex.cz>
-rw-r--r-- | src/ucm/parser.c | 360 | ||||
-rw-r--r-- | src/ucm/ucm_local.h | 1 | ||||
-rw-r--r-- | src/ucm/utils.c | 26 | ||||
-rw-r--r-- | test/ucm/TestHDA/Case1.conf | 24 | ||||
-rw-r--r-- | test/ucm/TestHDA/TestHDA.conf | 11 |
5 files changed, 268 insertions, 154 deletions
diff --git a/src/ucm/parser.c b/src/ucm/parser.c index 4e2a9d74..1b5a4310 100644 --- a/src/ucm/parser.c +++ b/src/ucm/parser.c @@ -33,6 +33,9 @@ #include "ucm_local.h" #include <dirent.h> +/** The name of the environment variable containing the UCM directory */ +#define ALSA_CONFIG_UCM_VAR "ALSA_CONFIG_UCM" + static int parse_sequence(snd_use_case_mgr_t *uc_mgr, struct list_head *base, snd_config_t *cfg); @@ -70,43 +73,37 @@ static int parse_transition(snd_use_case_mgr_t *uc_mgr, if (snd_config_get_id(cfg, &id) < 0) return -EINVAL; - tseq = calloc(1, sizeof(*tseq)); - if (tseq == NULL) - return -ENOMEM; - INIT_LIST_HEAD(&tseq->transition_list); - - tseq->name = strdup(id); - if (tseq->name == NULL) { - free(tseq); - return -ENOMEM; - } - if (snd_config_get_type(cfg) != SND_CONFIG_TYPE_COMPOUND) { uc_error("compound type expected for %s", id); - err = -EINVAL; - goto __err; + return -EINVAL; } - /* parse master config sections */ + snd_config_for_each(i, next, cfg) { n = snd_config_iterator_entry(i); - if (snd_config_get_type(cfg) != SND_CONFIG_TYPE_COMPOUND) { - uc_error("compound type expected for %s", id); - err = -EINVAL; - goto __err; + if (snd_config_get_id(n, &id) < 0) + return -EINVAL; + + tseq = calloc(1, sizeof(*tseq)); + if (tseq == NULL) + return -ENOMEM; + INIT_LIST_HEAD(&tseq->transition_list); + + tseq->name = strdup(id); + if (tseq->name == NULL) { + free(tseq); + return -ENOMEM; } - + err = parse_sequence(uc_mgr, &tseq->transition_list, n); - if (err < 0) + if (err < 0) { + uc_mgr_free_transition_element(tseq); return err; - } + } - list_add(&tseq->list, tlist); + list_add(&tseq->list, tlist); + } return 0; - __err: - free(tseq->name); - free(tseq); - return err; } /* @@ -128,7 +125,7 @@ static int parse_compound(snd_use_case_mgr_t *uc_mgr, snd_config_t *cfg, uc_error("compound type expected for %s", id); return -EINVAL; } - /* parse master config sections */ + /* parse compound */ snd_config_for_each(i, next, cfg) { n = snd_config_iterator_entry(i); @@ -145,6 +142,47 @@ static int parse_compound(snd_use_case_mgr_t *uc_mgr, snd_config_t *cfg, return 0; } + +/* + * Parse transition + */ +static int parse_supported_device(snd_use_case_mgr_t *uc_mgr ATTRIBUTE_UNUSED, + struct list_head *dlist, + snd_config_t *cfg) +{ + struct dev_list *sdev; + const char *id; + snd_config_iterator_t i, next; + snd_config_t *n; + int err; + + if (snd_config_get_id(cfg, &id) < 0) + return -EINVAL; + + if (snd_config_get_type(cfg) != SND_CONFIG_TYPE_COMPOUND) { + uc_error("compound type expected for %s", id); + return -EINVAL; + } + + snd_config_for_each(i, next, cfg) { + n = snd_config_iterator_entry(i); + + if (snd_config_get_id(n, &id) < 0) + return -EINVAL; + + sdev = calloc(1, sizeof(struct dev_list)); + if (sdev == NULL) + return -ENOMEM; + err = parse_string(n, &sdev->name); + if (err < 0) { + free(sdev); + return err; + } + list_add(&sdev->list, dlist); + } + return 0; +} + /* * Parse sequences. * @@ -163,58 +201,60 @@ static int parse_sequence(snd_use_case_mgr_t *uc_mgr ATTRIBUTE_UNUSED, snd_config_t *cfg) { struct sequence_element *curr; - snd_config_iterator_t i, next, j, next2; - snd_config_t *n, *n2; + snd_config_iterator_t i, next; + snd_config_t *n; int err; + if (snd_config_get_type(cfg) != SND_CONFIG_TYPE_COMPOUND) { + uc_error("error: compound is expected for sequence definition"); + return -EINVAL; + } + snd_config_for_each(i, next, cfg) { + const char *id; n = snd_config_iterator_entry(i); - snd_config_for_each(j, next2, n) { - const char *id; - n2 = snd_config_iterator_entry(i); - err = snd_config_get_id(n2, &id); - if (err < 0) - continue; + err = snd_config_get_id(n, &id); + if (err < 0) + continue; - /* alloc new sequence element */ - curr = calloc(1, sizeof(struct sequence_element)); - if (curr == NULL) - return -ENOMEM; - list_add_tail(&curr->list, base); - - if (strcmp(id, "cset") == 0) { - curr->type = SEQUENCE_ELEMENT_TYPE_CSET; - err = parse_string(n2, &curr->data.cset); - if (err < 0) { - uc_error("error: cset requires a string!"); - return err; - } - continue; + /* alloc new sequence element */ + curr = calloc(1, sizeof(struct sequence_element)); + if (curr == NULL) + return -ENOMEM; + list_add_tail(&curr->list, base); + + if (strcmp(id, "cset") == 0) { + curr->type = SEQUENCE_ELEMENT_TYPE_CSET; + err = parse_string(n, &curr->data.cset); + if (err < 0) { + uc_error("error: cset requires a string!"); + return err; } + continue; + } - if (strcmp(id, "usleep") == 0) { - curr->type = SEQUENCE_ELEMENT_TYPE_SLEEP; - err = snd_config_get_integer(n2, &curr->data.sleep); - if (err < 0) { - uc_error("error: usleep requires integer!"); - return err; - } - continue; + if (strcmp(id, "usleep") == 0) { + curr->type = SEQUENCE_ELEMENT_TYPE_SLEEP; + err = snd_config_get_integer(n, &curr->data.sleep); + if (err < 0) { + uc_error("error: usleep requires integer!"); + return err; } + continue; + } - if (strcmp(id, "exec") == 0) { - curr->type = SEQUENCE_ELEMENT_TYPE_EXEC; - err = parse_string(n2, &curr->data.exec); - if (err < 0) { - uc_error("error: exec requires a string!"); - return err; - } - continue; + if (strcmp(id, "exec") == 0) { + curr->type = SEQUENCE_ELEMENT_TYPE_EXEC; + err = parse_string(n, &curr->data.exec); + if (err < 0) { + uc_error("error: exec requires a string!"); + return err; } - - list_del(&curr->list); - uc_mgr_free_sequence_element(curr); + continue; } + + list_del(&curr->list); + uc_mgr_free_sequence_element(curr); } return 0; @@ -237,65 +277,66 @@ static int parse_value(snd_use_case_mgr_t *uc_mgr ATTRIBUTE_UNUSED, snd_config_t *cfg) { struct ucm_value *curr; - snd_config_iterator_t i, next, j, next2; - snd_config_t *n, *n2; + snd_config_iterator_t i, next; + snd_config_t *n; long l; long long ll; double d; snd_config_type_t type; int err; + if (snd_config_get_type(cfg) != SND_CONFIG_TYPE_COMPOUND) { + uc_error("error: compound is expected for value definition"); + return -EINVAL; + } snd_config_for_each(i, next, cfg) { + const char *id; n = snd_config_iterator_entry(i); - snd_config_for_each(j, next2, n) { - const char *id; - n2 = snd_config_iterator_entry(i); - err = snd_config_get_id(n2, &id); - if (err < 0) - continue; + err = snd_config_get_id(n, &id); + if (err < 0) + continue; - /* alloc new value */ - curr = calloc(1, sizeof(struct ucm_value)); - if (curr == NULL) + /* alloc new value */ + curr = calloc(1, sizeof(struct ucm_value)); + if (curr == NULL) + return -ENOMEM; + list_add_tail(&curr->list, base); + curr->name = strdup(id); + if (curr->name == NULL) + return -ENOMEM; + type = snd_config_get_type(n); + switch (type) { + case SND_CONFIG_TYPE_INTEGER: + curr->data = malloc(16); + if (curr->data == NULL) return -ENOMEM; - list_add_tail(&curr->list, base); - curr->name = strdup(id); - if (curr->name == NULL) + snd_config_get_integer(n, &l); + sprintf(curr->data, "%li", l); + break; + case SND_CONFIG_TYPE_INTEGER64: + curr->data = malloc(32); + if (curr->data == NULL) return -ENOMEM; - type = snd_config_get_type(n2); - switch (type) { - case SND_CONFIG_TYPE_INTEGER: - curr->data = malloc(16); - if (curr->data == NULL) - return -ENOMEM; - snd_config_get_integer(n2, &l); - sprintf(curr->data, "%li", l); - break; - case SND_CONFIG_TYPE_INTEGER64: - curr->data = malloc(32); - if (curr->data == NULL) - return -ENOMEM; - snd_config_get_integer64(n2, &ll); - sprintf(curr->data, "%lli", ll); - break; - case SND_CONFIG_TYPE_REAL: - curr->data = malloc(64); - if (curr->data == NULL) - return -ENOMEM; - snd_config_get_real(n2, &d); - sprintf(curr->data, "%-16g", d); - break; - case SND_CONFIG_TYPE_STRING: - err = parse_string(n2, &curr->data); - if (err < 0) { - uc_error("error: unable to parse a string for id '%s'!", id); - return err; - } - break; - default: - uc_error("error: invalid type %i in Value compound", type); - return -EINVAL; + snd_config_get_integer64(n, &ll); + sprintf(curr->data, "%lli", ll); + break; + case SND_CONFIG_TYPE_REAL: + curr->data = malloc(64); + if (curr->data == NULL) + return -ENOMEM; + snd_config_get_real(n, &d); + sprintf(curr->data, "%-16g", d); + break; + case SND_CONFIG_TYPE_STRING: + err = parse_string(n, &curr->data); + if (err < 0) { + uc_error("error: unable to parse a string for id '%s'!", id); + return err; } + break; + default: + uc_error("error: invalid type %i in Value compound", type); + return -EINVAL; } } @@ -322,6 +363,10 @@ static int parse_value(snd_use_case_mgr_t *uc_mgr ATTRIBUTE_UNUSED, * ... * ] * + * TransitionSequence."ToModifierName" [ + * ... + * ] + * * # Optional TQ and ALSA PCMs * Value { * TQ Voice @@ -377,18 +422,12 @@ static int parse_modifier(snd_use_case_mgr_t *uc_mgr, } if (strcmp(id, "SupportedDevice") == 0) { - struct dev_list *sdev; - - sdev = calloc(1, sizeof(struct dev_list)); - if (sdev == NULL) - return -ENOMEM; - err = parse_string(n, &sdev->name); + err = parse_supported_device(uc_mgr, &modifier->dev_list, n); if (err < 0) { - free(sdev); + uc_error("error: failed to parse supported" + " device list"); return err; } - list_add(&sdev->list, &modifier->dev_list); - continue; } if (strcmp(id, "EnableSequence") == 0) { @@ -411,7 +450,7 @@ static int parse_modifier(snd_use_case_mgr_t *uc_mgr, continue; } - if (strcmp(id, "TransitionModifier") == 0) { + if (strcmp(id, "TransitionSequence") == 0) { err = parse_transition(uc_mgr, &modifier->transition_list, n); if (err < 0) { uc_error("error: failed to parse transition" @@ -454,6 +493,10 @@ static int parse_modifier(snd_use_case_mgr_t *uc_mgr, * ... * ] * + * TransitionSequence."ToDevice" [ + * ... + * ] + * * Value { * PlaybackVolume "name='Master Playback Volume',index=2" * PlaybackSwitch "name='Master Playback Switch',index=2" @@ -527,8 +570,8 @@ static int parse_device_index(snd_use_case_mgr_t *uc_mgr, continue; } - if (strcmp(id, "TransitionDevice") == 0) { - uc_dbg("TransitionDevice"); + if (strcmp(id, "TransitionSequence") == 0) { + uc_dbg("TransitionSequence"); err = parse_transition(uc_mgr, &device->transition_list, n); if (err < 0) { uc_error("error: failed to parse transition" @@ -596,11 +639,16 @@ static int parse_device(snd_use_case_mgr_t *uc_mgr, * cset "name='Master Playback Volume',index=2 50,50" * ] * + * # Optional transition verb + * TransitionSequence."ToCaseName" [ + * msleep 1 + * ] + * * # Optional TQ and ALSA PCMs * Value { * TQ HiFi - * CapturePCM 0 - * PlaybackPCM 0 + * CapturePCM "hw:0" + * PlaybackPCM "hw:0" * } * } */ @@ -621,7 +669,7 @@ static int parse_verb(snd_use_case_mgr_t *uc_mgr, if (strcmp(id, "EnableSequence") == 0) { uc_dbg("Parse EnableSequence"); - err = parse_sequence(uc_mgr, &verb->enable_list, cfg); + err = parse_sequence(uc_mgr, &verb->enable_list, n); if (err < 0) { uc_error("error: failed to parse verb enable sequence"); return err; @@ -631,7 +679,7 @@ static int parse_verb(snd_use_case_mgr_t *uc_mgr, if (strcmp(id, "DisableSequence") == 0) { uc_dbg("Parse DisableSequence"); - err = parse_sequence(uc_mgr, &verb->disable_list, cfg); + err = parse_sequence(uc_mgr, &verb->disable_list, n); if (err < 0) { uc_error("error: failed to parse verb disable sequence"); return err; @@ -639,11 +687,11 @@ static int parse_verb(snd_use_case_mgr_t *uc_mgr, continue; } - if (strcmp(id, "TransitionVerb") == 0) { - uc_dbg("Parse TransitionVerb"); + if (strcmp(id, "TransitionSequence") == 0) { + uc_dbg("Parse TransitionSequence"); err = parse_transition(uc_mgr, &verb->transition_list, n); if (err < 0) { - uc_error("error: failed to parse transition verb"); + uc_error("error: failed to parse transition sequence"); return err; } continue; @@ -682,6 +730,7 @@ static int parse_verb_file(snd_use_case_mgr_t *uc_mgr, struct use_case_verb *verb; snd_config_t *cfg; char filename[MAX_FILE]; + char *env = getenv(ALSA_CONFIG_UCM_VAR); int err; /* allocate verb */ @@ -703,7 +752,8 @@ static int parse_verb_file(snd_use_case_mgr_t *uc_mgr, return -ENOMEM; /* open Verb file for reading */ - snprintf(filename, sizeof(filename), "%s/%s/%s", ALSA_USE_CASE_DIR, + snprintf(filename, sizeof(filename), "%s/%s/%s", + env ? env : ALSA_USE_CASE_DIR, uc_mgr->card_name, file); filename[sizeof(filename)-1] = '\0'; @@ -832,16 +882,18 @@ static int parse_master_section(snd_use_case_mgr_t *uc_mgr, snd_config_t *cfg, */ static int parse_controls(snd_use_case_mgr_t *uc_mgr, snd_config_t *cfg) { - struct list_head list; int err; - INIT_LIST_HEAD(&list); - err = parse_sequence(uc_mgr, &list, cfg); + if (!list_empty(&uc_mgr->default_list)) { + uc_error("Default list is not empty"); + return -EINVAL; + } + err = parse_sequence(uc_mgr, &uc_mgr->default_list, cfg); if (err < 0) { uc_error("Unable to parse SectionDefaults"); return err; } - printf("parse_controls - not yet implemented\n"); + return 0; } @@ -931,9 +983,6 @@ static int parse_master_file(snd_use_case_mgr_t *uc_mgr, snd_config_t *cfg) return 0; } -/** The name of the environment variable containing the UCM directory */ -#define ALSA_CONFIG_UCM_VAR "ALSA_CONFIG_UCM" - static int load_master_config(const char *card_name, snd_config_t **cfg) { char filename[MAX_FILE]; @@ -992,18 +1041,19 @@ static int filename_filter(const struct dirent *dirent) /* scan all cards and comments */ int uc_mgr_scan_master_configs(const char **_list[]) { - char filename[MAX_FILE]; + char filename[MAX_FILE], dfl[MAX_FILE]; char *env = getenv(ALSA_CONFIG_UCM_VAR); const char **list; snd_config_t *cfg, *c; int i, cnt, err; + ssize_t ss; struct dirent **namelist; snprintf(filename, sizeof(filename)-1, "%s", env ? env : ALSA_USE_CASE_DIR); filename[MAX_FILE-1] = '\0'; - err = scandir(filename, &namelist, filename_filter, alphasort); + err = scandir(filename, &namelist, filename_filter, versionsort); if (err < 0) { err = -errno; uc_error("error: could not scan directory %s: %s", @@ -1012,6 +1062,20 @@ int uc_mgr_scan_master_configs(const char **_list[]) } cnt = err; + dfl[0] = '\0'; + if (strlen(filename) + 8 < sizeof(filename)) { + strcat(filename, "/default"); + ss = readlink(filename, dfl, sizeof(dfl)-1); + if (ss >= 0) { + dfl[ss] = '\0'; + dfl[sizeof(dfl)-1] = '\0'; + if (dfl[0] && dfl[strlen(dfl)-1] == '/') + dfl[strlen(dfl)-1] = '\0'; + } else { + dfl[0] = '\0'; + } + } + list = calloc(1, cnt * 2 * sizeof(char *)); if (list == NULL) { err = -ENOMEM; @@ -1036,6 +1100,14 @@ int uc_mgr_scan_master_configs(const char **_list[]) err = -ENOMEM; goto __err; } + if (strcmp(dfl, list[i * 2]) == 0) { + /* default to top */ + const char *save1 = list[i * 2]; + const char *save2 = list[i * 2 + 1]; + memmove(list + 2, list, i * 2 * sizeof(char *)); + list[0] = save1; + list[1] = save2; + } } err = cnt * 2; diff --git a/src/ucm/ucm_local.h b/src/ucm/ucm_local.h index 7dae5b6a..0515de17 100644 --- a/src/ucm/ucm_local.h +++ b/src/ucm/ucm_local.h @@ -196,5 +196,6 @@ int uc_mgr_import_master_config(snd_use_case_mgr_t *uc_mgr); int uc_mgr_scan_master_configs(const char **_list[]); void uc_mgr_free_sequence_element(struct sequence_element *seq); +void uc_mgr_free_transition_element(struct transition_sequence *seq); void uc_mgr_free_verb(snd_use_case_mgr_t *uc_mgr); void uc_mgr_free(snd_use_case_mgr_t *uc_mgr); diff --git a/src/ucm/utils.c b/src/ucm/utils.c index 0f8207e8..267a13c9 100644 --- a/src/ucm/utils.c +++ b/src/ucm/utils.c @@ -94,7 +94,8 @@ void uc_mgr_free_value(struct list_head *base) val = list_entry(pos, struct ucm_value, list); free(val->name); free(val->data); - list_del(pos); + list_del(&val->list); + free(val); } } @@ -106,8 +107,8 @@ void uc_mgr_free_dev_list(struct list_head *base) list_for_each_safe(pos, npos, base) { dlist = list_entry(pos, struct dev_list, list); free(dlist->name); + list_del(&dlist->list); free(dlist); - list_del(pos); } } @@ -133,11 +134,18 @@ void uc_mgr_free_sequence(struct list_head *base) list_for_each_safe(pos, npos, base) { seq = list_entry(pos, struct sequence_element, list); + list_del(&seq->list); uc_mgr_free_sequence_element(seq); - list_del(pos); } } +void uc_mgr_free_transition_element(struct transition_sequence *tseq) +{ + free(tseq->name); + uc_mgr_free_sequence(&tseq->transition_list); + free(tseq); +} + void uc_mgr_free_transition(struct list_head *base) { struct list_head *pos, *npos; @@ -145,10 +153,8 @@ void uc_mgr_free_transition(struct list_head *base) list_for_each_safe(pos, npos, base) { tseq = list_entry(pos, struct transition_sequence, list); - free(tseq->name); - uc_mgr_free_sequence(&tseq->transition_list); - free(tseq); - list_del(pos); + list_del(&tseq->list); + uc_mgr_free_transition_element(tseq); } } @@ -166,8 +172,8 @@ void uc_mgr_free_modifier(struct list_head *base) uc_mgr_free_transition(&mod->transition_list); uc_mgr_free_dev_list(&mod->dev_list); uc_mgr_free_value(&mod->value_list); + list_del(&mod->list); free(mod); - list_del(pos); } } @@ -184,8 +190,8 @@ void uc_mgr_free_device(struct list_head *base) uc_mgr_free_sequence(&dev->disable_list); uc_mgr_free_transition(&dev->transition_list); uc_mgr_free_value(&dev->value_list); + list_del(&dev->list); free(dev); - list_del(pos); } } @@ -204,8 +210,8 @@ void uc_mgr_free_verb(snd_use_case_mgr_t *uc_mgr) uc_mgr_free_value(&verb->value_list); uc_mgr_free_device(&verb->device_list); uc_mgr_free_modifier(&verb->modifier_list); + list_del(&verb->list); free(verb); - list_del(pos); } uc_mgr_free_sequence(&uc_mgr->default_list); free(uc_mgr->comment); diff --git a/test/ucm/TestHDA/Case1.conf b/test/ucm/TestHDA/Case1.conf new file mode 100644 index 00000000..65af2600 --- /dev/null +++ b/test/ucm/TestHDA/Case1.conf @@ -0,0 +1,24 @@ +SectionVerb { + EnableSequence [ + exec "Case1 enable seq" + ] + DisableSequence [ + exec "Case2 disable seq" + ] + TransitionVerb."Case2" [ + exec "Case1->Case2 transition seq" + ] + Value { + TestValue1 "123" + } +} + +SectionDevice."Device1".0 { + +} + +SectionModifier."Modifier1" { + SupportedDevice [ + "Device1" + ] +} diff --git a/test/ucm/TestHDA/TestHDA.conf b/test/ucm/TestHDA/TestHDA.conf new file mode 100644 index 00000000..9b93b96e --- /dev/null +++ b/test/ucm/TestHDA/TestHDA.conf @@ -0,0 +1,11 @@ +Comment "A test HDA card" + +SectionUseCase."Case1" { + File "Case1.conf" + Comment "Case1 Comment" +} + +SectionDefaults [ + exec "my prg" + msleep 1 +] |