patch-2.4.7 linux/arch/i386/kernel/dmi_scan.c

Next file: linux/arch/i386/kernel/pci-irq.c
Previous file: linux/arch/i386/defconfig
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.4.6/linux/arch/i386/kernel/dmi_scan.c linux/arch/i386/kernel/dmi_scan.c
@@ -1,8 +1,10 @@
+#include <linux/config.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/string.h>
 #include <linux/init.h>
 #include <linux/apm_bios.h>
+#include <linux/slab.h>
 #include <asm/io.h>
 
 struct dmi_header
@@ -13,6 +15,7 @@
 };
 
 #define dmi_printk(x)
+//#define dmi_printk(x) printk(x)
 
 static char * __init dmi_string(struct dmi_header *dm, u8 s)
 {
@@ -90,9 +93,254 @@
 }
 
 
+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
+};
+
+static 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");
+}
+
+/*
+ *	DMI callbacks for problem boards
+ */
+
+struct dmi_strmatch
+{
+	u8 slot;
+	char *substr;
+};
+
+#define NONE	255
+
+struct dmi_blacklist
+{
+	int (*callback)(struct dmi_blacklist *);
+	char *ident;
+	struct dmi_strmatch matches[4];
+};
+
+#define NO_MATCH	{ NONE, NULL}
+#define MATCH(a,b)	{ a, b }
+
+/*
+ *	We have problems with IDE DMA on some platforms. In paticular the
+ *	KT7 series. On these it seems the newer BIOS has fixed them. The
+ *	rule needs to be improved to match specific BIOS revisions with
+ *	corruption problems
+ */ 
+ 
+static __init int disable_ide_dma(struct dmi_blacklist *d)
+{
+#ifdef CONFIG_BLK_DEV_IDE
+	extern int noautodma;
+	if(noautodma == 0)
+	{
+		noautodma = 1;
+		printk(KERN_INFO "%s series board detected. Disabling IDE DMA.\n", d->ident);
+	}
+#endif	
+	return 0;
+}
+
+/* 
+ * Some machines require the "reboot=b"  commandline option, this quirk makes that automatic.
+ */
+static __init int set_bios_reboot(struct dmi_blacklist *d)
+{
+	extern int reboot_thru_bios;
+	if (reboot_thru_bios == 0)
+	{
+		reboot_thru_bios = 1;
+		printk(KERN_INFO "%s series board detected. Selecting BIOS-method for reboots.\n", d->ident);
+	}
+	return 0;
+}
+
+/*
+ * Some bioses have a broken protected mode poweroff and need to use realmode
+ */
+
+static __init int set_realmode_power_off(struct dmi_blacklist *d)
+{
+       if (apm_info.realmode_power_off == 0)
+       {
+               apm_info.realmode_power_off = 1;
+               printk(KERN_INFO "%s bios detected. Using realmode poweroff only.\n", d->ident);
+       }
+       return 0;
+}
+
+
+/* 
+ * Some laptops require interrupts to be enabled during APM calls 
+ */
+
+static __init int set_apm_ints(struct dmi_blacklist *d)
+{
+	if (apm_info.allow_ints == 0)
+	{
+		apm_info.allow_ints = 1;
+		printk(KERN_INFO "%s machine detected. Enabling interrupts during APM calls.\n", d->ident);
+	}
+	return 0;
+}
+
+/* 
+ * Some APM bioses corrupt memory or just plain do not work
+ */
+
+static __init int apm_is_horked(struct dmi_blacklist *d)
+{
+	if (apm_info.disabled == 0)
+	{
+		apm_info.disabled = 1;
+		printk(KERN_INFO "%s machine detected. Disabling APM.\n", d->ident);
+	}
+	return 0;
+}
+
+
+/*
+ *  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)
+ */
+
+static __init int broken_apm_power(struct dmi_blacklist *d)
+{
+	apm_info.get_power_status_broken = 1;
+	printk(KERN_WARNING "BIOS strings suggest APM bugs, disabling power status reporting.\n");
+	return 0;
+}		
+
+/*
+ *	Process the DMI blacklists
+ */
+ 
+
+/*
+ *	This will be expanded over time to force things like the APM 
+ *	interrupt mask settings according to the laptop
+ */
+ 
+static __initdata struct dmi_blacklist dmi_blacklist[]={
+#if 0
+	{ disable_ide_dma, "KT7", {	/* Overbroad right now - kill DMA on problem KT7 boards */
+			MATCH(DMI_PRODUCT_NAME, "KT7-RAID"),
+			NO_MATCH, NO_MATCH, NO_MATCH
+			} },
+#endif			
+	{ broken_apm_power, "Dell Inspiron 5000e", {	/* Handle problems with APM on Inspiron 5000e */
+			MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"),
+			MATCH(DMI_BIOS_VERSION, "A04"),
+			MATCH(DMI_BIOS_DATE, "08/24/2000"), NO_MATCH
+			} },
+	{ set_realmode_power_off, "Award Software v4.60 PGMA", {	/* broken PM poweroff bios */
+			MATCH(DMI_BIOS_VENDOR, "Award Software International, Inc."),
+			MATCH(DMI_BIOS_VERSION, "4.60 PGMA"),
+			MATCH(DMI_BIOS_DATE, "134526184"), NO_MATCH
+			} },
+	{ set_bios_reboot, "PowerEdge 1300/500", {	/* Handle problems with rebooting on Dell 1300's */
+			MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"),
+			MATCH(DMI_PRODUCT_NAME, "PowerEdge 1300/500"),
+			NO_MATCH, NO_MATCH
+			} },
+	{ set_bios_reboot, "PowerEdge 1300/550", {	/* Handle problems with rebooting on Dell 1300's */
+			MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"),
+			MATCH(DMI_PRODUCT_NAME, "PowerEdge 1300/550"),
+			NO_MATCH, NO_MATCH
+			} },
+	{ set_apm_ints, "IBM", {	/* Allow interrupts during suspend on IBM laptops */
+			MATCH(DMI_SYS_VENDOR, "IBM"),
+			NO_MATCH, NO_MATCH, NO_MATCH
+			} },
+	{ set_apm_ints, "ASUSTeK", {   /* Allow interrupts during APM or the clock goes slow */
+			MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."),
+			MATCH(DMI_PRODUCT_NAME, "L8400K series Notebook PC"),
+			NO_MATCH, NO_MATCH
+			} },					
+	{ apm_is_horked, "Trigem Delhi3", { /* APM crashes */
+			MATCH(DMI_SYS_VENDOR, "TriGem Computer, Inc"),
+			MATCH(DMI_PRODUCT_NAME, "Delhi3"),
+			NO_MATCH, NO_MATCH,
+			} },
+	{ NULL, }
+};
+	
+	
+/*
+ *	Walk the blacklist table running matching functions until someone 
+ *	returns 1 or we hit the end.
+ */
+ 
+static __init void dmi_check_blacklist(void)
+{
+	struct dmi_blacklist *d;
+	int i;
+		
+	d=&dmi_blacklist[0];
+	while(d->callback)
+	{
+		for(i=0;i<4;i++)
+		{
+			int s = d->matches[i].slot;
+			if(s==NONE)
+				continue;
+			if(dmi_ident[s] && strstr(dmi_ident[s], d->matches[i].substr))
+				continue;
+			/* No match */
+			goto fail;
+		}
+		if(d->callback(d))
+			return;
+fail:			
+		d++;
+	}
+}
+
+	
+
 /*
  *	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
+ *	and machine entries. For 2.5 we should pull the smbus controller info
  *	out of here.
  */
 
@@ -105,66 +353,47 @@
 	{
 		case  0:
 			p=dmi_string(dm,data[4]);
-
-			if(*p && *p!=' ')
+			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])));
-			}
-				
-			/*
-			 *  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)
-			 */
-			 
-			if(strcmp(dmi_string(dm, data[4]), "Phoenix Technologies LTD")==0)
-			{
-				if(strcmp(dmi_string(dm, data[5]), "A04")==0 
-					&& 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");
-				}
+				dmi_save_ident(dm, DMI_BIOS_DATE, 8);
 			}
 			break;
+			
 		case 1:
 			p=dmi_string(dm,data[4]);
-
-			if(*p && *p!=' ')
+			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 && *p!=' ')
+			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:
@@ -177,7 +406,10 @@
 
 static int __init dmi_scan_machine(void)
 {
-	return dmi_iterate(dmi_decode);
+	int err = dmi_iterate(dmi_decode);
+	if(err == 0)
+		dmi_check_blacklist();
+	return err;
 }
 
 module_init(dmi_scan_machine);

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)