aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
-rw-r--r--arch/x86/include/asm/intel_scu_ipc.h8
-rw-r--r--drivers/input/sparse-keymap.c39
-rw-r--r--drivers/leds/Kconfig9
-rw-r--r--drivers/leds/Makefile1
-rw-r--r--drivers/leds/trigger/ledtrig-cpu.c33
-rw-r--r--drivers/platform/x86/Kconfig9
-rw-r--r--drivers/platform/x86/Makefile1
-rw-r--r--drivers/platform/x86/acer-wmi.c5
-rw-r--r--drivers/platform/x86/asus-laptop.c8
-rw-r--r--drivers/platform/x86/asus-nb-wmi.c9
-rw-r--r--drivers/platform/x86/asus-wmi.c8
-rw-r--r--drivers/platform/x86/dell-laptop.c217
-rw-r--r--drivers/platform/x86/dell-smbios.c20
-rw-r--r--drivers/platform/x86/dell-smbios.h11
-rw-r--r--drivers/platform/x86/dell-wmi-aio.c6
-rw-r--r--drivers/platform/x86/dell-wmi-led.c (renamed from drivers/leds/dell-led.c)141
-rw-r--r--drivers/platform/x86/dell-wmi.c20
-rw-r--r--drivers/platform/x86/eeepc-laptop.c10
-rw-r--r--drivers/platform/x86/fujitsu-laptop.c830
-rw-r--r--drivers/platform/x86/hp-wireless.c8
-rw-r--r--drivers/platform/x86/hp-wmi.c47
-rw-r--r--drivers/platform/x86/ideapad-laptop.c12
-rw-r--r--drivers/platform/x86/intel-hid.c50
-rw-r--r--drivers/platform/x86/intel_scu_ipc.c106
-rw-r--r--drivers/platform/x86/msi-laptop.c14
-rw-r--r--drivers/platform/x86/msi-wmi.c9
-rw-r--r--drivers/platform/x86/panasonic-laptop.c18
-rw-r--r--drivers/platform/x86/silead_dmi.c80
-rw-r--r--drivers/platform/x86/thinkpad_acpi.c99
-rw-r--r--drivers/platform/x86/topstar-laptop.c5
-rw-r--r--drivers/platform/x86/toshiba-wmi.c5
-rw-r--r--drivers/platform/x86/toshiba_acpi.c8
-rw-r--r--include/linux/dell-led.h6
-rw-r--r--sound/pci/hda/dell_wmi_helper.c30
34 files changed, 922 insertions, 960 deletions
diff --git a/arch/x86/include/asm/intel_scu_ipc.h b/arch/x86/include/asm/intel_scu_ipc.h
index 4fb1d0abef95..81d3d8776fd9 100644
--- a/arch/x86/include/asm/intel_scu_ipc.h
+++ b/arch/x86/include/asm/intel_scu_ipc.h
@@ -3,6 +3,9 @@
#include <linux/notifier.h>
+#define IPCMSG_INDIRECT_READ 0x02
+#define IPCMSG_INDIRECT_WRITE 0x05
+
#define IPCMSG_COLD_OFF 0x80 /* Only for Tangier */
#define IPCMSG_WARM_RESET 0xF0
@@ -45,7 +48,10 @@ int intel_scu_ipc_update_register(u16 addr, u8 data, u8 mask);
/* Issue commands to the SCU with or without data */
int intel_scu_ipc_simple_command(int cmd, int sub);
int intel_scu_ipc_command(int cmd, int sub, u32 *in, int inlen,
- u32 *out, int outlen);
+ u32 *out, int outlen);
+int intel_scu_ipc_raw_command(int cmd, int sub, u8 *in, int inlen,
+ u32 *out, int outlen, u32 dptr, u32 sptr);
+
/* I2C control api */
int intel_scu_ipc_i2c_cntrl(u32 addr, u32 *data);
diff --git a/drivers/input/sparse-keymap.c b/drivers/input/sparse-keymap.c
index e7409c45bdd0..12a3ad83296d 100644
--- a/drivers/input/sparse-keymap.c
+++ b/drivers/input/sparse-keymap.c
@@ -160,12 +160,12 @@ static int sparse_keymap_setkeycode(struct input_dev *dev,
* @keymap: Keymap in form of array of &key_entry structures ending
* with %KE_END type entry
* @setup: Function that can be used to adjust keymap entries
- * depending on device's deeds, may be %NULL
+ * depending on device's needs, may be %NULL
*
* The function calculates size and allocates copy of the original
* keymap after which sets up input device event bits appropriately.
- * Before destroying input device allocated keymap should be freed
- * with a call to sparse_keymap_free().
+ * The allocated copy of the keymap is automatically freed when it
+ * is no longer needed.
*/
int sparse_keymap_setup(struct input_dev *dev,
const struct key_entry *keymap,
@@ -180,19 +180,18 @@ int sparse_keymap_setup(struct input_dev *dev,
for (e = keymap; e->type != KE_END; e++)
map_size++;
- map = kcalloc(map_size, sizeof(struct key_entry), GFP_KERNEL);
+ map = devm_kmemdup(&dev->dev, keymap, map_size * sizeof(*map),
+ GFP_KERNEL);
if (!map)
return -ENOMEM;
- memcpy(map, keymap, map_size * sizeof(struct key_entry));
-
for (i = 0; i < map_size; i++) {
entry = &map[i];
if (setup) {
error = setup(dev, entry);
if (error)
- goto err_out;
+ return error;
}
switch (entry->type) {
@@ -221,10 +220,6 @@ int sparse_keymap_setup(struct input_dev *dev,
dev->setkeycode = sparse_keymap_setkeycode;
return 0;
-
- err_out:
- kfree(map);
- return error;
}
EXPORT_SYMBOL(sparse_keymap_setup);
@@ -232,29 +227,13 @@ EXPORT_SYMBOL(sparse_keymap_setup);
* sparse_keymap_free - free memory allocated for sparse keymap
* @dev: Input device using sparse keymap
*
- * This function is used to free memory allocated by sparse keymap
+ * This function used to free memory allocated by sparse keymap
* in an input device that was set up by sparse_keymap_setup().
- * NOTE: It is safe to cal this function while input device is
- * still registered (however the drivers should care not to try to
- * use freed keymap and thus have to shut off interrupts/polling
- * before freeing the keymap).
+ * Since sparse_keymap_setup() now uses a managed allocation for the
+ * keymap copy, use of this function is deprecated.
*/
void sparse_keymap_free(struct input_dev *dev)
{
- unsigned long flags;
-
- /*
- * Take event lock to prevent racing with input_get_keycode()
- * and input_set_keycode() if we are called while input device
- * is still registered.
- */
- spin_lock_irqsave(&dev->event_lock, flags);
-
- kfree(dev->keycode);
- dev->keycode = NULL;
- dev->keycodemax = 0;
-
- spin_unlock_irqrestore(&dev->event_lock, flags);
}
EXPORT_SYMBOL(sparse_keymap_free);
diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig
index 275f467956ee..6a88474b2970 100644
--- a/drivers/leds/Kconfig
+++ b/drivers/leds/Kconfig
@@ -463,15 +463,6 @@ config LEDS_ADP5520
To compile this driver as a module, choose M here: the module will
be called leds-adp5520.
-config LEDS_DELL_NETBOOKS
- tristate "External LED on Dell Business Netbooks"
- depends on LEDS_CLASS
- depends on X86 && ACPI_WMI
- depends on DELL_SMBIOS
- help
- This adds support for the Latitude 2100 and similar
- notebooks that have an external LED.
-
config LEDS_MC13783
tristate "LED Support for MC13XXX PMIC"
depends on LEDS_CLASS
diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile
index 6b8273736478..558d24675454 100644
--- a/drivers/leds/Makefile
+++ b/drivers/leds/Makefile
@@ -52,7 +52,6 @@ obj-$(CONFIG_LEDS_REGULATOR) += leds-regulator.o
obj-$(CONFIG_LEDS_INTEL_SS4200) += leds-ss4200.o
obj-$(CONFIG_LEDS_LT3593) += leds-lt3593.o
obj-$(CONFIG_LEDS_ADP5520) += leds-adp5520.o
-obj-$(CONFIG_LEDS_DELL_NETBOOKS) += dell-led.o
obj-$(CONFIG_LEDS_MC13783) += leds-mc13783.o
obj-$(CONFIG_LEDS_NS2) += leds-ns2.o
obj-$(CONFIG_LEDS_NETXBIG) += leds-netxbig.o
diff --git a/drivers/leds/trigger/ledtrig-cpu.c b/drivers/leds/trigger/ledtrig-cpu.c
index a41896468cb3..66a626091936 100644
--- a/drivers/leds/trigger/ledtrig-cpu.c
+++ b/drivers/leds/trigger/ledtrig-cpu.c
@@ -31,12 +31,16 @@
#define MAX_NAME_LEN 8
struct led_trigger_cpu {
+ bool is_active;
char name[MAX_NAME_LEN];
struct led_trigger *_trig;
};
static DEFINE_PER_CPU(struct led_trigger_cpu, cpu_trig);
+static struct led_trigger *trig_cpu_all;
+static atomic_t num_active_cpus = ATOMIC_INIT(0);
+
/**
* ledtrig_cpu - emit a CPU event as a trigger
* @evt: CPU event to be emitted
@@ -47,26 +51,46 @@ static DEFINE_PER_CPU(struct led_trigger_cpu, cpu_trig);
void ledtrig_cpu(enum cpu_led_event ledevt)
{
struct led_trigger_cpu *trig = this_cpu_ptr(&cpu_trig);
+ bool is_active = trig->is_active;
/* Locate the correct CPU LED */
switch (ledevt) {
case CPU_LED_IDLE_END:
case CPU_LED_START:
/* Will turn the LED on, max brightness */
- led_trigger_event(trig->_trig, LED_FULL);
+ is_active = true;
break;
case CPU_LED_IDLE_START:
case CPU_LED_STOP:
case CPU_LED_HALTED:
/* Will turn the LED off */
- led_trigger_event(trig->_trig, LED_OFF);
+ is_active = false;
break;
default:
/* Will leave the LED as it is */
break;
}
+
+ if (is_active != trig->is_active) {
+ unsigned int active_cpus;
+ unsigned int total_cpus;
+
+ /* Update trigger state */
+ trig->is_active = is_active;
+ atomic_add(is_active ? 1 : -1, &num_active_cpus);
+ active_cpus = atomic_read(&num_active_cpus);
+ total_cpus = num_present_cpus();
+
+ led_trigger_event(trig->_trig,
+ is_active ? LED_FULL : LED_OFF);
+
+
+ led_trigger_event(trig_cpu_all,
+ DIV_ROUND_UP(LED_FULL * active_cpus, total_cpus));
+
+ }
}
EXPORT_SYMBOL(ledtrig_cpu);
@@ -113,6 +137,11 @@ static int __init ledtrig_cpu_init(void)
BUILD_BUG_ON(CONFIG_NR_CPUS > 9999);
/*
+ * Registering a trigger for all CPUs.
+ */
+ led_trigger_register_simple("cpu", &trig_cpu_all);
+
+ /*
* Registering CPU led trigger for each CPU core here
* ignores CPU hotplug, but after this CPU hotplug works
* fine with this trigger.
diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
index 4bc88eb52712..5602bdfcad65 100644
--- a/drivers/platform/x86/Kconfig
+++ b/drivers/platform/x86/Kconfig
@@ -141,6 +141,14 @@ config DELL_WMI_AIO
To compile this driver as a module, choose M here: the module will
be called dell-wmi-aio.
+config DELL_WMI_LED
+ tristate "External LED on Dell Business Netbooks"
+ depends on LEDS_CLASS
+ depends on ACPI_WMI
+ help
+ This adds support for the Latitude 2100 and similar
+ notebooks that have an external LED.
+
config DELL_SMO8800
tristate "Dell Latitude freefall driver (ACPI SMO88XX)"
depends on ACPI
@@ -175,6 +183,7 @@ config FUJITSU_LAPTOP
depends on BACKLIGHT_CLASS_DEVICE
depends on ACPI_VIDEO || ACPI_VIDEO = n
depends on LEDS_CLASS || LEDS_CLASS=n
+ select INPUT_SPARSEKMAP
---help---
This is a driver for laptops built by Fujitsu:
diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile
index 299d0f9e40f7..776b3a7a4984 100644
--- a/drivers/platform/x86/Makefile
+++ b/drivers/platform/x86/Makefile
@@ -15,6 +15,7 @@ obj-$(CONFIG_DELL_SMBIOS) += dell-smbios.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_WMI_LED) += dell-wmi-led.o
obj-$(CONFIG_DELL_SMO8800) += dell-smo8800.o
obj-$(CONFIG_DELL_RBTN) += dell-rbtn.o
obj-$(CONFIG_ACER_WMI) += acer-wmi.o
diff --git a/drivers/platform/x86/acer-wmi.c b/drivers/platform/x86/acer-wmi.c
index dac0fbe87460..8a27f0be1aec 100644
--- a/drivers/platform/x86/acer-wmi.c
+++ b/drivers/platform/x86/acer-wmi.c
@@ -1987,7 +1987,7 @@ static int __init acer_wmi_input_setup(void)
acer_wmi_notify, NULL);
if (ACPI_FAILURE(status)) {
err = -EIO;
- goto err_free_keymap;
+ goto err_free_dev;
}
err = input_register_device(acer_wmi_input_dev);
@@ -1998,8 +1998,6 @@ static int __init acer_wmi_input_setup(void)
err_uninstall_notifier:
wmi_remove_notify_handler(ACERWMID_EVENT_GUID);
-err_free_keymap:
- sparse_keymap_free(acer_wmi_input_dev);
err_free_dev:
input_free_device(acer_wmi_input_dev);
return err;
@@ -2008,7 +2006,6 @@ err_free_dev:
static void acer_wmi_input_destroy(void)
{
wmi_remove_notify_handler(ACERWMID_EVENT_GUID);
- sparse_keymap_free(acer_wmi_input_dev);
input_unregister_device(acer_wmi_input_dev);
}
diff --git a/drivers/platform/x86/asus-laptop.c b/drivers/platform/x86/asus-laptop.c
index 28551f5a2e07..c4768be24ba9 100644
--- a/drivers/platform/x86/asus-laptop.c
+++ b/drivers/platform/x86/asus-laptop.c
@@ -1516,14 +1516,12 @@ static int asus_input_init(struct asus_laptop *asus)
error = input_register_device(input);
if (error) {
pr_warn("Unable to register input device\n");
- goto err_free_keymap;
+ goto err_free_dev;
}
asus->inputdev = input;
return 0;
-err_free_keymap:
- sparse_keymap_free(input);
err_free_dev:
input_free_device(input);
return error;
@@ -1531,10 +1529,8 @@ err_free_dev:
static void asus_input_exit(struct asus_laptop *asus)
{
- if (asus->inputdev) {
- sparse_keymap_free(asus->inputdev);
+ if (asus->inputdev)
input_unregister_device(asus->inputdev);
- }
asus->inputdev = NULL;
}
diff --git a/drivers/platform/x86/asus-nb-wmi.c b/drivers/platform/x86/asus-nb-wmi.c
index dea98ffb6f60..1ae58d906536 100644
--- a/drivers/platform/x86/asus-nb-wmi.c
+++ b/drivers/platform/x86/asus-nb-wmi.c
@@ -144,6 +144,15 @@ static const struct dmi_system_id asus_quirks[] = {
},
{
.callback = dmi_matched,
+ .ident = "ASUSTeK COMPUTER INC. X302UA",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
+ DMI_MATCH(DMI_PRODUCT_NAME, "X302UA"),
+ },
+ .driver_data = &quirk_asus_wapf4,
+ },
+ {
+ .callback = dmi_matched,
.ident = "ASUSTeK COMPUTER INC. X401U",
.matches = {
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 8fe5890bf539..d817e6327fec 100644
--- a/drivers/platform/x86/asus-wmi.c
+++ b/drivers/platform/x86/asus-wmi.c
@@ -269,12 +269,10 @@ static int asus_wmi_input_init(struct asus_wmi *asus)
err = input_register_device(asus->inputdev);
if (err)
- goto err_free_keymap;
+ goto err_free_dev;
return 0;
-err_free_keymap:
- sparse_keymap_free(asus->inputdev);
err_free_dev:
input_free_device(asus->inputdev);
return err;
@@ -282,10 +280,8 @@ err_free_dev:
static void asus_wmi_input_exit(struct asus_wmi *asus)
{
- if (asus->inputdev) {
- sparse_keymap_free(asus->inputdev);
+ if (asus->inputdev)
input_unregister_device(asus->inputdev);
- }
asus->inputdev = NULL;
}
diff --git a/drivers/platform/x86/dell-laptop.c b/drivers/platform/x86/dell-laptop.c
index f57dd282a002..47fe6264cadf 100644
--- a/drivers/platform/x86/dell-laptop.c
+++ b/drivers/platform/x86/dell-laptop.c
@@ -29,6 +29,7 @@
#include <linux/mm.h>
#include <linux/i8042.h>
#include <linux/debugfs.h>
+#include <linux/dell-led.h>
#include <linux/seq_file.h>
#include <acpi/video.h>
#include "dell-rbtn.h"
@@ -42,6 +43,8 @@
#define KBD_LED_AUTO_50_TOKEN 0x02EB
#define KBD_LED_AUTO_75_TOKEN 0x02EC
#define KBD_LED_AUTO_100_TOKEN 0x02F6
+#define GLOBAL_MIC_MUTE_ENABLE 0x0364
+#define GLOBAL_MIC_MUTE_DISABLE 0x0365
struct quirk_entry {
u8 touchpad_led;
@@ -1139,6 +1142,7 @@ static u8 kbd_previous_level;
static u8 kbd_previous_mode_bit;
static bool kbd_led_present;
+static DEFINE_MUTEX(kbd_led_mutex);
/*
* NOTE: there are three ways to set the keyboard backlight level.
@@ -1568,9 +1572,11 @@ static ssize_t kbd_led_timeout_store(struct device *dev,
}
}
+ mutex_lock(&kbd_led_mutex);
+
ret = kbd_get_state(&state);
if (ret)
- return ret;
+ goto out;
new_state = state;
new_state.timeout_value = value;
@@ -1578,9 +1584,12 @@ static ssize_t kbd_led_timeout_store(struct device *dev,
ret = kbd_set_state_safe(&new_state, &state);
if (ret)
- return ret;
+ goto out;
- return count;
+ ret = count;
+out:
+ mutex_unlock(&kbd_led_mutex);
+ return ret;
}
static ssize_t kbd_led_timeout_show(struct device *dev,
@@ -1640,9 +1649,11 @@ static ssize_t kbd_led_triggers_store(struct device *dev,
if (trigger[0] != '+' && trigger[0] != '-')
return -EINVAL;
+ mutex_lock(&kbd_led_mutex);
+
ret = kbd_get_state(&state);
if (ret)
- return ret;
+ goto out;
if (kbd_triggers_supported)
triggers_enabled = kbd_is_trigger_mode_bit(state.mode_bit);
@@ -1656,48 +1667,62 @@ static ssize_t kbd_led_triggers_store(struct device *dev,
if (strcmp(trigger+1, kbd_led_triggers[i]) != 0)
continue;
if (trigger[0] == '+' &&
- triggers_enabled && (state.triggers & BIT(i)))
- return count;
+ triggers_enabled && (state.triggers & BIT(i))) {
+ ret = count;
+ goto out;
+ }
if (trigger[0] == '-' &&
- (!triggers_enabled || !(state.triggers & BIT(i))))
- return count;
+ (!triggers_enabled || !(state.triggers & BIT(i)))) {
+ ret = count;
+ goto out;
+ }
trigger_bit = i;
break;
}
}
- if (trigger_bit != -1) {
- new_state = state;
- if (trigger[0] == '+')
- new_state.triggers |= BIT(trigger_bit);
- else {
- new_state.triggers &= ~BIT(trigger_bit);
- /* NOTE: trackstick bit (2) must be disabled when
- * disabling touchpad bit (1), otherwise touchpad
- * bit (1) will not be disabled */
- if (trigger_bit == 1)
- new_state.triggers &= ~BIT(2);
- }
- if ((kbd_info.triggers & new_state.triggers) !=
- new_state.triggers)
- return -EINVAL;
- if (new_state.triggers && !triggers_enabled) {
- new_state.mode_bit = KBD_MODE_BIT_TRIGGER;
- kbd_set_level(&new_state, kbd_previous_level);
- } else if (new_state.triggers == 0) {
- kbd_set_level(&new_state, 0);
- }
- if (!(kbd_info.modes & BIT(new_state.mode_bit)))
- return -EINVAL;
- ret = kbd_set_state_safe(&new_state, &state);
- if (ret)
- return ret;
- if (new_state.mode_bit != KBD_MODE_BIT_OFF)
- kbd_previous_mode_bit = new_state.mode_bit;
- return count;
+ if (trigger_bit == -1) {
+ ret = -EINVAL;
+ goto out;
}
- return -EINVAL;
+ new_state = state;
+ if (trigger[0] == '+')
+ new_state.triggers |= BIT(trigger_bit);
+ else {
+ new_state.triggers &= ~BIT(trigger_bit);
+ /*
+ * NOTE: trackstick bit (2) must be disabled when
+ * disabling touchpad bit (1), otherwise touchpad
+ * bit (1) will not be disabled
+ */
+ if (trigger_bit == 1)
+ new_state.triggers &= ~BIT(2);
+ }
+ if ((kbd_info.triggers & new_state.triggers) !=
+ new_state.triggers) {
+ ret = -EINVAL;
+ goto out;
+ }
+ if (new_state.triggers && !triggers_enabled) {
+ new_state.mode_bit = KBD_MODE_BIT_TRIGGER;
+ kbd_set_level(&new_state, kbd_previous_level);
+ } else if (new_state.triggers == 0) {
+ kbd_set_level(&new_state, 0);
+ }
+ if (!(kbd_info.modes & BIT(new_state.mode_bit))) {
+ ret = -EINVAL;
+ goto out;
+ }
+ ret = kbd_set_state_safe(&new_state, &state);
+ if (ret)
+ goto out;
+ if (new_state.mode_bit != KBD_MODE_BIT_OFF)
+ kbd_previous_mode_bit = new_state.mode_bit;
+ ret = count;
+out:
+ mutex_unlock(&kbd_led_mutex);
+ return ret;
}
static ssize_t kbd_led_triggers_show(struct device *dev,
@@ -1754,12 +1779,16 @@ static ssize_t kbd_led_als_enabled_store(struct device *dev,
if (ret)
return ret;
+ mutex_lock(&kbd_led_mutex);
+
ret = kbd_get_state(&state);
if (ret)
- return ret;
+ goto out;
- if (enable == kbd_is_als_mode_bit(state.mode_bit))
- return count;
+ if (enable == kbd_is_als_mode_bit(state.mode_bit)) {
+ ret = count;
+ goto out;
+ }
new_state = state;
@@ -1779,15 +1808,20 @@ static ssize_t kbd_led_als_enabled_store(struct device *dev,
new_state.mode_bit = KBD_MODE_BIT_ON;
}
}
- if (!(kbd_info.modes & BIT(new_state.mode_bit)))
- return -EINVAL;
+ if (!(kbd_info.modes & BIT(new_state.mode_bit))) {
+ ret = -EINVAL;
+ goto out;
+ }
ret = kbd_set_state_safe(&new_state, &state);
if (ret)
- return ret;
+ goto out;
kbd_previous_mode_bit = new_state.mode_bit;
- return count;
+ ret = count;
+out:
+ mutex_unlock(&kbd_led_mutex);
+ return ret;
}
static ssize_t kbd_led_als_enabled_show(struct device *dev,
@@ -1822,18 +1856,23 @@ static ssize_t kbd_led_als_setting_store(struct device *dev,
if (ret)
return ret;
+ mutex_lock(&kbd_led_mutex);
+
ret = kbd_get_state(&state);
if (ret)
- return ret;
+ goto out;
new_state = state;
new_state.als_setting = setting;
ret = kbd_set_state_safe(&new_state, &state);
if (ret)
- return ret;
+ goto out;
- return count;
+ ret = count;
+out:
+ mutex_unlock(&kbd_led_mutex);
+ return ret;
}
static ssize_t kbd_led_als_setting_show(struct device *dev,
@@ -1918,31 +1957,37 @@ static int kbd_led_level_set(struct led_classdev *led_cdev,
u16 num;
int ret;
+ mutex_lock(&kbd_led_mutex);
+
if (kbd_get_max_level()) {
ret = kbd_get_state(&state);
if (ret)
- return ret;
+ goto out;
new_state = state;
ret = kbd_set_level(&new_state, value);
if (ret)
- return ret;
- return kbd_set_state_safe(&new_state, &state);
- }
-
- if (kbd_get_valid_token_counts()) {
+ goto out;
+ ret = kbd_set_state_safe(&new_state, &state);
+ } else if (kbd_get_valid_token_counts()) {
for (num = kbd_token_bits; num != 0 && value > 0; --value)
num &= num - 1; /* clear the first bit set */
if (num == 0)
- return 0;
- return kbd_set_token_bit(ffs(num) - 1);
+ ret = 0;
+ else
+ ret = kbd_set_token_bit(ffs(num) - 1);
+ } else {
+ pr_warn("Keyboard brightness level control not supported\n");
+ ret = -ENXIO;
}
- pr_warn("Keyboard brightness level control not supported\n");
- return -ENXIO;
+out:
+ mutex_unlock(&kbd_led_mutex);
+ return ret;
}
static struct led_classdev kbd_led = {
.name = "dell::kbd_backlight",
+ .flags = LED_BRIGHT_HW_CHANGED,
.brightness_set_blocking = kbd_led_level_set,
.brightness_get = kbd_led_level_get,
.groups = kbd_led_groups,
@@ -1950,6 +1995,8 @@ static struct led_classdev kbd_led = {
static int __init kbd_led_init(struct device *dev)
{
+ int ret;
+
kbd_init();
if (!kbd_led_present)
return -ENODEV;
@@ -1961,7 +2008,11 @@ static int __init kbd_led_init(struct device *dev)
if (kbd_led.max_brightness)
kbd_led.max_brightness--;
}
- return led_classdev_register(dev, &kbd_led);
+ ret = led_classdev_register(dev, &kbd_led);
+ if (ret)
+ kbd_led_present = false;
+
+ return ret;
}
static void brightness_set_exit(struct led_classdev *led_cdev,
@@ -1978,6 +2029,51 @@ static void kbd_led_exit(void)
led_classdev_unregister(&kbd_led);
}
+static int dell_laptop_notifier_call(struct notifier_block *nb,
+ unsigned long action, void *data)
+{
+ switch (action) {
+ case DELL_LAPTOP_KBD_BACKLIGHT_BRIGHTNESS_CHANGED:
+ if (!kbd_led_present)
+ break;
+
+ led_classdev_notify_brightness_hw_changed(&kbd_led,
+ kbd_led_level_get(&kbd_led));
+ break;
+ }
+
+ return NOTIFY_OK;
+}
+
+static struct notifier_block dell_laptop_notifier = {
+ .notifier_call = dell_laptop_notifier_call,
+};
+
+int dell_micmute_led_set(int state)
+{
+ struct calling_interface_buffer *buffer;
+ struct calling_interface_token *token;
+
+ if (state == 0)
+ token = dell_smbios_find_token(GLOBAL_MIC_MUTE_DISABLE);
+ else if (state == 1)
+ token = dell_smbios_find_token(GLOBAL_MIC_MUTE_ENABLE);
+ else
+ return -EINVAL;
+
+ if (!token)
+ return -ENODEV;
+
+ buffer = dell_smbios_get_buffer();
+ buffer->input[0] = token->location;
+ buffer->input[1] = token->value;
+ dell_smbios_send_request(1, 0);
+ dell_smbios_release_buffer();
+
+ return state;
+}
+EXPORT_SYMBOL_GPL(dell_micmute_led_set);
+
static int __init dell_init(void)
{
struct calling_interface_buffer *buffer;
@@ -2021,6 +2117,8 @@ static int __init dell_init(void)
debugfs_create_file("rfkill", 0444, dell_laptop_dir, NULL,
&dell_debugfs_fops);
+ dell_laptop_register_notifier(&dell_laptop_notifier);
+
if (acpi_video_get_backlight_type() != acpi_backlight_vendor)
return 0;
@@ -2072,6 +2170,7 @@ fail_platform_driver:
static void __exit dell_exit(void)
{
+ dell_laptop_unregister_notifier(&dell_laptop_notifier);
debugfs_remove_recursive(dell_laptop_dir);
if (quirks && quirks->touchpad_led)
touchpad_led_exit();
diff --git a/drivers/platform/x86/dell-smbios.c b/drivers/platform/x86/dell-smbios.c
index d2412ab097da..0a5723468bff 100644
--- a/drivers/platform/x86/dell-smbios.c
+++ b/drivers/platform/x86/dell-smbios.c
@@ -105,6 +105,26 @@ struct calling_interface_token *dell_smbios_find_token(int tokenid)
}
EXPORT_SYMBOL_GPL(dell_smbios_find_token);
+static BLOCKING_NOTIFIER_HEAD(dell_laptop_chain_head);
+
+int dell_laptop_register_notifier(struct notifier_block *nb)
+{
+ return blocking_notifier_chain_register(&dell_laptop_chain_head, nb);
+}
+EXPORT_SYMBOL_GPL(dell_laptop_register_notifier);
+
+int dell_laptop_unregister_notifier(struct notifier_block *nb)
+{
+ return blocking_notifier_chain_unregister(&dell_laptop_chain_head, nb);
+}
+EXPORT_SYMBOL_GPL(dell_laptop_unregister_notifier);
+
+void dell_laptop_call_notifier(unsigned long action, void *data)
+{
+ blocking_notifier_call_chain(&dell_laptop_chain_head, action, data);
+}
+EXPORT_SYMBOL_GPL(dell_laptop_call_notifier);
+
static void __init parse_da_table(const struct dmi_header *dm)
{
/* Final token is a terminator, so we don't want to copy it */
diff --git a/drivers/platform/x86/dell-smbios.h b/drivers/platform/x86/dell-smbios.h
index ec7d40ae5e6e..45cbc2292cd3 100644
--- a/drivers/platform/x86/dell-smbios.h
+++ b/drivers/platform/x86/dell-smbios.h
@@ -16,6 +16,8 @@
#ifndef _DELL_SMBIOS_H_
#define _DELL_SMBIOS_H_
+struct notifier_block;
+
/* This structure will be modified by the firmware when we enter
* system management mode, hence the volatiles */
@@ -43,4 +45,13 @@ void dell_smbios_release_buffer(void);
void dell_smbios_send_request(int class, int select);
struct calling_interface_token *dell_smbios_find_token(int tokenid);
+
+enum dell_laptop_notifier_actions {
+ DELL_LAPTOP_KBD_BACKLIGHT_BRIGHTNESS_CHANGED,
+};
+
+int dell_laptop_register_notifier(struct notifier_block *nb);
+int dell_laptop_unregister_notifier(struct notifier_block *nb);
+void dell_laptop_call_notifier(unsigned long action, void *data);
+
#endif
diff --git a/drivers/platform/x86/dell-wmi-aio.c b/drivers/platform/x86/dell-wmi-aio.c
index dbc97a33bbc8..50c2078715d6 100644
--- a/drivers/platform/x86/dell-wmi-aio.c
+++ b/drivers/platform/x86/dell-wmi-aio.c
@@ -152,12 +152,10 @@ static int __init dell_wmi_aio_input_setup(void)
err = input_register_device(dell_wmi_aio_input_dev);
if (err) {
pr_info("Unable to register input device\n");
- goto err_free_keymap;
+ goto err_free_dev;
}
return 0;
-err_free_keymap:
- sparse_keymap_free(dell_wmi_aio_input_dev);
err_free_dev:
input_free_device(dell_wmi_aio_input_dev);
return err;
@@ -192,7 +190,6 @@ static int __init dell_wmi_aio_init(void)
err = wmi_install_notify_handler(guid, dell_wmi_aio_notify, NULL);
if (err) {
pr_err("Unable to register notify handler - %d\n", err);
- sparse_keymap_free(dell_wmi_aio_input_dev);
input_unregister_device(dell_wmi_aio_input_dev);
return err;
}
@@ -206,7 +203,6 @@ static void __exit dell_wmi_aio_exit(void)
guid = dell_wmi_aio_find();
wmi_remove_notify_handler(guid);
- sparse_keymap_free(dell_wmi_aio_input_dev);
input_unregister_device(dell_wmi_aio_input_dev);
}
diff --git a/drivers/leds/dell-led.c b/drivers/platform/x86/dell-wmi-led.c
index b3d6e9c15cf9..a0c7e99530ef 100644
--- a/drivers/leds/dell-led.c
+++ b/drivers/platform/x86/dell-wmi-led.c
@@ -1,6 +1,4 @@
/*
- * dell_led.c - Dell LED Driver
- *
* Copyright (C) 2010 Dell Inc.
* Louis Davis <louis_davis@dell.com>
* Jim Dailey <jim_dailey@dell.com>
@@ -15,16 +13,12 @@
#include <linux/leds.h>
#include <linux/slab.h>
#include <linux/module.h>
-#include <linux/dmi.h>
-#include <linux/dell-led.h>
-#include "../platform/x86/dell-smbios.h"
MODULE_AUTHOR("Louis Davis/Jim Dailey");
MODULE_DESCRIPTION("Dell LED Control Driver");
MODULE_LICENSE("GPL");
#define DELL_LED_BIOS_GUID "F6E4FE6E-909D-47cb-8BAB-C9F6F2F8D396"
-#define DELL_APP_GUID "A80593CE-A997-11DA-B012-B622A1EF5492"
MODULE_ALIAS("wmi:" DELL_LED_BIOS_GUID);
/* Error Result Codes: */
@@ -43,53 +37,6 @@ MODULE_ALIAS("wmi:" DELL_LED_BIOS_GUID);
#define CMD_LED_OFF 17
#define CMD_LED_BLINK 18
-#define GLOBAL_MIC_MUTE_ENABLE 0x364
-#define GLOBAL_MIC_MUTE_DISABLE 0x365
-
-static int dell_micmute_led_set(int state)
-{
- struct calling_interface_buffer *buffer;
- struct calling_interface_token *token;
-
- if (!wmi_has_guid(DELL_APP_GUID))
- return -ENODEV;
-
- if (state == 0)
- token = dell_smbios_find_token(GLOBAL_MIC_MUTE_DISABLE);
- else if (state == 1)
- token = dell_smbios_find_token(GLOBAL_MIC_MUTE_ENABLE);
- else
- return -EINVAL;
-
- if (!token)
- return -ENODEV;
-
- buffer = dell_smbios_get_buffer();
- buffer->input[0] = token->location;
- buffer->input[1] = token->value;
- dell_smbios_send_request(1, 0);
- dell_smbios_release_buffer();
-
- return state;
-}
-
-int dell_app_wmi_led_set(int whichled, int on)
-{
- int state = 0;
-
- switch (whichled) {
- case DELL_LED_MICMUTE:
- state = dell_micmute_led_set(on);
- break;
- default:
- pr_warn("led type %x is not supported\n", whichled);
- break;
- }
-
- return state;
-}
-EXPORT_SYMBOL_GPL(dell_app_wmi_led_set);
-
struct bios_args {
unsigned char length;
unsigned char result_code;
@@ -99,37 +46,29 @@ struct bios_args {
unsigned char off_time;
};
-static int dell_led_perform_fn(u8 length,
- u8 result_code,
- u8 device_id,
- u8 command,
- u8 on_time,
- u8 off_time)
+static int dell_led_perform_fn(u8 length, u8 result_code, u8 device_id,
+ u8 command, u8 on_time, u8 off_time)
{
- struct bios_args *bios_return;
- u8 return_code;
- union acpi_object *obj;
struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
+ struct bios_args *bios_return;
struct acpi_buffer input;
+ union acpi_object *obj;
acpi_status status;
+ u8 return_code;
- struct bios_args args;
- args.length = length;
- args.result_code = result_code;
- args.device_id = device_id;
- args.command = command;
- args.on_time = on_time;
- args.off_time = off_time;
+ struct bios_args args = {
+ .length = length,
+ .result_code = result_code,
+ .device_id = device_id,
+ .command = command,
+ .on_time = on_time,
+ .off_time = off_time
+ };
input.length = sizeof(struct bios_args);
input.pointer = &args;
- status = wmi_evaluate_method(DELL_LED_BIOS_GUID,
- 1,
- 1,
- &input,
- &output);
-
+ status = wmi_evaluate_method(DELL_LED_BIOS_GUID, 1, 1, &input, &output);
if (ACPI_FAILURE(status))
return status;
@@ -137,7 +76,7 @@ static int dell_led_perform_fn(u8 length,
if (!obj)
return -EINVAL;
- else if (obj->type != ACPI_TYPE_BUFFER) {
+ if (obj->type != ACPI_TYPE_BUFFER) {
kfree(obj);
return -EINVAL;
}
@@ -170,8 +109,7 @@ static int led_off(void)
0); /* not used */
}
-static int led_blink(unsigned char on_eighths,
- unsigned char off_eighths)
+static int led_blink(unsigned char on_eighths, unsigned char off_eighths)
{
return dell_led_perform_fn(5, /* Length of command */
INTERFACE_ERROR, /* Init to INTERFACE_ERROR */
@@ -182,7 +120,7 @@ static int led_blink(unsigned char on_eighths,
}
static void dell_led_set(struct led_classdev *led_cdev,
- enum led_brightness value)
+ enum led_brightness value)
{
if (value == LED_OFF)
led_off();
@@ -191,27 +129,22 @@ static void dell_led_set(struct led_classdev *led_cdev,
}
static int dell_led_blink(struct led_classdev *led_cdev,
- unsigned long *delay_on,
- unsigned long *delay_off)
+ unsigned long *delay_on, unsigned long *delay_off)
{
unsigned long on_eighths;
unsigned long off_eighths;
- /* The Dell LED delay is based on 125ms intervals.
- Need to round up to next interval. */
+ /*
+ * The Dell LED delay is based on 125ms intervals.
+ * Need to round up to next interval.
+ */
- on_eighths = (*delay_on + 124) / 125;
- if (0 == on_eighths)
- on_eighths = 1;
- if (on_eighths > 255)
- on_eighths = 255;
+ on_eighths = DIV_ROUND_UP(*delay_on, 125);
+ on_eighths = clamp_t(unsigned long, on_eighths, 1, 255);
*delay_on = on_eighths * 125;
- off_eighths = (*delay_off + 124) / 125;
- if (0 == off_eighths)
- off_eighths = 1;
- if (off_eighths > 255)
- off_eighths = 255;
+ off_eighths = DIV_ROUND_UP(*delay_off, 125);
+ off_eighths = clamp_t(unsigned long, off_eighths, 1, 255);
*delay_off = off_eighths * 125;
led_blink(on_eighths, off_eighths);
@@ -232,29 +165,21 @@ static int __init dell_led_init(void)
{
int error = 0;
- if (!wmi_has_guid(DELL_LED_BIOS_GUID) && !wmi_has_guid(DELL_APP_GUID))
+ if (!wmi_has_guid(DELL_LED_BIOS_GUID))
return -ENODEV;
- if (wmi_has_guid(DELL_LED_BIOS_GUID)) {
- error = led_off();
- if (error != 0)
- return -ENODEV;
-
- error = led_classdev_register(NULL, &dell_led);
- }
+ error = led_off();
+ if (error != 0)
+ return -ENODEV;
- return error;
+ return led_classdev_register(NULL, &dell_led);
}
static void __exit dell_led_exit(void)
{
- int error = 0;
+ led_classdev_unregister(&dell_led);
- if (wmi_has_guid(DELL_LED_BIOS_GUID)) {
- error = led_off();
- if (error == 0)
- led_classdev_unregister(&dell_led);
- }
+ led_off();
}
module_init(dell_led_init);
diff --git a/drivers/platform/x86/dell-wmi.c b/drivers/platform/x86/dell-wmi.c
index 75e637047d36..8a64c7967753 100644
--- a/drivers/platform/x86/dell-wmi.c
+++ b/drivers/platform/x86/dell-wmi.c
@@ -329,6 +329,10 @@ static void dell_wmi_process_key(int type, int code)
if (type == 0x0000 && code == 0xe025 && !wmi_requires_smbios_request)
return;
+ if (key->keycode == KEY_KBDILLUMTOGGLE)
+ dell_laptop_call_notifier(
+ DELL_LAPTOP_KBD_BACKLIGHT_BRIGHTNESS_CHANGED, NULL);
+
sparse_keymap_report_entry(dell_wmi_input_dev, key, 1, true);
}
@@ -603,23 +607,15 @@ static int __init dell_wmi_input_setup(void)
err = input_register_device(dell_wmi_input_dev);
if (err)
- goto err_free_keymap;
+ goto err_free_dev;
return 0;
- err_free_keymap:
- sparse_keymap_free(dell_wmi_input_dev);
err_free_dev:
input_free_device(dell_wmi_input_dev);
return err;
}
-static void dell_wmi_input_destroy(void)
-{
- sparse_keymap_free(dell_wmi_input_dev);
- input_unregister_device(dell_wmi_input_dev);
-}
-
/*
* Descriptor buffer is 128 byte long and contains:
*
@@ -740,7 +736,7 @@ static int __init dell_wmi_init(void)
status = wmi_install_notify_handler(DELL_EVENT_GUID,
dell_wmi_notify, NULL);
if (ACPI_FAILURE(status)) {
- dell_wmi_input_destroy();
+ input_unregister_device(dell_wmi_input_dev);
pr_err("Unable to register notify handler - %d\n", status);
return -ENODEV;
}
@@ -752,7 +748,7 @@ static int __init dell_wmi_init(void)
if (err) {
pr_err("Failed to enable WMI events\n");
wmi_remove_notify_handler(DELL_EVENT_GUID);
- dell_wmi_input_destroy();
+ input_unregister_device(dell_wmi_input_dev);
return err;
}
}
@@ -766,6 +762,6 @@ static void __exit dell_wmi_exit(void)
if (wmi_requires_smbios_request)
dell_wmi_events_set_enabled(false);
wmi_remove_notify_handler(DELL_EVENT_GUID);
- dell_wmi_input_destroy();
+ input_unregister_device(dell_wmi_input_dev);
}
module_exit(dell_wmi_exit);
diff --git a/drivers/platform/x86/eeepc-laptop.c b/drivers/platform/x86/eeepc-laptop.c
index 8cdf315f9730..2426399e1e04 100644
--- a/drivers/platform/x86/eeepc-laptop.c
+++ b/drivers/platform/x86/eeepc-laptop.c
@@ -150,6 +150,8 @@ static const struct key_entry eeepc_keymap[] = {
{ KE_KEY, 0x32, { KEY_SWITCHVIDEOMODE } },
{ KE_KEY, 0x37, { KEY_F13 } }, /* Disable Touchpad */
{ KE_KEY, 0x38, { KEY_F14 } },
+ { KE_IGNORE, 0x50, { KEY_RESERVED } }, /* AC plugged */
+ { KE_IGNORE, 0x51, { KEY_RESERVED } }, /* AC unplugged */
{ KE_END, 0 },
};
@@ -1205,14 +1207,12 @@ static int eeepc_input_init(struct eeepc_laptop *eeepc)
error = input_register_device(input);
if (error) {
pr_err("Unable to register input device\n");
- goto err_free_keymap;
+ goto err_free_dev;
}
eeepc->inputdev = input;
return 0;
-err_free_keymap:
- sparse_keymap_free(input);
err_free_dev:
input_free_device(input);
return error;
@@ -1220,10 +1220,8 @@ err_free_dev:
static void eeepc_input_exit(struct eeepc_laptop *eeepc)
{
- if (eeepc->inputdev) {
- sparse_keymap_free(eeepc->inputdev);
+ if (eeepc->inputdev)
input_unregister_device(eeepc->inputdev);
- }
eeepc->inputdev = NULL;
}
diff --git a/drivers/platform/x86/fujitsu-laptop.c b/drivers/platform/x86/fujitsu-laptop.c
index e12cc3504d48..84b561415875 100644
--- a/drivers/platform/x86/fujitsu-laptop.c
+++ b/drivers/platform/x86/fujitsu-laptop.c
@@ -32,18 +32,9 @@
* features made available on a range of Fujitsu laptops including the
* P2xxx/P5xxx/S6xxx/S7xxx series.
*
- * This driver exports a few files in /sys/devices/platform/fujitsu-laptop/;
- * others may be added at a later date.
- *
- * lcd_level - Screen brightness: contains a single integer in the
- * range 0..7. (rw)
- *
- * In addition to these platform device attributes the driver
- * registers itself in the Linux backlight control subsystem and is
- * available to userspace under /sys/class/backlight/fujitsu-laptop/.
- *
- * Hotkeys present on certain Fujitsu laptops (eg: the S6xxx series) are
- * also supported by this driver.
+ * This driver implements a vendor-specific backlight control interface for
+ * Fujitsu laptops and provides support for hotkeys present on certain Fujitsu
+ * laptops.
*
* This driver has been tested on a Fujitsu Lifebook S6410, S7020 and
* P8010. It should work on most P-series and S-series Lifebooks, but
@@ -66,6 +57,7 @@
#include <linux/backlight.h>
#include <linux/fb.h>
#include <linux/input.h>
+#include <linux/input/sparse-keymap.h>
#include <linux/kfifo.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
@@ -143,21 +135,16 @@
/* Device controlling the backlight and associated keys */
struct fujitsu_bl {
acpi_handle acpi_handle;
- struct acpi_device *dev;
struct input_dev *input;
char phys[32];
struct backlight_device *bl_device;
- struct platform_device *pf_device;
- int keycode1, keycode2, keycode3, keycode4, keycode5;
-
unsigned int max_brightness;
- unsigned int brightness_changed;
unsigned int brightness_level;
};
static struct fujitsu_bl *fujitsu_bl;
static int use_alt_lcd_levels = -1;
-static int disable_brightness_adjust = -1;
+static bool disable_brightness_adjust;
/* Device used to access hotkeys and other features on the laptop */
struct fujitsu_laptop {
@@ -227,42 +214,27 @@ static u32 dbg_level = 0x03;
/* Fujitsu ACPI interface function */
-static int call_fext_func(int cmd, int arg0, int arg1, int arg2)
+static int call_fext_func(int func, int op, int feature, int state)
{
- acpi_status status = AE_OK;
union acpi_object params[4] = {
- { .type = ACPI_TYPE_INTEGER },
- { .type = ACPI_TYPE_INTEGER },
- { .type = ACPI_TYPE_INTEGER },
- { .type = ACPI_TYPE_INTEGER }
+ { .integer.type = ACPI_TYPE_INTEGER, .integer.value = func },
+ { .integer.type = ACPI_TYPE_INTEGER, .integer.value = op },
+ { .integer.type = ACPI_TYPE_INTEGER, .integer.value = feature },
+ { .integer.type = ACPI_TYPE_INTEGER, .integer.value = state }
};
- struct acpi_object_list arg_list = { 4, &params[0] };
+ struct acpi_object_list arg_list = { 4, params };
unsigned long long value;
- acpi_handle handle = NULL;
+ acpi_status status;
- status = acpi_get_handle(fujitsu_laptop->acpi_handle, "FUNC", &handle);
+ status = acpi_evaluate_integer(fujitsu_laptop->acpi_handle, "FUNC",
+ &arg_list, &value);
if (ACPI_FAILURE(status)) {
- vdbg_printk(FUJLAPTOP_DBG_ERROR,
- "FUNC interface is not present\n");
+ vdbg_printk(FUJLAPTOP_DBG_ERROR, "Failed to evaluate FUNC\n");
return -ENODEV;
}
- params[0].integer.value = cmd;
- params[1].integer.value = arg0;
- params[2].integer.value = arg1;
- params[3].integer.value = arg2;
-
- status = acpi_evaluate_integer(handle, NULL, &arg_list, &value);
- if (ACPI_FAILURE(status)) {
- vdbg_printk(FUJLAPTOP_DBG_WARN,
- "FUNC 0x%x (args 0x%x, 0x%x, 0x%x) call failed\n",
- cmd, arg0, arg1, arg2);
- return -ENODEV;
- }
-
- vdbg_printk(FUJLAPTOP_DBG_TRACE,
- "FUNC 0x%x (args 0x%x, 0x%x, 0x%x) returned 0x%x\n",
- cmd, arg0, arg1, arg2, (int)value);
+ vdbg_printk(FUJLAPTOP_DBG_TRACE, "FUNC 0x%x (args 0x%x, 0x%x, 0x%x) returned 0x%x\n",
+ func, op, feature, state, (int)value);
return value;
}
@@ -368,49 +340,39 @@ static enum led_brightness eco_led_get(struct led_classdev *cdev)
static int set_lcd_level(int level)
{
- acpi_status status = AE_OK;
- acpi_handle handle = NULL;
-
- vdbg_printk(FUJLAPTOP_DBG_TRACE, "set lcd level via SBLL [%d]\n",
- level);
-
- if (level < 0 || level >= fujitsu_bl->max_brightness)
- return -EINVAL;
+ acpi_status status;
+ char *method;
- status = acpi_get_handle(fujitsu_bl->acpi_handle, "SBLL", &handle);
- if (ACPI_FAILURE(status)) {
- vdbg_printk(FUJLAPTOP_DBG_ERROR, "SBLL not present\n");
- return -ENODEV;
+ switch (use_alt_lcd_levels) {
+ case -1:
+ if (acpi_has_method(fujitsu_bl->acpi_handle, "SBL2"))
+ method = "SBL2";
+ else
+ method = "SBLL";
+ break;
+ case 1:
+ method = "SBL2";
+ break;
+ default:
+ method = "SBLL";
+ break;
}
-
- status = acpi_execute_simple_method(handle, NULL, level);
- if (ACPI_FAILURE(status))
- return -ENODEV;
-
- return 0;
-}
-
-static int set_lcd_level_alt(int level)
-{
- acpi_status status = AE_OK;
- acpi_handle handle = NULL;
-
- vdbg_printk(FUJLAPTOP_DBG_TRACE, "set lcd level via SBL2 [%d]\n",
- level);
+ vdbg_printk(FUJLAPTOP_DBG_TRACE, "set lcd level via %s [%d]\n",
+ method, level);
if (level < 0 || level >= fujitsu_bl->max_brightness)
return -EINVAL;
- status = acpi_get_handle(fujitsu_bl->acpi_handle, "SBL2", &handle);
+ status = acpi_execute_simple_method(fujitsu_bl->acpi_handle, method,
+ level);
if (ACPI_FAILURE(status)) {
- vdbg_printk(FUJLAPTOP_DBG_ERROR, "SBL2 not present\n");
+ vdbg_printk(FUJLAPTOP_DBG_ERROR, "Failed to evaluate %s\n",
+ method);
return -ENODEV;
}
- status = acpi_execute_simple_method(handle, NULL, level);
- if (ACPI_FAILURE(status))
- return -ENODEV;
+ fujitsu_bl->brightness_level = level;
return 0;
}
@@ -429,11 +391,6 @@ static int get_lcd_level(void)
fujitsu_bl->brightness_level = state & 0x0fffffff;
- if (state & 0x80000000)
- fujitsu_bl->brightness_changed = 1;
- else
- fujitsu_bl->brightness_changed = 0;
-
return fujitsu_bl->brightness_level;
}
@@ -458,30 +415,17 @@ static int get_max_brightness(void)
static int bl_get_brightness(struct backlight_device *b)
{
- return get_lcd_level();
+ return b->props.power == FB_BLANK_POWERDOWN ? 0 : get_lcd_level();
}
static int bl_update_status(struct backlight_device *b)
{
- int ret;
if (b->props.power == FB_BLANK_POWERDOWN)
- ret = call_fext_func(FUNC_BACKLIGHT, 0x1, 0x4, 0x3);
+ call_fext_func(FUNC_BACKLIGHT, 0x1, 0x4, 0x3);
else
- ret = call_fext_func(FUNC_BACKLIGHT, 0x1, 0x4, 0x0);
- if (ret != 0)
- vdbg_printk(FUJLAPTOP_DBG_ERROR,
- "Unable to adjust backlight power, error code %i\n",
- ret);
-
- if (use_alt_lcd_levels)
- ret = set_lcd_level_alt(b->props.brightness);
- else
- ret = set_lcd_level(b->props.brightness);
- if (ret != 0)
- vdbg_printk(FUJLAPTOP_DBG_ERROR,
- "Unable to adjust LCD brightness, error code %i\n",
- ret);
- return ret;
+ call_fext_func(FUNC_BACKLIGHT, 0x1, 0x4, 0x0);
+
+ return set_lcd_level(b->props.brightness);
}
static const struct backlight_ops fujitsu_bl_ops = {
@@ -489,84 +433,8 @@ static const struct backlight_ops fujitsu_bl_ops = {
.update_status = bl_update_status,
};
-/* Platform LCD brightness device */
-
-static ssize_t
-show_max_brightness(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
-
- int ret;
-
- ret = get_max_brightness();
- if (ret < 0)
- return ret;
-
- return sprintf(buf, "%i\n", ret);
-}
-
-static ssize_t
-show_brightness_changed(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
-
- int ret;
-
- ret = fujitsu_bl->brightness_changed;
- if (ret < 0)
- return ret;
-
- return sprintf(buf, "%i\n", ret);
-}
-
-static ssize_t show_lcd_level(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
-
- int ret;
-
- ret = get_lcd_level();
- if (ret < 0)
- return ret;
-
- return sprintf(buf, "%i\n", ret);
-}
-
-static ssize_t store_lcd_level(struct device *dev,
- struct device_attribute *attr, const char *buf,
- size_t count)
-{
-
- int level, ret;
-
- if (sscanf(buf, "%i", &level) != 1
- || (level < 0 || level >= fujitsu_bl->max_brightness))
- return -EINVAL;
-
- if (use_alt_lcd_levels)
- ret = set_lcd_level_alt(level);
- else
- ret = set_lcd_level(level);
- if (ret < 0)
- return ret;
-
- ret = get_lcd_level();
- if (ret < 0)
- return ret;
-
- return count;
-}
-
-static ssize_t
-ignore_store(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count)
-{
- return count;
-}
-
-static ssize_t
-show_lid_state(struct device *dev,
- struct device_attribute *attr, char *buf)
+static ssize_t lid_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
if (!(fujitsu_laptop->flags_supported & FLAG_LID))
return sprintf(buf, "unknown\n");
@@ -576,9 +444,8 @@ show_lid_state(struct device *dev,
return sprintf(buf, "closed\n");
}
-static ssize_t
-show_dock_state(struct device *dev,
- struct device_attribute *attr, char *buf)
+static ssize_t dock_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
if (!(fujitsu_laptop->flags_supported & FLAG_DOCK))
return sprintf(buf, "unknown\n");
@@ -588,9 +455,8 @@ show_dock_state(struct device *dev,
return sprintf(buf, "undocked\n");
}
-static ssize_t
-show_radios_state(struct device *dev,
- struct device_attribute *attr, char *buf)
+static ssize_t radios_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
if (!(fujitsu_laptop->flags_supported & FLAG_RFKILL))
return sprintf(buf, "unknown\n");
@@ -600,18 +466,11 @@ show_radios_state(struct device *dev,
return sprintf(buf, "killed\n");
}
-static DEVICE_ATTR(max_brightness, 0444, show_max_brightness, ignore_store);
-static DEVICE_ATTR(brightness_changed, 0444, show_brightness_changed,
- ignore_store);
-static DEVICE_ATTR(lcd_level, 0644, show_lcd_level, store_lcd_level);
-static DEVICE_ATTR(lid, 0444, show_lid_state, ignore_store);
-static DEVICE_ATTR(dock, 0444, show_dock_state, ignore_store);
-static DEVICE_ATTR(radios, 0444, show_radios_state, ignore_store);
+static DEVICE_ATTR_RO(lid);
+static DEVICE_ATTR_RO(dock);
+static DEVICE_ATTR_RO(radios);
static struct attribute *fujitsu_pf_attributes[] = {
- &dev_attr_brightness_changed.attr,
- &dev_attr_max_brightness.attr,
- &dev_attr_lcd_level.attr,
&dev_attr_lid.attr,
&dev_attr_dock.attr,
&dev_attr_radios.attr,
@@ -628,69 +487,66 @@ static struct platform_driver fujitsu_pf_driver = {
}
};
-static void __init dmi_check_cb_common(const struct dmi_system_id *id)
-{
- pr_info("Identified laptop model '%s'\n", id->ident);
-}
+/* ACPI device for LCD brightness control */
-static int __init dmi_check_cb_s6410(const struct dmi_system_id *id)
-{
- dmi_check_cb_common(id);
- fujitsu_bl->keycode1 = KEY_SCREENLOCK; /* "Lock" */
- fujitsu_bl->keycode2 = KEY_HELP; /* "Mobility Center" */
- return 1;
-}
+static const struct key_entry keymap_backlight[] = {
+ { KE_KEY, true, { KEY_BRIGHTNESSUP } },
+ { KE_KEY, false, { KEY_BRIGHTNESSDOWN } },
+ { KE_END, 0 }
+};
-static int __init dmi_check_cb_s6420(const struct dmi_system_id *id)
+static int acpi_fujitsu_bl_input_setup(struct acpi_device *device)
{
- dmi_check_cb_common(id);
- fujitsu_bl->keycode1 = KEY_SCREENLOCK; /* "Lock" */
- fujitsu_bl->keycode2 = KEY_HELP; /* "Mobility Center" */
- return 1;
+ struct fujitsu_bl *fujitsu_bl = acpi_driver_data(device);
+ int ret;
+
+ fujitsu_bl->input = devm_input_allocate_device(&device->dev);
+ if (!fujitsu_bl->input)
+ return -ENOMEM;
+
+ snprintf(fujitsu_bl->phys, sizeof(fujitsu_bl->phys),
+ "%s/video/input0", acpi_device_hid(device));
+
+ fujitsu_bl->input->name = acpi_device_name(device);
+ fujitsu_bl->input->phys = fujitsu_bl->phys;
+ fujitsu_bl->input->id.bustype = BUS_HOST;
+ fujitsu_bl->input->id.product = 0x06;
+
+ ret = sparse_keymap_setup(fujitsu_bl->input, keymap_backlight, NULL);
+ if (ret)
+ return ret;
+
+ return input_register_device(fujitsu_bl->input);
}
-static int __init dmi_check_cb_p8010(const struct dmi_system_id *id)
+static int fujitsu_backlight_register(struct acpi_device *device)
{
- dmi_check_cb_common(id);
- fujitsu_bl->keycode1 = KEY_HELP; /* "Support" */
- fujitsu_bl->keycode3 = KEY_SWITCHVIDEOMODE; /* "Presentation" */
- fujitsu_bl->keycode4 = KEY_WWW; /* "Internet" */
- return 1;
-}
+ const struct backlight_properties props = {
+ .brightness = fujitsu_bl->brightness_level,
+ .max_brightness = fujitsu_bl->max_brightness - 1,
+ .type = BACKLIGHT_PLATFORM
+ };
+ struct backlight_device *bd;
-static const struct dmi_system_id fujitsu_dmi_table[] __initconst = {
- {
- .ident = "Fujitsu Siemens S6410",
- .matches = {
- DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
- DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK S6410"),
- },
- .callback = dmi_check_cb_s6410},
- {
- .ident = "Fujitsu Siemens S6420",
- .matches = {
- DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
- DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK S6420"),
- },
- .callback = dmi_check_cb_s6420},
- {
- .ident = "Fujitsu LifeBook P8010",
- .matches = {
- DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
- DMI_MATCH(DMI_PRODUCT_NAME, "LifeBook P8010"),
- },
- .callback = dmi_check_cb_p8010},
- {}
-};
+ bd = devm_backlight_device_register(&device->dev, "fujitsu-laptop",
+ &device->dev, NULL,
+ &fujitsu_bl_ops, &props);
+ if (IS_ERR(bd))
+ return PTR_ERR(bd);
-/* ACPI device for LCD brightness control */
+ fujitsu_bl->bl_device = bd;
+
+ return 0;
+}
static int acpi_fujitsu_bl_add(struct acpi_device *device)
{
int state = 0;
- struct input_dev *input;
int error;
+ if (acpi_video_get_backlight_type() != acpi_backlight_vendor)
+ return -ENODEV;
+
if (!device)
return -EINVAL;
@@ -699,41 +555,20 @@ static int acpi_fujitsu_bl_add(struct acpi_device *device)
sprintf(acpi_device_class(device), "%s", ACPI_FUJITSU_CLASS);
device->driver_data = fujitsu_bl;
- fujitsu_bl->input = input = input_allocate_device();
- if (!input) {
- error = -ENOMEM;
- goto err_stop;
- }
-
- snprintf(fujitsu_bl->phys, sizeof(fujitsu_bl->phys),
- "%s/video/input0", acpi_device_hid(device));
-
- input->name = acpi_device_name(device);
- input->phys = fujitsu_bl->phys;
- input->id.bustype = BUS_HOST;
- input->id.product = 0x06;
- input->dev.parent = &device->dev;
- input->evbit[0] = BIT(EV_KEY);
- set_bit(KEY_BRIGHTNESSUP, input->keybit);
- set_bit(KEY_BRIGHTNESSDOWN, input->keybit);
- set_bit(KEY_UNKNOWN, input->keybit);
-
- error = input_register_device(input);
+ error = acpi_fujitsu_bl_input_setup(device);
if (error)
- goto err_free_input_dev;
+ return error;
error = acpi_bus_update_power(fujitsu_bl->acpi_handle, &state);
if (error) {
pr_err("Error reading power state\n");
- goto err_unregister_input_dev;
+ return error;
}
pr_info("ACPI: %s [%s] (%s)\n",
acpi_device_name(device), acpi_device_bid(device),
!device->power.state ? "on" : "off");
- fujitsu_bl->dev = device;
-
if (acpi_has_method(device->handle, METHOD_NAME__INI)) {
vdbg_printk(FUJLAPTOP_DBG_INFO, "Invoking _INI\n");
if (ACPI_FAILURE
@@ -742,45 +577,13 @@ static int acpi_fujitsu_bl_add(struct acpi_device *device)
pr_err("_INI Method failed\n");
}
- if (use_alt_lcd_levels == -1) {
- if (acpi_has_method(NULL, "\\_SB.PCI0.LPCB.FJEX.SBL2"))
- use_alt_lcd_levels = 1;
- else
- use_alt_lcd_levels = 0;
- vdbg_printk(FUJLAPTOP_DBG_TRACE, "auto-detected usealt as %i\n",
- use_alt_lcd_levels);
- }
-
- /* do config (detect defaults) */
- use_alt_lcd_levels = use_alt_lcd_levels == 1 ? 1 : 0;
- disable_brightness_adjust = disable_brightness_adjust == 1 ? 1 : 0;
- vdbg_printk(FUJLAPTOP_DBG_INFO,
- "config: [alt interface: %d], [adjust disable: %d]\n",
- use_alt_lcd_levels, disable_brightness_adjust);
-
if (get_max_brightness() <= 0)
fujitsu_bl->max_brightness = FUJITSU_LCD_N_LEVELS;
get_lcd_level();
- return 0;
-
-err_unregister_input_dev:
- input_unregister_device(input);
- input = NULL;
-err_free_input_dev:
- input_free_device(input);
-err_stop:
- return error;
-}
-
-static int acpi_fujitsu_bl_remove(struct acpi_device *device)
-{
- struct fujitsu_bl *fujitsu_bl = acpi_driver_data(device);
- struct input_dev *input = fujitsu_bl->input;
-
- input_unregister_device(input);
-
- fujitsu_bl->acpi_handle = NULL;
+ error = fujitsu_backlight_register(device);
+ if (error)
+ return error;
return 0;
}
@@ -790,62 +593,164 @@ static int acpi_fujitsu_bl_remove(struct acpi_device *device)
static void acpi_fujitsu_bl_notify(struct acpi_device *device, u32 event)
{
struct input_dev *input;
- int keycode;
int oldb, newb;
input = fujitsu_bl->input;
- switch (event) {
- case ACPI_FUJITSU_NOTIFY_CODE1:
- keycode = 0;
- oldb = fujitsu_bl->brightness_level;
- get_lcd_level();
- newb = fujitsu_bl->brightness_level;
-
- vdbg_printk(FUJLAPTOP_DBG_TRACE,
- "brightness button event [%i -> %i (%i)]\n",
- oldb, newb, fujitsu_bl->brightness_changed);
-
- if (oldb < newb) {
- if (disable_brightness_adjust != 1) {
- if (use_alt_lcd_levels)
- set_lcd_level_alt(newb);
- else
- set_lcd_level(newb);
- }
- keycode = KEY_BRIGHTNESSUP;
- } else if (oldb > newb) {
- if (disable_brightness_adjust != 1) {
- if (use_alt_lcd_levels)
- set_lcd_level_alt(newb);
- else
- set_lcd_level(newb);
- }
- keycode = KEY_BRIGHTNESSDOWN;
- }
- break;
- default:
- keycode = KEY_UNKNOWN;
+ if (event != ACPI_FUJITSU_NOTIFY_CODE1) {
vdbg_printk(FUJLAPTOP_DBG_WARN,
"unsupported event [0x%x]\n", event);
- break;
+ sparse_keymap_report_event(input, -1, 1, true);
+ return;
}
- if (keycode != 0) {
- input_report_key(input, keycode, 1);
- input_sync(input);
- input_report_key(input, keycode, 0);
- input_sync(input);
- }
+ oldb = fujitsu_bl->brightness_level;
+ get_lcd_level();
+ newb = fujitsu_bl->brightness_level;
+
+ vdbg_printk(FUJLAPTOP_DBG_TRACE, "brightness button event [%i -> %i]\n",
+ oldb, newb);
+
+ if (oldb == newb)
+ return;
+
+ if (!disable_brightness_adjust)
+ set_lcd_level(newb);
+
+ sparse_keymap_report_event(input, oldb < newb, 1, true);
}
/* ACPI device for hotkey handling */
+static const struct key_entry keymap_default[] = {
+ { KE_KEY, KEY1_CODE, { KEY_PROG1 } },
+ { KE_KEY, KEY2_CODE, { KEY_PROG2 } },
+ { KE_KEY, KEY3_CODE, { KEY_PROG3 } },
+ { KE_KEY, KEY4_CODE, { KEY_PROG4 } },
+ { KE_KEY, KEY5_CODE, { KEY_RFKILL } },
+ { KE_KEY, BIT(26), { KEY_TOUCHPAD_TOGGLE } },
+ { KE_END, 0 }
+};
+
+static const struct key_entry keymap_s64x0[] = {
+ { KE_KEY, KEY1_CODE, { KEY_SCREENLOCK } }, /* "Lock" */
+ { KE_KEY, KEY2_CODE, { KEY_HELP } }, /* "Mobility Center */
+ { KE_KEY, KEY3_CODE, { KEY_PROG3 } },
+ { KE_KEY, KEY4_CODE, { KEY_PROG4 } },
+ { KE_END, 0 }
+};
+
+static const struct key_entry keymap_p8010[] = {
+ { KE_KEY, KEY1_CODE, { KEY_HELP } }, /* "Support" */
+ { KE_KEY, KEY2_CODE, { KEY_PROG2 } },
+ { KE_KEY, KEY3_CODE, { KEY_SWITCHVIDEOMODE } }, /* "Presentation" */
+ { KE_KEY, KEY4_CODE, { KEY_WWW } }, /* "WWW" */
+ { KE_END, 0 }
+};
+
+static const struct key_entry *keymap = keymap_default;
+
+static int fujitsu_laptop_dmi_keymap_override(const struct dmi_system_id *id)
+{
+ pr_info("Identified laptop model '%s'\n", id->ident);
+ keymap = id->driver_data;
+ return 1;
+}
+
+static const struct dmi_system_id fujitsu_laptop_dmi_table[] = {
+ {
+ .callback = fujitsu_laptop_dmi_keymap_override,
+ .ident = "Fujitsu Siemens S6410",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK S6410"),
+ },
+ .driver_data = (void *)keymap_s64x0
+ },
+ {
+ .callback = fujitsu_laptop_dmi_keymap_override,
+ .ident = "Fujitsu Siemens S6420",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK S6420"),
+ },
+ .driver_data = (void *)keymap_s64x0
+ },
+ {
+ .callback = fujitsu_laptop_dmi_keymap_override,
+ .ident = "Fujitsu LifeBook P8010",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "LifeBook P8010"),
+ },
+ .driver_data = (void *)keymap_p8010
+ },
+ {}
+};
+
+static int acpi_fujitsu_laptop_input_setup(struct acpi_device *device)
+{
+ struct fujitsu_laptop *fujitsu_laptop = acpi_driver_data(device);
+ int ret;
+
+ fujitsu_laptop->input = devm_input_allocate_device(&device->dev);
+ if (!fujitsu_laptop->input)
+ return -ENOMEM;
+
+ snprintf(fujitsu_laptop->phys, sizeof(fujitsu_laptop->phys),
+ "%s/video/input0", acpi_device_hid(device));
+
+ fujitsu_laptop->input->name = acpi_device_name(device);
+ fujitsu_laptop->input->phys = fujitsu_laptop->phys;
+ fujitsu_laptop->input->id.bustype = BUS_HOST;
+ fujitsu_laptop->input->id.product = 0x06;
+
+ dmi_check_system(fujitsu_laptop_dmi_table);
+ ret = sparse_keymap_setup(fujitsu_laptop->input, keymap, NULL);
+ if (ret)
+ return ret;
+
+ return input_register_device(fujitsu_laptop->input);
+}
+
+static int fujitsu_laptop_platform_add(void)
+{
+ int ret;
+
+ fujitsu_laptop->pf_device = platform_device_alloc("fujitsu-laptop", -1);
+ if (!fujitsu_laptop->pf_device)
+ return -ENOMEM;
+
+ ret = platform_device_add(fujitsu_laptop->pf_device);
+ if (ret)
+ goto err_put_platform_device;
+
+ ret = sysfs_create_group(&fujitsu_laptop->pf_device->dev.kobj,
+ &fujitsu_pf_attribute_group);
+ if (ret)
+ goto err_del_platform_device;
+
+ return 0;
+
+err_del_platform_device:
+ platform_device_del(fujitsu_laptop->pf_device);
+err_put_platform_device:
+ platform_device_put(fujitsu_laptop->pf_device);
+
+ return ret;
+}
+
+static void fujitsu_laptop_platform_remove(void)
+{
+ sysfs_remove_group(&fujitsu_laptop->pf_device->dev.kobj,
+ &fujitsu_pf_attribute_group);
+ platform_device_unregister(fujitsu_laptop->pf_device);
+}
+
static int acpi_fujitsu_laptop_add(struct acpi_device *device)
{
int result = 0;
int state = 0;
- struct input_dev *input;
int error;
int i;
@@ -867,38 +772,14 @@ static int acpi_fujitsu_laptop_add(struct acpi_device *device)
goto err_stop;
}
- fujitsu_laptop->input = input = input_allocate_device();
- if (!input) {
- error = -ENOMEM;
- goto err_free_fifo;
- }
-
- snprintf(fujitsu_laptop->phys, sizeof(fujitsu_laptop->phys),
- "%s/video/input0", acpi_device_hid(device));
-
- input->name = acpi_device_name(device);
- input->phys = fujitsu_laptop->phys;
- input->id.bustype = BUS_HOST;
- input->id.product = 0x06;
- input->dev.parent = &device->dev;
-
- set_bit(EV_KEY, input->evbit);
- set_bit(fujitsu_bl->keycode1, input->keybit);
- set_bit(fujitsu_bl->keycode2, input->keybit);
- set_bit(fujitsu_bl->keycode3, input->keybit);
- set_bit(fujitsu_bl->keycode4, input->keybit);
- set_bit(fujitsu_bl->keycode5, input->keybit);
- set_bit(KEY_TOUCHPAD_TOGGLE, input->keybit);
- set_bit(KEY_UNKNOWN, input->keybit);
-
- error = input_register_device(input);
+ error = acpi_fujitsu_laptop_input_setup(device);
if (error)
- goto err_free_input_dev;
+ goto err_free_fifo;
error = acpi_bus_update_power(fujitsu_laptop->acpi_handle, &state);
if (error) {
pr_err("Error reading power state\n");
- goto err_unregister_input_dev;
+ goto err_free_fifo;
}
pr_info("ACPI: %s [%s] (%s)\n",
@@ -936,9 +817,22 @@ static int acpi_fujitsu_laptop_add(struct acpi_device *device)
/* Suspect this is a keymap of the application panel, print it */
pr_info("BTNI: [0x%x]\n", call_fext_func(FUNC_BUTTONS, 0x0, 0x0, 0x0));
+ /* Sync backlight power status */
+ if (fujitsu_bl->bl_device &&
+ acpi_video_get_backlight_type() == acpi_backlight_vendor) {
+ if (call_fext_func(FUNC_BACKLIGHT, 0x2, 0x4, 0x0) == 3)
+ fujitsu_bl->bl_device->props.power = FB_BLANK_POWERDOWN;
+ else
+ fujitsu_bl->bl_device->props.power = FB_BLANK_UNBLANK;
+ }
+
+ error = fujitsu_laptop_platform_add();
+ if (error)
+ goto err_free_fifo;
+
#if IS_ENABLED(CONFIG_LEDS_CLASS)
if (call_fext_func(FUNC_LEDS, 0x0, 0x0, 0x0) & LOGOLAMP_POWERON) {
- result = led_classdev_register(&fujitsu_bl->pf_device->dev,
+ result = led_classdev_register(&fujitsu_laptop->pf_device->dev,
&logolamp_led);
if (result == 0) {
fujitsu_laptop->logolamp_registered = 1;
@@ -950,7 +844,7 @@ static int acpi_fujitsu_laptop_add(struct acpi_device *device)
if ((call_fext_func(FUNC_LEDS, 0x0, 0x0, 0x0) & KEYBOARD_LAMPS) &&
(call_fext_func(FUNC_BUTTONS, 0x0, 0x0, 0x0) == 0x0)) {
- result = led_classdev_register(&fujitsu_bl->pf_device->dev,
+ result = led_classdev_register(&fujitsu_laptop->pf_device->dev,
&kblamps_led);
if (result == 0) {
fujitsu_laptop->kblamps_registered = 1;
@@ -967,7 +861,7 @@ static int acpi_fujitsu_laptop_add(struct acpi_device *device)
* that an RF LED is present.
*/
if (call_fext_func(FUNC_BUTTONS, 0x0, 0x0, 0x0) & BIT(24)) {
- result = led_classdev_register(&fujitsu_bl->pf_device->dev,
+ result = led_classdev_register(&fujitsu_laptop->pf_device->dev,
&radio_led);
if (result == 0) {
fujitsu_laptop->radio_led_registered = 1;
@@ -984,7 +878,7 @@ static int acpi_fujitsu_laptop_add(struct acpi_device *device)
*/
if ((call_fext_func(FUNC_LEDS, 0x0, 0x0, 0x0) & BIT(14)) &&
(call_fext_func(FUNC_LEDS, 0x2, ECO_LED, 0x0) != UNSUPPORTED_CMD)) {
- result = led_classdev_register(&fujitsu_bl->pf_device->dev,
+ result = led_classdev_register(&fujitsu_laptop->pf_device->dev,
&eco_led);
if (result == 0) {
fujitsu_laptop->eco_led_registered = 1;
@@ -997,11 +891,6 @@ static int acpi_fujitsu_laptop_add(struct acpi_device *device)
return result;
-err_unregister_input_dev:
- input_unregister_device(input);
- input = NULL;
-err_free_input_dev:
- input_free_device(input);
err_free_fifo:
kfifo_free(&fujitsu_laptop->fifo);
err_stop:
@@ -1011,7 +900,6 @@ err_stop:
static int acpi_fujitsu_laptop_remove(struct acpi_device *device)
{
struct fujitsu_laptop *fujitsu_laptop = acpi_driver_data(device);
- struct input_dev *input = fujitsu_laptop->input;
#if IS_ENABLED(CONFIG_LEDS_CLASS)
if (fujitsu_laptop->logolamp_registered)
@@ -1027,7 +915,7 @@ static int acpi_fujitsu_laptop_remove(struct acpi_device *device)
led_classdev_unregister(&eco_led);
#endif
- input_unregister_device(input);
+ fujitsu_laptop_platform_remove();
kfifo_free(&fujitsu_laptop->fifo);
@@ -1036,61 +924,54 @@ static int acpi_fujitsu_laptop_remove(struct acpi_device *device)
return 0;
}
-static void acpi_fujitsu_laptop_press(int keycode)
+static void acpi_fujitsu_laptop_press(int scancode)
{
struct input_dev *input = fujitsu_laptop->input;
int status;
status = kfifo_in_locked(&fujitsu_laptop->fifo,
- (unsigned char *)&keycode, sizeof(keycode),
+ (unsigned char *)&scancode, sizeof(scancode),
&fujitsu_laptop->fifo_lock);
- if (status != sizeof(keycode)) {
+ if (status != sizeof(scancode)) {
vdbg_printk(FUJLAPTOP_DBG_WARN,
- "Could not push keycode [0x%x]\n", keycode);
+ "Could not push scancode [0x%x]\n", scancode);
return;
}
- input_report_key(input, keycode, 1);
- input_sync(input);
+ sparse_keymap_report_event(input, scancode, 1, false);
vdbg_printk(FUJLAPTOP_DBG_TRACE,
- "Push keycode into ringbuffer [%d]\n", keycode);
+ "Push scancode into ringbuffer [0x%x]\n", scancode);
}
static void acpi_fujitsu_laptop_release(void)
{
struct input_dev *input = fujitsu_laptop->input;
- int keycode, status;
+ int scancode, status;
while (true) {
status = kfifo_out_locked(&fujitsu_laptop->fifo,
- (unsigned char *)&keycode,
- sizeof(keycode),
+ (unsigned char *)&scancode,
+ sizeof(scancode),
&fujitsu_laptop->fifo_lock);
- if (status != sizeof(keycode))
+ if (status != sizeof(scancode))
return;
- input_report_key(input, keycode, 0);
- input_sync(input);
+ sparse_keymap_report_event(input, scancode, 0, false);
vdbg_printk(FUJLAPTOP_DBG_TRACE,
- "Pop keycode from ringbuffer [%d]\n", keycode);
+ "Pop scancode from ringbuffer [0x%x]\n", scancode);
}
}
static void acpi_fujitsu_laptop_notify(struct acpi_device *device, u32 event)
{
struct input_dev *input;
- int keycode;
- unsigned int irb = 1;
- int i;
+ int scancode, i = 0;
+ unsigned int irb;
input = fujitsu_laptop->input;
if (event != ACPI_FUJITSU_NOTIFY_CODE1) {
- keycode = KEY_UNKNOWN;
vdbg_printk(FUJLAPTOP_DBG_WARN,
"Unsupported event [0x%x]\n", event);
- input_report_key(input, keycode, 1);
- input_sync(input);
- input_report_key(input, keycode, 0);
- input_sync(input);
+ sparse_keymap_report_event(input, -1, 1, true);
return;
}
@@ -1098,40 +979,16 @@ static void acpi_fujitsu_laptop_notify(struct acpi_device *device, u32 event)
fujitsu_laptop->flags_state =
call_fext_func(FUNC_FLAGS, 0x4, 0x0, 0x0);
- i = 0;
- while ((irb =
- call_fext_func(FUNC_BUTTONS, 0x1, 0x0, 0x0)) != 0
- && (i++) < MAX_HOTKEY_RINGBUFFER_SIZE) {
- switch (irb & 0x4ff) {
- case KEY1_CODE:
- keycode = fujitsu_bl->keycode1;
- break;
- case KEY2_CODE:
- keycode = fujitsu_bl->keycode2;
- break;
- case KEY3_CODE:
- keycode = fujitsu_bl->keycode3;
- break;
- case KEY4_CODE:
- keycode = fujitsu_bl->keycode4;
- break;
- case KEY5_CODE:
- keycode = fujitsu_bl->keycode5;
- break;
- case 0:
- keycode = 0;
- break;
- default:
+ while ((irb = call_fext_func(FUNC_BUTTONS, 0x1, 0x0, 0x0)) != 0 &&
+ i++ < MAX_HOTKEY_RINGBUFFER_SIZE) {
+ scancode = irb & 0x4ff;
+ if (sparse_keymap_entry_from_scancode(input, scancode))
+ acpi_fujitsu_laptop_press(scancode);
+ else if (scancode == 0)
+ acpi_fujitsu_laptop_release();
+ else
vdbg_printk(FUJLAPTOP_DBG_WARN,
"Unknown GIRB result [%x]\n", irb);
- keycode = -1;
- break;
- }
-
- if (keycode > 0)
- acpi_fujitsu_laptop_press(keycode);
- else if (keycode == 0)
- acpi_fujitsu_laptop_release();
}
/* On some models (first seen on the Skylake-based Lifebook
@@ -1139,14 +996,8 @@ static void acpi_fujitsu_laptop_notify(struct acpi_device *device, u32 event)
* handled in software; its state is queried using FUNC_FLAGS
*/
if ((fujitsu_laptop->flags_supported & BIT(26)) &&
- (call_fext_func(FUNC_FLAGS, 0x1, 0x0, 0x0) & BIT(26))) {
- keycode = KEY_TOUCHPAD_TOGGLE;
- input_report_key(input, keycode, 1);
- input_sync(input);
- input_report_key(input, keycode, 0);
- input_sync(input);
- }
-
+ (call_fext_func(FUNC_FLAGS, 0x1, 0x0, 0x0) & BIT(26)))
+ sparse_keymap_report_event(input, BIT(26), 1, true);
}
/* Initialization */
@@ -1162,7 +1013,6 @@ static struct acpi_driver acpi_fujitsu_bl_driver = {
.ids = fujitsu_bl_device_ids,
.ops = {
.add = acpi_fujitsu_bl_add,
- .remove = acpi_fujitsu_bl_remove,
.notify = acpi_fujitsu_bl_notify,
},
};
@@ -1192,7 +1042,7 @@ MODULE_DEVICE_TABLE(acpi, fujitsu_ids);
static int __init fujitsu_init(void)
{
- int ret, max_brightness;
+ int ret;
if (acpi_disabled)
return -ENODEV;
@@ -1200,100 +1050,40 @@ static int __init fujitsu_init(void)
fujitsu_bl = kzalloc(sizeof(struct fujitsu_bl), GFP_KERNEL);
if (!fujitsu_bl)
return -ENOMEM;
- fujitsu_bl->keycode1 = KEY_PROG1;
- fujitsu_bl->keycode2 = KEY_PROG2;
- fujitsu_bl->keycode3 = KEY_PROG3;
- fujitsu_bl->keycode4 = KEY_PROG4;
- fujitsu_bl->keycode5 = KEY_RFKILL;
- dmi_check_system(fujitsu_dmi_table);
ret = acpi_bus_register_driver(&acpi_fujitsu_bl_driver);
if (ret)
- goto fail_acpi;
+ goto err_free_fujitsu_bl;
/* Register platform stuff */
- fujitsu_bl->pf_device = platform_device_alloc("fujitsu-laptop", -1);
- if (!fujitsu_bl->pf_device) {
- ret = -ENOMEM;
- goto fail_platform_driver;
- }
-
- ret = platform_device_add(fujitsu_bl->pf_device);
- if (ret)
- goto fail_platform_device1;
-
- ret =
- sysfs_create_group(&fujitsu_bl->pf_device->dev.kobj,
- &fujitsu_pf_attribute_group);
- if (ret)
- goto fail_platform_device2;
-
- /* Register backlight stuff */
-
- if (acpi_video_get_backlight_type() == acpi_backlight_vendor) {
- struct backlight_properties props;
-
- memset(&props, 0, sizeof(struct backlight_properties));
- max_brightness = fujitsu_bl->max_brightness;
- props.type = BACKLIGHT_PLATFORM;
- props.max_brightness = max_brightness - 1;
- fujitsu_bl->bl_device = backlight_device_register("fujitsu-laptop",
- NULL, NULL,
- &fujitsu_bl_ops,
- &props);
- if (IS_ERR(fujitsu_bl->bl_device)) {
- ret = PTR_ERR(fujitsu_bl->bl_device);
- fujitsu_bl->bl_device = NULL;
- goto fail_sysfs_group;
- }
- fujitsu_bl->bl_device->props.brightness = fujitsu_bl->brightness_level;
- }
-
ret = platform_driver_register(&fujitsu_pf_driver);
if (ret)
- goto fail_backlight;
+ goto err_unregister_acpi;
/* Register laptop driver */
fujitsu_laptop = kzalloc(sizeof(struct fujitsu_laptop), GFP_KERNEL);
if (!fujitsu_laptop) {
ret = -ENOMEM;
- goto fail_laptop;
+ goto err_unregister_platform_driver;
}
ret = acpi_bus_register_driver(&acpi_fujitsu_laptop_driver);
if (ret)
- goto fail_laptop1;
-
- /* Sync backlight power status (needs FUJ02E3 device, hence deferred) */
- if (acpi_video_get_backlight_type() == acpi_backlight_vendor) {
- if (call_fext_func(FUNC_BACKLIGHT, 0x2, 0x4, 0x0) == 3)
- fujitsu_bl->bl_device->props.power = FB_BLANK_POWERDOWN;
- else
- fujitsu_bl->bl_device->props.power = FB_BLANK_UNBLANK;
- }
+ goto err_free_fujitsu_laptop;
pr_info("driver " FUJITSU_DRIVER_VERSION " successfully loaded\n");
return 0;
-fail_laptop1:
+err_free_fujitsu_laptop:
kfree(fujitsu_laptop);
-fail_laptop:
+err_unregister_platform_driver:
platform_driver_unregister(&fujitsu_pf_driver);
-fail_backlight:
- backlight_device_unregister(fujitsu_bl->bl_device);
-fail_sysfs_group:
- sysfs_remove_group(&fujitsu_bl->pf_device->dev.kobj,
- &fujitsu_pf_attribute_group);
-fail_platform_device2:
- platform_device_del(fujitsu_bl->pf_device);
-fail_platform_device1:
- platform_device_put(fujitsu_bl->pf_device);
-fail_platform_driver:
+err_unregister_acpi:
acpi_bus_unregister_driver(&acpi_fujitsu_bl_driver);
-fail_acpi:
+err_free_fujitsu_bl:
kfree(fujitsu_bl);
return ret;
@@ -1307,13 +1097,6 @@ static void __exit fujitsu_cleanup(void)
platform_driver_unregister(&fujitsu_pf_driver);
- backlight_device_unregister(fujitsu_bl->bl_device);
-
- sysfs_remove_group(&fujitsu_bl->pf_device->dev.kobj,
- &fujitsu_pf_attribute_group);
-
- platform_device_unregister(fujitsu_bl->pf_device);
-
acpi_bus_unregister_driver(&acpi_fujitsu_bl_driver);
kfree(fujitsu_bl);
@@ -1324,11 +1107,10 @@ static void __exit fujitsu_cleanup(void)
module_init(fujitsu_init);
module_exit(fujitsu_cleanup);
-module_param(use_alt_lcd_levels, uint, 0644);
-MODULE_PARM_DESC(use_alt_lcd_levels,
- "Use alternative interface for lcd_levels (needed for Lifebook s6410).");
-module_param(disable_brightness_adjust, uint, 0644);
-MODULE_PARM_DESC(disable_brightness_adjust, "Disable brightness adjustment .");
+module_param(use_alt_lcd_levels, int, 0644);
+MODULE_PARM_DESC(use_alt_lcd_levels, "Interface used for setting LCD brightness level (-1 = auto, 0 = force SBLL, 1 = force SBL2)");
+module_param(disable_brightness_adjust, bool, 0644);
+MODULE_PARM_DESC(disable_brightness_adjust, "Disable LCD brightness adjustment");
#ifdef CONFIG_FUJITSU_LAPTOP_DEBUG
module_param_named(debug, dbg_level, uint, 0644);
MODULE_PARM_DESC(debug, "Sets debug level bit-mask");
diff --git a/drivers/platform/x86/hp-wireless.c b/drivers/platform/x86/hp-wireless.c
index 988eedbd7c63..d860ea0d0e60 100644
--- a/drivers/platform/x86/hp-wireless.c
+++ b/drivers/platform/x86/hp-wireless.c
@@ -1,7 +1,7 @@
/*
- * hp-wireless button for Windows 8
+ * Airplane mode button for HP & Xiaomi laptops
*
- * Copyright (C) 2014 Alex Hung <alex.hung@canonical.com>
+ * Copyright (C) 2014-2017 Alex Hung <alex.hung@canonical.com>
*
* 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
@@ -29,11 +29,13 @@
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Alex Hung");
MODULE_ALIAS("acpi*:HPQ6001:*");
+MODULE_ALIAS("acpi*:WSTADEF:*");
static struct input_dev *hpwl_input_dev;
static const struct acpi_device_id hpwl_ids[] = {
{"HPQ6001", 0},
+ {"WSTADEF", 0},
{"", 0},
};
@@ -112,7 +114,6 @@ static int __init hpwl_init(void)
{
int err;
- pr_info("Initializing HPQ6001 module\n");
err = acpi_bus_register_driver(&hpwl_driver);
if (err)
pr_err("Unable to register HP wireless control driver.\n");
@@ -122,7 +123,6 @@ static int __init hpwl_init(void)
static void __exit hpwl_exit(void)
{
- pr_info("Exiting HPQ6001 module\n");
acpi_bus_unregister_driver(&hpwl_driver);
}
diff --git a/drivers/platform/x86/hp-wmi.c b/drivers/platform/x86/hp-wmi.c
index 96ffda493266..5c5efccf9f19 100644
--- a/drivers/platform/x86/hp-wmi.c
+++ b/drivers/platform/x86/hp-wmi.c
@@ -290,7 +290,7 @@ static int hp_wmi_tablet_state(void)
int ret = hp_wmi_perform_query(HPWMI_HARDWARE_QUERY, 0, &state,
sizeof(state), sizeof(state));
if (ret)
- return ret;
+ return -EINVAL;
return (state & 0x4) ? 1 : 0;
}
@@ -572,10 +572,12 @@ static void hp_wmi_notify(u32 value, void *context)
switch (event_id) {
case HPWMI_DOCK_EVENT:
- input_report_switch(hp_wmi_input_dev, SW_DOCK,
- hp_wmi_dock_state());
- input_report_switch(hp_wmi_input_dev, SW_TABLET_MODE,
- hp_wmi_tablet_state());
+ if (test_bit(SW_DOCK, hp_wmi_input_dev->swbit))
+ input_report_switch(hp_wmi_input_dev, SW_DOCK,
+ hp_wmi_dock_state());
+ if (test_bit(SW_TABLET_MODE, hp_wmi_input_dev->swbit))
+ input_report_switch(hp_wmi_input_dev, SW_TABLET_MODE,
+ hp_wmi_tablet_state());
input_sync(hp_wmi_input_dev);
break;
case HPWMI_PARK_HDD:
@@ -644,6 +646,7 @@ static int __init hp_wmi_input_setup(void)
{
acpi_status status;
int err;
+ int val;
hp_wmi_input_dev = input_allocate_device();
if (!hp_wmi_input_dev)
@@ -654,17 +657,26 @@ static int __init hp_wmi_input_setup(void)
hp_wmi_input_dev->id.bustype = BUS_HOST;
__set_bit(EV_SW, hp_wmi_input_dev->evbit);
- __set_bit(SW_DOCK, hp_wmi_input_dev->swbit);
- __set_bit(SW_TABLET_MODE, hp_wmi_input_dev->swbit);
+
+ /* Dock */
+ val = hp_wmi_dock_state();
+ if (!(val < 0)) {
+ __set_bit(SW_DOCK, hp_wmi_input_dev->swbit);
+ input_report_switch(hp_wmi_input_dev, SW_DOCK, val);
+ }
+
+ /* Tablet mode */
+ val = hp_wmi_tablet_state();
+ if (!(val < 0)) {
+ __set_bit(SW_TABLET_MODE, hp_wmi_input_dev->swbit);
+ input_report_switch(hp_wmi_input_dev, SW_TABLET_MODE, val);
+ }
err = sparse_keymap_setup(hp_wmi_input_dev, hp_wmi_keymap, NULL);
if (err)
goto err_free_dev;
/* Set initial hardware state */
- input_report_switch(hp_wmi_input_dev, SW_DOCK, hp_wmi_dock_state());
- input_report_switch(hp_wmi_input_dev, SW_TABLET_MODE,
- hp_wmi_tablet_state());
input_sync(hp_wmi_input_dev);
if (!hp_wmi_bios_2009_later() && hp_wmi_bios_2008_later())
@@ -673,7 +685,7 @@ static int __init hp_wmi_input_setup(void)
status = wmi_install_notify_handler(HPWMI_EVENT_GUID, hp_wmi_notify, NULL);
if (ACPI_FAILURE(status)) {
err = -EIO;
- goto err_free_keymap;
+ goto err_free_dev;
}
err = input_register_device(hp_wmi_input_dev);
@@ -684,8 +696,6 @@ static int __init hp_wmi_input_setup(void)
err_uninstall_notifier:
wmi_remove_notify_handler(HPWMI_EVENT_GUID);
- err_free_keymap:
- sparse_keymap_free(hp_wmi_input_dev);
err_free_dev:
input_free_device(hp_wmi_input_dev);
return err;
@@ -694,7 +704,6 @@ static int __init hp_wmi_input_setup(void)
static void hp_wmi_input_destroy(void)
{
wmi_remove_notify_handler(HPWMI_EVENT_GUID);
- sparse_keymap_free(hp_wmi_input_dev);
input_unregister_device(hp_wmi_input_dev);
}
@@ -950,10 +959,12 @@ static int hp_wmi_resume_handler(struct device *device)
* changed.
*/
if (hp_wmi_input_dev) {
- input_report_switch(hp_wmi_input_dev, SW_DOCK,
- hp_wmi_dock_state());
- input_report_switch(hp_wmi_input_dev, SW_TABLET_MODE,
- hp_wmi_tablet_state());
+ if (test_bit(SW_DOCK, hp_wmi_input_dev->swbit))
+ input_report_switch(hp_wmi_input_dev, SW_DOCK,
+ hp_wmi_dock_state());
+ if (test_bit(SW_TABLET_MODE, hp_wmi_input_dev->swbit))
+ input_report_switch(hp_wmi_input_dev, SW_TABLET_MODE,
+ hp_wmi_tablet_state());
input_sync(hp_wmi_input_dev);
}
diff --git a/drivers/platform/x86/ideapad-laptop.c b/drivers/platform/x86/ideapad-laptop.c
index f46ece2ce3c4..ca5eeb4d417d 100644
--- a/drivers/platform/x86/ideapad-laptop.c
+++ b/drivers/platform/x86/ideapad-laptop.c
@@ -604,14 +604,12 @@ static int ideapad_input_init(struct ideapad_private *priv)
error = input_register_device(inputdev);
if (error) {
pr_err("Unable to register input device\n");
- goto err_free_keymap;
+ goto err_free_dev;
}
priv->inputdev = inputdev;
return 0;
-err_free_keymap:
- sparse_keymap_free(inputdev);
err_free_dev:
input_free_device(inputdev);
return error;
@@ -619,7 +617,6 @@ err_free_dev:
static void ideapad_input_exit(struct ideapad_private *priv)
{
- sparse_keymap_free(priv->inputdev);
input_unregister_device(priv->inputdev);
priv->inputdev = NULL;
}
@@ -872,6 +869,13 @@ static const struct dmi_system_id no_hw_rfkill_list[] = {
},
},
{
+ .ident = "Lenovo ideapad 310-15IKB",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+ DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo ideapad 310-15IKB"),
+ },
+ },
+ {
.ident = "Lenovo ideapad Y700-15ACZ",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
diff --git a/drivers/platform/x86/intel-hid.c b/drivers/platform/x86/intel-hid.c
index bcf438f38781..b40059aba856 100644
--- a/drivers/platform/x86/intel-hid.c
+++ b/drivers/platform/x86/intel-hid.c
@@ -77,14 +77,12 @@ struct intel_hid_priv {
struct input_dev *array;
};
-static int intel_hid_set_enable(struct device *device, int enable)
+static int intel_hid_set_enable(struct device *device, bool enable)
{
- union acpi_object arg0 = { ACPI_TYPE_INTEGER };
- struct acpi_object_list args = { 1, &arg0 };
acpi_status status;
- arg0.integer.value = enable;
- status = acpi_evaluate_object(ACPI_HANDLE(device), "HDSM", &args, NULL);
+ status = acpi_execute_simple_method(ACPI_HANDLE(device), "HDSM",
+ enable);
if (ACPI_FAILURE(status)) {
dev_warn(device, "failed to %sable hotkeys\n",
enable ? "en" : "dis");
@@ -120,7 +118,7 @@ static void intel_button_array_enable(struct device *device, bool enable)
static int intel_hid_pl_suspend_handler(struct device *device)
{
- intel_hid_set_enable(device, 0);
+ intel_hid_set_enable(device, false);
intel_button_array_enable(device, false);
return 0;
@@ -128,7 +126,7 @@ static int intel_hid_pl_suspend_handler(struct device *device)
static int intel_hid_pl_resume_handler(struct device *device)
{
- intel_hid_set_enable(device, 1);
+ intel_hid_set_enable(device, true);
intel_button_array_enable(device, true);
return 0;
@@ -146,28 +144,18 @@ static int intel_hid_input_setup(struct platform_device *device)
struct intel_hid_priv *priv = dev_get_drvdata(&device->dev);
int ret;
- priv->input_dev = input_allocate_device();
+ priv->input_dev = devm_input_allocate_device(&device->dev);
if (!priv->input_dev)
return -ENOMEM;
ret = sparse_keymap_setup(priv->input_dev, intel_hid_keymap, NULL);
if (ret)
- goto err_free_device;
+ return ret;
- priv->input_dev->dev.parent = &device->dev;
priv->input_dev->name = "Intel HID events";
priv->input_dev->id.bustype = BUS_HOST;
- set_bit(KEY_RFKILL, priv->input_dev->keybit);
-
- ret = input_register_device(priv->input_dev);
- if (ret)
- goto err_free_device;
- return 0;
-
-err_free_device:
- input_free_device(priv->input_dev);
- return ret;
+ return input_register_device(priv->input_dev);
}
static int intel_button_array_input_setup(struct platform_device *device)
@@ -184,20 +172,12 @@ static int intel_button_array_input_setup(struct platform_device *device)
if (ret)
return ret;
- priv->array->dev.parent = &device->dev;
priv->array->name = "Intel HID 5 button array";
priv->array->id.bustype = BUS_HOST;
return input_register_device(priv->array);
}
-static void intel_hid_input_destroy(struct platform_device *device)
-{
- struct intel_hid_priv *priv = dev_get_drvdata(&device->dev);
-
- input_unregister_device(priv->input_dev);
-}
-
static void notify_handler(acpi_handle handle, u32 event, void *context)
{
struct platform_device *device = context;
@@ -272,12 +252,10 @@ static int intel_hid_probe(struct platform_device *device)
ACPI_DEVICE_NOTIFY,
notify_handler,
device);
- if (ACPI_FAILURE(status)) {
- err = -EBUSY;
- goto err_remove_input;
- }
+ if (ACPI_FAILURE(status))
+ return -EBUSY;
- err = intel_hid_set_enable(&device->dev, 1);
+ err = intel_hid_set_enable(&device->dev, true);
if (err)
goto err_remove_notify;
@@ -296,9 +274,6 @@ static int intel_hid_probe(struct platform_device *device)
err_remove_notify:
acpi_remove_notify_handler(handle, ACPI_DEVICE_NOTIFY, notify_handler);
-err_remove_input:
- intel_hid_input_destroy(device);
-
return err;
}
@@ -307,8 +282,7 @@ static int intel_hid_remove(struct platform_device *device)
acpi_handle handle = ACPI_HANDLE(&device->dev);
acpi_remove_notify_handler(handle, ACPI_DEVICE_NOTIFY, notify_handler);
- intel_hid_input_destroy(device);
- intel_hid_set_enable(&device->dev, 0);
+ intel_hid_set_enable(&device->dev, false);
intel_button_array_enable(&device->dev, false);
/*
diff --git a/drivers/platform/x86/intel_scu_ipc.c b/drivers/platform/x86/intel_scu_ipc.c
index e81daff65f62..f7cf981502cd 100644
--- a/drivers/platform/x86/intel_scu_ipc.c
+++ b/drivers/platform/x86/intel_scu_ipc.c
@@ -491,6 +491,69 @@ int intel_scu_ipc_command(int cmd, int sub, u32 *in, int inlen,
}
EXPORT_SYMBOL(intel_scu_ipc_command);
+#define IPC_SPTR 0x08
+#define IPC_DPTR 0x0C
+
+/**
+ * intel_scu_ipc_raw_command() - IPC command with data and pointers
+ * @cmd: IPC command code.
+ * @sub: IPC command sub type.
+ * @in: input data of this IPC command.
+ * @inlen: input data length in dwords.
+ * @out: output data of this IPC command.
+ * @outlen: output data length in dwords.
+ * @sptr: data writing to SPTR register.
+ * @dptr: data writing to DPTR register.
+ *
+ * Send an IPC command to SCU with input/output data and source/dest pointers.
+ *
+ * Return: an IPC error code or 0 on success.
+ */
+int intel_scu_ipc_raw_command(int cmd, int sub, u8 *in, int inlen,
+ u32 *out, int outlen, u32 dptr, u32 sptr)
+{
+ struct intel_scu_ipc_dev *scu = &ipcdev;
+ int inbuflen = DIV_ROUND_UP(inlen, 4);
+ u32 inbuf[4];
+ int i, err;
+
+ /* Up to 16 bytes */
+ if (inbuflen > 4)
+ return -EINVAL;
+
+ mutex_lock(&ipclock);
+ if (scu->dev == NULL) {
+ mutex_unlock(&ipclock);
+ return -ENODEV;
+ }
+
+ writel(dptr, scu->ipc_base + IPC_DPTR);
+ writel(sptr, scu->ipc_base + IPC_SPTR);
+
+ /*
+ * SRAM controller doesn't support 8-bit writes, it only
+ * supports 32-bit writes, so we have to copy input data into
+ * the temporary buffer, and SCU FW will use the inlen to
+ * determine the actual input data length in the temporary
+ * buffer.
+ */
+ memcpy(inbuf, in, inlen);
+
+ for (i = 0; i < inbuflen; i++)
+ ipc_data_writel(scu, inbuf[i], 4 * i);
+
+ ipc_command(scu, (inlen << 16) | (sub << 12) | cmd);
+ err = intel_scu_ipc_check_status(scu);
+ if (!err) {
+ for (i = 0; i < outlen; i++)
+ *out++ = ipc_data_readl(scu, 4 * i);
+ }
+
+ mutex_unlock(&ipclock);
+ return err;
+}
+EXPORT_SYMBOL_GPL(intel_scu_ipc_raw_command);
+
/* I2C commands */
#define IPC_I2C_WRITE 1 /* I2C Write command */
#define IPC_I2C_READ 2 /* I2C Read command */
@@ -566,21 +629,17 @@ static irqreturn_t ioc(int irq, void *dev_id)
*/
static int ipc_probe(struct pci_dev *pdev, const struct pci_device_id *id)
{
- int platform; /* Platform type */
int err;
struct intel_scu_ipc_dev *scu = &ipcdev;
struct intel_scu_ipc_pdata_t *pdata;
- platform = intel_mid_identify_cpu();
- if (platform == 0)
- return -ENODEV;
-
if (scu->dev) /* We support only one SCU */
return -EBUSY;
pdata = (struct intel_scu_ipc_pdata_t *)id->driver_data;
+ if (!pdata)
+ return -ENODEV;
- scu->dev = &pdev->dev;
scu->irq_mode = pdata->irq_mode;
err = pcim_enable_device(pdev);
@@ -593,39 +652,34 @@ static int ipc_probe(struct pci_dev *pdev, const struct pci_device_id *id)
init_completion(&scu->cmd_complete);
- err = devm_request_irq(&pdev->dev, pdev->irq, ioc, 0, "intel_scu_ipc",
- scu);
- if (err)
- return err;
-
scu->ipc_base = pcim_iomap_table(pdev)[0];
scu->i2c_base = ioremap_nocache(pdata->i2c_base, pdata->i2c_len);
if (!scu->i2c_base)
return -ENOMEM;
+ err = devm_request_irq(&pdev->dev, pdev->irq, ioc, 0, "intel_scu_ipc",
+ scu);
+ if (err)
+ return err;
+
+ /* Assign device at last */
+ scu->dev = &pdev->dev;
+
intel_scu_devices_create();
pci_set_drvdata(pdev, scu);
return 0;
}
+#define SCU_DEVICE(id, pdata) {PCI_VDEVICE(INTEL, id), (kernel_ulong_t)&pdata}
+
static const struct pci_device_id pci_ids[] = {
- {
- PCI_VDEVICE(INTEL, PCI_DEVICE_ID_LINCROFT),
- (kernel_ulong_t)&intel_scu_ipc_lincroft_pdata,
- }, {
- PCI_VDEVICE(INTEL, PCI_DEVICE_ID_PENWELL),
- (kernel_ulong_t)&intel_scu_ipc_penwell_pdata,
- }, {
- PCI_VDEVICE(INTEL, PCI_DEVICE_ID_CLOVERVIEW),
- (kernel_ulong_t)&intel_scu_ipc_penwell_pdata,
- }, {
- PCI_VDEVICE(INTEL, PCI_DEVICE_ID_TANGIER),
- (kernel_ulong_t)&intel_scu_ipc_tangier_pdata,
- }, {
- 0,
- }
+ SCU_DEVICE(PCI_DEVICE_ID_LINCROFT, intel_scu_ipc_lincroft_pdata),
+ SCU_DEVICE(PCI_DEVICE_ID_PENWELL, intel_scu_ipc_penwell_pdata),
+ SCU_DEVICE(PCI_DEVICE_ID_CLOVERVIEW, intel_scu_ipc_penwell_pdata),
+ SCU_DEVICE(PCI_DEVICE_ID_TANGIER, intel_scu_ipc_tangier_pdata),
+ {}
};
static struct pci_driver ipc_driver = {
diff --git a/drivers/platform/x86/msi-laptop.c b/drivers/platform/x86/msi-laptop.c
index 42317704629d..9e90827c176a 100644
--- a/drivers/platform/x86/msi-laptop.c
+++ b/drivers/platform/x86/msi-laptop.c
@@ -976,23 +976,15 @@ static int __init msi_laptop_input_setup(void)
err = input_register_device(msi_laptop_input_dev);
if (err)
- goto err_free_keymap;
+ goto err_free_dev;
return 0;
-err_free_keymap:
- sparse_keymap_free(msi_laptop_input_dev);
err_free_dev:
input_free_device(msi_laptop_input_dev);
return err;
}
-static void msi_laptop_input_destroy(void)
-{
- sparse_keymap_free(msi_laptop_input_dev);
- input_unregister_device(msi_laptop_input_dev);
-}
-
static int __init load_scm_model_init(struct platform_device *sdev)
{
u8 data;
@@ -1037,7 +1029,7 @@ static int __init load_scm_model_init(struct platform_device *sdev)
return 0;
fail_filter:
- msi_laptop_input_destroy();
+ input_unregister_device(msi_laptop_input_dev);
fail_input:
rfkill_cleanup();
@@ -1158,7 +1150,7 @@ static void __exit msi_cleanup(void)
{
if (quirks->load_scm_model) {
i8042_remove_filter(msi_laptop_i8042_filter);
- msi_laptop_input_destroy();
+ input_unregister_device(msi_laptop_input_dev);
cancel_delayed_work_sync(&msi_rfkill_dwork);
cancel_work_sync(&msi_rfkill_work);
rfkill_cleanup();
diff --git a/drivers/platform/x86/msi-wmi.c b/drivers/platform/x86/msi-wmi.c
index 9a32f8627ecc..f6209b739ec0 100644
--- a/drivers/platform/x86/msi-wmi.c
+++ b/drivers/platform/x86/msi-wmi.c
@@ -281,14 +281,12 @@ static int __init msi_wmi_input_setup(void)
err = input_register_device(msi_wmi_input_dev);
if (err)
- goto err_free_keymap;
+ goto err_free_dev;
last_pressed = 0;
return 0;
-err_free_keymap:
- sparse_keymap_free(msi_wmi_input_dev);
err_free_dev:
input_free_device(msi_wmi_input_dev);
return err;
@@ -342,10 +340,8 @@ err_uninstall_handler:
if (event_wmi)
wmi_remove_notify_handler(event_wmi->guid);
err_free_input:
- if (event_wmi) {
- sparse_keymap_free(msi_wmi_input_dev);
+ if (event_wmi)
input_unregister_device(msi_wmi_input_dev);
- }
return err;
}
@@ -353,7 +349,6 @@ static void __exit msi_wmi_exit(void)
{
if (event_wmi) {
wmi_remove_notify_handler(event_wmi->guid);
- sparse_keymap_free(msi_wmi_input_dev);
input_unregister_device(msi_wmi_input_dev);
}
backlight_device_unregister(backlight);
diff --git a/drivers/platform/x86/panasonic-laptop.c b/drivers/platform/x86/panasonic-laptop.c
index 59b8eb626dcc..975f4e100dbd 100644
--- a/drivers/platform/x86/panasonic-laptop.c
+++ b/drivers/platform/x86/panasonic-laptop.c
@@ -520,29 +520,17 @@ static int acpi_pcc_init_input(struct pcc_acpi *pcc)
if (error) {
ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
"Unable to register input device\n"));
- goto err_free_keymap;
+ goto err_free_dev;
}
pcc->input_dev = input_dev;
return 0;
- err_free_keymap:
- sparse_keymap_free(input_dev);
err_free_dev:
input_free_device(input_dev);
return error;
}
-static void acpi_pcc_destroy_input(struct pcc_acpi *pcc)
-{
- sparse_keymap_free(pcc->input_dev);
- input_unregister_device(pcc->input_dev);
- /*
- * No need to input_free_device() since core input API refcounts
- * and free()s the device.
- */
-}
-
/* kernel module interface */
#ifdef CONFIG_PM_SLEEP
@@ -640,7 +628,7 @@ static int acpi_pcc_hotkey_add(struct acpi_device *device)
out_backlight:
backlight_device_unregister(pcc->backlight);
out_input:
- acpi_pcc_destroy_input(pcc);
+ input_unregister_device(pcc->input_dev);
out_sinf:
kfree(pcc->sinf);
out_hotkey:
@@ -660,7 +648,7 @@ static int acpi_pcc_hotkey_remove(struct acpi_device *device)
backlight_device_unregister(pcc->backlight);
- acpi_pcc_destroy_input(pcc);
+ input_unregister_device(pcc->input_dev);
kfree(pcc->sinf);
kfree(pcc);
diff --git a/drivers/platform/x86/silead_dmi.c b/drivers/platform/x86/silead_dmi.c
index 02e11fdbf375..a3a57d93cf06 100644
--- a/drivers/platform/x86/silead_dmi.c
+++ b/drivers/platform/x86/silead_dmi.c
@@ -22,10 +22,10 @@
struct silead_ts_dmi_data {
const char *acpi_name;
- struct property_entry *properties;
+ const struct property_entry *properties;
};
-static struct property_entry cube_iwork8_air_props[] = {
+static const struct property_entry cube_iwork8_air_props[] = {
PROPERTY_ENTRY_U32("touchscreen-size-x", 1660),
PROPERTY_ENTRY_U32("touchscreen-size-y", 900),
PROPERTY_ENTRY_BOOL("touchscreen-swapped-x-y"),
@@ -39,7 +39,7 @@ static const struct silead_ts_dmi_data cube_iwork8_air_data = {
.properties = cube_iwork8_air_props,
};
-static struct property_entry jumper_ezpad_mini3_props[] = {
+static const struct property_entry jumper_ezpad_mini3_props[] = {
PROPERTY_ENTRY_U32("touchscreen-size-x", 1700),
PROPERTY_ENTRY_U32("touchscreen-size-y", 1150),
PROPERTY_ENTRY_BOOL("touchscreen-swapped-x-y"),
@@ -53,6 +53,33 @@ static const struct silead_ts_dmi_data jumper_ezpad_mini3_data = {
.properties = jumper_ezpad_mini3_props,
};
+static const struct property_entry dexp_ursus_7w_props[] = {
+ PROPERTY_ENTRY_U32("touchscreen-size-x", 890),
+ PROPERTY_ENTRY_U32("touchscreen-size-y", 630),
+ PROPERTY_ENTRY_STRING("firmware-name", "gsl1686-dexp-ursus-7w.fw"),
+ PROPERTY_ENTRY_U32("silead,max-fingers", 10),
+ { }
+};
+
+static const struct silead_ts_dmi_data dexp_ursus_7w_data = {
+ .acpi_name = "MSSL1680:00",
+ .properties = dexp_ursus_7w_props,
+};
+
+static const struct property_entry surftab_wintron70_st70416_6_props[] = {
+ PROPERTY_ENTRY_U32("touchscreen-size-x", 884),
+ PROPERTY_ENTRY_U32("touchscreen-size-y", 632),
+ PROPERTY_ENTRY_STRING("firmware-name",
+ "gsl1686-surftab-wintron70-st70416-6.fw"),
+ PROPERTY_ENTRY_U32("silead,max-fingers", 10),
+ { }
+};
+
+static const struct silead_ts_dmi_data surftab_wintron70_st70416_6_data = {
+ .acpi_name = "MSSL1680:00",
+ .properties = surftab_wintron70_st70416_6_props,
+};
+
static const struct dmi_system_id silead_ts_dmi_table[] = {
{
/* CUBE iwork8 Air */
@@ -72,24 +99,37 @@ static const struct dmi_system_id silead_ts_dmi_table[] = {
DMI_MATCH(DMI_BIOS_VERSION, "jumperx.T87.KFBNEEA"),
},
},
+ {
+ /* DEXP Ursus 7W */
+ .driver_data = (void *)&dexp_ursus_7w_data,
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Insyde"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "7W"),
+ },
+ },
+ {
+ /* Trekstor Surftab Wintron 7.0 ST70416-6 */
+ .driver_data = (void *)&surftab_wintron70_st70416_6_data,
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Insyde"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "ST70416-6"),
+ /* Exact match, different versions need different fw */
+ DMI_MATCH(DMI_BIOS_VERSION, "TREK.G.WI71C.JGBMRBA04"),
+ },
+ },
{ },
};
-static void silead_ts_dmi_add_props(struct device *dev)
+static const struct silead_ts_dmi_data *silead_ts_data;
+
+static void silead_ts_dmi_add_props(struct i2c_client *client)
{
- struct i2c_client *client = to_i2c_client(dev);
- const struct dmi_system_id *dmi_id;
- const struct silead_ts_dmi_data *ts_data;
+ struct device *dev = &client->dev;
int error;
- dmi_id = dmi_first_match(silead_ts_dmi_table);
- if (!dmi_id)
- return;
-
- ts_data = dmi_id->driver_data;
if (has_acpi_companion(dev) &&
- !strncmp(ts_data->acpi_name, client->name, I2C_NAME_SIZE)) {
- error = device_add_properties(dev, ts_data->properties);
+ !strncmp(silead_ts_data->acpi_name, client->name, I2C_NAME_SIZE)) {
+ error = device_add_properties(dev, silead_ts_data->properties);
if (error)
dev_err(dev, "failed to add properties: %d\n", error);
}
@@ -99,10 +139,13 @@ static int silead_ts_dmi_notifier_call(struct notifier_block *nb,
unsigned long action, void *data)
{
struct device *dev = data;
+ struct i2c_client *client;
switch (action) {
case BUS_NOTIFY_ADD_DEVICE:
- silead_ts_dmi_add_props(dev);
+ client = i2c_verify_client(dev);
+ if (client)
+ silead_ts_dmi_add_props(client);
break;
default:
@@ -118,8 +161,15 @@ static struct notifier_block silead_ts_dmi_notifier = {
static int __init silead_ts_dmi_init(void)
{
+ const struct dmi_system_id *dmi_id;
int error;
+ dmi_id = dmi_first_match(silead_ts_dmi_table);
+ if (!dmi_id)
+ return 0; /* Not an error */
+
+ silead_ts_data = dmi_id->driver_data;
+
error = bus_register_notifier(&i2c_bus_type, &silead_ts_dmi_notifier);
if (error)
pr_err("%s: failed to register i2c bus notifier: %d\n",
diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c
index 1d18b32628ec..7b6cb0c69b02 100644
--- a/drivers/platform/x86/thinkpad_acpi.c
+++ b/drivers/platform/x86/thinkpad_acpi.c
@@ -1922,7 +1922,9 @@ enum { /* hot key scan codes (derived from ACPI DSDT) */
TP_ACPI_HOTKEYSCAN_UNK7,
TP_ACPI_HOTKEYSCAN_UNK8,
- TP_ACPI_HOTKEYSCAN_MUTE2,
+ /* Adaptive keyboard keycodes */
+ TP_ACPI_HOTKEYSCAN_ADAPTIVE_START,
+ TP_ACPI_HOTKEYSCAN_MUTE2 = TP_ACPI_HOTKEYSCAN_ADAPTIVE_START,
TP_ACPI_HOTKEYSCAN_BRIGHTNESS_ZERO,
TP_ACPI_HOTKEYSCAN_CLIPPING_TOOL,
TP_ACPI_HOTKEYSCAN_CLOUD,
@@ -1943,6 +1945,15 @@ enum { /* hot key scan codes (derived from ACPI DSDT) */
TP_ACPI_HOTKEYSCAN_CAMERA_MODE,
TP_ACPI_HOTKEYSCAN_ROTATE_DISPLAY,
+ /* Lenovo extended keymap, starting at 0x1300 */
+ TP_ACPI_HOTKEYSCAN_EXTENDED_START,
+ /* first new observed key (star, favorites) is 0x1311 */
+ TP_ACPI_HOTKEYSCAN_STAR = 69,
+ TP_ACPI_HOTKEYSCAN_CLIPPING_TOOL2,
+ TP_ACPI_HOTKEYSCAN_UNK25,
+ TP_ACPI_HOTKEYSCAN_BLUETOOTH,
+ TP_ACPI_HOTKEYSCAN_KEYBOARD,
+
/* Hotkey keymap size */
TPACPI_HOTKEY_MAP_LEN
};
@@ -3250,6 +3261,15 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN,
KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN,
KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN,
+
+ /* No assignment, used for newer Lenovo models */
+ KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN,
+ KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN,
+ KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN,
+ KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN,
+ KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN,
+ KEY_UNKNOWN, KEY_UNKNOWN
+
},
/* Generic keymap for Lenovo ThinkPads */
@@ -3335,6 +3355,29 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
KEY_RESERVED, /* Microphone cancellation */
KEY_RESERVED, /* Camera mode */
KEY_RESERVED, /* Rotate display, 0x116 */
+
+ /*
+ * These are found in 2017 models (e.g. T470s, X270).
+ * The lowest known value is 0x311, which according to
+ * the manual should launch a user defined favorite
+ * application.
+ *
+ * The offset for these is TP_ACPI_HOTKEYSCAN_EXTENDED_START,
+ * corresponding to 0x34.
+ */
+
+ /* (assignments unknown, please report if found) */
+ KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN,
+ KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN,
+ KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN,
+ KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN,
+ KEY_UNKNOWN,
+
+ KEY_FAVORITES, /* Favorite app, 0x311 */
+ KEY_RESERVED, /* Clipping tool */
+ KEY_RESERVED,
+ KEY_BLUETOOTH, /* Bluetooth */
+ KEY_KEYBOARD /* Keyboard, 0x315 */
},
};
@@ -3656,7 +3699,6 @@ static const int adaptive_keyboard_modes[] = {
#define DFR_CHANGE_ROW 0x101
#define DFR_SHOW_QUICKVIEW_ROW 0x102
#define FIRST_ADAPTIVE_KEY 0x103
-#define ADAPTIVE_KEY_OFFSET 0x020
/* press Fn key a while second, it will switch to Function Mode. Then
* release Fn key, previous mode be restored.
@@ -3746,13 +3788,15 @@ static bool adaptive_keyboard_hotkey_notify_hotkey(unsigned int scancode)
default:
if (scancode < FIRST_ADAPTIVE_KEY ||
- scancode >= FIRST_ADAPTIVE_KEY + TPACPI_HOTKEY_MAP_LEN -
- ADAPTIVE_KEY_OFFSET) {
+ scancode >= FIRST_ADAPTIVE_KEY +
+ TP_ACPI_HOTKEYSCAN_EXTENDED_START -
+ TP_ACPI_HOTKEYSCAN_ADAPTIVE_START) {
pr_info("Unhandled adaptive keyboard key: 0x%x\n",
scancode);
return false;
}
- keycode = hotkey_keycode_map[scancode - FIRST_ADAPTIVE_KEY + ADAPTIVE_KEY_OFFSET];
+ keycode = hotkey_keycode_map[scancode - FIRST_ADAPTIVE_KEY +
+ TP_ACPI_HOTKEYSCAN_ADAPTIVE_START];
if (keycode != KEY_RESERVED) {
mutex_lock(&tpacpi_inputdev_send_mutex);
@@ -3777,19 +3821,44 @@ static bool hotkey_notify_hotkey(const u32 hkey,
*send_acpi_ev = true;
*ignore_acpi_ev = false;
- /* HKEY event 0x1001 is scancode 0x00 */
- if (scancode > 0 && scancode <= TPACPI_HOTKEY_MAP_LEN) {
- scancode--;
- if (!(hotkey_source_mask & (1 << scancode))) {
- tpacpi_input_send_key_masked(scancode);
- *send_acpi_ev = false;
- } else {
- *ignore_acpi_ev = true;
+ /*
+ * Original events are in the 0x10XX range, the adaptive keyboard
+ * found in 2014 X1 Carbon emits events are of 0x11XX. In 2017
+ * models, additional keys are emitted through 0x13XX.
+ */
+ switch ((hkey >> 8) & 0xf) {
+ case 0:
+ if (scancode > 0 &&
+ scancode <= TP_ACPI_HOTKEYSCAN_ADAPTIVE_START) {
+ /* HKEY event 0x1001 is scancode 0x00 */
+ scancode--;
+ if (!(hotkey_source_mask & (1 << scancode))) {
+ tpacpi_input_send_key_masked(scancode);
+ *send_acpi_ev = false;
+ } else {
+ *ignore_acpi_ev = true;
+ }
+ return true;
}
- return true;
- } else {
+ break;
+
+ case 1:
return adaptive_keyboard_hotkey_notify_hotkey(scancode);
+
+ case 3:
+ /* Extended keycodes start at 0x300 and our offset into the map
+ * TP_ACPI_HOTKEYSCAN_EXTENDED_START. The calculated scancode
+ * will be positive, but might not be in the correct range.
+ */
+ scancode -= (0x300 - TP_ACPI_HOTKEYSCAN_EXTENDED_START);
+ if (scancode >= TP_ACPI_HOTKEYSCAN_EXTENDED_START &&
+ scancode < TPACPI_HOTKEY_MAP_LEN) {
+ tpacpi_input_send_key(scancode);
+ return true;
+ }
+ break;
}
+
return false;
}
diff --git a/drivers/platform/x86/topstar-laptop.c b/drivers/platform/x86/topstar-laptop.c
index e597de05e6c2..70205d222da9 100644
--- a/drivers/platform/x86/topstar-laptop.c
+++ b/drivers/platform/x86/topstar-laptop.c
@@ -113,14 +113,12 @@ static int acpi_topstar_init_hkey(struct topstar_hkey *hkey)
error = input_register_device(input);
if (error) {
pr_err("Unable to register input device\n");
- goto err_free_keymap;
+ goto err_free_dev;
}
hkey->inputdev = input;
return 0;
- err_free_keymap:
- sparse_keymap_free(input);
err_free_dev:
input_free_device(input);
return error;
@@ -157,7 +155,6 @@ static int acpi_topstar_remove(struct acpi_device *device)
acpi_topstar_fncx_switch(device, false);
- sparse_keymap_free(tps_hkey->inputdev);
input_unregister_device(tps_hkey->inputdev);
kfree(tps_hkey);
diff --git a/drivers/platform/x86/toshiba-wmi.c b/drivers/platform/x86/toshiba-wmi.c
index 2df07ee8f3c3..440528676170 100644
--- a/drivers/platform/x86/toshiba-wmi.c
+++ b/drivers/platform/x86/toshiba-wmi.c
@@ -96,7 +96,7 @@ static int __init toshiba_wmi_input_setup(void)
toshiba_wmi_notify, NULL);
if (ACPI_FAILURE(status)) {
err = -EIO;
- goto err_free_keymap;
+ goto err_free_dev;
}
err = input_register_device(toshiba_wmi_input_dev);
@@ -107,8 +107,6 @@ static int __init toshiba_wmi_input_setup(void)
err_remove_notifier:
wmi_remove_notify_handler(WMI_EVENT_GUID);
- err_free_keymap:
- sparse_keymap_free(toshiba_wmi_input_dev);
err_free_dev:
input_free_device(toshiba_wmi_input_dev);
return err;
@@ -117,7 +115,6 @@ static int __init toshiba_wmi_input_setup(void)
static void toshiba_wmi_input_destroy(void)
{
wmi_remove_notify_handler(WMI_EVENT_GUID);
- sparse_keymap_free(toshiba_wmi_input_dev);
input_unregister_device(toshiba_wmi_input_dev);
}
diff --git a/drivers/platform/x86/toshiba_acpi.c b/drivers/platform/x86/toshiba_acpi.c
index 074bf2fa1c55..d0daf75cbed1 100644
--- a/drivers/platform/x86/toshiba_acpi.c
+++ b/drivers/platform/x86/toshiba_acpi.c
@@ -2849,7 +2849,7 @@ static int toshiba_acpi_setup_keyboard(struct toshiba_acpi_dev *dev)
error = i8042_install_filter(toshiba_acpi_i8042_filter);
if (error) {
pr_err("Error installing key filter\n");
- goto err_free_keymap;
+ goto err_free_dev;
}
dev->ntfy_supported = 1;
@@ -2880,8 +2880,6 @@ static int toshiba_acpi_setup_keyboard(struct toshiba_acpi_dev *dev)
err_remove_filter:
if (dev->ntfy_supported)
i8042_remove_filter(toshiba_acpi_i8042_filter);
- err_free_keymap:
- sparse_keymap_free(dev->hotkey_dev);
err_free_dev:
input_free_device(dev->hotkey_dev);
dev->hotkey_dev = NULL;
@@ -3018,10 +3016,8 @@ static int toshiba_acpi_remove(struct acpi_device *acpi_dev)
cancel_work_sync(&dev->hotkey_work);
}
- if (dev->hotkey_dev) {
+ if (dev->hotkey_dev)
input_unregister_device(dev->hotkey_dev);
- sparse_keymap_free(dev->hotkey_dev);
- }
backlight_device_unregister(dev->backlight_dev);
diff --git a/include/linux/dell-led.h b/include/linux/dell-led.h
index 7009b8bec77b..3f033c48071e 100644
--- a/include/linux/dell-led.h
+++ b/include/linux/dell-led.h
@@ -1,10 +1,6 @@
#ifndef __DELL_LED_H__
#define __DELL_LED_H__
-enum {
- DELL_LED_MICMUTE,
-};
-
-int dell_app_wmi_led_set(int whichled, int on);
+int dell_micmute_led_set(int on);
#endif
diff --git a/sound/pci/hda/dell_wmi_helper.c b/sound/pci/hda/dell_wmi_helper.c
index 19d41da79f93..7efa7bd7acb2 100644
--- a/sound/pci/hda/dell_wmi_helper.c
+++ b/sound/pci/hda/dell_wmi_helper.c
@@ -2,11 +2,11 @@
* to be included from codec driver
*/
-#if IS_ENABLED(CONFIG_LEDS_DELL_NETBOOKS)
+#if IS_ENABLED(CONFIG_DELL_LAPTOP)
#include <linux/dell-led.h>
static int dell_led_value;
-static int (*dell_led_set_func)(int, int);
+static int (*dell_micmute_led_set_func)(int);
static void (*dell_old_cap_hook)(struct hda_codec *,
struct snd_kcontrol *,
struct snd_ctl_elem_value *);
@@ -18,7 +18,7 @@ static void update_dell_wmi_micmute_led(struct hda_codec *codec,
if (dell_old_cap_hook)
dell_old_cap_hook(codec, kcontrol, ucontrol);
- if (!ucontrol || !dell_led_set_func)
+ if (!ucontrol || !dell_micmute_led_set_func)
return;
if (strcmp("Capture Switch", ucontrol->id.name) == 0 && ucontrol->id.index == 0) {
/* TODO: How do I verify if it's a mono or stereo here? */
@@ -26,8 +26,8 @@ static void update_dell_wmi_micmute_led(struct hda_codec *codec,
if (val == dell_led_value)
return;
dell_led_value = val;
- if (dell_led_set_func)
- dell_led_set_func(DELL_LED_MICMUTE, dell_led_value);
+ if (dell_micmute_led_set_func)
+ dell_micmute_led_set_func(dell_led_value);
}
}
@@ -39,15 +39,15 @@ static void alc_fixup_dell_wmi(struct hda_codec *codec,
bool removefunc = false;
if (action == HDA_FIXUP_ACT_PROBE) {
- if (!dell_led_set_func)
- dell_led_set_func = symbol_request(dell_app_wmi_led_set);
- if (!dell_led_set_func) {
- codec_warn(codec, "Failed to find dell wmi symbol dell_app_wmi_led_set\n");
+ if (!dell_micmute_led_set_func)
+ dell_micmute_led_set_func = symbol_request(dell_micmute_led_set);
+ if (!dell_micmute_led_set_func) {
+ codec_warn(codec, "Failed to find dell wmi symbol dell_micmute_led_set\n");
return;
}
removefunc = true;
- if (dell_led_set_func(DELL_LED_MICMUTE, false) >= 0) {
+ if (dell_micmute_led_set_func(false) >= 0) {
dell_led_value = 0;
if (spec->gen.num_adc_nids > 1 && !spec->gen.dyn_adc_switch)
codec_dbg(codec, "Skipping micmute LED control due to several ADCs");
@@ -60,17 +60,17 @@ static void alc_fixup_dell_wmi(struct hda_codec *codec,
}
- if (dell_led_set_func && (action == HDA_FIXUP_ACT_FREE || removefunc)) {
- symbol_put(dell_app_wmi_led_set);
- dell_led_set_func = NULL;
+ if (dell_micmute_led_set_func && (action == HDA_FIXUP_ACT_FREE || removefunc)) {
+ symbol_put(dell_micmute_led_set);
+ dell_micmute_led_set_func = NULL;
dell_old_cap_hook = NULL;
}
}
-#else /* CONFIG_LEDS_DELL_NETBOOKS */
+#else /* CONFIG_DELL_LAPTOP */
static void alc_fixup_dell_wmi(struct hda_codec *codec,
const struct hda_fixup *fix, int action)
{
}
-#endif /* CONFIG_LEDS_DELL_NETBOOKS */
+#endif /* CONFIG_DELL_LAPTOP */