diff options
author | Alex Hung <alex.hung@canonical.com> | 2013-06-13 04:46:25 -0400 |
---|---|---|
committer | Matthew Garrett <matthew.garrett@nebula.com> | 2013-07-10 15:42:48 -0400 |
commit | 8667ca9518bbe0eff2222e69d611f4c8549fcbde (patch) | |
tree | 80fca0c4e3433ab2d0639791a02161f470d7d8cc /drivers/platform | |
parent | e8f56c80aedacfb1552509c0e4ed265266328bc4 (diff) |
hp-wmi: add supports for POST code error
HP laptops include a POST code error query 0x2A that reports
which point BIOS fails to boot at. The error code is kept in CMOS
until it is cleared.
Signed-off-by: Alex Hung <alex.hung@canonical.com>
Signed-off-by: Matthew Garrett <matthew.garrett@nebula.com>
Diffstat (limited to 'drivers/platform')
-rw-r--r-- | drivers/platform/x86/hp-wmi.c | 47 |
1 files changed, 47 insertions, 0 deletions
diff --git a/drivers/platform/x86/hp-wmi.c b/drivers/platform/x86/hp-wmi.c index 6e142c3b5e97..97bb05edcb5a 100644 --- a/drivers/platform/x86/hp-wmi.c +++ b/drivers/platform/x86/hp-wmi.c | |||
@@ -56,6 +56,7 @@ MODULE_ALIAS("wmi:5FB7F034-2C63-45e9-BE91-3D44E2C707E4"); | |||
56 | #define HPWMI_BIOS_QUERY 0x9 | 56 | #define HPWMI_BIOS_QUERY 0x9 |
57 | #define HPWMI_HOTKEY_QUERY 0xc | 57 | #define HPWMI_HOTKEY_QUERY 0xc |
58 | #define HPWMI_WIRELESS2_QUERY 0x1b | 58 | #define HPWMI_WIRELESS2_QUERY 0x1b |
59 | #define HPWMI_POSTCODEERROR_QUERY 0x2a | ||
59 | 60 | ||
60 | enum hp_wmi_radio { | 61 | enum hp_wmi_radio { |
61 | HPWMI_WIFI = 0, | 62 | HPWMI_WIFI = 0, |
@@ -400,6 +401,16 @@ static int hp_wmi_rfkill2_refresh(void) | |||
400 | return 0; | 401 | return 0; |
401 | } | 402 | } |
402 | 403 | ||
404 | static int hp_wmi_post_code_state(void) | ||
405 | { | ||
406 | int state = 0; | ||
407 | int ret = hp_wmi_perform_query(HPWMI_POSTCODEERROR_QUERY, 0, &state, | ||
408 | sizeof(state), sizeof(state)); | ||
409 | if (ret) | ||
410 | return -EINVAL; | ||
411 | return state; | ||
412 | } | ||
413 | |||
403 | static ssize_t show_display(struct device *dev, struct device_attribute *attr, | 414 | static ssize_t show_display(struct device *dev, struct device_attribute *attr, |
404 | char *buf) | 415 | char *buf) |
405 | { | 416 | { |
@@ -445,6 +456,16 @@ static ssize_t show_tablet(struct device *dev, struct device_attribute *attr, | |||
445 | return sprintf(buf, "%d\n", value); | 456 | return sprintf(buf, "%d\n", value); |
446 | } | 457 | } |
447 | 458 | ||
459 | static ssize_t show_postcode(struct device *dev, struct device_attribute *attr, | ||
460 | char *buf) | ||
461 | { | ||
462 | /* Get the POST error code of previous boot failure. */ | ||
463 | int value = hp_wmi_post_code_state(); | ||
464 | if (value < 0) | ||
465 | return -EINVAL; | ||
466 | return sprintf(buf, "0x%x\n", value); | ||
467 | } | ||
468 | |||
448 | static ssize_t set_als(struct device *dev, struct device_attribute *attr, | 469 | static ssize_t set_als(struct device *dev, struct device_attribute *attr, |
449 | const char *buf, size_t count) | 470 | const char *buf, size_t count) |
450 | { | 471 | { |
@@ -457,11 +478,33 @@ static ssize_t set_als(struct device *dev, struct device_attribute *attr, | |||
457 | return count; | 478 | return count; |
458 | } | 479 | } |
459 | 480 | ||
481 | static ssize_t set_postcode(struct device *dev, struct device_attribute *attr, | ||
482 | const char *buf, size_t count) | ||
483 | { | ||
484 | int ret; | ||
485 | u32 tmp; | ||
486 | long unsigned int tmp2; | ||
487 | |||
488 | ret = kstrtoul(buf, 10, &tmp2); | ||
489 | if (ret || tmp2 != 1) | ||
490 | return -EINVAL; | ||
491 | |||
492 | /* Clear the POST error code. It is kept until until cleared. */ | ||
493 | tmp = (u32) tmp2; | ||
494 | ret = hp_wmi_perform_query(HPWMI_POSTCODEERROR_QUERY, 1, &tmp, | ||
495 | sizeof(tmp), sizeof(tmp)); | ||
496 | if (ret) | ||
497 | return -EINVAL; | ||
498 | |||
499 | return count; | ||
500 | } | ||
501 | |||
460 | static DEVICE_ATTR(display, S_IRUGO, show_display, NULL); | 502 | static DEVICE_ATTR(display, S_IRUGO, show_display, NULL); |
461 | static DEVICE_ATTR(hddtemp, S_IRUGO, show_hddtemp, NULL); | 503 | static DEVICE_ATTR(hddtemp, S_IRUGO, show_hddtemp, NULL); |
462 | static DEVICE_ATTR(als, S_IRUGO | S_IWUSR, show_als, set_als); | 504 | static DEVICE_ATTR(als, S_IRUGO | S_IWUSR, show_als, set_als); |
463 | static DEVICE_ATTR(dock, S_IRUGO, show_dock, NULL); | 505 | static DEVICE_ATTR(dock, S_IRUGO, show_dock, NULL); |
464 | static DEVICE_ATTR(tablet, S_IRUGO, show_tablet, NULL); | 506 | static DEVICE_ATTR(tablet, S_IRUGO, show_tablet, NULL); |
507 | static DEVICE_ATTR(postcode, S_IRUGO | S_IWUSR, show_postcode, set_postcode); | ||
465 | 508 | ||
466 | static void hp_wmi_notify(u32 value, void *context) | 509 | static void hp_wmi_notify(u32 value, void *context) |
467 | { | 510 | { |
@@ -642,6 +685,7 @@ static void cleanup_sysfs(struct platform_device *device) | |||
642 | device_remove_file(&device->dev, &dev_attr_als); | 685 | device_remove_file(&device->dev, &dev_attr_als); |
643 | device_remove_file(&device->dev, &dev_attr_dock); | 686 | device_remove_file(&device->dev, &dev_attr_dock); |
644 | device_remove_file(&device->dev, &dev_attr_tablet); | 687 | device_remove_file(&device->dev, &dev_attr_tablet); |
688 | device_remove_file(&device->dev, &dev_attr_postcode); | ||
645 | } | 689 | } |
646 | 690 | ||
647 | static int hp_wmi_rfkill_setup(struct platform_device *device) | 691 | static int hp_wmi_rfkill_setup(struct platform_device *device) |
@@ -859,6 +903,9 @@ static int __init hp_wmi_bios_setup(struct platform_device *device) | |||
859 | err = device_create_file(&device->dev, &dev_attr_tablet); | 903 | err = device_create_file(&device->dev, &dev_attr_tablet); |
860 | if (err) | 904 | if (err) |
861 | goto add_sysfs_error; | 905 | goto add_sysfs_error; |
906 | err = device_create_file(&device->dev, &dev_attr_postcode); | ||
907 | if (err) | ||
908 | goto add_sysfs_error; | ||
862 | return 0; | 909 | return 0; |
863 | 910 | ||
864 | add_sysfs_error: | 911 | add_sysfs_error: |