source: trunk/dmi.c @ 1425

Revision 1425, 6.2 KB checked in by stefanct, 5 months ago (diff)

Add a bunch of new/tested stuff and various small changes 7

  • remove unneeded nicintel_spi-related function declarations in programmer.h
  • typos and whitespace fixes
  • fix Asus P4P800-E Deluxe detection The original board enable was added before DMI matching and used the IDs of a Promise controller as secondary PCI ID set. The controller could be disabled in the BIOS which would make the board not match. This patch uses the SMBus controller instead and adds a DMI pattern. This was

Tested-by: Michael Schneider <vdrportal_midas at gmx dot de>

  • add "Sealed-case PC" to the list of chassis type (as indicating "not a laptop")

This is
Acked-by: Idwer Vollering <vidwer@…>

the fix for the typo unusued -> unused is
Signed-off-by: Sylvain "ythier" Hitier <sylvain.hitier@…>

everything else is
Signed-off-by: Stefan Tauner <stefan.tauner@…>
Acked-by: Stefan Tauner <stefan.tauner@…>

And everything was reviewed and
Acked-by: Uwe Hermann <uwe@…>

Line 
1/*
2 * This file is part of the flashrom project.
3 *
4 * Copyright (C) 2009,2010 Michael Karcher
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
19 */
20
21#include <string.h>
22#include <stdio.h>
23#include <stdlib.h>
24
25#include "flash.h"
26#include "programmer.h"
27
28int has_dmi_support = 0;
29
30#if STANDALONE
31
32/* Stub to indicate missing DMI functionality.
33 * has_dmi_support is 0 by default, so nothing to do here.
34 * Because dmidecode is not available on all systems, the goal is to implement
35 * the DMI subset we need directly in this file.
36 */
37void dmi_init(void)
38{
39}
40
41int dmi_match(const char *pattern)
42{
43        return 0;
44}
45
46#else /* STANDALONE */
47
48static const char *dmidecode_names[] = {
49        "system-manufacturer",
50        "system-product-name",
51        "system-version",
52        "baseboard-manufacturer",
53        "baseboard-product-name",
54        "baseboard-version",
55};
56
57/* This list is used to identify supposed laptops. The is_laptop field has the
58 * following meaning:
59 *      - 0: in all likelihood not a laptop
60 *      - 1: in all likelihood a laptop
61 *      - 2: chassis-type is not specific enough
62 * A full list of chassis types can be found in the System Management BIOS
63 * (SMBIOS) Reference Specification 2.7.0 section 7.4.1 "Chassis Types" at
64 * http://www.dmtf.org/sites/default/files/standards/documents/DSP0134_2.7.0.pdf
65 * The types below are the most common ones.
66 */
67static const struct {
68        unsigned char type;
69        unsigned char is_laptop;
70        const char *name;
71} dmi_chassis_types[] = {
72        {0x01, 2, "Other"},
73        {0x02, 2, "Unknown"},
74        {0x03, 0, "Desktop",},
75        {0x06, 0, "Mini Tower"},
76        {0x07, 0, "Tower"},
77        {0x08, 1, "Portable"},
78        {0x09, 1, "Laptop"},
79        {0x0a, 1, "Notebook"},
80        {0x0b, 1, "Hand Held"},
81        {0x0e, 1, "Sub Notebook"},
82        {0x11, 0, "Main Server Chassis"},
83        {0x17, 0, "Rack Mount Chassis"},
84        {0x18, 0, "Sealed-case PC"}, /* used by Supermicro (X8SIE) */
85};
86
87#define DMI_COMMAND_LEN_MAX 260
88static const char *dmidecode_command = "dmidecode";
89
90static char *dmistrings[ARRAY_SIZE(dmidecode_names)];
91
92/* Strings longer than 4096 in DMI are just insane. */
93#define DMI_MAX_ANSWER_LEN 4096
94
95static char *get_dmi_string(const char *string_name)
96{
97        FILE *dmidecode_pipe;
98        char *result;
99        char answerbuf[DMI_MAX_ANSWER_LEN];
100        char commandline[DMI_COMMAND_LEN_MAX + 40];
101
102        snprintf(commandline, sizeof(commandline),
103                 "%s -s %s", dmidecode_command, string_name);
104        dmidecode_pipe = popen(commandline, "r");
105        if (!dmidecode_pipe) {
106                msg_perr("DMI pipe open error\n");
107                return NULL;
108        }
109
110        /* Kill lines starting with '#', as recent dmidecode versions
111         * have the quirk to emit a "# SMBIOS implementations newer..."
112         * message even on "-s" if the SMBIOS declares a
113         * newer-than-supported version number, while it *should* only print
114         * the requested string.
115         */
116        do {
117                if (!fgets(answerbuf, DMI_MAX_ANSWER_LEN, dmidecode_pipe)) {
118                        if (ferror(dmidecode_pipe)) {
119                                msg_perr("DMI pipe read error\n");
120                                pclose(dmidecode_pipe);
121                                return NULL;
122                        } else {
123                                answerbuf[0] = 0;       /* Hit EOF */
124                        }
125                }
126        } while (answerbuf[0] == '#');
127
128        /* Toss all output above DMI_MAX_ANSWER_LEN away to prevent
129           deadlock on pclose. */
130        while (!feof(dmidecode_pipe))
131                getc(dmidecode_pipe);
132        if (pclose(dmidecode_pipe) != 0) {
133                msg_pinfo("dmidecode execution unsuccessful - continuing "
134                          "without DMI info\n");
135                return NULL;
136        }
137
138        /* Chomp trailing newline. */
139        if (answerbuf[0] != 0 && answerbuf[strlen(answerbuf) - 1] == '\n')
140                answerbuf[strlen(answerbuf) - 1] = 0;
141        msg_pdbg("DMI string %s: \"%s\"\n", string_name, answerbuf);
142
143        result = strdup(answerbuf);
144        if (!result)
145                puts("WARNING: Out of memory - DMI support fails");
146
147        return result;
148}
149
150void dmi_init(void)
151{
152        int i;
153        char *chassis_type;
154
155        has_dmi_support = 1;
156        for (i = 0; i < ARRAY_SIZE(dmidecode_names); i++) {
157                dmistrings[i] = get_dmi_string(dmidecode_names[i]);
158                if (!dmistrings[i]) {
159                        has_dmi_support = 0;
160                        return;
161                }
162        }
163
164        chassis_type = get_dmi_string("chassis-type");
165        if (chassis_type == NULL)
166                return;
167
168        is_laptop = 2;
169        for (i = 0; i < ARRAY_SIZE(dmi_chassis_types); i++) {
170                if (strcasecmp(chassis_type, dmi_chassis_types[i].name) == 0) {
171                        is_laptop = dmi_chassis_types[i].is_laptop;
172                        break;
173                }
174        }
175
176        switch (is_laptop) {
177        case 1:
178                msg_pdbg("Laptop detected via DMI.\n");
179                break;
180        case 2:
181                msg_pdbg("DMI chassis-type is not specific enough.\n");
182                break;
183        }
184        free(chassis_type);
185}
186
187/**
188 * Does an substring/prefix/postfix/whole-string match.
189 *
190 * The pattern is matched as-is. The only metacharacters supported are '^'
191 * at the beginning and '$' at the end. So you can look for "^prefix",
192 * "suffix$", "substring" or "^complete string$".
193 *
194 * @param value The string to check.
195 * @param pattern The pattern.
196 * @return Nonzero if pattern matches.
197 */
198static int dmi_compare(const char *value, const char *pattern)
199{
200        int anchored = 0;
201        int patternlen;
202
203        msg_pspew("matching %s against %s\n", value, pattern);
204        /* The empty string is part of all strings! */
205        if (pattern[0] == 0)
206                return 1;
207
208        if (pattern[0] == '^') {
209                anchored = 1;
210                pattern++;
211        }
212
213        patternlen = strlen(pattern);
214        if (pattern[patternlen - 1] == '$') {
215                int valuelen = strlen(value);
216                patternlen--;
217                if (patternlen > valuelen)
218                        return 0;
219
220                /* full string match: require same length */
221                if (anchored && (valuelen != patternlen))
222                        return 0;
223
224                /* start character to make ends match */
225                value += valuelen - patternlen;
226                anchored = 1;
227        }
228
229        if (anchored)
230                return strncmp(value, pattern, patternlen) == 0;
231        else
232                return strstr(value, pattern) != NULL;
233}
234
235int dmi_match(const char *pattern)
236{
237        int i;
238
239        if (!has_dmi_support)
240                return 0;
241
242        for (i = 0; i < ARRAY_SIZE(dmidecode_names); i++)
243                if (dmi_compare(dmistrings[i], pattern))
244                        return 1;
245
246        return 0;
247}
248
249#endif /* STANDALONE */
Note: See TracBrowser for help on using the repository browser.