alsactl init - CTL{values}, CTL{enums} and default "guess method" initialization
authorJaroslav Kysela <perex@perex.cz>
Mon, 18 Aug 2008 13:01:44 +0000 (15:01 +0200)
committerJaroslav Kysela <perex@perex.cz>
Mon, 18 Aug 2008 13:01:44 +0000 (15:01 +0200)
Implemented CTL{values)=value to set all values at once.
Implemented CTL{enums} to match against strings in enum list.
Added 'default' (guess method) initialization configuration.

Signed-off-by: Jaroslav Kysela <perex@perex.cz>

alsactl/alsactl_init.xml
alsactl/init/00main
alsactl/init/default [new file with mode: 0644]
alsactl/init/test
alsactl/init_parse.c

index c902fc8..0e0d46b 100644 (file)
                     </listitem>
                   </varlistentry>
                   <varlistentry>
+                    <term><option>enums</option></term>
+                    <listitem>
+                      <para>Enumerated value - list of text names stored between '|' character</para>
+                    </listitem>
+                  </varlistentry>
+                  <varlistentry>
                     <term><option>value</option></term>
                     <listitem>
                       <para>Value of control stored to a string delimited by
                  next key on line).</para>
               </listitem>
             </varlistentry>
+            <varlistentry>
+              <term><option>CTL{values}</option></term>
+              <listitem>
+                <para>Value is set (written) also to soundcard's control
+                device (all control values are set to specified value) and
+                RESULT key is set to errno code. The result of
+                 set operation is always true (it means continue with
+                 next key on line).</para>
+              </listitem>
+            </varlistentry>
 
             <varlistentry>
               <term><option>ENV{<replaceable>key</replaceable>}</option></term>
index 3d289cb..942f386 100644 (file)
@@ -7,6 +7,7 @@ CONFIG{sysfs_device}="/class/sound/controlC$cardinfo{card}/device"
 # test for extra commands
 ENV{CMD}=="help", INCLUDE="help", GOTO="00main_end"
 ENV{CMD}=="info", INCLUDE="info", GOTO="00main_end"
+ENV{CMD}=="default", INCLUDE="default", GOTO="00main_end"
 ENV{CMD}=="test", INCLUDE="test", GOTO="00main_end"
 ENV{CMD}=="*", ERROR="Unknown command '$env{CMD}'\n", GOTO="00main_end"
 
@@ -17,7 +18,8 @@ ENV{CMD}=="*", ERROR="Unknown command '$env{CMD}'\n", GOTO="00main_end"
 #   2) if RESULT=="skip", skip ALSA standard configuration files
 #   3) do ALSA standard configuration
 #   4) look for postinit subdirectory and parse all files in it
-#   5) if RESULT!="true", print an error message and return with exit code 99
+#   5) if RESULT!="true", initialize hardware using a guess method,
+#      print an error message and return with exit code 99
 #   6) return with exit code 0 (success)
 #
 
@@ -33,7 +35,8 @@ LABEL="init_end"
 ACCESS=="postinit", INCLUDE="postinit"
 RESULT=="true", GOTO="00_mainend"
 ERROR="Unknown hardware: \"$cardinfo{driver}\" \"$cardinfo{mixername}\" \"$cardinfo{components}\" \"$attr{subsystem_vendor}\" \"$attr{subsystem_device}\"\n"
-ERROR="Hardware is left uninitialized\n"
+ERROR="Hardware is initialized using a guess method\n"
+INCLUDE="default"
 EXIT="99"
 
 #
