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