diff --git a/drivers/platform/x86/eeepc-laptop.c b/drivers/platform/x86/eeepc-laptop.c index 5838c69b2fb3..e954f2af5724 100644 --- a/drivers/platform/x86/eeepc-laptop.c +++ b/drivers/platform/x86/eeepc-laptop.c @@ -35,6 +35,7 @@ #include #include #include +#include #define EEEPC_LAPTOP_VERSION "0.1" #define EEEPC_LAPTOP_NAME "Eee PC Hotkey Driver" @@ -159,6 +160,7 @@ struct eeepc_laptop { acpi_handle handle; /* the handle of the acpi device */ u32 cm_supported; /* the control methods supported by this BIOS */ + bool cpufv_disabled; u16 event_count[128]; /* count for each event */ struct platform_device *platform_device; @@ -378,6 +380,8 @@ static ssize_t store_cpufv(struct device *dev, struct eeepc_cpufv c; int rv, value; + if (eeepc->cpufv_disabled) + return -EPERM; if (get_cpufv(eeepc, &c)) return -ENODEV; rv = parse_arg(buf, count, &value); @@ -389,6 +393,41 @@ static ssize_t store_cpufv(struct device *dev, return rv; } +static ssize_t show_cpufv_disabled(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct eeepc_laptop *eeepc = dev_get_drvdata(dev); + + return sprintf(buf, "%d\n", eeepc->cpufv_disabled); +} + +static ssize_t store_cpufv_disabled(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct eeepc_laptop *eeepc = dev_get_drvdata(dev); + int rv, value; + + rv = parse_arg(buf, count, &value); + if (rv < 0) + return rv; + + switch (value) { + case 0: + if (eeepc->cpufv_disabled) + pr_warning("cpufv enabled (not officially supported " + "on this model)\n"); + eeepc->cpufv_disabled = false; + return rv; + case 1: + return -EPERM; + default: + return -EINVAL; + } +} + + static struct device_attribute dev_attr_cpufv = { .attr = { .name = "cpufv", @@ -404,12 +443,22 @@ static struct device_attribute dev_attr_available_cpufv = { .show = show_available_cpufv }; +static struct device_attribute dev_attr_cpufv_disabled = { + .attr = { + .name = "cpufv_disabled", + .mode = 0644 }, + .show = show_cpufv_disabled, + .store = store_cpufv_disabled +}; + + static struct attribute *platform_attributes[] = { &dev_attr_camera.attr, &dev_attr_cardr.attr, &dev_attr_disp.attr, &dev_attr_cpufv.attr, &dev_attr_available_cpufv.attr, + &dev_attr_cpufv_disabled.attr, NULL }; @@ -1261,6 +1310,42 @@ static void eeepc_acpi_notify(struct acpi_device *device, u32 event) } } +static void eeepc_dmi_check(struct eeepc_laptop *eeepc) +{ + const char *model; + + /* + * Blacklist for setting cpufv (cpu speed). + * + * EeePC 4G ("701") implements CFVS, but it is not supported + * by the pre-installed OS, and the original option to change it + * in the BIOS setup screen was removed in later versions. + * + * Judging by the lack of "Super Hybrid Engine" on Asus product pages, + * this applies to all "701" models (4G/4G Surf/2G Surf). + * + * So Asus made a deliberate decision not to support it on this model. + * We have several reports that using it can cause the system to hang + * + * The hang has also been reported on a "702" (Model name "8G"?). + * + * We avoid dmi_check_system() / dmi_match(), because they use + * substring matching. We don't want to affect the "701SD" + * and "701SDX" models, because they do support S.H.E. + */ + + model = dmi_get_system_info(DMI_PRODUCT_NAME); + if (!model) + return; + + if (strcmp(model, "701") == 0 || strcmp(model, "702") == 0) { + eeepc->cpufv_disabled = true; + pr_info("model %s does not officially support setting cpu " + "speed\n", model); + pr_info("cpufv disabled to avoid instability\n"); + } +} + static void cmsg_quirk(struct eeepc_laptop *eeepc, int cm, const char *name) { int dummy; @@ -1342,6 +1427,8 @@ static int __devinit eeepc_acpi_add(struct acpi_device *device) strcpy(acpi_device_class(device), EEEPC_ACPI_CLASS); device->driver_data = eeepc; + eeepc_dmi_check(eeepc); + result = eeepc_acpi_init(eeepc, device); if (result) goto fail_platform;