PageRenderTime 53ms CodeModel.GetById 2ms app.highlight 46ms RepoModel.GetById 2ms app.codeStats 0ms

/arch/i386/kernel/dmi_scan.c

https://bitbucket.org/evzijst/gittest
C | 487 lines | 338 code | 69 blank | 80 comment | 36 complexity | 3ce2cf3715450886fe83387bfd37c34d MD5 | raw file
  1#include <linux/types.h>
  2#include <linux/kernel.h>
  3#include <linux/string.h>
  4#include <linux/init.h>
  5#include <linux/module.h>
  6#include <linux/slab.h>
  7#include <linux/acpi.h>
  8#include <asm/io.h>
  9#include <linux/pm.h>
 10#include <asm/system.h>
 11#include <linux/dmi.h>
 12#include <linux/bootmem.h>
 13
 14
 15struct dmi_header
 16{
 17	u8	type;
 18	u8	length;
 19	u16	handle;
 20};
 21
 22#undef DMI_DEBUG
 23
 24#ifdef DMI_DEBUG
 25#define dmi_printk(x) printk x
 26#else
 27#define dmi_printk(x)
 28#endif
 29
 30static char * __init dmi_string(struct dmi_header *dm, u8 s)
 31{
 32	u8 *bp=(u8 *)dm;
 33	bp+=dm->length;
 34	if(!s)
 35		return "";
 36	s--;
 37	while(s>0 && *bp)
 38	{
 39		bp+=strlen(bp);
 40		bp++;
 41		s--;
 42	}
 43	return bp;
 44}
 45
 46/*
 47 *	We have to be cautious here. We have seen BIOSes with DMI pointers
 48 *	pointing to completely the wrong place for example
 49 */
 50 
 51static int __init dmi_table(u32 base, int len, int num, void (*decode)(struct dmi_header *))
 52{
 53	u8 *buf;
 54	struct dmi_header *dm;
 55	u8 *data;
 56	int i=0;
 57		
 58	buf = bt_ioremap(base, len);
 59	if(buf==NULL)
 60		return -1;
 61
 62	data = buf;
 63
 64	/*
 65 	 *	Stop when we see all the items the table claimed to have
 66 	 *	OR we run off the end of the table (also happens)
 67 	 */
 68 
 69	while(i<num && data-buf+sizeof(struct dmi_header)<=len)
 70	{
 71		dm=(struct dmi_header *)data;
 72		/*
 73		 *  We want to know the total length (formated area and strings)
 74		 *  before decoding to make sure we won't run off the table in
 75		 *  dmi_decode or dmi_string
 76		 */
 77		data+=dm->length;
 78		while(data-buf<len-1 && (data[0] || data[1]))
 79			data++;
 80		if(data-buf<len-1)
 81			decode(dm);
 82		data+=2;
 83		i++;
 84	}
 85	bt_iounmap(buf, len);
 86	return 0;
 87}
 88
 89
 90inline static int __init dmi_checksum(u8 *buf)
 91{
 92	u8 sum=0;
 93	int a;
 94	
 95	for(a=0; a<15; a++)
 96		sum+=buf[a];
 97	return (sum==0);
 98}
 99
