Back to index

lshw  02.16
spd.cc
Go to the documentation of this file.
00001 #include "version.h"
00002 #include "spd.h"
00003 #include "osutils.h"
00004 #include <sys/types.h>
00005 #include <sys/stat.h>
00006 #include <fcntl.h>
00007 #include <unistd.h>
00008 #include <string.h>
00009 #include <string>
00010 #include <dirent.h>
00011 #include <stdio.h>
00012 
00013 __ID("@(#) $Id: spd.cc 2433 2012-01-10 22:01:30Z lyonel $");
00014 
00015 /* SPD is 2048-bit long */
00016 #define SPD_MAXSIZE (2048/8)
00017 #define SPD_BLKSIZE 0x10
00018 
00019 #define TYPE_EDO  0x02
00020 #define TYPE_SDRAM  0x04
00021 
00022 #define PROCSENSORS "/proc/sys/dev/sensors"
00023 #define EEPROMPREFIX "eeprom-"
00024 
00025 static unsigned char spd[SPD_MAXSIZE];
00026 static bool spd_page_loaded[SPD_MAXSIZE / SPD_BLKSIZE];
00027 static string current_eeprom = "";
00028 static unsigned int current_bank = 0;
00029 
00030 static unsigned char get_spd_byte(unsigned int offset)
00031 {
00032   if ((offset < 0) || (offset >= SPD_MAXSIZE))
00033     return 0;
00034 
00035   if (!spd_page_loaded[offset / SPD_BLKSIZE])
00036   {
00037     char chunkname[10];
00038     string name = "";
00039     FILE *in = NULL;
00040 
00041     snprintf(chunkname, sizeof(chunkname), "%02x",
00042       (offset / SPD_BLKSIZE) * SPD_BLKSIZE);
00043 
00044     name = current_eeprom + "/" + string(chunkname);
00045 
00046     in = fopen(name.c_str(), "r");
00047     if (in)
00048     {
00049       for (int i = 0; i < SPD_BLKSIZE; i++)
00050         if(fscanf(in, "%d",
00051           (int *) &spd[i + (offset / SPD_BLKSIZE) * SPD_BLKSIZE]) < 1)
00052             break;
00053       fclose(in);
00054       spd_page_loaded[offset / SPD_BLKSIZE] = true;
00055     }
00056     else
00057       spd_page_loaded[offset / SPD_BLKSIZE] = false;
00058   }
00059 
00060   return spd[offset];
00061 }
00062 
00063 
00064 static int selecteeprom(const struct dirent *d)
00065 {
00066   struct stat buf;
00067 
00068   if (d->d_name[0] == '.')
00069     return 0;
00070 
00071   if (lstat(d->d_name, &buf) != 0)
00072     return 0;
00073 
00074   if (!S_ISDIR(buf.st_mode))
00075     return 0;
00076 
00077   return (strncmp(d->d_name, EEPROMPREFIX, strlen(EEPROMPREFIX)) == 0);
00078 }
00079 
00080 
00081 static hwNode *get_current_bank(hwNode & memory)
00082 {
00083   char id[20];
00084   hwNode *result = NULL;
00085 
00086   if ((current_bank == 0) && (result = memory.getChild("bank")))
00087     return result;
00088 
00089   snprintf(id, sizeof(id), "bank:%d", current_bank);
00090   result = memory.getChild(id);
00091 
00092   if (!result)
00093     return memory.addChild(hwNode(id, hw::memory));
00094   else
00095     return result;
00096 }
00097 
00098 
00099 static bool scan_eeprom(hwNode & memory,
00100 string name)
00101 {
00102   int memory_type = -1;
00103   char buff[20];
00104   unsigned char checksum = 0;
00105   unsigned char rows = 0;
00106   unsigned char density = 0;
00107   unsigned long long size = 0;
00108 
00109   current_eeprom = string(PROCSENSORS) + "/" + name;
00110   memset(spd, 0, sizeof(spd));
00111   memset(spd_page_loaded, 0, sizeof(spd_page_loaded));
00112 
00113   for (int i = 0; i < 63; i++)
00114     checksum += get_spd_byte(i);
00115 
00116   if (checksum != get_spd_byte(63))
00117     return false;
00118 
00119   memory_type = get_spd_byte(0x02);
00120 
00121   hwNode *bank = get_current_bank(memory);
00122 
00123   if (!bank)
00124     return false;
00125 
00126   switch (memory_type)
00127   {
00128     case TYPE_SDRAM:
00129       bank->setDescription("SDRAM");
00130       break;
00131     case TYPE_EDO:
00132       bank->setDescription("EDO");
00133       break;
00134   }
00135 
00136   rows = get_spd_byte(5);
00137   snprintf(buff, sizeof(buff), "%d", rows);
00138   bank->setConfig("rows", buff);
00139 
00140   if (bank->getSize() == 0)
00141   {
00142     density = get_spd_byte(31);
00143     for (int j = 0; (j < 8) && (rows > 0); j++)
00144       if (density & (1 << j))
00145     {
00146       rows--;
00147       size += (4 << j) * 1024 * 1024;             // MB
00148       density ^= (1 << j);
00149       if (density == 0)
00150         size += rows * (4 << j) * 1024 * 1024;
00151     }
00152     bank->setSize(size);
00153   }
00154 
00155   switch (get_spd_byte(11))                       // error detection and correction scheme
00156   {
00157     case 0x00:
00158       bank->setConfig("errordetection", "none");
00159       break;
00160     case 0x01:
00161       bank->addCapability("parity");
00162       bank->setConfig("errordetection", "parity");
00163       break;
00164     case 0x02:
00165       bank->addCapability("ecc");
00166       bank->setConfig("errordetection", "ecc");
00167       break;
00168   }
00169 
00170   int version = get_spd_byte(62);
00171 
00172   snprintf(buff, sizeof(buff), "spd-%d.%d", (version & 0xF0) >> 4,
00173     version & 0x0F);
00174   bank->addCapability(buff);
00175 
00176   return true;
00177 }
00178 
00179 
00180 static bool scan_eeproms(hwNode & memory)
00181 {
00182   struct dirent **namelist;
00183   int n;
00184 
00185   current_bank = 0;
00186 
00187   pushd(PROCSENSORS);
00188   n = scandir(".", &namelist, selecteeprom, alphasort);
00189   popd();
00190 
00191   if (n < 0)
00192     return false;
00193 
00194   for (int i = 0; i < n; i++)
00195     if (scan_eeprom(memory, namelist[i]->d_name))
00196       current_bank++;
00197 
00198   return true;
00199 }
00200 
00201 
00202 bool scan_spd(hwNode & n)
00203 {
00204   hwNode *memory = n.getChild("core/memory");
00205 
00206   current_bank = 0;
00207 
00208   if (!memory)
00209   {
00210     hwNode *core = n.getChild("core");
00211 
00212     if (!core)
00213     {
00214       n.addChild(hwNode("core", hw::bus));
00215       core = n.getChild("core");
00216     }
00217 
00218     if (core)
00219     {
00220       core->addChild(hwNode("memory", hw::memory));
00221       memory = core->getChild("memory");
00222     }
00223   }
00224 
00225   if (memory)
00226   {
00227     memory->claim();
00228 
00229     return scan_eeproms(*memory);
00230   }
00231 
00232   return false;
00233 }