diff --git a/alsactl/init/default b/alsactl/init/default
new file mode 100644 (file)
index 0000000..66692b3
--- /dev/null
@@ -0,0 +1,145 @@
+#
+# Default ALSA volume levels and setting when initialization database fails.
+#
+# Basic rules are:
+#  - keep volumes at minimal level, but sound should be hearable
+#  - enable just main speakers for playback and main microphone for recording
+#
+
+# **************************************************************************
+# playback
+# **************************************************************************
+
+ENV{volume}:="-20dB"
+
+CTL{reset}="mixer"
+CTL{name}="Playback Volume",PROGRAM=="__ctl_search", \
+  CTL{values}="$env{volume}",RESULT!="0",CTL{values}="75%"
+CTL{name}="Playback Switch",PROGRAM=="__ctl_search", \
+  CTL{values}="on"
+
+CTL{reset}="mixer"
+CTL{name}="Master Playback Volume",PROGRAM=="__ctl_search", \
+  CTL{values}="$env{volume}",RESULT!="0",CTL{values}="75%"
+CTL{name}="Master Playback Switch",PROGRAM=="__ctl_search", \
+  CTL{values}="on"
+
+CTL{reset}="mixer"
+CTL{name}="Master Digital Playback Volume",PROGRAM=="__ctl_search", \
+  CTL{values}="$env{volume}",RESULT!="0",CTL{values}="75%"
+CTL{name}="Master Digital Playback Switch",PROGRAM=="__ctl_search", \
+  CTL{values}="on"
+
+CTL{reset}="mixer"
+CTL{name}="Front Playback Volume",PROGRAM=="__ctl_search", \
+  CTL{values}="$env{volume}",RESULT!="0",CTL{values}="75%"
+CTL{name}="Front Playback Switch",PROGRAM=="__ctl_search", \
+  CTL{values}="on"
+
+CTL{reset}="mixer"
+CTL{name}="Headphone Playback Volume",PROGRAM=="__ctl_search", \
+  CTL{values}="$env{volume}",RESULT!="0",CTL{values}="75%"
+CTL{name}="Headphone Playback Switch",PROGRAM=="__ctl_search", \
+  CTL{values}="on"
+
+CTL{reset}="mixer"
+CTL{name}="Speaker Playback Volume",PROGRAM=="__ctl_search", \
+  CTL{values}="$env{volume}",RESULT!="0",CTL{values}="75%"
+CTL{name}="Speaker Playback Switch",PROGRAM=="__ctl_search", \
+  CTL{values}="on"
+
+CTL{reset}="mixer"
+CTL{name}="PC Speaker Playback Volume",PROGRAM=="__ctl_search", \
+  CTL{values}="$env{volume}",RESULT!="0",CTL{values}="75%"
+CTL{name}="PC Speaker Playback Switch",PROGRAM=="__ctl_search", \
+  CTL{values}="on"
+
+CTL{reset}="mixer"
+CTL{name}="PCM Playback Volume",PROGRAM=="__ctl_search", \
+  CTL{values}="$env{volume}",RESULT!="0",CTL{values}="75%"
+CTL{name}="PCM Playback Switch",PROGRAM=="__ctl_search", \
+  CTL{values}="on"
+
+CTL{reset}="mixer"
+CTL{name}="PCM Playback Volume",CTL{index}="1",PROGRAM=="__ctl_search", \
+  CTL{values}="$env{volume}",RESULT!="0",CTL{values}="75%"
+CTL{name}="PCM Playback Switch",CTL{index}="1",PROGRAM=="__ctl_search", \
+  CTL{values}="on"
+
+CTL{reset}="mixer"
+CTL{name}="DAC Playback Volume",PROGRAM=="__ctl_search", \
+  CTL{values}="$env{volume}",RESULT!="0",CTL{values}="75%"
+CTL{name}="DAC Playback Switch",PROGRAM=="__ctl_search", \
+  CTL{values}="on"
+
+CTL{reset}="mixer"
+CTL{name}="Synth Playback Volume",,PROGRAM=="__ctl_search", \
+  CTL{values}="$env{volume}",RESULT!="0",CTL{values}="75%"
+CTL{name}="Synth Playback Switch",PROGRAM=="__ctl_search", \
+  CTL{values}="on"
+
+CTL{reset}="mixer"
+CTL{name}="Wave Playback Volume",PROGRAM=="__ctl_search", \
+  CTL{values}="100%"
+CTL{name}="Wave Playback Switch",PROGRAM=="__ctl_search", \
+  CTL{values}="on"
+
+CTL{reset}="mixer"
+CTL{name}="Music Playback Volume",PROGRAM=="__ctl_search", \
+  CTL{values}="100%"
+CTL{name}="Music Playback Switch",PROGRAM=="__ctl_search", \
+  CTL{values}="on"
+
+CTL{reset}="mixer"
+CTL{name}="CD Playback Volume",PROGRAM=="__ctl_search", \
+  CTL{values}="$env{volume}",RESULT!="0",CTL{values}="75%"
+CTL{name}="CD Playback Switch",PROGRAM=="__ctl_search", \
+  CTL{values}="on"
+
+CTL{reset}="mixer"
+CTL{name}="Mono Playback Volume",PROGRAM=="__ctl_search", \
+  CTL{values}="$env{volume}",RESULT!="0",CTL{values}="75%"
+CTL{name}="Mono Playback Switch",PROGRAM=="__ctl_search", \
+  CTL{values}="on"
+
+CTL{reset}="mixer"
+CTL{name}="Master Mono Playback Volume",PROGRAM=="__ctl_search", \
+  CTL{values}="$env{volume}",RESULT!="0",CTL{values}="75%"
+CTL{name}="Master Mono Playback Switch",PROGRAM=="__ctl_search", \
+  CTL{values}="on"
+
+CTL{reset}="mixer"
+CTL{name}="AC97 Playback Volume",PROGRAM=="__ctl_search", \
+  CTL{values}="100%"
+CTL{name}="AC97 Playback Switch",PROGRAM=="__ctl_search", \
+  CTL{values}="on"
+
+#
+# Powermacs
+#
+
+CTL{reset}="mixer"
+CTL{name}="DRC Range",PROGRAM=="__ctl_search", \
+  CTL{values}="$env{volume}",RESULT!="0",CTL{values}="75%"
+
+# **************************************************************************
+# capture
+# **************************************************************************
+
+ENV{volume}:="20dB"
+
+CTL{reset}="mixer"
+CTL{name}="Capture Volume",PROGRAM=="__ctl_search", \
+  CTL{values}="$env{volume}",RESULT!="0",CTL{values}="75%"
+CTL{name}="Capture Switch",PROGRAM=="__ctl_search", \
+  CTL{values}="on"
+
+CTL{name}="Input Source",PROGRAM=="__ctl_search", \
+  CTL{enums}=="*|Internal Mic|*",CTL{values}="Internal Mic", \
+  GOTO="end_input_source"
+CTL{name}="Input Source",PROGRAM=="__ctl_search", \
+  CTL{enums}=="*|Mic|*",CTL{values}="Mic"
+LABEL="end_input_source"
+
+CTL{name}="Internal Mic Boost",PROGRAM=="__ctl_search", \
+  CTL{values}="on"
index 024787d..26db2a3 100644 (file)
@@ -58,7 +58,6 @@ PRINT="    CTL{device}=\"$ctl{device}\"\n"
 PRINT="    CTL{subdevice}=\"$ctl{subdevice}\"\n"
 PRINT="    CTL{name}=\"$ctl{name}\"\n"
 PRINT="    CTL{index}=\"$ctl{index}\"\n"
