diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2014-06-10 19:58:32 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2014-06-10 19:58:32 -0400 |
commit | 2937f5efa5754754daf46de745f67350f7f06ec2 (patch) | |
tree | 2b146ffc245cc78a6076585eddeda65ac2b6062f | |
parent | 9ee4d7a6538308a7681b638d2f35f2a301420355 (diff) | |
parent | f82bdd0d77b6bf0dea08a1d957ab45d503f328b1 (diff) |
Merge branch 'for_linus' of git://cavan.codon.org.uk/platform-drivers-x86
Pull x86 platform driver updates from Matthew Garrett:
"Very little of excitement here - the most significant is a new driver
for detecting device freefall on Dells, other than that it's pretty
much entirely minor fixes for specific machines"
* 'for_linus' of git://cavan.codon.org.uk/platform-drivers-x86:
hp-wmi: Enable hotkeys on some systems
thinkpad_acpi: Add mappings for F9 - F12 hotkeys on X240 / T440 / T540
platform: x86: dell-smo8800: Dell Latitude freefall driver (ACPI SMO8800/SMO8810)
ideapad_laptop: Introduce the use of the managed version of kzalloc
platform/x86: Fix run-time dependencies of OLPC drivers
platform: x86: asus-wmi.c: Cleaning up uninitialized variables
ix86/mid/thermal: Introduce the use of the managed version of kzalloc
platform x86 Kconfig: Refer to the laptop list in the Compal driver help
Documentation: Add list of laptop models supported by the Compal driver
ideapad-laptop: Blacklist rfkill control on the Lenovo Yoga 2 11
asus-wmi: Set WAPF to 4 for Asus X550CA
alienware-wmi: For WMAX HDMI method, introduce a way to query HDMI cable status
alienware-wmi: Update WMAX brightness method limit to 15
pvpanic: Set high notifier priority
platform/x86: samsung-laptop: Add support for Samsung's NP7[34]0U3E models.
toshiba_acpi: Add alternative keymap support for Satellite M840
platform-drivers-x86: intel_pmic_gpio: Fix off-by-one valid offset range check
-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 | ||