From b8560a6bbbf4d5b2eea20eac52e953dcbe786868 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Thu, 14 Aug 2008 16:46:27 +0200 Subject: [PATCH] alsactl init - restore calls also init on failure The initialization procedure consist from default initialization and state restoration. When restore fails for a reason or the config file contains inaccurate information, then init is called. Also, if something fails (init or restore), a file specified using -r option can be created with description what failed. It can be useful when user space decides to notify user to set the sound driver properly. Signed-off-by: Jaroslav Kysela --- alsactl/alsactl.c | 21 ++-- alsactl/alsactl.h | 22 ++++- alsactl/init_parse.c | 2 +- alsactl/state.c | 227 ++++++++++++++++++++++++++++--------------- alsactl/utils.c | 19 ++++ 5 files changed, 202 insertions(+), 89 deletions(-) diff --git a/alsactl/alsactl.c b/alsactl/alsactl.c index 8d3987a..9d79b47 100644 --- a/alsactl/alsactl.c +++ b/alsactl/alsactl.c @@ -36,6 +36,7 @@ int debugflag = 0; int force_restore = 1; char *command; +char *statefile = NULL; static void help(void) { @@ -49,6 +50,8 @@ static void help(void) printf(" -F,--force try to restore the matching controls as much as possible\n"); printf(" (default mode)\n"); printf(" -P,--pedantic don't restore mismatching controls (old default)\n"); + printf(" -r,--runstate # save restore and init state to this file (only errors)\n"); + printf(" default settings is 'no file set'\n"); printf("\nAvailable init options:\n"); printf(" -E,--env #=# set environment variable for init phase (NAME=VALUE)\n"); printf(" -i,--initfile # main configuation file for init phase (default " DATADIR "/init/00main)\n"); @@ -73,19 +76,21 @@ int main(int argc, char *argv[]) {"initfile", 1, NULL, 'i'}, {"force", 0, NULL, 'F'}, {"pedantic", 0, NULL, 'P'}, + {"runstate", 0, NULL, 'r'}, {"debug", 0, NULL, 'd'}, {"version", 0, NULL, 'v'}, {NULL, 0, NULL, 0}, }; char *cfgfile = SYS_ASOUNDRC; char *initfile = DATADIR "/init/00main"; + char *cardname; int res; command = argv[0]; while (1) { int c; - if ((c = getopt_long(argc, argv, "hdvf:FE:i:", long_option, NULL)) < 0) + if ((c = getopt_long(argc, argv, "hdvf:FE:i:Pr:", long_option, NULL)) < 0) break; switch (c) { case 'h': @@ -106,6 +111,9 @@ int main(int argc, char *argv[]) case 'i': initfile = optarg; break; + case 'r': + statefile = optarg; + break; case 'P': force_restore = 0; break; @@ -129,15 +137,14 @@ int main(int argc, char *argv[]) return 0; } + cardname = argc - optind > 1 ? argv[optind + 1] : NULL; if (!strcmp(argv[optind], "init")) { - res = init(initfile, - argc - optind > 1 ? argv[optind + 1] : NULL); + res = init(initfile, cardname); } else if (!strcmp(argv[optind], "store")) { - res = save_state(cfgfile, - argc - optind > 1 ? argv[optind + 1] : NULL); + res = save_state(cfgfile, cardname); } else if (!strcmp(argv[optind], "restore")) { - res = load_state(cfgfile, - argc - optind > 1 ? argv[optind + 1] : NULL); + remove(statefile); + res = load_state(cfgfile, initfile, cardname); } else if (!strcmp(argv[optind], "names")) { if (!strcmp(cfgfile, SYS_ASOUNDRC)) cfgfile = SYS_ASOUNDNAMES; diff --git a/alsactl/alsactl.h b/alsactl/alsactl.h index 51396da..408b145 100644 --- a/alsactl/alsactl.h +++ b/alsactl/alsactl.h @@ -1,6 +1,7 @@ extern int debugflag; extern int force_restore; extern char *command; +extern char *statefile; #if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 95) #define info(...) do {\ @@ -30,6 +31,24 @@ extern char *command; } while (0) #endif +#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 95) +#define cerror(cond, ...) do {\ + if (cond) { \ + fprintf(stderr, "%s: %s:%d: ", command, __FUNCTION__, __LINE__); \ + fprintf(stderr, __VA_ARGS__); \ + putc('\n', stderr); \ + } \ +} while (0) +#else +#define cerror(cond, args...) do {\ + if (cond) { \ + fprintf(stderr, "%s: %s:%d: ", command, __FUNCTION__, __LINE__); \ + fprintf(stderr, ##args); \ + putc('\n', stderr); \ + } \ +} while (0) +#endif + #if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 95) #define dbg(...) do {\ if (!debugflag) break; \ @@ -48,7 +67,7 @@ extern char *command; int init(const char *file, const char *cardname); int save_state(const char *file, const char *cardname); -int load_state(const char *file, const char *cardname); +int load_state(const char *file, const char *initfile, const char *cardname); int power(const char *argv[], int argc); int generate_names(const char *cfgfile); @@ -57,6 +76,7 @@ int generate_names(const char *cfgfile); int file_map(const char *filename, char **buf, size_t *bufsize); void file_unmap(void *buf, size_t bufsize); size_t line_width(const char *buf, size_t bufsize, size_t pos); +void initfailed(int cardnumber, const char *reason); static inline int hextodigit(int c) { diff --git a/alsactl/init_parse.c b/alsactl/init_parse.c index a9018d8..c4c757b 100644 --- a/alsactl/init_parse.c +++ b/alsactl/init_parse.c @@ -1627,7 +1627,7 @@ static int parse(struct space *space, const char *filename) space->linenum = -1; file_unmap(buf, bufsize); dbg("end of file '%s'", filename); - return err; + return err ? err : -abs(space->exit_code); } int init(const char *filename, const char *cardname) diff --git a/alsactl/state.c b/alsactl/state.c index 90e58cd..554020b 100644 --- a/alsactl/state.c +++ b/alsactl/state.c @@ -665,7 +665,7 @@ static long config_iface(snd_config_t *n) return -1; } -static int config_bool(snd_config_t *n) +static int config_bool(snd_config_t *n, int doit) { const char *str; long val; @@ -686,10 +686,10 @@ static int config_bool(snd_config_t *n) snd_config_get_string(n, &str); break; case SND_CONFIG_TYPE_COMPOUND: - if (!force_restore) + if (!force_restore || !doit) return -1; n = snd_config_iterator_entry(snd_config_iterator_first(n)); - return config_bool(n); + return config_bool(n, doit); default: return -1; } @@ -701,7 +701,7 @@ static int config_bool(snd_config_t *n) } static int config_enumerated(snd_config_t *n, snd_ctl_t *handle, - snd_ctl_elem_info_t *info) + snd_ctl_elem_info_t *info, int doit) { const char *str; long val; @@ -719,10 +719,10 @@ static int config_enumerated(snd_config_t *n, snd_ctl_t *handle, snd_config_get_string(n, &str); break; case SND_CONFIG_TYPE_COMPOUND: - if (!force_restore) + if (!force_restore || !doit) return -1; n = snd_config_iterator_entry(snd_config_iterator_first(n)); - return config_enumerated(n, handle, info); + return config_enumerated(n, handle, info, doit); default: return -1; } @@ -741,26 +741,26 @@ static int config_enumerated(snd_config_t *n, snd_ctl_t *handle, return -1; } -static int config_integer(snd_config_t *n, long *val) +static int config_integer(snd_config_t *n, long *val, int doit) { int err = snd_config_get_integer(n, val); - if (err < 0 && force_restore) { + if (err < 0 && force_restore && doit) { if (snd_config_get_type(n) != SND_CONFIG_TYPE_COMPOUND) return err; n = snd_config_iterator_entry(snd_config_iterator_first(n)); - return config_integer(n, val); + return config_integer(n, val, doit); } return err; } -static int config_integer64(snd_config_t *n, long long *val) +static int config_integer64(snd_config_t *n, long long *val, int doit) { int err = snd_config_get_integer64(n, val); - if (err < 0 && force_restore) { + if (err < 0 && force_restore && doit) { if (snd_config_get_type(n) != SND_CONFIG_TYPE_COMPOUND) return err; n = snd_config_iterator_entry(snd_config_iterator_first(n)); - return config_integer64(n, val); + return config_integer64(n, val, doit); } return err; } @@ -966,10 +966,11 @@ static int check_comment_type(snd_config_t *conf, int type) static int convert_to_new_db(snd_config_t *value, long omin, long omax, long nmin, long nmax, long odbmin, long odbmax, - long ndbmin, long ndbmax) + long ndbmin, long ndbmax, + int doit) { long val; - if (config_integer(value, &val) < 0) + if (config_integer(value, &val, doit) < 0) return -EINVAL; if (val < omin || val > omax) return -EINVAL; @@ -988,7 +989,8 @@ static int convert_to_new_db(snd_config_t *value, long omin, long omax, * if any change occurs, try to keep the same dB level. */ static int check_comment_range(snd_ctl_t *handle, snd_config_t *conf, - snd_ctl_elem_info_t *info, snd_config_t *value) + snd_ctl_elem_info_t *info, snd_config_t *value, + int doit) { snd_config_t *n; long omin, omax, ostep; @@ -1007,7 +1009,7 @@ static int check_comment_range(snd_ctl_t *handle, snd_config_t *conf, nmax = snd_ctl_elem_info_get_max(info); if (omin != nmin && omax != nmax) { /* Hey, the range mismatches */ - if (!force_restore) + if (!force_restore || !doit) return -EINVAL; } if (omin >= omax || nmin >= nmax) @@ -1016,12 +1018,12 @@ static int check_comment_range(snd_ctl_t *handle, snd_config_t *conf, n = search_comment_item(conf, "dbmin"); if (!n) return 0; - if (config_integer(n, &odbmin) < 0) + if (config_integer(n, &odbmin, doit) < 0) return 0; n = search_comment_item(conf, "dbmax"); if (!n) return 0; - if (config_integer(n, &odbmax) < 0) + if (config_integer(n, &odbmax, doit) < 0) return 0; if (odbmin >= odbmax) return 0; /* invalid values */ @@ -1041,18 +1043,19 @@ static int check_comment_range(snd_ctl_t *handle, snd_config_t *conf, snd_config_for_each(i, next, value) { snd_config_t *n = snd_config_iterator_entry(i); convert_to_new_db(n, omin, omax, nmin, nmax, - odbmin, odbmax, ndbmin, ndbmax); + odbmin, odbmax, ndbmin, ndbmax, doit); } } else convert_to_new_db(value, omin, omax, nmin, nmax, - odbmin, odbmax, ndbmin, ndbmax); + odbmin, odbmax, ndbmin, ndbmax, doit); return 0; } static int restore_config_value(snd_ctl_t *handle, snd_ctl_elem_info_t *info, snd_ctl_elem_iface_t type, snd_config_t *value, - snd_ctl_elem_value_t *ctl, int idx) + snd_ctl_elem_value_t *ctl, int idx, + int doit) { long val; long long lval; @@ -1060,28 +1063,28 @@ static int restore_config_value(snd_ctl_t *handle, snd_ctl_elem_info_t *info, switch (type) { case SND_CTL_ELEM_TYPE_BOOLEAN: - val = config_bool(value); + val = config_bool(value, doit); if (val >= 0) { snd_ctl_elem_value_set_boolean(ctl, idx, val); return 1; } break; case SND_CTL_ELEM_TYPE_INTEGER: - err = config_integer(value, &val); + err = config_integer(value, &val, doit); if (err == 0) { snd_ctl_elem_value_set_integer(ctl, idx, val); return 1; } break; case SND_CTL_ELEM_TYPE_INTEGER64: - err = config_integer64(value, &lval); + err = config_integer64(value, &lval, doit); if (err == 0) { snd_ctl_elem_value_set_integer64(ctl, idx, lval); return 1; } break; case SND_CTL_ELEM_TYPE_ENUMERATED: - val = config_enumerated(value, handle, info); + val = config_enumerated(value, handle, info, doit); if (val >= 0) { snd_ctl_elem_value_set_enumerated(ctl, idx, val); return 1; @@ -1091,7 +1094,7 @@ static int restore_config_value(snd_ctl_t *handle, snd_ctl_elem_info_t *info, case SND_CTL_ELEM_TYPE_IEC958: break; default: - error("Unknow control type: %d", type); + cerror(doit, "Unknow control type: %d", type); return -EINVAL; } return 0; @@ -1101,9 +1104,9 @@ static int restore_config_value2(snd_ctl_t *handle, snd_ctl_elem_info_t *info, snd_ctl_elem_iface_t type, snd_config_t *value, snd_ctl_elem_value_t *ctl, int idx, - unsigned int numid) + unsigned int numid, int doit) { - int err = restore_config_value(handle, info, type, value, ctl, idx); + int err = restore_config_value(handle, info, type, value, ctl, idx, doit); long val; if (err != 0) @@ -1113,8 +1116,8 @@ static int restore_config_value2(snd_ctl_t *handle, snd_ctl_elem_info_t *info, case SND_CTL_ELEM_TYPE_IEC958: err = snd_config_get_integer(value, &val); if (err < 0 || val < 0 || val > 255) { - error("bad control.%d.value.%d content", numid, idx); - return force_restore ? 0 : -EINVAL; + cerror(doit, "bad control.%d.value.%d content", numid, idx); + return force_restore && doit ? 0 : -EINVAL; } snd_ctl_elem_value_set_byte(ctl, idx, val); return 1; @@ -1125,7 +1128,8 @@ static int restore_config_value2(snd_ctl_t *handle, snd_ctl_elem_info_t *info, return 0; } -static int set_control(snd_ctl_t *handle, snd_config_t *control) +static int set_control(snd_ctl_t *handle, snd_config_t *control, + int *maxnumid, int doit) { snd_ctl_elem_value_t *ctl; snd_ctl_elem_info_t *info; @@ -1153,15 +1157,17 @@ static int set_control(snd_ctl_t *handle, snd_config_t *control) snd_ctl_elem_value_alloca(&ctl); snd_ctl_elem_info_alloca(&info); if (snd_config_get_type(control) != SND_CONFIG_TYPE_COMPOUND) { - error("control is not a compound"); + cerror(doit, "control is not a compound"); return -EINVAL; } err = snd_config_get_id(control, &id); if (err < 0) { - error("unable to get id"); + cerror(doit, "unable to get id"); return -EINVAL; } numid = atoi(id); + if (numid > *maxnumid) + *maxnumid = numid; snd_config_for_each(i, next, control) { snd_config_t *n = snd_config_iterator_entry(i); const char *fld; @@ -1169,7 +1175,7 @@ static int set_control(snd_ctl_t *handle, snd_config_t *control) continue; if (strcmp(fld, "comment") == 0) { if (snd_config_get_type(n) != SND_CONFIG_TYPE_COMPOUND) { - error("control.%d.%s is invalid", numid, fld); + cerror(doit, "control.%d.%s is invalid", numid, fld); return -EINVAL; } comment = n; @@ -1178,14 +1184,14 @@ static int set_control(snd_ctl_t *handle, snd_config_t *control) if (strcmp(fld, "iface") == 0) { iface = (snd_ctl_elem_iface_t)config_iface(n); if (iface < 0) { - error("control.%d.%s is invalid", numid, fld); + cerror(doit, "control.%d.%s is invalid", numid, fld); return -EINVAL; } continue; } if (strcmp(fld, "device") == 0) { if (snd_config_get_type(n) != SND_CONFIG_TYPE_INTEGER) { - error("control.%d.%s is invalid", numid, fld); + cerror(doit, "control.%d.%s is invalid", numid, fld); return -EINVAL; } snd_config_get_integer(n, &device); @@ -1193,7 +1199,7 @@ static int set_control(snd_ctl_t *handle, snd_config_t *control) } if (strcmp(fld, "subdevice") == 0) { if (snd_config_get_type(n) != SND_CONFIG_TYPE_INTEGER) { - error("control.%d.%s is invalid", numid, fld); + cerror(doit, "control.%d.%s is invalid", numid, fld); return -EINVAL; } snd_config_get_integer(n, &subdevice); @@ -1201,7 +1207,7 @@ static int set_control(snd_ctl_t *handle, snd_config_t *control) } if (strcmp(fld, "name") == 0) { if (snd_config_get_type(n) != SND_CONFIG_TYPE_STRING) { - error("control.%d.%s is invalid", numid, fld); + cerror(doit, "control.%d.%s is invalid", numid, fld); return -EINVAL; } snd_config_get_string(n, &name); @@ -1209,7 +1215,7 @@ static int set_control(snd_ctl_t *handle, snd_config_t *control) } if (strcmp(fld, "index") == 0) { if (snd_config_get_type(n) != SND_CONFIG_TYPE_INTEGER) { - error("control.%d.%s is invalid", numid, fld); + cerror(doit, "control.%d.%s is invalid", numid, fld); return -EINVAL; } snd_config_get_integer(n, &index); @@ -1219,10 +1225,10 @@ static int set_control(snd_ctl_t *handle, snd_config_t *control) value = n; continue; } - error("unknown control.%d.%s field", numid, fld); + cerror(doit, "unknown control.%d.%s field", numid, fld); } if (!value) { - error("missing control.%d.value", numid); + cerror(doit, "missing control.%d.value", numid); return -EINVAL; } if (device < 0) @@ -1233,7 +1239,7 @@ static int set_control(snd_ctl_t *handle, snd_config_t *control) index = 0; err = -EINVAL; - if (! force_restore) { + if (!force_restore) { snd_ctl_elem_info_set_numid(info, numid); err = snd_ctl_elem_info(handle, info); } @@ -1249,7 +1255,7 @@ static int set_control(snd_ctl_t *handle, snd_config_t *control) if (err < 0 && comment && is_user_control(comment)) { err = add_user_control(handle, info, comment); if (err < 0) { - error("failed to add user control #%d (%s)", + cerror(doit, "failed to add user control #%d (%s)", numid, snd_strerror(err)); return err; } @@ -1257,7 +1263,7 @@ static int set_control(snd_ctl_t *handle, snd_config_t *control) } } if (err < 0) { - error("failed to obtain info for control #%d (%s)", numid, snd_strerror(err)); + cerror(doit, "failed to obtain info for control #%d (%s)", numid, snd_strerror(err)); return -ENOENT; } numid1 = snd_ctl_elem_info_get_numid(info); @@ -1268,30 +1274,30 @@ static int set_control(snd_ctl_t *handle, snd_config_t *control) index1 = snd_ctl_elem_info_get_index(info); count = snd_ctl_elem_info_get_count(info); type = snd_ctl_elem_info_get_type(info); - if (err |= numid != numid1 && ! force_restore) - error("warning: numid mismatch (%d/%d) for control #%d", + if (err |= numid != numid1 && !force_restore) + cerror(doit, "warning: numid mismatch (%d/%d) for control #%d", numid, numid1, numid); if (err |= iface != iface1) - error("warning: iface mismatch (%d/%d) for control #%d", iface, iface1, numid); + cerror(doit, "warning: iface mismatch (%d/%d) for control #%d", iface, iface1, numid); if (err |= device != device1) - error("warning: device mismatch (%ld/%ld) for control #%d", device, device1, numid); + cerror(doit, "warning: device mismatch (%ld/%ld) for control #%d", device, device1, numid); if (err |= subdevice != subdevice1) - error("warning: subdevice mismatch (%ld/%ld) for control #%d", subdevice, subdevice1, numid); + cerror(doit, "warning: subdevice mismatch (%ld/%ld) for control #%d", subdevice, subdevice1, numid); if (err |= strcmp(name, name1)) - error("warning: name mismatch (%s/%s) for control #%d", name, name1, numid); + cerror(doit, "warning: name mismatch (%s/%s) for control #%d", name, name1, numid); if (err |= index != index1) - error("warning: index mismatch (%ld/%ld) for control #%d", index, index1, numid); + cerror(doit, "warning: index mismatch (%ld/%ld) for control #%d", index, index1, numid); if (err < 0) { - error("failed to obtain info for control #%d (%s)", numid, snd_strerror(err)); + cerror(doit, "failed to obtain info for control #%d (%s)", numid, snd_strerror(err)); return -ENOENT; } if (comment) { if (check_comment_type(comment, type) < 0) - error("incompatible field type for control #%d", numid); + cerror(doit, "incompatible field type for control #%d", numid); if (type == SND_CTL_ELEM_TYPE_INTEGER) { - if (check_comment_range(handle, comment, info, value) < 0) { - error("value range mismatch for control #%d", + if (check_comment_range(handle, comment, info, value, doit) < 0) { + cerror(doit, "value range mismatch for control #%d", numid); return -EINVAL; } @@ -1304,7 +1310,7 @@ static int set_control(snd_ctl_t *handle, snd_config_t *control) snd_ctl_elem_value_set_numid(ctl, numid1); if (count == 1) { - err = restore_config_value(handle, info, type, value, ctl, 0); + err = restore_config_value(handle, info, type, value, ctl, 0, doit); if (err < 0) return err; if (err > 0) @@ -1323,13 +1329,13 @@ static int set_control(snd_ctl_t *handle, snd_config_t *control) int size = type == SND_CTL_ELEM_TYPE_BYTES ? count : sizeof(snd_aes_iec958_t); if (size * 2 != len) { - error("bad control.%d.value contents\n", numid); + cerror(doit, "bad control.%d.value contents\n", numid); return -EINVAL; } while (*buf) { int c = *buf++; if ((c = hextodigit(c)) < 0) { - error("bad control.%d.value contents\n", numid); + cerror(doit, "bad control.%d.value contents\n", numid); return -EINVAL; } if (idx % 2 == 1) @@ -1345,13 +1351,13 @@ static int set_control(snd_ctl_t *handle, snd_config_t *control) break; } if (snd_config_get_type(value) != SND_CONFIG_TYPE_COMPOUND) { - if (!force_restore) { - error("bad control.%d.value type", numid); + if (!force_restore || !doit) { + cerror(doit, "bad control.%d.value type", numid); return -EINVAL; } for (idx = 0; idx < count; ++idx) { err = restore_config_value2(handle, info, type, value, - ctl, idx, numid); + ctl, idx, numid, doit); if (err < 0) return err; } @@ -1368,13 +1374,13 @@ static int set_control(snd_ctl_t *handle, snd_config_t *control) idx = atoi(id); if (idx < 0 || idx >= count || set[idx]) { - error("bad control.%d.value index", numid); - if (!force_restore) + cerror(doit, "bad control.%d.value index", numid); + if (!force_restore || !doit) return -EINVAL; continue; } err = restore_config_value2(handle, info, type, n, - ctl, idx, numid); + ctl, idx, numid, doit); if (err < 0) return err; if (err > 0) @@ -1382,14 +1388,14 @@ static int set_control(snd_ctl_t *handle, snd_config_t *control) } for (idx = 0; idx < count; ++idx) { if (!set[idx]) { - error("control.%d.value.%d is not specified", numid, idx); - if (!force_restore) + cerror(doit, "control.%d.value.%d is not specified", numid, idx); + if (!force_restore || !doit) return -EINVAL; } } _ok: - err = snd_ctl_elem_write(handle, ctl); + err = doit ? snd_ctl_elem_write(handle, ctl) : 0; if (err < 0) { error("Cannot write control '%d:%ld:%ld:%s:%ld' : %s", (int)iface, device, subdevice, name, index, snd_strerror(err)); return err; @@ -1397,13 +1403,13 @@ static int set_control(snd_ctl_t *handle, snd_config_t *control) return 0; } -static int set_controls(int card, snd_config_t *top) +static int set_controls(int card, snd_config_t *top, int doit) { snd_ctl_t *handle; snd_ctl_card_info_t *info; snd_config_t *control; snd_config_iterator_t i, next; - int err; + int err, maxnumid; char name[32], tmpid[16]; const char *id; snd_ctl_card_info_alloca(&info); @@ -1435,16 +1441,32 @@ static int set_controls(int card, snd_config_t *top) id = tmpid; } if (snd_config_get_type(control) != SND_CONFIG_TYPE_COMPOUND) { - error("state.%s.control is not a compound\n", id); + cerror(doit, "state.%s.control is not a compound\n", id); return -EINVAL; } snd_config_for_each(i, next, control) { snd_config_t *n = snd_config_iterator_entry(i); - err = set_control(handle, n); - if (err < 0 && ! force_restore) + err = set_control(handle, n, &maxnumid, doit); + if (err < 0 && (!force_restore || !doit)) goto _close; } + /* check if we have additional controls in driver */ + /* in this case we should go through init procedure */ + if (!doit) { + snd_ctl_elem_id_t *id; + snd_ctl_elem_info_t *info; + snd_ctl_elem_id_alloca(&id); + snd_ctl_elem_info_alloca(&info); + snd_ctl_elem_info_set_numid(info, maxnumid+1); + if (snd_ctl_elem_info(handle, info) == 0) { + /* not very informative */ + /* but value is used for check only */ + err = -EAGAIN; + goto _close; + } + } + _close: snd_ctl_close(handle); return err; @@ -1522,9 +1544,9 @@ int save_state(const char *file, const char *cardname) return 0; } -int load_state(const char *file, const char *cardname) +int load_state(const char *file, const char *initfile, const char *cardname) { - int err; + int err, finalerr = 0; snd_config_t *config; snd_input_t *in; int stdio; @@ -1547,12 +1569,35 @@ int load_state(const char *file, const char *cardname) return err; } } else { + int card, first = 1; + char cardname1[16]; + error("Cannot open %s for reading: %s", file, snd_strerror(err)); - return err; + finalerr = err; + card = -1; + /* find each installed soundcards */ + while (1) { + if (snd_card_next(&card) < 0) + break; + if (card < 0) + break; + first = 0; + sprintf(cardname1, "%i", card); + err = init(initfile, cardname1); + if (err < 0) { + finalerr = err; + initfailed(card, "init"); + } + initfailed(card, "restore"); + } + if (!first) + finalerr = 0; /* no cards, no error code */ + return finalerr; } if (!cardname) { int card, first = 1; + char cardname1[16]; card = -1; /* find each installed soundcards */ @@ -1567,8 +1612,20 @@ int load_state(const char *file, const char *cardname) break; } first = 0; - if ((err = set_controls(card, config)) && ! force_restore) - return err; + /* do a check if controls matches state file */ + if (set_controls(card, config, 0)) { + sprintf(cardname1, "%i", card); + err = init(initfile, cardname1); + if (err < 0) { + initfailed(card, "init"); + finalerr = err; + } + } + if ((err = set_controls(card, config, 1))) { + if (!force_restore) + finalerr = err; + initfailed(card, "restore"); + } } } else { int cardno; @@ -1578,9 +1635,19 @@ int load_state(const char *file, const char *cardname) error("Cannot find soundcard '%s'...", cardname); return -ENODEV; } - if ((err = set_controls(cardno, config)) && ! force_restore) { - return err; + /* do a check if controls matches state file */ + if (set_controls(cardno, config, 0)) { + err = init(initfile, cardname); + if (err < 0) { + initfailed(cardno, "init"); + return err; + } + } + if ((err = set_controls(cardno, config, 1))) { + initfailed(cardno, "restore"); + if (!force_restore) + return err; } } - return 0; + return finalerr; } diff --git a/alsactl/utils.c b/alsactl/utils.c index eb22ecc..ab4dbd4 100644 --- a/alsactl/utils.c +++ b/alsactl/utils.c @@ -30,6 +30,7 @@ #include #include +#include #include "alsactl.h" int file_map(const char *filename, char **buf, size_t *bufsize) @@ -77,3 +78,21 @@ size_t line_width(const char *buf, size_t bufsize, size_t pos) return count - pos; } + +void initfailed(int cardnumber, const char *reason) +{ + int fp; + char *str; + + if (statefile == NULL) + return; + if (snd_card_get_name(cardnumber, &str) < 0) + return; + fp = open(statefile, O_WRONLY|O_CREAT|O_APPEND, 0644); + write(fp, str, strlen(str)); + write(fp, ":", 1); + write(fp, reason, strlen(reason)); + write(fp, "\n", 1); + close(fp); + free(str); +}