-LABEL="skip_switch_search"
 
 PRINT="First ten elements:\n"
 CTL{search}="mixer", CTL{name}="*", PROGRAM!="__ctl_search 0", GOTO="skip_first_ten_search"
@@ -118,7 +117,6 @@ PRINT="    CTL{dBmin}=\"$ctl{dBmin}\"\n"
 PRINT="    CTL{dBmax}=\"$ctl{dBmax}\"\n"
 PRINT="    CTL{items}=\"$ctl{items}\"\n"
 PRINT="    CTL{value}=\"$ctl{value}\"\n"
-LABEL="skip_first_ten_search"
 CTL{search}="mixer", CTL{name}="*", PROGRAM!="__ctl_search 3", GOTO="skip_first_ten_search"
 PRINT="  Element #3:\n"
 PRINT="    CTL{numid}=\"$ctl{numid}\"\n"
@@ -138,7 +136,6 @@ PRINT="    CTL{dBmax}=\"$ctl{dBmax}\"\n"
 PRINT="    CTL{step}=\"$ctl{step}\"\n"
 PRINT="    CTL{items}=\"$ctl{items}\"\n"
 PRINT="    CTL{value}=\"$ctl{value}\"\n"
-LABEL="skip_first_ten_search"
 CTL{search}="mixer", CTL{name}="*", PROGRAM!="__ctl_search 4", GOTO="skip_first_ten_search"
 PRINT="  Element #4:\n"
 PRINT="    CTL{numid}=\"$ctl{numid}\"\n"
@@ -158,7 +155,6 @@ PRINT="    CTL{dBmin}=\"$ctl{dBmin}\"\n"
 PRINT="    CTL{dBmax}=\"$ctl{dBmax}\"\n"
 PRINT="    CTL{items}=\"$ctl{items}\"\n"
 PRINT="    CTL{value}=\"$ctl{value}\"\n"
