ACPI: Add Thinkpad T400, T500 to OSI(Linux) white-list
[safe/jmp/linux-2.6] / drivers / acpi / blacklist.c
index c8f4cac..23e5a05 100644 (file)
@@ -3,6 +3,7 @@
  *
  *  Check to see if the given machine has a known bad ACPI BIOS
  *  or if the BIOS is too old.
+ *  Check given machine against acpi_osi_dmi_table[].
  *
  *  Copyright (C) 2004 Len Brown <len.brown@intel.com>
  *  Copyright (C) 2002 Andy Grover <andrew.grover@intel.com>
@@ -33,6 +34,8 @@
 #include <acpi/acpi_bus.h>
 #include <linux/dmi.h>
 
+#include "internal.h"
+
 enum acpi_blacklist_predicates {
        all_versions,
        less_than_or_equal,
@@ -50,6 +53,8 @@ struct acpi_blacklist_item {
        u32 is_critical_error;
 };
 
+static struct dmi_system_id acpi_osi_dmi_table[] __initdata;
+
 /*
  * POLICY: If *anything* doesn't work, put it on the blacklist.
  *        If they are critical errors, mark it critical, and abort driver load.
@@ -67,8 +72,6 @@ static struct acpi_blacklist_item acpi_blacklist[] __initdata = {
        /* IBM 600E - _ADR should return 7, but it returns 1 */
        {"IBM   ", "TP600E  ", 0x00000105, ACPI_SIG_DSDT, less_than_or_equal,
         "Incorrect _ADR", 1},
-       {"ASUS\0\0", "P2B-S   ", 0, ACPI_SIG_DSDT, all_versions,
-        "Bogus PCI routing", 1},
 
        {""}
 };
