aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/platform/x86/eeepc-laptop.c87
1 files changed, 87 insertions, 0 deletions
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 @@
35#include <linux/pci.h> 35#include <linux/pci.h>
36#include <linux/pci_hotplug.h> 36#include <linux/pci_hotplug.h>
37#include <linux/leds.h> 37#include <linux/leds.h>
38#include <linux/dmi.h>
38 39
39#define EEEPC_LAPTOP_VERSION "0.1" 40#define EEEPC_LAPTOP_VERSION "0.1"
40#define EEEPC_LAPTOP_NAME "Eee PC Hotkey Driver" 41#define EEEPC_LAPTOP_NAME "Eee PC Hotkey Driver"
@@ -159,6 +160,7 @@ struct eeepc_laptop {
159 acpi_handle handle; /* the handle of the acpi device */ 160 acpi_handle handle; /* the handle of the acpi device */
160 u32 cm_supported; /* the control methods supported 161 u32 cm_supported; /* the control methods supported
161 by this BIOS */ 162 by this BIOS */
163 bool cpufv_disabled;
162 u16 event_count[128]; /* count for each event */ 164 u16 event_count[128]; /* count for each event */
163 165
164 struct platform_device *platform_device; 166 struct platform_device *platform_device;
@@ -378,6 +380,8 @@ static ssize_t store_cpufv(struct device *dev,
378 struct eeepc_cpufv c; 380 struct eeepc_cpufv c;
379 int rv, value; 381 int rv, value;
380 382
383 if (eeepc->cpufv_disabled)
384 return -EPERM;
381 if (get_cpufv(eeepc, &c)) 385 if (get_cpufv(eeepc, &c))
382 return -ENODEV; 386 return -ENODEV;
383 rv = parse_arg(buf, count, &value); 387 rv = parse_arg(buf, count, &value);
@@ -389,6 +393,41 @@ static ssize_t store_cpufv(struct device *dev,
389 return rv; 393 return rv;
390} 394}
391 395
396static ssize_t show_cpufv_disabled(struct device *dev,
397 struct device_attribute *attr,
398 char *buf)
399{
400 struct eeepc_laptop *eeepc = dev_get_drvdata(dev);
401
402 return sprintf(buf, "%d\n", eeepc->cpufv_disabled);
403}
404
405static ssize_t store_cpufv_disabled(struct device *dev,
406 struct device_attribute *attr,
407 const char *buf, size_t count)
408{
409 struct eeepc_laptop *eeepc = dev_get_drvdata(dev);
410 int rv, value;
411
412 rv = parse_arg(buf, count, &value);
413 if (rv < 0)
414 return rv;
415
416 switch (value) {
417 case 0:
418 if (eeepc->cpufv_disabled)
419 pr_warning("cpufv enabled (not officially supported "
420 "on this model)\n");
421 eeepc->cpufv_disabled = false;
422 return rv;
423 case 1:
424 return -EPERM;
425 default:
426 return -EINVAL;
427 }
428}
429
430
392static struct device_attribute dev_attr_cpufv = { 431static struct device_attribute dev_attr_cpufv = {
393 .attr = { 432 .attr = {
394 .name = "cpufv", 433 .name = "cpufv",
@@ -404,12 +443,22 @@ static struct device_attribute dev_attr_available_cpufv = {
404 .show = show_available_cpufv 443 .show = show_available_cpufv
405}; 444};
406 445
446static struct device_attribute dev_attr_cpufv_disabled = {
447 .attr = {
448 .name = "cpufv_disabled",
449 .mode = 0644 },
450 .show = show_cpufv_disabled,
451 .store = store_cpufv_disabled
452};
453
454
407static struct attribute *platform_attributes[] = { 455static struct attribute *platform_attributes[] = {
408 &dev_attr_camera.attr, 456 &dev_attr_camera.attr,
409 &dev_attr_cardr.attr, 457 &dev_attr_cardr.attr,
410 &dev_attr_disp.attr, 458 &dev_attr_disp.attr,
411 &dev_attr_cpufv.attr, 459 &dev_attr_cpufv.attr,
412 &dev_attr_available_cpufv.attr, 460 &dev_attr_available_cpufv.attr,
461 &dev_attr_cpufv_disabled.attr,
413 NULL 462 NULL
414}; 463};
415 464
@@ -1261,6 +1310,42 @@ static void eeepc_acpi_notify(struct acpi_device *device, u32 event)
1261 } 1310 }
1262} 1311}
1263 1312
1313static void eeepc_dmi_check(struct eeepc_laptop *eeepc)
1314{
1315 const char *model;
1316
1317 /*
1318 * Blacklist for setting cpufv (cpu speed).
1319 *
1320 * EeePC 4G ("701") implements CFVS, but it is not supported
1321 * by the pre-installed OS, and the original option to change it
1322 * in the BIOS setup screen was removed in later versions.
1323 *
1324 * Judging by the lack of "Super Hybrid Engine" on Asus product pages,
1325 * this applies to all "701" models (4G/4G Surf/2G Surf).
1326 *
1327 * So Asus made a deliberate decision not to support it on this model.
1328 * We have several reports that using it can cause the system to hang
1329 *
1330 * The hang has also been reported on a "702" (Model name "8G"?).
1331 *
1332 * We avoid dmi_check_system() / dmi_match(), because they use
1333 * substring matching. We don't want to affect the "701SD"
1334 * and "701SDX" models, because they do support S.H.E.
1335 */
1336
1337 model = dmi_get_system_info(DMI_PRODUCT_NAME);
1338 if (!model)
1339 return;
1340
1341 if (strcmp(model, "701") == 0 || strcmp(model, "702") == 0) {
1342 eeepc->cpufv_disabled = true;
1343 pr_info("model %s does not officially support setting cpu "
1344 "speed\n", model);
1345 pr_info("cpufv disabled to avoid instability\n");
1346 }
1347}
1348
1264static void cmsg_quirk(struct eeepc_laptop *eeepc, int cm, const char *name) 1349static void cmsg_quirk(struct eeepc_laptop *eeepc, int cm, const char *name)
1265{ 1350{
1266 int dummy; 1351 int dummy;
@@ -1342,6 +1427,8 @@ static int __devinit eeepc_acpi_add(struct acpi_device *device)
1342 strcpy(acpi_device_class(device), EEEPC_ACPI_CLASS); 1427 strcpy(acpi_device_class(device), EEEPC_ACPI_CLASS);
1343 device->driver_data = eeepc; 1428 device->driver_data = eeepc;
1344 1429
1430 eeepc_dmi_check(eeepc);
1431
1345 result = eeepc_acpi_init(eeepc, device); 1432 result = eeepc_acpi_init(eeepc, device);
1346 if (result) 1433 if (result)
1347 goto fail_platform; 1434 goto fail_platform;