1#include <linux/config.h>
2#include <linux/types.h>
3#include <linux/kernel.h>
4#include <linux/string.h>
5#include <linux/init.h>
6#include <linux/apm_bios.h>
7#include <linux/slab.h>
8#include <asm/io.h>
9#include <linux/pm.h>
10#include <asm/keyboard.h>
11#include <asm/system.h>
12#include <linux/bootmem.h>
13
14unsigned long dmi_broken;
15int is_sony_vaio_laptop;
16
17struct dmi_header
18{
19	u8	type;
20	u8	length;
21	u16	handle;
22};
23
24#define dmi_printk(x)
25//#define dmi_printk(x) printk x
26
27static char * __init dmi_string(struct dmi_header *dm, u8 s)
28{
29	u8 *bp=(u8 *)dm;
30	bp+=dm->length;
31	if(!s)
32		return "";
33	s--;
34	while(s>0 && *bp)
35	{
36		bp+=strlen(bp);
37		bp++;
38		s--;
39	}
40	return bp;
41}
42
43/*
44 *	We have to be cautious here. We have seen BIOSes with DMI pointers
45 *	pointing to completely the wrong place for example
46 */
47
48static int __init dmi_table(u32 base, int len, int num, void (*decode)(struct dmi_header *))
49{
50	u8 *buf;
51	struct dmi_header *dm;
52	u8 *data;
53	int i=0;
54
55	buf = bt_ioremap(base, len);
56	if(buf==NULL)
57		return -1;
58
59	data = buf;
60
61	/*
62 	 *	Stop when we see all the items the table claimed to have
63 	 *	OR we run off the end of the table (also happens)
64 	 */
65
66	while(i<num && data-buf+sizeof(struct dmi_header)<=len)
67	{
68		dm=(struct dmi_header *)data;
69		/*
70		 *  We want to know the total length (formated area and strings)
71		 *  before decoding to make sure we won't run off the table in
72		 *  dmi_decode or dmi_string
73		 */
74		data+=dm->length;
75		while(data-buf<len-1 && (data[0] || data[1]))
76			data++;
77		if(data-buf<len-1)
78			decode(dm);
79		data+=2;
80		i++;
81	}
82	bt_iounmap(buf, len);
83	return 0;
84}
85
86
87inline static int __init dmi_checksum(u8 *buf)
88{
89	u8 sum=0;
90	int a;
91
92	for(a=0; a<15; a++)
93		sum+=buf[a];
94	return (sum==0);
95}
96
97static int __init dmi_iterate(void (*decode)(struct dmi_header *))
98{
99	u8 buf[15];
100	u32 fp=0xF0000;
101
102#ifdef CONFIG_SIMNOW
103	/*
104 	 *	Skip on x86/64 with simnow. Will eventually go away
105 	 *	If you see this ifdef in 2.6pre mail me !
106 	 */
107	return -1;
108#endif
109
110	while( fp < 0xFFFFF)
111	{
112		isa_memcpy_fromio(buf, fp, 15);
113		if(memcmp(buf, "_DMI_", 5)==0 && dmi_checksum(buf))
114		{
115			u16 num=buf[13]<<8|buf[12];
116			u16 len=buf[7]<<8|buf[6];
117			u32 base=buf[11]<<24|buf[10]<<16|buf[9]<<8|buf[8];
118
119			/*
120			 * DMI version 0.0 means that the real version is taken from
121			 * the SMBIOS version, which we don't know at this point.
122			 */
123			if(buf[14]!=0)
124				dmi_printk((KERN_INFO "DMI %d.%d present.\n",
125					buf[14]>>4, buf[14]&0x0F));
126			else
127				dmi_printk((KERN_INFO "DMI present.\n"));
128			dmi_printk((KERN_INFO "%d structures occupying %d bytes.\n",
129				num, len));
130			dmi_printk((KERN_INFO "DMI table at 0x%08X.\n",
131				base));
132			if(dmi_table(base,len, num, decode)==0)
133				return 0;
134		}
135		fp+=16;
136	}
137	return -1;
138}
139
140
141enum
142{
143	DMI_BIOS_VENDOR,
144	DMI_BIOS_VERSION,
145	DMI_BIOS_DATE,
146	DMI_SYS_VENDOR,
147	DMI_PRODUCT_NAME,
148	DMI_PRODUCT_VERSION,
149	DMI_BOARD_VENDOR,
150	DMI_BOARD_NAME,
151	DMI_BOARD_VERSION,
152	DMI_STRING_MAX
153};
154
155static char *dmi_ident[DMI_STRING_MAX];
156
157/*
158 *	Save a DMI string
159 */
160
161static void __init dmi_save_ident(struct dmi_header *dm, int slot, int string)
162{
163	char *d = (char*)dm;
164	char *p = dmi_string(dm, d[string]);
165	if(p==NULL || *p == 0)
166		return;
167	if (dmi_ident[slot])
168		return;
169	dmi_ident[slot] = alloc_bootmem(strlen(p)+1);
170	if(dmi_ident[slot])
171		strcpy(dmi_ident[slot], p);
172	else
173		printk(KERN_ERR "dmi_save_ident: out of memory.\n");
174}
175
176/*
177 *	DMI callbacks for problem boards
178 */
179
180struct dmi_strmatch
181{
182	u8 slot;
183	char *substr;
184};
185
186#define NONE	255
187
188struct dmi_blacklist
189{
190	int (*callback)(struct dmi_blacklist *);
191	char *ident;
192	struct dmi_strmatch matches[4];
193};
194
195#define NO_MATCH	{ NONE, NULL}
196#define MATCH(a,b)	{ a, b }
197
198/*
199 *	We have problems with IDE DMA on some platforms. In paticular the
200 *	KT7 series. On these it seems the newer BIOS has fixed them. The
201 *	rule needs to be improved to match specific BIOS revisions with
202 *	corruption problems
203
204static __init int disable_ide_dma(struct dmi_blacklist *d)
205{
206#ifdef CONFIG_BLK_DEV_IDE
207	extern int noautodma;
208	if(noautodma == 0)
209	{
210		noautodma = 1;
211		printk(KERN_INFO "%s series board detected. Disabling IDE DMA.\n", d->ident);
212	}
213#endif
214	return 0;
215}
216 */
217
218/*
219 * Reboot options and system auto-detection code provided by
220 * Dell Computer Corporation so their systems "just work". :-)
221 */
222
223/*
224 * Some machines require the "reboot=b"  commandline option, this quirk makes that automatic.
225 */
226static __init int set_bios_reboot(struct dmi_blacklist *d)
227{
228	extern int reboot_thru_bios;
229	if (reboot_thru_bios == 0)
230	{
231		reboot_thru_bios = 1;
232		printk(KERN_INFO "%s series board detected. Selecting BIOS-method for reboots.\n", d->ident);
233	}
234	return 0;
235}
236
237/*
238 * Some machines require the "reboot=s"  commandline option, this quirk makes that automatic.
239 */
240static __init int set_smp_reboot(struct dmi_blacklist *d)
241{
242#ifdef CONFIG_SMP
243	extern int reboot_smp;
244	if (reboot_smp == 0)
245	{
246		reboot_smp = 1;
247		printk(KERN_INFO "%s series board detected. Selecting SMP-method for reboots.\n", d->ident);
248	}
249#endif
250	return 0;
251}
252
253/*
254 * Some machines require the "reboot=b,s"  commandline option, this quirk makes that automatic.
255 */
256static __init int set_smp_bios_reboot(struct dmi_blacklist *d)
257{
258	set_smp_reboot(d);
259	set_bios_reboot(d);
260	return 0;
261}
262
263/*
264 * Some bioses have a broken protected mode poweroff and need to use realmode
265 */
266
267static __init int set_realmode_power_off(struct dmi_blacklist *d)
268{
269       if (apm_info.realmode_power_off == 0)
270       {
271               apm_info.realmode_power_off = 1;
272               printk(KERN_INFO "%s bios detected. Using realmode poweroff only.\n", d->ident);
273       }
274       return 0;
275}
276
277
278/*
279 * Some laptops require interrupts to be enabled during APM calls
280 */
281
282static __init int set_apm_ints(struct dmi_blacklist *d)
283{
284	if (apm_info.allow_ints == 0)
285	{
286		apm_info.allow_ints = 1;
287		printk(KERN_INFO "%s machine detected. Enabling interrupts during APM calls.\n", d->ident);
288	}
289	return 0;
290}
291
292/*
293 * Some APM bioses corrupt memory or just plain do not work
294 */
295
296static __init int apm_is_horked(struct dmi_blacklist *d)
297{
298	if (apm_info.disabled == 0)
299	{
300		apm_info.disabled = 1;
301		printk(KERN_INFO "%s machine detected. Disabling APM.\n", d->ident);
302	}
303	return 0;
304}
305
306/*
307 * Some machines, usually laptops, can't handle an enabled local APIC.
308 * The symptoms include hangs or reboots when suspending or resuming,
309 * attaching or detaching the power cord, or entering BIOS setup screens
310 * through magic key sequences.
311 */
312static int __init local_apic_kills_bios(struct dmi_blacklist *d)
313{
314#ifdef CONFIG_X86_LOCAL_APIC
315	extern int dont_enable_local_apic;
316	if (!dont_enable_local_apic) {
317		dont_enable_local_apic = 1;
318		printk(KERN_WARNING "%s with broken BIOS detected. "
319		       "Refusing to enable the local APIC.\n",
320		       d->ident);
321	}
322#endif
323	return 0;
324}
325
326/*
327 * The Microstar 6163-2 (a.k.a Pro) mainboard will hang shortly after
328 * resumes, and also at what appears to be asynchronous APM events,
329 * if the local APIC is enabled.
330 */
331static int __init apm_kills_local_apic(struct dmi_blacklist *d)
332{
333#ifdef CONFIG_X86_LOCAL_APIC
334	extern int dont_enable_local_apic;
335	if (apm_info.bios.version && !dont_enable_local_apic) {
336		dont_enable_local_apic = 1;
337		printk(KERN_WARNING "%s with broken BIOS detected. "
338		       "Refusing to enable the local APIC.\n",
339		       d->ident);
340	}
341#endif
342	return 0;
343}
344
345/*
346 * The Intel AL440LX mainboard will hang randomly if the local APIC
347 * timer is running and the APM BIOS hasn't been disabled.
348 */
349static int __init apm_kills_local_apic_timer(struct dmi_blacklist *d)
350{
351#ifdef CONFIG_X86_LOCAL_APIC
352	extern int dont_use_local_apic_timer;
353	if (apm_info.bios.version && !dont_use_local_apic_timer) {
354		dont_use_local_apic_timer = 1;
355		printk(KERN_WARNING "%s with broken BIOS detected. "
356		       "The local APIC timer will not be used.\n",
357		       d->ident);
358	}
359#endif
360	return 0;
361}
362
363/*
364 *  Check for clue free BIOS implementations who use
365 *  the following QA technique
366 *
367 *      [ Write BIOS Code ]<------
368 *               |                ^
369 *      < Does it Compile >----N--
370 *               |Y               ^
371 *	< Does it Boot Win98 >-N--
372 *               |Y
373 *           [Ship It]
374 *
375 *	Phoenix A04  08/24/2000 is known bad (Dell Inspiron 5000e)
376 *	Phoenix A07  09/29/2000 is known good (Dell Inspiron 5000)
377 */
378
379static __init int broken_apm_power(struct dmi_blacklist *d)
380{
381	apm_info.get_power_status_broken = 1;
382	printk(KERN_WARNING "BIOS strings suggest APM bugs, disabling power status reporting.\n");
383	return 0;
384}
385
386/*
387 * Check for a Sony Vaio system
388 *
389 * On a Sony system we want to enable the use of the sonypi
390 * driver for Sony-specific goodies like the camera and jogdial.
391 * We also want to avoid using certain functions of the PnP BIOS.
392 */
393
394static __init int sony_vaio_laptop(struct dmi_blacklist *d)
395{
396	if (is_sony_vaio_laptop == 0)
397	{
398		is_sony_vaio_laptop = 1;
399		printk(KERN_INFO "%s laptop detected.\n", d->ident);
400	}
401	return 0;
402}
403
404/*
405 * This bios swaps the APM minute reporting bytes over (Many sony laptops
406 * have this problem).
407 */
408
409static __init int swab_apm_power_in_minutes(struct dmi_blacklist *d)
410{
411	apm_info.get_power_status_swabinminutes = 1;
412	printk(KERN_WARNING "BIOS strings suggest APM reports battery life in minutes and wrong byte order.\n");
413	return 0;
414}
415
416/*
417 * The Intel 440GX hall of shame.
418 *
419 * On many (all we have checked) of these boxes the $PIRQ table is wrong.
420 * The MP1.4 table is right however and so SMP kernels tend to work.
421 */
422
423extern int skip_ioapic_setup;
424static __init int broken_pirq(struct dmi_blacklist *d)
425{
426	printk(KERN_INFO " *** Possibly defective BIOS detected (irqtable)\n");
427	printk(KERN_INFO " *** Many BIOSes matching this signature have incorrect IRQ routing tables.\n");
428	printk(KERN_INFO " *** If you see IRQ problems, in paticular SCSI resets and hangs at boot\n");
429	printk(KERN_INFO " *** contact your hardware vendor and ask about updates.\n");
430	printk(KERN_INFO " *** Building an SMP kernel may evade the bug some of the time.\n");
431#ifdef CONFIG_X86_IO_APIC
432	skip_ioapic_setup = 0;
433#endif
434	return 0;
435}
436
437/*
438 * ASUS K7V-RM has broken ACPI table defining sleep modes
439 */
440
441static __init int broken_acpi_Sx(struct dmi_blacklist *d)
442{
443	printk(KERN_WARNING "Detected ASUS mainboard with broken ACPI sleep table\n");
444	dmi_broken |= BROKEN_ACPI_Sx;
445	return 0;
446}
447
448/*
449 * Toshiba keyboard likes to repeat keys when they are not repeated.
450 */
451
452static __init int broken_toshiba_keyboard(struct dmi_blacklist *d)
453{
454	printk(KERN_WARNING "Toshiba with broken keyboard detected. If your keyboard sometimes generates 3 keypresses instead of one, contact pavel@ucw.cz\n");
455	return 0;
456}
457
458/*
459 * Toshiba fails to preserve interrupts over S1
460 */
461
462static __init int init_ints_after_s1(struct dmi_blacklist *d)
463{
464	printk(KERN_WARNING "Toshiba with broken S1 detected.\n");
465	dmi_broken |= BROKEN_INIT_AFTER_S1;
466	return 0;
467}
468
469/*
470 * Some Bioses enable the PS/2 mouse (touchpad) at resume, even if it
471 * was disabled before the suspend. Linux gets terribly confused by that.
472 */
473
474typedef void (pm_kbd_func) (void);
475
476static __init int broken_ps2_resume(struct dmi_blacklist *d)
477{
478#ifdef CONFIG_VT
479	if (pm_kbd_request_override == NULL)
480	{
481		pm_kbd_request_override = pckbd_pm_resume;
482		printk(KERN_INFO "%s machine detected. Mousepad Resume Bug workaround enabled.\n", d->ident);
483	}
484#endif
485	return 0;
486}
487
488/*
489 * Work around broken HP Pavilion Notebooks which assign USB to
490 * IRQ 9 even though it is actually wired to IRQ 11
491 */
492static __init int fix_broken_hp_bios_irq9(struct dmi_blacklist *d)
493{
494#ifdef CONFIG_PCI
495	extern int broken_hp_bios_irq9;
496	if (broken_hp_bios_irq9 == 0)
497	{
498		broken_hp_bios_irq9 = 1;
499		printk(KERN_INFO "%s detected - fixing broken IRQ routing\n", d->ident);
500	}
501#endif
502	return 0;
503}
504
505/*
506 *	Simple "print if true" callback
507 */
508
509static __init int print_if_true(struct dmi_blacklist *d)
510{
511	printk("%s\n", d->ident);
512	return 0;
513}
514
515/*
516 *	Process the DMI blacklists
517 */
518
519
520/*
521 *	This will be expanded over time to force things like the APM
522 *	interrupt mask settings according to the laptop
523 */
524
525static __initdata struct dmi_blacklist dmi_blacklist[]={
526	{ broken_ps2_resume, "Dell Latitude C600", {	/* Handle problems with APM on the C600 */
527		        MATCH(DMI_SYS_VENDOR, "Dell"),
528			MATCH(DMI_PRODUCT_NAME, "Latitude C600"),
529			NO_MATCH, NO_MATCH
530	                } },
531	{ broken_apm_power, "Dell Inspiron 5000e", {	/* Handle problems with APM on Inspiron 5000e */
532			MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"),
533			MATCH(DMI_BIOS_VERSION, "A04"),
534			MATCH(DMI_BIOS_DATE, "08/24/2000"), NO_MATCH
535			} },
536	{ broken_apm_power, "Dell Inspiron 2500", {	/* Handle problems with APM on Inspiron 2500 */
537			MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"),
538			MATCH(DMI_BIOS_VERSION, "A12"),
539			MATCH(DMI_BIOS_DATE, "02/04/2002"), NO_MATCH
540			} },
541	{ set_realmode_power_off, "Award Software v4.60 PGMA", {	/* broken PM poweroff bios */
542			MATCH(DMI_BIOS_VENDOR, "Award Software International, Inc."),
543			MATCH(DMI_BIOS_VERSION, "4.60 PGMA"),
544			MATCH(DMI_BIOS_DATE, "134526184"), NO_MATCH
545			} },
546	{ set_smp_bios_reboot, "Dell PowerEdge 1300", {	/* Handle problems with rebooting on Dell 1300's */
547			MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"),
548			MATCH(DMI_PRODUCT_NAME, "PowerEdge 1300/"),
549			NO_MATCH, NO_MATCH
550			} },
551	{ set_bios_reboot, "Dell PowerEdge 300", {	/* Handle problems with rebooting on Dell 1300's */
552			MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"),
553			MATCH(DMI_PRODUCT_NAME, "PowerEdge 300/"),
554			NO_MATCH, NO_MATCH
555			} },
556	{ set_bios_reboot, "Dell PowerEdge 2400", {  /* Handle problems with rebooting on Dell 300/800's */
557			MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"),
558			MATCH(DMI_PRODUCT_NAME, "PowerEdge 2400"),
559			NO_MATCH, NO_MATCH
560			} },
561	{ set_apm_ints, "Dell Inspiron", {	/* Allow interrupts during suspend on Dell Inspiron laptops*/
562			MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"),
563			MATCH(DMI_PRODUCT_NAME, "Inspiron 4000"),
564			NO_MATCH, NO_MATCH
565			} },
566	{ set_apm_ints, "Compaq 12XL125", {	/* Allow interrupts during suspend on Compaq Laptops*/
567			MATCH(DMI_SYS_VENDOR, "Compaq"),
568			MATCH(DMI_PRODUCT_NAME, "Compaq PC"),
569			MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"),
570			MATCH(DMI_BIOS_VERSION,"4.06")
571			} },
572	{ set_apm_ints, "ASUSTeK", {   /* Allow interrupts during APM or the clock goes slow */
573			MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."),
574			MATCH(DMI_PRODUCT_NAME, "L8400K series Notebook PC"),
575			NO_MATCH, NO_MATCH
576			} },
577	{ apm_is_horked, "Trigem Delhi3", { /* APM crashes */
578			MATCH(DMI_SYS_VENDOR, "TriGem Computer, Inc"),
579			MATCH(DMI_PRODUCT_NAME, "Delhi3"),
580			NO_MATCH, NO_MATCH,
581			} },
582	{ apm_is_horked, "Fujitsu-Siemens", { /* APM crashes */
583			MATCH(DMI_BIOS_VENDOR, "hoenix/FUJITSU SIEMENS"),
584			MATCH(DMI_BIOS_VERSION, "Version1.01"),
585			NO_MATCH, NO_MATCH,
586			} },
587	{ apm_is_horked, "Intel D850MD", { /* APM crashes */
588			MATCH(DMI_BIOS_VENDOR, "Intel Corp."),
589			MATCH(DMI_BIOS_VERSION, "MV85010A.86A.0016.P07.0201251536"),
590			NO_MATCH, NO_MATCH,
591			} },
592	{ apm_is_horked, "Dell XPS-Z", { /* APM crashes */
593			MATCH(DMI_BIOS_VENDOR, "Intel Corp."),
594			MATCH(DMI_BIOS_VERSION, "A11"),
595			MATCH(DMI_PRODUCT_NAME, "XPS-Z"),
596			NO_MATCH,
597			} },
598	{ apm_is_horked, "Sharp PC-PJ/AX", { /* APM crashes */
599			MATCH(DMI_SYS_VENDOR, "SHARP"),
600			MATCH(DMI_PRODUCT_NAME, "PC-PJ/AX"),
601			MATCH(DMI_BIOS_VENDOR,"SystemSoft"),
602			MATCH(DMI_BIOS_VERSION,"Version R2.08")
603			} },
604	{ apm_is_horked, "Dell Inspiron 2500", { /* APM crashes */
605			MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"),
606			MATCH(DMI_PRODUCT_NAME, "Inspiron 2500"),
607			MATCH(DMI_BIOS_VENDOR,"Phoenix Technologies LTD"),
608			MATCH(DMI_BIOS_VERSION,"A11")
609			} },
610	{ sony_vaio_laptop, "Sony Vaio", { /* This is a Sony Vaio laptop */
611			MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
612			MATCH(DMI_PRODUCT_NAME, "PCG-"),
613			NO_MATCH, NO_MATCH,
614			} },
615	{ swab_apm_power_in_minutes, "Sony VAIO", { /* Handle problems with APM on Sony Vaio PCG-N505X(DE) */
616			MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"),
617			MATCH(DMI_BIOS_VERSION, "R0206H"),
618			MATCH(DMI_BIOS_DATE, "08/23/99"), NO_MATCH
619	} },
620
621	{ swab_apm_power_in_minutes, "Sony VAIO", { /* Handle problems with APM on Sony Vaio PCG-N505VX */
622			MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"),
623			MATCH(DMI_BIOS_VERSION, "W2K06H0"),
624			MATCH(DMI_BIOS_DATE, "02/03/00"), NO_MATCH
625			} },
626
627	{ swab_apm_power_in_minutes, "Sony VAIO", {	/* Handle problems with APM on Sony Vaio PCG-XG29 */
628			MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"),
629			MATCH(DMI_BIOS_VERSION, "R0117A0"),
630			MATCH(DMI_BIOS_DATE, "04/25/00"), NO_MATCH
631			} },
632
633	{ swab_apm_power_in_minutes, "Sony VAIO", {	/* Handle problems with APM on Sony Vaio PCG-Z600NE */
634			MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"),
635			MATCH(DMI_BIOS_VERSION, "R0121Z1"),
636			MATCH(DMI_BIOS_DATE, "05/11/00"), NO_MATCH
637			} },
638
639	{ swab_apm_power_in_minutes, "Sony VAIO", {	/* Handle problems with APM on Sony Vaio PCG-Z600NE */
640			MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"),
641			MATCH(DMI_BIOS_VERSION, "WME01Z1"),
642			MATCH(DMI_BIOS_DATE, "08/11/00"), NO_MATCH
643			} },
644
645	{ swab_apm_power_in_minutes, "Sony VAIO", {	/* Handle problems with APM on Sony Vaio PCG-Z600LEK(DE) */
646			MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"),
647			MATCH(DMI_BIOS_VERSION, "R0206Z3"),
648			MATCH(DMI_BIOS_DATE, "12/25/00"), NO_MATCH
649			} },
650
651	{ swab_apm_power_in_minutes, "Sony VAIO", {	/* Handle problems with APM on Sony Vaio PCG-Z505LS */
652			MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"),
653			MATCH(DMI_BIOS_VERSION, "R0203D0"),
654			MATCH(DMI_BIOS_DATE, "05/12/00"), NO_MATCH
655			} },
656
657	{ swab_apm_power_in_minutes, "Sony VAIO", {	/* Handle problems with APM on Sony Vaio PCG-Z505LS */
658			MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"),
659			MATCH(DMI_BIOS_VERSION, "R0203Z3"),
660			MATCH(DMI_BIOS_DATE, "08/25/00"), NO_MATCH
661			} },
662
663	{ swab_apm_power_in_minutes, "Sony VAIO", {	/* Handle problems with APM on Sony Vaio PCG-Z505LS (with updated BIOS) */
664			MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"),
665			MATCH(DMI_BIOS_VERSION, "R0209Z3"),
666			MATCH(DMI_BIOS_DATE, "05/12/01"), NO_MATCH
667			} },
668
669	{ swab_apm_power_in_minutes, "Sony VAIO", {	/* Handle problems with APM on Sony Vaio PCG-Z505LS (with updated BIOS) */
670			MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"),
671			MATCH(DMI_BIOS_VERSION, "WXP01Z3"),
672			MATCH(DMI_BIOS_DATE, "10/26/01"), NO_MATCH
673			} },
674
675	{ swab_apm_power_in_minutes, "Sony VAIO", {	/* Handle problems with APM on Sony Vaio PCG-F104K */
676			MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"),
677			MATCH(DMI_BIOS_VERSION, "R0204K2"),
678			MATCH(DMI_BIOS_DATE, "08/28/00"), NO_MATCH
679			} },
680
681	{ swab_apm_power_in_minutes, "Sony VAIO", {	/* Handle problems with APM on Sony Vaio PCG-C1VN/C1VE */
682			MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"),
683			MATCH(DMI_BIOS_VERSION, "R0208P1"),
684			MATCH(DMI_BIOS_DATE, "11/09/00"), NO_MATCH
685			} },
686	{ swab_apm_power_in_minutes, "Sony VAIO", {	/* Handle problems with APM on Sony Vaio PCG-C1VE */
687			MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"),
688			MATCH(DMI_BIOS_VERSION, "R0204P1"),
689			MATCH(DMI_BIOS_DATE, "09/12/00"), NO_MATCH
690			} },
691
692	/* Machines which have problems handling enabled local APICs */
693
694	{ local_apic_kills_bios, "Dell Inspiron", {
695			MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"),
696			MATCH(DMI_PRODUCT_NAME, "Inspiron"),
697			NO_MATCH, NO_MATCH
698			} },
699
700	{ local_apic_kills_bios, "Dell Latitude", {
701			MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"),
702			MATCH(DMI_PRODUCT_NAME, "Latitude"),
703			NO_MATCH, NO_MATCH
704			} },
705
706	{ local_apic_kills_bios, "IBM Thinkpad T20", {
707			MATCH(DMI_BOARD_VENDOR, "IBM"),
708			MATCH(DMI_BOARD_NAME, "264741U"),
709			NO_MATCH, NO_MATCH
710			} },
711
712	{ apm_kills_local_apic, "Microstar 6163", {
713			MATCH(DMI_BOARD_VENDOR, "MICRO-STAR INTERNATIONAL CO., LTD"),
714			MATCH(DMI_BOARD_NAME, "MS-6163"),
715			NO_MATCH, NO_MATCH } },
716
717	{ apm_kills_local_apic_timer, "Intel AL440LX", {
718			MATCH(DMI_BOARD_VENDOR, "Intel Corporation"),
719			MATCH(DMI_BOARD_NAME, "AL440LX"),
720			NO_MATCH, NO_MATCH } },
721
722	/* Problem Intel 440GX bioses */
723
724	{ broken_pirq, "SABR1 Bios", {			/* Bad $PIR */
725			MATCH(DMI_BIOS_VENDOR, "Intel Corporation"),
726			MATCH(DMI_BIOS_VERSION,"SABR1"),
727			NO_MATCH, NO_MATCH
728			} },
729	{ broken_pirq, "l44GX Bios", {        		/* Bad $PIR */
730			MATCH(DMI_BIOS_VENDOR, "Intel Corporation"),
731			MATCH(DMI_BIOS_VERSION,"L440GX0.86B.0094.P10"),
732			NO_MATCH, NO_MATCH
733                        } },
734	{ broken_pirq, "l44GX Bios", {        		/* Bad $PIR */
735			MATCH(DMI_BIOS_VENDOR, "Intel Corporation"),
736			MATCH(DMI_BIOS_VERSION,"L440GX0.86B.0120.P12"),
737			NO_MATCH, NO_MATCH
738                        } },
739	{ broken_pirq, "l44GX Bios", {		/* Bad $PIR */
740			MATCH(DMI_BIOS_VENDOR, "Intel Corporation"),
741			MATCH(DMI_BIOS_VERSION,"L440GX0.86B.0125.P13"),
742			NO_MATCH, NO_MATCH
743			} },
744	{ broken_pirq, "l44GX Bios", {		/* Bad $PIR */
745			MATCH(DMI_BIOS_VENDOR, "Intel Corporation"),
746			MATCH(DMI_BIOS_VERSION,"L440GX0.86B.0066.P07.9906041405"),
747			NO_MATCH, NO_MATCH
748			} },
749
750	/* Intel in disgiuse - In this case they can't hide and they don't run
751	   too well either... */
752	{ broken_pirq, "Dell PowerEdge 8450", {		/* Bad $PIR */
753			MATCH(DMI_PRODUCT_NAME, "Dell PowerEdge 8450"),
754			NO_MATCH, NO_MATCH, NO_MATCH
755			} },
756
757	{ broken_acpi_Sx, "ASUS K7V-RM", {		/* Bad ACPI Sx table */
758			MATCH(DMI_BIOS_VERSION,"ASUS K7V-RM ACPI BIOS Revision 1003A"),
759			MATCH(DMI_BOARD_NAME, "<K7V-RM>"),
760			NO_MATCH, NO_MATCH
761			} },
762
763	{ broken_toshiba_keyboard, "Toshiba Satellite 4030cdt", { /* Keyboard generates spurious repeats */
764			MATCH(DMI_PRODUCT_NAME, "S4030CDT/4.3"),
765			NO_MATCH, NO_MATCH, NO_MATCH
766			} },
767	{ init_ints_after_s1, "Toshiba Satellite 4030cdt", { /* Reinitialization of 8259 is needed after S1 resume */
768			MATCH(DMI_PRODUCT_NAME, "S4030CDT/4.3"),
769			NO_MATCH, NO_MATCH, NO_MATCH
770			} },
771
772	{ print_if_true, KERN_WARNING "IBM T23 - BIOS 1.03b+ and controller firmware 1.02+ may be needed for Linux APM.", {
773			MATCH(DMI_SYS_VENDOR, "IBM"),
774			MATCH(DMI_BIOS_VERSION, "1AET38WW (1.01b)"),
775			NO_MATCH, NO_MATCH
776			} },
777
778	{ fix_broken_hp_bios_irq9, "HP Pavilion N5400 Series Laptop", {
779			MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
780			MATCH(DMI_BIOS_VERSION, "GE.M1.03"),
781			MATCH(DMI_PRODUCT_VERSION, "HP Pavilion Notebook Model GE"),
782			MATCH(DMI_BOARD_VERSION, "OmniBook N32N-736")
783			} },
784
785
786	/*
787	 *	Generic per vendor APM settings
788	 */
789
790	{ set_apm_ints, "IBM", {	/* Allow interrupts during suspend on IBM laptops */
791			MATCH(DMI_SYS_VENDOR, "IBM"),
792			NO_MATCH, NO_MATCH, NO_MATCH
793			} },
794
795	{ NULL, }
796};
797
798
799/*
800 *	Walk the blacklist table running matching functions until someone
801 *	returns 1 or we hit the end.
802 */
803
804static __init void dmi_check_blacklist(void)
805{
806	struct dmi_blacklist *d;
807	int i;
808
809	d=&dmi_blacklist[0];
810	while(d->callback)
811	{
812		for(i=0;i<4;i++)
813		{
814			int s = d->matches[i].slot;
815			if(s==NONE)
816				continue;
817			if(dmi_ident[s] && strstr(dmi_ident[s], d->matches[i].substr))
818				continue;
819			/* No match */
820			goto fail;
821		}
822		if(d->callback(d))
823			return;
824fail:
825		d++;
826	}
827}
828
829
830
831/*
832 *	Process a DMI table entry. Right now all we care about are the BIOS
833 *	and machine entries. For 2.5 we should pull the smbus controller info
834 *	out of here.
835 */
836
837static void __init dmi_decode(struct dmi_header *dm)
838{
839	u8 *data = (u8 *)dm;
840
841	switch(dm->type)
842	{
843		case  0:
844			dmi_printk(("BIOS Vendor: %s\n",
845				dmi_string(dm, data[4])));
846			dmi_save_ident(dm, DMI_BIOS_VENDOR, 4);
847			dmi_printk(("BIOS Version: %s\n",
848				dmi_string(dm, data[5])));
849			dmi_save_ident(dm, DMI_BIOS_VERSION, 5);
850			dmi_printk(("BIOS Release: %s\n",
851				dmi_string(dm, data[8])));
852			dmi_save_ident(dm, DMI_BIOS_DATE, 8);
853			break;
854		case 1:
855			dmi_printk(("System Vendor: %s\n",
856				dmi_string(dm, data[4])));
857			dmi_save_ident(dm, DMI_SYS_VENDOR, 4);
858			dmi_printk(("Product Name: %s\n",
859				dmi_string(dm, data[5])));
860			dmi_save_ident(dm, DMI_PRODUCT_NAME, 5);
861			dmi_printk(("Version: %s\n",
862				dmi_string(dm, data[6])));
863			dmi_save_ident(dm, DMI_PRODUCT_VERSION, 6);
864			dmi_printk(("Serial Number: %s\n",
865				dmi_string(dm, data[7])));
866			break;
867		case 2:
868			dmi_printk(("Board Vendor: %s\n",
869				dmi_string(dm, data[4])));
870			dmi_save_ident(dm, DMI_BOARD_VENDOR, 4);
871			dmi_printk(("Board Name: %s\n",
872				dmi_string(dm, data[5])));
873			dmi_save_ident(dm, DMI_BOARD_NAME, 5);
874			dmi_printk(("Board Version: %s\n",
875				dmi_string(dm, data[6])));
876			dmi_save_ident(dm, DMI_BOARD_VERSION, 6);
877			break;
878	}
879}
880
881void __init dmi_scan_machine(void)
882{
883	int err = dmi_iterate(dmi_decode);
884	if(err == 0)
885		dmi_check_blacklist();
886}
887