From a51387a556fc97dd6cccf58d557410c5edd8a023 Mon Sep 17 00:00:00 2001 From: "Mark D. Studebaker" Date: Fri, 2 Aug 2002 01:56:56 +0000 Subject: [PATCH] Move dmi detection code from i2c-piix4 to new dmi_scan.c. This permits better kernel patching into kernels that already have dmi_scan.c. git-svn-id: http://lm-sensors.org/svn/lm-sensors/trunk@1478 7894878c-1315-0410-8ee3-d5d059ff63e0 --- CHANGES | 2 + kernel/busses/Module.mk | 2 +- kernel/busses/dmi_scan.c | 251 ++++++++++++++++++++++++++++++++++++++ kernel/busses/dmi_scan.h | 15 +++ kernel/busses/i2c-piix4.c | 124 +++---------------- 5 files changed, 284 insertions(+), 110 deletions(-) create mode 100644 kernel/busses/dmi_scan.c create mode 100644 kernel/busses/dmi_scan.h diff --git a/CHANGES b/CHANGES index e133c0e3..e31051ad 100644 --- a/CHANGES +++ b/CHANGES @@ -18,7 +18,9 @@ ask CVS about it: ----------------------------------------------------------------------------- 2.6.5 (2002????) + Module dmi_scan: new Module i2c-piix4: Refuse to load on IBM systems + Module lm92: Fix in-kernel initialization Program mkpatch: Add Config.in entries for, lm92, pcf8574, pcf8591, smsc47m1, vt1211 Program sensors: Add /usr/local/etc to config file path diff --git a/kernel/busses/Module.mk b/kernel/busses/Module.mk index 8b4337c7..0c38cc94 100644 --- a/kernel/busses/Module.mk +++ b/kernel/busses/Module.mk @@ -53,7 +53,7 @@ ifneq ($(shell if grep -q '^CONFIG_I2C_SIS5595=y' $(LINUX)/.config; then echo 1; KERNELBUSSESTARGETS += $(MODULE_DIR)/i2c-sis5595.o endif ifneq ($(shell if grep -q '^CONFIG_I2C_PIIX4=y' $(LINUX)/.config; then echo 1; fi),1) -KERNELBUSSESTARGETS += $(MODULE_DIR)/i2c-piix4.o +KERNELBUSSESTARGETS += $(MODULE_DIR)/i2c-piix4.o $(MODULE_DIR)/dmi_scan.o endif ifneq ($(shell if grep -q '^CONFIG_I2C_SAVAGE4=y' $(LINUX)/.config; then echo 1; fi),1) KERNELBUSSESTARGETS += $(MODULE_DIR)/i2c-savage4.o diff --git a/kernel/busses/dmi_scan.c b/kernel/busses/dmi_scan.c new file mode 100644 index 00000000..60e03e22 --- /dev/null +++ b/kernel/busses/dmi_scan.c @@ -0,0 +1,251 @@ +/* + Taken from arch/i386/kernel/dmi_scan.c. + Changes dmi_ident to be non-static so we can access. +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "version.h" +#include "dmi_scan.h" + +struct dmi_header +{ + u8 type; + u8 length; + u16 handle; +}; + +#define dmi_printk(x) +//#define dmi_printk(x) printk x + +static char * __init dmi_string(struct dmi_header *dm, u8 s) +{ + u8 *bp=(u8 *)dm; + bp+=dm->length; + if(!s) + return ""; + s--; + while(s>0) + { + bp+=strlen(bp); + bp++; + s--; + } + return bp; +} + +/* + * We have to be cautious here. We have seen BIOSes with DMI pointers + * pointing to completely the wrong place for example + */ + +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; + + buf = ioremap(base, len); + if(buf==NULL) + return -1; + + data = buf; + + /* + * Stop when we see al the items the table claimed to have + * OR we run off the end of the table (also happens) + */ + + while(ilength) >= len) + break; + decode(dm); + data+=dm->length; + /* + * Don't go off the end of the data if there is + * stuff looking like string fill past the end + */ + while((data-buf) < len && (*data || data[1])) + data++; + data+=2; + i++; + } + iounmap(buf); + return 0; +} + + +static int __init dmi_iterate(void (*decode)(struct dmi_header *)) +{ + unsigned char buf[20]; + long fp=0xE0000L; + fp -= 16; + +#ifdef CONFIG_SIMNOW + /* + * Skip on x86/64 with simnow. Will eventually go away + * If you see this ifdef in 2.6pre mail me ! + */ + return -1; +#endif + + while( fp < 0xFFFFF) + { + fp+=16; + isa_memcpy_fromio(buf, fp, 20); + 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]; + + dmi_printk((KERN_INFO "DMI %d.%d present.\n", + buf[14]>>4, buf[14]&0x0F)); + dmi_printk((KERN_INFO "%d structures occupying %d bytes.\n", + buf[13]<<8|buf[12], + buf[7]<<8|buf[6])); + dmi_printk((KERN_INFO "DMI table at 0x%08X.\n", + buf[11]<<24|buf[10]<<16|buf[9]<<8|buf[8])); + if(dmi_table(base,len, num, decode)==0) + return 0; + } + } + return -1; +} + + +char *dmi_ident[DMI_STRING_MAX]; + +/* + * Save a DMI string + */ + +static void __init dmi_save_ident(struct dmi_header *dm, int slot, int string) +{ + char *d = (char*)dm; + char *p = dmi_string(dm, d[string]); + if(p==NULL || *p == 0) + return; + if (dmi_ident[slot]) + return; + dmi_ident[slot] = kmalloc(strlen(p)+1, GFP_KERNEL); + if(dmi_ident[slot]) + strcpy(dmi_ident[slot], p); + else + printk(KERN_ERR "dmi_save_ident: out of memory.\n"); +} + +/* + * Process a DMI table entry. Right now all we care about are the BIOS + * and machine entries. For 2.5 we should pull the smbus controller info + * out of here. + */ + +static void __init dmi_decode(struct dmi_header *dm) +{ + u8 *data = (u8 *)dm; + char *p; + + switch(dm->type) + { + case 0: + p=dmi_string(dm,data[4]); + if(*p) + { + dmi_printk(("BIOS Vendor: %s\n", p)); + dmi_save_ident(dm, DMI_BIOS_VENDOR, 4); + dmi_printk(("BIOS Version: %s\n", + dmi_string(dm, data[5]))); + dmi_save_ident(dm, DMI_BIOS_VERSION, 5); + dmi_printk(("BIOS Release: %s\n", + dmi_string(dm, data[8]))); + dmi_save_ident(dm, DMI_BIOS_DATE, 8); + } + break; + + case 1: + p=dmi_string(dm,data[4]); + if(*p) + { + dmi_printk(("System Vendor: %s.\n",p)); + dmi_save_ident(dm, DMI_SYS_VENDOR, 4); + dmi_printk(("Product Name: %s.\n", + dmi_string(dm, data[5]))); + dmi_save_ident(dm, DMI_PRODUCT_NAME, 5); + dmi_printk(("Version %s.\n", + dmi_string(dm, data[6]))); + dmi_save_ident(dm, DMI_PRODUCT_VERSION, 6); + dmi_printk(("Serial Number %s.\n", + dmi_string(dm, data[7]))); + } + break; + case 2: + p=dmi_string(dm,data[4]); + if(*p) + { + dmi_printk(("Board Vendor: %s.\n",p)); + dmi_save_ident(dm, DMI_BOARD_VENDOR, 4); + dmi_printk(("Board Name: %s.\n", + dmi_string(dm, data[5]))); + dmi_save_ident(dm, DMI_BOARD_NAME, 5); + dmi_printk(("Board Version: %s.\n", + dmi_string(dm, data[6]))); + dmi_save_ident(dm, DMI_BOARD_VERSION, 6); + } + break; + case 3: + p=dmi_string(dm,data[8]); + if(*p && *p!=' ') + dmi_printk(("Asset Tag: %s.\n", p)); + break; + } +} + +void __init dmi_scan_machine(void) +{ + int err; + printk("dmi_scan.o version %s (%s)\n", LM_VERSION, LM_DATE); + err = dmi_iterate(dmi_decode); + if(err) + printk("dmi_scan.o: SM BIOS not found\n"); + else + printk("dmi_scan.o: SM BIOS found\n"); +} + +#ifdef MODULE +MODULE_DESCRIPTION("SM BIOS DMI Scanner"); +#ifdef MODULE_LICENSE +MODULE_LICENSE("GPL"); +#endif +EXPORT_SYMBOL(dmi_ident); +EXPORT_SYMBOL(dmi_scan_machine); +int init_module(void) +{ + return 0; +} + +int cleanup_module(void) +{ + return 0; +} + +#endif diff --git a/kernel/busses/dmi_scan.h b/kernel/busses/dmi_scan.h new file mode 100644 index 00000000..56067d67 --- /dev/null +++ b/kernel/busses/dmi_scan.h @@ -0,0 +1,15 @@ +enum +{ + DMI_BIOS_VENDOR, + DMI_BIOS_VERSION, + DMI_BIOS_DATE, + DMI_SYS_VENDOR, + DMI_PRODUCT_NAME, + DMI_PRODUCT_VERSION, + DMI_BOARD_VENDOR, + DMI_BOARD_NAME, + DMI_BOARD_VERSION, + DMI_STRING_MAX +}; + +extern char *dmi_ident[DMI_STRING_MAX]; diff --git a/kernel/busses/i2c-piix4.c b/kernel/busses/i2c-piix4.c index abbf85d2..07d88b64 100644 --- a/kernel/busses/i2c-piix4.c +++ b/kernel/busses/i2c-piix4.c @@ -30,6 +30,7 @@ #include #include +#include #include #include #include @@ -40,6 +41,7 @@ #include "version.h" #include #include +#include "dmi_scan.h" /* Note: We assume all devices are identical to the Intel PIIX4; we only mention it during detection. */ @@ -180,124 +182,26 @@ static struct i2c_adapter piix4_adapter = { static int __initdata piix4_initialized; static unsigned short piix4_smba = 0; -/* The following DMI section is used to detect IBM Thinkpad laptops, - whose AT24RF08 serial eeproms on the PIIX4 SMBus get corrupted. - We refuse to load on those systems. - From drivers/char/i8k.c (retabbed), which was - stolen from arch/i386/kernel/dmi_scan.c */ - -static char system_vendor[48] = "?"; -typedef struct { - u8 type; - u8 length; - u16 handle; -} DMIHeader; -#define IBM_SIGNATURE "IBM" - -static char* __init dmi_string(DMIHeader *dmi, u8 s) -{ - u8 *p; - - if (!s) - return ""; - s--; - - p = (u8 *)dmi + dmi->length; - while (s > 0) { - p += strlen(p); - p++; - s--; - } - - return p; -} - -static void __init dmi_decode(DMIHeader *dmi) -{ - u8 *data = (u8 *) dmi; - char *p; - - switch (dmi->type) { - case 1: /* System Information */ - p = dmi_string(dmi,data[4]); - if (*p) - strncpy(system_vendor, p, sizeof(system_vendor)); - break; - } -} - -static int __init dmi_table(u32 base, int len, int num, void (*fn)(DMIHeader*)) -{ - u8 *buf; - u8 *data; - DMIHeader *dmi; - int i = 1; - - buf = ioremap(base, len); - if (buf == NULL) - return -1; - data = buf; - -/* - * Stop when we see al the items the table claimed to have - * or we run off the end of the table (also happens) - */ - while ((ilength) >= len) - break; - fn(dmi); - data += dmi->length; -/* - * Don't go off the end of the data if there is - * stuff looking like string fill past the end - */ - while (((data-buf) < len) && (*data || data[1])) - data++; - data += 2; - i++; - } - iounmap(buf); - return 0; -} - -static int __init dmi_iterate(void (*decode)(DMIHeader *)) -{ - unsigned char buf[20]; - long fp = 0x000e0000L; - fp -= 16; - - while (fp < 0x000fffffL) { - fp += 16; - isa_memcpy_fromio(buf, fp, 20); - 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]; - if (dmi_table(base, len, num, decode)==0) - return 0; - } - } - return -1; -} -/* end of DMI code */ - +#ifdef CONFIG_X86 /* * Get DMI information. */ +void dmi_scan_machine(void); +#define IBM_SIGNATURE "IBM" static int __init ibm_dmi_probe(void) { - if (dmi_iterate(dmi_decode) != 0) +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,99) + + dmi_scan_machine(); +#endif + if(dmi_ident[DMI_SYS_VENDOR] == NULL) return 0; - if (strncmp(system_vendor,IBM_SIGNATURE,strlen(IBM_SIGNATURE)) == 0) + if(strncmp(dmi_ident[DMI_SYS_VENDOR], IBM_SIGNATURE, + strlen(IBM_SIGNATURE)) == 0) return 1; return 0; } +#endif /* Detect whether a PIIX4 can be found, and initialize it, where necessary. Note the differences between kernels with the old PCI BIOS interface and @@ -335,6 +239,7 @@ int piix4_setup(void) } printk(KERN_INFO "i2c-piix4.o: Found %s device\n", num->name); +#ifdef CONFIG_X86 if(ibm_dmi_probe()) { printk (KERN_ERR "i2c-piix4.o: IBM Laptop detected; this module may corrupt\n"); @@ -343,6 +248,7 @@ int piix4_setup(void) error_return = -EPERM; goto END; } +#endif /* Determine the address of the SMBus areas */ if (force_addr) {