diff options
author | Henrique de Moraes Holschuh <hmh@hmh.eng.br> | 2007-07-18 23:45:35 -0300 |
---|---|---|
committer | Len Brown <len.brown@intel.com> | 2007-07-21 23:38:44 -0400 |
commit | 6a38abbf2b68e37493f2d5e8702b895a6c23ba0f (patch) | |
tree | 23f4e4bad740a5b866ee31d46c907756127e5fb0 /drivers/misc/thinkpad_acpi.c | |
parent | 7f5d1cd6287b7b29d210f85e2343207ac4310da2 (diff) |
ACPI: thinkpad-acpi: add input device support to hotkey subdriver
Add input device support to the hotkey subdriver.
Hot keys that have a valid keycode mapping are reported through the input
layer if the input device is open. Otherwise, they will be reported as
ACPI events, as they were before.
Scan codes are reported (using EV_MSC MSC_SCAN events) along with EV_KEY
KEY_UNKNOWN events.
For backwards compatibility purposes, hot keys that used to be reported
through ACPI events are not mapped to anything meaningful by default.
Userspace is supposed to remap them if it wants to use the input device for
hot key reporting.
This patch is based on a patch by Richard Hughes <hughsient@gmail.com>.
Signed-off-by: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
Cc: Richard Hughes <hughsient@gmail.com>
Cc: Dmitry Torokhov <dmitry.torokhov@gmail.com>
Signed-off-by: Len Brown <len.brown@intel.com>
Diffstat (limited to 'drivers/misc/thinkpad_acpi.c')
-rw-r--r-- | drivers/misc/thinkpad_acpi.c | 108 |
1 files changed, 104 insertions, 4 deletions
diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c index 4427c994bc7..5c1bea1a6c3 100644 --- a/drivers/misc/thinkpad_acpi.c +++ b/drivers/misc/thinkpad_acpi.c @@ -730,7 +730,31 @@ static struct ibm_struct thinkpad_acpi_driver_data = { static int hotkey_orig_status; static u32 hotkey_orig_mask; static u32 hotkey_all_mask; -static u32 hotkey_reserved_mask = 0x00778000; +static u32 hotkey_reserved_mask; + +static u16 hotkey_keycode_map[] = { + /* Scan Codes 0x00 to 0x0B: ACPI HKEY FN+F1..F12 */ + KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, + KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, + KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, + /* Scan codes 0x0C to 0x0F: Other ACPI HKEY hot keys */ + KEY_UNKNOWN, /* 0x0C: FN+BACKSPACE */ + KEY_UNKNOWN, /* 0x0D: FN+INSERT */ + KEY_UNKNOWN, /* 0x0E: FN+DELETE */ + KEY_RESERVED, /* 0x0F: FN+HOME (brightness up) */ + /* Scan codes 0x10 to 0x1F: Extended ACPI HKEY hot keys */ + KEY_RESERVED, /* 0x10: FN+END (brightness down) */ + KEY_RESERVED, /* 0x11: FN+PGUP (thinklight toggle) */ + KEY_UNKNOWN, /* 0x12: FN+PGDOWN */ + KEY_ZOOM, /* 0x13: FN+SPACE (zoom) */ + KEY_RESERVED, /* 0x14: VOLUME UP */ + KEY_RESERVED, /* 0x15: VOLUME DOWN */ + KEY_RESERVED, /* 0x16: MUTE */ + KEY_VENDOR, /* 0x17: Thinkpad/AccessIBM/Lenovo */ + /* (assignments unknown, please report if found) */ + KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, + KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, +}; static struct attribute_set *hotkey_dev_attributes; @@ -889,11 +913,13 @@ static struct attribute *hotkey_mask_attributes[] = { static int __init hotkey_init(struct ibm_init_struct *iibm) { - int res; + int res, i; int status; vdbg_printk(TPACPI_DBG_INIT, "initializing hotkey subdriver\n"); + BUG_ON(!tpacpi_inputdev); + IBM_ACPIHANDLE_INIT(hkey); mutex_init(&hotkey_mutex); @@ -950,6 +976,23 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) &tpacpi_pdev->dev.kobj); if (res) return res; + + set_bit(EV_KEY, tpacpi_inputdev->evbit); + set_bit(EV_MSC, tpacpi_inputdev->evbit); + set_bit(MSC_SCAN, tpacpi_inputdev->mscbit); + tpacpi_inputdev->keycodesize = sizeof(hotkey_keycode_map[0]); + tpacpi_inputdev->keycodemax = ARRAY_SIZE(hotkey_keycode_map); + tpacpi_inputdev->keycode = &hotkey_keycode_map; + for (i = 0; i < ARRAY_SIZE(hotkey_keycode_map); i++) { + if (hotkey_keycode_map[i] != KEY_RESERVED) { + set_bit(hotkey_keycode_map[i], + tpacpi_inputdev->keybit); + } else { + if (i < sizeof(hotkey_reserved_mask)*8) + hotkey_reserved_mask |= 1 << i; + } + } + } return (tp_features.hotkey)? 0 : 1; @@ -972,12 +1015,69 @@ static void hotkey_exit(void) } } +static void tpacpi_input_send_key(unsigned int scancode, + unsigned int keycode) +{ + if (keycode != KEY_RESERVED) { + input_report_key(tpacpi_inputdev, keycode, 1); + if (keycode == KEY_UNKNOWN) + input_event(tpacpi_inputdev, EV_MSC, MSC_SCAN, + scancode); + input_sync(tpacpi_inputdev); + + input_report_key(tpacpi_inputdev, keycode, 0); + if (keycode == KEY_UNKNOWN) + input_event(tpacpi_inputdev, EV_MSC, MSC_SCAN, + scancode); + input_sync(tpacpi_inputdev); + } +} + static void hotkey_notify(struct ibm_struct *ibm, u32 event) { - int hkey; + u32 hkey; + unsigned int keycode, scancode; + int sendacpi = 1; if (event == 0x80 && acpi_evalf(hkey_handle, &hkey, "MHKP", "d")) { - acpi_bus_generate_event(ibm->acpi->device, event, hkey); + if (tpacpi_inputdev->users > 0) { + switch (hkey >> 12) { + case 1: + /* 0x1000-0x1FFF: key presses */ + scancode = hkey & 0xfff; + if (scancode > 0 && scancode < 0x21) { + scancode--; + keycode = hotkey_keycode_map[scancode]; + tpacpi_input_send_key(scancode, keycode); + sendacpi = (keycode == KEY_RESERVED + || keycode == KEY_UNKNOWN); + } else { + printk(IBM_ERR + "hotkey 0x%04x out of range for keyboard map\n", + hkey); + } + break; + case 5: + /* 0x5000-0x5FFF: LID */ + /* we don't handle it through this path, just + * eat up known LID events */ + if (hkey != 0x5001 && hkey != 0x5002) { + printk(IBM_ERR + "unknown LID-related hotkey event: 0x%04x\n", + hkey); + } + break; + default: + /* case 2: dock-related */ + /* 0x2305 - T43 waking up due to bay lever eject while aslept */ + /* case 3: ultra-bay related. maybe bay in dock? */ + /* 0x3003 - T43 after wake up by bay lever eject (0x2305) */ + printk(IBM_NOTICE "unhandled hotkey event 0x%04x\n", hkey); + } + } + + if (sendacpi) + acpi_bus_generate_event(ibm->acpi->device, event, hkey); } else { printk(IBM_ERR "unknown hotkey notification event %d\n", event); acpi_bus_generate_event(ibm->acpi->device, event, 0); |