Blame view

drivers/firmware/dmi_scan.c 17.5 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
  #include <linux/types.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2
3
4
  #include <linux/string.h>
  #include <linux/init.h>
  #include <linux/module.h>
8881cdceb   Bjorn Helgaas   dmi: log board, s...
5
  #include <linux/ctype.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6
  #include <linux/dmi.h>
3ed3bce84   Matt Domsch   [PATCH] ia64: use...
7
  #include <linux/efi.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
8
  #include <linux/bootmem.h>
f2d3efedb   Andi Kleen   [PATCH] x86_64: I...
9
  #include <asm/dmi.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
10

cb5dd7c10   Paul Jackson   x86 boot: add hea...
11
12
13
14
15
  /*
   * DMI stands for "Desktop Management Interface".  It is part
   * of and an antecedent to, SMBIOS, which stands for System
   * Management BIOS.  See further: http://www.dmtf.org/standards
   */
79da47211   Parag Warudkar   x86: fix DMI out ...
16
  static char dmi_empty_string[] = "        ";
9a22b6e76   Ingo Molnar   dmi scan: warn ab...
17
18
19
20
  /*
   * Catch too early calls to dmi_check_system():
   */
  static int dmi_initialized;
f3069ae9d   Jean Delvare   dmi: don't save t...
21
  static const char * __init dmi_string_nosave(const struct dmi_header *dm, u8 s)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
22
  {
1855256c4   Jeff Garzik   drivers/firmware:...
23
  	const u8 *bp = ((u8 *) dm) + dm->length;
1249c5138   Andrey Panin   [PATCH] dmi: spri...
24

c3c7120d5   Andrey Panin   [PATCH] dmi: make...
25
  	if (s) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
26
  		s--;
c3c7120d5   Andrey Panin   [PATCH] dmi: make...
27
28
29
30
31
32
  		while (s > 0 && *bp) {
  			bp += strlen(bp) + 1;
  			s--;
  		}
  
  		if (*bp != 0) {
79da47211   Parag Warudkar   x86: fix DMI out ...
33
34
35
36
37
  			size_t len = strlen(bp)+1;
  			size_t cmp_len = len > 8 ? 8 : len;
  
  			if (!memcmp(bp, dmi_empty_string, cmp_len))
  				return dmi_empty_string;
f3069ae9d   Jean Delvare   dmi: don't save t...
38
  			return bp;
c3c7120d5   Andrey Panin   [PATCH] dmi: make...
39
  		}
4f705ae3e   Bjorn Helgaas   [PATCH] DMI: move...
40
  	}
c3c7120d5   Andrey Panin   [PATCH] dmi: make...
41

