Commit d1e41ff1 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'platform-drivers-x86-v4.4-1' of...

Merge tag 'platform-drivers-x86-v4.4-1' of git://git.infradead.org/users/dvhart/linux-platform-drivers-x86

Pull x86 platform driver update from Darren Hart:
 "Various toshiba hotkey and keyboard related fixes and a new WMI
  driver.  Several intel_scu_ipc cleanups and a locking fix.  A
  spattering of small single fixes across various platforms.

  I was asked to pick up an OLPC cleanup as the driver appeared
  unmaintained and it seemed similar to what is maintained in
  platform/drivers/x86.  I have included the patch and an update to the
  MAINTAINERS file.

  toshiba_acpi:
   - Initialize hotkey_event_type variable
   - Remove unneeded u32 variables from *setup_keyboard
   - Add 0x prefix to available_kbd_modes_show function
   - Change default Hotkey enabling value
   - Unify hotkey enabling functions

  toshiba-wmi:
   - Toshiba WMI Hotkey Driver

  intel_scu_ipc:
   - Protect dev member assignment on ->remove()
   - Switch to use module_pci_driver() macro
   - Convert to use struct device *
   - Propagate pointer to struct intel_scu_ipc_dev
   - Fix error path by turning to devm_* / pcim_*

  acer-wmi:
   - remove threeg and interface sysfs interfaces

  OLPC:
   - Use %*ph specifier instead of passing direct values

  MAINTAINERS:
   - Add drivers/platform/olpc to drivers/platform/x86

  sony-laptop:
   - Fix handling sony_nc_hotkeys_decode result

  intel_mid_powerbtn:
   - Remove misuse of IRQF_NO_SUSPEND flag

  compal-laptop:
   - Add charge control limit

  asus-wmi:
   - restore kbd led level after resume"

* tag 'platform-drivers-x86-v4.4-1' of git://git.infradead.org/users/dvhart/linux-platform-drivers-x86:
  toshiba_acpi: Initialize hotkey_event_type variable
  intel_scu_ipc: Protect dev member assignment on ->remove()
  intel_scu_ipc: Switch to use module_pci_driver() macro
  intel_scu_ipc: Convert to use struct device *
  intel_scu_ipc: Propagate pointer to struct intel_scu_ipc_dev
  intel_scu_ipc: Fix error path by turning to devm_* / pcim_*
  acer-wmi: remove threeg and interface sysfs interfaces
  OLPC: Use %*ph specifier instead of passing direct values
  MAINTAINERS: Add drivers/platform/olpc to drivers/platform/x86
  platform/x86: Toshiba WMI Hotkey Driver
  sony-laptop: Fix handling sony_nc_hotkeys_decode result
  intel_mid_powerbtn: Remove misuse of IRQF_NO_SUSPEND flag
  compal-laptop: Add charge control limit
  asus-wmi: restore kbd led level after resume
  toshiba_acpi: Remove unneeded u32 variables from *setup_keyboard
  toshiba_acpi: Add 0x prefix to available_kbd_modes_show function
  toshiba_acpi: Change default Hotkey enabling value
  toshiba_acpi: Unify hotkey enabling functions
