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
This commit is contained in:
commit
2937f5efa5
15 changed files with 485 additions and 65 deletions
18
Documentation/platform/x86-laptop-drivers.txt
Normal file
18
Documentation/platform/x86-laptop-drivers.txt
Normal file
|
@ -0,0 +1,18 @@
|
|||
compal-laptop
|
||||
=============
|
||||
List of supported hardware:
|
||||
|
||||
by Compal:
|
||||
Compal FL90/IFL90
|
||||
Compal FL91/IFL91
|
||||
Compal FL92/JFL92
|
||||
Compal FT00/IFT00
|
||||
|
||||
by Dell:
|
||||
Dell Vostro 1200
|
||||
Dell Mini 9 (Inspiron 910)
|
||||
Dell Mini 10 (Inspiron 1010)
|
||||
Dell Mini 10v (Inspiron 1011)
|
||||
Dell Mini 1012 (Inspiron 1012)
|
||||
Dell Inspiron 11z (Inspiron 1110)
|
||||
Dell Mini 12 (Inspiron 1210)
|
|
@ -102,7 +102,7 @@ config DELL_LAPTOP
|
|||
default n
|
||||
---help---
|
||||
This driver adds support for rfkill and backlight control to Dell
|
||||
laptops.
|
||||
laptops (except for some models covered by the Compal driver).
|
||||
|
||||
config DELL_WMI
|
||||
tristate "Dell WMI extras"
|
||||
|
@ -127,6 +127,16 @@ config DELL_WMI_AIO
|
|||
To compile this driver as a module, choose M here: the module will
|
||||
be called dell-wmi-aio.
|
||||
|
||||
config DELL_SMO8800
|
||||
tristate "Dell Latitude freefall driver (ACPI SMO8800/SMO8810)"
|
||||
depends on ACPI
|
||||
---help---
|
||||
Say Y here if you want to support SMO8800/SMO8810 freefall device
|
||||
on Dell Latitude laptops.
|
||||
|
||||
To compile this driver as a module, choose M here: the module will
|
||||
be called dell-smo8800.
|
||||
|
||||
|
||||
config FUJITSU_LAPTOP
|
||||
tristate "Fujitsu Laptop Extras"
|
||||
|
@ -265,23 +275,21 @@ config PANASONIC_LAPTOP
|
|||
R2, R3, R5, T2, W2 and Y2 series), say Y.
|
||||
|
||||
config COMPAL_LAPTOP
|
||||
tristate "Compal Laptop Extras"
|
||||
tristate "Compal (and others) Laptop Extras"
|
||||
depends on ACPI
|
||||
depends on BACKLIGHT_CLASS_DEVICE
|
||||
depends on RFKILL
|
||||
depends on HWMON
|
||||
depends on POWER_SUPPLY
|
||||
---help---
|
||||
This is a driver for laptops built by Compal:
|
||||
This is a driver for laptops built by Compal, and some models by
|
||||
other brands (e.g. Dell, Toshiba).
|
||||
|
||||
Compal FL90/IFL90
|
||||
Compal FL91/IFL91
|
||||
Compal FL92/JFL92
|
||||
Compal FT00/IFT00
|
||||
It adds support for rfkill, Bluetooth, WLAN and LCD brightness
|
||||
control.
|
||||
|
||||
It adds support for Bluetooth, WLAN and LCD brightness control.
|
||||
|
||||
If you have an Compal FL9x/IFL9x/FT00 laptop, say Y or M here.
|
||||
For a (possibly incomplete) list of supported laptops, please refer
|
||||
to: Documentation/platform/x86-laptop-drivers.txt
|
||||
|
||||
config SONY_LAPTOP
|
||||
tristate "Sony Laptop Extras"
|
||||
|
@ -724,7 +732,7 @@ config IBM_RTL
|
|||
|
||||
config XO1_RFKILL
|
||||
tristate "OLPC XO-1 software RF kill switch"
|
||||
depends on OLPC
|
||||
depends on OLPC || COMPILE_TEST
|
||||
depends on RFKILL
|
||||
---help---
|
||||
Support for enabling/disabling the WLAN interface on the OLPC XO-1
|
||||
|
@ -732,6 +740,7 @@ config XO1_RFKILL
|
|||
|
||||
config XO15_EBOOK
|
||||
tristate "OLPC XO-1.5 ebook switch"
|
||||
depends on OLPC || COMPILE_TEST
|
||||
depends on ACPI && INPUT
|
||||
---help---
|
||||
Support for the ebook switch on the OLPC XO-1.5 laptop.
|
||||
|
|
|
@ -13,6 +13,7 @@ obj-$(CONFIG_COMPAL_LAPTOP) += compal-laptop.o
|
|||
obj-$(CONFIG_DELL_LAPTOP) += dell-laptop.o
|
||||
obj-$(CONFIG_DELL_WMI) += dell-wmi.o
|
||||
obj-$(CONFIG_DELL_WMI_AIO) += dell-wmi-aio.o
|
||||
obj-$(CONFIG_DELL_SMO8800) += dell-smo8800.o
|
||||
obj-$(CONFIG_ACER_WMI) += acer-wmi.o
|
||||
obj-$(CONFIG_ACERHDF) += acerhdf.o
|
||||
obj-$(CONFIG_HP_ACCEL) += hp_accel.o
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
#define WMAX_METHOD_HDMI_STATUS 0x2
|
||||
#define WMAX_METHOD_BRIGHTNESS 0x3
|
||||
#define WMAX_METHOD_ZONE_CONTROL 0x4
|
||||
#define WMAX_METHOD_HDMI_CABLE 0x5
|
||||
|
||||
MODULE_AUTHOR("Mario Limonciello <mario_limonciello@dell.com>");
|
||||
MODULE_DESCRIPTION("Alienware special feature control");
|
||||
|
@ -350,12 +351,11 @@ static int alienware_zone_init(struct platform_device *dev)
|
|||
char *name;
|
||||
|
||||
if (interface == WMAX) {
|
||||
global_led.max_brightness = 100;
|
||||
lighting_control_state = WMAX_RUNNING;
|
||||
} else if (interface == LEGACY) {
|
||||
global_led.max_brightness = 0x0F;
|
||||
lighting_control_state = LEGACY_RUNNING;
|
||||
}
|
||||
global_led.max_brightness = 0x0F;
|
||||
global_brightness = global_led.max_brightness;
|
||||
|
||||
/*
|
||||
|
@ -423,41 +423,85 @@ static void alienware_zone_exit(struct platform_device *dev)
|
|||
The HDMI mux sysfs node indicates the status of the HDMI input mux.
|
||||
It can toggle between standard system GPU output and HDMI input.
|
||||
*/
|
||||
static ssize_t show_hdmi(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
static acpi_status alienware_hdmi_command(struct hdmi_args *in_args,
|
||||
u32 command, int *out_data)
|
||||
{
|
||||
acpi_status status;
|
||||
struct acpi_buffer input;
|
||||
union acpi_object *obj;
|
||||
u32 tmp = 0;
|
||||
struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
|
||||
struct acpi_buffer input;
|
||||
struct acpi_buffer output;
|
||||
|
||||
input.length = (acpi_size) sizeof(*in_args);
|
||||
input.pointer = in_args;
|
||||
if (out_data != NULL) {
|
||||
output.length = ACPI_ALLOCATE_BUFFER;
|
||||
output.pointer = NULL;
|
||||
status = wmi_evaluate_method(WMAX_CONTROL_GUID, 1,
|
||||
command, &input, &output);
|
||||
} else
|
||||
status = wmi_evaluate_method(WMAX_CONTROL_GUID, 1,
|
||||
command, &input, NULL);
|
||||
|
||||
if (ACPI_SUCCESS(status) && out_data != NULL) {
|
||||
obj = (union acpi_object *)output.pointer;
|
||||
if (obj && obj->type == ACPI_TYPE_INTEGER)
|
||||
*out_data = (u32) obj->integer.value;
|
||||
}
|
||||
return status;
|
||||
|
||||
}
|
||||
|
||||
static ssize_t show_hdmi_cable(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
acpi_status status;
|
||||
u32 out_data;
|
||||
struct hdmi_args in_args = {
|
||||
.arg = 0,
|
||||
};
|
||||
input.length = (acpi_size) sizeof(in_args);
|
||||
input.pointer = &in_args;
|
||||
status = wmi_evaluate_method(WMAX_CONTROL_GUID, 1,
|
||||
WMAX_METHOD_HDMI_STATUS, &input, &output);
|
||||
status =
|
||||
alienware_hdmi_command(&in_args, WMAX_METHOD_HDMI_CABLE,
|
||||
(u32 *) &out_data);
|
||||
if (ACPI_SUCCESS(status)) {
|
||||
if (out_data == 0)
|
||||
return scnprintf(buf, PAGE_SIZE,
|
||||
"[unconnected] connected unknown\n");
|
||||
else if (out_data == 1)
|
||||
return scnprintf(buf, PAGE_SIZE,
|
||||
"unconnected [connected] unknown\n");
|
||||
}
|
||||
pr_err("alienware-wmi: unknown HDMI cable status: %d\n", status);
|
||||
return scnprintf(buf, PAGE_SIZE, "unconnected connected [unknown]\n");
|
||||
}
|
||||
|
||||
static ssize_t show_hdmi_source(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
acpi_status status;
|
||||
u32 out_data;
|
||||
struct hdmi_args in_args = {
|
||||
.arg = 0,
|
||||
};
|
||||
status =
|
||||
alienware_hdmi_command(&in_args, WMAX_METHOD_HDMI_STATUS,
|
||||
(u32 *) &out_data);
|
||||
|
||||
if (ACPI_SUCCESS(status)) {
|
||||
obj = (union acpi_object *)output.pointer;
|
||||
if (obj && obj->type == ACPI_TYPE_INTEGER)
|
||||
tmp = (u32) obj->integer.value;
|
||||
if (tmp == 1)
|
||||
if (out_data == 1)
|
||||
return scnprintf(buf, PAGE_SIZE,
|
||||
"[input] gpu unknown\n");
|
||||
else if (tmp == 2)
|
||||
else if (out_data == 2)
|
||||
return scnprintf(buf, PAGE_SIZE,
|
||||
"input [gpu] unknown\n");
|
||||
}
|
||||
pr_err("alienware-wmi: unknown HDMI status: %d\n", status);
|
||||
pr_err("alienware-wmi: unknown HDMI source status: %d\n", out_data);
|
||||
return scnprintf(buf, PAGE_SIZE, "input gpu [unknown]\n");
|
||||
}
|
||||
|
||||
static ssize_t toggle_hdmi(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
static ssize_t toggle_hdmi_source(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct acpi_buffer input;
|
||||
acpi_status status;
|
||||
struct hdmi_args args;
|
||||
if (strcmp(buf, "gpu\n") == 0)
|
||||
|
@ -467,33 +511,46 @@ static ssize_t toggle_hdmi(struct device *dev, struct device_attribute *attr,
|
|||
else
|
||||
args.arg = 3;
|
||||
pr_debug("alienware-wmi: setting hdmi to %d : %s", args.arg, buf);
|
||||
input.length = (acpi_size) sizeof(args);
|
||||
input.pointer = &args;
|
||||
status = wmi_evaluate_method(WMAX_CONTROL_GUID, 1,
|
||||
WMAX_METHOD_HDMI_SOURCE, &input, NULL);
|
||||
|
||||
status = alienware_hdmi_command(&args, WMAX_METHOD_HDMI_SOURCE, NULL);
|
||||
|
||||
if (ACPI_FAILURE(status))
|
||||
pr_err("alienware-wmi: HDMI toggle failed: results: %u\n",
|
||||
status);
|
||||
return count;
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(hdmi, S_IRUGO | S_IWUSR, show_hdmi, toggle_hdmi);
|
||||
static DEVICE_ATTR(cable, S_IRUGO, show_hdmi_cable, NULL);
|
||||
static DEVICE_ATTR(source, S_IRUGO | S_IWUSR, show_hdmi_source,
|
||||
toggle_hdmi_source);
|
||||
|
||||
static void remove_hdmi(struct platform_device *device)
|
||||
static struct attribute *hdmi_attrs[] = {
|
||||
&dev_attr_cable.attr,
|
||||
&dev_attr_source.attr,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static struct attribute_group hdmi_attribute_group = {
|
||||
.name = "hdmi",
|
||||
.attrs = hdmi_attrs,
|
||||
};
|
||||
|
||||
static void remove_hdmi(struct platform_device *dev)
|
||||
{
|
||||
device_remove_file(&device->dev, &dev_attr_hdmi);
|
||||
sysfs_remove_group(&dev->dev.kobj, &hdmi_attribute_group);
|
||||
}
|
||||
|
||||
static int create_hdmi(void)
|
||||
static int create_hdmi(struct platform_device *dev)
|
||||
{
|
||||
int ret = -ENOMEM;
|
||||
ret = device_create_file(&platform_device->dev, &dev_attr_hdmi);
|
||||
int ret;
|
||||
|
||||
ret = sysfs_create_group(&dev->dev.kobj, &hdmi_attribute_group);
|
||||
if (ret)
|
||||
goto error_create_hdmi;
|
||||
return 0;
|
||||
|
||||
error_create_hdmi:
|
||||
remove_hdmi(platform_device);
|
||||
remove_hdmi(dev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -527,7 +584,7 @@ static int __init alienware_wmi_init(void)
|
|||
goto fail_platform_device2;
|
||||
|
||||
if (interface == WMAX) {
|
||||
ret = create_hdmi();
|
||||
ret = create_hdmi(platform_device);
|
||||
if (ret)
|
||||
goto fail_prep_hdmi;
|
||||
}
|
||||
|
|
|
@ -135,6 +135,15 @@ static struct dmi_system_id asus_quirks[] = {
|
|||
},
|
||||
.driver_data = &quirk_asus_x401u,
|
||||
},
|
||||
{
|
||||
.callback = dmi_matched,
|
||||
.ident = "ASUSTeK COMPUTER INC. X550CA",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "X550CA"),
|
||||
},
|
||||
.driver_data = &quirk_asus_x401u,
|
||||
},
|
||||
{
|
||||
.callback = dmi_matched,
|
||||
.ident = "ASUSTeK COMPUTER INC. X55A",
|
||||
|
|
|
@ -266,7 +266,7 @@ static int asus_wmi_evaluate_method(u32 method_id, u32 arg0, u32 arg1,
|
|||
struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
|
||||
acpi_status status;
|
||||
union acpi_object *obj;
|
||||
u32 tmp;
|
||||
u32 tmp = 0;
|
||||
|
||||
status = wmi_evaluate_method(ASUS_WMI_MGMT_GUID, 1, method_id,
|
||||
&input, &output);
|
||||
|
@ -277,8 +277,6 @@ static int asus_wmi_evaluate_method(u32 method_id, u32 arg0, u32 arg1,
|
|||
obj = (union acpi_object *)output.pointer;
|
||||
if (obj && obj->type == ACPI_TYPE_INTEGER)
|
||||
tmp = (u32) obj->integer.value;
|
||||
else
|
||||
tmp = 0;
|
||||
|
||||
if (retval)
|
||||
*retval = tmp;
|
||||
|
|
233
drivers/platform/x86/dell-smo8800.c
Normal file
233
drivers/platform/x86/dell-smo8800.c
Normal file
|
@ -0,0 +1,233 @@
|
|||
/*
|
||||
* dell-smo8800.c - Dell Latitude ACPI SMO8800/SMO8810 freefall sensor driver
|
||||
*
|
||||
* Copyright (C) 2012 Sonal Santan <sonal.santan@gmail.com>
|
||||
* Copyright (C) 2014 Pali Rohár <pali.rohar@gmail.com>
|
||||
*
|
||||
* This is loosely based on lis3lv02d driver.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#define DRIVER_NAME "smo8800"
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/miscdevice.h>
|
||||
|
||||
struct smo8800_device {
|
||||
u32 irq; /* acpi device irq */
|
||||
atomic_t counter; /* count after last read */
|
||||
struct miscdevice miscdev; /* for /dev/freefall */
|
||||
unsigned long misc_opened; /* whether the device is open */
|
||||
wait_queue_head_t misc_wait; /* Wait queue for the misc dev */
|
||||
struct device *dev; /* acpi device */
|
||||
};
|
||||
|
||||
static irqreturn_t smo8800_interrupt_quick(int irq, void *data)
|
||||
{
|
||||
struct smo8800_device *smo8800 = data;
|
||||
|
||||
atomic_inc(&smo8800->counter);
|
||||
wake_up_interruptible(&smo8800->misc_wait);
|
||||
return IRQ_WAKE_THREAD;
|
||||
}
|
||||
|
||||
static irqreturn_t smo8800_interrupt_thread(int irq, void *data)
|
||||
{
|
||||
struct smo8800_device *smo8800 = data;
|
||||
|
||||
dev_info(smo8800->dev, "detected free fall\n");
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static acpi_status smo8800_get_resource(struct acpi_resource *resource,
|
||||
void *context)
|
||||
{
|
||||
struct acpi_resource_extended_irq *irq;
|
||||
|
||||
if (resource->type != ACPI_RESOURCE_TYPE_EXTENDED_IRQ)
|
||||
return AE_OK;
|
||||
|
||||
irq = &resource->data.extended_irq;
|
||||
if (!irq || !irq->interrupt_count)
|
||||
return AE_OK;
|
||||
|
||||
*((u32 *)context) = irq->interrupts[0];
|
||||
return AE_CTRL_TERMINATE;
|
||||
}
|
||||
|
||||
static u32 smo8800_get_irq(struct acpi_device *device)
|
||||
{
|
||||
u32 irq = 0;
|
||||
acpi_status status;
|
||||
|
||||
status = acpi_walk_resources(device->handle, METHOD_NAME__CRS,
|
||||
smo8800_get_resource, &irq);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
dev_err(&device->dev, "acpi_walk_resources failed\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return irq;
|
||||
}
|
||||
|
||||
static ssize_t smo8800_misc_read(struct file *file, char __user *buf,
|
||||
size_t count, loff_t *pos)
|
||||
{
|
||||
struct smo8800_device *smo8800 = container_of(file->private_data,
|
||||
struct smo8800_device, miscdev);
|
||||
|
||||
u32 data = 0;
|
||||
unsigned char byte_data = 0;
|
||||
ssize_t retval = 1;
|
||||
|
||||
if (count < 1)
|
||||
return -EINVAL;
|
||||
|
||||
atomic_set(&smo8800->counter, 0);
|
||||
retval = wait_event_interruptible(smo8800->misc_wait,
|
||||
(data = atomic_xchg(&smo8800->counter, 0)));
|
||||
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
byte_data = 1;
|
||||
retval = 1;
|
||||
|
||||
if (data < 255)
|
||||
byte_data = data;
|
||||
else
|
||||
byte_data = 255;
|
||||
|
||||
if (put_user(byte_data, buf))
|
||||
retval = -EFAULT;
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int smo8800_misc_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct smo8800_device *smo8800 = container_of(file->private_data,
|
||||
struct smo8800_device, miscdev);
|
||||
|
||||
if (test_and_set_bit(0, &smo8800->misc_opened))
|
||||
return -EBUSY; /* already open */
|
||||
|
||||
atomic_set(&smo8800->counter, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int smo8800_misc_release(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct smo8800_device *smo8800 = container_of(file->private_data,
|
||||
struct smo8800_device, miscdev);
|
||||
|
||||
clear_bit(0, &smo8800->misc_opened); /* release the device */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct file_operations smo8800_misc_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.read = smo8800_misc_read,
|
||||
.open = smo8800_misc_open,
|
||||
.release = smo8800_misc_release,
|
||||
};
|
||||
|
||||
static int smo8800_add(struct acpi_device *device)
|
||||
{
|
||||
int err;
|
||||
struct smo8800_device *smo8800;
|
||||
|
||||
smo8800 = devm_kzalloc(&device->dev, sizeof(*smo8800), GFP_KERNEL);
|
||||
if (!smo8800) {
|
||||
dev_err(&device->dev, "failed to allocate device data\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
smo8800->dev = &device->dev;
|
||||
smo8800->miscdev.minor = MISC_DYNAMIC_MINOR;
|
||||
smo8800->miscdev.name = "freefall";
|
||||
smo8800->miscdev.fops = &smo8800_misc_fops;
|
||||
|
||||
init_waitqueue_head(&smo8800->misc_wait);
|
||||
|
||||
err = misc_register(&smo8800->miscdev);
|
||||
if (err) {
|
||||
dev_err(&device->dev, "failed to register misc dev: %d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
device->driver_data = smo8800;
|
||||
|
||||
smo8800->irq = smo8800_get_irq(device);
|
||||
if (!smo8800->irq) {
|
||||
dev_err(&device->dev, "failed to obtain IRQ\n");
|
||||
err = -EINVAL;
|
||||
goto error;
|
||||
}
|
||||
|
||||
err = request_threaded_irq(smo8800->irq, smo8800_interrupt_quick,
|
||||
smo8800_interrupt_thread,
|
||||
IRQF_TRIGGER_RISING | IRQF_ONESHOT,
|
||||
DRIVER_NAME, smo8800);
|
||||
if (err) {
|
||||
dev_err(&device->dev,
|
||||
"failed to request thread for IRQ %d: %d\n",
|
||||
smo8800->irq, err);
|
||||
goto error;
|
||||
}
|
||||
|
||||
dev_dbg(&device->dev, "device /dev/freefall registered with IRQ %d\n",
|
||||
smo8800->irq);
|
||||
return 0;
|
||||
|
||||
error:
|
||||
misc_deregister(&smo8800->miscdev);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int smo8800_remove(struct acpi_device *device)
|
||||
{
|
||||
struct smo8800_device *smo8800 = device->driver_data;
|
||||
|
||||
free_irq(smo8800->irq, smo8800);
|
||||
misc_deregister(&smo8800->miscdev);
|
||||
dev_dbg(&device->dev, "device /dev/freefall unregistered\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct acpi_device_id smo8800_ids[] = {
|
||||
{ "SMO8800", 0 },
|
||||
{ "SMO8810", 0 },
|
||||
{ "", 0 },
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(acpi, smo8800_ids);
|
||||
|
||||
static struct acpi_driver smo8800_driver = {
|
||||
.name = DRIVER_NAME,
|
||||
.class = "Latitude",
|
||||
.ids = smo8800_ids,
|
||||
.ops = {
|
||||
.add = smo8800_add,
|
||||
.remove = smo8800_remove,
|
||||
},
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
module_acpi_driver(smo8800_driver);
|
||||
|
||||
MODULE_DESCRIPTION("Dell Latitude freefall driver (ACPI SMO8800/SMO8810)");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Sonal Santan, Pali Rohár");
|
|
@ -53,6 +53,7 @@ MODULE_ALIAS("wmi:5FB7F034-2C63-45e9-BE91-3D44E2C707E4");
|
|||
#define HPWMI_ALS_QUERY 0x3
|
||||
#define HPWMI_HARDWARE_QUERY 0x4
|
||||
#define HPWMI_WIRELESS_QUERY 0x5
|
||||
#define HPWMI_BIOS_QUERY 0x9
|
||||
#define HPWMI_HOTKEY_QUERY 0xc
|
||||
#define HPWMI_FEATURE_QUERY 0xd
|
||||
#define HPWMI_WIRELESS2_QUERY 0x1b
|
||||
|
@ -144,6 +145,7 @@ static const struct key_entry hp_wmi_keymap[] = {
|
|||
{ KE_KEY, 0x2142, { KEY_MEDIA } },
|
||||
{ KE_KEY, 0x213b, { KEY_INFO } },
|
||||
{ KE_KEY, 0x2169, { KEY_DIRECTION } },
|
||||
{ KE_KEY, 0x216a, { KEY_SETUP } },
|
||||
{ KE_KEY, 0x231b, { KEY_HELP } },
|
||||
{ KE_END, 0 }
|
||||
};
|
||||
|
@ -304,6 +306,19 @@ static int hp_wmi_bios_2009_later(void)
|
|||
return (state & 0x10) ? 1 : 0;
|
||||
}
|
||||
|
||||
static int hp_wmi_enable_hotkeys(void)
|
||||
{
|
||||
int ret;
|
||||
int query = 0x6e;
|
||||
|
||||
ret = hp_wmi_perform_query(HPWMI_BIOS_QUERY, 1, &query, sizeof(query),
|
||||
0);
|
||||
|
||||
if (ret)
|
||||
return -EINVAL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int hp_wmi_set_block(void *data, bool blocked)
|
||||
{
|
||||
enum hp_wmi_radio r = (enum hp_wmi_radio) data;
|
||||
|
@ -648,6 +663,9 @@ static int __init hp_wmi_input_setup(void)
|
|||
hp_wmi_tablet_state());
|
||||
input_sync(hp_wmi_input_dev);
|
||||
|
||||
if (hp_wmi_bios_2009_later() == 4)
|
||||
hp_wmi_enable_hotkeys();
|
||||
|
||||
status = wmi_install_notify_handler(HPWMI_EVENT_GUID, hp_wmi_notify, NULL);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
err = -EIO;
|
||||
|
|
|
@ -36,6 +36,8 @@
|
|||
#include <linux/debugfs.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/i8042.h>
|
||||
#include <linux/dmi.h>
|
||||
#include <linux/device.h>
|
||||
|
||||
#define IDEAPAD_RFKILL_DEV_NUM (3)
|
||||
|
||||
|
@ -819,6 +821,19 @@ static void ideapad_acpi_notify(acpi_handle handle, u32 event, void *data)
|
|||
}
|
||||
}
|
||||
|
||||
/* Blacklist for devices where the ideapad rfkill interface does not work */
|
||||
static struct dmi_system_id rfkill_blacklist[] = {
|
||||
/* The Lenovo Yoga 2 11 always reports everything as blocked */
|
||||
{
|
||||
.ident = "Lenovo Yoga 2 11",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
|
||||
DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo Yoga 2 11"),
|
||||
},
|
||||
},
|
||||
{}
|
||||
};
|
||||
|
||||
static int ideapad_acpi_add(struct platform_device *pdev)
|
||||
{
|
||||
int ret, i;
|
||||
|
@ -833,7 +848,7 @@ static int ideapad_acpi_add(struct platform_device *pdev)
|
|||
if (read_method_int(adev->handle, "_CFG", &cfg))
|
||||
return -ENODEV;
|
||||
|
||||
priv = kzalloc(sizeof(*priv), GFP_KERNEL);
|
||||
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
|
||||
|
@ -844,7 +859,7 @@ static int ideapad_acpi_add(struct platform_device *pdev)
|
|||
|
||||
ret = ideapad_sysfs_init(priv);
|
||||
if (ret)
|
||||
goto sysfs_failed;
|
||||
return ret;
|
||||
|
||||
ret = ideapad_debugfs_init(priv);
|
||||
if (ret)
|
||||
|
@ -854,11 +869,10 @@ static int ideapad_acpi_add(struct platform_device *pdev)
|
|||
if (ret)
|
||||
goto input_failed;
|
||||
|
||||
for (i = 0; i < IDEAPAD_RFKILL_DEV_NUM; i++) {
|
||||
if (test_bit(ideapad_rfk_data[i].cfgbit, &priv->cfg))
|
||||
ideapad_register_rfkill(priv, i);
|
||||
else
|
||||
priv->rfk[i] = NULL;
|
||||
if (!dmi_check_system(rfkill_blacklist)) {
|
||||
for (i = 0; i < IDEAPAD_RFKILL_DEV_NUM; i++)
|
||||
if (test_bit(ideapad_rfk_data[i].cfgbit, &priv->cfg))
|
||||
ideapad_register_rfkill(priv, i);
|
||||
}
|
||||
ideapad_sync_rfk_state(priv);
|
||||
ideapad_sync_touchpad_state(priv);
|
||||
|
@ -884,8 +898,6 @@ static int ideapad_acpi_add(struct platform_device *pdev)
|
|||
ideapad_debugfs_exit(priv);
|
||||
debugfs_failed:
|
||||
ideapad_sysfs_exit(priv);
|
||||
sysfs_failed:
|
||||
kfree(priv);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -903,7 +915,6 @@ static int ideapad_acpi_remove(struct platform_device *pdev)
|
|||
ideapad_debugfs_exit(priv);
|
||||
ideapad_sysfs_exit(priv);
|
||||
dev_set_drvdata(&pdev->dev, NULL);
|
||||
kfree(priv);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -481,7 +481,8 @@ static int mid_thermal_probe(struct platform_device *pdev)
|
|||
int i;
|
||||
struct platform_info *pinfo;
|
||||
|
||||
pinfo = kzalloc(sizeof(struct platform_info), GFP_KERNEL);
|
||||
pinfo = devm_kzalloc(&pdev->dev, sizeof(struct platform_info),
|
||||
GFP_KERNEL);
|
||||
if (!pinfo)
|
||||
return -ENOMEM;
|
||||
|
||||
|
@ -489,7 +490,6 @@ static int mid_thermal_probe(struct platform_device *pdev)
|
|||
ret = mid_initialize_adc(&pdev->dev);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "ADC init failed");
|
||||
kfree(pinfo);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -520,7 +520,6 @@ static int mid_thermal_probe(struct platform_device *pdev)
|
|||
thermal_zone_device_unregister(pinfo->tzd[i]);
|
||||
}
|
||||
configure_adc(0);
|
||||
kfree(pinfo);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -541,8 +540,6 @@ static int mid_thermal_remove(struct platform_device *pdev)
|
|||
thermal_zone_device_unregister(pinfo->tzd[i]);
|
||||
}
|
||||
|
||||
kfree(pinfo);
|
||||
|
||||
/* Stop the ADC */
|
||||
return configure_adc(0);
|
||||
}
|
||||
|
|
|
@ -91,7 +91,7 @@ static void pmic_program_irqtype(int gpio, int type)
|
|||
|
||||
static int pmic_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
|
||||
{
|
||||
if (offset > 8) {
|
||||
if (offset >= 8) {
|
||||
pr_err("only pin 0-7 support input\n");
|
||||
return -1;/* we only have 8 GPIO can use as input */
|
||||
}
|
||||
|
@ -130,7 +130,7 @@ static int pmic_gpio_get(struct gpio_chip *chip, unsigned offset)
|
|||
int ret;
|
||||
|
||||
/* we only have 8 GPIO pins we can use as input */
|
||||
if (offset > 8)
|
||||
if (offset >= 8)
|
||||
return -EOPNOTSUPP;
|
||||
ret = intel_scu_ipc_ioread8(GPIO0 + offset, &r);
|
||||
if (ret < 0)
|
||||
|
|
|
@ -70,6 +70,7 @@ pvpanic_panic_notify(struct notifier_block *nb, unsigned long code,
|
|||
|
||||
static struct notifier_block pvpanic_panic_nb = {
|
||||
.notifier_call = pvpanic_panic_notify,
|
||||
.priority = 1, /* let this called before broken drm_fb_helper */
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
#include <linux/debugfs.h>
|
||||
#include <linux/ctype.h>
|
||||
#include <linux/efi.h>
|
||||
#include <linux/suspend.h>
|
||||
#include <acpi/video.h>
|
||||
|
||||
/*
|
||||
|
@ -340,6 +341,8 @@ struct samsung_laptop {
|
|||
struct samsung_laptop_debug debug;
|
||||
struct samsung_quirks *quirks;
|
||||
|
||||
struct notifier_block pm_nb;
|
||||
|
||||
bool handle_backlight;
|
||||
bool has_stepping_quirk;
|
||||
|
||||
|
@ -348,6 +351,8 @@ struct samsung_laptop {
|
|||
|
||||
struct samsung_quirks {
|
||||
bool broken_acpi_video;
|
||||
bool four_kbd_backlight_levels;
|
||||
bool enable_kbd_backlight;
|
||||
};
|
||||
|
||||
static struct samsung_quirks samsung_unknown = {};
|
||||
|
@ -356,6 +361,11 @@ static struct samsung_quirks samsung_broken_acpi_video = {
|
|||
.broken_acpi_video = true,
|
||||
};
|
||||
|
||||
static struct samsung_quirks samsung_np740u3e = {
|
||||
.four_kbd_backlight_levels = true,
|
||||
.enable_kbd_backlight = true,
|
||||
};
|
||||
|
||||
static bool force;
|
||||
module_param(force, bool, 0);
|
||||
MODULE_PARM_DESC(force,
|
||||
|
@ -1051,6 +1061,8 @@ static int __init samsung_leds_init(struct samsung_laptop *samsung)
|
|||
samsung->kbd_led.brightness_set = kbd_led_set;
|
||||
samsung->kbd_led.brightness_get = kbd_led_get;
|
||||
samsung->kbd_led.max_brightness = 8;
|
||||
if (samsung->quirks->four_kbd_backlight_levels)
|
||||
samsung->kbd_led.max_brightness = 4;
|
||||
|
||||
ret = led_classdev_register(&samsung->platform_device->dev,
|
||||
&samsung->kbd_led);
|
||||
|
@ -1414,6 +1426,19 @@ static void samsung_platform_exit(struct samsung_laptop *samsung)
|
|||
}
|
||||
}
|
||||
|
||||
static int samsung_pm_notification(struct notifier_block *nb,
|
||||
unsigned long val, void *ptr)
|
||||
{
|
||||
struct samsung_laptop *samsung;
|
||||
|
||||
samsung = container_of(nb, struct samsung_laptop, pm_nb);
|
||||
if (val == PM_POST_HIBERNATION &&
|
||||
samsung->quirks->enable_kbd_backlight)
|
||||
kbd_backlight_enable(samsung);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __init samsung_platform_init(struct samsung_laptop *samsung)
|
||||
{
|
||||
struct platform_device *pdev;
|
||||
|
@ -1534,6 +1559,15 @@ static struct dmi_system_id __initdata samsung_dmi_table[] = {
|
|||
},
|
||||
.driver_data = &samsung_broken_acpi_video,
|
||||
},
|
||||
{
|
||||
.callback = samsung_dmi_matched,
|
||||
.ident = "730U3E/740U3E",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "730U3E/740U3E"),
|
||||
},
|
||||
.driver_data = &samsung_np740u3e,
|
||||
},
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(dmi, samsung_dmi_table);
|
||||
|
@ -1608,6 +1642,9 @@ static int __init samsung_init(void)
|
|||
if (ret)
|
||||
goto error_debugfs;
|
||||
|
||||
samsung->pm_nb.notifier_call = samsung_pm_notification;
|
||||
register_pm_notifier(&samsung->pm_nb);
|
||||
|
||||
samsung_platform_device = samsung->platform_device;
|
||||
return ret;
|
||||
|
||||
|
@ -1633,6 +1670,7 @@ static void __exit samsung_exit(void)
|
|||
struct samsung_laptop *samsung;
|
||||
|
||||
samsung = platform_get_drvdata(samsung_platform_device);
|
||||
unregister_pm_notifier(&samsung->pm_nb);
|
||||
|
||||
samsung_debugfs_exit(samsung);
|
||||
samsung_leds_exit(samsung);
|
||||
|
|
|
@ -3171,8 +3171,10 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
|
|||
KEY_MICMUTE, /* 0x1a: Mic mute (since ?400 or so) */
|
||||
|
||||
/* (assignments unknown, please report if found) */
|
||||
KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN,
|
||||
KEY_UNKNOWN,
|
||||
|
||||
/* Extra keys in use since the X240 / T440 / T540 */
|
||||
KEY_CONFIG, KEY_SEARCH, KEY_SCALE, KEY_COMPUTER,
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
@ -56,6 +56,7 @@
|
|||
#include <linux/workqueue.h>
|
||||
#include <linux/i8042.h>
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/dmi.h>
|
||||
#include <asm/uaccess.h>
|
||||
|
||||
MODULE_AUTHOR("John Belmonte");
|
||||
|
@ -213,6 +214,30 @@ static const struct key_entry toshiba_acpi_keymap[] = {
|
|||
{ KE_END, 0 },
|
||||
};
|
||||
|
||||
/* alternative keymap */
|
||||
static const struct dmi_system_id toshiba_alt_keymap_dmi[] = {
|
||||
{
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "Satellite M840"),
|
||||
},
|
||||
},
|
||||
{}
|
||||
};
|
||||
|
||||
static const struct key_entry toshiba_acpi_alt_keymap[] = {
|
||||
{ KE_KEY, 0x157, { KEY_MUTE } },
|
||||
{ KE_KEY, 0x102, { KEY_ZOOMOUT } },
|
||||
{ KE_KEY, 0x103, { KEY_ZOOMIN } },
|
||||
{ KE_KEY, 0x139, { KEY_ZOOMRESET } },
|
||||
{ KE_KEY, 0x13e, { KEY_SWITCHVIDEOMODE } },
|
||||
{ KE_KEY, 0x13c, { KEY_BRIGHTNESSDOWN } },
|
||||
{ KE_KEY, 0x13d, { KEY_BRIGHTNESSUP } },
|
||||
{ KE_KEY, 0x158, { KEY_WLAN } },
|
||||
{ KE_KEY, 0x13f, { KEY_TOUCHPAD_TOGGLE } },
|
||||
{ KE_END, 0 },
|
||||
};
|
||||
|
||||
/* utility
|
||||
*/
|
||||
|
||||
|
@ -1440,6 +1465,7 @@ static int toshiba_acpi_setup_keyboard(struct toshiba_acpi_dev *dev)
|
|||
acpi_handle ec_handle;
|
||||
int error;
|
||||
u32 hci_result;
|
||||
const struct key_entry *keymap = toshiba_acpi_keymap;
|
||||
|
||||
dev->hotkey_dev = input_allocate_device();
|
||||
if (!dev->hotkey_dev)
|
||||
|
@ -1449,7 +1475,9 @@ static int toshiba_acpi_setup_keyboard(struct toshiba_acpi_dev *dev)
|
|||
dev->hotkey_dev->phys = "toshiba_acpi/input0";
|
||||
dev->hotkey_dev->id.bustype = BUS_HOST;
|
||||
|
||||
error = sparse_keymap_setup(dev->hotkey_dev, toshiba_acpi_keymap, NULL);
|
||||
if (dmi_check_system(toshiba_alt_keymap_dmi))
|
||||
keymap = toshiba_acpi_alt_keymap;
|
||||
error = sparse_keymap_setup(dev->hotkey_dev, keymap, NULL);
|
||||
if (error)
|
||||
goto err_free_dev;
|
||||
|
||||
|
|
Loading…
Reference in a new issue