v2.4.8 -> v2.4.8.1
[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
10 struct dmi_header
11 {
12         u8      type;
13         u8      length;
14         u16     handle;
15 };
16
17 #define dmi_printk(x)
18 //#define dmi_printk(x) printk x
19
20 static char * __init dmi_string(struct dmi_header *dm, u8 s)
21 {
22         u8 *bp=(u8 *)dm;
23         bp+=dm->length;
24         if(!s)
25                 return "";
26         s--;
27         while(s>0)
28         {
29                 bp+=strlen(bp);
30                 bp++;
31                 s--;
32         }
33         return bp;
34 }
35
36 /*
37  *      We have to be cautious here. We have seen BIOSes with DMI pointers
38  *      pointing to completely the wrong place for example
39  */
40  
41 static int __init dmi_table(u32 base, int len, int num, void (*decode)(struct dmi_header *))
42 {
43         u8 *buf;
44         struct dmi_header *dm;
45         u8 *data;
46         int i=1;
47                 
48         buf = ioremap(base, len);
49         if(buf==NULL)
50                 return -1;
51
52         data = buf;
53
54         /*
55          *      Stop when we see al the items the table claimed to have
56          *      OR we run off the end of the table (also happens)
57          */
58  
59         while(i<num && (data - buf) < len)
60         {
61                 dm=(struct dmi_header *)data;
62         
63                 /*
64                  *      Avoid misparsing crud if the length of the last
65                  *      record is crap 
66                  */
67                 if((data-buf+dm->length) >= len)
68                         break;
69                 decode(dm);             
70                 data+=dm->length;
71                 /*
72                  *      Don't go off the end of the data if there is
73                  *      stuff looking like string fill past the end
74                  */
75                 while((data-buf) < len && (*data || data[1]))
76                         data++;
77                 data+=2;
78                 i++;
79         }
80         iounmap(buf);
81         return 0;
82 }
83
84
85 int __init dmi_iterate(void (*decode)(struct dmi_header *))
86 {
87         unsigned char buf[20];
88         long fp=0xE0000L;
89         fp -= 16;
90         
91         while( fp < 0xFFFFF)
92         {
93                 fp+=16;
94                 isa_memcpy_fromio(buf, fp, 20);
95                 if(memcmp(buf, "_DMI_", 5)==0)
96                 {
97                         u16 num=buf[13]<<8|buf[12];
98                         u16 len=buf[7]<<8|buf[6];
99                         u32 base=buf[11]<<24|buf[10]<<16|buf[9]<<8|buf[8];
100
101                         dmi_printk((KERN_INFO "DMI %d.%d present.\n",
102                                 buf[14]>>4, buf[14]&0x0F));
103                         dmi_printk((KERN_INFO "%d structures occupying %d bytes.\n",
104                                 buf[13]<<8|buf[12],
105                                 buf[7]<<8|buf[6]));
106                         dmi_printk((KERN_INFO "DMI table at 0x%08X.\n",
107                                 buf[11]<<24|buf[10]<<16|buf[9]<<8|buf[8]));
108                         if(dmi_table(base,len, num, decode)==0)
109                                 return 0;
110                 }
111         }
112         return -1;
113 }
114
115
116 enum
117 {
118         DMI_BIOS_VENDOR,
119         DMI_BIOS_VERSION,
120         DMI_BIOS_DATE,
121         DMI_SYS_VENDOR,
122         DMI_PRODUCT_NAME,
123         DMI_PRODUCT_VERSION,
124         DMI_BOARD_VENDOR,
125         DMI_BOARD_NAME,
126         DMI_BOARD_VERSION,
127         DMI_STRING_MAX
128 };
129
130 static char *dmi_ident[DMI_STRING_MAX];
131
132 /*
133  *      Save a DMI string
134  */
135  
136 static void __init dmi_save_ident(struct dmi_header *dm, int slot, int string)
137 {
138         char *d = (char*)dm;
139         char *p = dmi_string(dm, d[string]);
140         if(p==NULL || *p == 0)
141                 return;
142         if (dmi_ident[slot])
143                 return;
144         dmi_ident[slot] = kmalloc(strlen(p)+1, GFP_KERNEL);
145         if(dmi_ident[slot])
146                 strcpy(dmi_ident[slot], p);
147         else
148                 printk(KERN_ERR "dmi_save_ident: out of memory.\n");
149 }
150
151 /*
152  *      DMI callbacks for problem boards
153  */
154
155 struct dmi_strmatch
156 {
157         u8 slot;
158         char *substr;
159 };
160
161 #define NONE    255
162
163 struct dmi_blacklist
164 {
165         int (*callback)(struct dmi_blacklist *);
166         char *ident;
167         struct dmi_strmatch matches[4];
168 };
169
170 #define NO_MATCH        { NONE, NULL}
171 #define MATCH(a,b)      { a, b }
172
173 /*
174  *      We have problems with IDE DMA on some platforms. In paticular the
175  *      KT7 series. On these it seems the newer BIOS has fixed them. The
176  *      rule needs to be improved to match specific BIOS revisions with
177  *      corruption problems
178  */ 
179  
180 static __init int disable_ide_dma(struct dmi_blacklist *d)
181 {
182 #ifdef CONFIG_BLK_DEV_IDE
183         extern int noautodma;
184         if(noautodma == 0)
185         {
186                 noautodma = 1;
187                 printk(KERN_INFO "%s series board detected. Disabling IDE DMA.\n", d->ident);
188         }
189 #endif  
190         return 0;
191 }
192
193 /* 
194  * Some machines require the "reboot=b"  commandline option, this quirk makes that automatic.
195  */
196 static __init int set_bios_reboot(struct dmi_blacklist *d)
197 {
198         extern int reboot_thru_bios;
199         if (reboot_thru_bios == 0)
200         {
201                 reboot_thru_bios = 1;
202                 printk(KERN_INFO "%s series board detected. Selecting BIOS-method for reboots.\n", d->ident);
203         }
204         return 0;
205 }
206
207 /*
208  * Some bioses have a broken protected mode poweroff and need to use realmode
209  */
210
211 static __init int set_realmode_power_off(struct dmi_blacklist *d)
212 {
213        if (apm_info.realmode_power_off == 0)
214        {
215                apm_info.realmode_power_off = 1;
216                printk(KERN_INFO "%s bios detected. Using realmode poweroff only.\n", d->ident);
217        }
218        return 0;
219 }
220
221
222 /* 
223  * Some laptops require interrupts to be enabled during APM calls 
224  */
225
226 static __init int set_apm_ints(struct dmi_blacklist *d)
227 {
228         if (apm_info.allow_ints == 0)
229         {
230                 apm_info.allow_ints = 1;
231                 printk(KERN_INFO "%s machine detected. Enabling interrupts during APM calls.\n", d->ident);
232         }
233         return 0;
234 }
235
236 /* 
237  * Some APM bioses corrupt memory or just plain do not work
238  */
239
240 static __init int apm_is_horked(struct dmi_blacklist *d)
241 {
242         if (apm_info.disabled == 0)
243         {
244                 apm_info.disabled = 1;
245                 printk(KERN_INFO "%s machine detected. Disabling APM.\n", d->ident);
246         }
247         return 0;
248 }
249
250
251 /*
252  *  Check for clue free BIOS implementations who use
253  *  the following QA technique
254  *
255  *      [ Write BIOS Code ]<------
256  *               |                ^
257  *      < Does it Compile >----N--
258  *               |Y               ^
259  *      < Does it Boot Win98 >-N--
260  *               |Y
261  *           [Ship It]
262  *
263  *      Phoenix A04  08/24/2000 is known bad (Dell Inspiron 5000e)
264  *      Phoenix A07  09/29/2000 is known good (Dell Inspiron 5000)
265  */
266
267 static __init int broken_apm_power(struct dmi_blacklist *d)
268 {
269         apm_info.get_power_status_broken = 1;
270         printk(KERN_WARNING "BIOS strings suggest APM bugs, disabling power status reporting.\n");
271         return 0;
272 }               
273
274 /*
275  *      Process the DMI blacklists
276  */
277  
278
279 /*
280  *      This will be expanded over time to force things like the APM 
281  *      interrupt mask settings according to the laptop
282  */
283  
284 static __initdata struct dmi_blacklist dmi_blacklist[]={
285 #if 0
286         { disable_ide_dma, "KT7", {     /* Overbroad right now - kill DMA on problem KT7 boards */
287                         MATCH(DMI_PRODUCT_NAME, "KT7-RAID"),
288                         NO_MATCH, NO_MATCH, NO_MATCH
289                         } },
290 #endif                  
291         { broken_apm_power, "Dell Inspiron 5000e", {    /* Handle problems with APM on Inspiron 5000e */
292                         MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"),
293                         MATCH(DMI_BIOS_VERSION, "A04"),
294                         MATCH(DMI_BIOS_DATE, "08/24/2000"), NO_MATCH
295                         } },
296         { set_realmode_power_off, "Award Software v4.60 PGMA", {        /* broken PM poweroff bios */
297                         MATCH(DMI_BIOS_VENDOR, "Award Software International, Inc."),
298                         MATCH(DMI_BIOS_VERSION, "4.60 PGMA"),
299                         MATCH(DMI_BIOS_DATE, "134526184"), NO_MATCH
300                         } },
301         { set_bios_reboot, "PowerEdge 1300/500", {      /* Handle problems with rebooting on Dell 1300's */
302                         MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"),
303                         MATCH(DMI_PRODUCT_NAME, "PowerEdge 1300/500"),
304                         NO_MATCH, NO_MATCH
305                         } },
306         { set_bios_reboot, "PowerEdge 1300/550", {      /* Handle problems with rebooting on Dell 1300's */
307                         MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"),
308                         MATCH(DMI_PRODUCT_NAME, "PowerEdge 1300/550"),
309                         NO_MATCH, NO_MATCH
310                         } },
311         { set_apm_ints, "IBM", {        /* Allow interrupts during suspend on IBM laptops */
312                         MATCH(DMI_SYS_VENDOR, "IBM"),
313                         NO_MATCH, NO_MATCH, NO_MATCH
314                         } },
315         { set_apm_ints, "ASUSTeK", {   /* Allow interrupts during APM or the clock goes slow */
316                         MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."),
317                         MATCH(DMI_PRODUCT_NAME, "L8400K series Notebook PC"),
318                         NO_MATCH, NO_MATCH
319                         } },                                    
320         { apm_is_horked, "Trigem Delhi3", { /* APM crashes */
321                         MATCH(DMI_SYS_VENDOR, "TriGem Computer, Inc"),
322                         MATCH(DMI_PRODUCT_NAME, "Delhi3"),
323                         NO_MATCH, NO_MATCH,
324                         } },
325         { NULL, }
326 };
327         
328         
329 /*
330  *      Walk the blacklist table running matching functions until someone 
331  *      returns 1 or we hit the end.
332  */
333  
334 static __init void dmi_check_blacklist(void)
335 {
336         struct dmi_blacklist *d;
337         int i;
338                 
339         d=&dmi_blacklist[0];
340         while(d->callback)
341         {
342                 for(i=0;i<4;i++)
343                 {
344                         int s = d->matches[i].slot;
345                         if(s==NONE)
346                                 continue;
347                         if(dmi_ident[s] && strstr(dmi_ident[s], d->matches[i].substr))
348                                 continue;
349                         /* No match */
350                         goto fail;
351                 }
352                 if(d->callback(d))
353                         return;
354 fail:                   
355                 d++;
356         }
357 }
358
359         
360
361 /*
362  *      Process a DMI table entry. Right now all we care about are the BIOS
363  *      and machine entries. For 2.5 we should pull the smbus controller info
364  *      out of here.
365  */
366
367 static void __init dmi_decode(struct dmi_header *dm)
368 {
369         u8 *data = (u8 *)dm;
370         char *p;
371         
372         switch(dm->type)
373         {
374                 case  0:
375                         p=dmi_string(dm,data[4]);
376                         if(*p)
377                         {
378                                 dmi_printk(("BIOS Vendor: %s\n", p));
379                                 dmi_save_ident(dm, DMI_BIOS_VENDOR, 4);
380                                 dmi_printk(("BIOS Version: %s\n", 
381                                         dmi_string(dm, data[5])));
382                                 dmi_save_ident(dm, DMI_BIOS_VERSION, 5);
383                                 dmi_printk(("BIOS Release: %s\n",
384                                         dmi_string(dm, data[8])));
385                                 dmi_save_ident(dm, DMI_BIOS_DATE, 8);
386                         }
387                         break;
388                         
389                 case 1:
390                         p=dmi_string(dm,data[4]);
391                         if(*p)
392                         {
393                                 dmi_printk(("System Vendor: %s.\n",p));
394                                 dmi_save_ident(dm, DMI_SYS_VENDOR, 4);
395                                 dmi_printk(("Product Name: %s.\n",
396                                         dmi_string(dm, data[5])));
397                                 dmi_save_ident(dm, DMI_PRODUCT_NAME, 5);
398                                 dmi_printk(("Version %s.\n",
399                                         dmi_string(dm, data[6])));
400                                 dmi_save_ident(dm, DMI_PRODUCT_VERSION, 6);
401                                 dmi_printk(("Serial Number %s.\n",
402                                         dmi_string(dm, data[7])));
403                         }
404                         break;
405                 case 2:
406                         p=dmi_string(dm,data[4]);
407                         if(*p)
408                         {
409                                 dmi_printk(("Board Vendor: %s.\n",p));
410                                 dmi_save_ident(dm, DMI_BOARD_VENDOR, 4);
411                                 dmi_printk(("Board Name: %s.\n",
412                                         dmi_string(dm, data[5])));
413                                 dmi_save_ident(dm, DMI_BOARD_NAME, 5);
414                                 dmi_printk(("Board Version: %s.\n",
415                                         dmi_string(dm, data[6])));
416                                 dmi_save_ident(dm, DMI_BOARD_VERSION, 6);
417                         }
418                         break;
419                 case 3:
420                         p=dmi_string(dm,data[8]);
421                         if(*p && *p!=' ')
422                                 dmi_printk(("Asset Tag: %s.\n", p));
423                         break;
424         }
425 }
426
427 static int __init dmi_scan_machine(void)
428 {
429         int err = dmi_iterate(dmi_decode);
430         if(err == 0)
431                 dmi_check_blacklist();
432         return err;
433 }
434
435 module_init(dmi_scan_machine);