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