VServer 1.9.2 (patch-2.6.8.1-vs1.9.2.diff)
[linux-2.6.git] / arch / i386 / kernel / dmi_scan.c
1 #include <linux/types.h>
2 #include <linux/kernel.h>
3 #include <linux/string.h>
4 #include <linux/init.h>
5 #include <linux/module.h>
6 #include <linux/slab.h>
7 #include <asm/acpi.h>
8 #include <asm/io.h>
9 #include <linux/pm.h>
10 #include <asm/system.h>
11 #include <linux/dmi.h>
12 #include <linux/bootmem.h>
13
14
15 int es7000_plat = 0;
16
17 struct dmi_header
18 {
19         u8      type;
20         u8      length;
21         u16     handle;
22 };
23
24 #undef DMI_DEBUG
25
26 #ifdef DMI_DEBUG
27 #define dmi_printk(x) printk x
28 #else
29 #define dmi_printk(x)
30 #endif
31
32 static char * __init dmi_string(struct dmi_header *dm, u8 s)
33 {
34         u8 *bp=(u8 *)dm;
35         bp+=dm->length;
36         if(!s)
37                 return "";
38         s--;
39         while(s>0 && *bp)
40         {
41                 bp+=strlen(bp);
42                 bp++;
43                 s--;
44         }
45         return bp;
46 }
47
48 /*
49  *      We have to be cautious here. We have seen BIOSes with DMI pointers
50  *      pointing to completely the wrong place for example
51  */
52  
53 static int __init dmi_table(u32 base, int len, int num, void (*decode)(struct dmi_header *))
54 {
55         u8 *buf;
56         struct dmi_header *dm;
57         u8 *data;
58         int i=0;
59                 
60         buf = bt_ioremap(base, len);
61         if(buf==NULL)
62                 return -1;
63
64         data = buf;
65
66         /*
67          *      Stop when we see all the items the table claimed to have
68          *      OR we run off the end of the table (also happens)
69          */
70  
71         while(i<num && data-buf+sizeof(struct dmi_header)<=len)
72         {
73                 dm=(struct dmi_header *)data;
74                 /*
75                  *  We want to know the total length (formated area and strings)
76                  *  before decoding to make sure we won't run off the table in
77                  *  dmi_decode or dmi_string
78                  */
79                 data+=dm->length;
80                 while(data-buf<len-1 && (data[0] || data[1]))
81                         data++;
82                 if(data-buf<len-1)
83                         decode(dm);
84                 data+=2;
85                 i++;
86         }
87         bt_iounmap(buf, len);
88         return 0;
89 }
90
91
92 inline static int __init dmi_checksum(u8 *buf)
93 {
94         u8 sum=0;
95         int a;
96         
97         for(a=0; a<15; a++)
98                 sum+=buf[a];
99         return (sum==0);
100 }
101
102 static int __init dmi_iterate(void (*decode)(struct dmi_header *))
103 {
104         u8 buf[15];
105         u32 fp=0xF0000;
106
107         while (fp < 0xFFFFF)
108         {
109                 isa_memcpy_fromio(buf, fp, 15);
110                 if(memcmp(buf, "_DMI_", 5)==0 && dmi_checksum(buf))
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                         /*
117                          * DMI version 0.0 means that the real version is taken from
118                          * the SMBIOS version, which we don't know at this point.
119                          */
120                         if(buf[14]!=0)
121                                 printk(KERN_INFO "DMI %d.%d present.\n",
122                                         buf[14]>>4, buf[14]&0x0F);
123                         else
124                                 printk(KERN_INFO "DMI present.\n");
125                         dmi_printk((KERN_INFO "%d structures occupying %d bytes.\n",
126                                 num, len));
127                         dmi_printk((KERN_INFO "DMI table at 0x%08X.\n",
128                                 base));
129                         if(dmi_table(base,len, num, decode)==0)
130                                 return 0;
131                 }
132                 fp+=16;
133         }
134         return -1;
135 }
136
137 static char *dmi_ident[DMI_STRING_MAX];
138
139 /*
140  *      Save a DMI string
141  */
142  
143 static void __init dmi_save_ident(struct dmi_header *dm, int slot, int string)
144 {
145         char *d = (char*)dm;
146         char *p = dmi_string(dm, d[string]);
147         if(p==NULL || *p == 0)
148                 return;
149         if (dmi_ident[slot])
150                 return;
151         dmi_ident[slot] = alloc_bootmem(strlen(p)+1);
152         if(dmi_ident[slot])
153                 strcpy(dmi_ident[slot], p);
154         else
155                 printk(KERN_ERR "dmi_save_ident: out of memory.\n");
156 }
157
158 /*
159  * Ugly compatibility crap.
160  */
161 #define dmi_blacklist   dmi_system_id
162 #define NO_MATCH        { DMI_NONE, NULL}
163 #define MATCH           DMI_MATCH
164
165 /*
166  * Some machines, usually laptops, can't handle an enabled local APIC.
167  * The symptoms include hangs or reboots when suspending or resuming,
168  * attaching or detaching the power cord, or entering BIOS setup screens
169  * through magic key sequences.
170  */
171 static int __init local_apic_kills_bios(struct dmi_blacklist *d)
172 {
173 #ifdef CONFIG_X86_LOCAL_APIC
174         extern int enable_local_apic;
175         if (enable_local_apic == 0) {
176                 enable_local_apic = -1;
177                 printk(KERN_WARNING "%s with broken BIOS detected. "
178                        "Refusing to enable the local APIC.\n",
179                        d->ident);
180         }
181 #endif
182         return 0;
183 }
184
185
186 /*
187  * Toshiba keyboard likes to repeat keys when they are not repeated.
188  */
189
190 static __init int broken_toshiba_keyboard(struct dmi_blacklist *d)
191 {
192         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");
193         return 0;
194 }
195
196
197 #ifdef CONFIG_ACPI_SLEEP
198 static __init int reset_videomode_after_s3(struct dmi_blacklist *d)
199 {
200         /* See acpi_wakeup.S */
201         extern long acpi_video_flags;
202         acpi_video_flags |= 2;
203         return 0;
204 }
205 #endif
206
207
208 #ifdef  CONFIG_ACPI_BOOT
209 extern int acpi_force;
210
211 static __init __attribute__((unused)) int dmi_disable_acpi(struct dmi_blacklist *d) 
212
213         if (!acpi_force) { 
214                 printk(KERN_NOTICE "%s detected: acpi off\n",d->ident); 
215                 disable_acpi();
216         } else { 
217                 printk(KERN_NOTICE 
218                        "Warning: DMI blacklist says broken, but acpi forced\n"); 
219         }
220         return 0;
221
222
223 /*
224  * Limit ACPI to CPU enumeration for HT
225  */
226 static __init __attribute__((unused)) int force_acpi_ht(struct dmi_blacklist *d) 
227
228         if (!acpi_force) { 
229                 printk(KERN_NOTICE "%s detected: force use of acpi=ht\n", d->ident); 
230                 disable_acpi();
231                 acpi_ht = 1; 
232         } else { 
233                 printk(KERN_NOTICE 
234                        "Warning: acpi=force overrules DMI blacklist: acpi=ht\n"); 
235         }
236         return 0;
237
238
239 /*
240  * early nForce2 reference BIOS shipped with a
241  * bogus ACPI IRQ0 -> pin2 interrupt override -- ignore it
242  */
243 static __init int ignore_timer_override(struct dmi_blacklist *d)
244 {
245         extern int acpi_skip_timer_override;
246         printk(KERN_NOTICE "%s detected: BIOS IRQ0 pin2 override"
247                 " will be ignored\n", d->ident);        
248
249         acpi_skip_timer_override = 1;
250         return 0;
251 }
252 #endif
253
254 #ifdef  CONFIG_ACPI_PCI
255 static __init int disable_acpi_irq(struct dmi_blacklist *d) 
256 {
257         if (!acpi_force) {
258                 printk(KERN_NOTICE "%s detected: force use of acpi=noirq\n",
259                        d->ident);       
260                 acpi_noirq_set();
261         }
262         return 0;
263 }
264 static __init int disable_acpi_pci(struct dmi_blacklist *d) 
265 {
266         if (!acpi_force) {
267                 printk(KERN_NOTICE "%s detected: force use of pci=noacpi\n",
268                        d->ident);       
269                 acpi_disable_pci();
270         }
271         return 0;
272 }  
273 #endif
274
275 /*
276  *      Process the DMI blacklists
277  */
278  
279
280 /*
281  *      This will be expanded over time to force things like the APM 
282  *      interrupt mask settings according to the laptop
283  */
284  
285 static __initdata struct dmi_blacklist dmi_blacklist[]={
286
287         /* Machines which have problems handling enabled local APICs */
288
289         { local_apic_kills_bios, "Dell Inspiron", {
290                         MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"),
291                         MATCH(DMI_PRODUCT_NAME, "Inspiron"),
292                         NO_MATCH, NO_MATCH
293                         } },
294
295         { local_apic_kills_bios, "Dell Latitude", {
296                         MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"),
297                         MATCH(DMI_PRODUCT_NAME, "Latitude"),
298                         NO_MATCH, NO_MATCH
299                         } },
300
301         { local_apic_kills_bios, "IBM Thinkpad T20", {
302                         MATCH(DMI_BOARD_VENDOR, "IBM"),
303                         MATCH(DMI_BOARD_NAME, "264741U"),
304                         NO_MATCH, NO_MATCH
305                         } },
306
307         { local_apic_kills_bios, "ASUS L3C", {
308                         MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."),
309                         MATCH(DMI_BOARD_NAME, "P4_L3C"),
310                         NO_MATCH, NO_MATCH
311                         } },
312
313         { broken_toshiba_keyboard, "Toshiba Satellite 4030cdt", { /* Keyboard generates spurious repeats */
314                         MATCH(DMI_PRODUCT_NAME, "S4030CDT/4.3"),
315                         NO_MATCH, NO_MATCH, NO_MATCH
316                         } },
317 #ifdef CONFIG_ACPI_SLEEP
318         { reset_videomode_after_s3, "Toshiba Satellite 4030cdt", { /* Reset video mode after returning from ACPI S3 sleep */
319                         MATCH(DMI_PRODUCT_NAME, "S4030CDT/4.3"),
320                         NO_MATCH, NO_MATCH, NO_MATCH
321                         } },
322 #endif
323
324 #ifdef  CONFIG_ACPI_BOOT
325         /*
326          * If your system is blacklisted here, but you find that acpi=force
327          * works for you, please contact acpi-devel@sourceforge.net
328          */
329
330         /*
331          *      Boxes that need ACPI disabled
332          */
333
334         { dmi_disable_acpi, "IBM Thinkpad", {
335                         MATCH(DMI_BOARD_VENDOR, "IBM"),
336                         MATCH(DMI_BOARD_NAME, "2629H1G"),
337                         NO_MATCH, NO_MATCH }},
338
339         /*
340          *      Boxes that need acpi=ht 
341          */
342
343         { force_acpi_ht, "FSC Primergy T850", {
344                         MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
345                         MATCH(DMI_PRODUCT_NAME, "PRIMERGY T850"),
346                         NO_MATCH, NO_MATCH }},
347
348         { force_acpi_ht, "DELL GX240", {
349                         MATCH(DMI_BOARD_VENDOR, "Dell Computer Corporation"),
350                         MATCH(DMI_BOARD_NAME, "OptiPlex GX240"),
351                         NO_MATCH, NO_MATCH }},
352
353         { force_acpi_ht, "HP VISUALIZE NT Workstation", {
354                         MATCH(DMI_BOARD_VENDOR, "Hewlett-Packard"),
355                         MATCH(DMI_PRODUCT_NAME, "HP VISUALIZE NT Workstation"),
356                         NO_MATCH, NO_MATCH }},
357
358         { force_acpi_ht, "Compaq ProLiant DL380 G2", {
359                         MATCH(DMI_SYS_VENDOR, "Compaq"),
360                         MATCH(DMI_PRODUCT_NAME, "ProLiant DL380 G2"),
361                         NO_MATCH, NO_MATCH }},
362
363         { force_acpi_ht, "Compaq ProLiant ML530 G2", {
364                         MATCH(DMI_SYS_VENDOR, "Compaq"),
365                         MATCH(DMI_PRODUCT_NAME, "ProLiant ML530 G2"),
366                         NO_MATCH, NO_MATCH }},
367
368         { force_acpi_ht, "Compaq ProLiant ML350 G3", {
369                         MATCH(DMI_SYS_VENDOR, "Compaq"),
370                         MATCH(DMI_PRODUCT_NAME, "ProLiant ML350 G3"),
371                         NO_MATCH, NO_MATCH }},
372
373         { force_acpi_ht, "Compaq Workstation W8000", {
374                         MATCH(DMI_SYS_VENDOR, "Compaq"),
375                         MATCH(DMI_PRODUCT_NAME, "Workstation W8000"),
376                         NO_MATCH, NO_MATCH }},
377
378         { force_acpi_ht, "ASUS P4B266", {
379                         MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."),
380                         MATCH(DMI_BOARD_NAME, "P4B266"),
381                         NO_MATCH, NO_MATCH }},
382
383         { force_acpi_ht, "ASUS P2B-DS", {
384                         MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."),
385                         MATCH(DMI_BOARD_NAME, "P2B-DS"),
386                         NO_MATCH, NO_MATCH }},
387
388         { force_acpi_ht, "ASUS CUR-DLS", {
389                         MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."),
390                         MATCH(DMI_BOARD_NAME, "CUR-DLS"),
391                         NO_MATCH, NO_MATCH }},
392
393         { force_acpi_ht, "ABIT i440BX-W83977", {
394                         MATCH(DMI_BOARD_VENDOR, "ABIT <http://www.abit.com>"),
395                         MATCH(DMI_BOARD_NAME, "i440BX-W83977 (BP6)"),
396                         NO_MATCH, NO_MATCH }},
397
398         { force_acpi_ht, "IBM Bladecenter", {
399                         MATCH(DMI_BOARD_VENDOR, "IBM"),
400                         MATCH(DMI_BOARD_NAME, "IBM eServer BladeCenter HS20"),
401                         NO_MATCH, NO_MATCH }},
402
403         { force_acpi_ht, "IBM eServer xSeries 360", {
404                         MATCH(DMI_BOARD_VENDOR, "IBM"),
405                         MATCH(DMI_BOARD_NAME, "eServer xSeries 360"),
406                         NO_MATCH, NO_MATCH }},
407
408         { force_acpi_ht, "IBM eserver xSeries 330", {
409                         MATCH(DMI_BOARD_VENDOR, "IBM"),
410                         MATCH(DMI_BOARD_NAME, "eserver xSeries 330"),
411                         NO_MATCH, NO_MATCH }},
412
413         { force_acpi_ht, "IBM eserver xSeries 440", {
414                         MATCH(DMI_BOARD_VENDOR, "IBM"),
415                         MATCH(DMI_PRODUCT_NAME, "eserver xSeries 440"),
416                         NO_MATCH, NO_MATCH }},
417
418         /*
419          * Systems with nForce2 BIOS timer override bug
420          * nVidia claims all nForce have timer on pin0,
421          * and applying this workaround is a NOP on fixed BIOS,
422          * so prospects are good for replacing these entries
423          * with something to key of chipset PCI-ID.
424          */
425         { ignore_timer_override, "Abit NF7-S v2", {
426                         MATCH(DMI_BOARD_VENDOR, "http://www.abit.com.tw/"),
427                         MATCH(DMI_BOARD_NAME, "NF7-S/NF7,NF7-V (nVidia-nForce2)"),
428                         MATCH(DMI_BIOS_VERSION, "6.00 PG"),
429                         MATCH(DMI_BIOS_DATE, "03/24/2004") }},
430
431         { ignore_timer_override, "Asus A7N8X v2", {
432                         MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."),
433                         MATCH(DMI_BOARD_NAME, "A7N8X2.0"),
434                         MATCH(DMI_BIOS_VERSION, "ASUS A7N8X2.0 Deluxe ACPI BIOS Rev 1007"),
435                         MATCH(DMI_BIOS_DATE, "10/06/2003") }},
436
437         { ignore_timer_override, "Asus A7N8X-X", {
438                         MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."),
439                         MATCH(DMI_BOARD_NAME, "A7N8X-X"),
440                         MATCH(DMI_BIOS_VERSION, "ASUS A7N8X-X ACPI BIOS Rev 1009"),
441                         MATCH(DMI_BIOS_DATE, "2/3/2004") }},
442
443         { ignore_timer_override, "MSI K7N2-Delta", {
444                         MATCH(DMI_BOARD_VENDOR, "MICRO-STAR INTERNATIONAL CO., LTD"),
445                         MATCH(DMI_BOARD_NAME, "MS-6570"),
446                         MATCH(DMI_BIOS_VERSION, "6.00 PG"),
447                         MATCH(DMI_BIOS_DATE, "03/29/2004") }},
448
449         { ignore_timer_override, "Shuttle SN41G2", {
450                         MATCH(DMI_BOARD_VENDOR, "Shuttle Inc"),
451                         MATCH(DMI_BOARD_NAME, "FN41"),
452                         MATCH(DMI_BIOS_VERSION, "6.00 PG"),
453                         MATCH(DMI_BIOS_DATE, "01/14/2004") }},
454
455         { ignore_timer_override, "Shuttle AN35N", {
456                         MATCH(DMI_BOARD_VENDOR, "Shuttle Inc"),
457                         MATCH(DMI_BOARD_NAME, "AN35"),
458                         MATCH(DMI_BIOS_VERSION, "6.00 PG"),
459                         MATCH(DMI_BIOS_DATE, "12/05/2003") }},
460 #endif  // CONFIG_ACPI_BOOT
461
462 #ifdef  CONFIG_ACPI_PCI
463         /*
464          *      Boxes that need ACPI PCI IRQ routing disabled
465          */
466
467         { disable_acpi_irq, "ASUS A7V", {
468                         MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC"),
469                         MATCH(DMI_BOARD_NAME, "<A7V>"),
470                         /* newer BIOS, Revision 1011, does work */
471                         MATCH(DMI_BIOS_VERSION, "ASUS A7V ACPI BIOS Revision 1007"),
472                         NO_MATCH }},
473
474         /*
475          *      Boxes that need ACPI PCI IRQ routing and PCI scan disabled
476          */
477         { disable_acpi_pci, "ASUS PR-DLS", {    /* _BBN 0 bug */
478                         MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."),
479                         MATCH(DMI_BOARD_NAME, "PR-DLS"),
480                         MATCH(DMI_BIOS_VERSION, "ASUS PR-DLS ACPI BIOS Revision 1010"),
481                         MATCH(DMI_BIOS_DATE, "03/21/2003") }},
482
483         { disable_acpi_pci, "Acer TravelMate 36x Laptop", {
484                         MATCH(DMI_SYS_VENDOR, "Acer"),
485                         MATCH(DMI_PRODUCT_NAME, "TravelMate 360"),
486                         NO_MATCH, NO_MATCH
487                         } },
488
489 #endif
490
491         { NULL, }
492 };
493         
494         
495 /*
496  *      Walk the blacklist table running matching functions until someone 
497  *      returns 1 or we hit the end.
498  */
499  
500
501 static __init void dmi_check_blacklist(void)
502 {
503 #ifdef  CONFIG_ACPI_BOOT
504 #define ACPI_BLACKLIST_CUTOFF_YEAR      2001
505
506         if (dmi_ident[DMI_BIOS_DATE]) { 
507                 char *s = strrchr(dmi_ident[DMI_BIOS_DATE], '/'); 
508                 if (s) { 
509                         int year, disable = 0;
510                         s++; 
511                         year = simple_strtoul(s,NULL,0); 
512                         if (year >= 1000) 
513                                 disable = year < ACPI_BLACKLIST_CUTOFF_YEAR; 
514                         else if (year < 1 || (year > 90 && year <= 99))
515                                 disable = 1; 
516                         if (disable && !acpi_force) { 
517                                 printk(KERN_NOTICE "ACPI disabled because your bios is from %s and too old\n", s);
518                                 printk(KERN_NOTICE "You can enable it with acpi=force\n");
519                                 disable_acpi();
520                         } 
521                 }
522         }
523 #endif
524         dmi_check_system(dmi_blacklist);
525 }
526
527         
528
529 /*
530  *      Process a DMI table entry. Right now all we care about are the BIOS
531  *      and machine entries. For 2.5 we should pull the smbus controller info
532  *      out of here.
533  */
534
535 static void __init dmi_decode(struct dmi_header *dm)
536 {
537 #ifdef DMI_DEBUG
538         u8 *data = (u8 *)dm;
539 #endif
540         
541         switch(dm->type)
542         {
543                 case  0:
544                         dmi_printk(("BIOS Vendor: %s\n",
545                                 dmi_string(dm, data[4])));
546                         dmi_save_ident(dm, DMI_BIOS_VENDOR, 4);
547                         dmi_printk(("BIOS Version: %s\n", 
548                                 dmi_string(dm, data[5])));
549                         dmi_save_ident(dm, DMI_BIOS_VERSION, 5);
550                         dmi_printk(("BIOS Release: %s\n",
551                                 dmi_string(dm, data[8])));
552                         dmi_save_ident(dm, DMI_BIOS_DATE, 8);
553                         break;
554                 case 1:
555                         dmi_printk(("System Vendor: %s\n",
556                                 dmi_string(dm, data[4])));
557                         dmi_save_ident(dm, DMI_SYS_VENDOR, 4);
558                         dmi_printk(("Product Name: %s\n",
559                                 dmi_string(dm, data[5])));
560                         dmi_save_ident(dm, DMI_PRODUCT_NAME, 5);
561                         dmi_printk(("Version: %s\n",
562                                 dmi_string(dm, data[6])));
563                         dmi_save_ident(dm, DMI_PRODUCT_VERSION, 6);
564                         dmi_printk(("Serial Number: %s\n",
565                                 dmi_string(dm, data[7])));
566                         break;
567                 case 2:
568                         dmi_printk(("Board Vendor: %s\n",
569                                 dmi_string(dm, data[4])));
570                         dmi_save_ident(dm, DMI_BOARD_VENDOR, 4);
571                         dmi_printk(("Board Name: %s\n",
572                                 dmi_string(dm, data[5])));
573                         dmi_save_ident(dm, DMI_BOARD_NAME, 5);
574                         dmi_printk(("Board Version: %s\n",
575                                 dmi_string(dm, data[6])));
576                         dmi_save_ident(dm, DMI_BOARD_VERSION, 6);
577                         break;
578         }
579 }
580
581 void __init dmi_scan_machine(void)
582 {
583         int err = dmi_iterate(dmi_decode);
584         if(err == 0)
585                 dmi_check_blacklist();
586         else
587                 printk(KERN_INFO "DMI not present.\n");
588 }
589
590
591 /**
592  *      dmi_check_system - check system DMI data
593  *      @list: array of dmi_system_id structures to match against
594  *
595  *      Walk the blacklist table running matching functions until someone
596  *      returns non zero or we hit the end. Callback function is called for
597  *      each successfull match. Returns the number of matches.
598  */
599 int dmi_check_system(struct dmi_system_id *list)
600 {
601         int i, count = 0;
602         struct dmi_system_id *d = list;
603
604         while (d->ident) {
605                 for (i = 0; i < ARRAY_SIZE(d->matches); i++) {
606                         int s = d->matches[i].slot;
607                         if (s == DMI_NONE)
608                                 continue;
609                         if (dmi_ident[s] && strstr(dmi_ident[s], d->matches[i].substr))
610                                 continue;
611                         /* No match */
612                         goto fail;
613                 }
614                 if (d->callback && d->callback(d))
615                         break;
616                 count++;
617 fail:           d++;
618         }
619
620         return count;
621 }
622
623 EXPORT_SYMBOL(dmi_check_system);
624
625 /**
626  *      dmi_get_system_info - return DMI data value
627  *      @field: data index (see enum dmi_filed)
628  *
629  *      Returns one DMI data value, can be used to perform
630  *      complex DMI data checks.
631  */
632 char * dmi_get_system_info(int field)
633 {
634         return dmi_ident[field];
635 }
636
637 EXPORT_SYMBOL(dmi_get_system_info);