"Fossies" - the Fresh Open Source Software Archive

Member "dmidecode-3.2/dmioem.c" (14 Sep 2018, 13161 Bytes) of package /linux/privat/dmidecode-3.2.tar.xz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "dmioem.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 3.1_vs_3.2.

    1 /*
    2  * Decoding of OEM-specific entries
    3  * This file is part of the dmidecode project.
    4  *
    5  *   Copyright (C) 2007-2008 Jean Delvare <jdelvare@suse.de>
    6  *
    7  *   This program is free software; you can redistribute it and/or modify
    8  *   it under the terms of the GNU General Public License as published by
    9  *   the Free Software Foundation; either version 2 of the License, or
   10  *   (at your option) any later version.
   11  *
   12  *   This program is distributed in the hope that it will be useful,
   13  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
   14  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   15  *   GNU General Public License for more details.
   16  *
   17  *   You should have received a copy of the GNU General Public License
   18  *   along with this program; if not, write to the Free Software
   19  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
   20  */
   21 
   22 #include <stdio.h>
   23 #include <string.h>
   24 
   25 #include "types.h"
   26 #include "dmidecode.h"
   27 #include "dmioem.h"
   28 
   29 /*
   30  * Globals for vendor-specific decodes
   31  */
   32 
   33 enum DMI_VENDORS
   34 {
   35     VENDOR_UNKNOWN,
   36     VENDOR_ACER,
   37     VENDOR_HP,
   38     VENDOR_HPE,
   39     VENDOR_IBM,
   40     VENDOR_LENOVO,
   41 };
   42 
   43 static enum DMI_VENDORS dmi_vendor = VENDOR_UNKNOWN;
   44 
   45 /*
   46  * Remember the system vendor for later use. We only actually store the
   47  * value if we know how to decode at least one specific entry type for
   48  * that vendor.
   49  */
   50 void dmi_set_vendor(const char *s)
   51 {
   52     int len;
   53 
   54     /*
   55      * Often DMI strings have trailing spaces. Ignore these
   56      * when checking for known vendor names.
   57      */
   58     len = strlen(s);
   59     while (len && s[len - 1] == ' ')
   60         len--;
   61 
   62     if (strncmp(s, "Acer", len) == 0)
   63         dmi_vendor = VENDOR_ACER;
   64     else if (strncmp(s, "HP", len) == 0 || strncmp(s, "Hewlett-Packard", len) == 0)
   65         dmi_vendor = VENDOR_HP;
   66     else if (strncmp(s, "HPE", len) == 0 || strncmp(s, "Hewlett Packard Enterprise", len) == 0)
   67         dmi_vendor = VENDOR_HPE;
   68     else if (strncmp(s, "IBM", len) == 0)
   69         dmi_vendor = VENDOR_IBM;
   70     else if (strncmp(s, "LENOVO", len) == 0)
   71         dmi_vendor = VENDOR_LENOVO;
   72 }
   73 
   74 /*
   75  * Acer-specific data structures are decoded here.
   76  */
   77 
   78 static int dmi_decode_acer(const struct dmi_header *h)
   79 {
   80     u8 *data = h->data;
   81     u16 cap;
   82 
   83     switch (h->type)
   84     {
   85         case 170:
   86             /*
   87              * Vendor Specific: Acer Hotkey Function
   88              *
   89              * Source: acer-wmi kernel driver
   90              *
   91              * Probably applies to some laptop models of other
   92              * brands, including Fujitsu-Siemens, Medion, Lenovo,
   93              * and eMachines.
   94              */
   95             printf("Acer Hotkey Function\n");
   96             if (h->length < 0x0F) break;
   97             cap = WORD(data + 0x04);
   98             printf("\tFunction bitmap for Communication Button: 0x%04hx\n", cap);
   99             printf("\t\tWiFi: %s\n", cap & 0x0001 ? "Yes" : "No");
  100             printf("\t\t3G: %s\n", cap & 0x0040 ? "Yes" : "No");
  101             printf("\t\tWiMAX: %s\n", cap & 0x0080 ? "Yes" : "No");
  102             printf("\t\tBluetooth: %s\n", cap & 0x0800 ? "Yes" : "No");
  103             printf("\tFunction bitmap for Application Button: 0x%04hx\n", WORD(data + 0x06));
  104             printf("\tFunction bitmap for Media Button: 0x%04hx\n", WORD(data + 0x08));
  105             printf("\tFunction bitmap for Display Button: 0x%04hx\n", WORD(data + 0x0A));
  106             printf("\tFunction bitmap for Others Button: 0x%04hx\n", WORD(data + 0x0C));
  107             printf("\tCommunication Function Key Number: %d\n", data[0x0E]);
  108             break;
  109 
  110         default:
  111             return 0;
  112     }
  113     return 1;
  114 }
  115 
  116 /*
  117  * HPE-specific data structures are decoded here.
  118  *
  119  * Code contributed by John Cagle and Tyler Bell.
  120  */
  121 
  122 static void dmi_print_hp_net_iface_rec(u8 id, u8 bus, u8 dev, const u8 *mac)
  123 {
  124     /* Some systems do not provide an id. nic_ctr provides an artificial
  125      * id, and assumes the records will be provided "in order".  Also,
  126      * using 0xFF marker is not future proof. 256 NICs is a lot, but
  127      * 640K ought to be enough for anybody(said no one, ever).
  128      * */
  129     static u8 nic_ctr;
  130 
  131     if (id == 0xFF)
  132         id = ++nic_ctr;
  133 
  134     if (dev == 0x00 && bus == 0x00)
  135         printf("\tNIC %d: Disabled\n", id);
  136     else if (dev == 0xFF && bus == 0xFF)
  137         printf("\tNIC %d: Not Installed\n", id);
  138     else
  139     {
  140         printf("\tNIC %d: PCI device %02x:%02x.%x, "
  141             "MAC address %02X:%02X:%02X:%02X:%02X:%02X\n",
  142             id, bus, dev >> 3, dev & 7,
  143             mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
  144     }
  145 }
  146 
  147 static int dmi_decode_hp(const struct dmi_header *h)
  148 {
  149     u8 *data = h->data;
  150     int nic, ptr;
  151     u32 feat;
  152     const char *company = (dmi_vendor == VENDOR_HP) ? "HP" : "HPE";
  153 
  154     switch (h->type)
  155     {
  156         case 204:
  157             /*
  158              * Vendor Specific: HPE ProLiant System/Rack Locator
  159              */
  160             printf("%s ProLiant System/Rack Locator\n", company);
  161             if (h->length < 0x0B) break;
  162             printf("\tRack Name: %s\n", dmi_string(h, data[0x04]));
  163             printf("\tEnclosure Name: %s\n", dmi_string(h, data[0x05]));
  164             printf("\tEnclosure Model: %s\n", dmi_string(h, data[0x06]));
  165             printf("\tEnclosure Serial: %s\n", dmi_string(h, data[0x0A]));
  166             printf("\tEnclosure Bays: %d\n", data[0x08]);
  167             printf("\tServer Bay: %s\n", dmi_string(h, data[0x07]));
  168             printf("\tBays Filled: %d\n", data[0x09]);
  169             break;
  170 
  171         case 209:
  172         case 221:
  173             /*
  174              * Vendor Specific: HPE ProLiant NIC MAC Information
  175              *
  176              * This prints the BIOS NIC number,
  177              * PCI bus/device/function, and MAC address
  178              *
  179              * Type 209:
  180              * Offset |  Name  | Width | Description
  181              * -------------------------------------
  182              *  0x00  |  Type  | BYTE  | 0xD1, MAC Info
  183              *  0x01  | Length | BYTE  | Length of structure
  184              *  0x02  | Handle | WORD  | Unique handle
  185              *  0x04  | Dev No | BYTE  | PCI Device/Function No
  186              *  0x05  | Bus No | BYTE  | PCI Bus
  187              *  0x06  |   MAC  | 6B    | MAC addr
  188              *  0x0C  | NIC #2 | 8B    | Repeat 0x04-0x0B
  189              *
  190              * Type 221: is deprecated in the latest docs
  191              */
  192             printf("%s %s\n", company,
  193                 h->type == 221 ?
  194                     "BIOS iSCSI NIC PCI and MAC Information" :
  195                     "BIOS PXE NIC PCI and MAC Information");
  196             nic = 1;
  197             ptr = 4;
  198             while (h->length >= ptr + 8)
  199             {
  200                 dmi_print_hp_net_iface_rec(nic,
  201                                data[ptr + 0x01],
  202                                data[ptr],
  203                                &data[ptr + 0x02]);
  204                 nic++;
  205                 ptr += 8;
  206             }
  207             break;
  208 
  209         case 233:
  210             /*
  211              * Vendor Specific: HPE ProLiant NIC MAC Information
  212              *
  213              * This prints the BIOS NIC number,
  214              * PCI bus/device/function, and MAC address
  215              *
  216              * Offset |  Name  | Width | Description
  217              * -------------------------------------
  218              *  0x00  |  Type  | BYTE  | 0xE9, NIC structure
  219              *  0x01  | Length | BYTE  | Length of structure
  220              *  0x02  | Handle | WORD  | Unique handle
  221              *  0x04  | Grp No | WORD  | 0 for single segment
  222              *  0x06  | Bus No | BYTE  | PCI Bus
  223              *  0x07  | Dev No | BYTE  | PCI Device/Function No
  224              *  0x08  |   MAC  | 32B   | MAC addr padded w/ 0s
  225              *  0x28  | Port No| BYTE  | Each NIC maps to a Port
  226              */
  227             printf("%s BIOS PXE NIC PCI and MAC Information\n", company);
  228             if (h->length < 0x0E) break;
  229             /* If the record isn't long enough, we don't have an ID
  230              * use 0xFF to use the internal counter.
  231              * */
  232             nic = h->length > 0x28 ? data[0x28] : 0xFF;
  233             dmi_print_hp_net_iface_rec(nic, data[0x06], data[0x07],
  234                            &data[0x08]);
  235             break;
  236 
  237         case 212:
  238             /*
  239              * Vendor Specific: HPE 64-bit CRU Information
  240              *
  241              * Source: hpwdt kernel driver
  242              */
  243             printf("%s 64-bit CRU Information\n", company);
  244             if (h->length < 0x18) break;
  245             printf("\tSignature: 0x%08x", DWORD(data + 0x04));
  246             if (is_printable(data + 0x04, 4))
  247                 printf(" (%c%c%c%c)", data[0x04], data[0x05],
  248                     data[0x06], data[0x07]);
  249             printf("\n");
  250             if (DWORD(data + 0x04) == 0x55524324)
  251             {
  252                 u64 paddr = QWORD(data + 0x08);
  253                 paddr.l += DWORD(data + 0x14);
  254                 if (paddr.l < DWORD(data + 0x14))
  255                     paddr.h++;
  256                 printf("\tPhysical Address: 0x%08x%08x\n",
  257                     paddr.h, paddr.l);
  258                 printf("\tLength: 0x%08x\n", DWORD(data + 0x10));
  259             }
  260             break;
  261 
  262         case 219:
  263             /*
  264              * Vendor Specific: HPE ProLiant Information
  265              *
  266              * Source: hpwdt kernel driver
  267              */
  268             printf("%s ProLiant Information\n", company);
  269             if (h->length < 0x08) break;
  270             printf("\tPower Features: 0x%08x\n", DWORD(data + 0x04));
  271             if (h->length < 0x0C) break;
  272             printf("\tOmega Features: 0x%08x\n", DWORD(data + 0x08));
  273             if (h->length < 0x14) break;
  274             feat = DWORD(data + 0x10);
  275             printf("\tMisc. Features: 0x%08x\n", feat);
  276             printf("\t\tiCRU: %s\n", feat & 0x0001 ? "Yes" : "No");
  277             printf("\t\tUEFI: %s\n", feat & 0x1400 ? "Yes" : "No");
  278             break;
  279 
  280         default:
  281             return 0;
  282     }
  283     return 1;
  284 }
  285 
  286 static int dmi_decode_ibm_lenovo(const struct dmi_header *h)
  287 {
  288     u8 *data = h->data;
  289 
  290     switch (h->type)
  291     {
  292         case 131:
  293             /*
  294              * Vendor Specific: ThinkVantage Technologies feature bits
  295              *
  296              * Source: Compal hel81 Service Manual Software Specification,
  297              *         documented under "System Management BIOS(SM BIOS)
  298              *         version 2.4 or greater"
  299              *
  300              * Offset |  Name         | Width   | Description
  301              * ----------------------------------------------
  302              *  0x00  | Type          | BYTE    | 0x83
  303              *  0x01  | Length        | BYTE    | 0x16
  304              *  0x02  | Handle        | WORD    | Varies
  305              *  0x04  | Version       | BYTE    | 0x01
  306              *  0x05  | TVT Structure | BYTEx16 | Each of the 128 bits represents a TVT feature:
  307              *        |               |         |  - bit 127 means diagnostics (PC Doctor) is available
  308              *        |               |         |    (http://www.pc-doctor.com/company/pr-articles/45-lenovo-introduces-thinkvantage-toolbox)
  309              *        |               |         |  - the rest (126-0) are reserved/unknown
  310              *
  311              * It must also be followed by a string containing
  312              * "TVT-Enablement". There exist other type 131 records
  313              * with different length and a different string, for
  314              * other purposes.
  315              */
  316 
  317             if (h->length != 0x16
  318              || strcmp(dmi_string(h, 1), "TVT-Enablement") != 0)
  319                 return 0;
  320 
  321             printf("ThinkVantage Technologies\n");
  322             printf("\tVersion: %u\n", data[0x04]);
  323             printf("\tDiagnostics: %s\n",
  324                 data[0x14] & 0x80 ? "Available" : "No");
  325             break;
  326 
  327         case 135:
  328             /*
  329              * Vendor Specific: Device Presence Detection bits
  330              *
  331              * Source: Compal hel81 Service Manual Software Specification,
  332              *         documented as "SMBIOS Type 135: Bulk for Lenovo
  333              *         Mobile PC Unique OEM Data" under appendix D.
  334              *
  335              * Offset |  Name                | Width | Description
  336              * ---------------------------------------------------
  337              *  0x00  | Type                 | BYTE  | 0x87
  338              *  0x01  | Length               | BYTE  | 0x0A
  339              *  0x02  | Handle               | WORD  | Varies
  340              *  0x04  | Signature            | WORD  | 0x5054 (ASCII for "TP")
  341              *  0x06  | OEM struct offset    | BYTE  | 0x07
  342              *  0x07  | OEM struct number    | BYTE  | 0x03, for this structure
  343              *  0x08  | OEM struct revision  | BYTE  | 0x01, for this format
  344              *  0x09  | Device presence bits | BYTE  | Each of the 8 bits indicates device presence:
  345              *        |                      |       |  - bit 0 indicates the presence of a fingerprint reader
  346              *        |                      |       |  - the rest (7-1) are reserved/unknown
  347              *
  348              * Other OEM struct number+rev combinations have been
  349              * seen in the wild but we don't know how to decode
  350              * them.
  351              */
  352 
  353             if (h->length < 0x0A || data[0x04] != 'T' || data[0x05] != 'P')
  354                 return 0;
  355 
  356             /* Bail out if not the expected format */
  357             if (data[0x06] != 0x07 || data[0x07] != 0x03 || data[0x08] != 0x01)
  358                 return 0;
  359 
  360             printf("ThinkPad Device Presence Detection\n");
  361             printf("\tFingerprint Reader: %s\n",
  362                 data[0x09] & 0x01 ? "Present" : "No");
  363             break;
  364 
  365         case 140:
  366             /*
  367              * Vendor Specific: ThinkPad Embedded Controller Program
  368              *
  369              * Source: some guesswork, and publicly available information;
  370              *         Lenovo's BIOS update READMEs often contain the ECP IDs
  371              *         which match the first string in this type.
  372              *
  373              * Offset |  Name                | Width  | Description
  374              * ----------------------------------------------------
  375              *  0x00  | Type                 | BYTE   | 0x8C
  376              *  0x01  | Length               | BYTE   |
  377              *  0x02  | Handle               | WORD   | Varies
  378              *  0x04  | Signature            | BYTEx6 | ASCII for "LENOVO"
  379              *  0x0A  | OEM struct offset    | BYTE   | 0x0B
  380              *  0x0B  | OEM struct number    | BYTE   | 0x07, for this structure
  381              *  0x0C  | OEM struct revision  | BYTE   | 0x01, for this format
  382              *  0x0D  | ECP version ID       | STRING |
  383              *  0x0E  | ECP release date     | STRING |
  384              */
  385 
  386             if (h->length < 0x0F || memcmp(data + 4, "LENOVO", 6) != 0)
  387                 return 0;
  388 
  389             /* Bail out if not the expected format */
  390             if (data[0x0A] != 0x0B || data[0x0B] != 0x07 || data[0x0C] != 0x01)
  391                 return 0;
  392 
  393             printf("ThinkPad Embedded Controller Program\n");
  394             printf("\tVersion ID: %s\n", dmi_string(h, 1));
  395             printf("\tRelease Date: %s\n", dmi_string(h, 2));
  396             break;
  397 
  398         default:
  399             return 0;
  400     }
  401     return 1;
  402 }
  403 
  404 /*
  405  * Dispatch vendor-specific entries decoding
  406  * Return 1 if decoding was successful, 0 otherwise
  407  */
  408 int dmi_decode_oem(const struct dmi_header *h)
  409 {
  410     switch (dmi_vendor)
  411     {
  412         case VENDOR_HP:
  413         case VENDOR_HPE:
  414             return dmi_decode_hp(h);
  415         case VENDOR_ACER:
  416             return dmi_decode_acer(h);
  417         case VENDOR_IBM:
  418         case VENDOR_LENOVO:
  419             return dmi_decode_ibm_lenovo(h);
  420         default:
  421             return 0;
  422     }
  423 }