mirror of
https://github.com/alsa-project/alsa-lib.git
synced 2025-10-31 22:25:35 -04:00
ucm: debug parser
Signed-off-by: Jaroslav Kysela <perex@perex.cz>
This commit is contained in:
parent
e820866637
commit
e4083a1182
5 changed files with 274 additions and 160 deletions
364
src/ucm/parser.c
364
src/ucm/parser.c
|
|
@ -33,6 +33,9 @@
|
||||||
#include "ucm_local.h"
|
#include "ucm_local.h"
|
||||||
#include <dirent.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,
|
static int parse_sequence(snd_use_case_mgr_t *uc_mgr,
|
||||||
struct list_head *base,
|
struct list_head *base,
|
||||||
snd_config_t *cfg);
|
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)
|
if (snd_config_get_id(cfg, &id) < 0)
|
||||||
return -EINVAL;
|
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) {
|
if (snd_config_get_type(cfg) != SND_CONFIG_TYPE_COMPOUND) {
|
||||||
uc_error("compound type expected for %s", id);
|
uc_error("compound type expected for %s", id);
|
||||||
err = -EINVAL;
|
return -EINVAL;
|
||||||
goto __err;
|
|
||||||
}
|
}
|
||||||
/* parse master config sections */
|
|
||||||
snd_config_for_each(i, next, cfg) {
|
snd_config_for_each(i, next, cfg) {
|
||||||
n = snd_config_iterator_entry(i);
|
n = snd_config_iterator_entry(i);
|
||||||
|
|
||||||
if (snd_config_get_type(cfg) != SND_CONFIG_TYPE_COMPOUND) {
|
if (snd_config_get_id(n, &id) < 0)
|
||||||
uc_error("compound type expected for %s", id);
|
return -EINVAL;
|
||||||
err = -EINVAL;
|
|
||||||
goto __err;
|
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);
|
err = parse_sequence(uc_mgr, &tseq->transition_list, n);
|
||||||
if (err < 0)
|
if (err < 0) {
|
||||||
|
uc_mgr_free_transition_element(tseq);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
list_add(&tseq->list, tlist);
|
list_add(&tseq->list, tlist);
|
||||||
|
}
|
||||||
return 0;
|
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);
|
uc_error("compound type expected for %s", id);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
/* parse master config sections */
|
/* parse compound */
|
||||||
snd_config_for_each(i, next, cfg) {
|
snd_config_for_each(i, next, cfg) {
|
||||||
n = snd_config_iterator_entry(i);
|
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;
|
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.
|
* Parse sequences.
|
||||||
*
|
*
|
||||||
|
|
@ -163,58 +201,60 @@ static int parse_sequence(snd_use_case_mgr_t *uc_mgr ATTRIBUTE_UNUSED,
|
||||||
snd_config_t *cfg)
|
snd_config_t *cfg)
|
||||||
{
|
{
|
||||||
struct sequence_element *curr;
|
struct sequence_element *curr;
|
||||||
snd_config_iterator_t i, next, j, next2;
|
snd_config_iterator_t i, next;
|
||||||
snd_config_t *n, *n2;
|
snd_config_t *n;
|
||||||
int err;
|
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) {
|
snd_config_for_each(i, next, cfg) {
|
||||||
|
const char *id;
|
||||||
n = snd_config_iterator_entry(i);
|
n = snd_config_iterator_entry(i);
|
||||||
snd_config_for_each(j, next2, n) {
|
err = snd_config_get_id(n, &id);
|
||||||
const char *id;
|
if (err < 0)
|
||||||
n2 = snd_config_iterator_entry(i);
|
continue;
|
||||||
err = snd_config_get_id(n2, &id);
|
|
||||||
if (err < 0)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
/* alloc new sequence element */
|
/* alloc new sequence element */
|
||||||
curr = calloc(1, sizeof(struct sequence_element));
|
curr = calloc(1, sizeof(struct sequence_element));
|
||||||
if (curr == NULL)
|
if (curr == NULL)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
list_add_tail(&curr->list, base);
|
list_add_tail(&curr->list, base);
|
||||||
|
|
||||||
if (strcmp(id, "cset") == 0) {
|
if (strcmp(id, "cset") == 0) {
|
||||||
curr->type = SEQUENCE_ELEMENT_TYPE_CSET;
|
curr->type = SEQUENCE_ELEMENT_TYPE_CSET;
|
||||||
err = parse_string(n2, &curr->data.cset);
|
err = parse_string(n, &curr->data.cset);
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
uc_error("error: cset requires a string!");
|
uc_error("error: cset requires a string!");
|
||||||
return err;
|
return err;
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
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, "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;
|
|
||||||
}
|
|
||||||
|
|
||||||
list_del(&curr->list);
|
|
||||||
uc_mgr_free_sequence_element(curr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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(n, &curr->data.exec);
|
||||||
|
if (err < 0) {
|
||||||
|
uc_error("error: exec requires a string!");
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
list_del(&curr->list);
|
||||||
|
uc_mgr_free_sequence_element(curr);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
@ -237,65 +277,66 @@ static int parse_value(snd_use_case_mgr_t *uc_mgr ATTRIBUTE_UNUSED,
|
||||||
snd_config_t *cfg)
|
snd_config_t *cfg)
|
||||||
{
|
{
|
||||||
struct ucm_value *curr;
|
struct ucm_value *curr;
|
||||||
snd_config_iterator_t i, next, j, next2;
|
snd_config_iterator_t i, next;
|
||||||
snd_config_t *n, *n2;
|
snd_config_t *n;
|
||||||
long l;
|
long l;
|
||||||
long long ll;
|
long long ll;
|
||||||
double d;
|
double d;
|
||||||
snd_config_type_t type;
|
snd_config_type_t type;
|
||||||
int err;
|
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) {
|
snd_config_for_each(i, next, cfg) {
|
||||||
|
const char *id;
|
||||||
n = snd_config_iterator_entry(i);
|
n = snd_config_iterator_entry(i);
|
||||||
snd_config_for_each(j, next2, n) {
|
err = snd_config_get_id(n, &id);
|
||||||
const char *id;
|
if (err < 0)
|
||||||
n2 = snd_config_iterator_entry(i);
|
continue;
|
||||||
err = snd_config_get_id(n2, &id);
|
|
||||||
if (err < 0)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
/* alloc new value */
|
/* alloc new value */
|
||||||
curr = calloc(1, sizeof(struct ucm_value));
|
curr = calloc(1, sizeof(struct ucm_value));
|
||||||
if (curr == NULL)
|
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;
|
return -ENOMEM;
|
||||||
list_add_tail(&curr->list, base);
|
snd_config_get_integer(n, &l);
|
||||||
curr->name = strdup(id);
|
sprintf(curr->data, "%li", l);
|
||||||
if (curr->name == NULL)
|
break;
|
||||||
|
case SND_CONFIG_TYPE_INTEGER64:
|
||||||
|
curr->data = malloc(32);
|
||||||
|
if (curr->data == NULL)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
type = snd_config_get_type(n2);
|
snd_config_get_integer64(n, &ll);
|
||||||
switch (type) {
|
sprintf(curr->data, "%lli", ll);
|
||||||
case SND_CONFIG_TYPE_INTEGER:
|
break;
|
||||||
curr->data = malloc(16);
|
case SND_CONFIG_TYPE_REAL:
|
||||||
if (curr->data == NULL)
|
curr->data = malloc(64);
|
||||||
return -ENOMEM;
|
if (curr->data == NULL)
|
||||||
snd_config_get_integer(n2, &l);
|
return -ENOMEM;
|
||||||
sprintf(curr->data, "%li", l);
|
snd_config_get_real(n, &d);
|
||||||
break;
|
sprintf(curr->data, "%-16g", d);
|
||||||
case SND_CONFIG_TYPE_INTEGER64:
|
break;
|
||||||
curr->data = malloc(32);
|
case SND_CONFIG_TYPE_STRING:
|
||||||
if (curr->data == NULL)
|
err = parse_string(n, &curr->data);
|
||||||
return -ENOMEM;
|
if (err < 0) {
|
||||||
snd_config_get_integer64(n2, &ll);
|
uc_error("error: unable to parse a string for id '%s'!", id);
|
||||||
sprintf(curr->data, "%lli", ll);
|
return err;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
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
|
* # Optional TQ and ALSA PCMs
|
||||||
* Value {
|
* Value {
|
||||||
* TQ Voice
|
* TQ Voice
|
||||||
|
|
@ -377,18 +422,12 @@ static int parse_modifier(snd_use_case_mgr_t *uc_mgr,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strcmp(id, "SupportedDevice") == 0) {
|
if (strcmp(id, "SupportedDevice") == 0) {
|
||||||
struct dev_list *sdev;
|
err = parse_supported_device(uc_mgr, &modifier->dev_list, n);
|
||||||
|
|
||||||
sdev = calloc(1, sizeof(struct dev_list));
|
|
||||||
if (sdev == NULL)
|
|
||||||
return -ENOMEM;
|
|
||||||
err = parse_string(n, &sdev->name);
|
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
free(sdev);
|
uc_error("error: failed to parse supported"
|
||||||
|
" device list");
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
list_add(&sdev->list, &modifier->dev_list);
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strcmp(id, "EnableSequence") == 0) {
|
if (strcmp(id, "EnableSequence") == 0) {
|
||||||
|
|
@ -411,7 +450,7 @@ static int parse_modifier(snd_use_case_mgr_t *uc_mgr,
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strcmp(id, "TransitionModifier") == 0) {
|
if (strcmp(id, "TransitionSequence") == 0) {
|
||||||
err = parse_transition(uc_mgr, &modifier->transition_list, n);
|
err = parse_transition(uc_mgr, &modifier->transition_list, n);
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
uc_error("error: failed to parse transition"
|
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 {
|
* Value {
|
||||||
* PlaybackVolume "name='Master Playback Volume',index=2"
|
* PlaybackVolume "name='Master Playback Volume',index=2"
|
||||||
* PlaybackSwitch "name='Master Playback Switch',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;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strcmp(id, "TransitionDevice") == 0) {
|
if (strcmp(id, "TransitionSequence") == 0) {
|
||||||
uc_dbg("TransitionDevice");
|
uc_dbg("TransitionSequence");
|
||||||
err = parse_transition(uc_mgr, &device->transition_list, n);
|
err = parse_transition(uc_mgr, &device->transition_list, n);
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
uc_error("error: failed to parse transition"
|
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"
|
* cset "name='Master Playback Volume',index=2 50,50"
|
||||||
* ]
|
* ]
|
||||||
*
|
*
|
||||||
|
* # Optional transition verb
|
||||||
|
* TransitionSequence."ToCaseName" [
|
||||||
|
* msleep 1
|
||||||
|
* ]
|
||||||
|
*
|
||||||
* # Optional TQ and ALSA PCMs
|
* # Optional TQ and ALSA PCMs
|
||||||
* Value {
|
* Value {
|
||||||
* TQ HiFi
|
* TQ HiFi
|
||||||
* CapturePCM 0
|
* CapturePCM "hw:0"
|
||||||
* PlaybackPCM 0
|
* PlaybackPCM "hw:0"
|
||||||
* }
|
* }
|
||||||
* }
|
* }
|
||||||
*/
|
*/
|
||||||
|
|
@ -621,7 +669,7 @@ static int parse_verb(snd_use_case_mgr_t *uc_mgr,
|
||||||
|
|
||||||
if (strcmp(id, "EnableSequence") == 0) {
|
if (strcmp(id, "EnableSequence") == 0) {
|
||||||
uc_dbg("Parse EnableSequence");
|
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) {
|
if (err < 0) {
|
||||||
uc_error("error: failed to parse verb enable sequence");
|
uc_error("error: failed to parse verb enable sequence");
|
||||||
return err;
|
return err;
|
||||||
|
|
@ -631,7 +679,7 @@ static int parse_verb(snd_use_case_mgr_t *uc_mgr,
|
||||||
|
|
||||||
if (strcmp(id, "DisableSequence") == 0) {
|
if (strcmp(id, "DisableSequence") == 0) {
|
||||||
uc_dbg("Parse DisableSequence");
|
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) {
|
if (err < 0) {
|
||||||
uc_error("error: failed to parse verb disable sequence");
|
uc_error("error: failed to parse verb disable sequence");
|
||||||
return err;
|
return err;
|
||||||
|
|
@ -639,11 +687,11 @@ static int parse_verb(snd_use_case_mgr_t *uc_mgr,
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strcmp(id, "TransitionVerb") == 0) {
|
if (strcmp(id, "TransitionSequence") == 0) {
|
||||||
uc_dbg("Parse TransitionVerb");
|
uc_dbg("Parse TransitionSequence");
|
||||||
err = parse_transition(uc_mgr, &verb->transition_list, n);
|
err = parse_transition(uc_mgr, &verb->transition_list, n);
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
uc_error("error: failed to parse transition verb");
|
uc_error("error: failed to parse transition sequence");
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
|
|
@ -682,6 +730,7 @@ static int parse_verb_file(snd_use_case_mgr_t *uc_mgr,
|
||||||
struct use_case_verb *verb;
|
struct use_case_verb *verb;
|
||||||
snd_config_t *cfg;
|
snd_config_t *cfg;
|
||||||
char filename[MAX_FILE];
|
char filename[MAX_FILE];
|
||||||
|
char *env = getenv(ALSA_CONFIG_UCM_VAR);
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
/* allocate verb */
|
/* allocate verb */
|
||||||
|
|
@ -703,7 +752,8 @@ static int parse_verb_file(snd_use_case_mgr_t *uc_mgr,
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
/* open Verb file for reading */
|
/* 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);
|
uc_mgr->card_name, file);
|
||||||
filename[sizeof(filename)-1] = '\0';
|
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)
|
static int parse_controls(snd_use_case_mgr_t *uc_mgr, snd_config_t *cfg)
|
||||||
{
|
{
|
||||||
struct list_head list;
|
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
INIT_LIST_HEAD(&list);
|
if (!list_empty(&uc_mgr->default_list)) {
|
||||||
err = parse_sequence(uc_mgr, &list, cfg);
|
uc_error("Default list is not empty");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
err = parse_sequence(uc_mgr, &uc_mgr->default_list, cfg);
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
uc_error("Unable to parse SectionDefaults");
|
uc_error("Unable to parse SectionDefaults");
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
printf("parse_controls - not yet implemented\n");
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -931,9 +983,6 @@ static int parse_master_file(snd_use_case_mgr_t *uc_mgr, snd_config_t *cfg)
|
||||||
return 0;
|
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)
|
static int load_master_config(const char *card_name, snd_config_t **cfg)
|
||||||
{
|
{
|
||||||
char filename[MAX_FILE];
|
char filename[MAX_FILE];
|
||||||
|
|
@ -992,18 +1041,19 @@ static int filename_filter(const struct dirent *dirent)
|
||||||
/* scan all cards and comments */
|
/* scan all cards and comments */
|
||||||
int uc_mgr_scan_master_configs(const char **_list[])
|
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);
|
char *env = getenv(ALSA_CONFIG_UCM_VAR);
|
||||||
const char **list;
|
const char **list;
|
||||||
snd_config_t *cfg, *c;
|
snd_config_t *cfg, *c;
|
||||||
int i, cnt, err;
|
int i, cnt, err;
|
||||||
|
ssize_t ss;
|
||||||
struct dirent **namelist;
|
struct dirent **namelist;
|
||||||
|
|
||||||
snprintf(filename, sizeof(filename)-1,
|
snprintf(filename, sizeof(filename)-1,
|
||||||
"%s", env ? env : ALSA_USE_CASE_DIR);
|
"%s", env ? env : ALSA_USE_CASE_DIR);
|
||||||
filename[MAX_FILE-1] = '\0';
|
filename[MAX_FILE-1] = '\0';
|
||||||
|
|
||||||
err = scandir(filename, &namelist, filename_filter, alphasort);
|
err = scandir(filename, &namelist, filename_filter, versionsort);
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
err = -errno;
|
err = -errno;
|
||||||
uc_error("error: could not scan directory %s: %s",
|
uc_error("error: could not scan directory %s: %s",
|
||||||
|
|
@ -1012,6 +1062,20 @@ int uc_mgr_scan_master_configs(const char **_list[])
|
||||||
}
|
}
|
||||||
cnt = err;
|
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 *));
|
list = calloc(1, cnt * 2 * sizeof(char *));
|
||||||
if (list == NULL) {
|
if (list == NULL) {
|
||||||
err = -ENOMEM;
|
err = -ENOMEM;
|
||||||
|
|
@ -1036,6 +1100,14 @@ int uc_mgr_scan_master_configs(const char **_list[])
|
||||||
err = -ENOMEM;
|
err = -ENOMEM;
|
||||||
goto __err;
|
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;
|
err = cnt * 2;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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[]);
|
int uc_mgr_scan_master_configs(const char **_list[]);
|
||||||
|
|
||||||
void uc_mgr_free_sequence_element(struct sequence_element *seq);
|
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_verb(snd_use_case_mgr_t *uc_mgr);
|
||||||
void uc_mgr_free(snd_use_case_mgr_t *uc_mgr);
|
void uc_mgr_free(snd_use_case_mgr_t *uc_mgr);
|
||||||
|
|
|
||||||
|
|
@ -94,7 +94,8 @@ void uc_mgr_free_value(struct list_head *base)
|
||||||
val = list_entry(pos, struct ucm_value, list);
|
val = list_entry(pos, struct ucm_value, list);
|
||||||
free(val->name);
|
free(val->name);
|
||||||
free(val->data);
|
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) {
|
list_for_each_safe(pos, npos, base) {
|
||||||
dlist = list_entry(pos, struct dev_list, list);
|
dlist = list_entry(pos, struct dev_list, list);
|
||||||
free(dlist->name);
|
free(dlist->name);
|
||||||
|
list_del(&dlist->list);
|
||||||
free(dlist);
|
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) {
|
list_for_each_safe(pos, npos, base) {
|
||||||
seq = list_entry(pos, struct sequence_element, list);
|
seq = list_entry(pos, struct sequence_element, list);
|
||||||
|
list_del(&seq->list);
|
||||||
uc_mgr_free_sequence_element(seq);
|
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)
|
void uc_mgr_free_transition(struct list_head *base)
|
||||||
{
|
{
|
||||||
struct list_head *pos, *npos;
|
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) {
|
list_for_each_safe(pos, npos, base) {
|
||||||
tseq = list_entry(pos, struct transition_sequence, list);
|
tseq = list_entry(pos, struct transition_sequence, list);
|
||||||
free(tseq->name);
|
list_del(&tseq->list);
|
||||||
uc_mgr_free_sequence(&tseq->transition_list);
|
uc_mgr_free_transition_element(tseq);
|
||||||
free(tseq);
|
|
||||||
list_del(pos);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -166,8 +172,8 @@ void uc_mgr_free_modifier(struct list_head *base)
|
||||||
uc_mgr_free_transition(&mod->transition_list);
|
uc_mgr_free_transition(&mod->transition_list);
|
||||||
uc_mgr_free_dev_list(&mod->dev_list);
|
uc_mgr_free_dev_list(&mod->dev_list);
|
||||||
uc_mgr_free_value(&mod->value_list);
|
uc_mgr_free_value(&mod->value_list);
|
||||||
|
list_del(&mod->list);
|
||||||
free(mod);
|
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_sequence(&dev->disable_list);
|
||||||
uc_mgr_free_transition(&dev->transition_list);
|
uc_mgr_free_transition(&dev->transition_list);
|
||||||
uc_mgr_free_value(&dev->value_list);
|
uc_mgr_free_value(&dev->value_list);
|
||||||
|
list_del(&dev->list);
|
||||||
free(dev);
|
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_value(&verb->value_list);
|
||||||
uc_mgr_free_device(&verb->device_list);
|
uc_mgr_free_device(&verb->device_list);
|
||||||
uc_mgr_free_modifier(&verb->modifier_list);
|
uc_mgr_free_modifier(&verb->modifier_list);
|
||||||
|
list_del(&verb->list);
|
||||||
free(verb);
|
free(verb);
|
||||||
list_del(pos);
|
|
||||||
}
|
}
|
||||||
uc_mgr_free_sequence(&uc_mgr->default_list);
|
uc_mgr_free_sequence(&uc_mgr->default_list);
|
||||||
free(uc_mgr->comment);
|
free(uc_mgr->comment);
|
||||||
|
|
|
||||||
24
test/ucm/TestHDA/Case1.conf
Normal file
24
test/ucm/TestHDA/Case1.conf
Normal file
|
|
@ -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"
|
||||||
|
]
|
||||||
|
}
|
||||||
11
test/ucm/TestHDA/TestHDA.conf
Normal file
11
test/ucm/TestHDA/TestHDA.conf
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
Comment "A test HDA card"
|
||||||
|
|
||||||
|
SectionUseCase."Case1" {
|
||||||
|
File "Case1.conf"
|
||||||
|
Comment "Case1 Comment"
|
||||||
|
}
|
||||||
|
|
||||||
|
SectionDefaults [
|
||||||
|
exec "my prg"
|
||||||
|
msleep 1
|
||||||
|
]
|
||||||
Loading…
Add table
Add a link
Reference in a new issue