-LABEL="skip_first_ten_search"
 CTL{search}="mixer", CTL{name}="*", PROGRAM!="__ctl_search 5", GOTO="skip_first_ten_search"
 PRINT="  Element #5:\n"
 PRINT="    CTL{numid}=\"$ctl{numid}\"\n"
@@ -178,7 +174,6 @@ PRINT="    CTL{dBmin}=\"$ctl{dBmin}\"\n"
 PRINT="    CTL{dBmax}=\"$ctl{dBmax}\"\n"
 PRINT="    CTL{items}=\"$ctl{items}\"\n"
 PRINT="    CTL{value}=\"$ctl{value}\"\n"
-LABEL="skip_first_ten_search"
 CTL{search}="mixer", CTL{name}="*", PROGRAM!="__ctl_search 6", GOTO="skip_first_ten_search"
 PRINT="  Element #6:\n"
 PRINT="    CTL{numid}=\"$ctl{numid}\"\n"
@@ -198,7 +193,6 @@ PRINT="    CTL{dBmin}=\"$ctl{dBmin}\"\n"
 PRINT="    CTL{dBmax}=\"$ctl{dBmax}\"\n"
 PRINT="    CTL{items}=\"$ctl{items}\"\n"
 PRINT="    CTL{value}=\"$ctl{value}\"\n"
-LABEL="skip_first_ten_search"
 CTL{search}="mixer", CTL{name}="*", PROGRAM!="__ctl_search 7", GOTO="skip_first_ten_search"
 PRINT="  Element #7:\n"
 PRINT="    CTL{numid}=\"$ctl{numid}\"\n"
@@ -218,7 +212,6 @@ PRINT="    CTL{dBmin}=\"$ctl{dBmin}\"\n"
 PRINT="    CTL{dBmax}=\"$ctl{dBmax}\"\n"
 PRINT="    CTL{items}=\"$ctl{items}\"\n"
 PRINT="    CTL{value}=\"$ctl{value}\"\n"
-LABEL="skip_first_ten_search"
 CTL{search}="mixer", CTL{name}="*", PROGRAM!="__ctl_search 8", GOTO="skip_first_ten_search"
 PRINT="  Element #8:\n"
 PRINT="    CTL{numid}=\"$ctl{numid}\"\n"
@@ -238,7 +231,6 @@ PRINT="    CTL{dBmin}=\"$ctl{dBmin}\"\n"
 PRINT="    CTL{dBmax}=\"$ctl{dBmax}\"\n"
 PRINT="    CTL{items}=\"$ctl{items}\"\n"
 PRINT="    CTL{value}=\"$ctl{value}\"\n"
-LABEL="skip_first_ten_search"
 CTL{search}="mixer", CTL{name}="*", PROGRAM!="__ctl_search 9", GOTO="skip_first_ten_search"
 PRINT="  Element #9:\n"
 PRINT="    CTL{numid}=\"$ctl{numid}\"\n"
@@ -270,7 +262,9 @@ PRINT="Elements write test #2:\n", \
   PRINT="  result=$result\n"
 PRINT="Elements write test #3:\n", \
   CTL{search}="mixer", CTL{name}="Front Playback Volume Error", \
-  PROGRAM="__ctl_search", CTL{value}="32,32", \
-  PRINT="  result=$result\n"
+  PROGRAM="__ctl_search"
+PRINT="  result=$result\n"
+
+#CTL{reset}="mixer", CTL{name}="Input Source", PRINT="***$ctl{enums}\n"
 
 PRINT="\nAll tests done..\n"
index b93cf78..57f9a92 100644 (file)
@@ -335,7 +335,7 @@ static const char *get_ctl_value(struct space *space)
 #define convert_prange1(val, min, max) \
         ceil((val) * ((max) - (min)) * 0.01 + (min))
 
-static int set_ctl_value(struct space *space, const char *value)
+static int set_ctl_value(struct space *space, const char *value, int all)
 {
        snd_ctl_elem_type_t type;
        unsigned int idx, idx2, count, items;
@@ -358,6 +358,8 @@ static int set_ctl_value(struct space *space, const char *value)
                                strncasecmp(value, "on", 2) == 0 ||
                                strncasecmp(value, "1", 1) == 0;
                        snd_ctl_elem_value_set_boolean(space->ctl_value, idx, val);
+                       if (all)
+                               continue;
                        pos = strchr(value, ',');
                        value = pos ? pos + 1 : value + strlen(value) - 1;
                }