@@ -77,13 +80,20 @@ static struct acpi_blacklist_item acpi_blacklist[] __initdata = {
 
 static int __init blacklist_by_year(void)
 {
-       int year = dmi_get_year(DMI_BIOS_DATE);
+       int year;
+
        /* Doesn't exist? Likely an old system */
-       if (year == -1)
+       if (!dmi_get_date(DMI_BIOS_DATE, &year, NULL, NULL)) {
+               printk(KERN_ERR PREFIX "no DMI BIOS year, "
+                       "acpi=force is required to enable ACPI\n" );
                return 1;
+       }
        /* 0? Likely a buggy new BIOS */
-       if (year == 0)
+       if (year == 0) {
+               printk(KERN_ERR PREFIX "DMI BIOS year==0, "
+                       "assuming ACPI-capable machine\n" );
                return 0;
+       }
        if (year < CONFIG_ACPI_BLACKLIST_YEAR) {
                printk(KERN_ERR PREFIX "BIOS age (%d) fails cutoff (%d), "
                       "acpi=force is required to enable ACPI\n",
@@ -103,7 +113,7 @@ int __init acpi_blacklisted(void)
 {
        int i = 0;
        int blacklisted = 0;
-       struct acpi_table_header *table_header;
+       struct acpi_table_header table_header;
 
        while (acpi_blacklist[i].oem_id[0] != '\0') {
                if (acpi_get_table_header(acpi_blacklist[i].table, 0, &table_header)) {
@@ -111,13 +121,13 @@ int __init acpi_blacklisted(void)
                        continue;
                }
 
-               if (strncmp(acpi_blacklist[i].oem_id, table_header->oem_id, 6)) {
+               if (strncmp(acpi_blacklist[i].oem_id, table_header.oem_id, 6)) {
                        i++;
                        continue;
                }
 
                if (strncmp
-                   (acpi_blacklist[i].oem_table_id, table_header->oem_table_id,
+                   (acpi_blacklist[i].oem_table_id, table_header.oem_table_id,
                     8)) {
                        i++;
                        continue;
@@ -126,14 +136,14 @@ int __init acpi_blacklisted(void)
                if ((acpi_blacklist[i].oem_revision_predicate == all_versions)
                    || (acpi_blacklist[i].oem_revision_predicate ==
                        less_than_or_equal
-                       && table_header->oem_revision <=
+                       && table_header.oem_revision <=
                        acpi_blacklist[i].oem_revision)
                    || (acpi_blacklist[i].oem_revision_predicate ==
                        greater_than_or_equal
-                       && table_header->oem_revision >=
+                       && table_header.oem_revision >=
                        acpi_blacklist[i].oem_revision)
                    || (acpi_blacklist[i].oem_revision_predicate == equal
-                       && table_header->oem_revision ==
+                       && table_header.oem_revision ==
                        acpi_blacklist[i].oem_revision)) {
 
                        printk(KERN_ERR PREFIX
@@ -159,5 +169,109 @@ int __init acpi_blacklisted(void)
 
        blacklisted += blacklist_by_year();
 
+       dmi_check_system(acpi_osi_dmi_table);
+
        return blacklisted;
 }
+#ifdef CONFIG_DMI
+static int __init dmi_enable_osi_linux(const struct dmi_system_id *d)
+{
+       acpi_dmi_osi_linux(1, d);       /* enable */
+       return 0;
+}
+static int __init dmi_disable_osi_vista(const struct dmi_system_id *d)
+{
+       printk(KERN_NOTICE PREFIX "DMI detected: %s\n", d->ident);
+       acpi_osi_setup("!Windows 2006");
+       return 0;
+}
+
+static struct dmi_system_id acpi_osi_dmi_table[] __initdata = {
+       {
+       .callback = dmi_disable_osi_vista,
+       .ident = "Fujitsu Siemens",
+       .matches = {
+                    DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
+                    DMI_MATCH(DMI_PRODUCT_NAME, "ESPRIMO Mobile V5505"),
+               },
+       },
+       {
+       .callback = dmi_disable_osi_vista,
+       .ident = "Sony VGN-NS10J_S",
+       .matches = {
+                    DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
+                    DMI_MATCH(DMI_PRODUCT_NAME, "VGN-NS10J_S"),
+               },
+       },
+       {
+       .callback = dmi_disable_osi_vista,
+       .ident = "Sony VGN-SR290J",
+       .matches = {
+                    DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
+                    DMI_MATCH(DMI_PRODUCT_NAME, "Sony VGN-SR290J"),
+               },
+       },
+
+       /*
+        * BIOS invocation of _OSI(Linux) is almost always a BIOS bug.
+        * Linux ignores it, except for the machines enumerated below.
+        */
+
+       /*
+        * Lenovo has a mix of systems OSI(Linux) situations
+        * and thus we can not wildcard the vendor.
+        *
+        * _OSI(Linux) helps sound
+        * DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad R61"),
+        * DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad T61"),
+        * T400, T500
+        * _OSI(Linux) has Linux specific hooks
+        * DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad X61"),
+        * _OSI(Linux) is a NOP:
+        * DMI_MATCH(DMI_PRODUCT_VERSION, "3000 N100"),
+        * DMI_MATCH(DMI_PRODUCT_VERSION, "LENOVO3000 V100"),
+        */
+       {
+       .callback = dmi_enable_osi_linux,
+       .ident = "Lenovo ThinkPad R61",
+       .matches = {
+                    DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+                    DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad R61"),
+               },
+       },
+       {
+       .callback = dmi_enable_osi_linux,
+       .ident = "Lenovo ThinkPad T61",
+       .matches = {
+                    DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+                    DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad T61"),
+               },
+       },
+       {
+       .callback = dmi_enable_osi_linux,
+       .ident = "Lenovo ThinkPad X61",
+       .matches = {
+                    DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+                    DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad X61"),
+               },
+       },
+       {
+       .callback = dmi_enable_osi_linux,
+       .ident = "Lenovo ThinkPad T400",
+       .matches = {
+                    DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+                    DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad T400"),
+               },
+       },
+       {
+       .callback = dmi_enable_osi_linux,
+       .ident = "Lenovo ThinkPad T500",
+       .matches = {
+                    DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+                    DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad T500"),
+               },
+       },
+       {}
+};
+
+#endif /* CONFIG_DMI */