parents 2f4bf528 d2f20619
...@@ -10699,6 +10699,12 @@ L: platform-driver-x86@vger.kernel.org ...@@ -10699,6 +10699,12 @@ L: platform-driver-x86@vger.kernel.org
S: Maintained S: Maintained
F: drivers/platform/x86/toshiba_haps.c F: drivers/platform/x86/toshiba_haps.c
TOSHIBA WMI HOTKEYS DRIVER
M: Azael Avalos <coproscefalo@gmail.com>
L: platform-driver-x86@vger.kernel.org
S: Maintained
F: drivers/platform/x86/toshiba-wmi.c
TOSHIBA SMM DRIVER TOSHIBA SMM DRIVER
M: Jonathan Buzzard <jonathan@buzzard.org.uk> M: Jonathan Buzzard <jonathan@buzzard.org.uk>
W: http://www.buzzard.org.uk/toshiba/ W: http://www.buzzard.org.uk/toshiba/
...@@ -11621,6 +11627,7 @@ L: platform-driver-x86@vger.kernel.org ...@@ -11621,6 +11627,7 @@ L: platform-driver-x86@vger.kernel.org
T: git git://git.infradead.org/users/dvhart/linux-platform-drivers-x86.git T: git git://git.infradead.org/users/dvhart/linux-platform-drivers-x86.git
S: Maintained S: Maintained
F: drivers/platform/x86/ F: drivers/platform/x86/
F: drivers/platform/olpc/
X86 MCE INFRASTRUCTURE X86 MCE INFRASTRUCTURE
M: Tony Luck <tony.luck@intel.com> M: Tony Luck <tony.luck@intel.com>
......
...@@ -192,18 +192,15 @@ static ssize_t ec_dbgfs_cmd_write(struct file *file, const char __user *buf, ...@@ -192,18 +192,15 @@ static ssize_t ec_dbgfs_cmd_write(struct file *file, const char __user *buf,
for (i = 0; i <= ec_cmd_bytes; i++) for (i = 0; i <= ec_cmd_bytes; i++)
ec_cmd[i] = ec_cmd_int[i]; ec_cmd[i] = ec_cmd_int[i];
pr_debug("olpc-ec: debugfs cmd 0x%02x with %d args %02x %02x %02x %02x %02x, want %d returns\n", pr_debug("olpc-ec: debugfs cmd 0x%02x with %d args %5ph, want %d returns\n",
ec_cmd[0], ec_cmd_bytes, ec_cmd[1], ec_cmd[2], ec_cmd[0], ec_cmd_bytes, ec_cmd + 1,
ec_cmd[3], ec_cmd[4], ec_cmd[5], ec_dbgfs_resp_bytes); ec_dbgfs_resp_bytes);
olpc_ec_cmd(ec_cmd[0], (ec_cmd_bytes == 0) ? NULL : &ec_cmd[1], olpc_ec_cmd(ec_cmd[0], (ec_cmd_bytes == 0) ? NULL : &ec_cmd[1],
ec_cmd_bytes, ec_dbgfs_resp, ec_dbgfs_resp_bytes); ec_cmd_bytes, ec_dbgfs_resp, ec_dbgfs_resp_bytes);
pr_debug("olpc-ec: response %02x %02x %02x %02x %02x %02x %02x %02x (%d bytes expected)\n", pr_debug("olpc-ec: response %8ph (%d bytes expected)\n",
ec_dbgfs_resp[0], ec_dbgfs_resp[1], ec_dbgfs_resp[2], ec_dbgfs_resp, ec_dbgfs_resp_bytes);
ec_dbgfs_resp[3], ec_dbgfs_resp[4], ec_dbgfs_resp[5],
ec_dbgfs_resp[6], ec_dbgfs_resp[7],
ec_dbgfs_resp_bytes);
out: out:
mutex_unlock(&ec_dbgfs_lock); mutex_unlock(&ec_dbgfs_lock);
......
...@@ -309,8 +309,8 @@ config COMPAL_LAPTOP ...@@ -309,8 +309,8 @@ config COMPAL_LAPTOP
This is a driver for laptops built by Compal, and some models by This is a driver for laptops built by Compal, and some models by
other brands (e.g. Dell, Toshiba). other brands (e.g. Dell, Toshiba).
It adds support for rfkill, Bluetooth, WLAN and LCD brightness It adds support for rfkill, Bluetooth, WLAN, LCD brightness, hwmon
control. and battery charging level control.
For a (possibly incomplete) list of supported laptops, please refer For a (possibly incomplete) list of supported laptops, please refer
to: Documentation/platform/x86-laptop-drivers.txt to: Documentation/platform/x86-laptop-drivers.txt
...@@ -700,6 +700,24 @@ config TOSHIBA_HAPS ...@@ -700,6 +700,24 @@ config TOSHIBA_HAPS
If you have a recent Toshiba laptop with a built-in accelerometer If you have a recent Toshiba laptop with a built-in accelerometer
device, say Y. device, say Y.
config TOSHIBA_WMI
tristate "Toshiba WMI Hotkeys Driver (EXPERIMENTAL)"
default n
depends on ACPI_WMI
depends on INPUT
select INPUT_SPARSEKMAP
---help---
This driver adds hotkey monitoring support to some Toshiba models
that manage the hotkeys via WMI events.
WARNING: This driver is incomplete as it lacks a proper keymap and the
*notify function only prints the ACPI event type value. Be warned that
you will need to provide some information if you have a Toshiba model
with WMI event hotkeys and want to help with the develpment of this
driver.
If you have a WMI-based hotkeys Toshiba laptop, say Y or M here.
config ACPI_CMPC config ACPI_CMPC
tristate "CMPC Laptop Extras" tristate "CMPC Laptop Extras"
depends on X86 && ACPI depends on X86 && ACPI
......
...@@ -40,6 +40,7 @@ obj-$(CONFIG_ACPI_TOSHIBA) += toshiba_acpi.o ...@@ -40,6 +40,7 @@ obj-$(CONFIG_ACPI_TOSHIBA) += toshiba_acpi.o
obj-$(CONFIG_TOSHIBA_BT_RFKILL) += toshiba_bluetooth.o obj-$(CONFIG_TOSHIBA_BT_RFKILL) += toshiba_bluetooth.o
obj-$(CONFIG_TOSHIBA_HAPS) += toshiba_haps.o obj-$(CONFIG_TOSHIBA_HAPS) += toshiba_haps.o
obj-$(CONFIG_TOSHIBA_WMI) += toshiba-wmi.o
obj-$(CONFIG_INTEL_SCU_IPC) += intel_scu_ipc.o obj-$(CONFIG_INTEL_SCU_IPC) += intel_scu_ipc.o
obj-$(CONFIG_INTEL_SCU_IPC_UTIL) += intel_scu_ipcutil.o obj-$(CONFIG_INTEL_SCU_IPC_UTIL) += intel_scu_ipcutil.o
obj-$(CONFIG_INTEL_MFLD_THERMAL) += intel_mid_thermal.o obj-$(CONFIG_INTEL_MFLD_THERMAL) += intel_mid_thermal.o
......
...@@ -1662,58 +1662,6 @@ static void acer_rfkill_exit(void) ...@@ -1662,58 +1662,6 @@ static void acer_rfkill_exit(void)
return; return;
} }
/*
* sysfs interface
*/
static ssize_t show_bool_threeg(struct device *dev,
struct device_attribute *attr, char *buf)
{
u32 result; \
acpi_status status;
pr_info("This threeg sysfs will be removed in 2014 - used by: %s\n",
current->comm);
status = get_u32(&result, ACER_CAP_THREEG);
if (ACPI_SUCCESS(status))
return sprintf(buf, "%u\n", result);
return sprintf(buf, "Read error\n");
}
static ssize_t set_bool_threeg(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
u32 tmp = simple_strtoul(buf, NULL, 10);
acpi_status status = set_u32(tmp, ACER_CAP_THREEG);
pr_info("This threeg sysfs will be removed in 2014 - used by: %s\n",
current->comm);
if (ACPI_FAILURE(status))
return -EINVAL;
return count;
}
static DEVICE_ATTR(threeg, S_IRUGO | S_IWUSR, show_bool_threeg,
set_bool_threeg);
static ssize_t show_interface(struct device *dev, struct device_attribute *attr,
char *buf)
{
pr_info("This interface sysfs will be removed in 2014 - used by: %s\n",
current->comm);
switch (interface->type) {
case ACER_AMW0:
return sprintf(buf, "AMW0\n");
case ACER_AMW0_V2:
return sprintf(buf, "AMW0 v2\n");
case ACER_WMID:
return sprintf(buf, "WMID\n");
case ACER_WMID_v2:
return sprintf(buf, "WMID v2\n");
default:
return sprintf(buf, "Error!\n");
}
}
static DEVICE_ATTR(interface, S_IRUGO, show_interface, NULL);
static void acer_wmi_notify(u32 value, void *context) static void acer_wmi_notify(u32 value, void *context)
{ {
struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL }; struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL };
...@@ -2127,39 +2075,6 @@ static struct platform_driver acer_platform_driver = { ...@@ -2127,39 +2075,6 @@ static struct platform_driver acer_platform_driver = {
static struct platform_device *acer_platform_device; static struct platform_device *acer_platform_device;
static int remove_sysfs(struct platform_device *device)
{
if (has_cap(ACER_CAP_THREEG))
device_remove_file(&device->dev, &dev_attr_threeg);
device_remove_file(&device->dev, &dev_attr_interface);
return 0;
}
static int __init create_sysfs(void)
{
int retval = -ENOMEM;
if (has_cap(ACER_CAP_THREEG)) {
retval = device_create_file(&acer_platform_device->dev,
&dev_attr_threeg);
if (retval)
goto error_sysfs;
}
retval = device_create_file(&acer_platform_device->dev,
&dev_attr_interface);
if (retval)
goto error_sysfs;
return 0;
error_sysfs:
remove_sysfs(acer_platform_device);
return retval;
}
static void remove_debugfs(void) static void remove_debugfs(void)
{ {
debugfs_remove(interface->debug.devices); debugfs_remove(interface->debug.devices);
...@@ -2290,10 +2205,6 @@ static int __init acer_wmi_init(void) ...@@ -2290,10 +2205,6 @@ static int __init acer_wmi_init(void)
if (err) if (err)
goto error_device_add; goto error_device_add;
err = create_sysfs();
if (err)
goto error_create_sys;
if (wmi_has_guid(WMID_GUID2)) { if (wmi_has_guid(WMID_GUID2)) {
interface->debug.wmid_devices = get_wmid_devices(); interface->debug.wmid_devices = get_wmid_devices();
err = create_debugfs(); err = create_debugfs();
...@@ -2307,8 +2218,6 @@ static int __init acer_wmi_init(void) ...@@ -2307,8 +2218,6 @@ static int __init acer_wmi_init(void)
return 0; return 0;
error_create_debugfs: error_create_debugfs:
remove_sysfs(acer_platform_device);
error_create_sys:
platform_device_del(acer_platform_device); platform_device_del(acer_platform_device);
error_device_add: error_device_add:
platform_device_put(acer_platform_device); platform_device_put(acer_platform_device);
...@@ -2331,7 +2240,6 @@ static void __exit acer_wmi_exit(void) ...@@ -2331,7 +2240,6 @@ static void __exit acer_wmi_exit(void)
if (has_cap(ACER_CAP_ACCEL)) if (has_cap(ACER_CAP_ACCEL))
acer_wmi_accel_destroy(); acer_wmi_accel_destroy();
remove_sysfs(acer_platform_device);
remove_debugfs(); remove_debugfs();
platform_device_unregister(acer_platform_device); platform_device_unregister(acer_platform_device);
platform_driver_unregister(&acer_platform_driver); platform_driver_unregister(&acer_platform_driver);
......
...@@ -582,7 +582,7 @@ static void asus_wmi_led_exit(struct asus_wmi *asus) ...@@ -582,7 +582,7 @@ static void asus_wmi_led_exit(struct asus_wmi *asus)
static int asus_wmi_led_init(struct asus_wmi *asus) static int asus_wmi_led_init(struct asus_wmi *asus)
{ {
int rv = 0; int rv = 0, led_val;
asus->led_workqueue = create_singlethread_workqueue("led_workqueue"); asus->led_workqueue = create_singlethread_workqueue("led_workqueue");
if (!asus->led_workqueue) if (!asus->led_workqueue)
...@@ -602,9 +602,11 @@ static int asus_wmi_led_init(struct asus_wmi *asus) ...@@ -602,9 +602,11 @@ static int asus_wmi_led_init(struct asus_wmi *asus)
goto error; goto error;
} }
if (kbd_led_read(asus, NULL, NULL) >= 0) { led_val = kbd_led_read(asus, NULL, NULL);
if (led_val >= 0) {
INIT_WORK(&asus->kbd_led_work, kbd_led_update); INIT_WORK(&asus->kbd_led_work, kbd_led_update);
asus->kbd_led_wk = led_val;
asus->kbd_led.name = "asus::kbd_backlight"; asus->kbd_led.name = "asus::kbd_backlight";
asus->kbd_led.brightness_set = kbd_led_set; asus->kbd_led.brightness_set = kbd_led_set;
asus->kbd_led.brightness_get = kbd_led_get; asus->kbd_led.brightness_get = kbd_led_get;
...@@ -2160,6 +2162,16 @@ static int asus_hotk_thaw(struct device *device) ...@@ -2160,6 +2162,16 @@ static int asus_hotk_thaw(struct device *device)
return 0; return 0;
} }
static int asus_hotk_resume(struct device *device)
{
struct asus_wmi *asus = dev_get_drvdata(device);
if (!IS_ERR_OR_NULL(asus->kbd_led.dev))
queue_work(asus->led_workqueue, &asus->kbd_led_work);
return 0;
}
static int asus_hotk_restore(struct device *device) static int asus_hotk_restore(struct device *device)
{ {
struct asus_wmi *asus = dev_get_drvdata(device); struct asus_wmi *asus = dev_get_drvdata(device);
...@@ -2190,6 +2202,8 @@ static int asus_hotk_restore(struct device *device) ...@@ -2190,6 +2202,8 @@ static int asus_hotk_restore(struct device *device)
bl = !asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_UWB); bl = !asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_UWB);
rfkill_set_sw_state(asus->uwb.rfkill, bl); rfkill_set_sw_state(asus->uwb.rfkill, bl);
} }
if (!IS_ERR_OR_NULL(asus->kbd_led.dev))
queue_work(asus->led_workqueue, &asus->kbd_led_work);
return 0; return 0;
} }
...@@ -2197,6 +2211,7 @@ static int asus_hotk_restore(struct device *device) ...@@ -2197,6 +2211,7 @@ static int asus_hotk_restore(struct device *device)
static const struct dev_pm_ops asus_pm_ops = { static const struct dev_pm_ops asus_pm_ops = {
.thaw = asus_hotk_thaw, .thaw = asus_hotk_thaw,
.restore = asus_hotk_restore, .restore = asus_hotk_restore,
.resume = asus_hotk_resume,
}; };
static int asus_wmi_probe(struct platform_device *pdev) static int asus_wmi_probe(struct platform_device *pdev)
......
...@@ -151,6 +151,8 @@ ...@@ -151,6 +151,8 @@
#define BAT_STATUS2 0xF1 #define BAT_STATUS2 0xF1
#define BAT_STOP_CHARGE1 0xF2 #define BAT_STOP_CHARGE1 0xF2
#define BAT_STOP_CHARGE2 0xF3 #define BAT_STOP_CHARGE2 0xF3
#define BAT_CHARGE_LIMIT 0x03
#define BAT_CHARGE_LIMIT_MAX 100
#define BAT_S0_DISCHARGE (1 << 0) #define BAT_S0_DISCHARGE (1 << 0)
#define BAT_S0_DISCHRG_CRITICAL (1 << 2) #define BAT_S0_DISCHRG_CRITICAL (1 << 2)
...@@ -601,6 +603,12 @@ static int bat_get_property(struct power_supply *psy, ...@@ -601,6 +603,12 @@ static int bat_get_property(struct power_supply *psy,
case POWER_SUPPLY_PROP_CHARGE_NOW: case POWER_SUPPLY_PROP_CHARGE_NOW:
val->intval = ec_read_u16(BAT_CHARGE_NOW) * 1000; val->intval = ec_read_u16(BAT_CHARGE_NOW) * 1000;
break; break;
case POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT:
val->intval = ec_read_u8(BAT_CHARGE_LIMIT);
break;
case POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT_MAX:
val->intval = BAT_CHARGE_LIMIT_MAX;
break;
case POWER_SUPPLY_PROP_CAPACITY: case POWER_SUPPLY_PROP_CAPACITY:
val->intval = ec_read_u8(BAT_CAPACITY); val->intval = ec_read_u8(BAT_CAPACITY);
break; break;
...@@ -634,6 +642,36 @@ static int bat_get_property(struct power_supply *psy, ...@@ -634,6 +642,36 @@ static int bat_get_property(struct power_supply *psy,
return 0; return 0;
} }
static int bat_set_property(struct power_supply *psy,
enum power_supply_property psp,
const union power_supply_propval *val)
{
int level;
switch (psp) {
case POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT:
level = val->intval;
if (level < 0 || level > BAT_CHARGE_LIMIT_MAX)
return -EINVAL;
if (ec_write(BAT_CHARGE_LIMIT, level) < 0)
return -EIO;
break;
default:
break;
}
return 0;
}
static int bat_writeable_property(struct power_supply *psy,
enum power_supply_property psp)
{
switch (psp) {
case POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT:
return 1;
default:
return 0;
}
}
...@@ -726,6 +764,8 @@ static enum power_supply_property compal_bat_properties[] = { ...@@ -726,6 +764,8 @@ static enum power_supply_property compal_bat_properties[] = {
POWER_SUPPLY_PROP_POWER_NOW, POWER_SUPPLY_PROP_POWER_NOW,
POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
POWER_SUPPLY_PROP_CHARGE_NOW, POWER_SUPPLY_PROP_CHARGE_NOW,
POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT,
POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT_MAX,
POWER_SUPPLY_PROP_CAPACITY, POWER_SUPPLY_PROP_CAPACITY,
POWER_SUPPLY_PROP_CAPACITY_LEVEL, POWER_SUPPLY_PROP_CAPACITY_LEVEL,
POWER_SUPPLY_PROP_TEMP, POWER_SUPPLY_PROP_TEMP,
...@@ -880,11 +920,12 @@ static const struct power_supply_desc psy_bat_desc = { ...@@ -880,11 +920,12 @@ static const struct power_supply_desc psy_bat_desc = {
.properties = compal_bat_properties, .properties = compal_bat_properties,
.num_properties = ARRAY_SIZE(compal_bat_properties), .num_properties = ARRAY_SIZE(compal_bat_properties),
.get_property = bat_get_property, .get_property = bat_get_property,
.set_property = bat_set_property,
.property_is_writeable = bat_writeable_property,
}; };
static void initialize_power_supply_data(struct compal_data *data) static void initialize_power_supply_data(struct compal_data *data)
{ {
ec_read_sequence(BAT_MANUFACTURER_NAME_ADDR, ec_read_sequence(BAT_MANUFACTURER_NAME_ADDR,
data->bat_manufacturer_name, data->bat_manufacturer_name,
BAT_MANUFACTURER_NAME_LEN); BAT_MANUFACTURER_NAME_LEN);
......
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/input.h> #include <linux/input.h>
#include <linux/mfd/intel_msic.h> #include <linux/mfd/intel_msic.h>
#include <linux/pm_wakeirq.h>
#define DRIVER_NAME "msic_power_btn" #define DRIVER_NAME "msic_power_btn"
...@@ -76,7 +77,7 @@ static int mfld_pb_probe(struct platform_device *pdev) ...@@ -76,7 +77,7 @@ static int mfld_pb_probe(struct platform_device *pdev)
input_set_capability(input, EV_KEY, KEY_POWER); input_set_capability(input, EV_KEY, KEY_POWER);
error = request_threaded_irq(irq, NULL, mfld_pb_isr, IRQF_NO_SUSPEND, error = request_threaded_irq(irq, NULL, mfld_pb_isr, 0,
DRIVER_NAME, input); DRIVER_NAME, input);
if (error) { if (error) {
dev_err(&pdev->dev, "Unable to request irq %d for mfld power" dev_err(&pdev->dev, "Unable to request irq %d for mfld power"
...@@ -84,6 +85,9 @@ static int mfld_pb_probe(struct platform_device *pdev) ...@@ -84,6 +85,9 @@ static int mfld_pb_probe(struct platform_device *pdev)
goto err_free_input; goto err_free_input;
} }
device_init_wakeup(&pdev->dev, true);
dev_pm_set_wake_irq(&pdev->dev, irq);
error = input_register_device(input); error = input_register_device(input);
if (error) { if (error) {
dev_err(&pdev->dev, "Unable to register input dev, error " dev_err(&pdev->dev, "Unable to register input dev, error "
...@@ -124,6 +128,8 @@ static int mfld_pb_remove(struct platform_device *pdev) ...@@ -124,6 +128,8 @@ static int mfld_pb_remove(struct platform_device *pdev)
struct input_dev *input = platform_get_drvdata(pdev); struct input_dev *input = platform_get_drvdata(pdev);
int irq = platform_get_irq(pdev, 0); int irq = platform_get_irq(pdev, 0);
dev_pm_clear_wake_irq(&pdev->dev);
device_init_wakeup(&pdev->dev, false);
free_irq(irq, input); free_irq(irq, input);
input_unregister_device(input); input_unregister_device(input);
......
This diff is collapsed.
...@@ -1204,6 +1204,8 @@ static void sony_nc_notify(struct acpi_device *device, u32 event) ...@@ -1204,6 +1204,8 @@ static void sony_nc_notify(struct acpi_device *device, u32 event)
{ {
u32 real_ev = event; u32 real_ev = event;
u8 ev_type = 0; u8 ev_type = 0;
int ret;
dprintk("sony_nc_notify, event: 0x%.2x\n", event); dprintk("sony_nc_notify, event: 0x%.2x\n", event);
if (event >= 0x90) { if (event >= 0x90) {
...@@ -1225,13 +1227,12 @@ static void sony_nc_notify(struct acpi_device *device, u32 event) ...@@ -1225,13 +1227,12 @@ static void sony_nc_notify(struct acpi_device *device, u32 event)
case 0x0100: case 0x0100:
case 0x0127: case 0x0127:
ev_type = HOTKEY; ev_type = HOTKEY;
real_ev = sony_nc_hotkeys_decode(event, handle); ret = sony_nc_hotkeys_decode(event, handle);
if (real_ev > 0) if (ret > 0) {
sony_laptop_report_input_event(real_ev); sony_laptop_report_input_event(ret);
else real_ev = ret;
/* restore the original event for reporting */ }
real_ev = event;
break; break;
......
/*
* toshiba_wmi.c - Toshiba WMI Hotkey Driver
*
* Copyright (C) 2015 Azael Avalos <coproscefalo@gmail.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
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/types.h>
#include <linux/acpi.h>
#include <linux/input.h>
#include <linux/input/sparse-keymap.h>
MODULE_AUTHOR("Azael Avalos");
MODULE_DESCRIPTION("Toshiba WMI Hotkey Driver");
MODULE_LICENSE("GPL");
#define TOSHIBA_WMI_EVENT_GUID "59142400-C6A3-40FA-BADB-8A2652834100"
MODULE_ALIAS("wmi:"TOSHIBA_WMI_EVENT_GUID);
static struct input_dev *toshiba_wmi_input_dev;
static const struct key_entry toshiba_wmi_keymap[] __initconst = {
/* TODO: Add keymap values once found... */
/*{ KE_KEY, 0x00, { KEY_ } },*/
{ KE_END, 0 }
};
static void toshiba_wmi_notify(u32 value, void *context)
{
struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL };
union acpi_object *obj;
acpi_status status;
status = wmi_get_event_data(value, &response);
if (ACPI_FAILURE(status)) {
pr_err("Bad event status 0x%x\n", status);
return;
}
obj = (union acpi_object *)response.pointer;
if (!obj)
return;
/* TODO: Add proper checks once we have data */
pr_debug("Unknown event received, obj type %x\n", obj->type);
kfree(response.pointer);
}
static int __init toshiba_wmi_input_setup(void)
{
acpi_status status;
int err;
toshiba_wmi_input_dev = input_allocate_device();
if (!toshiba_wmi_input_dev)
return -ENOMEM;
toshiba_wmi_input_dev->name = "Toshiba WMI hotkeys";
toshiba_wmi_input_dev->phys = "wmi/input0";
toshiba_wmi_input_dev->id.bustype = BUS_HOST;
err = sparse_keymap_setup(toshiba_wmi_input_dev,
toshiba_wmi_keymap, NULL);
if (err)
goto err_free_dev;
status = wmi_install_notify_handler(TOSHIBA_WMI_EVENT_GUID,
toshiba_wmi_notify, NULL);
if (ACPI_FAILURE(status)) {
err = -EIO;
goto err_free_keymap;
}
err = input_register_device(toshiba_wmi_input_dev);
if (err)
goto err_remove_notifier;
return 0;
err_remove_notifier:
wmi_remove_notify_handler(TOSHIBA_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;
}
static void toshiba_wmi_input_destroy(void)
{
wmi_remove_notify_handler(TOSHIBA_WMI_EVENT_GUID);
sparse_keymap_free(toshiba_wmi_input_dev);
input_unregister_device(toshiba_wmi_input_dev);
}
static int __init toshiba_wmi_init(void)
{
int ret;
if (!wmi_has_guid(TOSHIBA_WMI_EVENT_GUID))
return -ENODEV;
ret = toshiba_wmi_input_setup();
if (ret) {
pr_err("Failed to setup input device\n");
return ret;
}
pr_info("Toshiba WMI Hotkey Driver\n");
return 0;
}
static void __exit toshiba_wmi_exit(void)
{
if (wmi_has_guid(TOSHIBA_WMI_EVENT_GUID))
toshiba_wmi_input_destroy();
}
module_init(toshiba_wmi_init);
module_exit(toshiba_wmi_exit);
...@@ -131,7 +131,7 @@ MODULE_LICENSE("GPL"); ...@@ -131,7 +131,7 @@ MODULE_LICENSE("GPL");
/* Field definitions */ /* Field definitions */
#define HCI_ACCEL_MASK 0x7fff #define HCI_ACCEL_MASK 0x7fff
#define HCI_HOTKEY_DISABLE 0x0b #define HCI_HOTKEY_DISABLE 0x0b
#define HCI_HOTKEY_ENABLE 0x09 #define HCI_HOTKEY_ENABLE 0x01
#define HCI_HOTKEY_SPECIAL_FUNCTIONS 0x10 #define HCI_HOTKEY_SPECIAL_FUNCTIONS 0x10
#define HCI_LCD_BRIGHTNESS_BITS 3 #define HCI_LCD_BRIGHTNESS_BITS 3
#define HCI_LCD_BRIGHTNESS_SHIFT (16-HCI_LCD_BRIGHTNESS_BITS) #define HCI_LCD_BRIGHTNESS_SHIFT (16-HCI_LCD_BRIGHTNESS_BITS)
...@@ -198,6 +198,7 @@ struct toshiba_acpi_dev { ...@@ -198,6 +198,7 @@ struct toshiba_acpi_dev {
unsigned int panel_power_on_supported:1; unsigned int panel_power_on_supported:1;
unsigned int usb_three_supported:1; unsigned int usb_three_supported:1;
unsigned int sysfs_created:1; unsigned int sysfs_created:1;
unsigned int special_functions;
bool kbd_led_registered; bool kbd_led_registered;
bool illumination_led_registered; bool illumination_led_registered;
...@@ -1668,10 +1669,10 @@ static ssize_t available_kbd_modes_show(struct device *dev, ...@@ -1668,10 +1669,10 @@ static ssize_t available_kbd_modes_show(struct device *dev,
struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
if (toshiba->kbd_type == 1) if (toshiba->kbd_type == 1)
return sprintf(buf, "%x %x\n", return sprintf(buf, "0x%x 0x%x\n",
SCI_KBD_MODE_FNZ, SCI_KBD_MODE_AUTO); SCI_KBD_MODE_FNZ, SCI_KBD_MODE_AUTO);
return sprintf(buf, "%x %x %x\n", return sprintf(buf, "0x%x 0x%x 0x%x\n",
SCI_KBD_MODE_AUTO, SCI_KBD_MODE_ON, SCI_KBD_MODE_OFF); SCI_KBD_MODE_AUTO, SCI_KBD_MODE_ON, SCI_KBD_MODE_OFF);
} }
static DEVICE_ATTR_RO(available_kbd_modes); static DEVICE_ATTR_RO(available_kbd_modes);
...@@ -2253,7 +2254,16 @@ static int toshiba_acpi_enable_hotkeys(struct toshiba_acpi_dev *dev) ...@@ -2253,7 +2254,16 @@ static int toshiba_acpi_enable_hotkeys(struct toshiba_acpi_dev *dev)
if (ACPI_FAILURE(status)) if (ACPI_FAILURE(status))
return -ENODEV; return -ENODEV;
/*
* Enable the "Special Functions" mode only if they are
* supported and if they are activated.
*/
if (dev->kbd_function_keys_supported && dev->special_functions)
result = hci_write(dev, HCI_HOTKEY_EVENT,
HCI_HOTKEY_SPECIAL_FUNCTIONS);
else
result = hci_write(dev, HCI_HOTKEY_EVENT, HCI_HOTKEY_ENABLE); result = hci_write(dev, HCI_HOTKEY_EVENT, HCI_HOTKEY_ENABLE);
if (result == TOS_FAILURE) if (result == TOS_FAILURE)
return -EIO; return -EIO;
else if (result == TOS_NOT_SUPPORTED) else if (result == TOS_NOT_SUPPORTED)
...@@ -2262,20 +2272,6 @@ static int toshiba_acpi_enable_hotkeys(struct toshiba_acpi_dev *dev) ...@@ -2262,20 +2272,6 @@ static int toshiba_acpi_enable_hotkeys(struct toshiba_acpi_dev *dev)
return 0; return 0;
} }
static void toshiba_acpi_enable_special_functions(struct toshiba_acpi_dev *dev)
{
u32 result;
/*
* Re-activate the hotkeys, but this time, we are using the
* "Special Functions" mode.
*/
result = hci_write(dev, HCI_HOTKEY_EVENT,
HCI_HOTKEY_SPECIAL_FUNCTIONS);
if (result != TOS_SUCCESS)
pr_err("Could not enable the Special Function mode\n");
}
static bool toshiba_acpi_i8042_filter(unsigned char data, unsigned char str, static bool toshiba_acpi_i8042_filter(unsigned char data, unsigned char str,
struct serio *port) struct serio *port)
{ {
...@@ -2385,8 +2381,6 @@ static int toshiba_acpi_setup_keyboard(struct toshiba_acpi_dev *dev) ...@@ -2385,8 +2381,6 @@ static int toshiba_acpi_setup_keyboard(struct toshiba_acpi_dev *dev)
{ {
const struct key_entry *keymap = toshiba_acpi_keymap; const struct key_entry *keymap = toshiba_acpi_keymap;
acpi_handle ec_handle; acpi_handle ec_handle;
u32 events_type;
u32 hci_result;
int error; int error;
if (wmi_has_guid(TOSHIBA_WMI_EVENT_GUID)) { if (wmi_has_guid(TOSHIBA_WMI_EVENT_GUID)) {
...@@ -2398,11 +2392,9 @@ static int toshiba_acpi_setup_keyboard(struct toshiba_acpi_dev *dev) ...@@ -2398,11 +2392,9 @@ static int toshiba_acpi_setup_keyboard(struct toshiba_acpi_dev *dev)
if (error) if (error)
return error; return error;
if (toshiba_hotkey_event_type_get(dev, &events_type)) if (toshiba_hotkey_event_type_get(dev, &dev->hotkey_event_type))
pr_notice("Unable to query Hotkey Event Type\n"); pr_notice("Unable to query Hotkey Event Type\n");
dev->hotkey_event_type = events_type;
dev->hotkey_dev = input_allocate_device(); dev->hotkey_dev = input_allocate_device();
if (!dev->hotkey_dev) if (!dev->hotkey_dev)
return -ENOMEM; return -ENOMEM;
...@@ -2411,14 +2403,15 @@ static int toshiba_acpi_setup_keyboard(struct toshiba_acpi_dev *dev) ...@@ -2411,14 +2403,15 @@ static int toshiba_acpi_setup_keyboard(struct toshiba_acpi_dev *dev)
dev->hotkey_dev->phys = "toshiba_acpi/input0"; dev->hotkey_dev->phys = "toshiba_acpi/input0";
dev->hotkey_dev->id.bustype = BUS_HOST; dev->hotkey_dev->id.bustype = BUS_HOST;
if (events_type == HCI_SYSTEM_TYPE1 || if (dev->hotkey_event_type == HCI_SYSTEM_TYPE1 ||
!dev->kbd_function_keys_supported) !dev->kbd_function_keys_supported)
keymap = toshiba_acpi_keymap; keymap = toshiba_acpi_keymap;
else if (events_type == HCI_SYSTEM_TYPE2 || else if (dev->hotkey_event_type == HCI_SYSTEM_TYPE2 ||
dev->kbd_function_keys_supported) dev->kbd_function_keys_supported)
keymap = toshiba_acpi_alt_keymap; keymap = toshiba_acpi_alt_keymap;
else else
pr_info("Unknown event type received %x\n", events_type); pr_info("Unknown event type received %x\n",
dev->hotkey_event_type);
error = sparse_keymap_setup(dev->hotkey_dev, keymap, NULL); error = sparse_keymap_setup(dev->hotkey_dev, keymap, NULL);
if (error) if (error)
goto err_free_dev; goto err_free_dev;
...@@ -2449,11 +2442,8 @@ static int toshiba_acpi_setup_keyboard(struct toshiba_acpi_dev *dev) ...@@ -2449,11 +2442,8 @@ static int toshiba_acpi_setup_keyboard(struct toshiba_acpi_dev *dev)
*/ */
if (acpi_has_method(dev->acpi_dev->handle, "INFO")) if (acpi_has_method(dev->acpi_dev->handle, "INFO"))
dev->info_supported = 1; dev->info_supported = 1;
else { else if (hci_write(dev, HCI_SYSTEM_EVENT, 1) == TOS_SUCCESS)
hci_result = hci_write(dev, HCI_SYSTEM_EVENT, 1);
if (hci_result == TOS_SUCCESS)
dev->system_event_supported = 1; dev->system_event_supported = 1;
}
if (!dev->info_supported && !dev->system_event_supported) { if (!dev->info_supported && !dev->system_event_supported) {
pr_warn("No hotkey query interface found\n"); pr_warn("No hotkey query interface found\n");
...@@ -2631,7 +2621,6 @@ static int toshiba_acpi_add(struct acpi_device *acpi_dev) ...@@ -2631,7 +2621,6 @@ static int toshiba_acpi_add(struct acpi_device *acpi_dev)
{ {
struct toshiba_acpi_dev *dev; struct toshiba_acpi_dev *dev;
const char *hci_method; const char *hci_method;
u32 special_functions;
u32 dummy; u32 dummy;
int ret = 0; int ret = 0;
...@@ -2673,9 +2662,10 @@ static int toshiba_acpi_add(struct acpi_device *acpi_dev) ...@@ -2673,9 +2662,10 @@ static int toshiba_acpi_add(struct acpi_device *acpi_dev)
* with the new keyboard layout, query for its presence to help * with the new keyboard layout, query for its presence to help
* determine the keymap layout to use. * determine the keymap layout to use.
*/ */
ret = toshiba_function_keys_get(dev, &special_functions); ret = toshiba_function_keys_get(dev, &dev->special_functions);
dev->kbd_function_keys_supported = !ret; dev->kbd_function_keys_supported = !ret;
dev->hotkey_event_type = 0;
if (toshiba_acpi_setup_keyboard(dev)) if (toshiba_acpi_setup_keyboard(dev))
pr_info("Unable to activate hotkeys\n"); pr_info("Unable to activate hotkeys\n");
...@@ -2748,13 +2738,6 @@ static int toshiba_acpi_add(struct acpi_device *acpi_dev) ...@@ -2748,13 +2738,6 @@ static int toshiba_acpi_add(struct acpi_device *acpi_dev)
print_supported_features(dev); print_supported_features(dev);
/*
* Enable the "Special Functions" mode only if they are
* supported and if they are activated.
*/
if (dev->kbd_function_keys_supported && special_functions)
toshiba_acpi_enable_special_functions(dev);
ret = sysfs_create_group(&dev->acpi_dev->dev.kobj, ret = sysfs_create_group(&dev->acpi_dev->dev.kobj,
&toshiba_attr_group); &toshiba_attr_group);
if (ret) { if (ret) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment