aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2013-01-23 12:47:11 +0100
committerTakashi Iwai <tiwai@suse.de>2013-01-23 12:52:36 +0100
commit85559967d8a51734d60ba363583257efffcf4195 (patch)
tree03e1f341718bd747d06a4d17dd20b6c851b4d516
parentdbf10856e5c3b03870aacd73929ffb21b6aada4a (diff)
downloadhda-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--README12
-rw-r--r--hda-ctlsh.c45
-rw-r--r--hda-emu.c60
-rw-r--r--hda-parse.c54
-rw-r--r--include/hda-log.h3
-rw-r--r--include/hda-types.h13
-rw-r--r--snd-wrapper.c150
7 files changed, 291 insertions, 46 deletions
diff --git a/README b/README
index b1c5998..4d098a9 100644
--- a/README
+++ b/README
@@ -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);
}
diff --git a/hda-emu.c b/hda-emu.c
index c9efbaa..aa58b58 100644
--- a/hda-emu.c
+++ b/hda-emu.c
@@ -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;
}