diff options
| -rw-r--r-- | Documentation/platform/x86-laptop-drivers.txt | 18 | ||||
| -rw-r--r-- | drivers/platform/x86/Kconfig | 31 | ||||
| -rw-r--r-- | drivers/platform/x86/Makefile | 1 | ||||
| -rw-r--r-- | drivers/platform/x86/alienware-wmi.c | 121 | ||||
| -rw-r--r-- | drivers/platform/x86/asus-nb-wmi.c | 9 | ||||
| -rw-r--r-- | drivers/platform/x86/asus-wmi.c | 4 | ||||
| -rw-r--r-- | drivers/platform/x86/dell-smo8800.c | 233 | ||||
| -rw-r--r-- | drivers/platform/x86/hp-wmi.c | 18 | ||||
| -rw-r--r-- | drivers/platform/x86/ideapad-laptop.c | 31 | ||||
| -rw-r--r-- | drivers/platform/x86/intel_mid_thermal.c | 7 | ||||
| -rw-r--r-- | drivers/platform/x86/intel_pmic_gpio.c | 4 | ||||
| -rw-r--r-- | drivers/platform/x86/pvpanic.c | 1 | ||||
| -rw-r--r-- | drivers/platform/x86/samsung-laptop.c | 38 | ||||
| -rw-r--r-- | drivers/platform/x86/thinkpad_acpi.c | 4 | ||||
| -rw-r--r-- | drivers/platform/x86/toshiba_acpi.c | 30 |
15 files changed, 485 insertions, 65 deletions
diff --git a/Documentation/platform/x86-laptop-drivers.txt b/Documentation/platform/x86-laptop-drivers.txt new file mode 100644 index 000000000000..01facd2590bb --- /dev/null +++ b/Documentation/platform/x86-laptop-drivers.txt | |||
| @@ -0,0 +1,18 @@ | |||
| 1 | compal-laptop | ||
| 2 | ============= | ||
| 3 | List of supported hardware: | ||
| 4 | |||
| 5 | by Compal: | ||
| 6 | Compal FL90/IFL90 | ||
| 7 | Compal FL91/IFL91 | ||
| 8 | Compal FL92/JFL92 | ||
| 9 | Compal FT00/IFT00 | ||
| 10 | |||
| 11 | by Dell: | ||
| 12 | Dell Vostro 1200 | ||
| 13 | Dell Mini 9 (Inspiron 910) | ||
| 14 | Dell Mini 10 (Inspiron 1010) | ||
| 15 | Dell Mini 10v (Inspiron 1011) | ||
| 16 | Dell Mini 1012 (Inspiron 1012) | ||
| 17 | Dell Inspiron 11z (Inspiron 1110) | ||
| 18 | Dell Mini 12 (Inspiron 1210) | ||
diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index 27df2c533b09..172f26ce59ac 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig | |||
| @@ -102,7 +102,7 @@ config DELL_LAPTOP | |||
| 102 | default n | 102 | default n |
| 103 | ---help--- | 103 | ---help--- |
| 104 | This driver adds support for rfkill and backlight control to Dell | 104 | This driver adds support for rfkill and backlight control to Dell |
| 105 | laptops. | 105 | laptops (except for some models covered by the Compal driver). |
| 106 | 106 | ||
| 107 | config DELL_WMI | 107 | config DELL_WMI |
| 108 | tristate "Dell WMI extras" | 108 | tristate "Dell WMI extras" |
| @@ -127,6 +127,16 @@ config DELL_WMI_AIO | |||
| 127 | To compile this driver as a module, choose M here: the module will | 127 | To compile this driver as a module, choose M here: the module will |
| 128 | be called dell-wmi-aio. | 128 | be called dell-wmi-aio. |
| 129 | 129 | ||
| 130 | config DELL_SMO8800 | ||
| 131 | tristate "Dell Latitude freefall driver (ACPI SMO8800/SMO8810)" | ||
| 132 | depends on ACPI | ||
| 133 | ---help--- | ||
| 134 | Say Y here if you want to support SMO8800/SMO8810 freefall device | ||
| 135 | on Dell Latitude laptops. | ||
| 136 | |||
| 137 | To compile this driver as a module, choose M here: the module will | ||
| 138 | be called dell-smo8800. | ||
| 139 | |||
| 130 | 140 | ||
| 131 | config FUJITSU_LAPTOP | 141 | config FUJITSU_LAPTOP |
| 132 | tristate "Fujitsu Laptop Extras" | 142 | tristate "Fujitsu Laptop Extras" |
| @@ -265,23 +275,21 @@ config PANASONIC_LAPTOP | |||
| 265 | R2, R3, R5, T2, W2 and Y2 series), say Y. | 275 | R2, R3, R5, T2, W2 and Y2 series), say Y. |
| 266 | 276 | ||
| 267 | config COMPAL_LAPTOP | 277 | config COMPAL_LAPTOP |
| 268 | tristate "Compal Laptop Extras" | 278 | tristate "Compal (and others) Laptop Extras" |
| 269 | depends on ACPI | 279 | depends on ACPI |
| 270 | depends on BACKLIGHT_CLASS_DEVICE | 280 | depends on BACKLIGHT_CLASS_DEVICE |
| 271 | depends on RFKILL | 281 | depends on RFKILL |
| 272 | depends on HWMON | 282 | depends on HWMON |
| 273 | depends on POWER_SUPPLY | 283 | depends on POWER_SUPPLY |
| 274 | ---help--- | 284 | ---help--- |
| 275 | This is a driver for laptops built by Compal: | 285 | This is a driver for laptops built by Compal, and some models by |
| 276 | 286 | other brands (e.g. Dell, Toshiba). | |
| 277 | Compal FL90/IFL90 | ||
| 278 | Compal FL91/IFL91 | ||
| 279 | Compal FL92/JFL92 | ||
| 280 | Compal FT00/IFT00 | ||
| 281 | 287 | ||
| 282 | It adds support for Bluetooth, WLAN and LCD brightness control. | 288 | It adds support for rfkill, Bluetooth, WLAN and LCD brightness |
| 289 | control. | ||
| 283 | 290 | ||
| 284 | If you have an Compal FL9x/IFL9x/FT00 laptop, say Y or M here. | 291 | For a (possibly incomplete) list of supported laptops, please refer |
| 292 | to: Documentation/platform/x86-laptop-drivers.txt | ||
| 285 | 293 | ||
| 286 | config SONY_LAPTOP | 294 | config SONY_LAPTOP |
| 287 | tristate "Sony Laptop Extras" | 295 | tristate "Sony Laptop Extras" |
| @@ -724,7 +732,7 @@ config IBM_RTL | |||
| 724 | 732 | ||
| 725 | config XO1_RFKILL | 733 | config XO1_RFKILL |
| 726 | tristate "OLPC XO-1 software RF kill switch" | 734 | tristate "OLPC XO-1 software RF kill switch" |
| 727 | depends on OLPC | 735 | depends on OLPC || COMPILE_TEST |
| 728 | depends on RFKILL | 736 | depends on RFKILL |
| 729 | ---help--- | 737 | ---help--- |
| 730 | Support for enabling/disabling the WLAN interface on the OLPC XO-1 | 738 | Support for enabling/disabling the WLAN interface on the OLPC XO-1 |
| @@ -732,6 +740,7 @@ config XO1_RFKILL | |||
| 732 | 740 | ||
| 733 | config XO15_EBOOK | 741 | config XO15_EBOOK |
| 734 | tristate "OLPC XO-1.5 ebook switch" | 742 | tristate "OLPC XO-1.5 ebook switch" |
| 743 | depends on OLPC || COMPILE_TEST | ||
| 735 | depends on ACPI && INPUT | 744 | depends on ACPI && INPUT |
| 736 | ---help--- | 745 | ---help--- |
| 737 | Support for the ebook switch on the OLPC XO-1.5 laptop. | 746 | Support for the ebook switch on the OLPC XO-1.5 laptop. |
diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile index 1a2eafc9d48e..c4ca428fd3db 100644 --- a/drivers/platform/x86/Makefile +++ b/drivers/platform/x86/Makefile | |||
| @@ -13,6 +13,7 @@ obj-$(CONFIG_COMPAL_LAPTOP) += compal-laptop.o | |||
| 13 | obj-$(CONFIG_DELL_LAPTOP) += dell-laptop.o | 13 | obj-$(CONFIG_DELL_LAPTOP) += dell-laptop.o |
| 14 | obj-$(CONFIG_DELL_WMI) += dell-wmi.o | 14 | obj-$(CONFIG_DELL_WMI) += dell-wmi.o |
| 15 | obj-$(CONFIG_DELL_WMI_AIO) += dell-wmi-aio.o | 15 | obj-$(CONFIG_DELL_WMI_AIO) += dell-wmi-aio.o |
| 16 | obj-$(CONFIG_DELL_SMO8800) += dell-smo8800.o | ||
| 16 | obj-$(CONFIG_ACER_WMI) += acer-wmi.o | 17 | obj-$(CONFIG_ACER_WMI) += acer-wmi.o |
| 17 | obj-$(CONFIG_ACERHDF) += acerhdf.o | 18 | obj-$(CONFIG_ACERHDF) += acerhdf.o |
| 18 | obj-$(CONFIG_HP_ACCEL) += hp_accel.o | 19 | obj-$(CONFIG_HP_ACCEL) += hp_accel.o |
diff --git a/drivers/platform/x86/alienware-wmi.c b/drivers/platform/x86/alienware-wmi.c index 541f9514f76f..297b6640213f 100644 --- a/drivers/platform/x86/alienware-wmi.c +++ b/drivers/platform/x86/alienware-wmi.c | |||
| @@ -32,6 +32,7 @@ | |||
| 32 | #define WMAX_METHOD_HDMI_STATUS 0x2 | 32 | #define WMAX_METHOD_HDMI_STATUS 0x2 |
| 33 | #define WMAX_METHOD_BRIGHTNESS 0x3 | 33 | #define WMAX_METHOD_BRIGHTNESS 0x3 |
| 34 | #define WMAX_METHOD_ZONE_CONTROL 0x4 | 34 | #define WMAX_METHOD_ZONE_CONTROL 0x4 |
| 35 | #define WMAX_METHOD_HDMI_CABLE 0x5 | ||
| 35 | 36 | ||
| 36 | MODULE_AUTHOR("Mario Limonciello <mario_limonciello@dell.com>"); | 37 | MODULE_AUTHOR("Mario Limonciello <mario_limonciello@dell.com>"); |
| 37 | MODULE_DESCRIPTION("Alienware special feature control"); | 38 | MODULE_DESCRIPTION("Alienware special feature control"); |
| @@ -350,12 +351,11 @@ static int alienware_zone_init(struct platform_device *dev) | |||
| 350 | char *name; | 351 | char *name; |
| 351 | 352 | ||
| 352 | if (interface == WMAX) { | 353 | if (interface == WMAX) { |
| 353 | global_led.max_brightness = 100; | ||
| 354 | lighting_control_state = WMAX_RUNNING; | 354 | lighting_control_state = WMAX_RUNNING; |
| 355 | } else if (interface == LEGACY) { | 355 | } else if (interface == LEGACY) { |
| 356 | global_led.max_brightness = 0x0F; | ||
| 357 | lighting_control_state = LEGACY_RUNNING; | 356 | lighting_control_state = LEGACY_RUNNING; |
| 358 | } | 357 | } |
| 358 | global_led.max_brightness = 0x0F; | ||
| 359 | global_brightness = global_led.max_brightness; | 359 | global_brightness = global_led.max_brightness; |
| 360 | 360 | ||
| 361 | /* | 361 | /* |
| @@ -423,41 +423,85 @@ static void alienware_zone_exit(struct platform_device *dev) | |||
| 423 | The HDMI mux sysfs node indicates the status of the HDMI input mux. | 423 | The HDMI mux sysfs node indicates the status of the HDMI input mux. |
| 424 | It can toggle between standard system GPU output and HDMI input. | 424 | It can toggle between standard system GPU output and HDMI input. |
| 425 | */ | 425 | */ |
| 426 | static ssize_t show_hdmi(struct device *dev, struct device_attribute *attr, | 426 | static acpi_status alienware_hdmi_command(struct hdmi_args *in_args, |
| 427 | char *buf) | 427 | u32 command, int *out_data) |
| 428 | { | 428 | { |
| 429 | acpi_status status; | 429 | acpi_status status; |
| 430 | struct acpi_buffer input; | ||
| 431 | union acpi_object *obj; | 430 | union acpi_object *obj; |
| 432 | u32 tmp = 0; | 431 | struct acpi_buffer input; |
| 433 | struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; | 432 | struct acpi_buffer output; |
| 433 | |||
| 434 | input.length = (acpi_size) sizeof(*in_args); | ||
| 435 | input.pointer = in_args; | ||
| 436 | if (out_data != NULL) { | ||
| 437 | output.length = ACPI_ALLOCATE_BUFFER; | ||
| 438 | output.pointer = NULL; | ||
| 439 | status = wmi_evaluate_method(WMAX_CONTROL_GUID, 1, | ||
| 440 | command, &input, &output); | ||
| 441 | } else | ||
| 442 | status = wmi_evaluate_method(WMAX_CONTROL_GUID, 1, | ||
| 443 | command, &input, NULL); | ||
| 444 | |||
| 445 | if (ACPI_SUCCESS(status) && out_data != NULL) { | ||
| 446 | obj = (union acpi_object *)output.pointer; | ||
| 447 | if (obj && obj->type == ACPI_TYPE_INTEGER) | ||
| 448 | *out_data = (u32) obj->integer.value; | ||
| 449 | } | ||
| 450 | return status; | ||
| 451 | |||
| 452 | } | ||
| 453 | |||
| 454 | static ssize_t show_hdmi_cable(struct device *dev, | ||
| 455 | struct device_attribute *attr, char *buf) | ||
| 456 | { | ||
| 457 | acpi_status status; | ||
| 458 | u32 out_data; | ||
| 434 | struct hdmi_args in_args = { | 459 | struct hdmi_args in_args = { |
| 435 | .arg = 0, | 460 | .arg = 0, |
| 436 | }; | 461 | }; |
| 437 | input.length = (acpi_size) sizeof(in_args); | 462 | status = |
| 438 | input.pointer = &in_args; | 463 | alienware_hdmi_command(&in_args, WMAX_METHOD_HDMI_CABLE, |
| 439 | status = wmi_evaluate_method(WMAX_CONTROL_GUID, 1, | 464 | (u32 *) &out_data); |
| 440 | WMAX_METHOD_HDMI_STATUS, &input, &output); | 465 | if (ACPI_SUCCESS(status)) { |
| 466 | if (out_data == 0) | ||
| 467 | return scnprintf(buf, PAGE_SIZE, | ||
| 468 | "[unconnected] connected unknown\n"); | ||
| 469 | else if (out_data == 1) | ||
| 470 | return scnprintf(buf, PAGE_SIZE, | ||
| 471 | "unconnected [connected] unknown\n"); | ||
| 472 | } | ||
| 473 | pr_err("alienware-wmi: unknown HDMI cable status: %d\n", status); | ||
| 474 | return scnprintf(buf, PAGE_SIZE, "unconnected connected [unknown]\n"); | ||
| 475 | } | ||
| 476 | |||
| 477 | static ssize_t show_hdmi_source(struct device *dev, | ||
| 478 | struct device_attribute *attr, char *buf) | ||
| 479 | { | ||
| 480 | acpi_status status; | ||
| 481 | u32 out_data; | ||
| 482 | struct hdmi_args in_args = { | ||
| 483 | .arg = 0, | ||
| 484 | }; | ||
| 485 | status = | ||
| 486 | alienware_hdmi_command(&in_args, WMAX_METHOD_HDMI_STATUS, | ||
| 487 | (u32 *) &out_data); | ||
| 441 | 488 | ||
| 442 | if (ACPI_SUCCESS(status)) { | 489 | if (ACPI_SUCCESS(status)) { |
| 443 | obj = (union acpi_object *)output.pointer; | 490 | if (out_data == 1) |
| 444 | if (obj && obj->type == ACPI_TYPE_INTEGER) | ||
| 445 | tmp = (u32) obj->integer.value; | ||
| 446 | if (tmp == 1) | ||
| 447 | return scnprintf(buf, PAGE_SIZE, | 491 | return scnprintf(buf, PAGE_SIZE, |
| 448 | "[input] gpu unknown\n"); | 492 | "[input] gpu unknown\n"); |
| 449 | else if (tmp == 2) | 493 | else if (out_data == 2) |
| 450 | return scnprintf(buf, PAGE_SIZE, | 494 | return scnprintf(buf, PAGE_SIZE, |
| 451 | "input [gpu] unknown\n"); | 495 | "input [gpu] unknown\n"); |
| 452 | } | 496 | } |
| 453 | pr_err("alienware-wmi: unknown HDMI status: %d\n", status); | 497 | pr_err("alienware-wmi: unknown HDMI source status: %d\n", out_data); |
| 454 | return scnprintf(buf, PAGE_SIZE, "input gpu [unknown]\n"); | 498 | return scnprintf(buf, PAGE_SIZE, "input gpu [unknown]\n"); |
| 455 | } | 499 | } |
| 456 | 500 | ||
| 457 | static ssize_t toggle_hdmi(struct device *dev, struct device_attribute *attr, | 501 | static ssize_t toggle_hdmi_source(struct device *dev, |
| 458 | const char *buf, size_t count) | 502 | struct device_attribute *attr, |
| 503 | const char *buf, size_t count) | ||
| 459 | { | 504 | { |
| 460 | struct acpi_buffer input; | ||
| 461 | acpi_status status; | 505 | acpi_status status; |
| 462 | struct hdmi_args args; | 506 | struct hdmi_args args; |
| 463 | if (strcmp(buf, "gpu\n") == 0) | 507 | if (strcmp(buf, "gpu\n") == 0) |
| @@ -467,33 +511,46 @@ static ssize_t toggle_hdmi(struct device *dev, struct device_attribute *attr, | |||
| 467 | else | 511 | else |
| 468 | args.arg = 3; | 512 | args.arg = 3; |
| 469 | pr_debug("alienware-wmi: setting hdmi to %d : %s", args.arg, buf); | 513 | pr_debug("alienware-wmi: setting hdmi to %d : %s", args.arg, buf); |
| 470 | input.length = (acpi_size) sizeof(args); | 514 | |
| 471 | input.pointer = &args; | 515 | status = alienware_hdmi_command(&args, WMAX_METHOD_HDMI_SOURCE, NULL); |
| 472 | status = wmi_evaluate_method(WMAX_CONTROL_GUID, 1, | 516 | |
| 473 | WMAX_METHOD_HDMI_SOURCE, &input, NULL); | ||
| 474 | if (ACPI_FAILURE(status)) | 517 | if (ACPI_FAILURE(status)) |
| 475 | pr_err("alienware-wmi: HDMI toggle failed: results: %u\n", | 518 | pr_err("alienware-wmi: HDMI toggle failed: results: %u\n", |
| 476 | status); | 519 | status); |
| 477 | return count; | 520 | return count; |
| 478 | } | 521 | } |
| 479 | 522 | ||
| 480 | static DEVICE_ATTR(hdmi, S_IRUGO | S_IWUSR, show_hdmi, toggle_hdmi); | 523 | static DEVICE_ATTR(cable, S_IRUGO, show_hdmi_cable, NULL); |
| 524 | static DEVICE_ATTR(source, S_IRUGO | S_IWUSR, show_hdmi_source, | ||
| 525 | toggle_hdmi_source); | ||
| 526 | |||
| 527 | static struct attribute *hdmi_attrs[] = { | ||
| 528 | &dev_attr_cable.attr, | ||
| 529 | &dev_attr_source.attr, | ||
| 530 | NULL, | ||
| 531 | }; | ||
| 481 | 532 | ||
| 482 | static void remove_hdmi(struct platform_device *device) | 533 | static struct attribute_group hdmi_attribute_group = { |
| 534 | .name = "hdmi", | ||
| 535 | .attrs = hdmi_attrs, | ||
| 536 | }; | ||
| 537 | |||
| 538 | static void remove_hdmi(struct platform_device *dev) | ||
| 483 | { | 539 | { |
| 484 | device_remove_file(&device->dev, &dev_attr_hdmi); | 540 | sysfs_remove_group(&dev->dev.kobj, &hdmi_attribute_group); |
| 485 | } | 541 | } |
| 486 | 542 | ||
| 487 | static int create_hdmi(void) | 543 | static int create_hdmi(struct platform_device *dev) |
| 488 | { | 544 | { |
| 489 | int ret = -ENOMEM; | 545 | int ret; |
| 490 | ret = device_create_file(&platform_device->dev, &dev_attr_hdmi); | 546 | |
| 547 | ret = sysfs_create_group(&dev->dev.kobj, &hdmi_attribute_group); | ||
| 491 | if (ret) | 548 | if (ret) |
| 492 | goto error_create_hdmi; | 549 | goto error_create_hdmi; |
| 493 | return 0; | 550 | return 0; |
| 494 | 551 | ||
| 495 | error_create_hdmi: | 552 | error_create_hdmi: |
| 496 | remove_hdmi(platform_device); | 553 | remove_hdmi(dev); |
| 497 | return ret; | 554 | return ret; |
| 498 | } | 555 | } |
| 499 | 556 | ||
| @@ -527,7 +584,7 @@ static int __init alienware_wmi_init(void) | |||
| 527 | goto fail_platform_device2; | 584 | goto fail_platform_device2; |
| 528 | 585 | ||
| 529 | if (interface == WMAX) { | 586 | if (interface == WMAX) { |
| 530 | ret = create_hdmi(); | 587 | ret = create_hdmi(platform_device); |
| 531 | if (ret) | 588 | if (ret) |
| 532 | goto fail_prep_hdmi; | 589 | goto fail_prep_hdmi; |
| 533 | } | 590 | } |
diff --git a/drivers/platform/x86/asus-nb-wmi.c b/drivers/platform/x86/asus-nb-wmi.c index 563f59efa669..ddf0eefd862c 100644 --- a/drivers/platform/x86/asus-nb-wmi.c +++ b/drivers/platform/x86/asus-nb-wmi.c | |||
| @@ -137,6 +137,15 @@ static struct dmi_system_id asus_quirks[] = { | |||
| 137 | }, | 137 | }, |
| 138 | { | 138 | { |
| 139 | .callback = dmi_matched, | 139 | .callback = dmi_matched, |
| 140 | .ident = "ASUSTeK COMPUTER INC. X550CA", | ||
| 141 | .matches = { | ||
| 142 | DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), | ||
| 143 | DMI_MATCH(DMI_PRODUCT_NAME, "X550CA"), | ||
| 144 | }, | ||
| 145 | .driver_data = &quirk_asus_x401u, | ||
| 146 | }, | ||
| 147 | { | ||
| 148 | .callback = dmi_matched, | ||
| 140 | .ident = "ASUSTeK COMPUTER INC. X55A", | 149 | .ident = "ASUSTeK COMPUTER INC. X55A", |
| 141 | .matches = { | 150 | .matches = { |
| 142 | DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), | 151 | DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), |
diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c index 91ef69a52263..3c6ccedc82b6 100644 --- a/drivers/platform/x86/asus-wmi.c +++ b/drivers/platform/x86/asus-wmi.c | |||
| @@ -266,7 +266,7 @@ static int asus_wmi_evaluate_method(u32 method_id, u32 arg0, u32 arg1, | |||
| 266 | struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; | 266 | struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; |
| 267 | acpi_status status; | 267 | acpi_status status; |
| 268 | union acpi_object *obj; | 268 | union acpi_object *obj; |
| 269 | u32 tmp; | 269 | u32 tmp = 0; |
| 270 | 270 | ||
| 271 | status = wmi_evaluate_method(ASUS_WMI_MGMT_GUID, 1, method_id, | 271 | status = wmi_evaluate_method(ASUS_WMI_MGMT_GUID, 1, method_id, |
| 272 | &input, &output); | 272 | &input, &output); |
| @@ -277,8 +277,6 @@ static int asus_wmi_evaluate_method(u32 method_id, u32 arg0, u32 arg1, | |||
| 277 | obj = (union acpi_object *)output.pointer; | 277 | obj = (union acpi_object *)output.pointer; |
| 278 | if (obj && obj->type == ACPI_TYPE_INTEGER) | 278 | if (obj && obj->type == ACPI_TYPE_INTEGER) |
| 279 | tmp = (u32) obj->integer.value; | 279 | tmp = (u32) obj->integer.value; |
| 280 | else | ||
| 281 | tmp = 0; | ||
| 282 | 280 | ||
| 283 | if (retval) | 281 | if (retval) |
| 284 | *retval = tmp; | 282 | *retval = tmp; |
diff --git a/drivers/platform/x86/dell-smo8800.c b/drivers/platform/x86/dell-smo8800.c new file mode 100644 index 000000000000..a653716055d1 --- /dev/null +++ b/drivers/platform/x86/dell-smo8800.c | |||
| @@ -0,0 +1,233 @@ | |||
| 1 | /* | ||
| 2 | * dell-smo8800.c - Dell Latitude ACPI SMO8800/SMO8810 freefall sensor driver | ||
| 3 | * | ||
| 4 | * Copyright (C) 2012 Sonal Santan <sonal.santan@gmail.com> | ||
| 5 | * Copyright (C) 2014 Pali Rohár <pali.rohar@gmail.com> | ||
| 6 | * | ||
| 7 | * This is loosely based on lis3lv02d driver. | ||
| 8 | * | ||
| 9 | * This program is free software; you can redistribute it and/or modify | ||
| 10 | * it under the terms of the GNU General Public License as published by | ||
| 11 | * the Free Software Foundation; either version 2 of the License, or | ||
| 12 | * (at your option) any later version. | ||
| 13 | * | ||
| 14 | * This program is distributed in the hope that it will be useful, | ||
| 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 17 | * GNU General Public License for more details. | ||
| 18 | */ | ||
| 19 | |||
| 20 | #define DRIVER_NAME "smo8800" | ||
| 21 | |||
| 22 | #include <linux/kernel.h> | ||
| 23 | #include <linux/module.h> | ||
| 24 | #include <linux/acpi.h> | ||
| 25 | #include <linux/interrupt.h> | ||
| 26 | #include <linux/miscdevice.h> | ||
| 27 | |||
| 28 | struct smo8800_device { | ||
| 29 | u32 irq; /* acpi device irq */ | ||
| 30 | atomic_t counter; /* count after last read */ | ||
| 31 | struct miscdevice miscdev; /* for /dev/freefall */ | ||
| 32 | unsigned long misc_opened; /* whether the device is open */ | ||
| 33 | wait_queue_head_t misc_wait; /* Wait queue for the misc dev */ | ||
| 34 | struct device *dev; /* acpi device */ | ||
| 35 | }; | ||
| 36 | |||
| 37 | static irqreturn_t smo8800_interrupt_quick(int irq, void *data) | ||
| 38 | { | ||
| 39 | struct smo8800_device *smo8800 = data; | ||
| 40 | |||
| 41 | atomic_inc(&smo8800->counter); | ||
| 42 | wake_up_interruptible(&smo8800->misc_wait); | ||
| 43 | return IRQ_WAKE_THREAD; | ||
| 44 | } | ||
| 45 | |||
| 46 | static irqreturn_t smo8800_interrupt_thread(int irq, void *data) | ||
| 47 | { | ||
| 48 | struct smo8800_device *smo8800 = data; | ||
| 49 | |||
| 50 | dev_info(smo8800->dev, "detected free fall\n"); | ||
| 51 | return IRQ_HANDLED; | ||
| 52 | } | ||
| 53 | |||
| 54 | static acpi_status smo8800_get_resource(struct acpi_resource *resource, | ||
| 55 | void *context) | ||
| 56 | { | ||
| 57 | struct acpi_resource_extended_irq *irq; | ||
| 58 | |||
| 59 | if (resource->type != ACPI_RESOURCE_TYPE_EXTENDED_IRQ) | ||
| 60 | return AE_OK; | ||
| 61 | |||
| 62 | irq = &resource->data.extended_irq; | ||
| 63 | if (!irq || !irq->interrupt_count) | ||
| 64 | return AE_OK; | ||
| 65 | |||
| 66 | *((u32 *)context) = irq->interrupts[0]; | ||
| 67 | return AE_CTRL_TERMINATE; | ||
| 68 | } | ||
| 69 | |||
| 70 | static u32 smo8800_get_irq(struct acpi_device *device) | ||
| 71 | { | ||
| 72 | u32 irq = 0; | ||
| 73 | acpi_status status; | ||
| 74 | |||
| 75 | status = acpi_walk_resources(device->handle, METHOD_NAME__CRS, | ||
| 76 | smo8800_get_resource, &irq); | ||
| 77 | if (ACPI_FAILURE(status)) { | ||
| 78 | dev_err(&device->dev, "acpi_walk_resources failed\n"); | ||
| 79 | return 0; | ||
| 80 | } | ||
| 81 | |||
| 82 | return irq; | ||
| 83 | } | ||
| 84 | |||
| 85 | static ssize_t smo8800_misc_read(struct file *file, char __user *buf, | ||
| 86 | size_t count, loff_t *pos) | ||
| 87 | { | ||
| 88 | struct smo8800_device *smo8800 = container_of(file->private_data, | ||
| 89 | struct smo8800_device, miscdev); | ||
| 90 | |||
| 91 | u32 data = 0; | ||
| 92 | unsigned char byte_data = 0; | ||
| 93 | ssize_t retval = 1; | ||
| 94 | |||
| 95 | if (count < 1) | ||
| 96 | return -EINVAL; | ||
| 97 | |||
| 98 | atomic_set(&smo8800->counter, 0); | ||
| 99 | retval = wait_event_interruptible(smo8800->misc_wait, | ||
| 100 | (data = atomic_xchg(&smo8800->counter, 0))); | ||
| 101 | |||
| 102 | if (retval) | ||
| 103 | return retval; | ||
| 104 | |||
| 105 | byte_data = 1; | ||
| 106 | retval = 1; | ||
| 107 | |||
| 108 | if (data < 255) | ||
| 109 | byte_data = data; | ||
| 110 | else | ||
| 111 | byte_data = 255; | ||
| 112 | |||
| 113 | if (put_user(byte_data, buf)) | ||
| 114 | retval = -EFAULT; | ||
| 115 | |||
| 116 | return retval; | ||
| 117 | } | ||
| 118 | |||
| 119 | static int smo8800_misc_open(struct inode *inode, struct file *file) | ||
| 120 | { | ||
| 121 | struct smo8800_device *smo8800 = container_of(file->private_data, | ||
| 122 | struct smo8800_device, miscdev); | ||
| 123 | |||
| 124 | if (test_and_set_bit(0, &smo8800->misc_opened)) | ||
| 125 | return -EBUSY; /* already open */ | ||
| 126 | |||
| 127 | atomic_set(&smo8800->counter, 0); | ||
| 128 | return 0; | ||
| 129 | } | ||
| 130 | |||
| 131 | static int smo8800_misc_release(struct inode *inode, struct file *file) | ||
| 132 | { | ||
| 133 | struct smo8800_device *smo8800 = container_of(file->private_data, | ||
| 134 | struct smo8800_device, miscdev); | ||
| 135 | |||
| 136 | clear_bit(0, &smo8800->misc_opened); /* release the device */ | ||
| 137 | return 0; | ||
| 138 | } | ||
| 139 | |||
| 140 | static const struct file_operations smo8800_misc_fops = { | ||
| 141 | .owner = THIS_MODULE, | ||
| 142 | .read = smo8800_misc_read, | ||
| 143 | .open = smo8800_misc_open, | ||
| 144 | .release = smo8800_misc_release, | ||
| 145 | }; | ||
| 146 | |||
| 147 | static int smo8800_add(struct acpi_device *device) | ||
| 148 | { | ||
| 149 | int err; | ||
| 150 | struct smo8800_device *smo8800; | ||
| 151 | |||
| 152 | smo8800 = devm_kzalloc(&device->dev, sizeof(*smo8800), GFP_KERNEL); | ||
| 153 | if (!smo8800) { | ||
| 154 | dev_err(&device->dev, "failed to allocate device data\n"); | ||
| 155 | return -ENOMEM; | ||
| 156 | } | ||
| 157 | |||
| 158 | smo8800->dev = &device->dev; | ||
| 159 | smo8800->miscdev.minor = MISC_DYNAMIC_MINOR; | ||
| 160 | smo8800->miscdev.name = "freefall"; | ||
| 161 | smo8800->miscdev.fops = &smo8800_misc_fops; | ||
| 162 | |||
| 163 | init_waitqueue_head(&smo8800->misc_wait); | ||
| 164 | |||
| 165 | err = misc_register(&smo8800->miscdev); | ||
| 166 | if (err) { | ||
| 167 | dev_err(&device->dev, "failed to register misc dev: %d\n", err); | ||
| 168 | return err; | ||
| 169 | } | ||
| 170 | |||
| 171 | device->driver_data = smo8800; | ||
| 172 | |||
| 173 | smo8800->irq = smo8800_get_irq(device); | ||
| 174 | if (!smo8800->irq) { | ||
| 175 | dev_err(&device->dev, "failed to obtain IRQ\n"); | ||
| 176 | err = -EINVAL; | ||
| 177 | goto error; | ||
| 178 | } | ||
| 179 | |||
| 180 | err = request_threaded_irq(smo8800->irq, smo8800_interrupt_quick, | ||
| 181 | smo8800_interrupt_thread, | ||
| 182 | IRQF_TRIGGER_RISING | IRQF_ONESHOT, | ||
| 183 | DRIVER_NAME, smo8800); | ||
| 184 | if (err) { | ||
| 185 | dev_err(&device->dev, | ||
| 186 | "failed to request thread for IRQ %d: %d\n", | ||
| 187 | smo8800->irq, err); | ||
| 188 | goto error; | ||
| 189 | } | ||
| 190 | |||
| 191 | dev_dbg(&device->dev, "device /dev/freefall registered with IRQ %d\n", | ||
| 192 | smo8800->irq); | ||
| 193 | return 0; | ||
| 194 | |||
| 195 | error: | ||
| 196 | misc_deregister(&smo8800->miscdev); | ||
| 197 | return err; | ||
| 198 | } | ||
| 199 | |||
| 200 | static int smo8800_remove(struct acpi_device *device) | ||
| 201 | { | ||
| 202 | struct smo8800_device *smo8800 = device->driver_data; | ||
| 203 | |||
| 204 | free_irq(smo8800->irq, smo8800); | ||
| 205 | misc_deregister(&smo8800->miscdev); | ||
| 206 | dev_dbg(&device->dev, "device /dev/freefall unregistered\n"); | ||
| 207 | return 0; | ||
| 208 | } | ||
| 209 | |||
| 210 | static const struct acpi_device_id smo8800_ids[] = { | ||
| 211 | { "SMO8800", 0 }, | ||
| 212 | { "SMO8810", 0 }, | ||
| 213 | { "", 0 }, | ||
| 214 | }; | ||
| 215 | |||
| 216 | MODULE_DEVICE_TABLE(acpi, smo8800_ids); | ||
| 217 | |||
| 218 | static struct acpi_driver smo8800_driver = { | ||
| 219 | .name = DRIVER_NAME, | ||
| 220 | .class = "Latitude", | ||
| 221 | .ids = smo8800_ids, | ||
| 222 | .ops = { | ||
| 223 | .add = smo8800_add, | ||
| 224 | .remove = smo8800_remove, | ||
| 225 | }, | ||
| 226 | .owner = THIS_MODULE, | ||
| 227 | }; | ||
| 228 | |||
| 229 | module_acpi_driver(smo8800_driver); | ||
| 230 | |||
| 231 | MODULE_DESCRIPTION("Dell Latitude freefall driver (ACPI SMO8800/SMO8810)"); | ||
| 232 | MODULE_LICENSE("GPL"); | ||
| 233 | MODULE_AUTHOR("Sonal Santan, Pali Rohár"); | ||
diff --git a/drivers/platform/x86/hp-wmi.c b/drivers/platform/x86/hp-wmi.c index 8ba8956b5a48..484a8673b835 100644 --- a/drivers/platform/x86/hp-wmi.c +++ b/drivers/platform/x86/hp-wmi.c | |||
| @@ -53,6 +53,7 @@ MODULE_ALIAS("wmi:5FB7F034-2C63-45e9-BE91-3D44E2C707E4"); | |||
| 53 | #define HPWMI_ALS_QUERY 0x3 | 53 | #define HPWMI_ALS_QUERY 0x3 |
| 54 | #define HPWMI_HARDWARE_QUERY 0x4 | 54 | #define HPWMI_HARDWARE_QUERY 0x4 |
| 55 | #define HPWMI_WIRELESS_QUERY 0x5 | 55 | #define HPWMI_WIRELESS_QUERY 0x5 |
| 56 | #define HPWMI_BIOS_QUERY 0x9 | ||
| 56 | #define HPWMI_HOTKEY_QUERY 0xc | 57 | #define HPWMI_HOTKEY_QUERY 0xc |
| 57 | #define HPWMI_FEATURE_QUERY 0xd | 58 | #define HPWMI_FEATURE_QUERY 0xd |
| 58 | #define HPWMI_WIRELESS2_QUERY 0x1b | 59 | #define HPWMI_WIRELESS2_QUERY 0x1b |
| @@ -144,6 +145,7 @@ static const struct key_entry hp_wmi_keymap[] = { | |||
| 144 | { KE_KEY, 0x2142, { KEY_MEDIA } }, | 145 | { KE_KEY, 0x2142, { KEY_MEDIA } }, |
| 145 | { KE_KEY, 0x213b, { KEY_INFO } }, | 146 | { KE_KEY, 0x213b, { KEY_INFO } }, |
| 146 | { KE_KEY, 0x2169, { KEY_DIRECTION } }, | 147 | { KE_KEY, 0x2169, { KEY_DIRECTION } }, |
| 148 | { KE_KEY, 0x216a, { KEY_SETUP } }, | ||
| 147 | { KE_KEY, 0x231b, { KEY_HELP } }, | 149 | { KE_KEY, 0x231b, { KEY_HELP } }, |
| 148 | { KE_END, 0 } | 150 | { KE_END, 0 } |
| 149 | }; | 151 | }; |
| @@ -304,6 +306,19 @@ static int hp_wmi_bios_2009_later(void) | |||
| 304 | return (state & 0x10) ? 1 : 0; | 306 | return (state & 0x10) ? 1 : 0; |
| 305 | } | 307 | } |
| 306 | 308 | ||
| 309 | static int hp_wmi_enable_hotkeys(void) | ||
| 310 | { | ||
| 311 | int ret; | ||
| 312 | int query = 0x6e; | ||
| 313 | |||
| 314 | ret = hp_wmi_perform_query(HPWMI_BIOS_QUERY, 1, &query, sizeof(query), | ||
| 315 | 0); | ||
| 316 | |||
| 317 | if (ret) | ||
| 318 | return -EINVAL; | ||
| 319 | return 0; | ||
| 320 | } | ||
| 321 | |||
| 307 | static int hp_wmi_set_block(void *data, bool blocked) | 322 | static int hp_wmi_set_block(void *data, bool blocked) |
| 308 | { | 323 | { |
| 309 | enum hp_wmi_radio r = (enum hp_wmi_radio) data; | 324 | enum hp_wmi_radio r = (enum hp_wmi_radio) data; |
| @@ -648,6 +663,9 @@ static int __init hp_wmi_input_setup(void) | |||
| 648 | hp_wmi_tablet_state()); | 663 | hp_wmi_tablet_state()); |
| 649 | input_sync(hp_wmi_input_dev); | 664 | input_sync(hp_wmi_input_dev); |
| 650 | 665 | ||
| 666 | if (hp_wmi_bios_2009_later() == 4) | ||
| 667 | hp_wmi_enable_hotkeys(); | ||
| 668 | |||
| 651 | status = wmi_install_notify_handler(HPWMI_EVENT_GUID, hp_wmi_notify, NULL); | 669 | status = wmi_install_notify_handler(HPWMI_EVENT_GUID, hp_wmi_notify, NULL); |
| 652 | if (ACPI_FAILURE(status)) { | 670 | if (ACPI_FAILURE(status)) { |
| 653 | err = -EIO; | 671 | err = -EIO; |
diff --git a/drivers/platform/x86/ideapad-laptop.c b/drivers/platform/x86/ideapad-laptop.c index 6dd060a0bb65..b4c495a62eec 100644 --- a/drivers/platform/x86/ideapad-laptop.c +++ b/drivers/platform/x86/ideapad-laptop.c | |||
| @@ -36,6 +36,8 @@ | |||
| 36 | #include <linux/debugfs.h> | 36 | #include <linux/debugfs.h> |
| 37 | #include <linux/seq_file.h> | 37 | #include <linux/seq_file.h> |
| 38 | #include <linux/i8042.h> | 38 | #include <linux/i8042.h> |
| 39 | #include <linux/dmi.h> | ||
| 40 | #include <linux/device.h> | ||
| 39 | 41 | ||
| 40 | #define IDEAPAD_RFKILL_DEV_NUM (3) | 42 | #define IDEAPAD_RFKILL_DEV_NUM (3) |
| 41 | 43 | ||
| @@ -819,6 +821,19 @@ static void ideapad_acpi_notify(acpi_handle handle, u32 event, void *data) | |||
| 819 | } | 821 | } |
| 820 | } | 822 | } |
| 821 | 823 | ||
| 824 | /* Blacklist for devices where the ideapad rfkill interface does not work */ | ||
| 825 | static struct dmi_system_id rfkill_blacklist[] = { | ||
| 826 | /* The Lenovo Yoga 2 11 always reports everything as blocked */ | ||
| 827 | { | ||
| 828 | .ident = "Lenovo Yoga 2 11", | ||
| 829 | .matches = { | ||
| 830 | DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), | ||
| 831 | DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo Yoga 2 11"), | ||
| 832 | }, | ||
| 833 | }, | ||
| 834 | {} | ||
| 835 | }; | ||
| 836 | |||
| 822 | static int ideapad_acpi_add(struct platform_device *pdev) | 837 | static int ideapad_acpi_add(struct platform_device *pdev) |
| 823 | { | 838 | { |
| 824 | int ret, i; | 839 | int ret, i; |
| @@ -833,7 +848,7 @@ static int ideapad_acpi_add(struct platform_device *pdev) | |||
| 833 | if (read_method_int(adev->handle, "_CFG", &cfg)) | 848 | if (read_method_int(adev->handle, "_CFG", &cfg)) |
| 834 | return -ENODEV; | 849 | return -ENODEV; |
| 835 | 850 | ||
| 836 | priv = kzalloc(sizeof(*priv), GFP_KERNEL); | 851 | priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); |
| 837 | if (!priv) | 852 | if (!priv) |
| 838 | return -ENOMEM; | 853 | return -ENOMEM; |
| 839 | 854 | ||
| @@ -844,7 +859,7 @@ static int ideapad_acpi_add(struct platform_device *pdev) | |||
| 844 | 859 | ||
| 845 | ret = ideapad_sysfs_init(priv); | 860 | ret = ideapad_sysfs_init(priv); |
| 846 | if (ret) | 861 | if (ret) |
| 847 | goto sysfs_failed; | 862 | return ret; |
| 848 | 863 | ||
| 849 | ret = ideapad_debugfs_init(priv); | 864 | ret = ideapad_debugfs_init(priv); |
| 850 | if (ret) | 865 | if (ret) |
| @@ -854,11 +869,10 @@ static int ideapad_acpi_add(struct platform_device *pdev) | |||
| 854 | if (ret) | 869 | if (ret) |
| 855 | goto input_failed; | 870 | goto input_failed; |
| 856 | 871 | ||
| 857 | for (i = 0; i < IDEAPAD_RFKILL_DEV_NUM; i++) { | 872 | if (!dmi_check_system(rfkill_blacklist)) { |
| 858 | if (test_bit(ideapad_rfk_data[i].cfgbit, &priv->cfg)) | 873 | for (i = 0; i < IDEAPAD_RFKILL_DEV_NUM; i++) |
| 859 | ideapad_register_rfkill(priv, i); | 874 | if (test_bit(ideapad_rfk_data[i].cfgbit, &priv->cfg)) |
| 860 | else | 875 | ideapad_register_rfkill(priv, i); |
| 861 | priv->rfk[i] = NULL; | ||
| 862 | } | 876 | } |
| 863 | ideapad_sync_rfk_state(priv); | 877 | ideapad_sync_rfk_state(priv); |
| 864 | ideapad_sync_touchpad_state(priv); | 878 | ideapad_sync_touchpad_state(priv); |
| @@ -884,8 +898,6 @@ input_failed: | |||
| 884 | ideapad_debugfs_exit(priv); | 898 | ideapad_debugfs_exit(priv); |
| 885 | debugfs_failed: | 899 | debugfs_failed: |
| 886 | ideapad_sysfs_exit(priv); | 900 | ideapad_sysfs_exit(priv); |
| 887 | sysfs_failed: | ||
| 888 | kfree(priv); | ||
| 889 | return ret; | 901 | return ret; |
| 890 | } | 902 | } |
| 891 | 903 | ||
| @@ -903,7 +915,6 @@ static int ideapad_acpi_remove(struct platform_device *pdev) | |||
| 903 | ideapad_debugfs_exit(priv); | 915 | ideapad_debugfs_exit(priv); |
| 904 | ideapad_sysfs_exit(priv); | 916 | ideapad_sysfs_exit(priv); |
| 905 | dev_set_drvdata(&pdev->dev, NULL); | 917 | dev_set_drvdata(&pdev->dev, NULL); |
| 906 | kfree(priv); | ||
| 907 | 918 | ||
| 908 | return 0; | 919 | return 0; |
| 909 | } | 920 | } |
diff --git a/drivers/platform/x86/intel_mid_thermal.c b/drivers/platform/x86/intel_mid_thermal.c index 93fab8b70ce1..ab7860a21a22 100644 --- a/drivers/platform/x86/intel_mid_thermal.c +++ b/drivers/platform/x86/intel_mid_thermal.c | |||
| @@ -481,7 +481,8 @@ static int mid_thermal_probe(struct platform_device *pdev) | |||
| 481 | int i; | 481 | int i; |
| 482 | struct platform_info *pinfo; | 482 | struct platform_info *pinfo; |
| 483 | 483 | ||
| 484 | pinfo = kzalloc(sizeof(struct platform_info), GFP_KERNEL); | 484 | pinfo = devm_kzalloc(&pdev->dev, sizeof(struct platform_info), |
| 485 | GFP_KERNEL); | ||
| 485 | if (!pinfo) | 486 | if (!pinfo) |
| 486 | return -ENOMEM; | 487 | return -ENOMEM; |
| 487 | 488 | ||
| @@ -489,7 +490,6 @@ static int mid_thermal_probe(struct platform_device *pdev) | |||
| 489 | ret = mid_initialize_adc(&pdev->dev); | 490 | ret = mid_initialize_adc(&pdev->dev); |
| 490 | if (ret) { | 491 | if (ret) { |
| 491 | dev_err(&pdev->dev, "ADC init failed"); | 492 | dev_err(&pdev->dev, "ADC init failed"); |
| 492 | kfree(pinfo); | ||
| 493 | return ret; | 493 | return ret; |
| 494 | } | 494 | } |
| 495 | 495 | ||
| @@ -520,7 +520,6 @@ err: | |||
| 520 | thermal_zone_device_unregister(pinfo->tzd[i]); | 520 | thermal_zone_device_unregister(pinfo->tzd[i]); |
| 521 | } | 521 | } |
| 522 | configure_adc(0); | 522 | configure_adc(0); |
| 523 | kfree(pinfo); | ||
| 524 | return ret; | 523 | return ret; |
| 525 | } | 524 | } |
| 526 | 525 | ||
| @@ -541,8 +540,6 @@ static int mid_thermal_remove(struct platform_device *pdev) | |||
| 541 | thermal_zone_device_unregister(pinfo->tzd[i]); | 540 | thermal_zone_device_unregister(pinfo->tzd[i]); |
| 542 | } | 541 | } |
| 543 | 542 | ||
| 544 | kfree(pinfo); | ||
| 545 | |||
| 546 | /* Stop the ADC */ | 543 | /* Stop the ADC */ |
| 547 | return configure_adc(0); | 544 | return configure_adc(0); |
| 548 | } | 545 | } |
diff --git a/drivers/platform/x86/intel_pmic_gpio.c b/drivers/platform/x86/intel_pmic_gpio.c index 2805988485f6..40929e4f7ad7 100644 --- a/drivers/platform/x86/intel_pmic_gpio.c +++ b/drivers/platform/x86/intel_pmic_gpio.c | |||
| @@ -91,7 +91,7 @@ static void pmic_program_irqtype(int gpio, int type) | |||
| 91 | 91 | ||
| 92 | static int pmic_gpio_direction_input(struct gpio_chip *chip, unsigned offset) | 92 | static int pmic_gpio_direction_input(struct gpio_chip *chip, unsigned offset) |
| 93 | { | 93 | { |
| 94 | if (offset > 8) { | 94 | if (offset >= 8) { |
| 95 | pr_err("only pin 0-7 support input\n"); | 95 | pr_err("only pin 0-7 support input\n"); |
| 96 | return -1;/* we only have 8 GPIO can use as input */ | 96 | return -1;/* we only have 8 GPIO can use as input */ |
| 97 | } | 97 | } |
| @@ -130,7 +130,7 @@ static int pmic_gpio_get(struct gpio_chip *chip, unsigned offset) | |||
| 130 | int ret; | 130 | int ret; |
| 131 | 131 | ||
| 132 | /* we only have 8 GPIO pins we can use as input */ | 132 | /* we only have 8 GPIO pins we can use as input */ |
| 133 | if (offset > 8) | 133 | if (offset >= 8) |
| 134 | return -EOPNOTSUPP; | 134 | return -EOPNOTSUPP; |
| 135 | ret = intel_scu_ipc_ioread8(GPIO0 + offset, &r); | 135 | ret = intel_scu_ipc_ioread8(GPIO0 + offset, &r); |
| 136 | if (ret < 0) | 136 | if (ret < 0) |
diff --git a/drivers/platform/x86/pvpanic.c b/drivers/platform/x86/pvpanic.c index c9f6e511daa6..073a90a63dbc 100644 --- a/drivers/platform/x86/pvpanic.c +++ b/drivers/platform/x86/pvpanic.c | |||
| @@ -70,6 +70,7 @@ pvpanic_panic_notify(struct notifier_block *nb, unsigned long code, | |||
| 70 | 70 | ||
| 71 | static struct notifier_block pvpanic_panic_nb = { | 71 | static struct notifier_block pvpanic_panic_nb = { |
| 72 | .notifier_call = pvpanic_panic_notify, | 72 | .notifier_call = pvpanic_panic_notify, |
| 73 | .priority = 1, /* let this called before broken drm_fb_helper */ | ||
| 73 | }; | 74 | }; |
| 74 | 75 | ||
| 75 | 76 | ||
diff --git a/drivers/platform/x86/samsung-laptop.c b/drivers/platform/x86/samsung-laptop.c index d1f030053176..5a5966512277 100644 --- a/drivers/platform/x86/samsung-laptop.c +++ b/drivers/platform/x86/samsung-laptop.c | |||
| @@ -27,6 +27,7 @@ | |||
| 27 | #include <linux/debugfs.h> | 27 | #include <linux/debugfs.h> |
| 28 | #include <linux/ctype.h> | 28 | #include <linux/ctype.h> |
| 29 | #include <linux/efi.h> | 29 | #include <linux/efi.h> |
| 30 | #include <linux/suspend.h> | ||
| 30 | #include <acpi/video.h> | 31 | #include <acpi/video.h> |
| 31 | 32 | ||
| 32 | /* | 33 | /* |
| @@ -340,6 +341,8 @@ struct samsung_laptop { | |||
| 340 | struct samsung_laptop_debug debug; | 341 | struct samsung_laptop_debug debug; |
| 341 | struct samsung_quirks *quirks; | 342 | struct samsung_quirks *quirks; |
| 342 | 343 | ||
| 344 | struct notifier_block pm_nb; | ||
| 345 | |||
| 343 | bool handle_backlight; | 346 | bool handle_backlight; |
| 344 | bool has_stepping_quirk; | 347 | bool has_stepping_quirk; |
| 345 | 348 | ||
| @@ -348,6 +351,8 @@ struct samsung_laptop { | |||
| 348 | 351 | ||
| 349 | struct samsung_quirks { | 352 | struct samsung_quirks { |
| 350 | bool broken_acpi_video; | 353 | bool broken_acpi_video; |
| 354 | bool four_kbd_backlight_levels; | ||
| 355 | bool enable_kbd_backlight; | ||
| 351 | }; | 356 | }; |
| 352 | 357 | ||
| 353 | static struct samsung_quirks samsung_unknown = {}; | 358 | static struct samsung_quirks samsung_unknown = {}; |
| @@ -356,6 +361,11 @@ static struct samsung_quirks samsung_broken_acpi_video = { | |||
| 356 | .broken_acpi_video = true, | 361 | .broken_acpi_video = true, |
| 357 | }; | 362 | }; |
| 358 | 363 | ||
| 364 | static struct samsung_quirks samsung_np740u3e = { | ||
| 365 | .four_kbd_backlight_levels = true, | ||
| 366 | .enable_kbd_backlight = true, | ||
| 367 | }; | ||
| 368 | |||
| 359 | static bool force; | 369 | static bool force; |
| 360 | module_param(force, bool, 0); | 370 | module_param(force, bool, 0); |
| 361 | MODULE_PARM_DESC(force, | 371 | MODULE_PARM_DESC(force, |
| @@ -1051,6 +1061,8 @@ static int __init samsung_leds_init(struct samsung_laptop *samsung) | |||
| 1051 | samsung->kbd_led.brightness_set = kbd_led_set; | 1061 | samsung->kbd_led.brightness_set = kbd_led_set; |
| 1052 | samsung->kbd_led.brightness_get = kbd_led_get; | 1062 | samsung->kbd_led.brightness_get = kbd_led_get; |
| 1053 | samsung->kbd_led.max_brightness = 8; | 1063 | samsung->kbd_led.max_brightness = 8; |
| 1064 | if (samsung->quirks->four_kbd_backlight_levels) | ||
| 1065 | samsung->kbd_led.max_brightness = 4; | ||
| 1054 | 1066 | ||
| 1055 | ret = led_classdev_register(&samsung->platform_device->dev, | 1067 | ret = led_classdev_register(&samsung->platform_device->dev, |
| 1056 | &samsung->kbd_led); | 1068 | &samsung->kbd_led); |
| @@ -1414,6 +1426,19 @@ static void samsung_platform_exit(struct samsung_laptop *samsung) | |||
| 1414 | } | 1426 | } |
| 1415 | } | 1427 | } |
| 1416 | 1428 | ||
| 1429 | static int samsung_pm_notification(struct notifier_block *nb, | ||
| 1430 | unsigned long val, void *ptr) | ||
| 1431 | { | ||
| 1432 | struct samsung_laptop *samsung; | ||
| 1433 | |||
| 1434 | samsung = container_of(nb, struct samsung_laptop, pm_nb); | ||
| 1435 | if (val == PM_POST_HIBERNATION && | ||
| 1436 | samsung->quirks->enable_kbd_backlight) | ||
| 1437 | kbd_backlight_enable(samsung); | ||
| 1438 | |||
| 1439 | return 0; | ||
| 1440 | } | ||
| 1441 | |||
| 1417 | static int __init samsung_platform_init(struct samsung_laptop *samsung) | 1442 | static int __init samsung_platform_init(struct samsung_laptop *samsung) |
| 1418 | { | 1443 | { |
| 1419 | struct platform_device *pdev; | 1444 | struct platform_device *pdev; |
| @@ -1534,6 +1559,15 @@ static struct dmi_system_id __initdata samsung_dmi_table[] = { | |||
| 1534 | }, | 1559 | }, |
| 1535 | .driver_data = &samsung_broken_acpi_video, | 1560 | .driver_data = &samsung_broken_acpi_video, |
| 1536 | }, | 1561 | }, |
| 1562 | { | ||
| 1563 | .callback = samsung_dmi_matched, | ||
| 1564 | .ident = "730U3E/740U3E", | ||
| 1565 | .matches = { | ||
| 1566 | DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."), | ||
| 1567 | DMI_MATCH(DMI_PRODUCT_NAME, "730U3E/740U3E"), | ||
| 1568 | }, | ||
| 1569 | .driver_data = &samsung_np740u3e, | ||
| 1570 | }, | ||
| 1537 | { }, | 1571 | { }, |
| 1538 | }; | 1572 | }; |
| 1539 | MODULE_DEVICE_TABLE(dmi, samsung_dmi_table); | 1573 | MODULE_DEVICE_TABLE(dmi, samsung_dmi_table); |
| @@ -1608,6 +1642,9 @@ static int __init samsung_init(void) | |||
| 1608 | if (ret) | 1642 | if (ret) |
| 1609 | goto error_debugfs; | 1643 | goto error_debugfs; |
| 1610 | 1644 | ||
| 1645 | samsung->pm_nb.notifier_call = samsung_pm_notification; | ||
| 1646 | register_pm_notifier(&samsung->pm_nb); | ||
| 1647 | |||
| 1611 | samsung_platform_device = samsung->platform_device; | 1648 | samsung_platform_device = samsung->platform_device; |
| 1612 | return ret; | 1649 | return ret; |
| 1613 | 1650 | ||
| @@ -1633,6 +1670,7 @@ static void __exit samsung_exit(void) | |||
| 1633 | struct samsung_laptop *samsung; | 1670 | struct samsung_laptop *samsung; |
| 1634 | 1671 | ||
| 1635 | samsung = platform_get_drvdata(samsung_platform_device); | 1672 | samsung = platform_get_drvdata(samsung_platform_device); |
| 1673 | unregister_pm_notifier(&samsung->pm_nb); | ||
| 1636 | 1674 | ||
| 1637 | samsung_debugfs_exit(samsung); | 1675 | samsung_debugfs_exit(samsung); |
| 1638 | samsung_leds_exit(samsung); | 1676 | samsung_leds_exit(samsung); |
diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index 15e61c16736e..d82f196e3cfe 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c | |||
| @@ -3171,8 +3171,10 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) | |||
| 3171 | KEY_MICMUTE, /* 0x1a: Mic mute (since ?400 or so) */ | 3171 | KEY_MICMUTE, /* 0x1a: Mic mute (since ?400 or so) */ |
| 3172 | 3172 | ||
| 3173 | /* (assignments unknown, please report if found) */ | 3173 | /* (assignments unknown, please report if found) */ |
| 3174 | KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, | ||
| 3175 | KEY_UNKNOWN, | 3174 | KEY_UNKNOWN, |
| 3175 | |||
| 3176 | /* Extra keys in use since the X240 / T440 / T540 */ | ||
| 3177 | KEY_CONFIG, KEY_SEARCH, KEY_SCALE, KEY_COMPUTER, | ||
| 3176 | }, | 3178 | }, |
| 3177 | }; | 3179 | }; |
| 3178 | 3180 | ||
diff --git a/drivers/platform/x86/toshiba_acpi.c b/drivers/platform/x86/toshiba_acpi.c index 46473ca7566b..76441dcbe5ff 100644 --- a/drivers/platform/x86/toshiba_acpi.c +++ b/drivers/platform/x86/toshiba_acpi.c | |||
| @@ -56,6 +56,7 @@ | |||
| 56 | #include <linux/workqueue.h> | 56 | #include <linux/workqueue.h> |
| 57 | #include <linux/i8042.h> | 57 | #include <linux/i8042.h> |
| 58 | #include <linux/acpi.h> | 58 | #include <linux/acpi.h> |
| 59 | #include <linux/dmi.h> | ||
| 59 | #include <asm/uaccess.h> | 60 | #include <asm/uaccess.h> |
| 60 | 61 | ||
| 61 | MODULE_AUTHOR("John Belmonte"); | 62 | MODULE_AUTHOR("John Belmonte"); |
| @@ -213,6 +214,30 @@ static const struct key_entry toshiba_acpi_keymap[] = { | |||
| 213 | { KE_END, 0 }, | 214 | { KE_END, 0 }, |
| 214 | }; | 215 | }; |
| 215 | 216 | ||
| 217 | /* alternative keymap */ | ||
| 218 | static const struct dmi_system_id toshiba_alt_keymap_dmi[] = { | ||
| 219 | { | ||
| 220 | .matches = { | ||
| 221 | DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), | ||
| 222 | DMI_MATCH(DMI_PRODUCT_NAME, "Satellite M840"), | ||
| 223 | }, | ||
| 224 | }, | ||
| 225 | {} | ||
| 226 | }; | ||
| 227 | |||
| 228 | static const struct key_entry toshiba_acpi_alt_keymap[] = { | ||
| 229 | { KE_KEY, 0x157, { KEY_MUTE } }, | ||
| 230 | { KE_KEY, 0x102, { KEY_ZOOMOUT } }, | ||
| 231 | { KE_KEY, 0x103, { KEY_ZOOMIN } }, | ||
| 232 | { KE_KEY, 0x139, { KEY_ZOOMRESET } }, | ||
| 233 | { KE_KEY, 0x13e, { KEY_SWITCHVIDEOMODE } }, | ||
| 234 | { KE_KEY, 0x13c, { KEY_BRIGHTNESSDOWN } }, | ||
| 235 | { KE_KEY, 0x13d, { KEY_BRIGHTNESSUP } }, | ||
| 236 | { KE_KEY, 0x158, { KEY_WLAN } }, | ||
| 237 | { KE_KEY, 0x13f, { KEY_TOUCHPAD_TOGGLE } }, | ||
| 238 | { KE_END, 0 }, | ||
| 239 | }; | ||
| 240 | |||
| 216 | /* utility | 241 | /* utility |
| 217 | */ | 242 | */ |
| 218 | 243 | ||
| @@ -1440,6 +1465,7 @@ static int toshiba_acpi_setup_keyboard(struct toshiba_acpi_dev *dev) | |||
| 1440 | acpi_handle ec_handle; | 1465 | acpi_handle ec_handle; |
| 1441 | int error; | 1466 | int error; |
| 1442 | u32 hci_result; | 1467 | u32 hci_result; |
| 1468 | const struct key_entry *keymap = toshiba_acpi_keymap; | ||
| 1443 | 1469 | ||
| 1444 | dev->hotkey_dev = input_allocate_device(); | 1470 | dev->hotkey_dev = input_allocate_device(); |
| 1445 | if (!dev->hotkey_dev) | 1471 | if (!dev->hotkey_dev) |
| @@ -1449,7 +1475,9 @@ static int toshiba_acpi_setup_keyboard(struct toshiba_acpi_dev *dev) | |||
| 1449 | dev->hotkey_dev->phys = "toshiba_acpi/input0"; | 1475 | dev->hotkey_dev->phys = "toshiba_acpi/input0"; |
| 1450 | dev->hotkey_dev->id.bustype = BUS_HOST; | 1476 | dev->hotkey_dev->id.bustype = BUS_HOST; |
| 1451 | 1477 | ||
| 1452 | error = sparse_keymap_setup(dev->hotkey_dev, toshiba_acpi_keymap, NULL); | 1478 | if (dmi_check_system(toshiba_alt_keymap_dmi)) |
| 1479 | keymap = toshiba_acpi_alt_keymap; | ||
| 1480 | error = sparse_keymap_setup(dev->hotkey_dev, keymap, NULL); | ||
| 1453 | if (error) | 1481 | if (error) |
| 1454 | goto err_free_dev; | 1482 | goto err_free_dev; |
| 1455 | 1483 | ||
