#include <linux/types.h> #include <linux/kernel.h> #include <linux/string.h> #include <linux/init.h> #include <linux/apm_bios.h> #include <asm/io.h> struct dmi_header { u8 type; u8 length; u16 handle; }; 15 static char * __init dmi_string(struct dmi_header *dm, u8 s) { u8 *bp=(u8 *)dm; bp+=dm->length; s--; 20 while(s>0) { bp+=strlen(bp); bp++; s--; } 26 return bp; } 29 static int __init dmi_table(u32 base, int len, int num, void (*decode)(struct dmi_header *)) { u8 *buf; struct dmi_header *dm; u8 *data; int i=1; int last = 0; buf = ioremap(base, len); 38 if(buf==NULL) 39 return -1; data = buf; 42 while(i<num && (data - buf) < len) { dm=(struct dmi_header *)data; 45 if(dm->type < last) 46 break; last = dm->type; decode(dm); data+=dm->length; 50 while(*data || data[1]) data++; data+=2; i++; } iounmap(buf); 56 return 0; } 60 int __init dmi_iterate(void (*decode)(struct dmi_header *)) { unsigned char buf[20]; long fp=0xE0000L; fp -= 16; 66 while( fp < 0xFFFFF) { fp+=16; isa_memcpy_fromio(buf, fp, 20); 70 if(memcmp(buf, "_DMI_", 5)==0) { u16 num=buf[13]<<8|buf[12]; u16 len=buf[7]<<8|buf[6]; u32 base=buf[11]<<24|buf[10]<<16|buf[9]<<8|buf[8]; printk(KERN_INFO "DMI %d.%d present.\n", buf[14]>>4, buf[14]&0x0F); printk(KERN_INFO "%d structures occupying %d bytes.\n", buf[13]<<8|buf[12], buf[7]<<8|buf[6]); printk(KERN_INFO "DMI table at 0x%08X.\n", buf[11]<<24|buf[10]<<16|buf[9]<<8|buf[8]); 83 if(dmi_table(base,len, num, decode)==0) 84 return 0; } } 87 return -1; } /* * Process a DMI table entry. Right now all we care about are the BIOS * and machine entries. For 2.4 we should pull the smbus controller info * out of here. */ 97 static void __init dmi_decode(struct dmi_header *dm) { u8 *data = (u8 *)dm; char *p; 102 switch(dm->type) { 104 case 0: p=dmi_string(dm,data[4]); 107 if(*p && *p!=' ') { printk("BIOS Vendor: %s\n", p); printk("BIOS Version: %s\n", dmi_string(dm, data[5])); printk("BIOS Release: %s\n", dmi_string(dm, data[8])); } /* * Check for clue free BIOS implementations who use * the following QA technique * * [ Write BIOS Code ]<------ * | ^ * < Does it Compile >----N-- * |Y ^ * < Does it Boot Win98 >-N-- * |Y * [Ship It] * * Phoenix A04 08/24/2000 is known bad (Dell Inspiron 5000e) * Phoenix A07 09/29/2000 is known good (Dell Inspiron 5000) */ 132 if(strcmp(dmi_string(dm, data[4]), "Phoenix Technologies LTD")==0) { if(strcmp(dmi_string(dm, data[5]), "A04")==0 135 && strcmp(dmi_string(dm, data[8]), "08/24/2000")==0) { apm_info.get_power_status_broken = 1; printk(KERN_WARNING "BIOS strings suggest APM bugs, disabling power status reporting.\n"); } } 141 break; 142 case 1: p=dmi_string(dm,data[4]); 145 if(*p && *p!=' ') { printk("System Vendor: %s.\n",p); printk("Product Name: %s.\n", dmi_string(dm, data[5])); printk("Version %s.\n", dmi_string(dm, data[6])); printk("Serial Number %s.\n", dmi_string(dm, data[7])); } 155 break; 156 case 2: p=dmi_string(dm,data[4]); 159 if(*p && *p!=' ') { printk("Board Vendor: %s.\n",p); printk("Board Name: %s.\n", dmi_string(dm, data[5])); printk("Board Version: %s.\n", dmi_string(dm, data[6])); } 167 break; 168 case 3: p=dmi_string(dm,data[8]); 170 if(*p && *p!=' ') printk("Asset Tag: %s.\n", p); 172 break; } } 176 static int __init dmi_scan_machine(void) { 178 return dmi_iterate(dmi_decode); } module_init(dmi_scan_machine);