100static int __init dmi_iterate(void (*decode)(struct dmi_header *))
101{
102	u8 buf[15];
103	char __iomem *p, *q;
104
105	/*
106	 * no iounmap() for that ioremap(); it would be a no-op, but it's
107	 * so early in setup that sucker gets confused into doing what
108	 * it shouldn't if we actually call it.
109	 */
110	p = ioremap(0xF0000, 0x10000);
111	if (p == NULL)
112		return -1;
113	for (q = p; q < p + 0x10000; q += 16) {
114		memcpy_fromio(buf, q, 15);
115		if(memcmp(buf, "_DMI_", 5)==0 && dmi_checksum(buf))
116		{
117			u16 num=buf[13]<<8|buf[12];
118			u16 len=buf[7]<<8|buf[6];
119			u32 base=buf[11]<<24|buf[10]<<16|buf[9]<<8|buf[8];
120
121			/*
122			 * DMI version 0.0 means that the real version is taken from
123			 * the SMBIOS version, which we don't know at this point.
124			 */
125			if(buf[14]!=0)
126				printk(KERN_INFO "DMI %d.%d present.\n",
127					buf[14]>>4, buf[14]&0x0F);
128			else
129				printk(KERN_INFO "DMI present.\n");
130			dmi_printk((KERN_INFO "%d structures occupying %d bytes.\n",
131				num, len));
132			dmi_printk((KERN_INFO "DMI table at 0x%08X.\n",
133				base));
134			if(dmi_table(base,len, num, decode)==0)
135				return 0;
136		}
137	}
138	return -1;
139}
140
141static char *dmi_ident[DMI_STRING_MAX];
142
143/*
144 *	Save a DMI string
145 */
146 
147static void __init dmi_save_ident(struct dmi_header *dm, int slot, int string)
148{
149	char *d = (char*)dm;
150	char *p = dmi_string(dm, d[string]);
151	if(p==NULL || *p == 0)
152		return;
153	if (dmi_ident[slot])
154		return;
155	dmi_ident[slot] = alloc_bootmem(strlen(p)+1);
156	if(dmi_ident[slot])
157		strcpy(dmi_ident[slot], p);
158	else
159		printk(KERN_ERR "dmi_save_ident: out of memory.\n");
160}
161
162/*
163 * Ugly compatibility crap.
164 */
165#define dmi_blacklist	dmi_system_id
166#define NO_MATCH	{ DMI_NONE, NULL}
167#define MATCH		DMI_MATCH
168
169/*
170 * Toshiba keyboard likes to repeat keys when they are not repeated.
171 */
172
173static __init int broken_toshiba_keyboard(struct dmi_blacklist *d)
174{
175	printk(KERN_WARNING "Toshiba with broken keyboard detected. If your keyboard sometimes generates 3 keypresses instead of one, see http://davyd.ucc.asn.au/projects/toshiba/README\n");
176	return 0;
177}
178
179
180#ifdef CONFIG_ACPI_SLEEP
181static __init int reset_videomode_after_s3(struct dmi_blacklist *d)
182{
183	/* See acpi_wakeup.S */
184	extern long acpi_video_flags;
185	acpi_video_flags |= 2;
186	return 0;
187}
188#endif
189
190
191#ifdef	CONFIG_ACPI_BOOT
192extern int acpi_force;
193
194static __init __attribute__((unused)) int dmi_disable_acpi(struct dmi_blacklist *d) 
195{ 
196	if (!acpi_force) { 
197		printk(KERN_NOTICE "%s detected: acpi off\n",d->ident); 
198		disable_acpi();
199	} else { 
200		printk(KERN_NOTICE 
201		       "Warning: DMI blacklist says broken, but acpi forced\n"); 
202	}
203	return 0;
204} 
205
206/*
207 * Limit ACPI to CPU enumeration for HT
208 */
209static __init __attribute__((unused)) int force_acpi_ht(struct dmi_blacklist *d) 
210{ 
211	if (!acpi_force) { 
212		printk(KERN_NOTICE "%s detected: force use of acpi=ht\n", d->ident); 
213		disable_acpi();
214		acpi_ht = 1; 
215	} else { 
216		printk(KERN_NOTICE 
217		       "Warning: acpi=force overrules DMI blacklist: acpi=ht\n"); 
218	}
219	return 0;
220} 
221#endif
222
223#ifdef	CONFIG_ACPI_PCI
224static __init int disable_acpi_irq(struct dmi_blacklist *d) 
225{
226	if (!acpi_force) {
227		printk(KERN_NOTICE "%s detected: force use of acpi=noirq\n",
228		       d->ident); 	
229		acpi_noirq_set();
230	}
231	return 0;
232}
233static __init int disable_acpi_pci(struct dmi_blacklist *d) 
234{
235	if (!acpi_force) {
236		printk(KERN_NOTICE "%s detected: force use of pci=noacpi\n",
237		       d->ident); 	
238		acpi_disable_pci();
239	}
240	return 0;
241}  
242#endif
243
244/*
245 *	Process the DMI blacklists
246 */
247 
248
249/*
250 *	This will be expanded over time to force things like the APM 
251 *	interrupt mask settings according to the laptop
252 */
253 
254static __initdata struct dmi_blacklist dmi_blacklist[]={
255
256	{ broken_toshiba_keyboard, "Toshiba Satellite 4030cdt", { /* Keyboard generates spurious repeats */
257			MATCH(DMI_PRODUCT_NAME, "S4030CDT/4.3"),
258			NO_MATCH, NO_MATCH, NO_MATCH
259			} },
260#ifdef CONFIG_ACPI_SLEEP
261	{ reset_videomode_after_s3, "Toshiba Satellite 4030cdt", { /* Reset video mode after returning from ACPI S3 sleep */
262			MATCH(DMI_PRODUCT_NAME, "S4030CDT/4.3"),
263			NO_MATCH, NO_MATCH, NO_MATCH
264			} },
265#endif
266
267#ifdef	CONFIG_ACPI_BOOT
268	/*
269	 * If your system is blacklisted here, but you find that acpi=force
270	 * works for you, please contact acpi-devel@sourceforge.net
271	 */
272
273	/*
274	 *	Boxes that need ACPI disabled
275	 */
276
277	{ dmi_disable_acpi, "IBM Thinkpad", {
278			MATCH(DMI_BOARD_VENDOR, "IBM"),
279			MATCH(DMI_BOARD_NAME, "2629H1G"),
280			NO_MATCH, NO_MATCH }},
281
282	/*
283	 *	Boxes that need acpi=ht 
284	 */
285
286	{ force_acpi_ht, "FSC Primergy T850", {
287			MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
288			MATCH(DMI_PRODUCT_NAME, "PRIMERGY T850"),
289			NO_MATCH, NO_MATCH }},
290
291	{ force_acpi_ht, "DELL GX240", {
292			MATCH(DMI_BOARD_VENDOR, "Dell Computer Corporation"),
293			MATCH(DMI_BOARD_NAME, "OptiPlex GX240"),
294			NO_MATCH, NO_MATCH }},
295
296	{ force_acpi_ht, "HP VISUALIZE NT Workstation", {
297			MATCH(DMI_BOARD_VENDOR, "Hewlett-Packard"),
298			MATCH(DMI_PRODUCT_NAME, "HP VISUALIZE NT Workstation"),
299			NO_MATCH, NO_MATCH }},
300
301	{ force_acpi_ht, "Compaq Workstation W8000", {
302			MATCH(DMI_SYS_VENDOR, "Compaq"),
303			MATCH(DMI_PRODUCT_NAME, "Workstation W8000"),
304			NO_MATCH, NO_MATCH }},
305
306	{ force_acpi_ht, "ASUS P4B266", {
307			MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."),
308			MATCH(DMI_BOARD_NAME, "P4B266"),
309			NO_MATCH, NO_MATCH }},
310
311	{ force_acpi_ht, "ASUS P2B-DS", {
312			MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."),
313			MATCH(DMI_BOARD_NAME, "P2B-DS"),
314			NO_MATCH, NO_MATCH }},
315
316	{ force_acpi_ht, "ASUS CUR-DLS", {
317			MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."),
318			MATCH(DMI_BOARD_NAME, "CUR-DLS"),
319			NO_MATCH, NO_MATCH }},
320
321	{ force_acpi_ht, "ABIT i440BX-W83977", {
322			MATCH(DMI_BOARD_VENDOR, "ABIT <http://www.abit.com>"),
323			MATCH(DMI_BOARD_NAME, "i440BX-W83977 (BP6)"),
324			NO_MATCH, NO_MATCH }},
325
326	{ force_acpi_ht, "IBM Bladecenter", {
327			MATCH(DMI_BOARD_VENDOR, "IBM"),
328			MATCH(DMI_BOARD_NAME, "IBM eServer BladeCenter HS20"),
329			NO_MATCH, NO_MATCH }},
330
331	{ force_acpi_ht, "IBM eServer xSeries 360", {
332			MATCH(DMI_BOARD_VENDOR, "IBM"),
333			MATCH(DMI_BOARD_NAME, "eServer xSeries 360"),
334			NO_MATCH, NO_MATCH }},
335
336	{ force_acpi_ht, "IBM eserver xSeries 330", {
337			MATCH(DMI_BOARD_VENDOR, "IBM"),
338			MATCH(DMI_BOARD_NAME, "eserver xSeries 330"),
339			NO_MATCH, NO_MATCH }},
340
341	{ force_acpi_ht, "IBM eserver xSeries 440", {
342			MATCH(DMI_BOARD_VENDOR, "IBM"),
343			MATCH(DMI_PRODUCT_NAME, "eserver xSeries 440"),
344			NO_MATCH, NO_MATCH }},
345
346#endif	// CONFIG_ACPI_BOOT
347
348#ifdef	CONFIG_ACPI_PCI
349	/*
350	 *	Boxes that need ACPI PCI IRQ routing disabled
351	 */
352
353	{ disable_acpi_irq, "ASUS A7V", {
354			MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC"),
355			MATCH(DMI_BOARD_NAME, "<A7V>"),
356			/* newer BIOS, Revision 1011, does work */
357			MATCH(DMI_BIOS_VERSION, "ASUS A7V ACPI BIOS Revision 1007"),
358			NO_MATCH }},
359
360	/*
361	 *	Boxes that need ACPI PCI IRQ routing and PCI scan disabled
362	 */
363	{ disable_acpi_pci, "ASUS PR-DLS", {	/* _BBN 0 bug */
364			MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."),
365			MATCH(DMI_BOARD_NAME, "PR-DLS"),
366			MATCH(DMI_BIOS_VERSION, "ASUS PR-DLS ACPI BIOS Revision 1010"),
367			MATCH(DMI_BIOS_DATE, "03/21/2003") }},
368
369 	{ disable_acpi_pci, "Acer TravelMate 36x Laptop", {
370 			MATCH(DMI_SYS_VENDOR, "Acer"),
371 			MATCH(DMI_PRODUCT_NAME, "TravelMate 360"),
372 			NO_MATCH, NO_MATCH
373 			} },
374
375#endif
376
377	{ NULL, }
378};
379
380/*
381 *	Process a DMI table entry. Right now all we care about are the BIOS
382 *	and machine entries. For 2.5 we should pull the smbus controller info
383 *	out of here.
384 */
385
386static void __init dmi_decode(struct dmi_header *dm)
387{
388#ifdef DMI_DEBUG
389	u8 *data = (u8 *)dm;
390#endif
391	
392	switch(dm->type)
393	{
394		case  0:
395			dmi_printk(("BIOS Vendor: %s\n",
396				dmi_string(dm, data[4])));
397			dmi_save_ident(dm, DMI_BIOS_VENDOR, 4);
398			dmi_printk(("BIOS Version: %s\n", 
399				dmi_string(dm, data[5])));
400			dmi_save_ident(dm, DMI_BIOS_VERSION, 5);
401			dmi_printk(("BIOS Release: %s\n",
402				dmi_string(dm, data[8])));
403			dmi_save_ident(dm, DMI_BIOS_DATE, 8);
404			break;
405		case 1:
406			dmi_printk(("System Vendor: %s\n",
407				dmi_string(dm, data[4])));
408			dmi_save_ident(dm, DMI_SYS_VENDOR, 4);
409			dmi_printk(("Product Name: %s\n",
410				dmi_string(dm, data[5])));
411			dmi_save_ident(dm, DMI_PRODUCT_NAME, 5);
412			dmi_printk(("Version: %s\n",
413				dmi_string(dm, data[6])));
414			dmi_save_ident(dm, DMI_PRODUCT_VERSION, 6);
415			dmi_printk(("Serial Number: %s\n",
416				dmi_string(dm, data[7])));
417			break;
418		case 2:
419			dmi_printk(("Board Vendor: %s\n",
420				dmi_string(dm, data[4])));
421			dmi_save_ident(dm, DMI_BOARD_VENDOR, 4);
422			dmi_printk(("Board Name: %s\n",
423				dmi_string(dm, data[5])));
424			dmi_save_ident(dm, DMI_BOARD_NAME, 5);
425			dmi_printk(("Board Version: %s\n",
426				dmi_string(dm, data[6])));
427			dmi_save_ident(dm, DMI_BOARD_VERSION, 6);
428			break;
429	}
430}
431
432void __init dmi_scan_machine(void)
433{
434	int err = dmi_iterate(dmi_decode);
435	if(err == 0)
436 		dmi_check_system(dmi_blacklist);
437	else
438		printk(KERN_INFO "DMI not present.\n");
439}
440
441
442/**
443 *	dmi_check_system - check system DMI data
444 *	@list: array of dmi_system_id structures to match against
445 *
446 *	Walk the blacklist table running matching functions until someone
447 *	returns non zero or we hit the end. Callback function is called for
448 *	each successfull match. Returns the number of matches.
449 */
450int dmi_check_system(struct dmi_system_id *list)
451{
452	int i, count = 0;
453	struct dmi_system_id *d = list;
454
455	while (d->ident) {
456		for (i = 0; i < ARRAY_SIZE(d->matches); i++) {
457			int s = d->matches[i].slot;
458			if (s == DMI_NONE)
459				continue;
460			if (dmi_ident[s] && strstr(dmi_ident[s], d->matches[i].substr))
461				continue;
462			/* No match */
463			goto fail;
464		}
465		if (d->callback && d->callback(d))
466			break;
467		count++;
468fail:		d++;
469	}
470
471	return count;
472}
473
474EXPORT_SYMBOL(dmi_check_system);
475
476/**
477 *	dmi_get_system_info - return DMI data value
478 *	@field: data index (see enum dmi_filed)
479 *
480 *	Returns one DMI data value, can be used to perform
481 *	complex DMI data checks.
482 */
483char * dmi_get_system_info(int field)
484{
485	return dmi_ident[field];
486}
487