File: /usr/src/linux/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 <linux/keyboard.h>
11 #include <asm/keyboard.h>
12
13 struct dmi_header
14 {
15 u8 type;
16 u8 length;
17 u16 handle;
18 };
19
20 #define dmi_printk(x)
21 //#define dmi_printk(x) printk x
22
23 static char * __init dmi_string(struct dmi_header *dm, u8 s)
24 {
25 u8 *bp=(u8 *)dm;
26 bp+=dm->length;
27 if(!s)
28 return "";
29 s--;
30 while(s>0)
31 {
32 bp+=strlen(bp);
33 bp++;
34 s--;
35 }
36 return bp;
37 }
38
39 /*
40 * We have to be cautious here. We have seen BIOSes with DMI pointers
41 * pointing to completely the wrong place for example
42 */
43
44 static int __init dmi_table(u32 base, int len, int num, void (*decode)(struct dmi_header *))
45 {
46 u8 *buf;
47 struct dmi_header *dm;
48 u8 *data;
49 int i=1;
50
51 buf = ioremap(base, len);
52 if(buf==NULL)
53 return -1;
54
55 data = buf;
56
57 /*
58 * Stop when we see al the items the table claimed to have
59 * OR we run off the end of the table (also happens)
60 */
61
62 while(i<num && (data - buf) < len)
63 {
64 dm=(struct dmi_header *)data;
65
66 /*
67 * Avoid misparsing crud if the length of the last
68 * record is crap
69 */
70 if((data-buf+dm->length) >= len)
71 break;
72 decode(dm);
73 data+=dm->length;
74 /*
75 * Don't go off the end of the data if there is
76 * stuff looking like string fill past the end
77 */
78 while((data-buf) < len && (*data || data[1]))
79 data++;
80 data+=2;
81 i++;
82 }
83 iounmap(buf);
84 return 0;
85 }
86
87
88 int __init dmi_iterate(void (*decode)(struct dmi_header *))
89 {
90 unsigned char buf[20];
91 long fp=0xE0000L;
92 fp -= 16;
93
94 #ifdef CONFIG_SIMNOW
95 /*
96 * Skip on x86/64 with simnow. Will eventually go away
97 * If you see this ifdef in 2.6pre mail me !
98 */
99 return;
100 #endif
101
102 while( fp < 0xFFFFF)
103 {
104 fp+=16;
105 isa_memcpy_fromio(buf, fp, 20);
106 if(memcmp(buf, "_DMI_", 5)==0)
107 {
108 u16 num=buf[13]<<8|buf[12];
109 u16 len=buf[7]<<8|buf[6];
110 u32 base=buf[11]<<24|buf[10]<<16|buf[9]<<8|buf[8];
111
112 dmi_printk((KERN_INFO "DMI %d.%d present.\n",
113 buf[14]>>4, buf[14]&0x0F));
114 dmi_printk((KERN_INFO "%d structures occupying %d bytes.\n",
115 buf[13]<<8|buf[12],
116 buf[7]<<8|buf[6]));
117 dmi_printk((KERN_INFO "DMI table at 0x%08X.\n",
118 buf[11]<<24|buf[10]<<16|buf[9]<<8|buf[8]));
119 if(dmi_table(base,len, num, decode)==0)
120 return 0;
121 }
122 }
123 return -1;
124 }
125
126
127 enum
128 {
129 DMI_BIOS_VENDOR,
130 DMI_BIOS_VERSION,
131 DMI_BIOS_DATE,
132 DMI_SYS_VENDOR,
133 DMI_PRODUCT_NAME,
134 DMI_PRODUCT_VERSION,
135 DMI_BOARD_VENDOR,
136 DMI_BOARD_NAME,
137 DMI_BOARD_VERSION,
138 DMI_STRING_MAX
139 };
140
141 static char *dmi_ident[DMI_STRING_MAX];
142
143 /*
144 * Save a DMI string
145 */
146
147 static void __init dmi_save_ident(struct dmi_header *dm, int slot, int string)
148 {
149 char *d = (char*)dm;
150 char *p = dmi_string(dm, d[string]);
151 if(p==NULL || *p == 0)
152 return;
153 if (dmi_ident[slot])
154 return;
155 dmi_ident[slot] = kmalloc(strlen(p)+1, GFP_KERNEL);
156 if(dmi_ident[slot])
157 strcpy(dmi_ident[slot], p);
158 else
159 printk(KERN_ERR "dmi_save_ident: out of memory.\n");
160 }
161
162 /*
163 * DMI callbacks for problem boards
164 */
165
166 struct dmi_strmatch
167 {
168 u8 slot;
169 char *substr;
170 };
171
172 #define NONE 255
173
174 struct dmi_blacklist
175 {
176 int (*callback)(struct dmi_blacklist *);
177 char *ident;
178 struct dmi_strmatch matches[4];
179 };
180
181 #define NO_MATCH { NONE, NULL}
182 #define MATCH(a,b) { a, b }
183
184 /*
185 * We have problems with IDE DMA on some platforms. In paticular the
186 * KT7 series. On these it seems the newer BIOS has fixed them. The
187 * rule needs to be improved to match specific BIOS revisions with
188 * corruption problems
189 */
190
191 static __init int disable_ide_dma(struct dmi_blacklist *d)
192 {
193 #ifdef CONFIG_BLK_DEV_IDE
194 extern int noautodma;
195 if(noautodma == 0)
196 {
197 noautodma = 1;
198 printk(KERN_INFO "%s series board detected. Disabling IDE DMA.\n", d->ident);
199 }
200 #endif
201 return 0;
202 }
203
204 /*
205 * Reboot options and system auto-detection code provided by
206 * Dell Computer Corporation so their systems "just work". :-)
207 */
208
209 /*
210 * Some machines require the "reboot=b" commandline option, this quirk makes that automatic.
211 */
212 static __init int set_bios_reboot(struct dmi_blacklist *d)
213 {
214 extern int reboot_thru_bios;
215 if (reboot_thru_bios == 0)
216 {
217 reboot_thru_bios = 1;
218 printk(KERN_INFO "%s series board detected. Selecting BIOS-method for reboots.\n", d->ident);
219 }
220 return 0;
221 }
222
223 /*
224 * Some machines require the "reboot=s" commandline option, this quirk makes that automatic.
225 */
226 static __init int set_smp_reboot(struct dmi_blacklist *d)
227 {
228 #ifdef CONFIG_SMP
229 extern int reboot_smp;
230 if (reboot_smp == 0)
231 {
232 reboot_smp = 1;
233 printk(KERN_INFO "%s series board detected. Selecting SMP-method for reboots.\n", d->ident);
234 }
235 #endif
236 return 0;
237 }
238
239 /*
240 * Some machines require the "reboot=b,s" commandline option, this quirk makes that automatic.
241 */
242 static __init int set_smp_bios_reboot(struct dmi_blacklist *d)
243 {
244 set_smp_reboot(d);
245 set_bios_reboot(d);
246 return 0;
247 }
248
249 /*
250 * Some bioses have a broken protected mode poweroff and need to use realmode
251 */
252
253 static __init int set_realmode_power_off(struct dmi_blacklist *d)
254 {
255 if (apm_info.realmode_power_off == 0)
256 {
257 apm_info.realmode_power_off = 1;
258 printk(KERN_INFO "%s bios detected. Using realmode poweroff only.\n", d->ident);
259 }
260 return 0;
261 }
262
263
264 /*
265 * Some laptops require interrupts to be enabled during APM calls
266 */
267
268 static __init int set_apm_ints(struct dmi_blacklist *d)
269 {
270 if (apm_info.allow_ints == 0)
271 {
272 apm_info.allow_ints = 1;
273 printk(KERN_INFO "%s machine detected. Enabling interrupts during APM calls.\n", d->ident);
274 }
275 return 0;
276 }
277
278 /*
279 * Some APM bioses corrupt memory or just plain do not work
280 */
281
282 static __init int apm_is_horked(struct dmi_blacklist *d)
283 {
284 if (apm_info.disabled == 0)
285 {
286 apm_info.disabled = 1;
287 printk(KERN_INFO "%s machine detected. Disabling APM.\n", d->ident);
288 }
289 return 0;
290 }
291
292
293 /*
294 * Check for clue free BIOS implementations who use
295 * the following QA technique
296 *
297 * [ Write BIOS Code ]<------
298 * | ^
299 * < Does it Compile >----N--
300 * |Y ^
301 * < Does it Boot Win98 >-N--
302 * |Y
303 * [Ship It]
304 *
305 * Phoenix A04 08/24/2000 is known bad (Dell Inspiron 5000e)
306 * Phoenix A07 09/29/2000 is known good (Dell Inspiron 5000)
307 */
308
309 static __init int broken_apm_power(struct dmi_blacklist *d)
310 {
311 apm_info.get_power_status_broken = 1;
312 printk(KERN_WARNING "BIOS strings suggest APM bugs, disabling power status reporting.\n");
313 return 0;
314 }
315
316 #if defined(CONFIG_SONYPI) || defined(CONFIG_SONYPI_MODULE)
317 /*
318 * Check for a Sony Vaio system in order to enable the use of
319 * the sonypi driver (we don't want this driver to be used on
320 * other systems, even if they have the good PCI IDs).
321 *
322 * This one isn't a bug detect for those who asked, we simply want to
323 * activate Sony specific goodies like the camera and jogdial..
324 */
325 int is_sony_vaio_laptop;
326
327 static __init int sony_vaio_laptop(struct dmi_blacklist *d)
328 {
329 if (is_sony_vaio_laptop == 0)
330 {
331 is_sony_vaio_laptop = 1;
332 printk(KERN_INFO "%s laptop detected.\n", d->ident);
333 }
334 return 0;
335 }
336 #endif
337
338 /*
339 * This bios swaps the APM minute reporting bytes over (Many sony laptops
340 * have this problem).
341 */
342
343 static __init int swab_apm_power_in_minutes(struct dmi_blacklist *d)
344 {
345 apm_info.get_power_status_swabinminutes = 1;
346 printk(KERN_WARNING "BIOS strings suggest APM reports battery life in minutes and wrong byte order.\n");
347 return 0;
348 }
349
350 /*
351 * The Intel 440GX hall of shame.
352 *
353 * On many (all we have checked) of these boxes the $PIRQ table is wrong.
354 * The MP1.4 table is right however and so SMP kernels tend to work.
355 */
356
357 static __init int broken_pirq(struct dmi_blacklist *d)
358 {
359 printk(KERN_INFO " *** Possibly defective BIOS detected (irqtable)\n");
360 printk(KERN_INFO " *** Many BIOSes matching this signature have incorrect IRQ routing tables.\n");
361 printk(KERN_INFO " *** If you see IRQ problems, in paticular SCSI resets and hangs at boot\n");
362 printk(KERN_INFO " *** contact your vendor and ask about updates.\n");
363 printk(KERN_INFO " *** Building an SMP kernel may evade the bug some of the time.\n");
364 return 0;
365 }
366
367 /*
368 * Some Bioses enable the PS/2 mouse (touchpad) at resume, even if it
369 * was disabled before the suspend. Linux gets terribly confused by that.
370 */
371
372 typedef void (pm_kbd_func) (void);
373 extern pm_kbd_func *pm_kbd_request_override;
374
375 static __init int broken_ps2_resume(struct dmi_blacklist *d)
376 {
377 #ifdef CONFIG_VT
378 if (pm_kbd_request_override == NULL)
379 {
380 pm_kbd_request_override = pckbd_pm_resume;
381 printk(KERN_INFO "%s machine detected. Mousepad Resume Bug workaround enabled.\n", d->ident);
382 }
383 #endif
384 return 0;
385 }
386
387
388
389 /*
390 * Process the DMI blacklists
391 */
392
393
394 /*
395 * This will be expanded over time to force things like the APM
396 * interrupt mask settings according to the laptop
397 */
398
399 static __initdata struct dmi_blacklist dmi_blacklist[]={
400 #if 0
401 { disable_ide_dma, "KT7", { /* Overbroad right now - kill DMA on problem KT7 boards */
402 MATCH(DMI_PRODUCT_NAME, "KT7-RAID"),
403 NO_MATCH, NO_MATCH, NO_MATCH
404 } },
405 #endif
406 { broken_ps2_resume, "Dell Latitude C600", { /* Handle problems with APM on the C600 */
407 MATCH(DMI_SYS_VENDOR, "Dell"),
408 MATCH(DMI_PRODUCT_NAME, "Latitude C600"),
409 NO_MATCH, NO_MATCH
410 } },
411 { broken_apm_power, "Dell Inspiron 5000e", { /* Handle problems with APM on Inspiron 5000e */
412 MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"),
413 MATCH(DMI_BIOS_VERSION, "A04"),
414 MATCH(DMI_BIOS_DATE, "08/24/2000"), NO_MATCH
415 } },
416 { set_realmode_power_off, "Award Software v4.60 PGMA", { /* broken PM poweroff bios */
417 MATCH(DMI_BIOS_VENDOR, "Award Software International, Inc."),
418 MATCH(DMI_BIOS_VERSION, "4.60 PGMA"),
419 MATCH(DMI_BIOS_DATE, "134526184"), NO_MATCH
420 } },
421 { set_smp_bios_reboot, "Dell PowerEdge 1300", { /* Handle problems with rebooting on Dell 1300's */
422 MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"),
423 MATCH(DMI_PRODUCT_NAME, "PowerEdge 1300/"),
424 NO_MATCH, NO_MATCH
425 } },
426 { set_bios_reboot, "Dell PowerEdge 300", { /* Handle problems with rebooting on Dell 1300's */
427 MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"),
428 MATCH(DMI_PRODUCT_NAME, "PowerEdge 300/"),
429 NO_MATCH, NO_MATCH
430 } },
431 { set_apm_ints, "IBM", { /* Allow interrupts during suspend on IBM laptops */
432 MATCH(DMI_SYS_VENDOR, "IBM"),
433 NO_MATCH, NO_MATCH, NO_MATCH
434 } },
435 { set_apm_ints, "Dell Inspiron", { /* Allow interrupts during suspend on Dell Inspiron laptops*/
436 MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"),
437 MATCH(DMI_PRODUCT_NAME, "Inspiron 4000"),
438 NO_MATCH, NO_MATCH
439 } },
440 { set_apm_ints, "Compaq 12XL125", { /* Allow interrupts during suspend on Compaq Laptops*/
441 MATCH(DMI_SYS_VENDOR, "Compaq"),
442 MATCH(DMI_PRODUCT_NAME, "Compaq PC"),
443 MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"),
444 MATCH(DMI_BIOS_VERSION,"4.06")
445 } },
446 { set_apm_ints, "ASUSTeK", { /* Allow interrupts during APM or the clock goes slow */
447 MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."),
448 MATCH(DMI_PRODUCT_NAME, "L8400K series Notebook PC"),
449 NO_MATCH, NO_MATCH
450 } },
451 { apm_is_horked, "Trigem Delhi3", { /* APM crashes */
452 MATCH(DMI_SYS_VENDOR, "TriGem Computer, Inc"),
453 MATCH(DMI_PRODUCT_NAME, "Delhi3"),
454 NO_MATCH, NO_MATCH,
455 } },
456 { apm_is_horked, "Sharp PC-PJ/AX", { /* APM crashes */
457 MATCH(DMI_SYS_VENDOR, "SHARP"),
458 MATCH(DMI_PRODUCT_NAME, "PC-PJ/AX"),
459 MATCH(DMI_BIOS_VENDOR,"SystemSoft"),
460 MATCH(DMI_BIOS_VERSION,"Version R2.08")
461 } },
462 #if defined(CONFIG_SONYPI) || defined(CONFIG_SONYPI_MODULE)
463 { sony_vaio_laptop, "Sony Vaio", { /* This is a Sony Vaio laptop */
464 MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
465 MATCH(DMI_PRODUCT_NAME, "PCG-"),
466 NO_MATCH, NO_MATCH,
467 } },
468 #endif
469 { swab_apm_power_in_minutes, "Sony VAIO", { /* Handle problems with APM on Sony Vaio PCG-N505X(DE) */
470 MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"),
471 MATCH(DMI_BIOS_VERSION, "R0206H"),
472 MATCH(DMI_BIOS_DATE, "08/23/99"), NO_MATCH
473 } },
474
475 { swab_apm_power_in_minutes, "Sony VAIO", { /* Handle problems with APM on Sony Vaio PCG-N505VX */
476 MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"),
477 MATCH(DMI_BIOS_VERSION, "W2K06H0"),
478 MATCH(DMI_BIOS_DATE, "02/03/00"), NO_MATCH
479 } },
480
481 { swab_apm_power_in_minutes, "Sony VAIO", { /* Handle problems with APM on Sony Vaio PCG-XG29 */
482 MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"),
483 MATCH(DMI_BIOS_VERSION, "R0117A0"),
484 MATCH(DMI_BIOS_DATE, "04/25/00"), NO_MATCH
485 } },
486
487 { swab_apm_power_in_minutes, "Sony VAIO", { /* Handle problems with APM on Sony Vaio PCG-Z600NE */
488 MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"),
489 MATCH(DMI_BIOS_VERSION, "R0121Z1"),
490 MATCH(DMI_BIOS_DATE, "05/11/00"), NO_MATCH
491 } },
492
493 { swab_apm_power_in_minutes, "Sony VAIO", { /* Handle problems with APM on Sony Vaio PCG-Z505LS */
494 MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"),
495 MATCH(DMI_BIOS_VERSION, "R0203D0"),
496 MATCH(DMI_BIOS_DATE, "05/12/00"), NO_MATCH
497 } },
498
499 { swab_apm_power_in_minutes, "Sony VAIO", { /* Handle problems with APM on Sony Vaio PCG-Z505LS */
500 MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"),
501 MATCH(DMI_BIOS_VERSION, "R0203Z3"),
502 MATCH(DMI_BIOS_DATE, "08/25/00"), NO_MATCH
503 } },
504
505 { swab_apm_power_in_minutes, "Sony VAIO", { /* Handle problems with APM on Sony Vaio PCG-F104K */
506 MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"),
507 MATCH(DMI_BIOS_VERSION, "R0204K2"),
508 MATCH(DMI_BIOS_DATE, "08/28/00"), NO_MATCH
509 } },
510
511 { swab_apm_power_in_minutes, "Sony VAIO", { /* Handle problems with APM on Sony Vaio PCG-C1VN/C1VE */
512 MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"),
513 MATCH(DMI_BIOS_VERSION, "R0208P1"),
514 MATCH(DMI_BIOS_DATE, "11/09/00"), NO_MATCH
515 } },
516 { swab_apm_power_in_minutes, "Sony VAIO", { /* Handle problems with APM on Sony Vaio PCG-C1VE */
517 MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"),
518 MATCH(DMI_BIOS_VERSION, "R0204P1"),
519 MATCH(DMI_BIOS_DATE, "09/12/00"), NO_MATCH
520 } },
521
522 /* Problem Intel 440GX bioses */
523
524 { broken_pirq, "SABR1 Bios", { /* Bad $PIR */
525 MATCH(DMI_BIOS_VENDOR, "Intel Corporation"),
526 MATCH(DMI_BIOS_VERSION,"SABR1"),
527 NO_MATCH, NO_MATCH
528 } },
529 { broken_pirq, "l44GX Bios", { /* Bad $PIR */
530 MATCH(DMI_BIOS_VENDOR, "Intel Corporation"),
531 MATCH(DMI_BIOS_VERSION,"L440GX0.86B.0094.P10"),
532 NO_MATCH, NO_MATCH
533 } },
534 { broken_pirq, "l44GX Bios", { /* Bad $PIR */
535 MATCH(DMI_BIOS_VENDOR, "Intel Corporation"),
536 MATCH(DMI_BIOS_VERSION,"L440GX0.86B.0125.P13"),
537 NO_MATCH, NO_MATCH
538 } },
539
540 /* Intel in disgiuse - In this case they can't hide and they don't run
541 too well either... */
542 { broken_pirq, "Dell PowerEdge 8450", { /* Bad $PIR */
543 MATCH(DMI_PRODUCT_NAME, "Dell PowerEdge 8450"),
544 NO_MATCH, NO_MATCH, NO_MATCH
545 } },
546
547 { NULL, }
548 };
549
550
551 /*
552 * Walk the blacklist table running matching functions until someone
553 * returns 1 or we hit the end.
554 */
555
556 static __init void dmi_check_blacklist(void)
557 {
558 struct dmi_blacklist *d;
559 int i;
560
561 d=&dmi_blacklist[0];
562 while(d->callback)
563 {
564 for(i=0;i<4;i++)
565 {
566 int s = d->matches[i].slot;
567 if(s==NONE)
568 continue;
569 if(dmi_ident[s] && strstr(dmi_ident[s], d->matches[i].substr))
570 continue;
571 /* No match */
572 goto fail;
573 }
574 if(d->callback(d))
575 return;
576 fail:
577 d++;
578 }
579 }
580
581
582
583 /*
584 * Process a DMI table entry. Right now all we care about are the BIOS
585 * and machine entries. For 2.5 we should pull the smbus controller info
586 * out of here.
587 */
588
589 static void __init dmi_decode(struct dmi_header *dm)
590 {
591 u8 *data = (u8 *)dm;
592 char *p;
593
594 switch(dm->type)
595 {
596 case 0:
597 p=dmi_string(dm,data[4]);
598 if(*p)
599 {
600 dmi_printk(("BIOS Vendor: %s\n", p));
601 dmi_save_ident(dm, DMI_BIOS_VENDOR, 4);
602 dmi_printk(("BIOS Version: %s\n",
603 dmi_string(dm, data[5])));
604 dmi_save_ident(dm, DMI_BIOS_VERSION, 5);
605 dmi_printk(("BIOS Release: %s\n",
606 dmi_string(dm, data[8])));
607 dmi_save_ident(dm, DMI_BIOS_DATE, 8);
608 }
609 break;
610
611 case 1:
612 p=dmi_string(dm,data[4]);
613 if(*p)
614 {
615 dmi_printk(("System Vendor: %s.\n",p));
616 dmi_save_ident(dm, DMI_SYS_VENDOR, 4);
617 dmi_printk(("Product Name: %s.\n",
618 dmi_string(dm, data[5])));
619 dmi_save_ident(dm, DMI_PRODUCT_NAME, 5);
620 dmi_printk(("Version %s.\n",
621 dmi_string(dm, data[6])));
622 dmi_save_ident(dm, DMI_PRODUCT_VERSION, 6);
623 dmi_printk(("Serial Number %s.\n",
624 dmi_string(dm, data[7])));
625 }
626 break;
627 case 2:
628 p=dmi_string(dm,data[4]);
629 if(*p)
630 {
631 dmi_printk(("Board Vendor: %s.\n",p));
632 dmi_save_ident(dm, DMI_BOARD_VENDOR, 4);
633 dmi_printk(("Board Name: %s.\n",
634 dmi_string(dm, data[5])));
635 dmi_save_ident(dm, DMI_BOARD_NAME, 5);
636 dmi_printk(("Board Version: %s.\n",
637 dmi_string(dm, data[6])));
638 dmi_save_ident(dm, DMI_BOARD_VERSION, 6);
639 }
640 break;
641 case 3:
642 p=dmi_string(dm,data[8]);
643 if(*p && *p!=' ')
644 dmi_printk(("Asset Tag: %s.\n", p));
645 break;
646 }
647 }
648
649 static int __init dmi_scan_machine(void)
650 {
651 int err = dmi_iterate(dmi_decode);
652 if(err == 0)
653 dmi_check_blacklist();
654 return err;
655 }
656
657 module_init(dmi_scan_machine);
658