*
* 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>
#include <acpi/acpi_bus.h>
#include <linux/dmi.h>
+#include "internal.h"
+
enum acpi_blacklist_predicates {
all_versions,
less_than_or_equal,
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.
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;
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"),
+ * _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"),
+ },
+ },
+ {}
+};
+
+#endif /* CONFIG_DMI */