home *** CD-ROM | disk | FTP | other *** search
/ Chip 2000 May / Chip_2000-05_cd2.bin / suse / inst-sys / lib / YaST2 / clients / sound.ycp < prev    next >
Encoding:
Text File  |  2000-03-30  |  49.2 KB  |  1,721 lines

  1. /**
  2.  *
  3.  * $Id: sound.ycp,v 1.59.4.2 2000/03/24 10:51:55 gs Exp $
  4.  *
  5.  * Module:        sound.ycp      
  6.  *
  7.  * Author:         Dan VeselĀ²
  8.  *
  9.  *
  10.  * Purpose:        Installation of the sound card. If the sound card was not auto-detected ask user.
  11.  *             
  12.  *
  13.  * user_settings:     
  14.  * 
  15.  * ro: "audio_file"         full path to "au" audio file for testing
  16.  * ro: "conf_modules"       full path to "/etc/conf.modules" file ("/etc/modules.conf")
  17.  * ro: "snd-pcm-oss"        name of Alsa module for OSS compatibility (in older versions "snd-pcm1-oss")
  18.  * ro: "snd_index"        first number of snd_index option (alsa 0.4.0 == 1; alsa 0.5.1 == 0)
  19.  *
  20.  * "rw" read/write
  21.  * "ro" readonly 
  22.  *
  23.  */
  24.  
  25. {
  26.     
  27.   // Menuentry for the YaST2 menu
  28.   if (Args() == [ "get_menuentry" ]) 
  29.     return [ "sound", $[
  30.             `menuentry    : UI(_("Hardware/Sound")),
  31.             `arguments    : [ ],
  32.             `widget       : `RichText(
  33.                           UI(_("Launch this module to configure your sound card."))
  34.                              +
  35.                           UI(_("<p>You need to be logged in as <i>root</i> in order to do this.</p>"))),
  36.             `codefragment : nil ]
  37.     ];
  38.   
  39.   map user_settings = $["audio_file"  : "/usr/share/sounds/alsa/whistle.au",
  40.       "conf_modules" : "/etc/modules.conf",
  41.       "snd-pcm-oss"  : "snd-pcm-oss",
  42.       "snd_index"    : 0];
  43.     
  44.  
  45.     
  46.   SCR(``{            // reads/writes lines from file, deletes blank lines
  47.     MountAgent (`anyagent(
  48.       ``Description (
  49.     ``File("/etc/modules.conf"),         // real file name
  50.     "\n",                     // Comment
  51.     false,                     // read-only
  52.     ``List (
  53.       String ("^\n"),
  54.       "\n"
  55.       )
  56.     )
  57.       ), .lines);
  58.  
  59.   });
  60.   
  61.   UI(``{
  62.  
  63.  
  64.     // The main dialog. Copied from installation.ycp.
  65.     OpenDialog(`opt(`defaultsize),
  66.     `VBox(`Image(`suseheader, "SuSE"),
  67.         `HBox(`HWeight(30, `RichText(`id(`help), "")),
  68.         `HWeight(70, `VBox(
  69.           `Left(`Heading(`id(`title), _("YaST2\nInitializing ..."))),
  70.           `HVCenter(`ReplacePoint(`id(`contents), `Empty())),
  71.           `HBox(
  72.             // back pushbutton: the user input is ignored and the last dialog is called
  73.             `PushButton(`id(`back), `opt(`disabled), _("&Back")),
  74.             `HStretch(),
  75.             // next pushbutton: the user input is checked and the next dialog is called
  76.             `PushButton(`id(`next), `opt(`disabled), _("&Next"))))))));
  77.     
  78.     define SetContents(string title, term contents, string helptext,
  79.     boolean has_back, boolean has_next) ``{
  80.       ChangeWidget(`id(`next), `Enabled, has_next);
  81.       ChangeWidget(`id(`back), `Enabled, has_back);
  82.       ChangeWidget(`id(`help), `Value, helptext);
  83.       ChangeWidget(`id(`title), `Value, title);
  84.       ReplaceWidget(`id(`contents), contents);
  85.       // ControlWidget(TheWizardDialog(), `id(`next), `SetFocus());
  86.     };
  87.  
  88.     // This is a popup dialog for displaying (usually) error messages      
  89.     define DisplayMessage(string message, integer code, string stack) ``{
  90.       // ok pushbutton: confirm the dialog
  91.       term t = `VBox();
  92.       t = add(t, `Left(`Label(message)));
  93.       if (code != 0)
  94.     // optional warning dialog text
  95.     t = add(t, `Left(`Label(sformat(_("Error code %1"), code))));
  96.       if (stack != "") 
  97.     t = add(t, `Left(`Label(stack)));
  98.       OpenDialog(`opt(`decorated), add(t, `PushButton(_("&OK"))));
  99.       UserInput();
  100.       CloseDialog();
  101.     };
  102.  
  103.     // This is a popup dialog with Yes/No question
  104.     define DisplayYesNo(string message) ``{
  105.  
  106.       term t = `VBox();
  107.       t = add(t, `Left(`Label(message)));
  108.       term b = `HBox (
  109.               `PushButton(`id(`yes), _("&Yes")),
  110.               `PushButton(`id(`no), `opt (`default), _("&No"))
  111.               );
  112.       OpenDialog(`opt(`decorated), add(t, b));
  113.       any ret = UserInput();
  114.       CloseDialog();
  115.  
  116.       if (ret == `yes)
  117.     return 1;
  118.       else return 0;
  119.       //return (ret == `yes);
  120.       
  121.     };
  122.  
  123.   });
  124.   
  125.   // creates list [`item (`id(0), <element>), `item (`id (1), <element>), ...] where sel is marked with true
  126.   // these items are usable in the selection boxes
  127.   define index_list (list l, integer sel) ``{
  128.     integer i = 0;
  129.     list new_l = [];
  130.     integer s = size (l);
  131.     while (i < s) {
  132.       new_l = add (new_l,`item (`id(i), select (l, i), (i == sel)));
  133.       i = i + 1;
  134.     }
  135.       
  136.     return new_l;
  137.   };
  138.  
  139.   // contatenates two lists (both contains strings) this way:
  140.   // creates new list, where the item concatenation of string contained in the lists
  141.   // these list should be the same length
  142.   define concat_list (list l1, list l2) ``{
  143.       integer i = 0;
  144.       list new_l = [];
  145.       integer s = size (l1);
  146.       string des = "";
  147.       while (i < s) {
  148.     des = (select (l1, i) + select (l2, i));
  149.     new_l = add (new_l,`item (`id(i), des, (i == 0)));
  150.     i = i + 1;
  151.       }
  152.       
  153.       return new_l;
  154.   };
  155.  
  156.                 // creates new list from list l
  157.                 // but cards with the same device/vendor id are added just once
  158.   define remove_duplicates (list l) ``{
  159.  
  160.     list n = [];
  161.     foreach (`c, l, ``{
  162.       integer vid = lookup (c, "vendor_id");
  163.       integer did = lookup (c, "device_id");
  164.       boolean to_add = true;
  165.       foreach (`nc, n, ``{
  166.     if ((lookup (nc, "device_id") == did) && (lookup (nc, "vendor_id") == vid))
  167.       to_add = false;
  168.       });
  169.       if (to_add)
  170.     n = add (n, c);
  171.     });
  172.     
  173.     
  174.     return n;
  175.   };
  176.  
  177.                 // sets the volume, with amixer check
  178.                 // if an error occurs popup error is displayed
  179.   define set_volume (integer v) ``{
  180.     integer ret = Shell ("/usr/bin/amixer set Master $VOL unmute", $["VOL" : v]);
  181.     if (ret == 127){
  182.                 // To translators: This is just popup message, shouldn't be too long
  183.       UI (`DisplayMessage (_("Cannot find program 'amixer'"), 0,
  184.                 // To translators: This is just popup message, shouldn't be too long
  185.                _("Please install the package 'ALSA' from the 'snd' series")));
  186.     }
  187.     return ret;
  188.   };
  189.  
  190.                 // converts hex num to integer
  191.                 // keeps decimal number as is
  192.   define hextoi (string num) ``{
  193.  
  194.     if (filterchars (num, "0123456789") == num)
  195.       return tointeger (num);
  196.  
  197.     if (tolower(substring (num, 0, 2)) != "0x")
  198.       return 0;
  199.  
  200.     integer ret = 0;
  201.     integer pos = size (num) - 1;
  202.     integer times = 1;
  203.     
  204.     while (pos > 1) {
  205.  
  206.       string num_char = tolower (substring (num, pos, 1));
  207.       
  208.       if (num_char == "f")
  209.     ret = ret + 15 * times;
  210.       else if (num_char == "e")
  211.     ret = ret + 14 * times;
  212.       else if (num_char == "d")
  213.     ret = ret + 13 * times;
  214.       else if (num_char == "c")
  215.     ret = ret + 12 * times;
  216.       else if (num_char == "b")
  217.     ret = ret + 11 * times;
  218.       else if (num_char == "a")
  219.     ret = ret + 10 * times;      
  220.       else 
  221.     ret = ret + tointeger (num_char) * times;      
  222.       
  223.       times = times * 16;
  224.       pos = pos - 1;
  225.     }
  226.     
  227.     return ret;
  228.   };
  229.  
  230.  
  231.                 // tries to extract list of values from description
  232.                 // these value are generated from alsa modules
  233.                 // and can be in form
  234.                 // [list=value,value,..] or
  235.                 // [range=1-19] or something not
  236.                 // recognized
  237.  
  238.   define get_values (string des) ``{
  239.     list ret = [];
  240.     integer pos = 0;
  241.     integer len = size (des);
  242.     while ((pos < len) && (substring (des, pos, 1) != "[")) {
  243.       pos = pos + 1;
  244.     }
  245.     pos = pos + 1;
  246.     
  247.     if (pos < len) {        // found "["
  248.       if (tolower(substring (des, pos, 5)) == "list=") {
  249.     pos = pos + 5;
  250.     integer s = pos;
  251.     while ((pos < len) && substring (des, pos, 1) != "]") {
  252.       if (substring (des, pos, 1) == ",") {
  253.         ret = add (ret, hextoi (substring (des, s, pos - s))); 
  254.         s = pos + 1;
  255.       }
  256.       pos = pos + 1;
  257.     }
  258.     ret = add (ret, hextoi (substring (des, s, pos - s))); 
  259.       }
  260.       else if (tolower(substring (des, pos, 6)) == "range=") {
  261.     pos = pos + 6;
  262.     integer s = pos;
  263.     integer range_start = 0;
  264.     while ((pos < len) && substring (des, pos, 1) != "]") {
  265.       if (substring (des, pos, 1) == "-") {
  266.         range_start = tointeger(substring (des, s, pos - s));
  267.         s = pos + 1;
  268.       }
  269.       pos = pos + 1;
  270.     }
  271.     integer range_stop = tointeger(substring (des, s, pos - s));
  272.                 // now create the range list
  273.     while (range_start <= range_stop) {
  274.       ret = add (ret, range_start);
  275.       range_start = range_start + 1;
  276.     }
  277.       }
  278.       else if (tolower(substring (des, pos, 4)) == "bool") {
  279.     ret = [0, 1];
  280.       }
  281.     }
  282.     
  283.     return ret;
  284.   };
  285.  
  286.  
  287.                 // this dialog is displayed, when its
  288.                 // not possible to remove some alsa
  289.                 // modules, it happens, when user not
  290.                 // a root or the modules are used
  291.   define CanNotReset () ``{
  292.     map after = SCR(`Read(.proc.modules));
  293.     string not_removed = "";
  294.  
  295.     foreach (`k, `v, after, ``{
  296.       string temp = substring (k, 0, 3);
  297.       
  298.       if (temp == "snd") {    // this is alsa module
  299.     not_removed = not_removed + k + "\n";
  300.       }
  301.     });
  302.     
  303.     if (haskey (after, "soundcore"))
  304.       not_removed = not_removed + "soundcore" + "\n";
  305.     
  306.     
  307.     if (size (not_removed) > 0) {
  308.       string msg = "";
  309.       if (size (not_removed) > 1)
  310.       // To translators: This is just popup message, shouldn't be too long
  311.     msg = sformat (UI(_("Cannot remove modules:\n%1")), not_removed);
  312.       else
  313.       // To translators: This is just popup message, shouldn't be too long
  314.     msg = sformat (UI(_("Cannot remove module:\n%1")), not_removed);
  315.       UI (`DisplayMessage (msg, 0,
  316.                // To translators: This is just popup message, shouldn't be too long
  317.                _("Please check that you are logged in as root and\n
  318. no sound programs (i.e. players, mixers, etc...) are running
  319. ")));
  320.     }
  321.   };
  322.  
  323.  
  324.                 // this routine tests if the ALSA
  325.                 // package is installed, it is
  326.                 // necessary to have installed this
  327.                 // package in order to continue with
  328.                 // the configuration
  329.   define IsAlsaInstalled () ``{
  330.  
  331.     integer ret = Shell ("/bin/rpm -q alsa");
  332.  
  333.     if (ret == 127) {
  334.     // To translators: This is just popup message, shouldn't be too long
  335.       UI (`DisplayMessage (_("Cannot execute the program \"rpm\"."), 0,
  336.                // To translators: This is just popup message, shouldn't be too long
  337.                _("Please check if the 'rpm' package from the series 'a1' is installed.")));
  338.     }
  339.       
  340.                 // if this package not installed, we have to use alsa au file
  341.     if (Shell ("/bin/rpm -q snd_au") == 0)
  342.       user_settings = add (user_settings, "audio_file", "/usr/share/sounds/au/linus-english.au");
  343.     
  344.     return (ret == 0);
  345.   };
  346.   
  347.                 // here the test sound is played, by
  348.                 // default ist alsa whistle sound, but
  349.                 // if snd_au package is installed,
  350.                 // than it's Linus Torvals voice, the
  351.                 // if the test file cannot be found,
  352.                 // the message is displayed
  353.  
  354.   define PlayTest () ``{
  355.     
  356.     if ((Shell ("/bin/ls $FILE", $["FILE" : lookup (user_settings, "audio_file")]) != 0)) {
  357.       string file = lookup (user_settings, "audio_file");
  358.  
  359.       // To translators: just one file will be displayed
  360.       // To translators: if the test audio file can not be found this message is displayed
  361.       // To translators: This is just popup message, shouldn't be too long
  362.       string msg = sformat (UI (_("Cannot find file:\n %1\n\n(test audio file)")), file);
  363.  
  364.       UI (`DisplayMessage (msg, 0, ""));
  365.     }
  366.     else
  367.       Shell ("/bin/cat $AUDIO > /dev/audio &", $["AUDIO" : lookup (user_settings, "audio_file")]);
  368.   };
  369.  
  370.                 // here we get some additional params
  371.                 // from isapnp
  372.  
  373.                 // this function is NOT used now,
  374.                 // because too many isapnp options
  375.                 // vary too much
  376.   define GetIsaParm (map cc) ``{
  377.     string ret = "";
  378.     /*
  379.       if (lookup (cc, "cardtype", "") != "PnP")
  380.       return ret;
  381.  
  382.       map cr = lookup (cc, "resource");
  383.  
  384.       if (haskey (cr, "io"))
  385.       ret = ret + " " + sformat ("snd_port=%1", lookup(select (lookup (cr, "io"), 0), "start"));
  386.       if (haskey (cr, "irq"))
  387.       ret = ret + " " + sformat ("snd_irq=%1", lookup(lookup (cr, "irq"), "irq"));
  388.       if (haskey (cr, "dma")) {
  389.       integer n = 1;
  390.       foreach (`dma, lookup (cr, "dma"), ``{
  391.       ret = ret + " "  + sformat ("snd_dma%1=%2", n, lookup(dma, "channel"));
  392.       n = n + 1;
  393.       });
  394.       }
  395.     */
  396.     return ret;
  397.       
  398.   };
  399.  
  400.                 // Chooses one message according to
  401.                 // the language, used for translating
  402.                 // sndcard options 
  403.   define Trans (map|void msgs, string lang) ``{
  404.     string|void message = "";
  405.     if (msgs != nil) {
  406.       message = lookup(msgs, lang);
  407.       if (message == nil)
  408.         message = lookup(msgs, "default");
  409.       if (message == nil)
  410.         message = "";             // Everything has failed.
  411.     }
  412.     return message;
  413.   };
  414.  
  415.                 // dialog for setting the options for
  416.                 // the sound card driver, now it uses
  417.                 // global cur_options_map and
  418.                 // cur_options for setting options for
  419.                 // a current_driver
  420.  
  421.                 // It checks if the values entered by
  422.                 // the user are correct
  423.   define OptionsSetup (map driver) ``{
  424.  
  425.                 // Help text for options 1/4
  426.     string help_text = UI(_("Here you can modify the options for the sound modules. "));
  427.                 // Help text for options 2/4
  428.     help_text = help_text + UI(_("If you are not <b>absolutely sure</b> what are you doing, please leave this dialog untouched."));
  429.  
  430.                 // Help text for options 3/4
  431.     help_text = help_text + UI (_("<p>Choose the option you want to set and use the <i>Set</i> button to enable 
  432. the new value. You can reset all values by pressing <i>Reset</i>.  Number 
  433. values can be entered as decimal or hexadecimal (hexadecimal with a 
  434. <b>0x</b> prefix).</p>
  435. "));
  436.  
  437.                 // Help text for options 4/4
  438.     help_text = help_text + UI (_("Please refer to the <b>SuSE</b> help system, section 'package description', series 'snd', <b>alsa</b> package for more information."));
  439.  
  440.  
  441.  
  442.  
  443.                 // This is unused  ;-(
  444.     //help_text = help_text + UI (_("Please refer to the <i>INSTALL</i> file in <small>/usr/doc/packages/alsa</small> directory for appropriate information about options for your card."));
  445.  
  446.     any ret = nil;
  447.  
  448.  
  449.     
  450.  
  451.     list params = lookup (driver, "params");
  452.  
  453.  
  454.                 // these options are irelevant, 
  455.                 // because just one card can be configured
  456.                 // at this time
  457.     params = filter (`p, params, ``(lookup (p, "name") != "snd_index"));
  458.     params = filter (`p, params, ``(lookup (p, "name") != "snd_id"));
  459.  
  460.     string language = UI(`GetLanguage());
  461.     
  462.     list description = maplist (`p, params, ``(Trans(lookup (p, "description"), language)));
  463.     
  464.     
  465.     list pname = maplist (`p, params, ``(lookup (p, "name")));
  466.     list types = maplist (`p, params, ``(lookup (p, "type")));
  467.     list possible_values = maplist (`p, params, ``(lookup (p, "values", "")));
  468.  
  469.     map options = cur_options_map;
  470.  
  471.     integer n = 0;
  472.     list index_description = concat_list (description, possible_values);
  473.     string name = select (description, n);
  474.     string desc = select (pname, n);
  475.     
  476.     
  477.     term con = `VBox (
  478.       `Top(`Label (card_title)),
  479.       `SelectionBox (`id(`op), `opt(`notify), "Options", index_description),
  480.       `VBox (
  481.     `TextEntry (`id (`des), desc, lookup (options, desc, "")),
  482.     `HBox (
  483.                 // To translators: This is button label, shouldn't be too long
  484.       `PushButton (`id (`set), `opt(`default), _("&Set")),
  485.                 // To translators: This is button label, shouldn't be too long
  486.       `PushButton (`id (`reset), _("&Reset"))
  487.       )
  488.     )
  489.       );
  490.  
  491.     
  492.     UI(`SetContents (_("Sound cards"),
  493.     con, help_text, true, true));
  494.  
  495.  
  496.     repeat {
  497.       ret = UI(`UserInput ());
  498.     
  499.       if (ret == `op) {
  500.     n = UI (`QueryWidget (`id(`op), `CurrentItem));
  501.     name = select (description, n);
  502.     desc = select (pname, n);
  503.     UI(`ChangeWidget(`id(`des), `Label, desc));
  504.     UI(`ChangeWidget(`id(`des), `Value, lookup (options, desc, "")));
  505.         
  506.       }
  507.       else if (ret == `set) {    // set button pressed
  508.     string value = UI(`QueryWidget(`id(`des), `Value));
  509.  
  510.     if (select(types, n) == "int") {
  511.                 
  512.       if (tolower(substring (value, 0, 2)) == "0x") {        // hex number
  513.         string rest = tolower(substring (value, 2));
  514.         if (filterchars(rest, "0123456789abcdef") != rest) {
  515.                 // To translators: This is a warning message, shouldn't be too long
  516.           UI(`ChangeWidget(`id(`des), `Value, _("This value must be a number !!!")));
  517.           sleep(1000);
  518.           UI(`ChangeWidget(`id(`des), `Value, ""));
  519.           value = "";
  520.         }
  521.       }
  522.       else if (filterchars(value, "0123456789") != value) {
  523.                 // To translators: This is a warning message, shouldn't be too long
  524.         UI(`ChangeWidget(`id(`des), `Value, _("This value must be a number !!!")));
  525.         sleep(1000);
  526.         UI(`ChangeWidget(`id(`des), `Value, ""));
  527.         value = "";
  528.       }
  529.       if (false) {
  530.       if (size (value) > 0) {
  531.                 // get possible values
  532.         list possible_values = get_values (select (possible_values, n));
  533.  
  534.  
  535.         if (possible_values != []) {
  536.           if (!contains (possible_values, hextoi (value))) {
  537.                 // // To translators: This is just popup message, shouldn't be too long
  538.         string msg = sformat (UI(_("This value must be one of %1\nor its hexadecimal equivalent.")), 
  539.                       possible_values);
  540.         UI(`DisplayMessage (msg, 0, ""));
  541.         UI(`ChangeWidget(`id(`des), `Value, ""));
  542.         value = "";
  543.           }
  544.         }
  545.       }
  546.       }
  547.     }
  548.     else {            // string
  549.       if (filterchars (tolower (value), "abcdefghijklmnopqrstuvwxyz_0123456789") != value) {
  550.         
  551.         integer wrong_pos = findfirstnotof (tolower (value), "abcdefghijklmnopqrstuvwxyz_0123456789");
  552.         string wrong_char = substring (value, wrong_pos, 1);
  553.         if (wrong_char == " ") {
  554.                 // To translators: "space" means blank character
  555.           wrong_char = wrong_char + " " + UI(_("(space)"));
  556.         }
  557.         // To translators: This is just popup message, shouldn't be too long
  558.         string msg = sformat (UI(_("String cannot contain: %1")), wrong_char);
  559.  
  560.         UI(`DisplayMessage (msg, 0, ""));
  561.         UI(`ChangeWidget(`id(`des), `Value, ""));
  562.         
  563.         value = "";
  564.       }
  565.       if (size (value) > 8) {
  566.           // To translators: This is just popup message, shouldn't be too long
  567.         UI(`ChangeWidget(`id(`des), `Value, _("String too long (maximal lenght 8) !!!")));
  568.         sleep(1000);
  569.         UI(`ChangeWidget(`id(`des), `Value, ""));
  570.         value = "";
  571.       }
  572.     }
  573.     
  574.     if (size (value) > 0)
  575.       options = add (options, desc, value);
  576.  
  577.       }
  578.       else if (ret == `reset) {
  579.     options = $[];
  580.     UI(`ChangeWidget(`id(`des), `Value, ""));
  581.       }
  582.         
  583.     
  584.     } until ((ret == `back) || (ret == `next) || ret == `cancel);
  585.  
  586.     if (ret == `next) {
  587.       map m = lookup (current_driver, "module");
  588.       string args = "";
  589.       
  590.       foreach (`k, `v, options, ``{
  591.                 // we DO!!! ignore empty options
  592.     if (size (v) > 0) 
  593.       args = args + sformat ("%1=%2 ", k, v);
  594.       });
  595.  
  596.       current_options = args;
  597.       cur_options_map = options;
  598.  
  599.       m = add (m, "args", args);
  600.       m = add (m, "conf", args);
  601.       current_driver = add (current_driver, "module", m);
  602.  
  603.       
  604.     }
  605.  
  606.     return ret;
  607.         
  608.   };
  609.  
  610.  
  611.                 // writes modules.conf, it makes a
  612.                 // backup and appends to the end of
  613.                 // modules.conf aliases and options
  614.                 // for the configured sound card
  615.  
  616.   define ConfModules (string file) ``{
  617.     // first comment out all lines containing snd|sound
  618.     Shell ("/bin/cp -f $FILE $FILE.old; /usr/bin/sed 's/^\\([^#].*snd.*$\\|[^#].*sound.*$\\)/# \\1/' $FILE > /tmp/$FILE.sed; /bin/mv -f /tmp/$FILE.sed $FILE",
  619.     $["FILE" : file]);
  620.  
  621.  
  622.     list l = SCR(`Read(.lines));
  623.  
  624.     if (l == nil) 
  625.              // To translators: just one file will be displayed
  626.       return sformat (UI(_("Cannot find file: %1")), file);
  627.     
  628.     list newl = [];
  629.  
  630.     integer length = size (l);
  631.     
  632.     integer n = 0;
  633.     string|void line = select (l, n);
  634.  
  635.                 // read until ALSA section
  636.     while ((line != nil) && (n < length)  &&
  637.     (line != "# ALSA section {$#@begin@#$} [don't remove or move this line] vvvvv")) {
  638.       newl = add (newl, line);
  639.       line = select (l, n);
  640.       n = n + 1;
  641.     }
  642.                 // skip ALSA section
  643.     while ((line != nil) &&  (n < length)  &&
  644.     (line != "# ALSA section {$#@_end_@#$} [don't remove or move this line] ^^^^^")) {
  645.       line = select (l, n);
  646.       n = n + 1;
  647.     }
  648.     
  649.     n = n + 1;
  650.     if (n < length)
  651.     line = select (l, n);
  652.                 // read the rest
  653.     while ((line != nil) && (n < length)) {
  654.       newl = add (newl, line);
  655.       line = select (l, n);
  656.       n = n + 1;
  657.     }
  658.  
  659.                 // and write configured card
  660.     newl = add (newl, "# ALSA section {$#@begin@#$} [don't remove or move this line] vvvvv");
  661.     newl = add (newl, "#");
  662.     newl = add (newl, "# ALSA native device support, generated by YaST2");
  663.     newl = add (newl, "#");
  664.     newl = add (newl, "alias char-major-116 snd");
  665.     newl = add (newl, "options snd snd_major=116 snd_cards_limit=1");
  666.     newl = add (newl, sformat ("alias snd-card-0 %1", lookup (lookup(current_driver, "module"), "name")));
  667.     newl = add (newl, sformat ("options %1 snd_index=%2 snd_id=card1 %3 %4",
  668.     lookup (lookup(current_driver, "module"), "name"),
  669.     lookup (user_settings, "snd_index"),
  670.     current_options,
  671.     GetIsaParm (current_card)
  672.                    ));
  673.     newl = add (newl, "#");
  674.     newl = add (newl, "# OSS/Free emulation");
  675.     newl = add (newl, "#");
  676.     newl = add (newl, "alias sound-slot-0 snd-card-0");
  677.     newl = add (newl, "alias sound-service-0-0 snd-mixer-oss");
  678.     newl = add (newl, "alias sound-service-0-1 snd-seq-oss");
  679.     newl = add (newl, sformat("alias sound-service-0-3 %1", lookup (user_settings, "snd-pcm-oss")));
  680.     newl = add (newl, "alias sound-service-0-8 snd-seq-oss");
  681.     newl = add (newl, sformat("alias sound-service-0-12 %1", lookup (user_settings, "snd-pcm-oss")));
  682.     newl = add (newl, "#");
  683.     newl = add (newl, "# ALSA section {$#@_end_@#$} [don't remove or move this line] ^^^^^");
  684.  
  685.     if (SCR(`Write(.lines, newl)) != 0)
  686.              // To translators: just one file will be displayed in instead parameter %1
  687.       return sformat (UI(_("Cannot write file: %1.\nThe sound will not be started after next reboot.\nThe sound is not configured well.")), file);
  688.   };
  689.  
  690.  
  691.                 // shortcuts for maplists
  692.   define GetDrivers (list db) ``{
  693.     return  maplist (`v, db, ``(lookup(v, "name")));
  694.   };
  695.   
  696.   define GetCards (string|void mod, list db) ``{
  697.     if (mod == nil)
  698.       return [];
  699.     list|void mdl = filter (`s, db, ``(lookup (s, "name") == mod));
  700.     list c = [];
  701.  
  702.     if (mdl != []) {
  703.       c = lookup (select (mdl, 0), "cards");
  704.     
  705.       if (c == [])
  706.     c = add (c, mod);
  707.     }
  708.       
  709.     else
  710.                 // To translators: Name of 'unknown card', shouldn't be too long
  711.       c = add (c, _("Unknown card"));
  712.     return c;
  713.   };
  714.   
  715.   
  716.                 // main autodetection is done through
  717.                 // SCR and libhd
  718.  
  719.   define GetAudio () ``{
  720.     list ret = SCR(`Read(.probe.byclass.multimedia.audio));
  721.     
  722.     ret = remove_duplicates (ret);
  723.  
  724.     return ret;
  725.   };
  726.   
  727.  
  728.  
  729.   define GetName (map cc) ``{
  730.       
  731.     if (haskey (cc, "name"))
  732.       return lookup (cc, "name");
  733.  
  734.     return "Unknown module";      
  735.       
  736.   };
  737.  
  738.  
  739.                 // lookups in the sndcards database
  740.                 // for card name, when gets bus,
  741.                 // device_id and vendor_id as parameters
  742.   define GetCardName (string bus, integer vendor_id, integer device_id) ``{
  743.       // To translators: Name of 'unknown driver', shouldn't be too long
  744.     string ret = UI (_("Unknown driver"));
  745.     integer offset = 0;
  746.     if (tolower (bus) == "pci")
  747.       offset = 0x10000;
  748.     else if (tolower (bus) == "isa")
  749.       offset = 0x20000;
  750.     else
  751.       return ret;
  752.  
  753.     list|void fc = nil;
  754.     if (tolower (bus) == "pci") 
  755.       fc = filter (`d, snd_database, 
  756.       ``(filter(`c, lookup (d, "libhd"), ``((lookup (c, "vendor_id") == vendor_id - offset) && 
  757.           (contains(lookup(c, "device_id"), device_id - offset)))) != []));
  758.  
  759.       
  760.     else {
  761.  
  762.     
  763.       fc = filter (`d, snd_database, 
  764.       ``(filter(`c, lookup (d, "libhd"), ``((lookup (c, "vendor_id") == vendor_id - offset) &&
  765.           (lookup (c, "device_id") == device_id - offset))) != []));
  766.  
  767.     }
  768.       
  769.     if (fc != nil)
  770.       ret = lookup (select (fc, 0), "name");
  771.       
  772.     return ret;
  773.       
  774.   };
  775.   
  776.       
  777.                 // let's try modprobe, all is done
  778.                 // through SCR agents 
  779.   define ProbeModule () ``{
  780.  
  781.     map module = $[];
  782.       
  783.     module = lookup(current_driver, "module", $[]);
  784.  
  785.  
  786.     if (size (module) == 0)
  787.                 // To translators: label message
  788.       return sformat (UI(_("The appropriate module for the soundcard %1 could not be found.\n")), 
  789.               GetName (current_driver));
  790.  
  791.  
  792.  
  793.  
  794.  
  795.     boolean mod_active = lookup (module, "active", false);
  796.                 // if we have some additional options
  797.     string mod_parm = lookup(module, "name") + " " + current_options;
  798.  
  799.       
  800.     mod_parm = mod_parm + " " + GetIsaParm (current_card);
  801.       
  802.     Shell("/sbin/depmod -a -F /boot/System.map-`uname -r` `uname -r`");
  803.  
  804.     if (mod_active == false) {
  805.       boolean probe = lookup (module, "modprobe", true);
  806.       if (!probe)
  807.     Shell("/sbin/insmod "+mod_parm);
  808.       else
  809.     Shell("/sbin/modprobe "+mod_parm);
  810.     }
  811.  
  812.     mod_parm = lookup (user_settings, "snd-pcm-oss"); // this module is for compatibility with OSS
  813.       
  814.     Shell("/sbin/modprobe "+mod_parm);
  815.       
  816.     map pm = SCR(`Read(.proc.modules));
  817.  
  818.     string ret = "";
  819.  
  820.     if (haskey (pm, lookup (module, "name")))
  821.       module = add (module, "active", true);
  822.     else
  823.                 // To translators: label message
  824.       ret = sformat (UI(_("The kernel module %1 for sound support cannot be loaded.")), lookup (module, "name"));
  825.  
  826.     current_driver = add (current_driver, "module", module);
  827.  
  828.     return ret;
  829.       
  830.       
  831.   };
  832.  
  833.  
  834.   define RemoveModule (string m) ``{
  835.     Shell ("/sbin/rmmod -r $MODULE", $["MODULE" : m]);
  836.   };
  837.  
  838.   define RemoveModules (list modules) ``{
  839.     foreach (`m, modules, ``{
  840.       RemoveModule (m);
  841.     });
  842.   };
  843.  
  844.                 // quits all sound programs; if
  845.                 // someone want to reset the
  846.                 // configuration (remove the modules),
  847.                 // nothing using sound devices can be
  848.                 // running, popup dialog with
  849.                 // confirmation is displayed
  850.   define QuitAllSoundPrograms () ``{
  851.  
  852.     integer ret = Shell ("/bin/fuser /dev/dsp* /dev/audio* /dev/mixer* /dev/midi* /dev/mixer*");
  853.     if (ret == 0) {        
  854.       
  855.                 // To translators: To reset the sound configuration these programs must be terminated
  856.                 // To translators: label message
  857.       string msg = UI (_("There are running programs using some audio device.\n"));
  858.                 // To translators: label message
  859.       msg = msg + UI (_("To reset the configuration these programs will be terminated. Proceed?"));
  860.  
  861.       integer terminate = UI(`DisplayYesNo (msg));
  862.       if (terminate == 1) {
  863.     Shell ("/bin/fuser -k /dev/dsp* /dev/audio* /dev/mixer* /dev/midi* /dev/mixer*");
  864.       }
  865.       return terminate;
  866.     }
  867.     return 1;
  868.   };
  869.  
  870.                 // tries to remove all loaded alsa modules
  871.   define RemoveAllAlsaModules () ``{
  872.     map pm = SCR(`Read(.proc.modules));
  873.     string not_removed = "";
  874.     
  875.     QuitAllSoundPrograms ();
  876.  
  877.     foreach (`k, `v, pm, ``{
  878.       string temp = substring (k, 0, 3);
  879.       
  880.       if (temp == "snd") {    // this is alsa module
  881.     Shell ("/sbin/rmmod -r $MODULE", $["MODULE" : k]);
  882.       
  883.       }
  884.     });
  885.  
  886.     Shell ("/sbin/rmmod -r $MODULE", $["MODULE" : "soundcore"]);
  887.  
  888.     /*
  889.  
  890.     */    
  891.   };
  892.   
  893.                 // NOT used now
  894.   define NotImplemented () ``{
  895.     UI(`SetContents (_("Sound cards"),
  896.     `HVCenter (
  897.                 // To translators: obsolete dialog, not used now
  898.       `Label (_("Sorry, but this is not implemented yet!!!"))
  899.       ), help_text, true, true));
  900.     
  901.     return UI(`UserInput ());
  902.   };
  903.  
  904.  
  905.                 // called when exists /proc/asound/cars
  906.                 // but with unreadable output
  907.   define WrongOutput () ``{
  908.                 // Help text, if an attempt for configuration failed 1/2
  909.     string help_text = UI (_("<p>The sound card does not function correctly although it has <b>previously</b> been configured. Possible causes are: 1. You have tried to configure the sound outside the <b>YaST2</b> and you were unsuccessful, 2. The card requires option values which you must enter manually. 3. You have passed incorrect options or optionvalues to the sound card module.</p>
  910. "));
  911.  
  912.  
  913.                 // Help text, if an attempt for configuration failed 2/2
  914.     help_text = help_text + UI(_("<p>You can reset the configuration process by pressing the 
  915. <i>Reset</i>button and try to configure the card again. Please refer to the 
  916. <b>SuSE</b> system, section 'package description', series 'snd', 
  917. <b>alsa</b>package for more information.</p>
  918. "));
  919.  
  920.  
  921.  
  922.  
  923.  
  924.                 // This is unused  ;-(
  925.     //Please refer to the <i>INSTALL</i> file in <i>/usr/doc/packages/alsa</i> directory for appropriate information about possibly required options for your card.</p>"));
  926.  
  927.     UI(`SetContents (_("Sound cards"),
  928.     `HVCenter (
  929.       `ReplacePoint (`id(`wo),
  930.           `VBox(
  931.                 // To translators: label message
  932.         `Label (_("Incorrect sound configuration found.")),
  933.                 // To translators: button label
  934.         `PushButton (`id (`reset), _("&Reset"))
  935.         )
  936.              )
  937.       ), help_text, true, true));
  938.     any ret = nil;
  939.     
  940.     repeat {
  941.  
  942.       ret = UI(`UserInput ());
  943.       
  944.       if (ret == `reset) {
  945.     RemoveAllAlsaModules ();
  946.  
  947.     list|void r = nil;
  948.     
  949.     if ((Shell ("/bin/ls /proc/asound/cards")) == 0)
  950.         r = SCR(`Read(.proc.asound.cards));
  951.  
  952.         if (r != nil) {
  953.       CanNotReset ();
  954.     }
  955.     else {
  956.                 // To translators: label message
  957.       UI(`ReplaceWidget(`id(`wo), `Label (_("The configuration has been reset."))));
  958.       UI(`ChangeWidget(`id(`back), `Enabled, false));
  959.     }
  960.       }
  961.     
  962.     } until (((ret == `back) || (ret == `next) || ret == `cancel));
  963.     
  964.     return ret;
  965.   };
  966.                 // this dialog is displayed if ALSA
  967.                 // not istalled
  968.   define NotInstalled () ``{
  969.                 // Help text when Alsa-drivers are not installed 1/1
  970.     string help_text = UI(_("Sound support requires the <b>ALSA</b> package. You can find it in the 
  971. <b>SuSE</b> distribution (series 'snd') or you can download it from 
  972. <i>http://www.alsa-project.org</i> and then install it.
  973. "));
  974.       
  975.     UI(`SetContents (_("Sound cards"),
  976.     `HVCenter (
  977.                 // This label is displayed when no alsa package is not installed
  978.                 // To translators: label message
  979.       `Label (_("Please install the package ALSA (Advanced Linux Sound Architecture)\n
  980. before you proceed with the configuration of your sound system.
  981. "))
  982.       ), help_text, true, true));
  983.       
  984.     return UI(`UserInput ());
  985.   };
  986.  
  987.                 // this dialog is displayed, when
  988.                 // sndcards DB not found, this should
  989.                 // never happen, just if someone
  990.                 // delete or edit this db
  991.  
  992.   define DBNotFound () ``{
  993.                 // Help text when sndcards database not found 1/1
  994.     string help_text = UI(_("An internal <b>YaST2</b> file is missing or corrupted. Please try 
  995. toreinstall <b>YaST2</b>. You will find it in <b>SuSE</b> 
  996. distribution,series 'a1'. 
  997. "));
  998.       
  999.     UI(`SetContents (_("Sound cards"),
  1000.     `HVCenter (
  1001.                 // To translators: label message
  1002.       `Label (_("The Sound card database cannot be found!!!"))
  1003.       ), help_text, true, true));
  1004.       
  1005.     return UI(`UserInput ());
  1006.   };
  1007.  
  1008.  
  1009.   define SearchForCard (string name) ``{
  1010.     integer len = size (name);
  1011.     name = tolower(name);
  1012.     map ret = $[];
  1013.     string cmp = "";
  1014.  
  1015.     integer j = 0;
  1016.     foreach (`m, snd_database, ``{
  1017.       integer i = 0;
  1018.       foreach(`c, lookup (m, "cards"), ``{
  1019.     cmp = substring (c, 0, len);
  1020.     if (tolower(cmp) == name) {
  1021.       ret = add (ret, "module", lookup (m, "name"));
  1022.       ret = add (ret, "card", i);
  1023.       ret = add (ret, "driver", j);
  1024.  
  1025.       return ret;
  1026.     }
  1027.     i = i + 1;
  1028.       });
  1029.       j = j + 1;
  1030.     });
  1031.     return ret;
  1032.   };
  1033.   
  1034.  
  1035.                 // dialog, when no sound cards were
  1036.                 // autodetected, manual selection is
  1037.                 // provided here, with two selection
  1038.                 // boxes and the text entry for searching
  1039.   define ChooseCard () ``{
  1040.                 // Help text - manual configuration 1/1
  1041.     string help_text = UI(_("Please <b>manually</b> choose the sound card you want to configure. You can 
  1042. search for a particular sound card by entering the name in the search box.
  1043. "));
  1044.       
  1045.     
  1046.     list drivers = GetDrivers (snd_database);
  1047.     string ven = select (drivers, 0);
  1048.     list models = GetCards (ven, snd_database);
  1049.       
  1050.     list index_drivers = index_list (drivers, 0);
  1051.     list index_models = index_list (models, 0);
  1052.       
  1053.  
  1054.     UI(`SetContents(_("Sound cards"),
  1055.     `VBox (
  1056.       `HBox (
  1057.         `ReplacePoint (`id (`rep_ven),
  1058.                 // To translators: selection box title
  1059.         `SelectionBox (`id (`sel_ven), `opt(`notify), _("Sound card driver"), index_drivers)
  1060.                ),
  1061.         `ReplacePoint(`id(`rep_mod),
  1062.                 // To translators: selection box title
  1063.         `SelectionBox (`id (`sel_mod), `opt(`notify), _("Sound card model"), index_models)
  1064.               )
  1065.         ),
  1066.                 // To translators: text entry label
  1067.       `TextEntry (`id(`search), `opt(`notify), _("Search"))
  1068.       //`Empty ()
  1069.       )
  1070.     , help_text, true, true));
  1071.  
  1072.  
  1073.     any ret = nil;
  1074.     
  1075.     repeat {
  1076.     
  1077.       ret =  UI (`UserInput ());
  1078.       
  1079.  
  1080.       if (ret == `sel_ven) {
  1081.     integer n = UI (`QueryWidget (`id(`sel_ven), `CurrentItem));
  1082.     ven = select (drivers, n);
  1083.     models = GetCards (ven, snd_database);
  1084.     index_models = index_list (models, 0);
  1085.  
  1086.     UI(`ReplaceWidget (`id(`rep_mod),
  1087.                 // To translators: selection box title
  1088.         `SelectionBox (`id (`sel_mod), _("Sound card model"), index_models)));
  1089.  
  1090.       
  1091.       }
  1092.       else if (ret == `search) {
  1093.     string entry = UI(`QueryWidget (`id(`search), `Value));
  1094.     if (size (entry) > 0) {
  1095.           
  1096.       map found = SearchForCard (entry);
  1097.       if (size(found) > 0) {
  1098.           
  1099.         models = GetCards(lookup (found, "module"), snd_database);
  1100.         index_drivers = index_list (drivers, lookup (found, "driver"));
  1101.           
  1102.         index_models = index_list (models, lookup(found, "card"));
  1103.         UI(`ReplaceWidget (`id(`rep_ven),
  1104.                 // To translators: selection box title
  1105.         `SelectionBox (`id (`sel_ven), `opt(`notify), _("Sound card driver"), index_drivers)));          
  1106.         UI(`ReplaceWidget (`id(`rep_mod),
  1107.                 // To translators: selection box title
  1108.         `SelectionBox (`id (`sel_mod), `opt(`notify), _("Sound card model"), index_models)));
  1109.       }
  1110.     }
  1111.     else {
  1112.       models = GetCards (select (drivers, 0), snd_database);
  1113.       index_models = index_list (models, 0);
  1114.       index_drivers = index_list (drivers, 0);
  1115.       UI(`ReplaceWidget (`id(`rep_ven),
  1116.                 // To translators: selection box title
  1117.           `SelectionBox (`id (`sel_ven), `opt(`notify), _("Sound card driver"), index_drivers)));
  1118.       UI(`ReplaceWidget (`id(`rep_mod),
  1119.                 // To translators: selection box title
  1120.           `SelectionBox (`id (`sel_mod), `opt(`notify), _("Sound card model"), index_models)));
  1121.     }
  1122.       }
  1123.       
  1124.       card_title = select (models, UI (`QueryWidget (`id(`sel_mod), `CurrentItem)));
  1125.  
  1126.     } until ((ret == `back) || (ret == `next) || ret == `cancel);
  1127.  
  1128.     if (ret == `next) {
  1129.  
  1130.       cards = filter (`d, snd_database, ``(lookup (d, "name") == select (drivers, UI (`QueryWidget (`id(`sel_ven), `CurrentItem)))));
  1131.     
  1132.     
  1133.     }
  1134.     
  1135.     return ret;
  1136.     
  1137.   };
  1138.  
  1139.  
  1140.                 // main dialog, searching for the
  1141.                 // sound card; if some is found, than
  1142.                 // its displayed, if none, dialog with
  1143.                 // "Manual" button it shown to the user
  1144.  
  1145.   
  1146.   define FindCard () ``{
  1147.                 // Help text - found cards 1/3
  1148.     string help_text = UI (_("<p>If multiple sound cards were found on your system, select on the left 
  1149. side <b>the driver</b> that is appropriate for the sound card model listed 
  1150. on the right side. If only one sound card is found, then <b>one</b> 
  1151. displayed on the left. If there are multiple models of the card, they are 
  1152. listed on the right.</p>
  1153. "));
  1154.  
  1155.  
  1156.                 // Help text - found cards 2/3
  1157.     help_text = help_text + UI(_("If <b>no sound cards</b> were found, you can try manual setup. You can skip 
  1158. sound card configuration by pressing the <i>Next</i> button. 
  1159. "));
  1160.                 // Help text - found cards 3/3
  1161.     help_text = help_text + UI(_("Press the button <i>Options</i> if you want to set the module options manually. "));
  1162.  
  1163.                 // To translators: label message
  1164.     locale msg = _("Searching for a sound card on your system...");
  1165.     term con = `ReplacePoint (`id (`rp), `Label (msg));
  1166.  
  1167.     UI(`SetContents (_("Sound cards"), con, help_text, false, false));
  1168.       
  1169.  
  1170.     
  1171.     cards = GetAudio ();
  1172.     
  1173.     UI(`ChangeWidget(`id(`back), `Enabled, true));
  1174.     UI(`ChangeWidget(`id(`next), `Enabled, true));
  1175.  
  1176.     
  1177.     list card_names = maplist (`c, cards, ``(GetCardName (lookup(c, "bus"), lookup (c, "vendor_id"),lookup (c, "device_id"))));
  1178.  
  1179.     
  1180.     list index_names = index_list (card_names, 0);
  1181.     
  1182.     string|void ven = select (card_names, 0);
  1183.  
  1184.     list models = GetCards (ven, snd_database);
  1185.     list index_models = index_list (models, 0);
  1186.  
  1187.  
  1188.     if (cards == []) {
  1189.       con = `VBox (
  1190.                 // To translators: label message
  1191.     `HVCenter(`Label (_("No sound cards were found on your system.\n
  1192.  Try manual setup.
  1193. "))),
  1194.                 // To translators: button label to popup dialog when no sound cards were autodetected
  1195.     `Bottom (`PushButton (`id (`manual), _("&Manual")))
  1196.     );
  1197.       
  1198.     }
  1199.     else {
  1200.       if (card_names == [""]) {
  1201.     con = `VBox(
  1202.       `HVCenter (`Label (_("Found card does not have a database entry.\n Try manual setup."))),
  1203.                 // To translators: button label to popup dialog when no sound cards were autodetected
  1204.       `Bottom (`PushButton (`id (`manual), _("&Manual")))
  1205.       );
  1206.       }
  1207.       else {
  1208.  
  1209.         
  1210.     con = `VBox (
  1211.       `HBox (
  1212.         `SelectionBox (`id(`fc), `opt(`notify), _("Sound card driver"), index_names),
  1213.         `ReplacePoint(`id(`rep_mod), 
  1214.         `SelectionBox (`id (`sel_mod), `opt(`notify), _("Sound card model"), index_models)
  1215.               )),
  1216.         // To traslators: this is button label, dialog with options setup for a particular sound card is called
  1217.       `PushButton (`id (`expert),  _("&Options"))
  1218.       );
  1219.       }
  1220.       
  1221.     }
  1222.       
  1223.     UI(`ReplaceWidget (`id (`rp), con));
  1224.       
  1225.     any ret = nil;
  1226.     
  1227.     boolean manually_selected = false;
  1228.       
  1229.     repeat {
  1230.  
  1231.       
  1232.       ret =  UI (`UserInput ());
  1233.  
  1234.  
  1235.       card_title = select (models, UI (`QueryWidget (`id(`sel_mod), `CurrentItem)));
  1236.  
  1237.       if (ret == `fc) {
  1238.     integer n = UI (`QueryWidget (`id(`fc), `CurrentItem));
  1239.     ven = select (card_names, n);
  1240.     models = GetCards (ven, snd_database);
  1241.     index_models = index_list (models, 0);
  1242.  
  1243.     UI(`ReplaceWidget (`id(`rep_mod),
  1244.                 // To translators: selection box title
  1245.         `SelectionBox (`id (`sel_mod), _("Sound card model"), index_models)));
  1246.       }      
  1247.       
  1248.       else if (ret == `expert) {
  1249.     integer n = 0;
  1250.     n = UI (`QueryWidget(`id(`fc), `CurrentItem));
  1251.     if (manually_selected)
  1252.       current_driver = select (cards, n);
  1253.     else {
  1254.       current_card = select (cards, n);
  1255.       current_driver = select (filter (`d, snd_database, ``(lookup (d, "name") ==
  1256.           GetCardName (lookup (current_card, "bus"),
  1257.           lookup (current_card, "vendor_id"),
  1258.           lookup (current_card, "device_id")))), 0);
  1259.     }
  1260.       
  1261.     OptionsSetup (current_driver);
  1262.       
  1263.     UI(`SetContents (_("Sound cards"), con, help_text, true, true));
  1264.       }
  1265.  
  1266.       if (ret == `back && manually_selected)
  1267.     ret = `manual;
  1268.       
  1269.       if (ret == `manual) {
  1270.     cards = [];
  1271.     card_names = [];
  1272.     index_names = [];
  1273.  
  1274.       
  1275.     if (ChooseCard () == `next){
  1276.                 // Help text - user should confirm his/her decision 1/1
  1277.       string help_text = UI(_("You should be sure that you have selected the <b>correct</b> sound card.
  1278. "));
  1279.           
  1280.       if (size (cards) > 0) {
  1281.         card_names = maplist(`c, cards, ``(lookup (c, "name")));
  1282.           
  1283.         index_names = index_list (card_names, 0);
  1284.           
  1285.         con = `VBox(
  1286.                 // To translators: selection box title
  1287.           `SelectionBox (`id(`fc), _("Manually configured drivers"), index_names),
  1288.           // To traslators: this is button label, dialog with options setup for a particular sound card is called
  1289.           `PushButton (`id(`expert),  _("&Options"))
  1290.           );
  1291.         UI(`SetContents (_("Sound cards"), con, help_text, true, true));
  1292.  
  1293.         manually_selected = true;
  1294.       }
  1295.           
  1296.     }                // back to first dialog
  1297.     else {
  1298.       con = `VBox (
  1299.                 // To translators: label message
  1300.         `Label (_("No sound cards were found on your system.\n
  1301.  Try manual setup.
  1302. ")),
  1303.         // To translators: button label to popup dialog when no sound cards were autodetected
  1304.         `Bottom (`PushButton (`id (`manual), _("&Manual")))
  1305.         );
  1306.       UI(`SetContents (_("Sound cards"), con, help_text, true, true));
  1307.       manually_selected = false;
  1308.  
  1309.     }
  1310.       
  1311.       }
  1312.       
  1313.       
  1314.     } until (( ret == `back) || (ret == `next) || ret == `cancel);
  1315.  
  1316.     if ((ret == `next) && (size (cards) > 0)) {
  1317.  
  1318.       integer n = 0;
  1319.       n = UI (`QueryWidget(`id(`fc), `CurrentItem));
  1320.       
  1321.       if (manually_selected) {
  1322.     current_card = $[];
  1323.     current_driver = select (cards, n);
  1324.       }
  1325.       
  1326.       else {
  1327.         
  1328.  
  1329.         
  1330.  
  1331.     current_card = select (cards, n);
  1332.  
  1333.     current_driver = select (filter (`d, snd_database, ``(lookup (d, "name") ==
  1334.         GetCardName (lookup (current_card, "bus"),
  1335.         lookup (current_card, "vendor_id"),
  1336.         lookup (current_card, "device_id")))), 0);
  1337.  
  1338.           
  1339.       }
  1340.  
  1341.       string error = "";
  1342.       
  1343.       if (current_driver == nil)
  1344.                 // To translators: label message
  1345.       error = _("This sound card is NOT supported by YaST2 !");
  1346.       else
  1347.       error = ProbeModule ();
  1348.       
  1349.       if (size(error) > 0) {
  1350.                 // Help text - intenal YaST2 error 1/3
  1351.     string help_text = UI(_("<p>An error has occurred. </p>
  1352. "));
  1353.                 // Help text - intenal YaST2 error 2/3
  1354.     help_text = help_text + UI(_("<p>Check that you have installed the correct <b>ALSA</b> package (series 
  1355. 'snd') and that you are running this configuration as root.</p>
  1356. "));
  1357.                 // Help text - intenal YaST2 error 3/3
  1358.     help_text = help_text + UI (_("<p>If this problem persists, you can try to pass <b>options</b> to the ALSA 
  1359. kernel module. If you still cannot get the sound card to work, you can try 
  1360. <i>OSS/Free</i> or other sound modules(drivers). However, <b>YaST2</b>sound 
  1361. configuration currently supports only ALSA modules. </p>
  1362. "));
  1363.  
  1364.     UI(`SetContents(_("Sound cards"),
  1365.                 // To translators: parameter to this is text, one of cannot find/write file
  1366.         `Label(sformat (UI(_("There was an error.\n%1")), error)),
  1367.         help_text, true, true));
  1368.     
  1369.           
  1370.     ret = UI(`UserInput ());
  1371.     if (ret == `next)
  1372.       id = size (conf_dialogs); // skip the rest of dialogs
  1373.     else if (ret == `back)
  1374.       id = 1; // first one
  1375.       }
  1376.     }
  1377.       
  1378.     return ret;
  1379.   };
  1380.  
  1381.                 // dialog for adjusting volume
  1382.   
  1383.   define AdjustVolume (integer step) ``{
  1384.                 // Help text - adjusting volume 1/3
  1385.     string help_text = UI(_("Please adjust the volume. "));
  1386.                 // Help text - adjusting volume 2/3
  1387.     help_text = help_text + UI(_("You can test your sound card by pressing the <i>Test</i> button. "));
  1388.                 // Help text - adjusting volume 3/3
  1389.     help_text = help_text + UI(_("After the configuration is done you can use <b>amixer</b> (or any program of your choice) for adjusting the volume."));
  1390.       
  1391.     integer vol = 50;        // let's start with 50% volume
  1392.     
  1393.     Shell ("/usr/bin/amixer set PCM $VOL unmute", $["VOL" : 100]);
  1394.  
  1395.     // various settings for various cards
  1396.     // ESS 1969 chipset has 2 PCM channels
  1397.     Shell ("/usr/bin/amixer set PCM,1 100% unmute 2>/dev/null");
  1398.     // Trident chipsets have also Wave group on digital path
  1399.     Shell ("/usr/bin/amixer set Wave 100% unmute 2>/dev/null");
  1400.     // CS4237B chipset
  1401.     Shell ("/usr/bin/amixer set Master Digital' 80% unmute 2>/dev/null");
  1402.     // for some GUS soundcards
  1403.     Shell ("/usr/bin/amixer set Synth 50% unmute 2>/dev/null");
  1404.  
  1405.     set_volume (vol);
  1406.  
  1407.     
  1408.     term con = `VBox (
  1409.       `VBox (
  1410.     `Top (
  1411.       `Label (card_title)
  1412.       ),
  1413.     `ReplacePoint (`id(`rprog),
  1414.                 // To translators: progress bar title
  1415.         `ProgressBar(`id(`pb), _("Volume"), 100, vol)),
  1416.     `HBox (
  1417.       `PushButton (`id(`minus), "-"),
  1418.       `PushButton (`id(`plus), "+")
  1419.       )
  1420.     ),
  1421.       `VStretch (),
  1422.                 // To translators: this label is just above the Test button
  1423.       `Label (_("To test the sound card press the button")),
  1424.                 // To translators: Test button label
  1425.       `PushButton (`id (`test), _("&Test"))
  1426.       );
  1427.     
  1428.     UI(`SetContents (_("Sound cards"), con, help_text, true, true));
  1429.     
  1430.     any ret = nil;
  1431.     
  1432.     repeat {
  1433.     
  1434.       ret =  UI (`UserInput ());
  1435.     
  1436.       if (ret == `minus) {
  1437.     if (vol > step) {
  1438.       vol = vol - step;
  1439.       set_volume (vol);
  1440.     }
  1441.     else {
  1442.       vol = 0;
  1443.     }
  1444.       }
  1445.       else if (ret == `plus) {
  1446.     if (vol + step < 100) {
  1447.       vol = vol + step;
  1448.       set_volume (vol);
  1449.     }
  1450.     else {
  1451.       vol = 100;
  1452.     }
  1453.       }
  1454.       else if (ret == `test)
  1455.     PlayTest ();
  1456.     
  1457.  
  1458.     
  1459.     
  1460.       UI (`ChangeWidget(`id(`pb), `Value, vol));
  1461.     
  1462.     } until ((ret == `back) || (ret == `next) || ret == `cancel);
  1463.     
  1464.     if (ret == `back) {
  1465.       RemoveModule (lookup (lookup(current_driver, "module"), "name"));
  1466.     }
  1467.     
  1468.     return ret;
  1469.   };
  1470.  
  1471.                 // dialog for saving volume and
  1472.                 // modules.conf, now joined into one dialog
  1473.   
  1474.   define SaveVolume () ``{
  1475.                 // Help text - saving configuration/volume 1/2
  1476.     string help_text = UI(_("The previously adjusted <b>volume</b> will be <b>stored</b> now for later use."));
  1477.                 // Help text - saving configuration/volume 2/2
  1478.     help_text = help_text + UI(_("The configuration of the sound card will be <b>saved</b>."));
  1479.  
  1480.     UI (`SetContents (_("Sound cards"),
  1481.     `VBox (
  1482.       `Top (
  1483.         `Label (card_title)
  1484.         ),
  1485.       `HVCenter (
  1486.           `ReplacePoint(`id(`la),
  1487.                 // To translators: label message
  1488.                 `Label (_("Sound volume and the configuration for the sound card\n
  1489. will be saved now.
  1490. "))
  1491.                 ))
  1492.       ), help_text, true, true));
  1493.     
  1494.       
  1495.     
  1496.  
  1497.     any ret = UI(`UserInput ());
  1498.       
  1499.       
  1500.     if (ret == `next) {
  1501.       if (Shell ("/usr/sbin/alsactl store") == 127) {
  1502.     
  1503.     // To translators: alsa package corrupted, exactly: alsactl missing
  1504.     string msg = sformat (UI(_("Cannot find 'alsactl'\nPlease check your installation of ALSA package")));
  1505.  
  1506.     UI (`DisplayMessage (msg, 0, ""));
  1507.       }
  1508.       
  1509.       else {
  1510.     UI(`ChangeWidget(`id(`back), `Enabled, false));
  1511.     UI(`ChangeWidget(`id(`next), `Enabled, false));
  1512.     
  1513.     string|void err = ConfModules (lookup (user_settings, "conf_modules"));
  1514.     
  1515.     UI(`ChangeWidget(`id(`back), `Enabled, true));
  1516.     UI(`ChangeWidget(`id(`next), `Enabled, true));
  1517.     
  1518.     if (err != nil) {
  1519.                 // show error to the user
  1520.       UI(`ReplaceWidget(`id(`la), `Label(err)));
  1521.       ret = UI(`UserInput ());
  1522.     }
  1523.     else {
  1524.       
  1525.       if (Shell("/sbin/depmod -a -F /boot/System.map-`uname -r` `uname -r`") == 127) { 
  1526.                 // To translators: possibly never happens, except that someone delete this file
  1527.         UI (`DisplayMessage (_("Cannot make a list of module dependencies."), 0, _("Program 'depmod' missing. Please reinstall 'modules' package (series 'a1').")));
  1528.       }
  1529.       else {
  1530.  
  1531.         UI(`ReplaceWidget(`id(`la),
  1532.                 // To translators: label message
  1533.                   `Label(_("The sound card was successfully configured\nand you can now use it."))));
  1534.         ret = UI(`UserInput ());
  1535.       }
  1536.     }
  1537.       }
  1538.     }
  1539.     return ret;
  1540.       
  1541.   };
  1542.  
  1543.                 // OBSOLETE NOW AND NOT USED, becouse
  1544.                 // it was joined into one dialog
  1545.   define SaveConfig (string f) ``{
  1546.                 // Help text 1/1
  1547.     string help_text = UI(_("The configuration of the sound card will be <b>saved</b>."));
  1548.       
  1549.     UI (`SetContents (_("Sound cards"),
  1550.     `VBox (
  1551.       `Top (
  1552.         `Label (card_title)
  1553.         ),
  1554.       `HVCenter (
  1555.         `ReplacePoint(`id(`la),
  1556.                 // To translators: label message
  1557.         `Label (_("The configuration for the sound card will be saved now.")))
  1558.         )), help_text, true, true));
  1559.       
  1560.  
  1561.     any ret = UI(`UserInput ());
  1562.  
  1563.     if (ret == `next) {
  1564.       
  1565.       string|void err = ConfModules (f);
  1566.  
  1567.       if (err != nil) {
  1568.                 // show error to the user
  1569.     UI(`ReplaceWidget(`id(`la), `Label(err)));
  1570.     ret = UI(`UserInput ());
  1571.       }
  1572.       
  1573.     }
  1574.  
  1575.     if (Shell("/sbin/depmod -a -F /boot/System.map-`uname -r` `uname -r`") == 127) { 
  1576.                 // To translators: possibly never happens, except that someone delete this file
  1577.       UI (`DisplayMessage (_("Cannot make a list of module dependencies."), 0, _("Program 'depmod' missing. Please reinstall 'modules' package (series 'a1').")));
  1578.     }
  1579.  
  1580.     return ret;
  1581.       
  1582.   };
  1583.  
  1584.                 // dialog, when some configuration
  1585.                 // already exists, it can be reseted
  1586.                 // by "Reset" button
  1587.   
  1588.   define EditCard () ``{
  1589.                 // Help text - existing sound card 1/2
  1590.     string help_text = UI(_("There <b>already exists</b> a configured sound card. "));
  1591.                 // Help text - existing sound card 2/2
  1592.     // To translators: the only way to change the configuration is to delete an old one and create another
  1593.     help_text = help_text + UI(_("Currently, YaST2 <b>cannot</b> be used for modifying existing sound card 
  1594. configurations. If you want to change a sound card's configuration,you must 
  1595. <b>reset</b> the existing card configuration and reconfigure the card from 
  1596. scratch.
  1597. "));
  1598.  
  1599.     list names = index_list (maplist (`i, already_configured, ``(lookup (i, "line1"))), 0);
  1600.       
  1601.     term contents = `ReplacePoint(`id(`ac_whole),`VBox(
  1602.                 
  1603.       `ReplacePoint (`id(`ac),
  1604.                 // To translators: selection box title
  1605.       `SelectionBox (_("Already configured sound cards"), names)),
  1606.                 // To translators: button label
  1607.       `PushButton (`id(`reset), _("&Reset"))
  1608.       )
  1609.                   );
  1610.       
  1611.     UI(`SetContents (_("Sound cards"), contents, help_text, true, true));
  1612.       
  1613.     any ret = nil;
  1614.       
  1615.     repeat {
  1616.       ret = UI(`UserInput ());
  1617.       
  1618.       if (ret == `reset) {
  1619.     RemoveAllAlsaModules ();
  1620.     
  1621.     if ((Shell ("/bin/ls /proc/asound/cards")) == 0)
  1622.         already_configured = SCR(`Read(.proc.asound.cards));
  1623.     else
  1624.         already_configured = nil;
  1625.     
  1626.     if (already_configured == nil) {
  1627.                 // To translators: label message
  1628.       UI(`ReplaceWidget(`id(`ac_whole), `Label (_("The previous configuration has been reset."))));
  1629.       UI(`ChangeWidget(`id(`back), `Enabled, false));
  1630.     }
  1631.     else {
  1632.       CanNotReset ();
  1633.       names = index_list (maplist (`i, already_configured, ``(lookup (i, "line1"))), 0);
  1634.     }
  1635.  
  1636.       }
  1637.       
  1638.       
  1639.     } until ((ret == `back) || (ret == `next) || ret == `cancel);
  1640.   };
  1641.   
  1642.  
  1643.  
  1644.  
  1645.   
  1646.   /* ==== */
  1647.   /* main */
  1648.   /* ==== */
  1649.   
  1650.   list|void snd_database = ReadY2 ("sndcards.ycp");
  1651.   
  1652.   
  1653.   
  1654.   map conf_dialogs = $[
  1655.     0 : ``FindCard (),
  1656.     1 : ``AdjustVolume (3),
  1657.     2 : ``SaveVolume ()
  1658.     //3 : ``SaveConfig (lookup (user_settings, "conf_modules"))
  1659.   ];
  1660.   
  1661.   
  1662.   integer id = 0;
  1663.   list cards = [];
  1664.                 // global variables
  1665.   map|void current_card = nil;
  1666.   map|void current_driver = nil;
  1667.   string current_options = "";
  1668.   map cur_options_map = $[];
  1669.   string card_title = "";
  1670.   
  1671.   list|void already_configured = nil;
  1672.  
  1673.   if ((Shell ("/bin/ls /proc/asound/cards")) == 0)
  1674.       already_configured = SCR(`Read(.proc.asound.cards));
  1675.  
  1676.   if (already_configured != nil && already_configured != []) {
  1677.     EditCard ();
  1678.   }
  1679.   if (already_configured == []) {
  1680.     WrongOutput ();        // "--- no soundcards ---" or other unrecognized output
  1681.   }
  1682.  
  1683.  
  1684.   if (IsAlsaInstalled ()) {
  1685.       
  1686.     if (snd_database != nil) {
  1687.       
  1688.       if (already_configured == nil) {
  1689.           
  1690.                 // FindCard, AdjustVolume, SaveVolume, SaveConfig
  1691.           
  1692.     while (id >= 0 && id < size (conf_dialogs)) {
  1693.           
  1694.       term dlg = lookup (conf_dialogs, id);
  1695.           
  1696.       any ret = eval(dlg);
  1697.           
  1698.       if (ret == `next)
  1699.         id = id + 1;
  1700.       else if (ret == `back) {
  1701.         id = id - 1;
  1702.         if (id == 0)
  1703.           cards = GetAudio ();
  1704.       }
  1705.       else if (ret == `cancel) break;
  1706.           
  1707.       if (id > 0 && cards == []) // no sound cards - exit
  1708.         break;
  1709.     }
  1710.       }
  1711.     }
  1712.     else
  1713.       DBNotFound ();
  1714.   }
  1715.   else
  1716.     NotInstalled ();
  1717.   
  1718.   UI(`CloseDialog());
  1719.  
  1720. }
  1721.