diff options
author | Takashi Iwai <tiwai@suse.de> | 2013-01-23 12:47:11 +0100 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2013-01-23 12:52:36 +0100 |
commit | 85559967d8a51734d60ba363583257efffcf4195 (patch) | |
tree | 03e1f341718bd747d06a4d17dd20b6c851b4d516 | |
parent | dbf10856e5c3b03870aacd73929ffb21b6aada4a (diff) | |
download | hda-emu-85559967d8a51734d60ba363583257efffcf4195.tar.gz |
Add handling of sysfs hints
Also add -H option to give the initial hints.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
-rw-r--r-- | README | 12 | ||||
-rw-r--r-- | hda-ctlsh.c | 45 | ||||
-rw-r--r-- | hda-emu.c | 60 | ||||
-rw-r--r-- | hda-parse.c | 54 | ||||
-rw-r--r-- | include/hda-log.h | 3 | ||||
-rw-r--r-- | include/hda-types.h | 13 | ||||
-rw-r--r-- | snd-wrapper.c | 150 |
7 files changed, 291 insertions, 46 deletions
@@ -366,6 +366,11 @@ ADVANCED COMMANDS send: NID=0x24, VERB=0x71c(set_config_def_0), PARM=0xf0 ... + > fs set hints jack_detect=false + + > fs get hints + jack_detect = false + > fs set reconfig 1 @@ -397,8 +402,8 @@ though. You can toggle color/non-color behavior via -C and -M options, respectively. -INITIAL PIN-CONFIGURATION -------------------------- +INITIAL PIN-CONFIGURATION AND HINTS +----------------------------------- As default, hda-emu takes the default pin-configurations as set in the given codec proc file (or the proc file content in the given @@ -417,6 +422,9 @@ sysfs files in the input file. The file must contain a pair of register and pin-config value in each line just like in *_pin_configs sysfs files. +Similarly, you can give the initial hints strings either from sysfs +file in alsa-info.sh output or an external file via -H option. + If you want to debug a certain jack-plug state at the initial time, pass the pin NID to turn on via -j option. When nothing is set, all pins are assumed to be unplugged at the start up. diff --git a/hda-ctlsh.c b/hda-ctlsh.c index b00cd0e..64f225e 100644 --- a/hda-ctlsh.c +++ b/hda-ctlsh.c @@ -630,35 +630,18 @@ static void help(char *buf) } #ifdef CONFIG_SND_HDA_RECONFIG -struct hda_codec; - -const char *snd_hda_get_hint(struct hda_codec *codec, const char *key) -{ - return NULL; -} - -int snd_hda_get_bool_hint(struct hda_codec *codec, const char *key) -{ - return -ENOENT; -} - -int snd_hda_get_int_hint(struct hda_codec *codec, const char *key, int *valp) -{ - return -ENOENT; -} - #ifdef HAVE_USER_PINCFGS -static void get_drv_pincfgs(void) +static void get_drv_pincfgs(char *line) { hda_log_show_driver_pin_configs(); } -static void get_init_pincfgs(void) +static void get_init_pincfgs(char *line) { hda_log_show_init_pin_configs(); } -static void get_user_pincfgs(void) +static void get_user_pincfgs(char *line) { hda_log_show_user_pin_configs(); } @@ -676,7 +659,17 @@ static void set_user_pincfgs(char *line) } #endif /* HAVE_USER_PINCFGS */ -static void get_not_yet(void) +static void get_hints(char *line) +{ + hda_log_show_hints(*line ? line : NULL); +} + +static void set_hints(char *line) +{ + hda_log_set_hints(line); +} + +static void get_not_yet(char *line) { hda_log(HDA_LOG_ERR, "Not implemented yet\n"); } @@ -697,8 +690,6 @@ static void reconfig_codec(char *line) hda_codec_reconfig(); } -#define get_hints get_not_yet -#define set_hints set_not_yet #define get_vendor_id get_not_yet #define set_vendor_id set_not_yet #define get_subsystem_id get_not_yet @@ -708,7 +699,7 @@ static void reconfig_codec(char *line) struct sysfs_entry { const char *name; - void (*get)(void); + void (*get)(char *line); void (*set)(char *line); }; @@ -747,7 +738,7 @@ static struct sysfs_entry *find_sysfs_entry(char *file) return NULL; } -static void get_sysfs(char *file) +static void get_sysfs(char *file, char *line) { struct sysfs_entry *s; s = find_sysfs_entry(file); @@ -757,7 +748,7 @@ static void get_sysfs(char *file) hda_log(HDA_LOG_INFO, "%s has no read premission\n", file); return; } - s->get(); + s->get(line); } static void set_sysfs(char *file, char *line) @@ -797,7 +788,7 @@ static void handle_sysfs(char *line) if (!file) goto error; if (*cmd == 'g') - get_sysfs(file); + get_sysfs(file, line); else set_sysfs(file, line); } @@ -560,6 +560,19 @@ void hda_log_set_user_pin_configs(unsigned int nid, unsigned int cfg) } #endif /* HAVE_USER_PINCFGS */ +extern int _show_hints(struct hda_codec *codec, const char *key); +extern int _parse_hints(struct hda_codec *codec, const char *buf); + +void hda_log_show_hints(char *hint) +{ + _show_hints(_codec, hint); +} + +void hda_log_set_hints(char *hint) +{ + _parse_hints(_codec, hint); +} + #endif /* CONFIG_SND_HDA_RECONFIG */ /* @@ -1012,10 +1025,11 @@ static int override_pincfg(struct xhda_codec *codec, char *pincfg) struct xhda_sysfs_list *sys; for (sys = codec->sysfs_list; sys; sys = sys->next) { - if (!strcmp(sys->id, pincfg)) { + if (sys->type == XHDA_SYS_PINCFG && + !strcmp(sys->id, pincfg)) { struct xhda_sysfs_value *val; hda_log(HDA_LOG_INFO, "Overriding pin-configs via %s\n", pincfg); - for (val = sys->entry; val; val = val->next) + for (val = sys->entry.vals; val; val = val->next) set_pincfg(codec, val->val[0], val->val[1]); return 0; } @@ -1038,6 +1052,36 @@ static int override_pincfg(struct xhda_codec *codec, char *pincfg) return 0; } +static int load_init_hints(struct xhda_codec *codec, char *hints) +{ + FILE *fp; + char buf[256]; + struct xhda_sysfs_list *sys; + + for (sys = codec->sysfs_list; sys; sys = sys->next) { + if (sys->type == XHDA_SYS_HINTS && + !strcmp(sys->id, hints)) { + struct xhda_sysfs_hints *val; + hda_log(HDA_LOG_INFO, "Add hints from %s\n", hints); + for (val = sys->entry.hints; val; val = val->next) + _parse_hints(_codec, val->line); + return 0; + } + } + + /* if not found in the given input, try to open it */ + fp = fopen(hints, "r"); + if (!fp) { + hda_log(HDA_LOG_ERR, "Cannot find hints %s\n", hints); + return -EINVAL; + } + hda_log(HDA_LOG_INFO, "Add hints from file %s\n", hints); + while (fgets(buf, sizeof(buf), fp)) + _parse_hints(_codec, buf); + fclose(fp); + return 0; +} + /* */ static void usage(void) @@ -1056,6 +1100,7 @@ static void usage(void) fprintf(stderr, " -F print prefixes to messages\n"); fprintf(stderr, " -a issues SIGTRAP at codec errors\n"); fprintf(stderr, " -P pincfg initialize pin-configuration from sysfs entry\n"); + fprintf(stderr, " -H hints add initial hints from sysfs entry or file\n"); fprintf(stderr, " -j NID turn on the initial jack-state of the given pin\n"); } @@ -1099,10 +1144,11 @@ int main(int argc, char **argv) struct hda_bus_template temp; struct hda_codec *codec; char *init_pincfg = NULL; + char *init_hints = NULL; int num_active_jacks = 0; unsigned int active_jacks[16]; - while ((c = getopt(argc, argv, "al:i:p:m:do:qCMFP:j:")) != -1) { + while ((c = getopt(argc, argv, "al:i:p:m:do:qCMFP:H:j:")) != -1) { switch (c) { case 'a': hda_log_trap_on_error = 1; @@ -1141,6 +1187,9 @@ int main(int argc, char **argv) case 'P': init_pincfg = optarg; break; + case 'H': + init_hints = optarg; + break; case 'j': if (num_active_jacks >= ARRAY_SIZE(active_jacks)) { fprintf(stderr, "Too many -j options given\n"); @@ -1266,6 +1315,11 @@ int main(int argc, char **argv) snd_array_init(&codec->user_pins, sizeof(struct hda_pincfg), 16); #endif + if (init_hints) { + if (load_init_hints(&proc, init_hints) < 0) + return 1; + } + #ifdef HAVE_HDA_PATCH_LOADER snd_hda_codec_configure(codec); #endif diff --git a/hda-parse.c b/hda-parse.c index c75b03b..9c49a31 100644 --- a/hda-parse.c +++ b/hda-parse.c @@ -511,10 +511,27 @@ static int add_sysfs_list(struct xhda_codec *codec, int *vals) memcpy(item->val, vals, sizeof(item->val)); item->next = NULL; - if (!codec->sysfs_list->entry) - codec->sysfs_list->entry = item; + if (!codec->sysfs_list->entry.vals) + codec->sysfs_list->entry.vals = item; else { - for (p = codec->sysfs_list->entry; p->next; p = p->next) + for (p = codec->sysfs_list->entry.vals; p->next; p = p->next) + ; + p->next = item; + } + return 0; +} + +static int add_sysfs_hint(struct xhda_codec *codec, char *line) +{ + struct xhda_sysfs_hints *item = xalloc(sizeof(*item)); + struct xhda_sysfs_hints *p; + + item->line = strdup(line); + item->next = NULL; + if (!codec->sysfs_list->entry.hints) + codec->sysfs_list->entry.hints = item; + else { + for (p = codec->sysfs_list->entry.hints; p->next; p = p->next) ; p->next = item; } @@ -534,27 +551,42 @@ static int do_parse_sysfs(struct xhda_codec *codec, char *buffer) p = strchr(sys->id, ':'); if (p) *p = 0; + p = strchr(sys->id, '/'); + if (!p) { + free(sys->id); + free(sys); + return 0; + } + if (!strcmp(p + 1, "init_verbs")) + sys->type = XHDA_SYS_VERBS; + else if (!strcmp(p + 1, "hints")) + sys->type = XHDA_SYS_HINTS; + else + sys->type = XHDA_SYS_PINCFG; hda_log(HDA_LOG_INFO, "Adding sysfs entry %s\n", sys->id); sys->next = codec->sysfs_list; - sys->entry = NULL; + sys->entry.vals = NULL; codec->sysfs_list = sys; return 0; } - if (isdigit(*buffer)) { - char *p; + if (strchr(buffer, '=')) { + add_sysfs_hint(codec, buffer); + } else if (isdigit(*buffer)) { int val[3]; if (!codec->sysfs_list) return 0; - p = strchr(codec->sysfs_list->id, '/'); - if (!p) - return 0; - if (!strcmp(p + 1, "init_verbs")) { + switch (codec->sysfs_list->type) { + case XHDA_SYS_VERBS: if (sscanf(buffer, "%i %i %i", &val[0], &val[1], &val[2]) != 3) return 0; - } else { + break; + case XHDA_SYS_PINCFG: if (sscanf(buffer, "%i %i", &val[0], &val[1]) != 2) return 0; val[2] = 0; + break; + default: + return 0; } add_sysfs_list(codec, val); return 0; diff --git a/include/hda-log.h b/include/hda-log.h index 3bcaaf6..fcdf737 100644 --- a/include/hda-log.h +++ b/include/hda-log.h @@ -69,4 +69,7 @@ void hda_log_show_user_pin_configs(void); void hda_log_set_user_pin_configs(unsigned int nid, unsigned int cfg); #endif /* HAVE_USER_PINCFGS */ +void hda_log_show_hints(char *hint); +void hda_log_set_hints(char *hint); + #endif /* __HDA_LOG_H */ diff --git a/include/hda-types.h b/include/hda-types.h index 325b223..0db0839 100644 --- a/include/hda-types.h +++ b/include/hda-types.h @@ -83,10 +83,21 @@ struct xhda_sysfs_value { struct xhda_sysfs_value *next; }; +struct xhda_sysfs_hints { + char *line; + struct xhda_sysfs_hints *next; +}; + +enum { XHDA_SYS_PINCFG, XHDA_SYS_VERBS, XHDA_SYS_HINTS }; + struct xhda_sysfs_list { char *id; struct xhda_sysfs_list *next; - struct xhda_sysfs_value *entry; + int type; + union { + struct xhda_sysfs_value *vals; + struct xhda_sysfs_hints *hints; + } entry; }; struct xhda_codec { diff --git a/snd-wrapper.c b/snd-wrapper.c index 11d8324..ebca9f0 100644 --- a/snd-wrapper.c +++ b/snd-wrapper.c @@ -20,6 +20,7 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#include <ctype.h> #include <sound/driver.h> #include <sound/core.h> #include <sound/pcm.h> @@ -44,16 +45,161 @@ int snd_pcm_format_width(int format) } } +/* hint string pair */ +struct hda_hint { + const char *key; + const char *val; /* contained in the same alloc as key */ +}; + +static char *skip_spaces(const char *p) +{ + while (*p && isspace(*p)) + p++; + return (char *)p; +} + +static void remove_trail_spaces(char *str) +{ + char *p; + if (!*str) + return; + p = str + strlen(str) - 1; + for (; isspace(*p); p--) { + *p = 0; + if (p == str) + return; + } +} + +static struct hda_hint *get_hint(struct hda_codec *codec, const char *key) +{ + int i; + + for (i = 0; i < codec->hints.used; i++) { + struct hda_hint *hint = snd_array_elem(&codec->hints, i); + if (!strcmp(hint->key, key)) + return hint; + } + return NULL; +} + +#define MAX_HINTS 1024 + +int _parse_hints(struct hda_codec *codec, const char *buf) +{ + char *key, *val; + struct hda_hint *hint; + int err = 0; + + buf = skip_spaces(buf); + if (!*buf || *buf == '#' || *buf == '\n') + return 0; + if (*buf == '=') + return -EINVAL; + key = strdup(buf); + if (!key) + return -ENOMEM; + val = strrchr(buf, '\n'); + if (val) + *val = 0; + /* extract key and val */ + val = strchr(key, '='); + if (!val) { + kfree(key); + return -EINVAL; + } + *val++ = 0; + val = skip_spaces(val); + remove_trail_spaces(key); + remove_trail_spaces(val); + hint = get_hint(codec, key); + if (hint) { + /* replace */ + free((void *)hint->key); + hint->key = key; + hint->val = val; + return 0; + } + /* allocate a new hint entry */ + if (codec->hints.used >= MAX_HINTS) + hint = NULL; + else + hint = snd_array_new(&codec->hints); + if (hint) { + hint->key = key; + hint->val = val; + } else { + err = -ENOMEM; + } + if (err) + free(key); + return err; +} + +int _show_hints(struct hda_codec *codec, const char *key) +{ + int i; + + for (i = 0; i < codec->hints.used; i++) { + struct hda_hint *hint = snd_array_elem(&codec->hints, i); + if (!key || !strcmp(hint->key, key)) + hda_log(HDA_LOG_INFO, "%s = %s\n", hint->key, hint->val); + } + return 0; +} + +const char *snd_hda_get_hint(struct hda_codec *codec, const char *key) +{ + struct hda_hint *hint = get_hint(codec, key); + return hint ? hint->val : NULL; +} + +int snd_hda_get_bool_hint(struct hda_codec *codec, const char *key) +{ + const char *p; + int ret; + + p = snd_hda_get_hint(codec, key); + if (!p || !*p) + ret = -ENOENT; + else { + switch (toupper(*p)) { + case 'T': /* true */ + case 'Y': /* yes */ + case '1': + ret = 1; + break; + default: + ret = 0; + break; + } + } + return ret; +} + +int snd_hda_get_int_hint(struct hda_codec *codec, const char *key, int *valp) +{ + const char *p; + int ret; + + p = snd_hda_get_hint(codec, key); + if (!p) + ret = -ENOENT; + else { + *valp = strtoul(p, NULL, 0); + ret = 0; + } + return ret; +} + int snd_hda_create_hwdep(struct hda_codec *codec) { #ifdef HAVE_CODEC_USER_MUTEX mutex_init(&codec->user_mutex); #endif -#if 0 snd_array_init(&codec->init_verbs, sizeof(struct hda_verb), 32); snd_array_init(&codec->hints, sizeof(struct hda_hint), 32); snd_array_init(&codec->user_pins, sizeof(struct hda_pincfg), 16); -#endif return 0; } |