diff options
author | Stephen Rothwell <sfr@canb.auug.org.au> | 2010-11-30 11:49:36 +1100 |
---|---|---|
committer | Stephen Rothwell <sfr@canb.auug.org.au> | 2010-11-30 11:49:36 +1100 |
commit | 04d2f69c903f18611178d93b60268dc0b9353a68 (patch) | |
tree | 1d7ff914ed8c2aad086099a664e25d5bed465752 | |
parent | 871568fe58e628239d0c050bcae5476baa69a373 (diff) | |
parent | 42078305f8a6b2ef0e8e6c55b4e3f3170ee51e50 (diff) |
Merge remote branch 'drivers-x86/linux-next'
-rw-r--r-- | Documentation/ABI/testing/sysfs-platform-asus-laptop | 16 | ||||
-rw-r--r-- | Documentation/ABI/testing/sysfs-platform-eeepc-wmi | 10 | ||||
-rw-r--r-- | drivers/platform/x86/Kconfig | 9 | ||||
-rw-r--r-- | drivers/platform/x86/Makefile | 1 | ||||
-rw-r--r-- | drivers/platform/x86/asus-laptop.c | 97 | ||||
-rw-r--r-- | drivers/platform/x86/classmate-laptop.c | 2 | ||||
-rw-r--r-- | drivers/platform/x86/eeepc-wmi.c | 4 | ||||
-rw-r--r-- | drivers/platform/x86/hp-wmi.c | 2 | ||||
-rw-r--r-- | drivers/platform/x86/ibm_rtl.c | 34 | ||||
-rw-r--r-- | drivers/platform/x86/intel_scu_ipc.c | 4 | ||||
-rw-r--r-- | drivers/platform/x86/intel_scu_ipcutil.c | 133 | ||||
-rw-r--r-- | drivers/platform/x86/msi-wmi.c | 16 | ||||
-rw-r--r-- | drivers/platform/x86/thinkpad_acpi.c | 3 | ||||
-rw-r--r-- | drivers/platform/x86/toshiba_acpi.c | 1 | ||||
-rw-r--r-- | drivers/platform/x86/wmi.c | 133 |
15 files changed, 362 insertions, 103 deletions
diff --git a/Documentation/ABI/testing/sysfs-platform-asus-laptop b/Documentation/ABI/testing/sysfs-platform-asus-laptop index 1d775390e856..41ff8ae4dee0 100644 --- a/Documentation/ABI/testing/sysfs-platform-asus-laptop +++ b/Documentation/ABI/testing/sysfs-platform-asus-laptop @@ -47,6 +47,20 @@ Date: January 2007 KernelVersion: 2.6.20 Contact: "Corentin Chary" <corentincj@iksaif.net> Description: - Control the bluetooth device. 1 means on, 0 means off. + Control the wlan device. 1 means on, 0 means off. This may control the led, the device or both. Users: Lapsus + +What: /sys/devices/platform/asus_laptop/wimax +Date: October 2010 +KernelVersion: 2.6.37 +Contact: "Corentin Chary" <corentincj@iksaif.net> +Description: + Control the wimax device. 1 means on, 0 means off. + +What: /sys/devices/platform/asus_laptop/wwan +Date: October 2010 +KernelVersion: 2.6.37 +Contact: "Corentin Chary" <corentincj@iksaif.net> +Description: + Control the wwan (3G) device. 1 means on, 0 means off. diff --git a/Documentation/ABI/testing/sysfs-platform-eeepc-wmi b/Documentation/ABI/testing/sysfs-platform-eeepc-wmi new file mode 100644 index 000000000000..e4b5fef5fadd --- /dev/null +++ b/Documentation/ABI/testing/sysfs-platform-eeepc-wmi @@ -0,0 +1,10 @@ +What: /sys/devices/platform/eeepc-wmi/cpufv +Date: Oct 2010 +KernelVersion: 2.6.37 +Contact: "Corentin Chary" <corentincj@iksaif.net> +Description: + Change CPU clock configuration (write-only). + There are three available clock configuration: + * 0 -> Super Performance Mode + * 1 -> High Performance Mode + * 2 -> Power Saving Mode diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index faec777b1ed4..65ba62086ca8 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -576,6 +576,15 @@ config INTEL_SCU_IPC some embedded Intel x86 platforms. This is not needed for PC-type machines. +config INTEL_SCU_IPC_UTIL + tristate "Intel SCU IPC utility driver" + depends on INTEL_SCU_IPC + default y + ---help--- + The IPC Util driver provides an interface with the SCU enabling + low level access for debug work and updating the firmware. Say + N unless you will be doing this on an Intel MID platform. + config GPIO_INTEL_PMIC bool "Intel PMIC GPIO support" depends on INTEL_SCU_IPC && GPIOLIB diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile index 9950ccc940b5..4ec4ff8f9182 100644 --- a/drivers/platform/x86/Makefile +++ b/drivers/platform/x86/Makefile @@ -28,6 +28,7 @@ obj-$(CONFIG_TOPSTAR_LAPTOP) += topstar-laptop.o obj-$(CONFIG_ACPI_TOSHIBA) += toshiba_acpi.o obj-$(CONFIG_TOSHIBA_BT_RFKILL) += toshiba_bluetooth.o obj-$(CONFIG_INTEL_SCU_IPC) += intel_scu_ipc.o +obj-$(CONFIG_INTEL_SCU_IPC_UTIL)+= intel_scu_ipcutil.o obj-$(CONFIG_RAR_REGISTER) += intel_rar_register.o obj-$(CONFIG_INTEL_IPS) += intel_ips.o obj-$(CONFIG_GPIO_INTEL_PMIC) += intel_pmic_gpio.o diff --git a/drivers/platform/x86/asus-laptop.c b/drivers/platform/x86/asus-laptop.c index 3640599446fc..f3aa6a7fdab6 100644 --- a/drivers/platform/x86/asus-laptop.c +++ b/drivers/platform/x86/asus-laptop.c @@ -81,6 +81,8 @@ MODULE_PARM_DESC(wapf, "WAPF value"); static int wlan_status = 1; static int bluetooth_status = 1; +static int wimax_status = -1; +static int wwan_status = -1; module_param(wlan_status, int, 0444); MODULE_PARM_DESC(wlan_status, "Set the wireless status on boot " @@ -92,6 +94,16 @@ MODULE_PARM_DESC(bluetooth_status, "Set the wireless status on boot " "(0 = disabled, 1 = enabled, -1 = don't do anything). " "default is 1"); +module_param(wimax_status, int, 0444); +MODULE_PARM_DESC(wimax_status, "Set the wireless status on boot " + "(0 = disabled, 1 = enabled, -1 = don't do anything). " + "default is 1"); + +module_param(wwan_status, int, 0444); +MODULE_PARM_DESC(wwan_status, "Set the wireless status on boot " + "(0 = disabled, 1 = enabled, -1 = don't do anything). " + "default is 1"); + /* * Some events we use, same for all Asus */ @@ -114,6 +126,8 @@ MODULE_PARM_DESC(bluetooth_status, "Set the wireless status on boot " */ #define WL_RSTS 0x01 /* internal Wifi */ #define BT_RSTS 0x02 /* internal Bluetooth */ +#define WM_RSTS 0x08 /* internal wimax */ +#define WW_RSTS 0x20 /* internal wwan */ /* LED */ #define METHOD_MLED "MLED" @@ -132,6 +146,11 @@ MODULE_PARM_DESC(bluetooth_status, "Set the wireless status on boot " */ #define METHOD_WLAN "WLED" #define METHOD_BLUETOOTH "BLED" + +/* WWAN and WIMAX */ +#define METHOD_WWAN "GSMC" +#define METHOD_WIMAX "WMXC" + #define METHOD_WL_STATUS "RSTS" /* Brightness */ @@ -883,6 +902,64 @@ static ssize_t store_bluetooth(struct device *dev, } /* + * Wimax + */ +static int asus_wimax_set(struct asus_laptop *asus, int status) +{ + if (write_acpi_int(asus->handle, METHOD_WIMAX, !!status)) { + pr_warning("Error setting wimax status to %d", status); + return -EIO; + } + return 0; +} + +static ssize_t show_wimax(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct asus_laptop *asus = dev_get_drvdata(dev); + + return sprintf(buf, "%d\n", asus_wireless_status(asus, WM_RSTS)); +} + +static ssize_t store_wimax(struct device *dev, + struct device_attribute *attr, const char *buf, + size_t count) +{ + struct asus_laptop *asus = dev_get_drvdata(dev); + + return sysfs_acpi_set(asus, buf, count, METHOD_WIMAX); +} + +/* + * Wwan + */ +static int asus_wwan_set(struct asus_laptop *asus, int status) +{ + if (write_acpi_int(asus->handle, METHOD_WWAN, !!status)) { + pr_warning("Error setting wwan status to %d", status); + return -EIO; + } + return 0; +} + +static ssize_t show_wwan(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct asus_laptop *asus = dev_get_drvdata(dev); + + return sprintf(buf, "%d\n", asus_wireless_status(asus, WW_RSTS)); +} + +static ssize_t store_wwan(struct device *dev, + struct device_attribute *attr, const char *buf, + size_t count) +{ + struct asus_laptop *asus = dev_get_drvdata(dev); + + return sysfs_acpi_set(asus, buf, count, METHOD_WWAN); +} + +/* * Display */ static void asus_set_display(struct asus_laptop *asus, int value) @@ -1202,6 +1279,8 @@ static DEVICE_ATTR(infos, S_IRUGO, show_infos, NULL); static DEVICE_ATTR(wlan, S_IRUGO | S_IWUSR, show_wlan, store_wlan); static DEVICE_ATTR(bluetooth, S_IRUGO | S_IWUSR, show_bluetooth, store_bluetooth); +static DEVICE_ATTR(wimax, S_IRUGO | S_IWUSR, show_wimax, store_wimax); +static DEVICE_ATTR(wwan, S_IRUGO | S_IWUSR, show_wwan, store_wwan); static DEVICE_ATTR(display, S_IRUGO | S_IWUSR, show_disp, store_disp); static DEVICE_ATTR(ledd, S_IRUGO | S_IWUSR, show_ledd, store_ledd); static DEVICE_ATTR(ls_level, S_IRUGO | S_IWUSR, show_lslvl, store_lslvl); @@ -1212,6 +1291,8 @@ static struct attribute *asus_attributes[] = { &dev_attr_infos.attr, &dev_attr_wlan.attr, &dev_attr_bluetooth.attr, + &dev_attr_wimax.attr, + &dev_attr_wwan.attr, &dev_attr_display.attr, &dev_attr_ledd.attr, &dev_attr_ls_level.attr, @@ -1239,6 +1320,13 @@ static mode_t asus_sysfs_is_visible(struct kobject *kobj, } else if (attr == &dev_attr_display.attr) { supported = !acpi_check_handle(handle, METHOD_SWITCH_DISPLAY, NULL); + } else if (attr == &dev_attr_wimax.attr) { + supported = + !acpi_check_handle(asus->handle, METHOD_WIMAX, NULL); + + } else if (attr == &dev_attr_wwan.attr) { + supported = !acpi_check_handle(asus->handle, METHOD_WWAN, NULL); + } else if (attr == &dev_attr_ledd.attr) { supported = !acpi_check_handle(handle, METHOD_LEDD, NULL); @@ -1397,7 +1485,8 @@ static int asus_laptop_get_info(struct asus_laptop *asus) /* * The HWRS method return informations about the hardware. - * 0x80 bit is for WLAN, 0x100 for Bluetooth. + * 0x80 bit is for WLAN, 0x100 for Bluetooth, + * 0x40 for WWAN, 0x10 for WIMAX. * The significance of others is yet to be found. */ status = @@ -1440,6 +1529,12 @@ static int __devinit asus_acpi_init(struct asus_laptop *asus) if (wlan_status >= 0) asus_wlan_set(asus, !!wlan_status); + if (wimax_status >= 0) + asus_wimax_set(asus, !!wimax_status); + + if (wwan_status >= 0) + asus_wwan_set(asus, !!wwan_status); + /* Keyboard Backlight is on by default */ if (!acpi_check_handle(asus->handle, METHOD_KBD_LIGHT_SET, NULL)) asus_kled_set(asus, 1); diff --git a/drivers/platform/x86/classmate-laptop.c b/drivers/platform/x86/classmate-laptop.c index 341cbfef93ee..d2b7720c0e6f 100644 --- a/drivers/platform/x86/classmate-laptop.c +++ b/drivers/platform/x86/classmate-laptop.c @@ -653,7 +653,7 @@ static void cmpc_keys_handler(struct acpi_device *dev, u32 event) if ((event & 0x0F) < ARRAY_SIZE(cmpc_keys_codes)) code = cmpc_keys_codes[event & 0x0F]; - inputdev = dev_get_drvdata(&dev->dev);; + inputdev = dev_get_drvdata(&dev->dev); input_report_key(inputdev, code, !(event & 0x10)); } diff --git a/drivers/platform/x86/eeepc-wmi.c b/drivers/platform/x86/eeepc-wmi.c index 462ceab93f87..0d50fbbe2478 100644 --- a/drivers/platform/x86/eeepc-wmi.c +++ b/drivers/platform/x86/eeepc-wmi.c @@ -298,8 +298,8 @@ static void eeepc_wmi_notify(u32 value, void *context) kfree(obj); } -static int store_cpufv(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) +static ssize_t store_cpufv(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { int value; struct acpi_buffer input = { (acpi_size)sizeof(value), &value }; diff --git a/drivers/platform/x86/hp-wmi.c b/drivers/platform/x86/hp-wmi.c index 1dac659b5e0c..9e05af9c41cb 100644 --- a/drivers/platform/x86/hp-wmi.c +++ b/drivers/platform/x86/hp-wmi.c @@ -172,6 +172,8 @@ static int hp_wmi_perform_query(int query, int write, u32 *buffer, bios_return = *((struct bios_return *)obj->buffer.pointer); memcpy(buffer, &bios_return.value, sizeof(bios_return.value)); + + kfree(obj); return 0; } diff --git a/drivers/platform/x86/ibm_rtl.c b/drivers/platform/x86/ibm_rtl.c index 3c2c6b91ecb3..94a114aa8e28 100644 --- a/drivers/platform/x86/ibm_rtl.c +++ b/drivers/platform/x86/ibm_rtl.c @@ -28,6 +28,7 @@ #include <linux/io.h> #include <linux/sysdev.h> #include <linux/dmi.h> +#include <linux/efi.h> #include <linux/mutex.h> #include <asm/bios_ebda.h> @@ -220,32 +221,13 @@ static void rtl_teardown_sysfs(void) { sysdev_class_unregister(&class_rtl); } -static int dmi_check_cb(const struct dmi_system_id *id) -{ - RTL_DEBUG("found IBM server '%s'\n", id->ident); - return 0; -} - -#define ibm_dmi_entry(NAME, TYPE) \ -{ \ - .ident = NAME, \ - .matches = { \ - DMI_MATCH(DMI_SYS_VENDOR, "IBM"), \ - DMI_MATCH(DMI_PRODUCT_NAME, TYPE), \ - }, \ - .callback = dmi_check_cb \ -} static struct dmi_system_id __initdata ibm_rtl_dmi_table[] = { - ibm_dmi_entry("BladeCenter LS21", "7971"), - ibm_dmi_entry("BladeCenter LS22", "7901"), - ibm_dmi_entry("BladeCenter HS21 XM", "7995"), - ibm_dmi_entry("BladeCenter HS22", "7870"), - ibm_dmi_entry("BladeCenter HS22V", "7871"), - ibm_dmi_entry("System x3550 M2", "7946"), - ibm_dmi_entry("System x3650 M2", "7947"), - ibm_dmi_entry("System x3550 M3", "7944"), - ibm_dmi_entry("System x3650 M3", "7945"), + { \ + .matches = { \ + DMI_MATCH(DMI_SYS_VENDOR, "IBM"), \ + }, \ + }, { } }; @@ -257,7 +239,7 @@ static int __init ibm_rtl_init(void) { if (force) pr_warning("ibm-rtl: module loaded by force\n"); /* first ensure that we are running on IBM HW */ - else if (!dmi_check_system(ibm_rtl_dmi_table)) + else if (efi_enabled || !dmi_check_system(ibm_rtl_dmi_table)) return -ENODEV; /* Get the address for the Extended BIOS Data Area */ @@ -302,7 +284,7 @@ static int __init ibm_rtl_init(void) { RTL_DEBUG("rtl_cmd_width = %u, rtl_cmd_type = %u\n", rtl_cmd_width, rtl_cmd_type); addr = ioread32(&rtl_table->cmd_port_address); - RTL_DEBUG("addr = %#llx\n", addr); + RTL_DEBUG("addr = %#llx\n", (unsigned long long)addr); plen = rtl_cmd_width/sizeof(char); rtl_cmd_addr = rtl_port_map(addr, plen); RTL_DEBUG("rtl_cmd_addr = %#llx\n", (u64)rtl_cmd_addr); diff --git a/drivers/platform/x86/intel_scu_ipc.c b/drivers/platform/x86/intel_scu_ipc.c index ca35b0ce944a..1752ef006d26 100644 --- a/drivers/platform/x86/intel_scu_ipc.c +++ b/drivers/platform/x86/intel_scu_ipc.c @@ -497,7 +497,7 @@ int intel_scu_ipc_i2c_cntrl(u32 addr, u32 *data) "intel_scu_ipc: I2C INVALID_CMD = 0x%x\n", cmd); mutex_unlock(&ipclock); - return -1; + return -EIO; } mutex_unlock(&ipclock); return 0; @@ -642,7 +642,7 @@ update_end: if (status == IPC_FW_UPDATE_SUCCESS) return 0; - return -1; + return -EIO; } EXPORT_SYMBOL(intel_scu_ipc_fw_update); diff --git a/drivers/platform/x86/intel_scu_ipcutil.c b/drivers/platform/x86/intel_scu_ipcutil.c new file mode 100644 index 000000000000..ba3231d0819e --- /dev/null +++ b/drivers/platform/x86/intel_scu_ipcutil.c @@ -0,0 +1,133 @@ +/* + * intel_scu_ipc.c: Driver for the Intel SCU IPC mechanism + * + * (C) Copyright 2008-2010 Intel Corporation + * Author: Sreedhara DS (sreedhara.ds@intel.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; version 2 + * of the License. + * + * This driver provides ioctl interfaces to call intel scu ipc driver api + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/types.h> +#include <linux/fs.h> +#include <linux/fcntl.h> +#include <linux/sched.h> +#include <linux/uaccess.h> +#include <linux/slab.h> +#include <linux/init.h> +#include <asm/intel_scu_ipc.h> + +static u32 major; + +#define MAX_FW_SIZE 264192 + +/* ioctl commnds */ +#define INTE_SCU_IPC_REGISTER_READ 0 +#define INTE_SCU_IPC_REGISTER_WRITE 1 +#define INTE_SCU_IPC_REGISTER_UPDATE 2 +#define INTE_SCU_IPC_FW_UPDATE 0xA2 + +struct scu_ipc_data { + u32 count; /* No. of registers */ + u16 addr[5]; /* Register addresses */ + u8 data[5]; /* Register data */ + u8 mask; /* Valid for read-modify-write */ +}; + +/** + * scu_reg_access - implement register access ioctls + * @cmd: command we are doing (read/write/update) + * @data: kernel copy of ioctl data + * + * Allow the user to perform register accesses on the SCU via the + * kernel interface + */ + +static int scu_reg_access(u32 cmd, struct scu_ipc_data *data) +{ + int count = data->count; + + if (count == 0 || count == 3 || count > 4) + return -EINVAL; + + switch (cmd) { + case INTE_SCU_IPC_REGISTER_READ: + return intel_scu_ipc_readv(data->addr, data->data, count); + case INTE_SCU_IPC_REGISTER_WRITE: + return intel_scu_ipc_writev(data->addr, data->data, count); + case INTE_SCU_IPC_REGISTER_UPDATE: + return intel_scu_ipc_update_register(data->addr[0], + data->data[0], data->mask); + default: + return -ENOTTY; + } +} + +/** + * scu_ipc_ioctl - control ioctls for the SCU + * @fp: file handle of the SCU device + * @cmd: ioctl coce + * @arg: pointer to user passed structure + * + * Support the I/O and firmware flashing interfaces of the SCU + */ +static long scu_ipc_ioctl(struct file *fp, unsigned int cmd, + unsigned long arg) +{ + int ret; + struct scu_ipc_data data; + void __user *argp = (void __user *)arg; + + if (!capable(CAP_SYS_RAWIO)) + return -EPERM; + + if (cmd == INTE_SCU_IPC_FW_UPDATE) { + u8 *fwbuf = kmalloc(MAX_FW_SIZE, GFP_KERNEL); + if (fwbuf == NULL) + return -ENOMEM; + if (copy_from_user(fwbuf, (u8 *)arg, MAX_FW_SIZE)) { + kfree(fwbuf); + return -EFAULT; + } + ret = intel_scu_ipc_fw_update(fwbuf, MAX_FW_SIZE); + kfree(fwbuf); + return ret; + } else { + if (copy_from_user(&data, argp, sizeof(struct scu_ipc_data))) + return -EFAULT; + ret = scu_reg_access(cmd, &data); + if (ret < 0) + return ret; + if (copy_to_user(argp, &data, sizeof(struct scu_ipc_data))) + return -EFAULT; + return 0; + } +} + +static const struct file_operations scu_ipc_fops = { + .unlocked_ioctl = scu_ipc_ioctl, +}; + +static int __init ipc_module_init(void) +{ + return register_chrdev(0, "intel_mid_scu", &scu_ipc_fops); +} + +static void __exit ipc_module_exit(void) +{ + unregister_chrdev(major, "intel_mid_scu"); +} + +module_init(ipc_module_init); +module_exit(ipc_module_exit); + +MODULE_LICENSE("GPL V2"); +MODULE_DESCRIPTION("Utility driver for intel scu ipc"); +MODULE_AUTHOR("Sreedhara <sreedhara.ds@intel.com>"); diff --git a/drivers/platform/x86/msi-wmi.c b/drivers/platform/x86/msi-wmi.c index 42a5469a2459..35278ad7e628 100644 --- a/drivers/platform/x86/msi-wmi.c +++ b/drivers/platform/x86/msi-wmi.c @@ -43,16 +43,18 @@ MODULE_ALIAS("wmi:B6F3EEF2-3D2F-49DC-9DE3-85BCE18C62F2"); #define dprintk(msg...) pr_debug(DRV_PFX msg) -#define KEYCODE_BASE 0xD0 -#define MSI_WMI_BRIGHTNESSUP KEYCODE_BASE -#define MSI_WMI_BRIGHTNESSDOWN (KEYCODE_BASE + 1) -#define MSI_WMI_VOLUMEUP (KEYCODE_BASE + 2) -#define MSI_WMI_VOLUMEDOWN (KEYCODE_BASE + 3) +#define SCANCODE_BASE 0xD0 +#define MSI_WMI_BRIGHTNESSUP SCANCODE_BASE +#define MSI_WMI_BRIGHTNESSDOWN (SCANCODE_BASE + 1) +#define MSI_WMI_VOLUMEUP (SCANCODE_BASE + 2) +#define MSI_WMI_VOLUMEDOWN (SCANCODE_BASE + 3) +#define MSI_WMI_MUTE (SCANCODE_BASE + 4) static struct key_entry msi_wmi_keymap[] = { { KE_KEY, MSI_WMI_BRIGHTNESSUP, {KEY_BRIGHTNESSUP} }, { KE_KEY, MSI_WMI_BRIGHTNESSDOWN, {KEY_BRIGHTNESSDOWN} }, { KE_KEY, MSI_WMI_VOLUMEUP, {KEY_VOLUMEUP} }, { KE_KEY, MSI_WMI_VOLUMEDOWN, {KEY_VOLUMEDOWN} }, + { KE_KEY, MSI_WMI_MUTE, {KEY_MUTE} }, { KE_END, 0} }; static ktime_t last_pressed[ARRAY_SIZE(msi_wmi_keymap) - 1]; @@ -169,7 +171,7 @@ static void msi_wmi_notify(u32 value, void *context) ktime_t diff; cur = ktime_get_real(); diff = ktime_sub(cur, last_pressed[key->code - - KEYCODE_BASE]); + SCANCODE_BASE]); /* Ignore event if the same event happened in a 50 ms timeframe -> Key press may result in 10-20 GPEs */ if (ktime_to_us(diff) < 1000 * 50) { @@ -178,7 +180,7 @@ static void msi_wmi_notify(u32 value, void *context) key->code, ktime_to_us(diff)); return; } - last_pressed[key->code - KEYCODE_BASE] = cur; + last_pressed[key->code - SCANCODE_BASE] = cur; if (key->type == KE_KEY && /* Brightness is served via acpi video driver */ diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index efda9c54e0e2..292f4acd897d 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -6345,7 +6345,7 @@ static int __init brightness_init(struct ibm_init_struct *iibm) "as change notification\n"); tpacpi_hotkey_driver_mask_set(hotkey_driver_mask | TP_ACPI_HKEY_BRGHTUP_MASK - | TP_ACPI_HKEY_BRGHTDWN_MASK);; + | TP_ACPI_HKEY_BRGHTDWN_MASK); return 0; } @@ -8497,7 +8497,6 @@ static void ibm_exit(struct ibm_struct *ibm) ibm->acpi->type, dispatch_acpi_notify); ibm->flags.acpi_notify_installed = 0; - ibm->flags.acpi_notify_installed = 0; } if (ibm->flags.proc_created) { diff --git a/drivers/platform/x86/toshiba_acpi.c b/drivers/platform/x86/toshiba_acpi.c index 81bca5a4d8aa..209cced786c6 100644 --- a/drivers/platform/x86/toshiba_acpi.c +++ b/drivers/platform/x86/toshiba_acpi.c @@ -135,6 +135,7 @@ static const struct key_entry toshiba_acpi_keymap[] __initconst = { { KE_KEY, 0x141, { KEY_BRIGHTNESSUP } }, { KE_KEY, 0x142, { KEY_WLAN } }, { KE_KEY, 0x143, { KEY_PROG1 } }, + { KE_KEY, 0x17f, { KEY_FN } }, { KE_KEY, 0xb05, { KEY_PROG2 } }, { KE_KEY, 0xb06, { KEY_WWW } }, { KE_KEY, 0xb07, { KEY_MAIL } }, diff --git a/drivers/platform/x86/wmi.c b/drivers/platform/x86/wmi.c index 104b77c87ef5..3dafb434632e 100644 --- a/drivers/platform/x86/wmi.c +++ b/drivers/platform/x86/wmi.c @@ -549,21 +549,34 @@ acpi_status wmi_install_notify_handler(const char *guid, wmi_notify_handler handler, void *data) { struct wmi_block *block; - acpi_status status; + acpi_status status = AE_NOT_EXIST; + char tmp[16], guid_input[16]; + struct list_head *p; if (!guid || !handler) return AE_BAD_PARAMETER; - if (!find_guid(guid, &block)) - return AE_NOT_EXIST; + wmi_parse_guid(guid, tmp); + wmi_swap_bytes(tmp, guid_input); - if (block->handler && block->handler != wmi_notify_debug) - return AE_ALREADY_ACQUIRED; + list_for_each(p, &wmi_block_list) { + acpi_status wmi_status; + block = list_entry(p, struct wmi_block, list); - block->handler = handler; - block->handler_data = data; + if (memcmp(block->gblock.guid, guid_input, 16) == 0) { + if (block->handler && + block->handler != wmi_notify_debug) + return AE_ALREADY_ACQUIRED; - status = wmi_method_enable(block, 1); + block->handler = handler; + block->handler_data = data; + + wmi_status = wmi_method_enable(block, 1); + if ((wmi_status != AE_OK) || + ((wmi_status == AE_OK) && (status == AE_NOT_EXIST))) + status = wmi_status; + } + } return status; } @@ -577,24 +590,40 @@ EXPORT_SYMBOL_GPL(wmi_install_notify_handler); acpi_status wmi_remove_notify_handler(const char *guid) { struct wmi_block *block; - acpi_status status = AE_OK; + acpi_status status = AE_NOT_EXIST; + char tmp[16], guid_input[16]; + struct list_head *p; if (!guid) return AE_BAD_PARAMETER; - if (!find_guid(guid, &block)) - return AE_NOT_EXIST; + wmi_parse_guid(guid, tmp); + wmi_swap_bytes(tmp, guid_input); - if (!block->handler || block->handler == wmi_notify_debug) - return AE_NULL_ENTRY; + list_for_each(p, &wmi_block_list) { + acpi_status wmi_status; + block = list_entry(p, struct wmi_block, list); - if (debug_event) { - block->handler = wmi_notify_debug; - } else { - status = wmi_method_enable(block, 0); - block->handler = NULL; - block->handler_data = NULL; + if (memcmp(block->gblock.guid, guid_input, 16) == 0) { + if (!block->handler || + block->handler == wmi_notify_debug) + return AE_NULL_ENTRY; + + if (debug_event) { + block->handler = wmi_notify_debug; + status = AE_OK; + } else { + wmi_status = wmi_method_enable(block, 0); + block->handler = NULL; + block->handler_data = NULL; + if ((wmi_status != AE_OK) || + ((wmi_status == AE_OK) && + (status == AE_NOT_EXIST))) + status = wmi_status; + } + } } + return status; } EXPORT_SYMBOL_GPL(wmi_remove_notify_handler); @@ -705,22 +734,11 @@ static struct class wmi_class = { .dev_attrs = wmi_dev_attrs, }; -static struct wmi_block *wmi_create_device(const struct guid_block *gblock, - acpi_handle handle) +static int wmi_create_device(const struct guid_block *gblock, + struct wmi_block *wblock, acpi_handle handle) { - struct wmi_block *wblock; - int error; char guid_string[37]; - wblock = kzalloc(sizeof(struct wmi_block), GFP_KERNEL); - if (!wblock) { - error = -ENOMEM; - goto err_out; - } - - wblock->handle = handle; - wblock->gblock = *gblock; - wblock->dev.class = &wmi_class; wmi_gtoa(gblock->guid, guid_string); @@ -728,17 +746,7 @@ static struct wmi_block *wmi_create_device(const struct guid_block *gblock, dev_set_drvdata(&wblock->dev, wblock); - error = device_register(&wblock->dev); - if (error) - goto err_free; - - list_add_tail(&wblock->list, &wmi_block_list); - return wblock; - -err_free: - kfree(wblock); -err_out: - return ERR_PTR(error); + return device_register(&wblock->dev); } static void wmi_free_devices(void) @@ -747,7 +755,8 @@ static void wmi_free_devices(void) /* Delete devices for all the GUIDs */ list_for_each_entry_safe(wblock, next, &wmi_block_list, list) - device_unregister(&wblock->dev); + if (wblock->dev.class) + device_unregister(&wblock->dev); } static bool guid_already_parsed(const char *guid_string) @@ -770,7 +779,6 @@ static acpi_status parse_wdg(acpi_handle handle) union acpi_object *obj; const struct guid_block *gblock; struct wmi_block *wblock; - char guid_string[37]; acpi_status status; int retval; u32 i, total; @@ -792,28 +800,31 @@ static acpi_status parse_wdg(acpi_handle handle) total = obj->buffer.length / sizeof(struct guid_block); for (i = 0; i < total; i++) { + if (debug_dump_wdg) + wmi_dump_wdg(&gblock[i]); + + wblock = kzalloc(sizeof(struct wmi_block), GFP_KERNEL); + if (!wblock) + return AE_NO_MEMORY; + + wblock->handle = handle; + wblock->gblock = gblock[i]; + /* Some WMI devices, like those for nVidia hooks, have a duplicate GUID. It's not clear what we should do in this - case yet, so for now, we'll just ignore the duplicate. - Anyone who wants to add support for that device can come - up with a better workaround for the mess then. + case yet, so for now, we'll just ignore the duplicate + for device creation. */ - if (guid_already_parsed(gblock[i].guid) == true) { - wmi_gtoa(gblock[i].guid, guid_string); - pr_info("Skipping duplicate GUID %s\n", guid_string); - continue; + if (!guid_already_parsed(gblock[i].guid)) { + retval = wmi_create_device(&gblock[i], wblock, handle); + if (retval) { + wmi_free_devices(); + break; + } } - if (debug_dump_wdg) - wmi_dump_wdg(&gblock[i]); - - wblock = wmi_create_device(&gblock[i], handle); - if (IS_ERR(wblock)) { - retval = PTR_ERR(wblock); - wmi_free_devices(); - break; - } + list_add_tail(&wblock->list, &wmi_block_list); if (debug_event) { wblock->handler = wmi_notify_debug; |