Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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

+485 -65
+18
Documentation/platform/x86-laptop-drivers.txt
··· 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)
+20 -11
drivers/platform/x86/Kconfig
··· 102 102 default n 103 103 ---help--- 104 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 107 config DELL_WMI 108 108 tristate "Dell WMI extras" ··· 126 126 127 127 To compile this driver as a module, choose M here: the module will 128 128 be called dell-wmi-aio. 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. 129 139 130 140 131 141 config FUJITSU_LAPTOP ··· 275 265 R2, R3, R5, T2, W2 and Y2 series), say Y. 276 266 277 267 config COMPAL_LAPTOP 278 - tristate "Compal Laptop Extras" 268 + tristate "Compal (and others) Laptop Extras" 279 269 depends on ACPI 280 270 depends on BACKLIGHT_CLASS_DEVICE 281 271 depends on RFKILL 282 272 depends on HWMON 283 273 depends on POWER_SUPPLY 284 274 ---help--- 285 - This is a driver for laptops built by Compal: 275 + This is a driver for laptops built by Compal, and some models by 276 + other brands (e.g. Dell, Toshiba). 286 277 287 - Compal FL90/IFL90 288 - Compal FL91/IFL91 289 - Compal FL92/JFL92 290 - Compal FT00/IFT00 278 + It adds support for rfkill, Bluetooth, WLAN and LCD brightness 279 + control. 291 280 292 - It adds support for Bluetooth, WLAN and LCD brightness control. 293 - 294 - If you have an Compal FL9x/IFL9x/FT00 laptop, say Y or M here. 281 + For a (possibly incomplete) list of supported laptops, please refer 282 + to: Documentation/platform/x86-laptop-drivers.txt 295 283 296 284 config SONY_LAPTOP 297 285 tristate "Sony Laptop Extras" ··· 732 724 733 725 config XO1_RFKILL 734 726 tristate "OLPC XO-1 software RF kill switch" 735 - depends on OLPC 727 + depends on OLPC || COMPILE_TEST 736 728 depends on RFKILL 737 729 ---help--- 738 730 Support for enabling/disabling the WLAN interface on the OLPC XO-1 ··· 740 732 741 733 config XO15_EBOOK 742 734 tristate "OLPC XO-1.5 ebook switch" 735 + depends on OLPC || COMPILE_TEST 743 736 depends on ACPI && INPUT 744 737 ---help--- 745 738 Support for the ebook switch on the OLPC XO-1.5 laptop.
+1
drivers/platform/x86/Makefile
··· 13 13 obj-$(CONFIG_DELL_LAPTOP) += dell-laptop.o 14 14 obj-$(CONFIG_DELL_WMI) += dell-wmi.o 15 15 obj-$(CONFIG_DELL_WMI_AIO) += dell-wmi-aio.o 16 + obj-$(CONFIG_DELL_SMO8800) += dell-smo8800.o 16 17 obj-$(CONFIG_ACER_WMI) += acer-wmi.o 17 18 obj-$(CONFIG_ACERHDF) += acerhdf.o 18 19 obj-$(CONFIG_HP_ACCEL) += hp_accel.o
+89 -32
drivers/platform/x86/alienware-wmi.c
··· 32 32 #define WMAX_METHOD_HDMI_STATUS 0x2 33 33 #define WMAX_METHOD_BRIGHTNESS 0x3 34 34 #define WMAX_METHOD_ZONE_CONTROL 0x4 35 + #define WMAX_METHOD_HDMI_CABLE 0x5 35 36 36 37 MODULE_AUTHOR("Mario Limonciello <mario_limonciello@dell.com>"); 37 38 MODULE_DESCRIPTION("Alienware special feature control"); ··· 351 350 char *name; 352 351 353 352 if (interface == WMAX) { 354 - global_led.max_brightness = 100; 355 353 lighting_control_state = WMAX_RUNNING; 356 354 } else if (interface == LEGACY) { 357 - global_led.max_brightness = 0x0F; 358 355 lighting_control_state = LEGACY_RUNNING; 359 356 } 357 + global_led.max_brightness = 0x0F; 360 358 global_brightness = global_led.max_brightness; 361 359 362 360 /* ··· 423 423 The HDMI mux sysfs node indicates the status of the HDMI input mux. 424 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, 427 - char *buf) 426 + static acpi_status alienware_hdmi_command(struct hdmi_args *in_args, 427 + u32 command, int *out_data) 428 428 { 429 429 acpi_status status; 430 - struct acpi_buffer input; 431 430 union acpi_object *obj; 432 - u32 tmp = 0; 433 - struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; 431 + struct acpi_buffer input; 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 459 struct hdmi_args in_args = { 435 460 .arg = 0, 436 461 }; 437 - input.length = (acpi_size) sizeof(in_args); 438 - input.pointer = &in_args; 439 - status = wmi_evaluate_method(WMAX_CONTROL_GUID, 1, 440 - WMAX_METHOD_HDMI_STATUS, &input, &output); 462 + status = 463 + alienware_hdmi_command(&in_args, WMAX_METHOD_HDMI_CABLE, 464 + (u32 *) &out_data); 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 489 if (ACPI_SUCCESS(status)) { 443 - obj = (union acpi_object *)output.pointer; 444 - if (obj && obj->type == ACPI_TYPE_INTEGER) 445 - tmp = (u32) obj->integer.value; 446 - if (tmp == 1) 490 + if (out_data == 1) 447 491 return scnprintf(buf, PAGE_SIZE, 448 492 "[input] gpu unknown\n"); 449 - else if (tmp == 2) 493 + else if (out_data == 2) 450 494 return scnprintf(buf, PAGE_SIZE, 451 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 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, 458 - const char *buf, size_t count) 501 + static ssize_t toggle_hdmi_source(struct device *dev, 502 + struct device_attribute *attr, 503 + const char *buf, size_t count) 459 504 { 460 - struct acpi_buffer input; 461 505 acpi_status status; 462 506 struct hdmi_args args; 463 507 if (strcmp(buf, "gpu\n") == 0) ··· 511 467 else 512 468 args.arg = 3; 513 469 pr_debug("alienware-wmi: setting hdmi to %d : %s", args.arg, buf); 514 - input.length = (acpi_size) sizeof(args); 515 - input.pointer = &args; 516 - status = wmi_evaluate_method(WMAX_CONTROL_GUID, 1, 517 - WMAX_METHOD_HDMI_SOURCE, &input, NULL); 470 + 471 + status = alienware_hdmi_command(&args, WMAX_METHOD_HDMI_SOURCE, NULL); 472 + 518 473 if (ACPI_FAILURE(status)) 519 474 pr_err("alienware-wmi: HDMI toggle failed: results: %u\n", 520 475 status); 521 476 return count; 522 477 } 523 478 524 - static DEVICE_ATTR(hdmi, S_IRUGO | S_IWUSR, show_hdmi, toggle_hdmi); 479 + static DEVICE_ATTR(cable, S_IRUGO, show_hdmi_cable, NULL); 480 + static DEVICE_ATTR(source, S_IRUGO | S_IWUSR, show_hdmi_source, 481 + toggle_hdmi_source); 525 482 526 - static void remove_hdmi(struct platform_device *device) 483 + static struct attribute *hdmi_attrs[] = { 484 + &dev_attr_cable.attr, 485 + &dev_attr_source.attr, 486 + NULL, 487 + }; 488 + 489 + static struct attribute_group hdmi_attribute_group = { 490 + .name = "hdmi", 491 + .attrs = hdmi_attrs, 492 + }; 493 + 494 + static void remove_hdmi(struct platform_device *dev) 527 495 { 528 - device_remove_file(&device->dev, &dev_attr_hdmi); 496 + sysfs_remove_group(&dev->dev.kobj, &hdmi_attribute_group); 529 497 } 530 498 531 - static int create_hdmi(void) 499 + static int create_hdmi(struct platform_device *dev) 532 500 { 533 - int ret = -ENOMEM; 534 - ret = device_create_file(&platform_device->dev, &dev_attr_hdmi); 501 + int ret; 502 + 503 + ret = sysfs_create_group(&dev->dev.kobj, &hdmi_attribute_group); 535 504 if (ret) 536 505 goto error_create_hdmi; 537 506 return 0; 538 507 539 508 error_create_hdmi: 540 - remove_hdmi(platform_device); 509 + remove_hdmi(dev); 541 510 return ret; 542 511 } 543 512 ··· 584 527 goto fail_platform_device2; 585 528 586 529 if (interface == WMAX) { 587 - ret = create_hdmi(); 530 + ret = create_hdmi(platform_device); 588 531 if (ret) 589 532 goto fail_prep_hdmi; 590 533 }
+9
drivers/platform/x86/asus-nb-wmi.c
··· 137 137 }, 138 138 { 139 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 149 .ident = "ASUSTeK COMPUTER INC. X55A", 141 150 .matches = { 142 151 DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
+1 -3
drivers/platform/x86/asus-wmi.c
··· 266 266 struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; 267 267 acpi_status status; 268 268 union acpi_object *obj; 269 - u32 tmp; 269 + u32 tmp = 0; 270 270 271 271 status = wmi_evaluate_method(ASUS_WMI_MGMT_GUID, 1, method_id, 272 272 &input, &output); ··· 277 277 obj = (union acpi_object *)output.pointer; 278 278 if (obj && obj->type == ACPI_TYPE_INTEGER) 279 279 tmp = (u32) obj->integer.value; 280 - else 281 - tmp = 0; 282 280 283 281 if (retval) 284 282 *retval = tmp;
+233
drivers/platform/x86/dell-smo8800.c
··· 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");
+18
drivers/platform/x86/hp-wmi.c
··· 53 53 #define HPWMI_ALS_QUERY 0x3 54 54 #define HPWMI_HARDWARE_QUERY 0x4 55 55 #define HPWMI_WIRELESS_QUERY 0x5 56 + #define HPWMI_BIOS_QUERY 0x9 56 57 #define HPWMI_HOTKEY_QUERY 0xc 57 58 #define HPWMI_FEATURE_QUERY 0xd 58 59 #define HPWMI_WIRELESS2_QUERY 0x1b ··· 145 144 { KE_KEY, 0x2142, { KEY_MEDIA } }, 146 145 { KE_KEY, 0x213b, { KEY_INFO } }, 147 146 { KE_KEY, 0x2169, { KEY_DIRECTION } }, 147 + { KE_KEY, 0x216a, { KEY_SETUP } }, 148 148 { KE_KEY, 0x231b, { KEY_HELP } }, 149 149 { KE_END, 0 } 150 150 }; ··· 304 302 return ret; 305 303 306 304 return (state & 0x10) ? 1 : 0; 305 + } 306 + 307 + static int hp_wmi_enable_hotkeys(void) 308 + { 309 + int ret; 310 + int query = 0x6e; 311 + 312 + ret = hp_wmi_perform_query(HPWMI_BIOS_QUERY, 1, &query, sizeof(query), 313 + 0); 314 + 315 + if (ret) 316 + return -EINVAL; 317 + return 0; 307 318 } 308 319 309 320 static int hp_wmi_set_block(void *data, bool blocked) ··· 662 647 input_report_switch(hp_wmi_input_dev, SW_TABLET_MODE, 663 648 hp_wmi_tablet_state()); 664 649 input_sync(hp_wmi_input_dev); 650 + 651 + if (hp_wmi_bios_2009_later() == 4) 652 + hp_wmi_enable_hotkeys(); 665 653 666 654 status = wmi_install_notify_handler(HPWMI_EVENT_GUID, hp_wmi_notify, NULL); 667 655 if (ACPI_FAILURE(status)) {
+21 -10
drivers/platform/x86/ideapad-laptop.c
··· 36 36 #include <linux/debugfs.h> 37 37 #include <linux/seq_file.h> 38 38 #include <linux/i8042.h> 39 + #include <linux/dmi.h> 40 + #include <linux/device.h> 39 41 40 42 #define IDEAPAD_RFKILL_DEV_NUM (3) 41 43 ··· 821 819 } 822 820 } 823 821 822 + /* Blacklist for devices where the ideapad rfkill interface does not work */ 823 + static struct dmi_system_id rfkill_blacklist[] = { 824 + /* The Lenovo Yoga 2 11 always reports everything as blocked */ 825 + { 826 + .ident = "Lenovo Yoga 2 11", 827 + .matches = { 828 + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), 829 + DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo Yoga 2 11"), 830 + }, 831 + }, 832 + {} 833 + }; 834 + 824 835 static int ideapad_acpi_add(struct platform_device *pdev) 825 836 { 826 837 int ret, i; ··· 848 833 if (read_method_int(adev->handle, "_CFG", &cfg)) 849 834 return -ENODEV; 850 835 851 - priv = kzalloc(sizeof(*priv), GFP_KERNEL); 836 + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); 852 837 if (!priv) 853 838 return -ENOMEM; 854 839 ··· 859 844 860 845 ret = ideapad_sysfs_init(priv); 861 846 if (ret) 862 - goto sysfs_failed; 847 + return ret; 863 848 864 849 ret = ideapad_debugfs_init(priv); 865 850 if (ret) ··· 869 854 if (ret) 870 855 goto input_failed; 871 856 872 - for (i = 0; i < IDEAPAD_RFKILL_DEV_NUM; i++) { 873 - if (test_bit(ideapad_rfk_data[i].cfgbit, &priv->cfg)) 874 - ideapad_register_rfkill(priv, i); 875 - else 876 - priv->rfk[i] = NULL; 857 + if (!dmi_check_system(rfkill_blacklist)) { 858 + for (i = 0; i < IDEAPAD_RFKILL_DEV_NUM; i++) 859 + if (test_bit(ideapad_rfk_data[i].cfgbit, &priv->cfg)) 860 + ideapad_register_rfkill(priv, i); 877 861 } 878 862 ideapad_sync_rfk_state(priv); 879 863 ideapad_sync_touchpad_state(priv); ··· 898 884 ideapad_debugfs_exit(priv); 899 885 debugfs_failed: 900 886 ideapad_sysfs_exit(priv); 901 - sysfs_failed: 902 - kfree(priv); 903 887 return ret; 904 888 } 905 889 ··· 915 903 ideapad_debugfs_exit(priv); 916 904 ideapad_sysfs_exit(priv); 917 905 dev_set_drvdata(&pdev->dev, NULL); 918 - kfree(priv); 919 906 920 907 return 0; 921 908 }
+2 -5
drivers/platform/x86/intel_mid_thermal.c
··· 481 481 int i; 482 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 486 if (!pinfo) 486 487 return -ENOMEM; 487 488 ··· 490 489 ret = mid_initialize_adc(&pdev->dev); 491 490 if (ret) { 492 491 dev_err(&pdev->dev, "ADC init failed"); 493 - kfree(pinfo); 494 492 return ret; 495 493 } 496 494 ··· 520 520 thermal_zone_device_unregister(pinfo->tzd[i]); 521 521 } 522 522 configure_adc(0); 523 - kfree(pinfo); 524 523 return ret; 525 524 } 526 525 ··· 539 540 kfree(pinfo->tzd[i]->devdata); 540 541 thermal_zone_device_unregister(pinfo->tzd[i]); 541 542 } 542 - 543 - kfree(pinfo); 544 543 545 544 /* Stop the ADC */ 546 545 return configure_adc(0);
+2 -2
drivers/platform/x86/intel_pmic_gpio.c
··· 91 91 92 92 static int pmic_gpio_direction_input(struct gpio_chip *chip, unsigned offset) 93 93 { 94 - if (offset > 8) { 94 + if (offset >= 8) { 95 95 pr_err("only pin 0-7 support input\n"); 96 96 return -1;/* we only have 8 GPIO can use as input */ 97 97 } ··· 130 130 int ret; 131 131 132 132 /* we only have 8 GPIO pins we can use as input */ 133 - if (offset > 8) 133 + if (offset >= 8) 134 134 return -EOPNOTSUPP; 135 135 ret = intel_scu_ipc_ioread8(GPIO0 + offset, &r); 136 136 if (ret < 0)
+1
drivers/platform/x86/pvpanic.c
··· 70 70 71 71 static struct notifier_block pvpanic_panic_nb = { 72 72 .notifier_call = pvpanic_panic_notify, 73 + .priority = 1, /* let this called before broken drm_fb_helper */ 73 74 }; 74 75 75 76
+38
drivers/platform/x86/samsung-laptop.c
··· 27 27 #include <linux/debugfs.h> 28 28 #include <linux/ctype.h> 29 29 #include <linux/efi.h> 30 + #include <linux/suspend.h> 30 31 #include <acpi/video.h> 31 32 32 33 /* ··· 341 340 struct samsung_laptop_debug debug; 342 341 struct samsung_quirks *quirks; 343 342 343 + struct notifier_block pm_nb; 344 + 344 345 bool handle_backlight; 345 346 bool has_stepping_quirk; 346 347 ··· 351 348 352 349 struct samsung_quirks { 353 350 bool broken_acpi_video; 351 + bool four_kbd_backlight_levels; 352 + bool enable_kbd_backlight; 354 353 }; 355 354 356 355 static struct samsung_quirks samsung_unknown = {}; 357 356 358 357 static struct samsung_quirks samsung_broken_acpi_video = { 359 358 .broken_acpi_video = true, 359 + }; 360 + 361 + static struct samsung_quirks samsung_np740u3e = { 362 + .four_kbd_backlight_levels = true, 363 + .enable_kbd_backlight = true, 360 364 }; 361 365 362 366 static bool force; ··· 1061 1051 samsung->kbd_led.brightness_set = kbd_led_set; 1062 1052 samsung->kbd_led.brightness_get = kbd_led_get; 1063 1053 samsung->kbd_led.max_brightness = 8; 1054 + if (samsung->quirks->four_kbd_backlight_levels) 1055 + samsung->kbd_led.max_brightness = 4; 1064 1056 1065 1057 ret = led_classdev_register(&samsung->platform_device->dev, 1066 1058 &samsung->kbd_led); ··· 1426 1414 } 1427 1415 } 1428 1416 1417 + static int samsung_pm_notification(struct notifier_block *nb, 1418 + unsigned long val, void *ptr) 1419 + { 1420 + struct samsung_laptop *samsung; 1421 + 1422 + samsung = container_of(nb, struct samsung_laptop, pm_nb); 1423 + if (val == PM_POST_HIBERNATION && 1424 + samsung->quirks->enable_kbd_backlight) 1425 + kbd_backlight_enable(samsung); 1426 + 1427 + return 0; 1428 + } 1429 + 1429 1430 static int __init samsung_platform_init(struct samsung_laptop *samsung) 1430 1431 { 1431 1432 struct platform_device *pdev; ··· 1559 1534 }, 1560 1535 .driver_data = &samsung_broken_acpi_video, 1561 1536 }, 1537 + { 1538 + .callback = samsung_dmi_matched, 1539 + .ident = "730U3E/740U3E", 1540 + .matches = { 1541 + DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."), 1542 + DMI_MATCH(DMI_PRODUCT_NAME, "730U3E/740U3E"), 1543 + }, 1544 + .driver_data = &samsung_np740u3e, 1545 + }, 1562 1546 { }, 1563 1547 }; 1564 1548 MODULE_DEVICE_TABLE(dmi, samsung_dmi_table); ··· 1642 1608 if (ret) 1643 1609 goto error_debugfs; 1644 1610 1611 + samsung->pm_nb.notifier_call = samsung_pm_notification; 1612 + register_pm_notifier(&samsung->pm_nb); 1613 + 1645 1614 samsung_platform_device = samsung->platform_device; 1646 1615 return ret; 1647 1616 ··· 1670 1633 struct samsung_laptop *samsung; 1671 1634 1672 1635 samsung = platform_get_drvdata(samsung_platform_device); 1636 + unregister_pm_notifier(&samsung->pm_nb); 1673 1637 1674 1638 samsung_debugfs_exit(samsung); 1675 1639 samsung_leds_exit(samsung);
+3 -1
drivers/platform/x86/thinkpad_acpi.c
··· 3171 3171 KEY_MICMUTE, /* 0x1a: Mic mute (since ?400 or so) */ 3172 3172 3173 3173 /* (assignments unknown, please report if found) */ 3174 - KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, 3175 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
+29 -1
drivers/platform/x86/toshiba_acpi.c
··· 56 56 #include <linux/workqueue.h> 57 57 #include <linux/i8042.h> 58 58 #include <linux/acpi.h> 59 + #include <linux/dmi.h> 59 60 #include <asm/uaccess.h> 60 61 61 62 MODULE_AUTHOR("John Belmonte"); ··· 211 210 { KE_KEY, 0xb33, { KEY_PLAYPAUSE } }, 212 211 { KE_KEY, 0xb5a, { KEY_MEDIA } }, 213 212 { KE_IGNORE, 0x1430, { KEY_RESERVED } }, 213 + { KE_END, 0 }, 214 + }; 215 + 216 + /* alternative keymap */ 217 + static const struct dmi_system_id toshiba_alt_keymap_dmi[] = { 218 + { 219 + .matches = { 220 + DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), 221 + DMI_MATCH(DMI_PRODUCT_NAME, "Satellite M840"), 222 + }, 223 + }, 224 + {} 225 + }; 226 + 227 + static const struct key_entry toshiba_acpi_alt_keymap[] = { 228 + { KE_KEY, 0x157, { KEY_MUTE } }, 229 + { KE_KEY, 0x102, { KEY_ZOOMOUT } }, 230 + { KE_KEY, 0x103, { KEY_ZOOMIN } }, 231 + { KE_KEY, 0x139, { KEY_ZOOMRESET } }, 232 + { KE_KEY, 0x13e, { KEY_SWITCHVIDEOMODE } }, 233 + { KE_KEY, 0x13c, { KEY_BRIGHTNESSDOWN } }, 234 + { KE_KEY, 0x13d, { KEY_BRIGHTNESSUP } }, 235 + { KE_KEY, 0x158, { KEY_WLAN } }, 236 + { KE_KEY, 0x13f, { KEY_TOUCHPAD_TOGGLE } }, 214 237 { KE_END, 0 }, 215 238 }; 216 239 ··· 1465 1440 acpi_handle ec_handle; 1466 1441 int error; 1467 1442 u32 hci_result; 1443 + const struct key_entry *keymap = toshiba_acpi_keymap; 1468 1444 1469 1445 dev->hotkey_dev = input_allocate_device(); 1470 1446 if (!dev->hotkey_dev) ··· 1475 1449 dev->hotkey_dev->phys = "toshiba_acpi/input0"; 1476 1450 dev->hotkey_dev->id.bustype = BUS_HOST; 1477 1451 1478 - error = sparse_keymap_setup(dev->hotkey_dev, toshiba_acpi_keymap, NULL); 1452 + if (dmi_check_system(toshiba_alt_keymap_dmi)) 1453 + keymap = toshiba_acpi_alt_keymap; 1454 + error = sparse_keymap_setup(dev->hotkey_dev, keymap, NULL); 1479 1455 if (error) 1480 1456 goto err_free_dev; 1481 1457