@@ -398,6 +400,8 @@ static int set_ctl_value(struct space *space, const char *value)
                        } else {
                                snd_ctl_elem_value_set_integer(space->ctl_value, idx, strtol(value, NULL, 0));
                        }
+                       if (all)
+                               continue;
                        value = pos ? pos + 1 : value + strlen(value) - 1;
                }
                break;
@@ -406,6 +410,8 @@ static int set_ctl_value(struct space *space, const char *value)
                        while (*value == ' ')
                                value++;
                        snd_ctl_elem_value_set_integer64(space->ctl_value, idx, strtoll(value, NULL, 0));
+                       if (all)
+                               continue;
                        pos = strchr(value, ',');
                        value = pos ? pos + 1 : value + strlen(value) - 1;
                }
@@ -440,6 +446,8 @@ static int set_ctl_value(struct space *space, const char *value)
                                        return -EINVAL;
                                }
                        }
+                       if (all)
+                               continue;
                        value = pos ? pos + 1 : value + strlen(value) - 1;
                }
                break;
@@ -478,7 +486,7 @@ static const char *elemid_get(struct space *space, const char *attr)
 {
        long long val;
        snd_ctl_elem_type_t type;
-       static char res[32];
+       static char res[256];
 
        if (strncasecmp(attr, "numid", 5) == 0) {
                val = snd_ctl_elem_id_get_numid(space->ctl_id);
@@ -617,6 +625,27 @@ dbvalue:
                val = max;
                goto dbvalue;
        }
+       if (strncasecmp(attr, "enums", 5) == 0) {
+               unsigned int idx, items;
+               snd_hctl_elem_t *elem;
+               if (check_id_changed(space, 1))
+                       return NULL;
+               if (snd_ctl_elem_info_get_type(space->ctl_info) != SND_CTL_ELEM_TYPE_ENUMERATED)
+                       goto empty;
+               items = snd_ctl_elem_info_get_items(space->ctl_info);
+               strcpy(res, "|");
+               for (idx = 0; idx < items; idx++) {
+                       snd_ctl_elem_info_set_item(space->ctl_info, idx);
+                       elem = snd_hctl_find_elem(space->ctl_handle, space->ctl_id);
+                       if (elem == NULL)
+                               break;
+                       if (snd_hctl_elem_info(elem, space->ctl_info) < 0)
+                               break;
+                       strlcat(res, snd_ctl_elem_info_get_item_name(space->ctl_info), sizeof(res));
+                       strlcat(res, "|", sizeof(res));
+               }
+               return res;
+       }
        Perror(space, "unknown ctl{} attribute '%s'", attr);
        return NULL;
   value:
@@ -684,13 +713,14 @@ static int elemid_set(struct space *space, const char *attr, const char *value)
                fcn = snd_ctl_elem_id_set_index;
                goto value;
        }
-       if (strncasecmp(attr, "value", 5) == 0) {
+       if (strncasecmp(attr, "values", 6) == 0 ||
+           strncasecmp(attr, "value", 5) == 0) {
                err = check_id_changed(space, 1);
                if (err < 0) {
                        Perror(space, "control element not found");
                        return err;
                }
-               err = set_ctl_value(space, value);
+               err = set_ctl_value(space, value, strncasecmp(attr, "values", 6) == 0);
                if (err < 0) {
                        space->ctl_id_changed |= 2;
                } else {
@@ -1244,7 +1274,7 @@ static int parse_line(struct space *space, char *line, size_t linesize)
                
                err = get_key(&linepos, &key, &op, &value);
                if (err < 0)
-                       break;
+                       goto invalid;
 
                if (strncasecmp(key, "LABEL", 5) == 0) {
                        if (op != KEY_OP_ASSIGN) {
@@ -1392,6 +1422,13 @@ static int parse_line(struct space *space, char *line, size_t linesize)
                                dbg("env: '%s' '%s'", attr, temp);
                                if (!do_match(key, op, value, temp))
                                        break;
+                       } else if (op == KEY_OP_ASSIGN ||
+                                  op == KEY_OP_ASSIGN_FINAL) {
+                               strlcpy(result, value, sizeof(result));
+                               apply_format(space, result, sizeof(result));
+                               dbg("env set: '%s' '%s'", attr, result);
+                               if (setenv(attr, result, op == KEY_OP_ASSIGN_FINAL))
+                                       break;
                        } else {
                                Perror(space, "invalid ENV{} operation");
                                goto invalid;