home *** CD-ROM | disk | FTP | other *** search
/ Chip 2007 January, February, March & April / Chip-Cover-CD-2007-02.iso / boot / i386 / root / usr / share / YaST2 / modules / NewID.ycp < prev    next >
Text File  |  2006-11-29  |  16KB  |  658 lines

  1. /**
  2.  *
  3.  * Module:    Set new PCI ID for kernel drivers
  4.  *
  5.  * Author:    Ladislav Slezak <lslezak@suse.cz>
  6.  *
  7.  * $Id: NewID.ycp 33530 2006-10-20 11:08:26Z lslezak $
  8.  *
  9.  * Manage new PCI IDs for kernel drivers
  10.  */
  11.  
  12. {
  13.     import "String";
  14.     import "Report";
  15.     import "ModuleLoading";
  16.     import "Linuxrc";
  17.     import "FileUtils";
  18.  
  19.     include "hwinfo/routines.ycp";
  20.  
  21.     module "NewID";
  22.     textdomain "tune";
  23.  
  24.     // list of configured PCI IDs
  25.     list< map<string,any> > new_ids = nil;
  26.     list< map<string,any> > removed_ids = [];
  27.  
  28.     // cache .probe.pci values
  29.     list<map> pcidevices = nil;
  30.  
  31.     boolean refresh_proposal = false;
  32.     string configfile = "/etc/sysconfig/hardware/newids";
  33.  
  34.     global define list<map> GetPCIdevices() {
  35.       if (pcidevices == nil)
  36.       {
  37.           // initialize list
  38.           pcidevices = (list<map>)SCR::Read(.probe.pci);
  39.  
  40.           // still nil, set to empty - avoid reprobing next time
  41.           if (pcidevices == nil)
  42.           {
  43.               pcidevices = [];
  44.           }
  45.       }
  46.  
  47.       return pcidevices;
  48.     }
  49.  
  50.  
  51.     global define void AddID(map<string,string> new_id) {
  52.         // initialize list if needed
  53.         if (new_ids == nil)
  54.         {
  55.             new_ids = [];
  56.         }
  57.  
  58.     if (new_id != nil && new_id != $[])
  59.     {
  60.         if (new_ids == nil)
  61.         {
  62.         new_ids = [ new_id ];
  63.         refresh_proposal = true;
  64.  
  65.         if (contains(removed_ids, new_id))
  66.         {
  67.             // remove added id from removed list
  68.             removed_ids = filter(map<string,any> i, removed_ids, {return i != new_id;});
  69.         }
  70.         }
  71.         else if (!contains(new_ids, new_id))
  72.         {
  73.         new_ids = add(new_ids, new_id);
  74.         refresh_proposal = true;
  75.         }
  76.     }
  77.     }
  78.  
  79.     global define void RemoveID(integer index) {
  80.         map<string,any> removed_id = new_ids[index]:$[];
  81.  
  82.     new_ids = remove(new_ids, index);
  83.     refresh_proposal = true;
  84.  
  85.     // add to removed
  86.     if (removed_id != nil && removed_id != $[] && !contains(removed_ids, removed_id))
  87.     {
  88.         removed_ids = add(removed_ids, removed_id);
  89.  
  90.         if (contains(new_ids, removed_id))
  91.         {
  92.         // remove deleted id from list of new
  93.         new_ids = filter(map<string,any> i, new_ids, {return i != removed_id;});
  94.         }
  95.     }
  96.     }
  97.  
  98.     global define list< map<string,any> > GetNewIDs() {
  99.     return new_ids;
  100.     }
  101.  
  102.     global define map<string,any> GetNewID(integer index) {
  103.     return new_ids[index]:$[];
  104.     }
  105.  
  106.     global define void SetNewID(map<string,any> nid, integer index) {
  107.     new_ids[index] = nid;
  108.     refresh_proposal = true;
  109.     }
  110.  
  111.     global define boolean RefreshProposal() {
  112.     return refresh_proposal;
  113.     }
  114.  
  115.     global define boolean Read(string filename) {
  116.     if (filename != nil && filename != "")
  117.     {
  118.         new_ids = [];
  119.  
  120.         // read file
  121.         string file = nil;
  122.         if (FileUtils::Exists(filename)) {
  123.         file = (string) SCR::Read(.target.string, filename);
  124.         } else {
  125.         y2milestone("File %1 does not exist yet", filename);
  126.         }
  127.  
  128.         if (file == nil)
  129.         {
  130.         return false;
  131.         }
  132.  
  133.         list<string> lines = splitstring(file, "\n");
  134.  
  135.         y2debug("lines: %1", lines);
  136.         list<string> comment = [];
  137.  
  138.         // parse lines
  139.         foreach(string line, lines, {
  140.             line = String::CutBlanks(line);
  141.  
  142.             if (regexpmatch(line, "^#.*"))
  143.             {
  144.             // line is a comment
  145.             comment = add(comment, line);
  146.             }
  147.             else
  148.             {
  149.             list<string> parts = splitstring(line, ",");
  150.  
  151.             string driver = parts[1]:nil;
  152.             string sysdir = parts[2]:nil;
  153.  
  154.             // parse newid line
  155.             // replace tabs by spaces
  156.             line = mergestring(splitstring(parts[0]:"", "\t"), " ");
  157.  
  158.             list<string> idparts = splitstring(line, " ");
  159.  
  160.             idparts = filter(string part, idparts, {return part != nil && part != "";});
  161.  
  162.             string vendor = idparts[0]:nil;
  163.             string device = idparts[1]:nil;
  164.             string subvendor = idparts[2]:nil;
  165.             string subdevice = idparts[3]:nil;
  166.             string class = idparts[4]:nil;
  167.             string class_mask = idparts[5]:nil;
  168.             string driver_data = idparts[6]:nil;
  169.  
  170.             map<string,any> newid = $[];
  171.  
  172.             // search for existing PCI card if class is not specified
  173.             if (class_mask == nil && class == nil && vendor != nil && device != nil)
  174.             {
  175.                 integer vid = nil;
  176.                 integer did = nil;
  177.                 integer svid = nil;
  178.                 integer sdid = nil;
  179.  
  180.                 if (vendor != nil)
  181.                 {
  182.                 vid = tointeger((!has_hex_prefix(vendor)) ? "0x" + vendor : vendor);
  183.                 }
  184.                 if (device != nil)
  185.                 {
  186.                 did = tointeger((!has_hex_prefix(device)) ? "0x" + device : device);
  187.                 }
  188.                 if (subvendor != nil)
  189.                 {
  190.                 svid = tointeger((!has_hex_prefix(subvendor)) ? "0x" + subvendor : subvendor);
  191.                 }
  192.                 if (subdevice != nil)
  193.                 {
  194.                 sdid = tointeger((!has_hex_prefix(subdevice)) ? "0x" + subdevice : subdevice);
  195.                 }
  196.  
  197.                 y2debug("vid: %1", vid);
  198.                 y2debug("did: %1", did);
  199.                 y2debug("svid: %1", svid);
  200.                 y2debug("sdid: %1", sdid);
  201.  
  202.                 foreach(map dev, GetPCIdevices(), {
  203.                     // check ID
  204.  
  205.                     if (vid == dev["vendor_id"]:0 - 0x10000 && did == dev["device_id"]:0 - 0x10000)
  206.                     {
  207.                     // some devices don't have subdevice, subvendor
  208.                     if (haskey(dev, "sub_vendor_id") && haskey(dev, "sub_device_id"))
  209.                     {
  210.                         if (svid == dev["sub_vendor_id"]:0 - 0x10000 && sdid == dev["sub_device_id"]:0 - 0x10000)
  211.                         {
  212.                         newid["uniq"] = dev["unique_key"]:"";
  213.                         }
  214.                     }
  215.                     else
  216.                     {
  217.                         newid["uniq"] = dev["unique_key"]:"";
  218.                     }
  219.                     }
  220.                 }
  221.                 );
  222.             }
  223.  
  224.             if (!haskey(newid, "uniq"))
  225.             {
  226.                 if (vendor != nil) newid["vendor"] = vendor;
  227.                 if (device != nil) newid["device"] = device;
  228.                 if (subvendor != nil) newid["subvendor"] = subvendor;
  229.                 if (subdevice != nil) newid["subdevice"] = subdevice;
  230.                 if (class != nil) newid["class"] = class;
  231.                 if (class_mask != nil) newid["class_mask"] = class_mask;
  232.             }
  233.  
  234.             if (driver_data != nil) newid["driver_data"] = driver_data;
  235.  
  236.             if (driver != nil) newid["driver"] = driver;
  237.             if (sysdir != nil) newid["sysdir"] = sysdir;
  238.             if (size(comment) > 0) newid["comment"] = comment;
  239.  
  240.             y2milestone("read newid: %1", newid);
  241.  
  242.             if (newid != $[])
  243.             {
  244.                 new_ids = add(new_ids, newid);
  245.             }
  246.  
  247.             comment = [];
  248.             }
  249.         }
  250.         );
  251.  
  252.         y2milestone("Read settings: %1", new_ids);
  253.  
  254.         return true;
  255.     }
  256.     return false;
  257.     }
  258.  
  259.     /**
  260.      * Prepend option to PCI ID string, use default value if required
  261.      * @param newopt Prepend this option
  262.      * @param opts Already existing option string
  263.      * @param defval Default value, used when newopt is empty
  264.      */
  265.     define string prepend_option(string newopt, string opts, string defval) {
  266.  
  267.     if (opts == "" && newopt == "")
  268.     {
  269.         return "";
  270.     }
  271.  
  272.     if (size(opts) > 0)
  273.     {
  274.         return ((size(newopt) > 0) ? newopt : defval) + " " + opts;
  275.     }
  276.     else
  277.     {
  278.         return newopt;
  279.     }
  280.     }
  281.  
  282.     global define map AddIDs(map id)
  283.     {
  284.     map newid = id;
  285.  
  286.     if (haskey(newid, "uniq"))
  287.     {
  288.         // add device/vendor values from PCI scan for selected PCI device
  289.         foreach(map pcidev, GetPCIdevices(), {
  290.             if (pcidev["unique_key"]:"" == newid["uniq"]:"")
  291.             {
  292.             y2debug("Found PCI device: %1", pcidev);
  293.             // libhd uses 0x10000 offset for PCI devices
  294.             if (haskey(pcidev, "device_id"))
  295.             {
  296.                 newid["device"] = tohexstring(pcidev["device_id"]:0 - 0x10000);
  297.             }
  298.             if (haskey(pcidev, "sub_device_id"))
  299.             {
  300.                 newid["subdevice"] = tohexstring(pcidev["sub_device_id"]:0 - 0x10000);
  301.             }
  302.             if (haskey(pcidev, "vendor_id"))
  303.             {
  304.                 newid["vendor"] = tohexstring(pcidev["vendor_id"]:0 - 0x10000);
  305.             }
  306.             if (haskey(pcidev, "sub_vendor_id"))
  307.             {
  308.                 newid["subvendor"] = tohexstring(pcidev["sub_vendor_id"]:0 - 0x10000);
  309.             }
  310.             }
  311.         }
  312.         );
  313.     }
  314.  
  315.     return newid;
  316.     }
  317.  
  318.     define string FormatActivationString(map newid)
  319.     {
  320.     // create ID string which is passed to the driver
  321.     string ret = "";
  322.  
  323.     string pci_any_id = "ffffffff";
  324.     string default_class = "0";
  325.     string default_mask = "0";
  326.  
  327.         if (haskey(newid, "uniq"))
  328.         {
  329.             newid = AddIDs(newid);
  330.         }
  331.  
  332.     ret = prepend_option(remove_hex_prefix(newid["class_mask"]:""), ret, default_mask);
  333.     ret = prepend_option(remove_hex_prefix(newid["class"]:""), ret, default_class);
  334.     ret = prepend_option(remove_hex_prefix(newid["subdevice"]:""), ret, pci_any_id);
  335.     ret = prepend_option(remove_hex_prefix(newid["subvendor"]:""), ret, pci_any_id);
  336.     ret = prepend_option(remove_hex_prefix(newid["device"]:""), ret, pci_any_id);
  337.     ret = prepend_option(remove_hex_prefix(newid["vendor"]:""), ret, pci_any_id);
  338.  
  339.     return ret;
  340.     }
  341.  
  342.     /**
  343.      * Activate value stored in the internal list
  344.      * @return boolean True if all settings were successfuly set
  345.      */
  346.     global define boolean Activate() {
  347.     boolean ret = true;
  348.  
  349.     if (new_ids != nil)
  350.     {
  351.         foreach(map newid, new_ids, {
  352.             string modulename = newid["driver"]:"";
  353.             string sysdir = newid["sysdir"]:"";
  354.  
  355.             // load kernel module if it isn't already loaded
  356.             if (modulename != nil && modulename != "")
  357.             {
  358.             ModuleLoading::Load(modulename, "", // TODO allow setting of module args?
  359.                 // vendor is empty, device name is unknown
  360.                 "", _("Unknown device"), Linuxrc::manual(), true);
  361.             }
  362.  
  363.  
  364.             if (sysdir == nil || sysdir == "")
  365.             {
  366.             sysdir = modulename;
  367.             }
  368.  
  369.             string targetfile = sformat("/sys/bus/pci/drivers/%1/new_id", sysdir);
  370.  
  371.             // create ID string passed to the driver
  372.             string idstring = FormatActivationString(newid);
  373.  
  374.             // check whether target file exists
  375.             integer filesize = (integer) SCR::Read(.target.size, targetfile);
  376.  
  377.             if (filesize >= 0)
  378.             {
  379.             // set the new value
  380.             boolean set = (integer) SCR::Execute(.target.bash, sformat("echo '%1' > %2", idstring, targetfile)) == 0;
  381.  
  382.             if (!set)
  383.             {
  384.                 y2error("Setting the new id failed: driver: %1, value: %2", targetfile, idstring);
  385.                 ret = false;
  386.             }
  387.             else
  388.             {
  389.                 y2milestone("File %1 - new PCI ID '%2' was succesfully set", targetfile, idstring);
  390.             }
  391.             }
  392.             else
  393.             {
  394.             // Error message
  395.             Report::Error(sformat(_("File '%1' does not exist. Cannot set new PCI ID."), targetfile));
  396.             ret = false;
  397.             }
  398.  
  399.         }
  400.         );
  401.     }
  402.  
  403.     return ret;
  404.     }
  405.  
  406.     define string HwcfgFileName(map newid) {
  407.     string ret = "";
  408.  
  409.         if (haskey(newid, "uniq"))
  410.         {
  411.             newid = AddIDs(newid);
  412.         }
  413.  
  414.     string vendor = remove_hex_prefix(newid["vendor"]:"");
  415.     string device = remove_hex_prefix(newid["device"]:"");
  416.  
  417.     if (size(vendor) > 0 && size(device) > 0)
  418.     {
  419.         ret = sformat("vpid-%1-%2", vendor, device);
  420.  
  421.         string subvendor = remove_hex_prefix(newid["subvendor"]:"");
  422.         string subdevice = remove_hex_prefix(newid["subdevice"]:"");
  423.  
  424.         if (size(subvendor) > 0 && size(subdevice) > 0)
  425.         {
  426.         ret = sformat("%1-%2-%3", ret, subvendor, subdevice);
  427.         }
  428.     }
  429.  
  430.     y2debug("activation string: %1", ret);
  431.     return ret;
  432.     }
  433.  
  434.     define boolean WriteHwcfg(map newid) {
  435.     boolean ret = false;
  436.     string cfgname = HwcfgFileName(newid);
  437.     string driver = newid["driver"]:"";
  438.  
  439.     y2debug("newid: %1", newid);
  440.     y2debug("cfgname: %1", cfgname);
  441.     y2debug("driver: %1", driver);
  442.  
  443.     if (cfgname != "" && driver != "")
  444.     {
  445.         // prepare hwcfg values
  446.         string startmode = "auto";
  447.         string module_options = "";
  448.  
  449.         path p = .sysconfig.hardware.value + topath(cfgname);
  450.  
  451.         // write the values
  452.         SCR::Write(p + .MODULE, driver);
  453.         SCR::Write(p + .STARTMODE, startmode);
  454.         SCR::Write(p + .MODULE_OPTIONS, module_options);
  455.  
  456.         // flush the changes
  457.         SCR::Write(.sysconfig.hardware, nil);
  458.     }
  459.  
  460.     return ret;
  461.     }
  462.  
  463.     define boolean RemoveExistingFile(string fname)
  464.     {
  465.     boolean ret = true;
  466.  
  467.     if (fname != nil && fname != "")
  468.     {
  469.         // remove old config file if it exists
  470.         if (SCR::Read(.target.size, fname) > 0)
  471.         {
  472.         integer res = (integer) SCR::Execute(.target.bash, "/bin/rm " + fname);
  473.  
  474.         if (res != 0)
  475.         {
  476.             y2warning("Removing of file %1 has failed, exit: %2", fname, res);
  477.         }
  478.         else
  479.         {
  480.             y2milestone("Removed file: %1", fname);
  481.         }
  482.         }
  483.     }
  484.  
  485.     return ret;
  486.     }
  487.  
  488.     global define boolean Write() {
  489.     y2milestone("Writing PCI ID cofiguration...");
  490.  
  491.     boolean ret = true;
  492.  
  493.     // content of /etc/sysconfig/hardware/newids
  494.     string sysconfig = "";
  495.  
  496.     // map ID commands to driver
  497.     map<string,list<string> > settings = $[];
  498.  
  499.         // handle removed configurations - remove all modprobe entries
  500.     if (size(removed_ids) > 0)
  501.     {
  502.         list<string> drvs = SCR::Dir(.modprobe_newid.install);
  503.  
  504.         if (drvs != nil && size(drvs) > 0)
  505.         {
  506.         foreach(string d, drvs, {
  507.             SCR::Write(add(.modprobe_newid.install, d), nil);
  508.             }
  509.         );
  510.         }
  511.     }
  512.  
  513.     if (new_ids != nil)
  514.     {
  515.         foreach(map newid, new_ids, {
  516.             string modulename = newid["driver"]:"";
  517.             string sysdir = newid["sysdir"]:"";
  518.             string idstring = FormatActivationString(newid);
  519.  
  520.             // write settings to /etc/modprobe.d/newid if the module is known
  521.             // (the module is not compiled into the kernel)
  522.             if (modulename != "")
  523.             {
  524.             string targetfile = (sysdir != "") ? sysdir : modulename;
  525.             string install_string = sformat("echo '%1' > /sys/bus/pci/drivers/%2/new_id", idstring, targetfile);
  526.  
  527.             list<string> current = settings[modulename]:[];
  528.             current = add(current, install_string);
  529.             settings[modulename] = current;
  530.             }
  531.  
  532.             // write hwcfg file to load the driver
  533.             WriteHwcfg(newid);
  534.  
  535.             // add to /etc/sysconfig/hardware/newids
  536.             if (haskey(newid, "comment"))
  537.             {
  538.             // add the comment
  539.             sysconfig = sysconfig + mergestring(newid["comment"]:[], "\n") + "\n";
  540.             }
  541.  
  542.             sysconfig = sysconfig + idstring + "," + modulename;
  543.  
  544.             if (sysdir != "")
  545.             {
  546.             sysconfig = sysconfig + "," + sysdir;
  547.             }
  548.  
  549.             // add trailing newline
  550.             sysconfig = sysconfig + "\n";
  551.         }
  552.         );
  553.     }
  554.  
  555.     // write sysconfig settings
  556.     if (size(sysconfig) > 0)
  557.     {
  558.         // write sysconfig file
  559.         ret = ret && (boolean) SCR::Write(.target.string, configfile, sysconfig);
  560.     }
  561.     else
  562.     {
  563.         // remove old config file if it exists
  564.         RemoveExistingFile(configfile);
  565.     }
  566.  
  567.     // write modprobe settings
  568.     if (size(settings) > 0)
  569.     {
  570.         foreach(string modulename, list<string> values, settings, {
  571.             string install_string = sformat("/sbin/modprobe --ignore-install %1; %2", modulename, mergestring(values, "; "));
  572.  
  573.             ret = ret && (boolean) SCR::Write(add(.modprobe_newid.install, modulename), install_string);
  574.         }
  575.         );
  576.  
  577.         // flush changes
  578.         SCR::Write(.modprobe_newid, nil);
  579.     }
  580.  
  581.     // handle removed configurations - remove hwcfg files
  582.     if (size(removed_ids) > 0)
  583.     {
  584.         foreach(map<string,any> rem, removed_ids, {
  585.             string fname = HwcfgFileName(rem);
  586.  
  587.             if (fname != "")
  588.             {
  589.             // remove the file
  590.             fname = "/etc/sysconfig/hardware/hwcfg-" + fname;
  591.             RemoveExistingFile(fname);
  592.             }
  593.         }
  594.         );
  595.     }
  596.  
  597.     return ret;
  598.     }
  599.  
  600.     global define string GetModelString(string uniq) {
  601.     string ret = "";
  602.  
  603.     foreach(map d, GetPCIdevices(), {
  604.         if (d["unique_key"]:"" == uniq)
  605.         {
  606.             ret = d["model"]:"";
  607.         }
  608.         }
  609.     );
  610.  
  611.     return ret;
  612.     }
  613.  
  614.     /**
  615.      * Return new ID description
  616.      * @return list(string) list of hardware desciptions
  617.      */
  618.     global define list<string> MakeProposal() ``{
  619.     list<string> ret = [];
  620.  
  621.     if (size(new_ids) > 0)
  622.     {
  623.         foreach(map newid, new_ids, {
  624.             string modulename = newid["driver"]:"";
  625.             string sysdir = newid["sysdir"]:"";
  626.  
  627.             string idstring = FormatActivationString(newid);
  628.             string targetfile = (sysdir != "") ? sysdir : modulename;
  629.  
  630.             // test for installation proposal
  631.             // %1 - name of kernel driver (e.g. e100)
  632.             // %2 - PCI ID (hexnumbers)
  633.             string info = sformat(_("Driver: %1, New PCI ID: %2"), targetfile, idstring);
  634.  
  635.             if (haskey(newid, "uniq"))
  636.             {
  637.             string model = GetModelString(newid["uniq"]:"");
  638.  
  639.             if (model != nil && model != "")
  640.             {
  641.                 info = info + sformat(" (%1)", model);
  642.             }
  643.             }
  644.  
  645.             ret = add(ret, info);
  646.         }
  647.         );
  648.     }
  649.  
  650.     y2milestone("NewID proposal: %1", ret);
  651.  
  652.     // proposal is valid
  653.     refresh_proposal = false;
  654.  
  655.     return ret;
  656.     }
  657. }
  658.