summaryrefslogtreecommitdiffstats
path: root/linux-2.6-input-fix-toshiba-hotkeys.patch
diff options
context:
space:
mode:
Diffstat (limited to 'linux-2.6-input-fix-toshiba-hotkeys.patch')
-rw-r--r--linux-2.6-input-fix-toshiba-hotkeys.patch278
1 files changed, 278 insertions, 0 deletions
diff --git a/linux-2.6-input-fix-toshiba-hotkeys.patch b/linux-2.6-input-fix-toshiba-hotkeys.patch
new file mode 100644
index 0000000..74558e6
--- /dev/null
+++ b/linux-2.6-input-fix-toshiba-hotkeys.patch
@@ -0,0 +1,278 @@
+commit 61a2aa30877a6e2be1d3fb3a71385e1f741819d7
+Author: Matthew Garrett <mjg@redhat.com>
+Date: Fri Mar 6 00:25:45 2009 +0000
+
+ toshiba-acpi: Add support for hotkey notifications
+
+ Calling the ENAB method on Toshiba laptops results in notifications being
+ sent when laptop hotkeys are pressed. This patch simply calls that method
+ and sets up an input device if it's successful.
+
+ Signed-off-by: Matthew Garrett <mjg@redhat.com>
+
+diff --git a/drivers/platform/x86/toshiba_acpi.c b/drivers/platform/x86/toshiba_acpi.c
+index 40e60fc..604f9fa 100644
+--- a/drivers/platform/x86/toshiba_acpi.c
++++ b/drivers/platform/x86/toshiba_acpi.c
+@@ -46,6 +46,7 @@
+ #include <linux/platform_device.h>
+ #include <linux/rfkill.h>
+ #include <linux/input-polldev.h>
++#include <linux/input.h>
+
+ #include <asm/uaccess.h>
+
+@@ -62,9 +63,10 @@ MODULE_LICENSE("GPL");
+
+ /* Toshiba ACPI method paths */
+ #define METHOD_LCD_BRIGHTNESS "\\_SB_.PCI0.VGA_.LCD_._BCM"
+-#define METHOD_HCI_1 "\\_SB_.VALD.GHCI"
+-#define METHOD_HCI_2 "\\_SB_.VALZ.GHCI"
++#define TOSH_INTERFACE_1 "\\_SB_.VALD"
++#define TOSH_INTERFACE_2 "\\_SB_.VALZ"
+ #define METHOD_VIDEO_OUT "\\_SB_.VALX.DSSX"
++#define GHCI_METHOD ".GHCI"
+
+ /* Toshiba HCI interface definitions
+ *
+@@ -116,6 +118,36 @@ static const struct acpi_device_id toshiba_device_ids[] = {
+ };
+ MODULE_DEVICE_TABLE(acpi, toshiba_device_ids);
+
++struct key_entry {
++ char type;
++ u16 code;
++ u16 keycode;
++};
++
++enum {KE_KEY, KE_END};
++
++static struct key_entry toshiba_acpi_keymap[] = {
++ {KE_KEY, 0x101, KEY_MUTE},
++ {KE_KEY, 0x13b, KEY_COFFEE},
++ {KE_KEY, 0x13c, KEY_BATTERY},
++ {KE_KEY, 0x13d, KEY_SLEEP},
++ {KE_KEY, 0x13e, KEY_SUSPEND},
++ {KE_KEY, 0x13f, KEY_SWITCHVIDEOMODE},
++ {KE_KEY, 0x140, KEY_BRIGHTNESSDOWN},
++ {KE_KEY, 0x141, KEY_BRIGHTNESSUP},
++ {KE_KEY, 0x142, KEY_WLAN},
++ {KE_KEY, 0x143, KEY_PROG1},
++ {KE_KEY, 0xb05, KEY_PROG2},
++ {KE_KEY, 0xb06, KEY_WWW},
++ {KE_KEY, 0xb07, KEY_MAIL},
++ {KE_KEY, 0xb30, KEY_STOP},
++ {KE_KEY, 0xb31, KEY_PREVIOUSSONG},
++ {KE_KEY, 0xb32, KEY_NEXTSONG},
++ {KE_KEY, 0xb33, KEY_PLAYPAUSE},
++ {KE_KEY, 0xb5a, KEY_MEDIA},
++ {KE_END, 0, 0},
++};
++
+ /* utility
+ */
+
+@@ -252,6 +284,8 @@ struct toshiba_acpi_dev {
+ struct platform_device *p_dev;
+ struct rfkill *rfk_dev;
+ struct input_polled_dev *poll_dev;
++ struct input_dev *hotkey_dev;
++ acpi_handle handle;
+
+ const char *bt_name;
+ const char *rfk_name;
+@@ -702,6 +736,154 @@ static struct backlight_ops toshiba_backlight_data = {
+ .update_status = set_lcd_status,
+ };
+
++static struct key_entry *toshiba_acpi_get_entry_by_scancode(int code)
++{
++ struct key_entry *key;
++
++ for (key = toshiba_acpi_keymap; key->type != KE_END; key++)
++ if (code == key->code)
++ return key;
++
++ return NULL;
++}
++
++static struct key_entry *toshiba_acpi_get_entry_by_keycode(int code)
++{
++ struct key_entry *key;
++
++ for (key = toshiba_acpi_keymap; key->type != KE_END; key++)
++ if (code == key->keycode && key->type == KE_KEY)
++ return key;
++
++ return NULL;
++}
++
++static int toshiba_acpi_getkeycode(struct input_dev *dev, int scancode,
++ int *keycode)
++{
++ struct key_entry *key = toshiba_acpi_get_entry_by_scancode(scancode);
++
++ if (key && key->type == KE_KEY) {
++ *keycode = key->keycode;
++ return 0;
++ }
++
++ return -EINVAL;
++}
++
++static int toshiba_acpi_setkeycode(struct input_dev *dev, int scancode,
++ int keycode)
++{
++ struct key_entry *key;
++ int old_keycode;
++
++ if (keycode < 0 || keycode > KEY_MAX)
++ return -EINVAL;
++
++ key = toshiba_acpi_get_entry_by_scancode(scancode);
++ if (key && key->type == KE_KEY) {
++ old_keycode = key->keycode;
++ key->keycode = keycode;
++ set_bit(keycode, dev->keybit);
++ if (!toshiba_acpi_get_entry_by_keycode(old_keycode))
++ clear_bit(old_keycode, dev->keybit);
++ return 0;
++ }
++
++ return -EINVAL;
++}
++
++static void toshiba_acpi_notify(acpi_handle handle, u32 event, void *data)
++{
++ u32 hci_result, value;
++ struct key_entry *key;
++
++ if (event != 0x80)
++ return;
++ do {
++ hci_read1(HCI_SYSTEM_EVENT, &value, &hci_result);
++ if (hci_result == HCI_SUCCESS) {
++ if (value == 0x100)
++ continue;
++ else if (value & 0x80) {
++ key = toshiba_acpi_get_entry_by_scancode
++ (value & ~0x80);
++ if (!key) {
++ printk(MY_INFO "Unknown key %x\n",
++ value & ~0x80);
++ continue;
++ }
++ input_report_key(toshiba_acpi.hotkey_dev,
++ key->keycode, 1);
++ input_sync(toshiba_acpi.hotkey_dev);
++ input_report_key(toshiba_acpi.hotkey_dev,
++ key->keycode, 0);
++ input_sync(toshiba_acpi.hotkey_dev);
++ }
++ } else if (hci_result == HCI_NOT_SUPPORTED) {
++ /* This is a workaround for an unresolved issue on
++ * some machines where system events sporadically
++ * become disabled. */
++ hci_write1(HCI_SYSTEM_EVENT, 1, &hci_result);
++ printk(MY_NOTICE "Re-enabled hotkeys\n");
++ }
++ } while (hci_result != HCI_EMPTY);
++}
++
++static int toshiba_acpi_setup_keyboard(char *device)
++{
++ acpi_status status;
++ acpi_handle handle;
++ int result;
++ const struct key_entry *key;
++
++ status = acpi_get_handle(NULL, device, &handle);
++ if (ACPI_FAILURE(status)) {
++ printk(MY_INFO "Unable to get notification device\n");
++ return -ENODEV;
++ }
++
++ toshiba_acpi.handle = handle;
++
++ status = acpi_evaluate_object(handle, "ENAB", NULL, NULL);
++ if (ACPI_FAILURE(status)) {
++ printk(MY_INFO "Unable to enable hotkeys\n");
++ return -ENODEV;
++ }
++
++ status = acpi_install_notify_handler (handle, ACPI_DEVICE_NOTIFY,
++ toshiba_acpi_notify, NULL);
++ if (ACPI_FAILURE(status)) {
++ printk(MY_INFO "Unable to install hotkey notification\n");
++ return -ENODEV;
++ }
++
++ toshiba_acpi.hotkey_dev = input_allocate_device();
++ if (!toshiba_acpi.hotkey_dev) {
++ printk(MY_INFO "Unable to register input device\n");
++ return -ENOMEM;
++ }
++
++ toshiba_acpi.hotkey_dev->name = "Toshiba input device";
++ toshiba_acpi.hotkey_dev->phys = device;
++ toshiba_acpi.hotkey_dev->id.bustype = BUS_HOST;
++ toshiba_acpi.hotkey_dev->getkeycode = toshiba_acpi_getkeycode;
++ toshiba_acpi.hotkey_dev->setkeycode = toshiba_acpi_setkeycode;
++
++ for (key = toshiba_acpi_keymap; key->type != KE_END; key++) {
++ set_bit(EV_KEY, toshiba_acpi.hotkey_dev->evbit);
++ set_bit(key->keycode, toshiba_acpi.hotkey_dev->keybit);
++ }
++
++ result = input_register_device(toshiba_acpi.hotkey_dev);
++ if (result) {
++ printk(MY_INFO "Unable to register input device\n");
++ return result;
++ }
++
++ return 0;
++}
++
+ static void toshiba_acpi_exit(void)
+ {
+ if (toshiba_acpi.poll_dev) {
+@@ -709,12 +891,18 @@ static void toshiba_acpi_exit(void)
+ input_free_polled_device(toshiba_acpi.poll_dev);
+ }
+
++ if (toshiba_acpi.hotkey_dev)
++ input_unregister_device(toshiba_acpi.hotkey_dev);
++
+ if (toshiba_acpi.rfk_dev)
+ rfkill_unregister(toshiba_acpi.rfk_dev);
+
+ if (toshiba_backlight_device)
+ backlight_device_unregister(toshiba_backlight_device);
+
++ acpi_remove_notify_handler(toshiba_acpi.handle, ACPI_DEVICE_NOTIFY,
++ toshiba_acpi_notify);
++
+ remove_device();
+
+ if (toshiba_proc_dir)
+@@ -738,11 +926,15 @@ static int __init toshiba_acpi_init(void)
+ return -ENODEV;
+
+ /* simple device detection: look for HCI method */
+- if (is_valid_acpi_path(METHOD_HCI_1))
+- method_hci = METHOD_HCI_1;
+- else if (is_valid_acpi_path(METHOD_HCI_2))
+- method_hci = METHOD_HCI_2;
+- else
++ if (is_valid_acpi_path(TOSH_INTERFACE_1 GHCI_METHOD)) {
++ method_hci = TOSH_INTERFACE_1 GHCI_METHOD;
++ if (toshiba_acpi_setup_keyboard(TOSH_INTERFACE_1))
++ printk(MY_INFO "Unable to activate hotkeys\n");
++ } else if (is_valid_acpi_path(TOSH_INTERFACE_2 GHCI_METHOD)) {
++ method_hci = TOSH_INTERFACE_2 GHCI_METHOD;
++ if (toshiba_acpi_setup_keyboard(TOSH_INTERFACE_2))
++ printk(MY_INFO "Unable to activate hotkeys\n");
++ } else
+ return -ENODEV;
+
+ printk(MY_INFO "Toshiba Laptop ACPI Extras version %s\n",