summaryrefslogtreecommitdiffstats
path: root/drivers/platform
diff options
context:
space:
mode:
authorJens Axboe <jens.axboe@oracle.com>2010-03-19 08:05:10 +0100
committerJens Axboe <jens.axboe@oracle.com>2010-03-19 08:05:10 +0100
commitb4b7a4ef097f288f724420b473dbf92a89c0ab7e (patch)
tree23ad8101e3e77c32a8d1e1b95a9c1cd7f7a475b7 /drivers/platform
parente9ce335df51ff782035a15c261a3c0c9892a1767 (diff)
parenta3d3203e4bb40f253b1541e310dc0f9305be7c84 (diff)
downloadop-kernel-dev-b4b7a4ef097f288f724420b473dbf92a89c0ab7e.zip
op-kernel-dev-b4b7a4ef097f288f724420b473dbf92a89c0ab7e.tar.gz
Merge branch 'master' into for-linus
Conflicts: block/Kconfig Signed-off-by: Jens Axboe <jens.axboe@oracle.com>
Diffstat (limited to 'drivers/platform')
-rw-r--r--drivers/platform/x86/Kconfig1
-rw-r--r--drivers/platform/x86/dell-wmi.c16
-rw-r--r--drivers/platform/x86/hp-wmi.c19
-rw-r--r--drivers/platform/x86/msi-laptop.c360
-rw-r--r--drivers/platform/x86/panasonic-laptop.c15
-rw-r--r--drivers/platform/x86/sony-laptop.c91
-rw-r--r--drivers/platform/x86/thinkpad_acpi.c4
-rw-r--r--drivers/platform/x86/topstar-laptop.c13
-rw-r--r--drivers/platform/x86/toshiba_acpi.c17
9 files changed, 441 insertions, 95 deletions
diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
index cd2ee6f..e631dbe 100644
--- a/drivers/platform/x86/Kconfig
+++ b/drivers/platform/x86/Kconfig
@@ -150,6 +150,7 @@ config MSI_LAPTOP
tristate "MSI Laptop Extras"
depends on ACPI
depends on BACKLIGHT_CLASS_DEVICE
+ depends on RFKILL
---help---
This is a driver for laptops built by MSI (MICRO-STAR
INTERNATIONAL):
diff --git a/drivers/platform/x86/dell-wmi.c b/drivers/platform/x86/dell-wmi.c
index 1b1dddb..bed764e 100644
--- a/drivers/platform/x86/dell-wmi.c
+++ b/drivers/platform/x86/dell-wmi.c
@@ -142,7 +142,7 @@ static struct key_entry *dell_wmi_keymap = dell_legacy_wmi_keymap;
static struct input_dev *dell_wmi_input_dev;
-static struct key_entry *dell_wmi_get_entry_by_scancode(int code)
+static struct key_entry *dell_wmi_get_entry_by_scancode(unsigned int code)
{
struct key_entry *key;
@@ -153,7 +153,7 @@ static struct key_entry *dell_wmi_get_entry_by_scancode(int code)
return NULL;
}
-static struct key_entry *dell_wmi_get_entry_by_keycode(int keycode)
+static struct key_entry *dell_wmi_get_entry_by_keycode(unsigned int keycode)
{
struct key_entry *key;
@@ -164,8 +164,8 @@ static struct key_entry *dell_wmi_get_entry_by_keycode(int keycode)
return NULL;
}
-static int dell_wmi_getkeycode(struct input_dev *dev, int scancode,
- int *keycode)
+static int dell_wmi_getkeycode(struct input_dev *dev,
+ unsigned int scancode, unsigned int *keycode)
{
struct key_entry *key = dell_wmi_get_entry_by_scancode(scancode);
@@ -177,13 +177,11 @@ static int dell_wmi_getkeycode(struct input_dev *dev, int scancode,
return -EINVAL;
}
-static int dell_wmi_setkeycode(struct input_dev *dev, int scancode, int keycode)
+static int dell_wmi_setkeycode(struct input_dev *dev,
+ unsigned int scancode, unsigned int keycode)
{
struct key_entry *key;
- int old_keycode;
-
- if (keycode < 0 || keycode > KEY_MAX)
- return -EINVAL;
+ unsigned int old_keycode;
key = dell_wmi_get_entry_by_scancode(scancode);
if (key && key->type == KE_KEY) {
diff --git a/drivers/platform/x86/hp-wmi.c b/drivers/platform/x86/hp-wmi.c
index 3aa57da..5608636 100644
--- a/drivers/platform/x86/hp-wmi.c
+++ b/drivers/platform/x86/hp-wmi.c
@@ -57,7 +57,7 @@ enum hp_wmi_radio {
HPWMI_WWAN = 2,
};
-static int __init hp_wmi_bios_setup(struct platform_device *device);
+static int __devinit hp_wmi_bios_setup(struct platform_device *device);
static int __exit hp_wmi_bios_remove(struct platform_device *device);
static int hp_wmi_resume_handler(struct device *device);
@@ -278,7 +278,7 @@ static DEVICE_ATTR(als, S_IRUGO | S_IWUSR, show_als, set_als);
static DEVICE_ATTR(dock, S_IRUGO, show_dock, NULL);
static DEVICE_ATTR(tablet, S_IRUGO, show_tablet, NULL);
-static struct key_entry *hp_wmi_get_entry_by_scancode(int code)
+static struct key_entry *hp_wmi_get_entry_by_scancode(unsigned int code)
{
struct key_entry *key;
@@ -289,7 +289,7 @@ static struct key_entry *hp_wmi_get_entry_by_scancode(int code)
return NULL;
}
-static struct key_entry *hp_wmi_get_entry_by_keycode(int keycode)
+static struct key_entry *hp_wmi_get_entry_by_keycode(unsigned int keycode)
{
struct key_entry *key;
@@ -300,7 +300,8 @@ static struct key_entry *hp_wmi_get_entry_by_keycode(int keycode)
return NULL;
}
-static int hp_wmi_getkeycode(struct input_dev *dev, int scancode, int *keycode)
+static int hp_wmi_getkeycode(struct input_dev *dev,
+ unsigned int scancode, unsigned int *keycode)
{
struct key_entry *key = hp_wmi_get_entry_by_scancode(scancode);
@@ -312,13 +313,11 @@ static int hp_wmi_getkeycode(struct input_dev *dev, int scancode, int *keycode)
return -EINVAL;
}
-static int hp_wmi_setkeycode(struct input_dev *dev, int scancode, int keycode)
+static int hp_wmi_setkeycode(struct input_dev *dev,
+ unsigned int scancode, unsigned int keycode)
{
struct key_entry *key;
- int old_keycode;
-
- if (keycode < 0 || keycode > KEY_MAX)
- return -EINVAL;
+ unsigned int old_keycode;
key = hp_wmi_get_entry_by_scancode(scancode);
if (key && key->type == KE_KEY) {
@@ -447,7 +446,7 @@ static void cleanup_sysfs(struct platform_device *device)
device_remove_file(&device->dev, &dev_attr_tablet);
}
-static int __init hp_wmi_bios_setup(struct platform_device *device)
+static int __devinit hp_wmi_bios_setup(struct platform_device *device)
{
int err;
int wireless = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, 0);
diff --git a/drivers/platform/x86/msi-laptop.c b/drivers/platform/x86/msi-laptop.c
index 759763d..c2b05da 100644
--- a/drivers/platform/x86/msi-laptop.c
+++ b/drivers/platform/x86/msi-laptop.c
@@ -58,6 +58,7 @@
#include <linux/dmi.h>
#include <linux/backlight.h>
#include <linux/platform_device.h>
+#include <linux/rfkill.h>
#define MSI_DRIVER_VERSION "0.5"
@@ -66,6 +67,20 @@
#define MSI_EC_COMMAND_WIRELESS 0x10
#define MSI_EC_COMMAND_LCD_LEVEL 0x11
+#define MSI_STANDARD_EC_COMMAND_ADDRESS 0x2e
+#define MSI_STANDARD_EC_BLUETOOTH_MASK (1 << 0)
+#define MSI_STANDARD_EC_WEBCAM_MASK (1 << 1)
+#define MSI_STANDARD_EC_WLAN_MASK (1 << 3)
+#define MSI_STANDARD_EC_3G_MASK (1 << 4)
+
+/* For set SCM load flag to disable BIOS fn key */
+#define MSI_STANDARD_EC_SCM_LOAD_ADDRESS 0x2d
+#define MSI_STANDARD_EC_SCM_LOAD_MASK (1 << 0)
+
+static int msi_laptop_resume(struct platform_device *device);
+
+#define MSI_STANDARD_EC_DEVICES_EXISTS_ADDRESS 0x2f
+
static int force;
module_param(force, bool, 0);
MODULE_PARM_DESC(force, "Force driver load, ignore DMI data");
@@ -74,6 +89,23 @@ static int auto_brightness;
module_param(auto_brightness, int, 0);
MODULE_PARM_DESC(auto_brightness, "Enable automatic brightness control (0: disabled; 1: enabled; 2: don't touch)");
+static bool old_ec_model;
+static int wlan_s, bluetooth_s, threeg_s;
+static int threeg_exists;
+
+/* Some MSI 3G netbook only have one fn key to control Wlan/Bluetooth/3G,
+ * those netbook will load the SCM (windows app) to disable the original
+ * Wlan/Bluetooth control by BIOS when user press fn key, then control
+ * Wlan/Bluetooth/3G by SCM (software control by OS). Without SCM, user
+ * cann't on/off 3G module on those 3G netbook.
+ * On Linux, msi-laptop driver will do the same thing to disable the
+ * original BIOS control, then might need use HAL or other userland
+ * application to do the software control that simulate with SCM.
+ * e.g. MSI N034 netbook
+ */
+static bool load_scm_model;
+static struct rfkill *rfk_wlan, *rfk_bluetooth, *rfk_threeg;
+
/* Hardware access */
static int set_lcd_level(int level)
@@ -130,6 +162,35 @@ static int set_auto_brightness(int enable)
return ec_transaction(MSI_EC_COMMAND_LCD_LEVEL, wdata, 2, NULL, 0, 1);
}
+static ssize_t set_device_state(const char *buf, size_t count, u8 mask)
+{
+ int status;
+ u8 wdata = 0, rdata;
+ int result;
+
+ if (sscanf(buf, "%i", &status) != 1 || (status < 0 || status > 1))
+ return -EINVAL;
+
+ /* read current device state */
+ result = ec_read(MSI_STANDARD_EC_COMMAND_ADDRESS, &rdata);
+ if (result < 0)
+ return -EINVAL;
+
+ if (!!(rdata & mask) != status) {
+ /* reverse device bit */
+ if (rdata & mask)
+ wdata = rdata & ~mask;
+ else
+ wdata = rdata | mask;
+
+ result = ec_write(MSI_STANDARD_EC_COMMAND_ADDRESS, wdata);
+ if (result < 0)
+ return -EINVAL;
+ }
+
+ return count;
+}
+
static int get_wireless_state(int *wlan, int *bluetooth)
{
u8 wdata = 0, rdata;
@@ -148,6 +209,38 @@ static int get_wireless_state(int *wlan, int *bluetooth)
return 0;
}
+static int get_wireless_state_ec_standard(void)
+{
+ u8 rdata;
+ int result;
+
+ result = ec_read(MSI_STANDARD_EC_COMMAND_ADDRESS, &rdata);
+ if (result < 0)
+ return -1;
+
+ wlan_s = !!(rdata & MSI_STANDARD_EC_WLAN_MASK);
+
+ bluetooth_s = !!(rdata & MSI_STANDARD_EC_BLUETOOTH_MASK);
+
+ threeg_s = !!(rdata & MSI_STANDARD_EC_3G_MASK);
+
+ return 0;
+}
+
+static int get_threeg_exists(void)
+{
+ u8 rdata;
+ int result;
+
+ result = ec_read(MSI_STANDARD_EC_DEVICES_EXISTS_ADDRESS, &rdata);
+ if (result < 0)
+ return -1;
+
+ threeg_exists = !!(rdata & MSI_STANDARD_EC_3G_MASK);
+
+ return 0;
+}
+
/* Backlight device stuff */
static int bl_get_brightness(struct backlight_device *b)
@@ -176,26 +269,71 @@ static ssize_t show_wlan(struct device *dev,
int ret, enabled;
- ret = get_wireless_state(&enabled, NULL);
+ if (old_ec_model) {
+ ret = get_wireless_state(&enabled, NULL);
+ } else {
+ ret = get_wireless_state_ec_standard();
+ enabled = wlan_s;
+ }
if (ret < 0)
return ret;
return sprintf(buf, "%i\n", enabled);
}
+static ssize_t store_wlan(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ return set_device_state(buf, count, MSI_STANDARD_EC_WLAN_MASK);
+}
+
static ssize_t show_bluetooth(struct device *dev,
struct device_attribute *attr, char *buf)
{
int ret, enabled;
- ret = get_wireless_state(NULL, &enabled);
+ if (old_ec_model) {
+ ret = get_wireless_state(NULL, &enabled);
+ } else {
+ ret = get_wireless_state_ec_standard();
+ enabled = bluetooth_s;
+ }
if (ret < 0)
return ret;
return sprintf(buf, "%i\n", enabled);
}
+static ssize_t store_bluetooth(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ return set_device_state(buf, count, MSI_STANDARD_EC_BLUETOOTH_MASK);
+}
+
+static ssize_t show_threeg(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+
+ int ret;
+
+ /* old msi ec not support 3G */
+ if (old_ec_model)
+ return -1;
+
+ ret = get_wireless_state_ec_standard();
+ if (ret < 0)
+ return ret;
+
+ return sprintf(buf, "%i\n", threeg_s);
+}
+
+static ssize_t store_threeg(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ return set_device_state(buf, count, MSI_STANDARD_EC_3G_MASK);
+}
+
static ssize_t show_lcd_level(struct device *dev,
struct device_attribute *attr, char *buf)
{
@@ -258,6 +396,7 @@ static DEVICE_ATTR(lcd_level, 0644, show_lcd_level, store_lcd_level);
static DEVICE_ATTR(auto_brightness, 0644, show_auto_brightness, store_auto_brightness);
static DEVICE_ATTR(bluetooth, 0444, show_bluetooth, NULL);
static DEVICE_ATTR(wlan, 0444, show_wlan, NULL);
+static DEVICE_ATTR(threeg, 0444, show_threeg, NULL);
static struct attribute *msipf_attributes[] = {
&dev_attr_lcd_level.attr,
@@ -275,7 +414,8 @@ static struct platform_driver msipf_driver = {
.driver = {
.name = "msi-laptop-pf",
.owner = THIS_MODULE,
- }
+ },
+ .resume = msi_laptop_resume,
};
static struct platform_device *msipf_device;
@@ -332,6 +472,192 @@ static struct dmi_system_id __initdata msi_dmi_table[] = {
{ }
};
+static struct dmi_system_id __initdata msi_load_scm_models_dmi_table[] = {
+ {
+ .ident = "MSI N034",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR,
+ "MICRO-STAR INTERNATIONAL CO., LTD"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "MS-N034"),
+ DMI_MATCH(DMI_CHASSIS_VENDOR,
+ "MICRO-STAR INTERNATIONAL CO., LTD")
+ },
+ .callback = dmi_check_cb
+ },
+ { }
+};
+
+static int rfkill_bluetooth_set(void *data, bool blocked)
+{
+ /* Do something with blocked...*/
+ /*
+ * blocked == false is on
+ * blocked == true is off
+ */
+ if (blocked)
+ set_device_state("0", 0, MSI_STANDARD_EC_BLUETOOTH_MASK);
+ else
+ set_device_state("1", 0, MSI_STANDARD_EC_BLUETOOTH_MASK);
+
+ return 0;
+}
+
+static int rfkill_wlan_set(void *data, bool blocked)
+{
+ if (blocked)
+ set_device_state("0", 0, MSI_STANDARD_EC_WLAN_MASK);
+ else
+ set_device_state("1", 0, MSI_STANDARD_EC_WLAN_MASK);
+
+ return 0;
+}
+
+static int rfkill_threeg_set(void *data, bool blocked)
+{
+ if (blocked)
+ set_device_state("0", 0, MSI_STANDARD_EC_3G_MASK);
+ else
+ set_device_state("1", 0, MSI_STANDARD_EC_3G_MASK);
+
+ return 0;
+}
+
+static struct rfkill_ops rfkill_bluetooth_ops = {
+ .set_block = rfkill_bluetooth_set
+};
+
+static struct rfkill_ops rfkill_wlan_ops = {
+ .set_block = rfkill_wlan_set
+};
+
+static struct rfkill_ops rfkill_threeg_ops = {
+ .set_block = rfkill_threeg_set
+};
+
+static void rfkill_cleanup(void)
+{
+ if (rfk_bluetooth) {
+ rfkill_unregister(rfk_bluetooth);
+ rfkill_destroy(rfk_bluetooth);
+ }
+
+ if (rfk_threeg) {
+ rfkill_unregister(rfk_threeg);
+ rfkill_destroy(rfk_threeg);
+ }
+
+ if (rfk_wlan) {
+ rfkill_unregister(rfk_wlan);
+ rfkill_destroy(rfk_wlan);
+ }
+}
+
+static int rfkill_init(struct platform_device *sdev)
+{
+ /* add rfkill */
+ int retval;
+
+ rfk_bluetooth = rfkill_alloc("msi-bluetooth", &sdev->dev,
+ RFKILL_TYPE_BLUETOOTH,
+ &rfkill_bluetooth_ops, NULL);
+ if (!rfk_bluetooth) {
+ retval = -ENOMEM;
+ goto err_bluetooth;
+ }
+ retval = rfkill_register(rfk_bluetooth);
+ if (retval)
+ goto err_bluetooth;
+
+ rfk_wlan = rfkill_alloc("msi-wlan", &sdev->dev, RFKILL_TYPE_WLAN,
+ &rfkill_wlan_ops, NULL);
+ if (!rfk_wlan) {
+ retval = -ENOMEM;
+ goto err_wlan;
+ }
+ retval = rfkill_register(rfk_wlan);
+ if (retval)
+ goto err_wlan;
+
+ if (threeg_exists) {
+ rfk_threeg = rfkill_alloc("msi-threeg", &sdev->dev,
+ RFKILL_TYPE_WWAN, &rfkill_threeg_ops, NULL);
+ if (!rfk_threeg) {
+ retval = -ENOMEM;
+ goto err_threeg;
+ }
+ retval = rfkill_register(rfk_threeg);
+ if (retval)
+ goto err_threeg;
+ }
+
+ return 0;
+
+err_threeg:
+ rfkill_destroy(rfk_threeg);
+ if (rfk_wlan)
+ rfkill_unregister(rfk_wlan);
+err_wlan:
+ rfkill_destroy(rfk_wlan);
+ if (rfk_bluetooth)
+ rfkill_unregister(rfk_bluetooth);
+err_bluetooth:
+ rfkill_destroy(rfk_bluetooth);
+
+ return retval;
+}
+
+static int msi_laptop_resume(struct platform_device *device)
+{
+ u8 data;
+ int result;
+
+ if (!load_scm_model)
+ return 0;
+
+ /* set load SCM to disable hardware control by fn key */
+ result = ec_read(MSI_STANDARD_EC_SCM_LOAD_ADDRESS, &data);
+ if (result < 0)
+ return result;
+
+ result = ec_write(MSI_STANDARD_EC_SCM_LOAD_ADDRESS,
+ data | MSI_STANDARD_EC_SCM_LOAD_MASK);
+ if (result < 0)
+ return result;
+
+ return 0;
+}
+
+static int load_scm_model_init(struct platform_device *sdev)
+{
+ u8 data;
+ int result;
+
+ /* allow userland write sysfs file */
+ dev_attr_bluetooth.store = store_bluetooth;
+ dev_attr_wlan.store = store_wlan;
+ dev_attr_threeg.store = store_threeg;
+ dev_attr_bluetooth.attr.mode |= S_IWUSR;
+ dev_attr_wlan.attr.mode |= S_IWUSR;
+ dev_attr_threeg.attr.mode |= S_IWUSR;
+
+ /* disable hardware control by fn key */
+ result = ec_read(MSI_STANDARD_EC_SCM_LOAD_ADDRESS, &data);
+ if (result < 0)
+ return result;
+
+ result = ec_write(MSI_STANDARD_EC_SCM_LOAD_ADDRESS,
+ data | MSI_STANDARD_EC_SCM_LOAD_MASK);
+ if (result < 0)
+ return result;
+
+ /* initial rfkill */
+ result = rfkill_init(sdev);
+ if (result < 0)
+ return result;
+
+ return 0;
+}
+
static int __init msi_init(void)
{
int ret;
@@ -339,8 +665,14 @@ static int __init msi_init(void)
if (acpi_disabled)
return -ENODEV;
- if (!force && !dmi_check_system(msi_dmi_table))
- return -ENODEV;
+ if (force || dmi_check_system(msi_dmi_table))
+ old_ec_model = 1;
+
+ if (!old_ec_model)
+ get_threeg_exists();
+
+ if (!old_ec_model && dmi_check_system(msi_load_scm_models_dmi_table))
+ load_scm_model = 1;
if (auto_brightness < 0 || auto_brightness > 2)
return -EINVAL;
@@ -374,10 +706,23 @@ static int __init msi_init(void)
if (ret)
goto fail_platform_device1;
+ if (load_scm_model && (load_scm_model_init(msipf_device) < 0)) {
+ ret = -EINVAL;
+ goto fail_platform_device1;
+ }
+
ret = sysfs_create_group(&msipf_device->dev.kobj, &msipf_attribute_group);
if (ret)
goto fail_platform_device2;
+ if (!old_ec_model) {
+ if (threeg_exists)
+ ret = device_create_file(&msipf_device->dev,
+ &dev_attr_threeg);
+ if (ret)
+ goto fail_platform_device2;
+ }
+
/* Disable automatic brightness control by default because
* this module was probably loaded to do brightness control in
* software. */
@@ -412,10 +757,14 @@ static void __exit msi_cleanup(void)
{
sysfs_remove_group(&msipf_device->dev.kobj, &msipf_attribute_group);
+ if (!old_ec_model && threeg_exists)
+ device_remove_file(&msipf_device->dev, &dev_attr_threeg);
platform_device_unregister(msipf_device);
platform_driver_unregister(&msipf_driver);
backlight_device_unregister(msibl_device);
+ rfkill_cleanup();
+
/* Enable automatic brightness control again */
if (auto_brightness != 2)
set_auto_brightness(1);
@@ -435,3 +784,4 @@ MODULE_ALIAS("dmi:*:svnMICRO-STARINT'LCO.,LTD:pnMS-1013:pvr0131*:cvnMICRO-STARIN
MODULE_ALIAS("dmi:*:svnMicro-StarInternational:pnMS-1058:pvr0581:rvnMSI:rnMS-1058:*:ct10:*");
MODULE_ALIAS("dmi:*:svnMicro-StarInternational:pnMS-1412:*:rvnMSI:rnMS-1412:*:cvnMICRO-STARINT'LCO.,LTD:ct10:*");
MODULE_ALIAS("dmi:*:svnNOTEBOOK:pnSAM2000:pvr0131*:cvnMICRO-STARINT'LCO.,LTD:ct10:*");
+MODULE_ALIAS("dmi:*:svnMICRO-STARINTERNATIONAL*:pnMS-N034:*");
diff --git a/drivers/platform/x86/panasonic-laptop.c b/drivers/platform/x86/panasonic-laptop.c
index fe7cf01..c9fc479 100644
--- a/drivers/platform/x86/panasonic-laptop.c
+++ b/drivers/platform/x86/panasonic-laptop.c
@@ -200,7 +200,7 @@ static struct acpi_driver acpi_pcc_driver = {
};
#define KEYMAP_SIZE 11
-static const int initial_keymap[KEYMAP_SIZE] = {
+static const unsigned int initial_keymap[KEYMAP_SIZE] = {
/* 0 */ KEY_RESERVED,
/* 1 */ KEY_BRIGHTNESSDOWN,
/* 2 */ KEY_BRIGHTNESSUP,
@@ -222,7 +222,7 @@ struct pcc_acpi {
struct acpi_device *device;
struct input_dev *input_dev;
struct backlight_device *backlight;
- int keymap[KEYMAP_SIZE];
+ unsigned int keymap[KEYMAP_SIZE];
};
struct pcc_keyinput {
@@ -445,7 +445,8 @@ static struct attribute_group pcc_attr_group = {
/* hotkey input device driver */
-static int pcc_getkeycode(struct input_dev *dev, int scancode, int *keycode)
+static int pcc_getkeycode(struct input_dev *dev,
+ unsigned int scancode, unsigned int *keycode)
{
struct pcc_acpi *pcc = input_get_drvdata(dev);
@@ -457,7 +458,7 @@ static int pcc_getkeycode(struct input_dev *dev, int scancode, int *keycode)
return 0;
}
-static int keymap_get_by_keycode(struct pcc_acpi *pcc, int keycode)
+static int keymap_get_by_keycode(struct pcc_acpi *pcc, unsigned int keycode)
{
int i;
@@ -469,7 +470,8 @@ static int keymap_get_by_keycode(struct pcc_acpi *pcc, int keycode)
return 0;
}
-static int pcc_setkeycode(struct input_dev *dev, int scancode, int keycode)
+static int pcc_setkeycode(struct input_dev *dev,
+ unsigned int scancode, unsigned int keycode)
{
struct pcc_acpi *pcc = input_get_drvdata(dev);
int oldkeycode;
@@ -477,9 +479,6 @@ static int pcc_setkeycode(struct input_dev *dev, int scancode, int keycode)
if (scancode >= ARRAY_SIZE(pcc->keymap))
return -EINVAL;
- if (keycode < 0 || keycode > KEY_MAX)
- return -EINVAL;
-
oldkeycode = pcc->keymap[scancode];
pcc->keymap[scancode] = keycode;
diff --git a/drivers/platform/x86/sony-laptop.c b/drivers/platform/x86/sony-laptop.c
index 3f71a60..5a3d851 100644
--- a/drivers/platform/x86/sony-laptop.c
+++ b/drivers/platform/x86/sony-laptop.c
@@ -145,7 +145,7 @@ struct sony_laptop_input_s {
struct input_dev *key_dev;
struct kfifo fifo;
spinlock_t fifo_lock;
- struct workqueue_struct *wq;
+ struct timer_list release_key_timer;
};
static struct sony_laptop_input_s sony_laptop_input = {
@@ -299,20 +299,26 @@ static int sony_laptop_input_keycode_map[] = {
};
/* release buttons after a short delay if pressed */
-static void do_sony_laptop_release_key(struct work_struct *work)
+static void do_sony_laptop_release_key(unsigned long unused)
{
struct sony_laptop_keypress kp;
+ unsigned long flags;
+
+ spin_lock_irqsave(&sony_laptop_input.fifo_lock, flags);
- while (kfifo_out_locked(&sony_laptop_input.fifo, (unsigned char *)&kp,
- sizeof(kp), &sony_laptop_input.fifo_lock)
- == sizeof(kp)) {
- msleep(10);
+ if (kfifo_out(&sony_laptop_input.fifo,
+ (unsigned char *)&kp, sizeof(kp)) == sizeof(kp)) {
input_report_key(kp.dev, kp.key, 0);
input_sync(kp.dev);
}
+
+ /* If there is something in the fifo schedule next release. */
+ if (kfifo_len(&sony_laptop_input.fifo) != 0)
+ mod_timer(&sony_laptop_input.release_key_timer,
+ jiffies + msecs_to_jiffies(10));
+
+ spin_unlock_irqrestore(&sony_laptop_input.fifo_lock, flags);
}
-static DECLARE_WORK(sony_laptop_release_key_work,
- do_sony_laptop_release_key);
/* forward event to the input subsystem */
static void sony_laptop_report_input_event(u8 event)
@@ -366,13 +372,13 @@ static void sony_laptop_report_input_event(u8 event)
/* we emit the scancode so we can always remap the key */
input_event(kp.dev, EV_MSC, MSC_SCAN, event);
input_sync(kp.dev);
- kfifo_in_locked(&sony_laptop_input.fifo,
- (unsigned char *)&kp, sizeof(kp),
- &sony_laptop_input.fifo_lock);
- if (!work_pending(&sony_laptop_release_key_work))
- queue_work(sony_laptop_input.wq,
- &sony_laptop_release_key_work);
+ /* schedule key release */
+ kfifo_in_locked(&sony_laptop_input.fifo,
+ (unsigned char *)&kp, sizeof(kp),
+ &sony_laptop_input.fifo_lock);
+ mod_timer(&sony_laptop_input.release_key_timer,
+ jiffies + msecs_to_jiffies(10));
} else
dprintk("unknown input event %.2x\n", event);
}
@@ -390,27 +396,21 @@ static int sony_laptop_setup_input(struct acpi_device *acpi_device)
/* kfifo */
spin_lock_init(&sony_laptop_input.fifo_lock);
- error =
- kfifo_alloc(&sony_laptop_input.fifo, SONY_LAPTOP_BUF_SIZE, GFP_KERNEL);
+ error = kfifo_alloc(&sony_laptop_input.fifo,
+ SONY_LAPTOP_BUF_SIZE, GFP_KERNEL);
if (error) {
printk(KERN_ERR DRV_PFX "kfifo_alloc failed\n");
goto err_dec_users;
}
- /* init workqueue */
- sony_laptop_input.wq = create_singlethread_workqueue("sony-laptop");
- if (!sony_laptop_input.wq) {
- printk(KERN_ERR DRV_PFX
- "Unable to create workqueue.\n");
- error = -ENXIO;
- goto err_free_kfifo;
- }
+ setup_timer(&sony_laptop_input.release_key_timer,
+ do_sony_laptop_release_key, 0);
/* input keys */
key_dev = input_allocate_device();
if (!key_dev) {
error = -ENOMEM;
- goto err_destroy_wq;
+ goto err_free_kfifo;
}
key_dev->name = "Sony Vaio Keys";
@@ -419,18 +419,15 @@ static int sony_laptop_setup_input(struct acpi_device *acpi_device)
key_dev->dev.parent = &acpi_device->dev;
/* Initialize the Input Drivers: special keys */
- set_bit(EV_KEY, key_dev->evbit);
- set_bit(EV_MSC, key_dev->evbit);
- set_bit(MSC_SCAN, key_dev->mscbit);
+ input_set_capability(key_dev, EV_MSC, MSC_SCAN);
+
+ __set_bit(EV_KEY, key_dev->evbit);
key_dev->keycodesize = sizeof(sony_laptop_input_keycode_map[0]);
key_dev->keycodemax = ARRAY_SIZE(sony_laptop_input_keycode_map);
key_dev->keycode = &sony_laptop_input_keycode_map;
- for (i = 0; i < ARRAY_SIZE(sony_laptop_input_keycode_map); i++) {
- if (sony_laptop_input_keycode_map[i] != KEY_RESERVED) {
- set_bit(sony_laptop_input_keycode_map[i],
- key_dev->keybit);
- }
- }
+ for (i = 0; i < ARRAY_SIZE(sony_laptop_input_keycode_map); i++)
+ __set_bit(sony_laptop_input_keycode_map[i], key_dev->keybit);
+ __clear_bit(KEY_RESERVED, key_dev->keybit);
error = input_register_device(key_dev);
if (error)
@@ -450,9 +447,8 @@ static int sony_laptop_setup_input(struct acpi_device *acpi_device)
jog_dev->id.vendor = PCI_VENDOR_ID_SONY;
key_dev->dev.parent = &acpi_device->dev;
- jog_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL);
- jog_dev->keybit[BIT_WORD(BTN_MOUSE)] = BIT_MASK(BTN_MIDDLE);
- jog_dev->relbit[0] = BIT_MASK(REL_WHEEL);
+ input_set_capability(jog_dev, EV_KEY, BTN_MIDDLE);
+ input_set_capability(jog_dev, EV_REL, REL_WHEEL);
error = input_register_device(jog_dev);
if (error)
@@ -473,9 +469,6 @@ err_unregister_keydev:
err_free_keydev:
input_free_device(key_dev);
-err_destroy_wq:
- destroy_workqueue(sony_laptop_input.wq);
-
err_free_kfifo:
kfifo_free(&sony_laptop_input.fifo);
@@ -486,12 +479,23 @@ err_dec_users:
static void sony_laptop_remove_input(void)
{
- /* cleanup only after the last user has gone */
+ struct sony_laptop_keypress kp = { NULL };
+
+ /* Cleanup only after the last user has gone */
if (!atomic_dec_and_test(&sony_laptop_input.users))
return;
- /* flush workqueue first */
- flush_workqueue(sony_laptop_input.wq);
+ del_timer_sync(&sony_laptop_input.release_key_timer);
+
+ /*
+ * Generate key-up events for remaining keys. Note that we don't
+ * need locking since nobody is adding new events to the kfifo.
+ */
+ while (kfifo_out(&sony_laptop_input.fifo,
+ (unsigned char *)&kp, sizeof(kp)) == sizeof(kp)) {
+ input_report_key(kp.dev, kp.key, 0);
+ input_sync(kp.dev);
+ }
/* destroy input devs */
input_unregister_device(sony_laptop_input.key_dev);
@@ -502,7 +506,6 @@ static void sony_laptop_remove_input(void)
sony_laptop_input.jog_dev = NULL;
}
- destroy_workqueue(sony_laptop_input.wq);
kfifo_free(&sony_laptop_input.fifo);
}
diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c
index e7b0c3b..c64e352 100644
--- a/drivers/platform/x86/thinkpad_acpi.c
+++ b/drivers/platform/x86/thinkpad_acpi.c
@@ -1668,7 +1668,7 @@ static void tpacpi_remove_driver_attributes(struct device_driver *drv)
* Table of recommended minimum BIOS versions
*
* Reasons for listing:
- * 1. Stable BIOS, listed because the unknown ammount of
+ * 1. Stable BIOS, listed because the unknown amount of
* bugs and bad ACPI behaviour on older versions
*
* 2. BIOS or EC fw with known bugs that trigger on Linux
@@ -7108,7 +7108,7 @@ static struct ibm_struct volume_driver_data = {
*
* Fan speed changes of any sort (including those caused by the
* disengaged mode) are usually done slowly by the firmware as the
- * maximum ammount of fan duty cycle change per second seems to be
+ * maximum amount of fan duty cycle change per second seems to be
* limited.
*
* Reading is not available if GFAN exists.
diff --git a/drivers/platform/x86/topstar-laptop.c b/drivers/platform/x86/topstar-laptop.c
index 02f3d4e..4d6516f 100644
--- a/drivers/platform/x86/topstar-laptop.c
+++ b/drivers/platform/x86/topstar-laptop.c
@@ -46,7 +46,7 @@ static struct tps_key_entry topstar_keymap[] = {
{ }
};
-static struct tps_key_entry *tps_get_key_by_scancode(int code)
+static struct tps_key_entry *tps_get_key_by_scancode(unsigned int code)
{
struct tps_key_entry *key;
@@ -57,7 +57,7 @@ static struct tps_key_entry *tps_get_key_by_scancode(int code)
return NULL;
}
-static struct tps_key_entry *tps_get_key_by_keycode(int code)
+static struct tps_key_entry *tps_get_key_by_keycode(unsigned int code)
{
struct tps_key_entry *key;
@@ -126,7 +126,8 @@ static int acpi_topstar_fncx_switch(struct acpi_device *device, bool state)
return 0;
}
-static int topstar_getkeycode(struct input_dev *dev, int scancode, int *keycode)
+static int topstar_getkeycode(struct input_dev *dev,
+ unsigned int scancode, unsigned int *keycode)
{
struct tps_key_entry *key = tps_get_key_by_scancode(scancode);
@@ -137,14 +138,12 @@ static int topstar_getkeycode(struct input_dev *dev, int scancode, int *keycode)
return 0;
}
-static int topstar_setkeycode(struct input_dev *dev, int scancode, int keycode)
+static int topstar_setkeycode(struct input_dev *dev,
+ unsigned int scancode, unsigned int keycode)
{
struct tps_key_entry *key;
int old_keycode;
- if (keycode < 0 || keycode > KEY_MAX)
- return -EINVAL;
-
key = tps_get_key_by_scancode(scancode);
if (!key)
diff --git a/drivers/platform/x86/toshiba_acpi.c b/drivers/platform/x86/toshiba_acpi.c
index 405b969..789240d 100644
--- a/drivers/platform/x86/toshiba_acpi.c
+++ b/drivers/platform/x86/toshiba_acpi.c
@@ -745,7 +745,7 @@ static struct backlight_ops toshiba_backlight_data = {
.update_status = set_lcd_status,
};
-static struct key_entry *toshiba_acpi_get_entry_by_scancode(int code)
+static struct key_entry *toshiba_acpi_get_entry_by_scancode(unsigned int code)
{
struct key_entry *key;
@@ -756,7 +756,7 @@ static struct key_entry *toshiba_acpi_get_entry_by_scancode(int code)
return NULL;
}
-static struct key_entry *toshiba_acpi_get_entry_by_keycode(int code)
+static struct key_entry *toshiba_acpi_get_entry_by_keycode(unsigned int code)
{
struct key_entry *key;
@@ -767,8 +767,8 @@ static struct key_entry *toshiba_acpi_get_entry_by_keycode(int code)
return NULL;
}
-static int toshiba_acpi_getkeycode(struct input_dev *dev, int scancode,
- int *keycode)
+static int toshiba_acpi_getkeycode(struct input_dev *dev,
+ unsigned int scancode, unsigned int *keycode)
{
struct key_entry *key = toshiba_acpi_get_entry_by_scancode(scancode);
@@ -780,14 +780,11 @@ static int toshiba_acpi_getkeycode(struct input_dev *dev, int scancode,
return -EINVAL;
}
-static int toshiba_acpi_setkeycode(struct input_dev *dev, int scancode,
- int keycode)
+static int toshiba_acpi_setkeycode(struct input_dev *dev,
+ unsigned int scancode, unsigned int keycode)
{
struct key_entry *key;
- int old_keycode;
-
- if (keycode < 0 || keycode > KEY_MAX)
- return -EINVAL;
+ unsigned int old_keycode;
key = toshiba_acpi_get_entry_by_scancode(scancode);
if (key && key->type == KE_KEY) {
OpenPOWER on IntegriCloud