f3069ae9d   Jean Delvare   dmi: don't save t...
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
  	return "";
  }
  
  static char * __init dmi_string(const struct dmi_header *dm, u8 s)
  {
  	const char *bp = dmi_string_nosave(dm, s);
  	char *str;
  	size_t len;
  
  	if (bp == dmi_empty_string)
  		return dmi_empty_string;
  
  	len = strlen(bp) + 1;
  	str = dmi_alloc(len);
  	if (str != NULL)
  		strcpy(str, bp);
  	else
  		printk(KERN_ERR "dmi_string: cannot allocate %Zu bytes.
  ", len);
c3c7120d5   Andrey Panin   [PATCH] dmi: make...
61
  	return str;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
62
63
64
65
66
67
  }
  
  /*
   *	We have to be cautious here. We have seen BIOSes with DMI pointers
   *	pointing to completely the wrong place for example
   */
7fce084a0   Jean Delvare   dmi: Let drivers ...
68
  static void dmi_table(u8 *buf, int len, int num,
e7a19c562   Jean Delvare   dmi: Let dmi_walk...
69
70
  		      void (*decode)(const struct dmi_header *, void *),
  		      void *private_data)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
71
  {
7fce084a0   Jean Delvare   dmi: Let drivers ...
72
  	u8 *data = buf;
1249c5138   Andrey Panin   [PATCH] dmi: spri...
73
  	int i = 0;
4f705ae3e   Bjorn Helgaas   [PATCH] DMI: move...
74

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
75
  	/*
4f705ae3e   Bjorn Helgaas   [PATCH] DMI: move...
76
77
78
  	 *	Stop when we see all the items the table claimed to have
  	 *	OR we run off the end of the table (also happens)
  	 */
1249c5138   Andrey Panin   [PATCH] dmi: spri...
79
  	while ((i < num) && (data - buf + sizeof(struct dmi_header)) <= len) {
1855256c4   Jeff Garzik   drivers/firmware:...
80
  		const struct dmi_header *dm = (const struct dmi_header *)data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
81
  		/*
8638545c3   Alan Cox   trivial: dmi_scan...
82
83
84
  		 *  We want to know the total length (formatted area and
  		 *  strings) before decoding to make sure we won't run off the
  		 *  table in dmi_decode or dmi_string
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
85
  		 */
1249c5138   Andrey Panin   [PATCH] dmi: spri...
86
87
  		data += dm->length;
  		while ((data - buf < len - 1) && (data[0] || data[1]))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
88
  			data++;
1249c5138   Andrey Panin   [PATCH] dmi: spri...
89
  		if (data - buf < len - 1)
e7a19c562   Jean Delvare   dmi: Let dmi_walk...
90
  			decode(dm, private_data);
1249c5138   Andrey Panin   [PATCH] dmi: spri...
91
  		data += 2;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
92
93
  		i++;
  	}
7fce084a0   Jean Delvare   dmi: Let drivers ...
94
95
96
97
98
  }
  
  static u32 dmi_base;
  static u16 dmi_len;
  static u16 dmi_num;
e7a19c562   Jean Delvare   dmi: Let dmi_walk...
99
100
  static int __init dmi_walk_early(void (*decode)(const struct dmi_header *,
  		void *))
7fce084a0   Jean Delvare   dmi: Let drivers ...
101
102
103
104
105
106
  {
  	u8 *buf;
  
  	buf = dmi_ioremap(dmi_base, dmi_len);
  	if (buf == NULL)
  		return -1;
e7a19c562   Jean Delvare   dmi: Let dmi_walk...
107
  	dmi_table(buf, dmi_len, dmi_num, decode, NULL);
7fce084a0   Jean Delvare   dmi: Let drivers ...
108
109
  
  	dmi_iounmap(buf, dmi_len);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
110
111
  	return 0;
  }
1855256c4   Jeff Garzik   drivers/firmware:...
112
  static int __init dmi_checksum(const u8 *buf)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
113
  {
1249c5138   Andrey Panin   [PATCH] dmi: spri...
114
  	u8 sum = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
115
  	int a;
4f705ae3e   Bjorn Helgaas   [PATCH] DMI: move...
116

1249c5138   Andrey Panin   [PATCH] dmi: spri...
117
118
119
120
  	for (a = 0; a < 15; a++)
  		sum += buf[a];
  
  	return sum == 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
121
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
122
  static char *dmi_ident[DMI_STRING_MAX];
ebad6a423   Andrey Panin   [PATCH] dmi: add ...
123
  static LIST_HEAD(dmi_devices);
4f5c791a8   Lennart Poettering   DMI-based module ...
124
  int dmi_available;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
125
126
127
128
  
  /*
   *	Save a DMI string
   */
1855256c4   Jeff Garzik   drivers/firmware:...
129
  static void __init dmi_save_ident(const struct dmi_header *dm, int slot, int string)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
130
  {
1855256c4   Jeff Garzik   drivers/firmware:...
131
132
  	const char *d = (const char*) dm;
  	char *p;
1249c5138   Andrey Panin   [PATCH] dmi: spri...
133

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
134
135
  	if (dmi_ident[slot])
  		return;
1249c5138   Andrey Panin   [PATCH] dmi: spri...
136

c3c7120d5   Andrey Panin   [PATCH] dmi: make...
137
138
139
140
141
  	p = dmi_string(dm, d[string]);
  	if (p == NULL)
  		return;
  
  	dmi_ident[slot] = p;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
142
  }
1855256c4   Jeff Garzik   drivers/firmware:...
143
  static void __init dmi_save_uuid(const struct dmi_header *dm, int slot, int index)
4f5c791a8   Lennart Poettering   DMI-based module ...
144
  {
1855256c4   Jeff Garzik   drivers/firmware:...
145
  	const u8 *d = (u8*) dm + index;
4f5c791a8   Lennart Poettering   DMI-based module ...
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
  	char *s;
  	int is_ff = 1, is_00 = 1, i;
  
  	if (dmi_ident[slot])
  		return;
  
  	for (i = 0; i < 16 && (is_ff || is_00); i++) {
  		if(d[i] != 0x00) is_ff = 0;
  		if(d[i] != 0xFF) is_00 = 0;
  	}
  
  	if (is_ff || is_00)
  		return;
  
  	s = dmi_alloc(16*2+4+1);
  	if (!s)
  		return;
bc058f65e   Joe Perches   drivers/firmware/...
163
  	sprintf(s, "%pUB", d);
4f5c791a8   Lennart Poettering   DMI-based module ...
164
165
166
  
          dmi_ident[slot] = s;
  }
1855256c4   Jeff Garzik   drivers/firmware:...
167
  static void __init dmi_save_type(const struct dmi_header *dm, int slot, int index)
4f5c791a8   Lennart Poettering   DMI-based module ...
168
  {
1855256c4   Jeff Garzik   drivers/firmware:...
169
  	const u8 *d = (u8*) dm + index;
4f5c791a8   Lennart Poettering   DMI-based module ...
170
171
172
173
174
175
176
177
178
179
180
181
  	char *s;
  
  	if (dmi_ident[slot])
  		return;
  
  	s = dmi_alloc(4);
  	if (!s)
  		return;
  
  	sprintf(s, "%u", *d & 0x7F);
  	dmi_ident[slot] = s;
  }
f3069ae9d   Jean Delvare   dmi: don't save t...
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
  static void __init dmi_save_one_device(int type, const char *name)
  {
  	struct dmi_device *dev;
  
  	/* No duplicate device */
  	if (dmi_find_device(type, name, NULL))
  		return;
  
  	dev = dmi_alloc(sizeof(*dev) + strlen(name) + 1);
  	if (!dev) {
  		printk(KERN_ERR "dmi_save_one_device: out of memory.
  ");
  		return;
  	}
  
  	dev->type = type;
  	strcpy((char *)(dev + 1), name);
  	dev->name = (char *)(dev + 1);
  	dev->device_data = NULL;
  	list_add(&dev->list, &dmi_devices);
  }
1855256c4   Jeff Garzik   drivers/firmware:...
203
  static void __init dmi_save_devices(const struct dmi_header *dm)
ebad6a423   Andrey Panin   [PATCH] dmi: add ...
204
205
  {
  	int i, count = (dm->length - sizeof(struct dmi_header)) / 2;
ebad6a423   Andrey Panin   [PATCH] dmi: add ...
206
207
  
  	for (i = 0; i < count; i++) {
1855256c4   Jeff Garzik   drivers/firmware:...
208
  		const char *d = (char *)(dm + 1) + (i * 2);
ebad6a423   Andrey Panin   [PATCH] dmi: add ...
209
210
211
212
  
  		/* Skip disabled device */
  		if ((*d & 0x80) == 0)
  			continue;
f3069ae9d   Jean Delvare   dmi: don't save t...
213
  		dmi_save_one_device(*d & 0x7f, dmi_string_nosave(dm, *(d + 1)));
2e0c1f6ce   Shem Multinymous   [PATCH] DMI: Deco...
214
215
  	}
  }
1855256c4   Jeff Garzik   drivers/firmware:...
216
  static void __init dmi_save_oem_strings_devices(const struct dmi_header *dm)
2e0c1f6ce   Shem Multinymous   [PATCH] DMI: Deco...
217
218
219
220
221
  {
  	int i, count = *(u8 *)(dm + 1);
  	struct dmi_device *dev;
  
  	for (i = 1; i <= count; i++) {
79da47211   Parag Warudkar   x86: fix DMI out ...
222
  		char *devname = dmi_string(dm, i);
43fe105a5   Jean Delvare   dmi: prevent link...
223
  		if (devname == dmi_empty_string)
79da47211   Parag Warudkar   x86: fix DMI out ...
224
  			continue;
79da47211   Parag Warudkar   x86: fix DMI out ...
225

2e0c1f6ce   Shem Multinymous   [PATCH] DMI: Deco...
226
227
228
229
230
231
232
233
234
  		dev = dmi_alloc(sizeof(*dev));
  		if (!dev) {
  			printk(KERN_ERR
  			   "dmi_save_oem_strings_devices: out of memory.
  ");
  			break;
  		}
  
  		dev->type = DMI_DEV_TYPE_OEM_STRING;
79da47211   Parag Warudkar   x86: fix DMI out ...
235
  		dev->name = devname;
2e0c1f6ce   Shem Multinymous   [PATCH] DMI: Deco...
236
  		dev->device_data = NULL;
ebad6a423   Andrey Panin   [PATCH] dmi: add ...
237
238
239
240
  
  		list_add(&dev->list, &dmi_devices);
  	}
  }
1855256c4   Jeff Garzik   drivers/firmware:...
241
  static void __init dmi_save_ipmi_device(const struct dmi_header *dm)
ebad6a423   Andrey Panin   [PATCH] dmi: add ...
242
243
244
  {
  	struct dmi_device *dev;
  	void * data;
e99286744   Andi Kleen   [PATCH] x86_64: G...
245
  	data = dmi_alloc(dm->length);
ebad6a423   Andrey Panin   [PATCH] dmi: add ...
246
247
248
249
250
251
252
  	if (data == NULL) {
  		printk(KERN_ERR "dmi_save_ipmi_device: out of memory.
  ");
  		return;
  	}
  
  	memcpy(data, dm, dm->length);
e99286744   Andi Kleen   [PATCH] x86_64: G...
253
  	dev = dmi_alloc(sizeof(*dev));
ebad6a423   Andrey Panin   [PATCH] dmi: add ...
254
255
256
257
258
259
260
261
262
  	if (!dev) {
  		printk(KERN_ERR "dmi_save_ipmi_device: out of memory.
  ");
  		return;
  	}
  
  	dev->type = DMI_DEV_TYPE_IPMI;
  	dev->name = "IPMI controller";
  	dev->device_data = data;
abd24df82   Carol Hebert   ipmi: change devi...
263
  	list_add_tail(&dev->list, &dmi_devices);
ebad6a423   Andrey Panin   [PATCH] dmi: add ...
264
  }
911e1c9b0   Narendra K   PCI: export SMBIO...
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
  static void __init dmi_save_dev_onboard(int instance, int segment, int bus,
  					int devfn, const char *name)
  {
  	struct dmi_dev_onboard *onboard_dev;
  
  	onboard_dev = dmi_alloc(sizeof(*onboard_dev) + strlen(name) + 1);
  	if (!onboard_dev) {
  		printk(KERN_ERR "dmi_save_dev_onboard: out of memory.
  ");
  		return;
  	}
  	onboard_dev->instance = instance;
  	onboard_dev->segment = segment;
  	onboard_dev->bus = bus;
  	onboard_dev->devfn = devfn;
  
  	strcpy((char *)&onboard_dev[1], name);
  	onboard_dev->dev.type = DMI_DEV_TYPE_DEV_ONBOARD;
  	onboard_dev->dev.name = (char *)&onboard_dev[1];
  	onboard_dev->dev.device_data = onboard_dev;
  
  	list_add(&onboard_dev->dev.list, &dmi_devices);
  }
b4bd7d594   Wim Van Sebroeck   SMBIOS/DMI: add t...
288
289
290
  static void __init dmi_save_extended_devices(const struct dmi_header *dm)
  {
  	const u8 *d = (u8*) dm + 5;
b4bd7d594   Wim Van Sebroeck   SMBIOS/DMI: add t...
291
292
293
294
  
  	/* Skip disabled device */
  	if ((*d & 0x80) == 0)
  		return;
911e1c9b0   Narendra K   PCI: export SMBIO...
295
296
  	dmi_save_dev_onboard(*(d+1), *(u16 *)(d+2), *(d+4), *(d+5),
  			     dmi_string_nosave(dm, *(d-1)));
f3069ae9d   Jean Delvare   dmi: don't save t...
297
  	dmi_save_one_device(*d & 0x7f, dmi_string_nosave(dm, *(d - 1)));
b4bd7d594   Wim Van Sebroeck   SMBIOS/DMI: add t...
298
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
299
  /*
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
300
301
302
303
   *	Process a DMI table entry. Right now all we care about are the BIOS
   *	and machine entries. For 2.5 we should pull the smbus controller info
   *	out of here.
   */
e7a19c562   Jean Delvare   dmi: Let dmi_walk...
304
  static void __init dmi_decode(const struct dmi_header *dm, void *dummy)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
305
  {
1249c5138   Andrey Panin   [PATCH] dmi: spri...
306
  	switch(dm->type) {
ebad6a423   Andrey Panin   [PATCH] dmi: add ...
307
  	case 0:		/* BIOS Information */
1249c5138   Andrey Panin   [PATCH] dmi: spri...
308
  		dmi_save_ident(dm, DMI_BIOS_VENDOR, 4);
1249c5138   Andrey Panin   [PATCH] dmi: spri...
309
  		dmi_save_ident(dm, DMI_BIOS_VERSION, 5);
1249c5138   Andrey Panin   [PATCH] dmi: spri...
310
311
  		dmi_save_ident(dm, DMI_BIOS_DATE, 8);
  		break;
ebad6a423   Andrey Panin   [PATCH] dmi: add ...
312
  	case 1:		/* System Information */
1249c5138   Andrey Panin   [PATCH] dmi: spri...
313
  		dmi_save_ident(dm, DMI_SYS_VENDOR, 4);
1249c5138   Andrey Panin   [PATCH] dmi: spri...
314
  		dmi_save_ident(dm, DMI_PRODUCT_NAME, 5);
1249c5138   Andrey Panin   [PATCH] dmi: spri...
315
  		dmi_save_ident(dm, DMI_PRODUCT_VERSION, 6);
1249c5138   Andrey Panin   [PATCH] dmi: spri...
316
  		dmi_save_ident(dm, DMI_PRODUCT_SERIAL, 7);
4f5c791a8   Lennart Poettering   DMI-based module ...
317
  		dmi_save_uuid(dm, DMI_PRODUCT_UUID, 8);
1249c5138   Andrey Panin   [PATCH] dmi: spri...
318
  		break;
ebad6a423   Andrey Panin   [PATCH] dmi: add ...
319
  	case 2:		/* Base Board Information */
1249c5138   Andrey Panin   [PATCH] dmi: spri...
320
  		dmi_save_ident(dm, DMI_BOARD_VENDOR, 4);
1249c5138   Andrey Panin   [PATCH] dmi: spri...
321
  		dmi_save_ident(dm, DMI_BOARD_NAME, 5);
1249c5138   Andrey Panin   [PATCH] dmi: spri...
322
  		dmi_save_ident(dm, DMI_BOARD_VERSION, 6);
4f5c791a8   Lennart Poettering   DMI-based module ...
323
324
325
326
327
328
329
330
331
  		dmi_save_ident(dm, DMI_BOARD_SERIAL, 7);
  		dmi_save_ident(dm, DMI_BOARD_ASSET_TAG, 8);
  		break;
  	case 3:		/* Chassis Information */
  		dmi_save_ident(dm, DMI_CHASSIS_VENDOR, 4);
  		dmi_save_type(dm, DMI_CHASSIS_TYPE, 5);
  		dmi_save_ident(dm, DMI_CHASSIS_VERSION, 6);
  		dmi_save_ident(dm, DMI_CHASSIS_SERIAL, 7);
  		dmi_save_ident(dm, DMI_CHASSIS_ASSET_TAG, 8);
1249c5138   Andrey Panin   [PATCH] dmi: spri...
332
  		break;
ebad6a423   Andrey Panin   [PATCH] dmi: add ...
333
334
335
  	case 10:	/* Onboard Devices Information */
  		dmi_save_devices(dm);
  		break;
2e0c1f6ce   Shem Multinymous   [PATCH] DMI: Deco...
336
337
338
  	case 11:	/* OEM Strings */
  		dmi_save_oem_strings_devices(dm);
  		break;
ebad6a423   Andrey Panin   [PATCH] dmi: add ...
339
340
  	case 38:	/* IPMI Device Information */
  		dmi_save_ipmi_device(dm);
b4bd7d594   Wim Van Sebroeck   SMBIOS/DMI: add t...
341
342
343
  		break;
  	case 41:	/* Onboard Devices Extended Information */
  		dmi_save_extended_devices(dm);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
344
345
  	}
  }
8881cdceb   Bjorn Helgaas   dmi: log board, s...
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
  static void __init print_filtered(const char *info)
  {
  	const char *p;
  
  	if (!info)
  		return;
  
  	for (p = info; *p; p++)
  		if (isprint(*p))
  			printk(KERN_CONT "%c", *p);
  		else
  			printk(KERN_CONT "\\x%02x", *p & 0xff);
  }
  
  static void __init dmi_dump_ids(void)
  {
84e383b32   Naga Chumbalkar   x86, dmi, debug: ...
362
  	const char *board;	/* Board Name is optional */
8881cdceb   Bjorn Helgaas   dmi: log board, s...
363
  	printk(KERN_DEBUG "DMI: ");
84e383b32   Naga Chumbalkar   x86, dmi, debug: ...
364
365
  	print_filtered(dmi_get_system_info(DMI_SYS_VENDOR));
  	printk(KERN_CONT " ");
8881cdceb   Bjorn Helgaas   dmi: log board, s...
366
  	print_filtered(dmi_get_system_info(DMI_PRODUCT_NAME));
84e383b32   Naga Chumbalkar   x86, dmi, debug: ...
367
368
369
370
371
  	board = dmi_get_system_info(DMI_BOARD_NAME);
  	if (board) {
  		printk(KERN_CONT "/");
  		print_filtered(board);
  	}
8881cdceb   Bjorn Helgaas   dmi: log board, s...
372
373
374
375
376
377
378
  	printk(KERN_CONT ", BIOS ");
  	print_filtered(dmi_get_system_info(DMI_BIOS_VERSION));
  	printk(KERN_CONT " ");
  	print_filtered(dmi_get_system_info(DMI_BIOS_DATE));
  	printk(KERN_CONT "
  ");
  }
1855256c4   Jeff Garzik   drivers/firmware:...
379
  static int __init dmi_present(const char __iomem *p)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
380
  {
61e032fa2   Andrey Panin   [PATCH] dmi: remo...
381
  	u8 buf[15];
1855256c4   Jeff Garzik   drivers/firmware:...
382

3ed3bce84   Matt Domsch   [PATCH] ia64: use...
383
384
  	memcpy_fromio(buf, p, 15);
  	if ((memcmp(buf, "_DMI_", 5) == 0) && dmi_checksum(buf)) {
7fce084a0   Jean Delvare   dmi: Let drivers ...
385
386
387
  		dmi_num = (buf[13] << 8) | buf[12];
  		dmi_len = (buf[7] << 8) | buf[6];
  		dmi_base = (buf[11] << 24) | (buf[10] << 16) |
3ed3bce84   Matt Domsch   [PATCH] ia64: use...
388
  			(buf[9] << 8) | buf[8];
61e032fa2   Andrey Panin   [PATCH] dmi: remo...
389

3ed3bce84   Matt Domsch   [PATCH] ia64: use...
390
391
392
393
394
395
396
397
398
399
400
  		/*
  		 * DMI version 0.0 means that the real version is taken from
  		 * the SMBIOS version, which we don't know at this point.
  		 */
  		if (buf[14] != 0)
  			printk(KERN_INFO "DMI %d.%d present.
  ",
  			       buf[14] >> 4, buf[14] & 0xF);
  		else
  			printk(KERN_INFO "DMI present.
  ");
8881cdceb   Bjorn Helgaas   dmi: log board, s...
401
402
  		if (dmi_walk_early(dmi_decode) == 0) {
  			dmi_dump_ids();
3ed3bce84   Matt Domsch   [PATCH] ia64: use...
403
  			return 0;
8881cdceb   Bjorn Helgaas   dmi: log board, s...
404
  		}
3ed3bce84   Matt Domsch   [PATCH] ia64: use...
405
406
407
  	}
  	return 1;
  }
61e032fa2   Andrey Panin   [PATCH] dmi: remo...
408

3ed3bce84   Matt Domsch   [PATCH] ia64: use...
409
410
411
412
413
414
  void __init dmi_scan_machine(void)
  {
  	char __iomem *p, *q;
  	int rc;
  
  	if (efi_enabled) {
b2c99e3c7   Bjorn Helgaas   [PATCH] EFI: keep...
415
  		if (efi.smbios == EFI_INVALID_TABLE_ADDR)
9a22b6e76   Ingo Molnar   dmi scan: warn ab...
416
  			goto error;
3ed3bce84   Matt Domsch   [PATCH] ia64: use...
417

4f5c791a8   Lennart Poettering   DMI-based module ...
418
419
420
421
  		/* This is called as a core_initcall() because it isn't
  		 * needed during early boot.  This also means we can
  		 * iounmap the space when we're done with it.
  		 */
b2c99e3c7   Bjorn Helgaas   [PATCH] EFI: keep...
422
  		p = dmi_ioremap(efi.smbios, 32);
3ed3bce84   Matt Domsch   [PATCH] ia64: use...
423
  		if (p == NULL)
9a22b6e76   Ingo Molnar   dmi scan: warn ab...
424
  			goto error;
3ed3bce84   Matt Domsch   [PATCH] ia64: use...
425
426
  
  		rc = dmi_present(p + 0x10); /* offset of _DMI_ string */
23dd842c0   Tolentino, Matthew E   [PATCH] EFI fixes
427
  		dmi_iounmap(p, 32);
4f5c791a8   Lennart Poettering   DMI-based module ...
428
429
  		if (!rc) {
  			dmi_available = 1;
9a22b6e76   Ingo Molnar   dmi scan: warn ab...
430
  			goto out;
4f5c791a8   Lennart Poettering   DMI-based module ...
431
  		}
3ed3bce84   Matt Domsch   [PATCH] ia64: use...
432
433
434
435
436
437
438
439
440
  	}
  	else {
  		/*
  		 * no iounmap() for that ioremap(); it would be a no-op, but
  		 * it's so early in setup that sucker gets confused into doing
  		 * what it shouldn't if we actually call it.
  		 */
  		p = dmi_ioremap(0xF0000, 0x10000);
  		if (p == NULL)
9a22b6e76   Ingo Molnar   dmi scan: warn ab...
441
  			goto error;
3ed3bce84   Matt Domsch   [PATCH] ia64: use...
442
443
444
  
  		for (q = p; q < p + 0x10000; q += 16) {
  			rc = dmi_present(q);
4f5c791a8   Lennart Poettering   DMI-based module ...
445
446
  			if (!rc) {
  				dmi_available = 1;
0d64484f7   Ingo Molnar   x86: fix DMI iore...
447
  				dmi_iounmap(p, 0x10000);
9a22b6e76   Ingo Molnar   dmi scan: warn ab...
448
  				goto out;
4f5c791a8   Lennart Poettering   DMI-based module ...
449
  			}
61e032fa2   Andrey Panin   [PATCH] dmi: remo...
450
  		}
3212bff37   Yinghai Lu   x86: left over fi...
451
  		dmi_iounmap(p, 0x10000);
61e032fa2   Andrey Panin   [PATCH] dmi: remo...
452
  	}
9a22b6e76   Ingo Molnar   dmi scan: warn ab...
453
454
455
456
457
   error:
  	printk(KERN_INFO "DMI not present or invalid.
  ");
   out:
  	dmi_initialized = 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
458
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
459
  /**
d7b1956fe   Rafael J. Wysocki   DMI: Introduce dm...
460
461
462
463
464
465
466
467
468
469
470
471
472
   *	dmi_matches - check if dmi_system_id structure matches system DMI data
   *	@dmi: pointer to the dmi_system_id structure to check
   */
  static bool dmi_matches(const struct dmi_system_id *dmi)
  {
  	int i;
  
  	WARN(!dmi_initialized, KERN_ERR "dmi check: not initialized yet.
  ");
  
  	for (i = 0; i < ARRAY_SIZE(dmi->matches); i++) {
  		int s = dmi->matches[i].slot;
  		if (s == DMI_NONE)
75757507e   Dmitry Torokhov   DMI: allow omitti...
473
  			break;
d7b1956fe   Rafael J. Wysocki   DMI: Introduce dm...
474
475
476
477
478
479
480
481
482
483
  		if (dmi_ident[s]
  		    && strstr(dmi_ident[s], dmi->matches[i].substr))
  			continue;
  		/* No match */
  		return false;
  	}
  	return true;
  }
  
  /**
75757507e   Dmitry Torokhov   DMI: allow omitti...
484
485
486
487
488
489
490
491
492
   *	dmi_is_end_of_table - check for end-of-table marker
   *	@dmi: pointer to the dmi_system_id structure to check
   */
  static bool dmi_is_end_of_table(const struct dmi_system_id *dmi)
  {
  	return dmi->matches[0].slot == DMI_NONE;
  }
  
  /**
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
493
494
   *	dmi_check_system - check system DMI data
   *	@list: array of dmi_system_id structures to match against
b0ef371e3   Randy Dunlap   [PATCH] DMI: clea...
495
496
497
498
499
   *		All non-null elements of the list must match
   *		their slot's (field index's) data (i.e., each
   *		list string must be a substring of the specified
   *		DMI slot's string data) to be considered a
   *		successful match.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
500
501
502
   *
   *	Walk the blacklist table running matching functions until someone
   *	returns non zero or we hit the end. Callback function is called for
b0ef371e3   Randy Dunlap   [PATCH] DMI: clea...
503
   *	each successful match. Returns the number of matches.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
504
   */
1855256c4   Jeff Garzik   drivers/firmware:...
505
  int dmi_check_system(const struct dmi_system_id *list)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
506
  {
d7b1956fe   Rafael J. Wysocki   DMI: Introduce dm...
507
508
  	int count = 0;
  	const struct dmi_system_id *d;
75757507e   Dmitry Torokhov   DMI: allow omitti...
509
  	for (d = list; !dmi_is_end_of_table(d); d++)
d7b1956fe   Rafael J. Wysocki   DMI: Introduce dm...
510
511
512
513
  		if (dmi_matches(d)) {
  			count++;
  			if (d->callback && d->callback(d))
  				break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
514
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
515
516
517
  
  	return count;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
518
519
520
  EXPORT_SYMBOL(dmi_check_system);
  
  /**
d7b1956fe   Rafael J. Wysocki   DMI: Introduce dm...
521
522
523
524
525
526
527
528
529
530
531
532
533
534
   *	dmi_first_match - find dmi_system_id structure matching system DMI data
   *	@list: array of dmi_system_id structures to match against
   *		All non-null elements of the list must match
   *		their slot's (field index's) data (i.e., each
   *		list string must be a substring of the specified
   *		DMI slot's string data) to be considered a
   *		successful match.
   *
   *	Walk the blacklist table until the first match is found.  Return the
   *	pointer to the matching entry or NULL if there's no match.
   */
  const struct dmi_system_id *dmi_first_match(const struct dmi_system_id *list)
  {
  	const struct dmi_system_id *d;
75757507e   Dmitry Torokhov   DMI: allow omitti...
535
  	for (d = list; !dmi_is_end_of_table(d); d++)
d7b1956fe   Rafael J. Wysocki   DMI: Introduce dm...
536
537
538
539
540
541
542
543
  		if (dmi_matches(d))
  			return d;
  
  	return NULL;
  }
  EXPORT_SYMBOL(dmi_first_match);
  
  /**
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
544
   *	dmi_get_system_info - return DMI data value
b0ef371e3   Randy Dunlap   [PATCH] DMI: clea...
545
   *	@field: data index (see enum dmi_field)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
546
547
548
549
   *
   *	Returns one DMI data value, can be used to perform
   *	complex DMI data checks.
   */
1855256c4   Jeff Garzik   drivers/firmware:...
550
  const char *dmi_get_system_info(int field)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
551
552
553
  {
  	return dmi_ident[field];
  }
e70c9d5e6   Dmitry Torokhov   [PATCH] I8K: use ...
554
  EXPORT_SYMBOL(dmi_get_system_info);
ebad6a423   Andrey Panin   [PATCH] dmi: add ...
555

fd8cd7e19   Alok Kataria   x86: vmware: look...
556
  /**
c2bacfc44   Randy Dunlap   dmi: fix kernel-d...
557
558
   * dmi_name_in_serial - Check if string is in the DMI product serial information
   * @str: string to check for
fd8cd7e19   Alok Kataria   x86: vmware: look...
559
560
561
562
563
564
565
566
   */
  int dmi_name_in_serial(const char *str)
  {
  	int f = DMI_PRODUCT_SERIAL;
  	if (dmi_ident[f] && strstr(dmi_ident[f], str))
  		return 1;
  	return 0;
  }
a1bae6724   Andi Kleen   [PATCH] i386: Dis...
567
568
  
  /**
66e13e66b   Jean Delvare   drivers/firmware/...
569
   *	dmi_name_in_vendors - Check if string is in the DMI system or board vendor name
a1bae6724   Andi Kleen   [PATCH] i386: Dis...
570
571
   *	@str: 	Case sensitive Name
   */
1855256c4   Jeff Garzik   drivers/firmware:...
572
  int dmi_name_in_vendors(const char *str)
a1bae6724   Andi Kleen   [PATCH] i386: Dis...
573
  {
66e13e66b   Jean Delvare   drivers/firmware/...
574
  	static int fields[] = { DMI_SYS_VENDOR, DMI_BOARD_VENDOR, DMI_NONE };
a1bae6724   Andi Kleen   [PATCH] i386: Dis...
575
576
577
578
579
580
581
582
583
  	int i;
  	for (i = 0; fields[i] != DMI_NONE; i++) {
  		int f = fields[i];
  		if (dmi_ident[f] && strstr(dmi_ident[f], str))
  			return 1;
  	}
  	return 0;
  }
  EXPORT_SYMBOL(dmi_name_in_vendors);
ebad6a423   Andrey Panin   [PATCH] dmi: add ...
584
585
586
  /**
   *	dmi_find_device - find onboard device by type/name
   *	@type: device type or %DMI_DEV_TYPE_ANY to match all device types
b0ef371e3   Randy Dunlap   [PATCH] DMI: clea...
587
   *	@name: device name string or %NULL to match all
ebad6a423   Andrey Panin   [PATCH] dmi: add ...
588
589
590
591
592
   *	@from: previous device found in search, or %NULL for new search.
   *
   *	Iterates through the list of known onboard devices. If a device is
   *	found with a matching @vendor and @device, a pointer to its device
   *	structure is returned.  Otherwise, %NULL is returned.
b0ef371e3   Randy Dunlap   [PATCH] DMI: clea...
593
   *	A new search is initiated by passing %NULL as the @from argument.
ebad6a423   Andrey Panin   [PATCH] dmi: add ...
594
595
   *	If @from is not %NULL, searches continue from next device.
   */
1855256c4   Jeff Garzik   drivers/firmware:...
596
597
  const struct dmi_device * dmi_find_device(int type, const char *name,
  				    const struct dmi_device *from)
ebad6a423   Andrey Panin   [PATCH] dmi: add ...
598
  {
1855256c4   Jeff Garzik   drivers/firmware:...
599
600
  	const struct list_head *head = from ? &from->list : &dmi_devices;
  	struct list_head *d;
ebad6a423   Andrey Panin   [PATCH] dmi: add ...
601
602
  
  	for(d = head->next; d != &dmi_devices; d = d->next) {
1855256c4   Jeff Garzik   drivers/firmware:...
603
604
  		const struct dmi_device *dev =
  			list_entry(d, struct dmi_device, list);
ebad6a423   Andrey Panin   [PATCH] dmi: add ...
605
606
607
608
609
610
611
612
613
  
  		if (((type == DMI_DEV_TYPE_ANY) || (dev->type == type)) &&
  		    ((name == NULL) || (strcmp(dev->name, name) == 0)))
  			return dev;
  	}
  
  	return NULL;
  }
  EXPORT_SYMBOL(dmi_find_device);
f083a329e   Andi Kleen   [PATCH] x86_64: C...
614
615
  
  /**
3e5cd1f25   Tejun Heo   dmi: extend dmi_g...
616
617
618
619
620
   *	dmi_get_date - parse a DMI date
   *	@field:	data index (see enum dmi_field)
   *	@yearp: optional out parameter for the year
   *	@monthp: optional out parameter for the month
   *	@dayp: optional out parameter for the day
f083a329e   Andi Kleen   [PATCH] x86_64: C...
621
   *
3e5cd1f25   Tejun Heo   dmi: extend dmi_g...
622
623
624
625
626
627
628
629
630
631
   *	The date field is assumed to be in the form resembling
   *	[mm[/dd]]/yy[yy] and the result is stored in the out
   *	parameters any or all of which can be omitted.
   *
   *	If the field doesn't exist, all out parameters are set to zero
   *	and false is returned.  Otherwise, true is returned with any
   *	invalid part of date set to zero.
   *
   *	On return, year, month and day are guaranteed to be in the
   *	range of [0,9999], [0,12] and [0,31] respectively.
f083a329e   Andi Kleen   [PATCH] x86_64: C...
632
   */
3e5cd1f25   Tejun Heo   dmi: extend dmi_g...
633
  bool dmi_get_date(int field, int *yearp, int *monthp, int *dayp)
f083a329e   Andi Kleen   [PATCH] x86_64: C...
634
  {
3e5cd1f25   Tejun Heo   dmi: extend dmi_g...
635
636
637
  	int year = 0, month = 0, day = 0;
  	bool exists;
  	const char *s, *y;
02c24fa87   Tejun Heo   dmi: fix date han...
638
  	char *e;
f083a329e   Andi Kleen   [PATCH] x86_64: C...
639

3e5cd1f25   Tejun Heo   dmi: extend dmi_g...
640
641
642
643
  	s = dmi_get_system_info(field);
  	exists = s;
  	if (!exists)
  		goto out;
f083a329e   Andi Kleen   [PATCH] x86_64: C...
644

3e5cd1f25   Tejun Heo   dmi: extend dmi_g...
645
646
647
648
649
650
651
652
653
654
655
656
657
  	/*
  	 * Determine year first.  We assume the date string resembles
  	 * mm/dd/yy[yy] but the original code extracted only the year
  	 * from the end.  Keep the behavior in the spirit of no
  	 * surprises.
  	 */
  	y = strrchr(s, '/');
  	if (!y)
  		goto out;
  
  	y++;
  	year = simple_strtoul(y, &e, 10);
  	if (y != e && year < 100) {	/* 2-digit year */
f083a329e   Andi Kleen   [PATCH] x86_64: C...
658
659
660
661
  		year += 1900;
  		if (year < 1996)	/* no dates < spec 1.0 */
  			year += 100;
  	}
3e5cd1f25   Tejun Heo   dmi: extend dmi_g...
662
663
664
665
666
667
668
669
670
  	if (year > 9999)		/* year should fit in %04d */
  		year = 0;
  
  	/* parse the mm and dd */
  	month = simple_strtoul(s, &e, 10);
  	if (s == e || *e != '/' || !month || month > 12) {
  		month = 0;
  		goto out;
  	}
f083a329e   Andi Kleen   [PATCH] x86_64: C...
671

3e5cd1f25   Tejun Heo   dmi: extend dmi_g...
672
673
674
675
676
677
678
679
680
681
682
683
  	s = e + 1;
  	day = simple_strtoul(s, &e, 10);
  	if (s == y || s == e || *e != '/' || day > 31)
  		day = 0;
  out:
  	if (yearp)
  		*yearp = year;
  	if (monthp)
  		*monthp = month;
  	if (dayp)
  		*dayp = day;
  	return exists;
f083a329e   Andi Kleen   [PATCH] x86_64: C...
684
  }
3e5cd1f25   Tejun Heo   dmi: extend dmi_g...
685
  EXPORT_SYMBOL(dmi_get_date);
7fce084a0   Jean Delvare   dmi: Let drivers ...
686
687
688
689
  
  /**
   *	dmi_walk - Walk the DMI table and get called back for every record
   *	@decode: Callback function
e7a19c562   Jean Delvare   dmi: Let dmi_walk...
690
   *	@private_data: Private data to be passed to the callback function
7fce084a0   Jean Delvare   dmi: Let drivers ...
691
692
693
   *
   *	Returns -1 when the DMI table can't be reached, 0 on success.
   */
e7a19c562   Jean Delvare   dmi: Let dmi_walk...
694
695
  int dmi_walk(void (*decode)(const struct dmi_header *, void *),
  	     void *private_data)
7fce084a0   Jean Delvare   dmi: Let drivers ...
696
697
698
699
700
701
702
703
704
  {
  	u8 *buf;
  
  	if (!dmi_available)
  		return -1;
  
  	buf = ioremap(dmi_base, dmi_len);
  	if (buf == NULL)
  		return -1;
e7a19c562   Jean Delvare   dmi: Let dmi_walk...
705
  	dmi_table(buf, dmi_len, dmi_num, decode, private_data);
7fce084a0   Jean Delvare   dmi: Let drivers ...
706
707
708
709
710
  
  	iounmap(buf);
  	return 0;
  }
  EXPORT_SYMBOL_GPL(dmi_walk);
d61c72e52   Jiri Slaby   DMI: add dmi_match
711
712
713
  
  /**
   * dmi_match - compare a string to the dmi field (if exists)
c2bacfc44   Randy Dunlap   dmi: fix kernel-d...
714
715
   * @f: DMI field identifier
   * @str: string to compare the DMI field to
d61c72e52   Jiri Slaby   DMI: add dmi_match
716
717
718
719
720
721
722
723
724
725
726
727
728
   *
   * Returns true if the requested field equals to the str (including NULL).
   */
  bool dmi_match(enum dmi_field f, const char *str)
  {
  	const char *info = dmi_get_system_info(f);
  
  	if (info == NULL || str == NULL)
  		return info == str;
  
  	return !strcmp(info, str);
  }
  EXPORT_SYMBOL_GPL(dmi_match);