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 | |
| 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>
| -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: |
