1d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 21da177e4SLinus Torvalds /* 31da177e4SLinus Torvalds * AT and PS/2 keyboard driver 41da177e4SLinus Torvalds * 51da177e4SLinus Torvalds * Copyright (c) 1999-2002 Vojtech Pavlik 61da177e4SLinus Torvalds */ 71da177e4SLinus Torvalds 81da177e4SLinus Torvalds 91da177e4SLinus Torvalds /* 101da177e4SLinus Torvalds * This driver can handle standard AT keyboards and PS/2 keyboards in 111da177e4SLinus Torvalds * Translated and Raw Set 2 and Set 3, as well as AT keyboards on dumb 121da177e4SLinus Torvalds * input-only controllers and AT keyboards connected over a one way RS232 131da177e4SLinus Torvalds * converter. 141da177e4SLinus Torvalds */ 151da177e4SLinus Torvalds 161da177e4SLinus Torvalds #include <linux/delay.h> 171da177e4SLinus Torvalds #include <linux/module.h> 181da177e4SLinus Torvalds #include <linux/slab.h> 191da177e4SLinus Torvalds #include <linux/interrupt.h> 201da177e4SLinus Torvalds #include <linux/init.h> 211da177e4SLinus Torvalds #include <linux/input.h> 2245ceaf14SStephen Boyd #include <linux/input/vivaldi-fmap.h> 231da177e4SLinus Torvalds #include <linux/serio.h> 241da177e4SLinus Torvalds #include <linux/workqueue.h> 251da177e4SLinus Torvalds #include <linux/libps2.h> 2633d3f07aSIngo Molnar #include <linux/mutex.h> 27554101e3SGiel de Nijs #include <linux/dmi.h> 288f7b057aSRajat Jain #include <linux/property.h> 291da177e4SLinus Torvalds 301da177e4SLinus Torvalds #define DRIVER_DESC "AT and PS/2 keyboard driver" 311da177e4SLinus Torvalds 321da177e4SLinus Torvalds MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>"); 331da177e4SLinus Torvalds MODULE_DESCRIPTION(DRIVER_DESC); 341da177e4SLinus Torvalds MODULE_LICENSE("GPL"); 351da177e4SLinus Torvalds 361da177e4SLinus Torvalds static int atkbd_set = 2; 371da177e4SLinus Torvalds module_param_named(set, atkbd_set, int, 0); 381da177e4SLinus Torvalds MODULE_PARM_DESC(set, "Select keyboard code set (2 = default, 3 = PS/2 native)"); 391da177e4SLinus Torvalds 401da177e4SLinus Torvalds #if defined(__i386__) || defined(__x86_64__) || defined(__hppa__) 41a9a1f9c3SDmitry Torokhov static bool atkbd_reset; 421da177e4SLinus Torvalds #else 43a9a1f9c3SDmitry Torokhov static bool atkbd_reset = true; 441da177e4SLinus Torvalds #endif 451da177e4SLinus Torvalds module_param_named(reset, atkbd_reset, bool, 0); 461da177e4SLinus Torvalds MODULE_PARM_DESC(reset, "Reset keyboard during initialization"); 471da177e4SLinus Torvalds 48a9a1f9c3SDmitry Torokhov static bool atkbd_softrepeat; 491da177e4SLinus Torvalds module_param_named(softrepeat, atkbd_softrepeat, bool, 0); 501da177e4SLinus Torvalds MODULE_PARM_DESC(softrepeat, "Use software keyboard repeat"); 511da177e4SLinus Torvalds 52a9a1f9c3SDmitry Torokhov static bool atkbd_softraw = true; 531da177e4SLinus Torvalds module_param_named(softraw, atkbd_softraw, bool, 0); 541da177e4SLinus Torvalds MODULE_PARM_DESC(softraw, "Use software generated rawmode"); 551da177e4SLinus Torvalds 56a9a1f9c3SDmitry Torokhov static bool atkbd_scroll; 571da177e4SLinus Torvalds module_param_named(scroll, atkbd_scroll, bool, 0); 581da177e4SLinus Torvalds MODULE_PARM_DESC(scroll, "Enable scroll-wheel on MS Office and similar keyboards"); 591da177e4SLinus Torvalds 60a9a1f9c3SDmitry Torokhov static bool atkbd_extra; 611da177e4SLinus Torvalds module_param_named(extra, atkbd_extra, bool, 0); 621da177e4SLinus Torvalds MODULE_PARM_DESC(extra, "Enable extra LEDs and keys on IBM RapidAcces, EzKey and similar keyboards"); 631da177e4SLinus Torvalds 648c5188b6SBenjamin LaHaise static bool atkbd_terminal; 658c5188b6SBenjamin LaHaise module_param_named(terminal, atkbd_terminal, bool, 0); 668c5188b6SBenjamin LaHaise MODULE_PARM_DESC(terminal, "Enable break codes on an IBM Terminal keyboard connected via AT/PS2"); 678c5188b6SBenjamin LaHaise 689d17ad23SRajat Jain #define SCANCODE(keymap) ((keymap >> 16) & 0xFFFF) 699d17ad23SRajat Jain #define KEYCODE(keymap) (keymap & 0xFFFF) 709d17ad23SRajat Jain 711da177e4SLinus Torvalds /* 721da177e4SLinus Torvalds * Scancode to keycode tables. These are just the default setting, and 730211a9c8SFrederik Schwarzer * are loadable via a userland utility. 741da177e4SLinus Torvalds */ 751da177e4SLinus Torvalds 761ba36e11SDmitry Torokhov #define ATKBD_KEYMAP_SIZE 512 771ba36e11SDmitry Torokhov 781ba36e11SDmitry Torokhov static const unsigned short atkbd_set2_keycode[ATKBD_KEYMAP_SIZE] = { 791da177e4SLinus Torvalds 801da177e4SLinus Torvalds #ifdef CONFIG_KEYBOARD_ATKBD_HP_KEYCODES 811da177e4SLinus Torvalds 821da177e4SLinus Torvalds /* XXX: need a more general approach */ 831da177e4SLinus Torvalds 841da177e4SLinus Torvalds #include "hpps2atkbd.h" /* include the keyboard scancodes */ 851da177e4SLinus Torvalds 861da177e4SLinus Torvalds #else 871da177e4SLinus Torvalds 0, 67, 65, 63, 61, 59, 60, 88, 0, 68, 66, 64, 62, 15, 41,117, 881da177e4SLinus Torvalds 0, 56, 42, 93, 29, 16, 2, 0, 0, 0, 44, 31, 30, 17, 3, 0, 891da177e4SLinus Torvalds 0, 46, 45, 32, 18, 5, 4, 95, 0, 57, 47, 33, 20, 19, 6,183, 901da177e4SLinus Torvalds 0, 49, 48, 35, 34, 21, 7,184, 0, 0, 50, 36, 22, 8, 9,185, 911da177e4SLinus Torvalds 0, 51, 37, 23, 24, 11, 10, 0, 0, 52, 53, 38, 39, 25, 12, 0, 921da177e4SLinus Torvalds 0, 89, 40, 0, 26, 13, 0, 0, 58, 54, 28, 27, 0, 43, 0, 85, 931da177e4SLinus Torvalds 0, 86, 91, 90, 92, 0, 14, 94, 0, 79,124, 75, 71,121, 0, 0, 941da177e4SLinus Torvalds 82, 83, 80, 76, 77, 72, 1, 69, 87, 78, 81, 74, 55, 73, 70, 99, 951da177e4SLinus Torvalds 961da177e4SLinus Torvalds 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 971da177e4SLinus Torvalds 217,100,255, 0, 97,165, 0, 0,156, 0, 0, 0, 0, 0, 0,125, 981da177e4SLinus Torvalds 173,114, 0,113, 0, 0, 0,126,128, 0, 0,140, 0, 0, 0,127, 9972a42f24SHans de Goede 159, 0,115, 0,164, 0, 0,116,158, 0,172,166, 0, 0, 0,142, 1001da177e4SLinus Torvalds 157, 0, 0, 0, 0, 0, 0, 0,155, 0, 98, 0, 0,163, 0, 0, 1011da177e4SLinus Torvalds 226, 0, 0, 0, 0, 0, 0, 0, 0,255, 96, 0, 0, 0,143, 0, 1021da177e4SLinus Torvalds 0, 0, 0, 0, 0, 0, 0, 0, 0,107, 0,105,102, 0, 0,112, 1031da177e4SLinus Torvalds 110,111,108,112,106,103, 0,119, 0,118,109, 0, 99,104,119, 0, 1041da177e4SLinus Torvalds 1051da177e4SLinus Torvalds 0, 0, 0, 65, 99, 1061da177e4SLinus Torvalds #endif 1071da177e4SLinus Torvalds }; 1081da177e4SLinus Torvalds 1091ba36e11SDmitry Torokhov static const unsigned short atkbd_set3_keycode[ATKBD_KEYMAP_SIZE] = { 1101da177e4SLinus Torvalds 1111da177e4SLinus Torvalds 0, 0, 0, 0, 0, 0, 0, 59, 1,138,128,129,130, 15, 41, 60, 1121da177e4SLinus Torvalds 131, 29, 42, 86, 58, 16, 2, 61,133, 56, 44, 31, 30, 17, 3, 62, 1131da177e4SLinus Torvalds 134, 46, 45, 32, 18, 5, 4, 63,135, 57, 47, 33, 20, 19, 6, 64, 1141da177e4SLinus Torvalds 136, 49, 48, 35, 34, 21, 7, 65,137,100, 50, 36, 22, 8, 9, 66, 1151da177e4SLinus Torvalds 125, 51, 37, 23, 24, 11, 10, 67,126, 52, 53, 38, 39, 25, 12, 68, 1161da177e4SLinus Torvalds 113,114, 40, 43, 26, 13, 87, 99, 97, 54, 28, 27, 43, 43, 88, 70, 1171da177e4SLinus Torvalds 108,105,119,103,111,107, 14,110, 0, 79,106, 75, 71,109,102,104, 1181da177e4SLinus Torvalds 82, 83, 80, 76, 77, 72, 69, 98, 0, 96, 81, 0, 78, 73, 55,183, 1191da177e4SLinus Torvalds 1201da177e4SLinus Torvalds 184,185,186,187, 74, 94, 92, 93, 0, 0, 0,125,126,127,112, 0, 12172a42f24SHans de Goede 0,139,172,163,165,115,152,172,166,140,160,154,113,114,167,168, 1221da177e4SLinus Torvalds 148,149,147,140 1231da177e4SLinus Torvalds }; 1241da177e4SLinus Torvalds 125f6d65610SDmitry Torokhov static const unsigned short atkbd_unxlate_table[128] = { 1261da177e4SLinus Torvalds 0,118, 22, 30, 38, 37, 46, 54, 61, 62, 70, 69, 78, 85,102, 13, 1271da177e4SLinus Torvalds 21, 29, 36, 45, 44, 53, 60, 67, 68, 77, 84, 91, 90, 20, 28, 27, 1281da177e4SLinus Torvalds 35, 43, 52, 51, 59, 66, 75, 76, 82, 14, 18, 93, 26, 34, 33, 42, 1291da177e4SLinus Torvalds 50, 49, 58, 65, 73, 74, 89,124, 17, 41, 88, 5, 6, 4, 12, 3, 1301da177e4SLinus Torvalds 11, 2, 10, 1, 9,119,126,108,117,125,123,107,115,116,121,105, 1311da177e4SLinus Torvalds 114,122,112,113,127, 96, 97,120, 7, 15, 23, 31, 39, 47, 55, 63, 1321da177e4SLinus Torvalds 71, 79, 86, 94, 8, 16, 24, 32, 40, 48, 56, 64, 72, 80, 87,111, 1331da177e4SLinus Torvalds 19, 25, 57, 81, 83, 92, 95, 98, 99,100,101,103,104,106,109,110 1341da177e4SLinus Torvalds }; 1351da177e4SLinus Torvalds 1361da177e4SLinus Torvalds #define ATKBD_CMD_SETLEDS 0x10ed 1371da177e4SLinus Torvalds #define ATKBD_CMD_GSCANSET 0x11f0 1381da177e4SLinus Torvalds #define ATKBD_CMD_SSCANSET 0x10f0 1391da177e4SLinus Torvalds #define ATKBD_CMD_GETID 0x02f2 1401da177e4SLinus Torvalds #define ATKBD_CMD_SETREP 0x10f3 1411da177e4SLinus Torvalds #define ATKBD_CMD_ENABLE 0x00f4 1424a299bf5SDmitry Torokhov #define ATKBD_CMD_RESET_DIS 0x00f5 /* Reset to defaults and disable */ 1434a299bf5SDmitry Torokhov #define ATKBD_CMD_RESET_DEF 0x00f6 /* Reset to defaults */ 1448c5188b6SBenjamin LaHaise #define ATKBD_CMD_SETALL_MB 0x00f8 /* Set all keys to give break codes */ 1458c5188b6SBenjamin LaHaise #define ATKBD_CMD_SETALL_MBR 0x00fa /* ... and repeat */ 1461da177e4SLinus Torvalds #define ATKBD_CMD_RESET_BAT 0x02ff 1471da177e4SLinus Torvalds #define ATKBD_CMD_RESEND 0x00fe 1481da177e4SLinus Torvalds #define ATKBD_CMD_EX_ENABLE 0x10ea 1491da177e4SLinus Torvalds #define ATKBD_CMD_EX_SETLEDS 0x20eb 1501da177e4SLinus Torvalds #define ATKBD_CMD_OK_GETID 0x02e8 1511da177e4SLinus Torvalds 1521da177e4SLinus Torvalds #define ATKBD_RET_ACK 0xfa 1531da177e4SLinus Torvalds #define ATKBD_RET_NAK 0xfe 1541da177e4SLinus Torvalds #define ATKBD_RET_BAT 0xaa 1551da177e4SLinus Torvalds #define ATKBD_RET_EMUL0 0xe0 1561da177e4SLinus Torvalds #define ATKBD_RET_EMUL1 0xe1 1571da177e4SLinus Torvalds #define ATKBD_RET_RELEASE 0xf0 1580ae051a1SDmitry Torokhov #define ATKBD_RET_HANJA 0xf1 1590ae051a1SDmitry Torokhov #define ATKBD_RET_HANGEUL 0xf2 1601da177e4SLinus Torvalds #define ATKBD_RET_ERR 0xff 1611da177e4SLinus Torvalds 1621da177e4SLinus Torvalds #define ATKBD_KEY_UNKNOWN 0 1631da177e4SLinus Torvalds #define ATKBD_KEY_NULL 255 1641da177e4SLinus Torvalds 1654b70858bSDmitry Torokhov #define ATKBD_SCR_1 0xfffe 1664b70858bSDmitry Torokhov #define ATKBD_SCR_2 0xfffd 1674b70858bSDmitry Torokhov #define ATKBD_SCR_4 0xfffc 1684b70858bSDmitry Torokhov #define ATKBD_SCR_8 0xfffb 1694b70858bSDmitry Torokhov #define ATKBD_SCR_CLICK 0xfffa 1704b70858bSDmitry Torokhov #define ATKBD_SCR_LEFT 0xfff9 1714b70858bSDmitry Torokhov #define ATKBD_SCR_RIGHT 0xfff8 1721da177e4SLinus Torvalds 173f6d65610SDmitry Torokhov #define ATKBD_SPECIAL ATKBD_SCR_RIGHT 1741da177e4SLinus Torvalds 1750d4c8597SDmitry Torokhov #define ATKBD_LED_EVENT_BIT 0 1760d4c8597SDmitry Torokhov #define ATKBD_REP_EVENT_BIT 1 1770d4c8597SDmitry Torokhov 1780ae051a1SDmitry Torokhov #define ATKBD_XL_ERR 0x01 1790ae051a1SDmitry Torokhov #define ATKBD_XL_BAT 0x02 1800ae051a1SDmitry Torokhov #define ATKBD_XL_ACK 0x04 1810ae051a1SDmitry Torokhov #define ATKBD_XL_NAK 0x08 1820ae051a1SDmitry Torokhov #define ATKBD_XL_HANGEUL 0x10 1830ae051a1SDmitry Torokhov #define ATKBD_XL_HANJA 0x20 1840ae051a1SDmitry Torokhov 185f6d65610SDmitry Torokhov static const struct { 1864b70858bSDmitry Torokhov unsigned short keycode; 1871da177e4SLinus Torvalds unsigned char set2; 1881da177e4SLinus Torvalds } atkbd_scroll_keys[] = { 1891da177e4SLinus Torvalds { ATKBD_SCR_1, 0xc5 }, 1905212dd58SVojtech Pavlik { ATKBD_SCR_2, 0x9d }, 1915212dd58SVojtech Pavlik { ATKBD_SCR_4, 0xa4 }, 1925212dd58SVojtech Pavlik { ATKBD_SCR_8, 0x9b }, 1931da177e4SLinus Torvalds { ATKBD_SCR_CLICK, 0xe0 }, 1941da177e4SLinus Torvalds { ATKBD_SCR_LEFT, 0xcb }, 1951da177e4SLinus Torvalds { ATKBD_SCR_RIGHT, 0xd2 }, 1961da177e4SLinus Torvalds }; 1971da177e4SLinus Torvalds 1981da177e4SLinus Torvalds /* 1991da177e4SLinus Torvalds * The atkbd control structure 2001da177e4SLinus Torvalds */ 2011da177e4SLinus Torvalds 2021da177e4SLinus Torvalds struct atkbd { 2031da177e4SLinus Torvalds 2041da177e4SLinus Torvalds struct ps2dev ps2dev; 2053c42f0c3SDmitry Torokhov struct input_dev *dev; 2061da177e4SLinus Torvalds 2071da177e4SLinus Torvalds /* Written only during init */ 2081da177e4SLinus Torvalds char name[64]; 2091da177e4SLinus Torvalds char phys[32]; 2101da177e4SLinus Torvalds 2111da177e4SLinus Torvalds unsigned short id; 2121ba36e11SDmitry Torokhov unsigned short keycode[ATKBD_KEYMAP_SIZE]; 2131ba36e11SDmitry Torokhov DECLARE_BITMAP(force_release_mask, ATKBD_KEYMAP_SIZE); 2141da177e4SLinus Torvalds unsigned char set; 215a9a1f9c3SDmitry Torokhov bool translated; 216a9a1f9c3SDmitry Torokhov bool extra; 217a9a1f9c3SDmitry Torokhov bool write; 218a9a1f9c3SDmitry Torokhov bool softrepeat; 219a9a1f9c3SDmitry Torokhov bool softraw; 220a9a1f9c3SDmitry Torokhov bool scroll; 221a9a1f9c3SDmitry Torokhov bool enabled; 2221da177e4SLinus Torvalds 2231da177e4SLinus Torvalds /* Accessed only from interrupt */ 2241da177e4SLinus Torvalds unsigned char emul; 225a9a1f9c3SDmitry Torokhov bool resend; 226a9a1f9c3SDmitry Torokhov bool release; 2270ae051a1SDmitry Torokhov unsigned long xl_bit; 2281da177e4SLinus Torvalds unsigned int last; 2291da177e4SLinus Torvalds unsigned long time; 23086255d9dSDmitry Torokhov unsigned long err_count; 2310d4c8597SDmitry Torokhov 232da4249c9SDmitry Torokhov struct delayed_work event_work; 233da4249c9SDmitry Torokhov unsigned long event_jiffies; 2340d4c8597SDmitry Torokhov unsigned long event_mask; 23559b01513SEric W. Biederman 23659b01513SEric W. Biederman /* Serializes reconnect(), attr->set() and event work */ 23759b01513SEric W. Biederman struct mutex mutex; 2388f7b057aSRajat Jain 23945ceaf14SStephen Boyd struct vivaldi_data vdata; 2401da177e4SLinus Torvalds }; 2411da177e4SLinus Torvalds 242554101e3SGiel de Nijs /* 24336726dd9SThadeu Lima de Souza Cascardo * System-specific keymap fixup routine 244554101e3SGiel de Nijs */ 24539191698SDaniel Mierswa static void (*atkbd_platform_fixup)(struct atkbd *, const void *data); 24639191698SDaniel Mierswa static void *atkbd_platform_fixup_data; 247e5713069SJamie Lentin static unsigned int (*atkbd_platform_scancode_fixup)(struct atkbd *, unsigned int); 248554101e3SGiel de Nijs 2493d725caaSSheng-Liang Song /* 2503d725caaSSheng-Liang Song * Certain keyboards to not like ATKBD_CMD_RESET_DIS and stop responding 2513d725caaSSheng-Liang Song * to many commands until full reset (ATKBD_CMD_RESET_BAT) is performed. 2523d725caaSSheng-Liang Song */ 2533d725caaSSheng-Liang Song static bool atkbd_skip_deactivate; 2543d725caaSSheng-Liang Song 2551da177e4SLinus Torvalds static ssize_t atkbd_attr_show_helper(struct device *dev, char *buf, 2561da177e4SLinus Torvalds ssize_t (*handler)(struct atkbd *, char *)); 2571da177e4SLinus Torvalds static ssize_t atkbd_attr_set_helper(struct device *dev, const char *buf, size_t count, 2581da177e4SLinus Torvalds ssize_t (*handler)(struct atkbd *, const char *, size_t)); 2591da177e4SLinus Torvalds #define ATKBD_DEFINE_ATTR(_name) \ 2601da177e4SLinus Torvalds static ssize_t atkbd_show_##_name(struct atkbd *, char *); \ 2611da177e4SLinus Torvalds static ssize_t atkbd_set_##_name(struct atkbd *, const char *, size_t); \ 26286255d9dSDmitry Torokhov static ssize_t atkbd_do_show_##_name(struct device *d, \ 26386255d9dSDmitry Torokhov struct device_attribute *attr, char *b) \ 2641da177e4SLinus Torvalds { \ 2651da177e4SLinus Torvalds return atkbd_attr_show_helper(d, b, atkbd_show_##_name); \ 2661da177e4SLinus Torvalds } \ 26786255d9dSDmitry Torokhov static ssize_t atkbd_do_set_##_name(struct device *d, \ 26886255d9dSDmitry Torokhov struct device_attribute *attr, const char *b, size_t s) \ 2691da177e4SLinus Torvalds { \ 2701da177e4SLinus Torvalds return atkbd_attr_set_helper(d, b, s, atkbd_set_##_name); \ 2711da177e4SLinus Torvalds } \ 2721da177e4SLinus Torvalds static struct device_attribute atkbd_attr_##_name = \ 2731da177e4SLinus Torvalds __ATTR(_name, S_IWUSR | S_IRUGO, atkbd_do_show_##_name, atkbd_do_set_##_name); 2741da177e4SLinus Torvalds 2751da177e4SLinus Torvalds ATKBD_DEFINE_ATTR(extra); 2761ba36e11SDmitry Torokhov ATKBD_DEFINE_ATTR(force_release); 2771da177e4SLinus Torvalds ATKBD_DEFINE_ATTR(scroll); 2781da177e4SLinus Torvalds ATKBD_DEFINE_ATTR(set); 2791da177e4SLinus Torvalds ATKBD_DEFINE_ATTR(softrepeat); 2801da177e4SLinus Torvalds ATKBD_DEFINE_ATTR(softraw); 2811da177e4SLinus Torvalds 28286255d9dSDmitry Torokhov #define ATKBD_DEFINE_RO_ATTR(_name) \ 28386255d9dSDmitry Torokhov static ssize_t atkbd_show_##_name(struct atkbd *, char *); \ 28486255d9dSDmitry Torokhov static ssize_t atkbd_do_show_##_name(struct device *d, \ 28586255d9dSDmitry Torokhov struct device_attribute *attr, char *b) \ 28686255d9dSDmitry Torokhov { \ 28786255d9dSDmitry Torokhov return atkbd_attr_show_helper(d, b, atkbd_show_##_name); \ 28886255d9dSDmitry Torokhov } \ 28986255d9dSDmitry Torokhov static struct device_attribute atkbd_attr_##_name = \ 29086255d9dSDmitry Torokhov __ATTR(_name, S_IRUGO, atkbd_do_show_##_name, NULL); 29186255d9dSDmitry Torokhov 29286255d9dSDmitry Torokhov ATKBD_DEFINE_RO_ATTR(err_count); 2938f7b057aSRajat Jain ATKBD_DEFINE_RO_ATTR(function_row_physmap); 29486255d9dSDmitry Torokhov 29586255d9dSDmitry Torokhov static struct attribute *atkbd_attributes[] = { 29686255d9dSDmitry Torokhov &atkbd_attr_extra.attr, 2971ba36e11SDmitry Torokhov &atkbd_attr_force_release.attr, 29886255d9dSDmitry Torokhov &atkbd_attr_scroll.attr, 29986255d9dSDmitry Torokhov &atkbd_attr_set.attr, 30086255d9dSDmitry Torokhov &atkbd_attr_softrepeat.attr, 30186255d9dSDmitry Torokhov &atkbd_attr_softraw.attr, 30286255d9dSDmitry Torokhov &atkbd_attr_err_count.attr, 3038f7b057aSRajat Jain &atkbd_attr_function_row_physmap.attr, 30486255d9dSDmitry Torokhov NULL 30586255d9dSDmitry Torokhov }; 30686255d9dSDmitry Torokhov 3078f7b057aSRajat Jain static ssize_t atkbd_show_function_row_physmap(struct atkbd *atkbd, char *buf) 3088f7b057aSRajat Jain { 30945ceaf14SStephen Boyd return vivaldi_function_row_physmap_show(&atkbd->vdata, buf); 3108f7b057aSRajat Jain } 3118f7b057aSRajat Jain 312*100e1695SDmitry Torokhov static struct atkbd *atkbd_from_serio(struct serio *serio) 313*100e1695SDmitry Torokhov { 314*100e1695SDmitry Torokhov struct ps2dev *ps2dev = serio_get_drvdata(serio); 315*100e1695SDmitry Torokhov 316*100e1695SDmitry Torokhov return container_of(ps2dev, struct atkbd, ps2dev); 317*100e1695SDmitry Torokhov } 318*100e1695SDmitry Torokhov 3198f7b057aSRajat Jain static umode_t atkbd_attr_is_visible(struct kobject *kobj, 3208f7b057aSRajat Jain struct attribute *attr, int i) 3218f7b057aSRajat Jain { 32250221b0bSYueHaibing struct device *dev = kobj_to_dev(kobj); 3238f7b057aSRajat Jain struct serio *serio = to_serio_port(dev); 324*100e1695SDmitry Torokhov struct atkbd *atkbd = atkbd_from_serio(serio); 3258f7b057aSRajat Jain 3268f7b057aSRajat Jain if (attr == &atkbd_attr_function_row_physmap.attr && 32745ceaf14SStephen Boyd !atkbd->vdata.num_function_row_keys) 3288f7b057aSRajat Jain return 0; 3298f7b057aSRajat Jain 3308f7b057aSRajat Jain return attr->mode; 3318f7b057aSRajat Jain } 3328f7b057aSRajat Jain 333c99e3ac6SDmitry Torokhov static const struct attribute_group atkbd_attribute_group = { 33486255d9dSDmitry Torokhov .attrs = atkbd_attributes, 3358f7b057aSRajat Jain .is_visible = atkbd_attr_is_visible, 33686255d9dSDmitry Torokhov }; 33786255d9dSDmitry Torokhov 338c99e3ac6SDmitry Torokhov __ATTRIBUTE_GROUPS(atkbd_attribute); 339c99e3ac6SDmitry Torokhov 3400ae051a1SDmitry Torokhov static const unsigned int xl_table[] = { 3410ae051a1SDmitry Torokhov ATKBD_RET_BAT, ATKBD_RET_ERR, ATKBD_RET_ACK, 3420ae051a1SDmitry Torokhov ATKBD_RET_NAK, ATKBD_RET_HANJA, ATKBD_RET_HANGEUL, 3430ae051a1SDmitry Torokhov }; 3441da177e4SLinus Torvalds 3450ae051a1SDmitry Torokhov /* 3460ae051a1SDmitry Torokhov * Checks if we should mangle the scancode to extract 'release' bit 3470ae051a1SDmitry Torokhov * in translated mode. 3480ae051a1SDmitry Torokhov */ 349a9a1f9c3SDmitry Torokhov static bool atkbd_need_xlate(unsigned long xl_bit, unsigned char code) 3501da177e4SLinus Torvalds { 3510ae051a1SDmitry Torokhov int i; 3520ae051a1SDmitry Torokhov 3530ae051a1SDmitry Torokhov if (code == ATKBD_RET_EMUL0 || code == ATKBD_RET_EMUL1) 354a9a1f9c3SDmitry Torokhov return false; 3550ae051a1SDmitry Torokhov 3560ae051a1SDmitry Torokhov for (i = 0; i < ARRAY_SIZE(xl_table); i++) 3570ae051a1SDmitry Torokhov if (code == xl_table[i]) 3580ae051a1SDmitry Torokhov return test_bit(i, &xl_bit); 3590ae051a1SDmitry Torokhov 360a9a1f9c3SDmitry Torokhov return true; 3610ae051a1SDmitry Torokhov } 3620ae051a1SDmitry Torokhov 3630ae051a1SDmitry Torokhov /* 3640ae051a1SDmitry Torokhov * Calculates new value of xl_bit so the driver can distinguish 3650ae051a1SDmitry Torokhov * between make/break pair of scancodes for select keys and PS/2 3660ae051a1SDmitry Torokhov * protocol responses. 3670ae051a1SDmitry Torokhov */ 3680ae051a1SDmitry Torokhov static void atkbd_calculate_xl_bit(struct atkbd *atkbd, unsigned char code) 3690ae051a1SDmitry Torokhov { 3700ae051a1SDmitry Torokhov int i; 3710ae051a1SDmitry Torokhov 3720ae051a1SDmitry Torokhov for (i = 0; i < ARRAY_SIZE(xl_table); i++) { 3730ae051a1SDmitry Torokhov if (!((code ^ xl_table[i]) & 0x7f)) { 3740ae051a1SDmitry Torokhov if (code & 0x80) 3750ae051a1SDmitry Torokhov __clear_bit(i, &atkbd->xl_bit); 3760ae051a1SDmitry Torokhov else 3770ae051a1SDmitry Torokhov __set_bit(i, &atkbd->xl_bit); 3780ae051a1SDmitry Torokhov break; 3790ae051a1SDmitry Torokhov } 3800ae051a1SDmitry Torokhov } 3810ae051a1SDmitry Torokhov } 3820ae051a1SDmitry Torokhov 3830ae051a1SDmitry Torokhov /* 3840ae051a1SDmitry Torokhov * Encode the scancode, 0xe0 prefix, and high bit into a single integer, 3850ae051a1SDmitry Torokhov * keeping kernel 2.4 compatibility for set 2 3860ae051a1SDmitry Torokhov */ 3870ae051a1SDmitry Torokhov static unsigned int atkbd_compat_scancode(struct atkbd *atkbd, unsigned int code) 3880ae051a1SDmitry Torokhov { 3890ae051a1SDmitry Torokhov if (atkbd->set == 3) { 3900ae051a1SDmitry Torokhov if (atkbd->emul == 1) 3910ae051a1SDmitry Torokhov code |= 0x100; 3920ae051a1SDmitry Torokhov } else { 3930ae051a1SDmitry Torokhov code = (code & 0x7f) | ((code & 0x80) << 1); 3940ae051a1SDmitry Torokhov if (atkbd->emul == 1) 3950ae051a1SDmitry Torokhov code |= 0x80; 3960ae051a1SDmitry Torokhov } 3970ae051a1SDmitry Torokhov 3980ae051a1SDmitry Torokhov return code; 3991da177e4SLinus Torvalds } 4001da177e4SLinus Torvalds 4011da177e4SLinus Torvalds /* 4021da177e4SLinus Torvalds * atkbd_interrupt(). Here takes place processing of data received from 4031da177e4SLinus Torvalds * the keyboard into events. 4041da177e4SLinus Torvalds */ 4051da177e4SLinus Torvalds 4061da177e4SLinus Torvalds static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data, 4077d12e780SDavid Howells unsigned int flags) 4081da177e4SLinus Torvalds { 409*100e1695SDmitry Torokhov struct atkbd *atkbd = atkbd_from_serio(serio); 4100ae051a1SDmitry Torokhov struct input_dev *dev = atkbd->dev; 4111da177e4SLinus Torvalds unsigned int code = data; 412554101e3SGiel de Nijs int scroll = 0, hscroll = 0, click = -1; 4131da177e4SLinus Torvalds int value; 414f6d65610SDmitry Torokhov unsigned short keycode; 4151da177e4SLinus Torvalds 416a9a1f9c3SDmitry Torokhov dev_dbg(&serio->dev, "Received %02x flags %02x\n", data, flags); 4171da177e4SLinus Torvalds 4181da177e4SLinus Torvalds #if !defined(__i386__) && !defined (__x86_64__) 4191da177e4SLinus Torvalds if ((flags & (SERIO_FRAME | SERIO_PARITY)) && (~flags & SERIO_TIMEOUT) && !atkbd->resend && atkbd->write) { 420a9a1f9c3SDmitry Torokhov dev_warn(&serio->dev, "Frame/parity error: %02x\n", flags); 4211da177e4SLinus Torvalds serio_write(serio, ATKBD_CMD_RESEND); 422a9a1f9c3SDmitry Torokhov atkbd->resend = true; 4231da177e4SLinus Torvalds goto out; 4241da177e4SLinus Torvalds } 4251da177e4SLinus Torvalds 4261da177e4SLinus Torvalds if (!flags && data == ATKBD_RET_ACK) 427a9a1f9c3SDmitry Torokhov atkbd->resend = false; 4281da177e4SLinus Torvalds #endif 4291da177e4SLinus Torvalds 4301da177e4SLinus Torvalds if (unlikely(atkbd->ps2dev.flags & PS2_FLAG_ACK)) 4311da177e4SLinus Torvalds if (ps2_handle_ack(&atkbd->ps2dev, data)) 4321da177e4SLinus Torvalds goto out; 4331da177e4SLinus Torvalds 4341da177e4SLinus Torvalds if (unlikely(atkbd->ps2dev.flags & PS2_FLAG_CMD)) 4351da177e4SLinus Torvalds if (ps2_handle_response(&atkbd->ps2dev, data)) 4361da177e4SLinus Torvalds goto out; 4371da177e4SLinus Torvalds 438aaca981eSDmitry Torokhov pm_wakeup_event(&serio->dev, 0); 439aaca981eSDmitry Torokhov 4401da177e4SLinus Torvalds if (!atkbd->enabled) 4411da177e4SLinus Torvalds goto out; 4421da177e4SLinus Torvalds 4430ae051a1SDmitry Torokhov input_event(dev, EV_MSC, MSC_RAW, code); 4441da177e4SLinus Torvalds 445e5713069SJamie Lentin if (atkbd_platform_scancode_fixup) 446e5713069SJamie Lentin code = atkbd_platform_scancode_fixup(atkbd, code); 447e5713069SJamie Lentin 4481da177e4SLinus Torvalds if (atkbd->translated) { 4491da177e4SLinus Torvalds 4500ae051a1SDmitry Torokhov if (atkbd->emul || atkbd_need_xlate(atkbd->xl_bit, code)) { 4511da177e4SLinus Torvalds atkbd->release = code >> 7; 4521da177e4SLinus Torvalds code &= 0x7f; 4531da177e4SLinus Torvalds } 4541da177e4SLinus Torvalds 4550ae051a1SDmitry Torokhov if (!atkbd->emul) 4560ae051a1SDmitry Torokhov atkbd_calculate_xl_bit(atkbd, data); 4571da177e4SLinus Torvalds } 4581da177e4SLinus Torvalds 4591da177e4SLinus Torvalds switch (code) { 4601da177e4SLinus Torvalds case ATKBD_RET_BAT: 461a9a1f9c3SDmitry Torokhov atkbd->enabled = false; 462dbc26344SDmitry Torokhov serio_reconnect(atkbd->ps2dev.serio); 4631da177e4SLinus Torvalds goto out; 4641da177e4SLinus Torvalds case ATKBD_RET_EMUL0: 4651da177e4SLinus Torvalds atkbd->emul = 1; 4661da177e4SLinus Torvalds goto out; 4671da177e4SLinus Torvalds case ATKBD_RET_EMUL1: 4681da177e4SLinus Torvalds atkbd->emul = 2; 4691da177e4SLinus Torvalds goto out; 4701da177e4SLinus Torvalds case ATKBD_RET_RELEASE: 471a9a1f9c3SDmitry Torokhov atkbd->release = true; 4721da177e4SLinus Torvalds goto out; 4730ae051a1SDmitry Torokhov case ATKBD_RET_ACK: 4740ae051a1SDmitry Torokhov case ATKBD_RET_NAK: 4759f7a60d6SQi Yong if (printk_ratelimit()) 476a9a1f9c3SDmitry Torokhov dev_warn(&serio->dev, 477a9a1f9c3SDmitry Torokhov "Spurious %s on %s. " 478f57fe78eSJesper Juhl "Some program might be trying to access hardware directly.\n", 4790ae051a1SDmitry Torokhov data == ATKBD_RET_ACK ? "ACK" : "NAK", serio->phys); 4800ae051a1SDmitry Torokhov goto out; 4811da177e4SLinus Torvalds case ATKBD_RET_ERR: 48286255d9dSDmitry Torokhov atkbd->err_count++; 483a9a1f9c3SDmitry Torokhov dev_dbg(&serio->dev, "Keyboard on %s reports too many keys pressed.\n", 484a9a1f9c3SDmitry Torokhov serio->phys); 4851da177e4SLinus Torvalds goto out; 4861da177e4SLinus Torvalds } 4871da177e4SLinus Torvalds 4880ae051a1SDmitry Torokhov code = atkbd_compat_scancode(atkbd, code); 4890ae051a1SDmitry Torokhov 4900ae051a1SDmitry Torokhov if (atkbd->emul && --atkbd->emul) 4911da177e4SLinus Torvalds goto out; 4921da177e4SLinus Torvalds 4930ae051a1SDmitry Torokhov keycode = atkbd->keycode[code]; 4941da177e4SLinus Torvalds 4955447326fSStefan Brüns if (!(atkbd->release && test_bit(code, atkbd->force_release_mask))) 4960ae051a1SDmitry Torokhov if (keycode != ATKBD_KEY_NULL) 4970ae051a1SDmitry Torokhov input_event(dev, EV_MSC, MSC_SCAN, code); 4980ae051a1SDmitry Torokhov 4990ae051a1SDmitry Torokhov switch (keycode) { 5001da177e4SLinus Torvalds case ATKBD_KEY_NULL: 5011da177e4SLinus Torvalds break; 5021da177e4SLinus Torvalds case ATKBD_KEY_UNKNOWN: 503a9a1f9c3SDmitry Torokhov dev_warn(&serio->dev, 504a9a1f9c3SDmitry Torokhov "Unknown key %s (%s set %d, code %#x on %s).\n", 5051da177e4SLinus Torvalds atkbd->release ? "released" : "pressed", 5061da177e4SLinus Torvalds atkbd->translated ? "translated" : "raw", 5071da177e4SLinus Torvalds atkbd->set, code, serio->phys); 508a9a1f9c3SDmitry Torokhov dev_warn(&serio->dev, 509a9a1f9c3SDmitry Torokhov "Use 'setkeycodes %s%02x <keycode>' to make it known.\n", 5101da177e4SLinus Torvalds code & 0x80 ? "e0" : "", code & 0x7f); 5110ae051a1SDmitry Torokhov input_sync(dev); 5121da177e4SLinus Torvalds break; 5131da177e4SLinus Torvalds case ATKBD_SCR_1: 514a9a1f9c3SDmitry Torokhov scroll = 1; 5151da177e4SLinus Torvalds break; 5161da177e4SLinus Torvalds case ATKBD_SCR_2: 517a9a1f9c3SDmitry Torokhov scroll = 2; 5181da177e4SLinus Torvalds break; 5191da177e4SLinus Torvalds case ATKBD_SCR_4: 520a9a1f9c3SDmitry Torokhov scroll = 4; 5211da177e4SLinus Torvalds break; 5221da177e4SLinus Torvalds case ATKBD_SCR_8: 523a9a1f9c3SDmitry Torokhov scroll = 8; 5241da177e4SLinus Torvalds break; 5251da177e4SLinus Torvalds case ATKBD_SCR_CLICK: 5261da177e4SLinus Torvalds click = !atkbd->release; 5271da177e4SLinus Torvalds break; 5281da177e4SLinus Torvalds case ATKBD_SCR_LEFT: 5291da177e4SLinus Torvalds hscroll = -1; 5301da177e4SLinus Torvalds break; 5311da177e4SLinus Torvalds case ATKBD_SCR_RIGHT: 5321da177e4SLinus Torvalds hscroll = 1; 5331da177e4SLinus Torvalds break; 5341da177e4SLinus Torvalds default: 5350ae051a1SDmitry Torokhov if (atkbd->release) { 5360ae051a1SDmitry Torokhov value = 0; 5371da177e4SLinus Torvalds atkbd->last = 0; 5380ae051a1SDmitry Torokhov } else if (!atkbd->softrepeat && test_bit(keycode, dev->key)) { 5390ae051a1SDmitry Torokhov /* Workaround Toshiba laptop multiple keypress */ 5400ae051a1SDmitry Torokhov value = time_before(jiffies, atkbd->time) && atkbd->last == code ? 1 : 2; 5410ae051a1SDmitry Torokhov } else { 5421da177e4SLinus Torvalds value = 1; 5430ae051a1SDmitry Torokhov atkbd->last = code; 5440ae051a1SDmitry Torokhov atkbd->time = jiffies + msecs_to_jiffies(dev->rep[REP_DELAY]) / 2; 5451da177e4SLinus Torvalds } 5461da177e4SLinus Torvalds 547f8b4c46cSDmitry Torokhov input_event(dev, EV_KEY, keycode, value); 5480ae051a1SDmitry Torokhov input_sync(dev); 5490ae051a1SDmitry Torokhov 550554101e3SGiel de Nijs if (value && test_bit(code, atkbd->force_release_mask)) { 5515447326fSStefan Brüns input_event(dev, EV_MSC, MSC_SCAN, code); 5520ae051a1SDmitry Torokhov input_report_key(dev, keycode, 0); 5530ae051a1SDmitry Torokhov input_sync(dev); 5540ae051a1SDmitry Torokhov } 5551da177e4SLinus Torvalds } 5561da177e4SLinus Torvalds 5571da177e4SLinus Torvalds if (atkbd->scroll) { 5581da177e4SLinus Torvalds if (click != -1) 5590ae051a1SDmitry Torokhov input_report_key(dev, BTN_MIDDLE, click); 560a9a1f9c3SDmitry Torokhov input_report_rel(dev, REL_WHEEL, 561a9a1f9c3SDmitry Torokhov atkbd->release ? -scroll : scroll); 5620ae051a1SDmitry Torokhov input_report_rel(dev, REL_HWHEEL, hscroll); 5630ae051a1SDmitry Torokhov input_sync(dev); 5641da177e4SLinus Torvalds } 5651da177e4SLinus Torvalds 566a9a1f9c3SDmitry Torokhov atkbd->release = false; 5671da177e4SLinus Torvalds out: 5681da177e4SLinus Torvalds return IRQ_HANDLED; 5691da177e4SLinus Torvalds } 5701da177e4SLinus Torvalds 5713d0f0fa0SDmitry Torokhov static int atkbd_set_repeat_rate(struct atkbd *atkbd) 5721da177e4SLinus Torvalds { 5731da177e4SLinus Torvalds const short period[32] = 5741da177e4SLinus Torvalds { 33, 37, 42, 46, 50, 54, 58, 63, 67, 75, 83, 92, 100, 109, 116, 125, 5751da177e4SLinus Torvalds 133, 149, 167, 182, 200, 217, 232, 250, 270, 303, 333, 370, 400, 435, 470, 500 }; 5761da177e4SLinus Torvalds const short delay[4] = 5771da177e4SLinus Torvalds { 250, 500, 750, 1000 }; 5780d4c8597SDmitry Torokhov 5793d0f0fa0SDmitry Torokhov struct input_dev *dev = atkbd->dev; 5803d0f0fa0SDmitry Torokhov unsigned char param; 5813d0f0fa0SDmitry Torokhov int i = 0, j = 0; 5823d0f0fa0SDmitry Torokhov 5833d0f0fa0SDmitry Torokhov while (i < ARRAY_SIZE(period) - 1 && period[i] < dev->rep[REP_PERIOD]) 5843d0f0fa0SDmitry Torokhov i++; 5853d0f0fa0SDmitry Torokhov dev->rep[REP_PERIOD] = period[i]; 5863d0f0fa0SDmitry Torokhov 5878ea371fbSFlorin Malita while (j < ARRAY_SIZE(delay) - 1 && delay[j] < dev->rep[REP_DELAY]) 5883d0f0fa0SDmitry Torokhov j++; 5893d0f0fa0SDmitry Torokhov dev->rep[REP_DELAY] = delay[j]; 5903d0f0fa0SDmitry Torokhov 5913d0f0fa0SDmitry Torokhov param = i | (j << 5); 5923d0f0fa0SDmitry Torokhov return ps2_command(&atkbd->ps2dev, ¶m, ATKBD_CMD_SETREP); 5933d0f0fa0SDmitry Torokhov } 5943d0f0fa0SDmitry Torokhov 5953d0f0fa0SDmitry Torokhov static int atkbd_set_leds(struct atkbd *atkbd) 5963d0f0fa0SDmitry Torokhov { 5970d4c8597SDmitry Torokhov struct input_dev *dev = atkbd->dev; 5981da177e4SLinus Torvalds unsigned char param[2]; 5991da177e4SLinus Torvalds 6001da177e4SLinus Torvalds param[0] = (test_bit(LED_SCROLLL, dev->led) ? 1 : 0) 6011da177e4SLinus Torvalds | (test_bit(LED_NUML, dev->led) ? 2 : 0) 6021da177e4SLinus Torvalds | (test_bit(LED_CAPSL, dev->led) ? 4 : 0); 6033d0f0fa0SDmitry Torokhov if (ps2_command(&atkbd->ps2dev, param, ATKBD_CMD_SETLEDS)) 6043d0f0fa0SDmitry Torokhov return -1; 6051da177e4SLinus Torvalds 6061da177e4SLinus Torvalds if (atkbd->extra) { 6071da177e4SLinus Torvalds param[0] = 0; 6081da177e4SLinus Torvalds param[1] = (test_bit(LED_COMPOSE, dev->led) ? 0x01 : 0) 6091da177e4SLinus Torvalds | (test_bit(LED_SLEEP, dev->led) ? 0x02 : 0) 6101da177e4SLinus Torvalds | (test_bit(LED_SUSPEND, dev->led) ? 0x04 : 0) 6111da177e4SLinus Torvalds | (test_bit(LED_MISC, dev->led) ? 0x10 : 0) 6121da177e4SLinus Torvalds | (test_bit(LED_MUTE, dev->led) ? 0x20 : 0); 6133d0f0fa0SDmitry Torokhov if (ps2_command(&atkbd->ps2dev, param, ATKBD_CMD_EX_SETLEDS)) 6143d0f0fa0SDmitry Torokhov return -1; 6151da177e4SLinus Torvalds } 6161da177e4SLinus Torvalds 6173d0f0fa0SDmitry Torokhov return 0; 6180d4c8597SDmitry Torokhov } 6190d4c8597SDmitry Torokhov 6203d0f0fa0SDmitry Torokhov /* 6213d0f0fa0SDmitry Torokhov * atkbd_event_work() is used to complete processing of events that 6223d0f0fa0SDmitry Torokhov * can not be processed by input_event() which is often called from 6233d0f0fa0SDmitry Torokhov * interrupt context. 6243d0f0fa0SDmitry Torokhov */ 6253d0f0fa0SDmitry Torokhov 62665f27f38SDavid Howells static void atkbd_event_work(struct work_struct *work) 6273d0f0fa0SDmitry Torokhov { 628da4249c9SDmitry Torokhov struct atkbd *atkbd = container_of(work, struct atkbd, event_work.work); 6293d0f0fa0SDmitry Torokhov 63059b01513SEric W. Biederman mutex_lock(&atkbd->mutex); 6313d0f0fa0SDmitry Torokhov 63294dfb0d6SDmitry Torokhov if (!atkbd->enabled) { 63394dfb0d6SDmitry Torokhov /* 63494dfb0d6SDmitry Torokhov * Serio ports are resumed asynchronously so while driver core 63594dfb0d6SDmitry Torokhov * thinks that device is already fully operational in reality 63694dfb0d6SDmitry Torokhov * it may not be ready yet. In this case we need to keep 63794dfb0d6SDmitry Torokhov * rescheduling till reconnect completes. 63894dfb0d6SDmitry Torokhov */ 63994dfb0d6SDmitry Torokhov schedule_delayed_work(&atkbd->event_work, 64094dfb0d6SDmitry Torokhov msecs_to_jiffies(100)); 64194dfb0d6SDmitry Torokhov } else { 6423d0f0fa0SDmitry Torokhov if (test_and_clear_bit(ATKBD_LED_EVENT_BIT, &atkbd->event_mask)) 6433d0f0fa0SDmitry Torokhov atkbd_set_leds(atkbd); 6443d0f0fa0SDmitry Torokhov 6453d0f0fa0SDmitry Torokhov if (test_and_clear_bit(ATKBD_REP_EVENT_BIT, &atkbd->event_mask)) 6463d0f0fa0SDmitry Torokhov atkbd_set_repeat_rate(atkbd); 64794dfb0d6SDmitry Torokhov } 6483d0f0fa0SDmitry Torokhov 64959b01513SEric W. Biederman mutex_unlock(&atkbd->mutex); 6500d4c8597SDmitry Torokhov } 6510d4c8597SDmitry Torokhov 6520d4c8597SDmitry Torokhov /* 653da4249c9SDmitry Torokhov * Schedule switch for execution. We need to throttle requests, 654da4249c9SDmitry Torokhov * otherwise keyboard may become unresponsive. 655da4249c9SDmitry Torokhov */ 656da4249c9SDmitry Torokhov static void atkbd_schedule_event_work(struct atkbd *atkbd, int event_bit) 657da4249c9SDmitry Torokhov { 658da4249c9SDmitry Torokhov unsigned long delay = msecs_to_jiffies(50); 659da4249c9SDmitry Torokhov 660da4249c9SDmitry Torokhov if (time_after(jiffies, atkbd->event_jiffies + delay)) 661da4249c9SDmitry Torokhov delay = 0; 662da4249c9SDmitry Torokhov 663da4249c9SDmitry Torokhov atkbd->event_jiffies = jiffies; 664da4249c9SDmitry Torokhov set_bit(event_bit, &atkbd->event_mask); 66559b01513SEric W. Biederman mb(); 666da4249c9SDmitry Torokhov schedule_delayed_work(&atkbd->event_work, delay); 667da4249c9SDmitry Torokhov } 668da4249c9SDmitry Torokhov 669da4249c9SDmitry Torokhov /* 6700d4c8597SDmitry Torokhov * Event callback from the input module. Events that change the state of 6710d4c8597SDmitry Torokhov * the hardware are processed here. If action can not be performed in 6720d4c8597SDmitry Torokhov * interrupt context it is offloaded to atkbd_event_work. 6730d4c8597SDmitry Torokhov */ 6740d4c8597SDmitry Torokhov 675da4249c9SDmitry Torokhov static int atkbd_event(struct input_dev *dev, 676da4249c9SDmitry Torokhov unsigned int type, unsigned int code, int value) 6770d4c8597SDmitry Torokhov { 678b356872fSDmitry Torokhov struct atkbd *atkbd = input_get_drvdata(dev); 6790d4c8597SDmitry Torokhov 6800d4c8597SDmitry Torokhov if (!atkbd->write) 6810d4c8597SDmitry Torokhov return -1; 6820d4c8597SDmitry Torokhov 6830d4c8597SDmitry Torokhov switch (type) { 6840d4c8597SDmitry Torokhov 6850d4c8597SDmitry Torokhov case EV_LED: 686da4249c9SDmitry Torokhov atkbd_schedule_event_work(atkbd, ATKBD_LED_EVENT_BIT); 6870d4c8597SDmitry Torokhov return 0; 6880d4c8597SDmitry Torokhov 6890d4c8597SDmitry Torokhov case EV_REP: 690da4249c9SDmitry Torokhov if (!atkbd->softrepeat) 691da4249c9SDmitry Torokhov atkbd_schedule_event_work(atkbd, ATKBD_REP_EVENT_BIT); 6921da177e4SLinus Torvalds return 0; 6931da177e4SLinus Torvalds 694a9a1f9c3SDmitry Torokhov default: 6951da177e4SLinus Torvalds return -1; 6961da177e4SLinus Torvalds } 697a9a1f9c3SDmitry Torokhov } 6981da177e4SLinus Torvalds 6991da177e4SLinus Torvalds /* 7001da177e4SLinus Torvalds * atkbd_enable() signals that interrupt handler is allowed to 7011da177e4SLinus Torvalds * generate input events. 7021da177e4SLinus Torvalds */ 7031da177e4SLinus Torvalds 7041da177e4SLinus Torvalds static inline void atkbd_enable(struct atkbd *atkbd) 7051da177e4SLinus Torvalds { 7061da177e4SLinus Torvalds serio_pause_rx(atkbd->ps2dev.serio); 707a9a1f9c3SDmitry Torokhov atkbd->enabled = true; 7081da177e4SLinus Torvalds serio_continue_rx(atkbd->ps2dev.serio); 7091da177e4SLinus Torvalds } 7101da177e4SLinus Torvalds 7111da177e4SLinus Torvalds /* 7121da177e4SLinus Torvalds * atkbd_disable() tells input handler that all incoming data except 7131da177e4SLinus Torvalds * for ACKs and command response should be dropped. 7141da177e4SLinus Torvalds */ 7151da177e4SLinus Torvalds 7161da177e4SLinus Torvalds static inline void atkbd_disable(struct atkbd *atkbd) 7171da177e4SLinus Torvalds { 7181da177e4SLinus Torvalds serio_pause_rx(atkbd->ps2dev.serio); 719a9a1f9c3SDmitry Torokhov atkbd->enabled = false; 7201da177e4SLinus Torvalds serio_continue_rx(atkbd->ps2dev.serio); 7211da177e4SLinus Torvalds } 7221da177e4SLinus Torvalds 723be2d7e42SShawn Nematbakhsh static int atkbd_activate(struct atkbd *atkbd) 724be2d7e42SShawn Nematbakhsh { 725be2d7e42SShawn Nematbakhsh struct ps2dev *ps2dev = &atkbd->ps2dev; 726be2d7e42SShawn Nematbakhsh 727be2d7e42SShawn Nematbakhsh /* 728be2d7e42SShawn Nematbakhsh * Enable the keyboard to receive keystrokes. 729be2d7e42SShawn Nematbakhsh */ 730be2d7e42SShawn Nematbakhsh 731be2d7e42SShawn Nematbakhsh if (ps2_command(ps2dev, NULL, ATKBD_CMD_ENABLE)) { 732be2d7e42SShawn Nematbakhsh dev_err(&ps2dev->serio->dev, 733be2d7e42SShawn Nematbakhsh "Failed to enable keyboard on %s\n", 734be2d7e42SShawn Nematbakhsh ps2dev->serio->phys); 735be2d7e42SShawn Nematbakhsh return -1; 736be2d7e42SShawn Nematbakhsh } 737be2d7e42SShawn Nematbakhsh 738be2d7e42SShawn Nematbakhsh return 0; 739be2d7e42SShawn Nematbakhsh } 740be2d7e42SShawn Nematbakhsh 741be2d7e42SShawn Nematbakhsh /* 742be2d7e42SShawn Nematbakhsh * atkbd_deactivate() resets and disables the keyboard from sending 743be2d7e42SShawn Nematbakhsh * keystrokes. 744be2d7e42SShawn Nematbakhsh */ 745be2d7e42SShawn Nematbakhsh 746be2d7e42SShawn Nematbakhsh static void atkbd_deactivate(struct atkbd *atkbd) 747be2d7e42SShawn Nematbakhsh { 748be2d7e42SShawn Nematbakhsh struct ps2dev *ps2dev = &atkbd->ps2dev; 749be2d7e42SShawn Nematbakhsh 750be2d7e42SShawn Nematbakhsh if (ps2_command(ps2dev, NULL, ATKBD_CMD_RESET_DIS)) 751be2d7e42SShawn Nematbakhsh dev_err(&ps2dev->serio->dev, 752be2d7e42SShawn Nematbakhsh "Failed to deactivate keyboard on %s\n", 753be2d7e42SShawn Nematbakhsh ps2dev->serio->phys); 754be2d7e42SShawn Nematbakhsh } 755be2d7e42SShawn Nematbakhsh 7561da177e4SLinus Torvalds /* 7571da177e4SLinus Torvalds * atkbd_probe() probes for an AT keyboard on a serio port. 7581da177e4SLinus Torvalds */ 7591da177e4SLinus Torvalds 7601da177e4SLinus Torvalds static int atkbd_probe(struct atkbd *atkbd) 7611da177e4SLinus Torvalds { 7621da177e4SLinus Torvalds struct ps2dev *ps2dev = &atkbd->ps2dev; 7631da177e4SLinus Torvalds unsigned char param[2]; 7641da177e4SLinus Torvalds 7651da177e4SLinus Torvalds /* 7661da177e4SLinus Torvalds * Some systems, where the bit-twiddling when testing the io-lines of the 7671da177e4SLinus Torvalds * controller may confuse the keyboard need a full reset of the keyboard. On 7681da177e4SLinus Torvalds * these systems the BIOS also usually doesn't do it for us. 7691da177e4SLinus Torvalds */ 7701da177e4SLinus Torvalds 7711da177e4SLinus Torvalds if (atkbd_reset) 7721da177e4SLinus Torvalds if (ps2_command(ps2dev, NULL, ATKBD_CMD_RESET_BAT)) 773a9a1f9c3SDmitry Torokhov dev_warn(&ps2dev->serio->dev, 774a9a1f9c3SDmitry Torokhov "keyboard reset failed on %s\n", 775a9a1f9c3SDmitry Torokhov ps2dev->serio->phys); 7761da177e4SLinus Torvalds 7771da177e4SLinus Torvalds /* 7781da177e4SLinus Torvalds * Then we check the keyboard ID. We should get 0xab83 under normal conditions. 7791da177e4SLinus Torvalds * Some keyboards report different values, but the first byte is always 0xab or 7801da177e4SLinus Torvalds * 0xac. Some old AT keyboards don't report anything. If a mouse is connected, this 7811da177e4SLinus Torvalds * should make sure we don't try to set the LEDs on it. 7821da177e4SLinus Torvalds */ 7831da177e4SLinus Torvalds 7841da177e4SLinus Torvalds param[0] = param[1] = 0xa5; /* initialize with invalid values */ 7851da177e4SLinus Torvalds if (ps2_command(ps2dev, param, ATKBD_CMD_GETID)) { 7861da177e4SLinus Torvalds 7871da177e4SLinus Torvalds /* 7881da177e4SLinus Torvalds * If the get ID command failed, we check if we can at least set the LEDs on 7891da177e4SLinus Torvalds * the keyboard. This should work on every keyboard out there. It also turns 7901da177e4SLinus Torvalds * the LEDs off, which we want anyway. 7911da177e4SLinus Torvalds */ 7921da177e4SLinus Torvalds param[0] = 0; 7931da177e4SLinus Torvalds if (ps2_command(ps2dev, param, ATKBD_CMD_SETLEDS)) 7941da177e4SLinus Torvalds return -1; 7951da177e4SLinus Torvalds atkbd->id = 0xabba; 7961da177e4SLinus Torvalds return 0; 7971da177e4SLinus Torvalds } 7981da177e4SLinus Torvalds 7999807879bSDmitry Torokhov if (!ps2_is_keyboard_id(param[0])) 8001da177e4SLinus Torvalds return -1; 8011da177e4SLinus Torvalds 8021da177e4SLinus Torvalds atkbd->id = (param[0] << 8) | param[1]; 8031da177e4SLinus Torvalds 8041da177e4SLinus Torvalds if (atkbd->id == 0xaca1 && atkbd->translated) { 805a9a1f9c3SDmitry Torokhov dev_err(&ps2dev->serio->dev, 806236d6a77SDmitry Torokhov "NCD terminal keyboards are only supported on non-translating controllers. " 807a9a1f9c3SDmitry Torokhov "Use i8042.direct=1 to disable translation.\n"); 8081da177e4SLinus Torvalds return -1; 8091da177e4SLinus Torvalds } 8101da177e4SLinus Torvalds 811be2d7e42SShawn Nematbakhsh /* 812be2d7e42SShawn Nematbakhsh * Make sure nothing is coming from the keyboard and disturbs our 813be2d7e42SShawn Nematbakhsh * internal state. 814be2d7e42SShawn Nematbakhsh */ 8153d725caaSSheng-Liang Song if (!atkbd_skip_deactivate) 816be2d7e42SShawn Nematbakhsh atkbd_deactivate(atkbd); 817be2d7e42SShawn Nematbakhsh 8181da177e4SLinus Torvalds return 0; 8191da177e4SLinus Torvalds } 8201da177e4SLinus Torvalds 8211da177e4SLinus Torvalds /* 8221da177e4SLinus Torvalds * atkbd_select_set checks if a keyboard has a working Set 3 support, and 8231da177e4SLinus Torvalds * sets it into that. Unfortunately there are keyboards that can be switched 8241da177e4SLinus Torvalds * to Set 3, but don't work well in that (BTC Multimedia ...) 8251da177e4SLinus Torvalds */ 8261da177e4SLinus Torvalds 8271da177e4SLinus Torvalds static int atkbd_select_set(struct atkbd *atkbd, int target_set, int allow_extra) 8281da177e4SLinus Torvalds { 8291da177e4SLinus Torvalds struct ps2dev *ps2dev = &atkbd->ps2dev; 8301da177e4SLinus Torvalds unsigned char param[2]; 8311da177e4SLinus Torvalds 832a9a1f9c3SDmitry Torokhov atkbd->extra = false; 8331da177e4SLinus Torvalds /* 8341da177e4SLinus Torvalds * For known special keyboards we can go ahead and set the correct set. 8351da177e4SLinus Torvalds * We check for NCD PS/2 Sun, NorthGate OmniKey 101 and 8361da177e4SLinus Torvalds * IBM RapidAccess / IBM EzButton / Chicony KBP-8993 keyboards. 8371da177e4SLinus Torvalds */ 8381da177e4SLinus Torvalds 8391da177e4SLinus Torvalds if (atkbd->translated) 8401da177e4SLinus Torvalds return 2; 8411da177e4SLinus Torvalds 8421da177e4SLinus Torvalds if (atkbd->id == 0xaca1) { 8431da177e4SLinus Torvalds param[0] = 3; 8441da177e4SLinus Torvalds ps2_command(ps2dev, param, ATKBD_CMD_SSCANSET); 8451da177e4SLinus Torvalds return 3; 8461da177e4SLinus Torvalds } 8471da177e4SLinus Torvalds 8481da177e4SLinus Torvalds if (allow_extra) { 8491da177e4SLinus Torvalds param[0] = 0x71; 8501da177e4SLinus Torvalds if (!ps2_command(ps2dev, param, ATKBD_CMD_EX_ENABLE)) { 851a9a1f9c3SDmitry Torokhov atkbd->extra = true; 8521da177e4SLinus Torvalds return 2; 8531da177e4SLinus Torvalds } 8541da177e4SLinus Torvalds } 8551da177e4SLinus Torvalds 8568c5188b6SBenjamin LaHaise if (atkbd_terminal) { 8578c5188b6SBenjamin LaHaise ps2_command(ps2dev, param, ATKBD_CMD_SETALL_MB); 8588c5188b6SBenjamin LaHaise return 3; 8598c5188b6SBenjamin LaHaise } 8608c5188b6SBenjamin LaHaise 8611da177e4SLinus Torvalds if (target_set != 3) 8621da177e4SLinus Torvalds return 2; 8631da177e4SLinus Torvalds 8641da177e4SLinus Torvalds if (!ps2_command(ps2dev, param, ATKBD_CMD_OK_GETID)) { 8651da177e4SLinus Torvalds atkbd->id = param[0] << 8 | param[1]; 8661da177e4SLinus Torvalds return 2; 8671da177e4SLinus Torvalds } 8681da177e4SLinus Torvalds 8691da177e4SLinus Torvalds param[0] = 3; 8701da177e4SLinus Torvalds if (ps2_command(ps2dev, param, ATKBD_CMD_SSCANSET)) 8711da177e4SLinus Torvalds return 2; 8721da177e4SLinus Torvalds 8731da177e4SLinus Torvalds param[0] = 0; 8741da177e4SLinus Torvalds if (ps2_command(ps2dev, param, ATKBD_CMD_GSCANSET)) 8751da177e4SLinus Torvalds return 2; 8761da177e4SLinus Torvalds 8771da177e4SLinus Torvalds if (param[0] != 3) { 8781da177e4SLinus Torvalds param[0] = 2; 8791da177e4SLinus Torvalds if (ps2_command(ps2dev, param, ATKBD_CMD_SSCANSET)) 8801da177e4SLinus Torvalds return 2; 8811da177e4SLinus Torvalds } 8821da177e4SLinus Torvalds 8831da177e4SLinus Torvalds ps2_command(ps2dev, param, ATKBD_CMD_SETALL_MBR); 8841da177e4SLinus Torvalds 8851da177e4SLinus Torvalds return 3; 8861da177e4SLinus Torvalds } 8871da177e4SLinus Torvalds 888fc0eb28cSDmitry Torokhov static int atkbd_reset_state(struct atkbd *atkbd) 889fc0eb28cSDmitry Torokhov { 890fc0eb28cSDmitry Torokhov struct ps2dev *ps2dev = &atkbd->ps2dev; 891fc0eb28cSDmitry Torokhov unsigned char param[1]; 892fc0eb28cSDmitry Torokhov 893fc0eb28cSDmitry Torokhov /* 894fc0eb28cSDmitry Torokhov * Set the LEDs to a predefined state (all off). 895fc0eb28cSDmitry Torokhov */ 896fc0eb28cSDmitry Torokhov 897fc0eb28cSDmitry Torokhov param[0] = 0; 898fc0eb28cSDmitry Torokhov if (ps2_command(ps2dev, param, ATKBD_CMD_SETLEDS)) 899fc0eb28cSDmitry Torokhov return -1; 900fc0eb28cSDmitry Torokhov 901fc0eb28cSDmitry Torokhov /* 902fc0eb28cSDmitry Torokhov * Set autorepeat to fastest possible. 903fc0eb28cSDmitry Torokhov */ 904fc0eb28cSDmitry Torokhov 905fc0eb28cSDmitry Torokhov param[0] = 0; 906fc0eb28cSDmitry Torokhov if (ps2_command(ps2dev, param, ATKBD_CMD_SETREP)) 907fc0eb28cSDmitry Torokhov return -1; 908fc0eb28cSDmitry Torokhov 909fc0eb28cSDmitry Torokhov return 0; 910fc0eb28cSDmitry Torokhov } 911fc0eb28cSDmitry Torokhov 9121da177e4SLinus Torvalds /* 9131da177e4SLinus Torvalds * atkbd_cleanup() restores the keyboard state so that BIOS is happy after a 9141da177e4SLinus Torvalds * reboot. 9151da177e4SLinus Torvalds */ 9161da177e4SLinus Torvalds 9171da177e4SLinus Torvalds static void atkbd_cleanup(struct serio *serio) 9181da177e4SLinus Torvalds { 919*100e1695SDmitry Torokhov struct atkbd *atkbd = atkbd_from_serio(serio); 92057f5b159SDmitry Torokhov 92157f5b159SDmitry Torokhov atkbd_disable(atkbd); 9224a299bf5SDmitry Torokhov ps2_command(&atkbd->ps2dev, NULL, ATKBD_CMD_RESET_DEF); 9231da177e4SLinus Torvalds } 9241da177e4SLinus Torvalds 9251da177e4SLinus Torvalds 9261da177e4SLinus Torvalds /* 9271da177e4SLinus Torvalds * atkbd_disconnect() closes and frees. 9281da177e4SLinus Torvalds */ 9291da177e4SLinus Torvalds 9301da177e4SLinus Torvalds static void atkbd_disconnect(struct serio *serio) 9311da177e4SLinus Torvalds { 932*100e1695SDmitry Torokhov struct atkbd *atkbd = atkbd_from_serio(serio); 9331da177e4SLinus Torvalds 9341da177e4SLinus Torvalds atkbd_disable(atkbd); 9351da177e4SLinus Torvalds 9360ef7a26aSDmitry Torokhov input_unregister_device(atkbd->dev); 9370ef7a26aSDmitry Torokhov 9380ef7a26aSDmitry Torokhov /* 9390ef7a26aSDmitry Torokhov * Make sure we don't have a command in flight. 9400ef7a26aSDmitry Torokhov * Note that since atkbd->enabled is false event work will keep 9410ef7a26aSDmitry Torokhov * rescheduling itself until it gets canceled and will not try 9420ef7a26aSDmitry Torokhov * accessing freed input device or serio port. 9430ef7a26aSDmitry Torokhov */ 944d6d79a78SJiri Pirko cancel_delayed_work_sync(&atkbd->event_work); 9451da177e4SLinus Torvalds 9461da177e4SLinus Torvalds serio_close(serio); 9471da177e4SLinus Torvalds serio_set_drvdata(serio, NULL); 9481da177e4SLinus Torvalds kfree(atkbd); 9491da177e4SLinus Torvalds } 9501da177e4SLinus Torvalds 951554101e3SGiel de Nijs /* 95239191698SDaniel Mierswa * generate release events for the keycodes given in data 95339191698SDaniel Mierswa */ 95439191698SDaniel Mierswa static void atkbd_apply_forced_release_keylist(struct atkbd* atkbd, 95539191698SDaniel Mierswa const void *data) 95639191698SDaniel Mierswa { 95739191698SDaniel Mierswa const unsigned int *keys = data; 95839191698SDaniel Mierswa unsigned int i; 95939191698SDaniel Mierswa 96039191698SDaniel Mierswa if (atkbd->set == 2) 96139191698SDaniel Mierswa for (i = 0; keys[i] != -1U; i++) 96239191698SDaniel Mierswa __set_bit(keys[i], atkbd->force_release_mask); 96339191698SDaniel Mierswa } 96439191698SDaniel Mierswa 96539191698SDaniel Mierswa /* 96661579ba8SMatthew Garrett * Most special keys (Fn+F?) on Dell laptops do not generate release 967554101e3SGiel de Nijs * events so we have to do it ourselves. 968554101e3SGiel de Nijs */ 96939191698SDaniel Mierswa static unsigned int atkbd_dell_laptop_forced_release_keys[] = { 97039191698SDaniel Mierswa 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8f, 0x93, -1U 971554101e3SGiel de Nijs }; 9721da177e4SLinus Torvalds 9731da177e4SLinus Torvalds /* 9745a54c011SJiri Kosina * Perform fixup for HP system that doesn't generate release 9755a54c011SJiri Kosina * for its video switch 9765a54c011SJiri Kosina */ 97739191698SDaniel Mierswa static unsigned int atkbd_hp_forced_release_keys[] = { 97839191698SDaniel Mierswa 0x94, -1U 9795a54c011SJiri Kosina }; 9805a54c011SJiri Kosina 9815a54c011SJiri Kosina /* 982e04126c7SBarry Carroll * Samsung NC10,NC20 with Fn+F? key release not working 9834200844bSStuart Hopkins */ 98439191698SDaniel Mierswa static unsigned int atkbd_samsung_forced_release_keys[] = { 98539191698SDaniel Mierswa 0x82, 0x83, 0x84, 0x86, 0x88, 0x89, 0xb3, 0xf7, 0xf9, -1U 9864200844bSStuart Hopkins }; 9874200844bSStuart Hopkins 9884200844bSStuart Hopkins /* 989f0a14de2SSimon Davie * Amilo Pi 3525 key release for Fn+Volume keys not working 990f0a14de2SSimon Davie */ 991f0a14de2SSimon Davie static unsigned int atkbd_amilo_pi3525_forced_release_keys[] = { 992f0a14de2SSimon Davie 0x20, 0xa0, 0x2e, 0xae, 0x30, 0xb0, -1U 993f0a14de2SSimon Davie }; 994f0a14de2SSimon Davie 995f0a14de2SSimon Davie /* 9969166d0f6SAdrian Batzill * Amilo Xi 3650 key release for light touch bar not working 9979166d0f6SAdrian Batzill */ 9989166d0f6SAdrian Batzill static unsigned int atkbd_amilo_xi3650_forced_release_keys[] = { 9999166d0f6SAdrian Batzill 0x67, 0xed, 0x90, 0xa2, 0x99, 0xa4, 0xae, 0xb0, -1U 10009166d0f6SAdrian Batzill }; 10019166d0f6SAdrian Batzill 10029166d0f6SAdrian Batzill /* 1003032e46cbSJerone Young * Soltech TA12 system with broken key release on volume keys and mute key 1004032e46cbSJerone Young */ 1005032e46cbSJerone Young static unsigned int atkdb_soltech_ta12_forced_release_keys[] = { 1006032e46cbSJerone Young 0xa0, 0xae, 0xb0, -1U 1007032e46cbSJerone Young }; 1008032e46cbSJerone Young 1009032e46cbSJerone Young /* 1010000c2a35SHerton Ronaldo Krzesinski * Many notebooks don't send key release event for volume up/down 1011000c2a35SHerton Ronaldo Krzesinski * keys, with key list below common among them 1012000c2a35SHerton Ronaldo Krzesinski */ 1013000c2a35SHerton Ronaldo Krzesinski static unsigned int atkbd_volume_forced_release_keys[] = { 1014000c2a35SHerton Ronaldo Krzesinski 0xae, 0xb0, -1U 1015000c2a35SHerton Ronaldo Krzesinski }; 1016000c2a35SHerton Ronaldo Krzesinski 1017000c2a35SHerton Ronaldo Krzesinski /* 1018e5713069SJamie Lentin * OQO 01+ multimedia keys (64--66) generate e0 6x upon release whereas 1019e5713069SJamie Lentin * they should be generating e4-e6 (0x80 | code). 1020e5713069SJamie Lentin */ 1021e5713069SJamie Lentin static unsigned int atkbd_oqo_01plus_scancode_fixup(struct atkbd *atkbd, 1022e5713069SJamie Lentin unsigned int code) 1023e5713069SJamie Lentin { 1024e5713069SJamie Lentin if (atkbd->translated && atkbd->emul == 1 && 1025e5713069SJamie Lentin (code == 0x64 || code == 0x65 || code == 0x66)) { 1026e5713069SJamie Lentin atkbd->emul = 0; 1027e5713069SJamie Lentin code |= 0x80; 1028e5713069SJamie Lentin } 1029e5713069SJamie Lentin 1030e5713069SJamie Lentin return code; 1031e5713069SJamie Lentin } 1032e5713069SJamie Lentin 10339d17ad23SRajat Jain static int atkbd_get_keymap_from_fwnode(struct atkbd *atkbd) 10349d17ad23SRajat Jain { 10359d17ad23SRajat Jain struct device *dev = &atkbd->ps2dev.serio->dev; 10369d17ad23SRajat Jain int i, n; 10379d17ad23SRajat Jain u32 *ptr; 10389d17ad23SRajat Jain u16 scancode, keycode; 10399d17ad23SRajat Jain 10409d17ad23SRajat Jain /* Parse "linux,keymap" property */ 10419d17ad23SRajat Jain n = device_property_count_u32(dev, "linux,keymap"); 10429d17ad23SRajat Jain if (n <= 0 || n > ATKBD_KEYMAP_SIZE) 10439d17ad23SRajat Jain return -ENXIO; 10449d17ad23SRajat Jain 10459d17ad23SRajat Jain ptr = kcalloc(n, sizeof(u32), GFP_KERNEL); 10469d17ad23SRajat Jain if (!ptr) 10479d17ad23SRajat Jain return -ENOMEM; 10489d17ad23SRajat Jain 10499d17ad23SRajat Jain if (device_property_read_u32_array(dev, "linux,keymap", ptr, n)) { 10509d17ad23SRajat Jain dev_err(dev, "problem parsing FW keymap property\n"); 10519d17ad23SRajat Jain kfree(ptr); 10529d17ad23SRajat Jain return -EINVAL; 10539d17ad23SRajat Jain } 10549d17ad23SRajat Jain 10559d17ad23SRajat Jain memset(atkbd->keycode, 0, sizeof(atkbd->keycode)); 10569d17ad23SRajat Jain for (i = 0; i < n; i++) { 10579d17ad23SRajat Jain scancode = SCANCODE(ptr[i]); 10589d17ad23SRajat Jain keycode = KEYCODE(ptr[i]); 10599d17ad23SRajat Jain atkbd->keycode[scancode] = keycode; 10609d17ad23SRajat Jain } 10619d17ad23SRajat Jain 10629d17ad23SRajat Jain kfree(ptr); 10639d17ad23SRajat Jain return 0; 10649d17ad23SRajat Jain } 10659d17ad23SRajat Jain 1066e5713069SJamie Lentin /* 10673c42f0c3SDmitry Torokhov * atkbd_set_keycode_table() initializes keyboard's keycode table 10681da177e4SLinus Torvalds * according to the selected scancode set 10691da177e4SLinus Torvalds */ 10701da177e4SLinus Torvalds 10711da177e4SLinus Torvalds static void atkbd_set_keycode_table(struct atkbd *atkbd) 10721da177e4SLinus Torvalds { 10739d17ad23SRajat Jain struct device *dev = &atkbd->ps2dev.serio->dev; 1074554101e3SGiel de Nijs unsigned int scancode; 10751da177e4SLinus Torvalds int i, j; 10761da177e4SLinus Torvalds 10771da177e4SLinus Torvalds memset(atkbd->keycode, 0, sizeof(atkbd->keycode)); 10781ba36e11SDmitry Torokhov bitmap_zero(atkbd->force_release_mask, ATKBD_KEYMAP_SIZE); 10791da177e4SLinus Torvalds 10809d17ad23SRajat Jain if (!atkbd_get_keymap_from_fwnode(atkbd)) { 10819d17ad23SRajat Jain dev_dbg(dev, "Using FW keymap\n"); 10829d17ad23SRajat Jain } else if (atkbd->translated) { 10831da177e4SLinus Torvalds for (i = 0; i < 128; i++) { 1084554101e3SGiel de Nijs scancode = atkbd_unxlate_table[i]; 1085554101e3SGiel de Nijs atkbd->keycode[i] = atkbd_set2_keycode[scancode]; 1086554101e3SGiel de Nijs atkbd->keycode[i | 0x80] = atkbd_set2_keycode[scancode | 0x80]; 10871da177e4SLinus Torvalds if (atkbd->scroll) 10881da177e4SLinus Torvalds for (j = 0; j < ARRAY_SIZE(atkbd_scroll_keys); j++) 1089554101e3SGiel de Nijs if ((scancode | 0x80) == atkbd_scroll_keys[j].set2) 10901da177e4SLinus Torvalds atkbd->keycode[i | 0x80] = atkbd_scroll_keys[j].keycode; 10911da177e4SLinus Torvalds } 10921da177e4SLinus Torvalds } else if (atkbd->set == 3) { 10931da177e4SLinus Torvalds memcpy(atkbd->keycode, atkbd_set3_keycode, sizeof(atkbd->keycode)); 10941da177e4SLinus Torvalds } else { 10951da177e4SLinus Torvalds memcpy(atkbd->keycode, atkbd_set2_keycode, sizeof(atkbd->keycode)); 10961da177e4SLinus Torvalds 10971da177e4SLinus Torvalds if (atkbd->scroll) 1098554101e3SGiel de Nijs for (i = 0; i < ARRAY_SIZE(atkbd_scroll_keys); i++) { 1099554101e3SGiel de Nijs scancode = atkbd_scroll_keys[i].set2; 1100554101e3SGiel de Nijs atkbd->keycode[scancode] = atkbd_scroll_keys[i].keycode; 1101554101e3SGiel de Nijs } 11021da177e4SLinus Torvalds } 11030ae051a1SDmitry Torokhov 1104554101e3SGiel de Nijs /* 1105554101e3SGiel de Nijs * HANGEUL and HANJA keys do not send release events so we need to 1106554101e3SGiel de Nijs * generate such events ourselves 1107554101e3SGiel de Nijs */ 1108554101e3SGiel de Nijs scancode = atkbd_compat_scancode(atkbd, ATKBD_RET_HANGEUL); 1109554101e3SGiel de Nijs atkbd->keycode[scancode] = KEY_HANGEUL; 1110554101e3SGiel de Nijs __set_bit(scancode, atkbd->force_release_mask); 1111554101e3SGiel de Nijs 1112554101e3SGiel de Nijs scancode = atkbd_compat_scancode(atkbd, ATKBD_RET_HANJA); 1113554101e3SGiel de Nijs atkbd->keycode[scancode] = KEY_HANJA; 1114554101e3SGiel de Nijs __set_bit(scancode, atkbd->force_release_mask); 1115554101e3SGiel de Nijs 1116554101e3SGiel de Nijs /* 1117554101e3SGiel de Nijs * Perform additional fixups 1118554101e3SGiel de Nijs */ 1119554101e3SGiel de Nijs if (atkbd_platform_fixup) 112039191698SDaniel Mierswa atkbd_platform_fixup(atkbd, atkbd_platform_fixup_data); 11211da177e4SLinus Torvalds } 11221da177e4SLinus Torvalds 11231da177e4SLinus Torvalds /* 11241da177e4SLinus Torvalds * atkbd_set_device_attrs() sets up keyboard's input device structure 11251da177e4SLinus Torvalds */ 11261da177e4SLinus Torvalds 11271da177e4SLinus Torvalds static void atkbd_set_device_attrs(struct atkbd *atkbd) 11281da177e4SLinus Torvalds { 11293c42f0c3SDmitry Torokhov struct input_dev *input_dev = atkbd->dev; 11301da177e4SLinus Torvalds int i; 11311da177e4SLinus Torvalds 11323c42f0c3SDmitry Torokhov if (atkbd->extra) 1133ea08c6faSDmitry Torokhov snprintf(atkbd->name, sizeof(atkbd->name), 1134ea08c6faSDmitry Torokhov "AT Set 2 Extra keyboard"); 11353c42f0c3SDmitry Torokhov else 1136ea08c6faSDmitry Torokhov snprintf(atkbd->name, sizeof(atkbd->name), 1137ea08c6faSDmitry Torokhov "AT %s Set %d keyboard", 11383c42f0c3SDmitry Torokhov atkbd->translated ? "Translated" : "Raw", atkbd->set); 11391da177e4SLinus Torvalds 1140ea08c6faSDmitry Torokhov snprintf(atkbd->phys, sizeof(atkbd->phys), 1141ea08c6faSDmitry Torokhov "%s/input0", atkbd->ps2dev.serio->phys); 11421da177e4SLinus Torvalds 11433c42f0c3SDmitry Torokhov input_dev->name = atkbd->name; 11443c42f0c3SDmitry Torokhov input_dev->phys = atkbd->phys; 11453c42f0c3SDmitry Torokhov input_dev->id.bustype = BUS_I8042; 11463c42f0c3SDmitry Torokhov input_dev->id.vendor = 0x0001; 11473c42f0c3SDmitry Torokhov input_dev->id.product = atkbd->translated ? 1 : atkbd->set; 11483c42f0c3SDmitry Torokhov input_dev->id.version = atkbd->id; 11493c42f0c3SDmitry Torokhov input_dev->event = atkbd_event; 1150469ba4dfSDmitry Torokhov input_dev->dev.parent = &atkbd->ps2dev.serio->dev; 11511da177e4SLinus Torvalds 1152b356872fSDmitry Torokhov input_set_drvdata(input_dev, atkbd); 1153b356872fSDmitry Torokhov 11547b19ada2SJiri Slaby input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP) | 11557b19ada2SJiri Slaby BIT_MASK(EV_MSC); 11561da177e4SLinus Torvalds 11571da177e4SLinus Torvalds if (atkbd->write) { 11587b19ada2SJiri Slaby input_dev->evbit[0] |= BIT_MASK(EV_LED); 11597b19ada2SJiri Slaby input_dev->ledbit[0] = BIT_MASK(LED_NUML) | 11607b19ada2SJiri Slaby BIT_MASK(LED_CAPSL) | BIT_MASK(LED_SCROLLL); 11611da177e4SLinus Torvalds } 11621da177e4SLinus Torvalds 11631da177e4SLinus Torvalds if (atkbd->extra) 11647b19ada2SJiri Slaby input_dev->ledbit[0] |= BIT_MASK(LED_COMPOSE) | 11657b19ada2SJiri Slaby BIT_MASK(LED_SUSPEND) | BIT_MASK(LED_SLEEP) | 11667b19ada2SJiri Slaby BIT_MASK(LED_MUTE) | BIT_MASK(LED_MISC); 11671da177e4SLinus Torvalds 11681da177e4SLinus Torvalds if (!atkbd->softrepeat) { 11693c42f0c3SDmitry Torokhov input_dev->rep[REP_DELAY] = 250; 11703c42f0c3SDmitry Torokhov input_dev->rep[REP_PERIOD] = 33; 11711da177e4SLinus Torvalds } 11721da177e4SLinus Torvalds 11737b19ada2SJiri Slaby input_dev->mscbit[0] = atkbd->softraw ? BIT_MASK(MSC_SCAN) : 11747b19ada2SJiri Slaby BIT_MASK(MSC_RAW) | BIT_MASK(MSC_SCAN); 11751da177e4SLinus Torvalds 11761da177e4SLinus Torvalds if (atkbd->scroll) { 11777b19ada2SJiri Slaby input_dev->evbit[0] |= BIT_MASK(EV_REL); 11787b19ada2SJiri Slaby input_dev->relbit[0] = BIT_MASK(REL_WHEEL) | 11797b19ada2SJiri Slaby BIT_MASK(REL_HWHEEL); 1180f6d65610SDmitry Torokhov __set_bit(BTN_MIDDLE, input_dev->keybit); 11811da177e4SLinus Torvalds } 11821da177e4SLinus Torvalds 11833c42f0c3SDmitry Torokhov input_dev->keycode = atkbd->keycode; 1184f6d65610SDmitry Torokhov input_dev->keycodesize = sizeof(unsigned short); 11853c42f0c3SDmitry Torokhov input_dev->keycodemax = ARRAY_SIZE(atkbd_set2_keycode); 11861da177e4SLinus Torvalds 11874b70858bSDmitry Torokhov for (i = 0; i < ATKBD_KEYMAP_SIZE; i++) { 11884b70858bSDmitry Torokhov if (atkbd->keycode[i] != KEY_RESERVED && 11894b70858bSDmitry Torokhov atkbd->keycode[i] != ATKBD_KEY_NULL && 11904b70858bSDmitry Torokhov atkbd->keycode[i] < ATKBD_SPECIAL) { 1191f6d65610SDmitry Torokhov __set_bit(atkbd->keycode[i], input_dev->keybit); 11921da177e4SLinus Torvalds } 11934b70858bSDmitry Torokhov } 11944b70858bSDmitry Torokhov } 11951da177e4SLinus Torvalds 11968f7b057aSRajat Jain static void atkbd_parse_fwnode_data(struct serio *serio) 11978f7b057aSRajat Jain { 1198*100e1695SDmitry Torokhov struct atkbd *atkbd = atkbd_from_serio(serio); 11998f7b057aSRajat Jain struct device *dev = &serio->dev; 12008f7b057aSRajat Jain int n; 12018f7b057aSRajat Jain 12028f7b057aSRajat Jain /* Parse "function-row-physmap" property */ 12038f7b057aSRajat Jain n = device_property_count_u32(dev, "function-row-physmap"); 120445ceaf14SStephen Boyd if (n > 0 && n <= VIVALDI_MAX_FUNCTION_ROW_KEYS && 12058f7b057aSRajat Jain !device_property_read_u32_array(dev, "function-row-physmap", 120645ceaf14SStephen Boyd atkbd->vdata.function_row_physmap, 120745ceaf14SStephen Boyd n)) { 120845ceaf14SStephen Boyd atkbd->vdata.num_function_row_keys = n; 12098f7b057aSRajat Jain dev_dbg(dev, "FW reported %d function-row key locations\n", n); 12108f7b057aSRajat Jain } 12118f7b057aSRajat Jain } 12128f7b057aSRajat Jain 12131da177e4SLinus Torvalds /* 12141da177e4SLinus Torvalds * atkbd_connect() is called when the serio module finds an interface 12151da177e4SLinus Torvalds * that isn't handled yet by an appropriate device driver. We check if 12161da177e4SLinus Torvalds * there is an AT keyboard out there and if yes, we register ourselves 12171da177e4SLinus Torvalds * to the input module. 12181da177e4SLinus Torvalds */ 12191da177e4SLinus Torvalds 12201da177e4SLinus Torvalds static int atkbd_connect(struct serio *serio, struct serio_driver *drv) 12211da177e4SLinus Torvalds { 12221da177e4SLinus Torvalds struct atkbd *atkbd; 12233c42f0c3SDmitry Torokhov struct input_dev *dev; 12243c42f0c3SDmitry Torokhov int err = -ENOMEM; 12251da177e4SLinus Torvalds 12263c42f0c3SDmitry Torokhov atkbd = kzalloc(sizeof(struct atkbd), GFP_KERNEL); 12273c42f0c3SDmitry Torokhov dev = input_allocate_device(); 12283c42f0c3SDmitry Torokhov if (!atkbd || !dev) 12292b03b60eSDmitry Torokhov goto fail1; 12301da177e4SLinus Torvalds 12313c42f0c3SDmitry Torokhov atkbd->dev = dev; 12321da177e4SLinus Torvalds ps2_init(&atkbd->ps2dev, serio); 1233da4249c9SDmitry Torokhov INIT_DELAYED_WORK(&atkbd->event_work, atkbd_event_work); 123459b01513SEric W. Biederman mutex_init(&atkbd->mutex); 12351da177e4SLinus Torvalds 12361da177e4SLinus Torvalds switch (serio->id.type) { 12371da177e4SLinus Torvalds 12381da177e4SLinus Torvalds case SERIO_8042_XL: 1239a9a1f9c3SDmitry Torokhov atkbd->translated = true; 12406f49c4f5SGustavo A. R. Silva fallthrough; 1241a9a1f9c3SDmitry Torokhov 12421da177e4SLinus Torvalds case SERIO_8042: 12431da177e4SLinus Torvalds if (serio->write) 1244a9a1f9c3SDmitry Torokhov atkbd->write = true; 12451da177e4SLinus Torvalds break; 12461da177e4SLinus Torvalds } 12471da177e4SLinus Torvalds 12481da177e4SLinus Torvalds atkbd->softraw = atkbd_softraw; 12491da177e4SLinus Torvalds atkbd->softrepeat = atkbd_softrepeat; 12501da177e4SLinus Torvalds atkbd->scroll = atkbd_scroll; 12511da177e4SLinus Torvalds 12521da177e4SLinus Torvalds if (atkbd->softrepeat) 1253a9a1f9c3SDmitry Torokhov atkbd->softraw = true; 12541da177e4SLinus Torvalds 12551da177e4SLinus Torvalds serio_set_drvdata(serio, atkbd); 12561da177e4SLinus Torvalds 12571da177e4SLinus Torvalds err = serio_open(serio, drv); 12583c42f0c3SDmitry Torokhov if (err) 12592b03b60eSDmitry Torokhov goto fail2; 12601da177e4SLinus Torvalds 12611da177e4SLinus Torvalds if (atkbd->write) { 12621da177e4SLinus Torvalds 12631da177e4SLinus Torvalds if (atkbd_probe(atkbd)) { 12643c42f0c3SDmitry Torokhov err = -ENODEV; 12652b03b60eSDmitry Torokhov goto fail3; 12661da177e4SLinus Torvalds } 12671da177e4SLinus Torvalds 12681da177e4SLinus Torvalds atkbd->set = atkbd_select_set(atkbd, atkbd_set, atkbd_extra); 1269fc0eb28cSDmitry Torokhov atkbd_reset_state(atkbd); 12701da177e4SLinus Torvalds 12711da177e4SLinus Torvalds } else { 12721da177e4SLinus Torvalds atkbd->set = 2; 12731da177e4SLinus Torvalds atkbd->id = 0xab00; 12741da177e4SLinus Torvalds } 12751da177e4SLinus Torvalds 12768f7b057aSRajat Jain atkbd_parse_fwnode_data(serio); 12778f7b057aSRajat Jain 12781da177e4SLinus Torvalds atkbd_set_keycode_table(atkbd); 12791da177e4SLinus Torvalds atkbd_set_device_attrs(atkbd); 12801da177e4SLinus Torvalds 12811da177e4SLinus Torvalds atkbd_enable(atkbd); 1282be2d7e42SShawn Nematbakhsh if (serio->write) 1283be2d7e42SShawn Nematbakhsh atkbd_activate(atkbd); 12841da177e4SLinus Torvalds 12852b03b60eSDmitry Torokhov err = input_register_device(atkbd->dev); 12862b03b60eSDmitry Torokhov if (err) 1287c99e3ac6SDmitry Torokhov goto fail3; 12881da177e4SLinus Torvalds 12891da177e4SLinus Torvalds return 0; 12903c42f0c3SDmitry Torokhov 12912b03b60eSDmitry Torokhov fail3: serio_close(serio); 12922b03b60eSDmitry Torokhov fail2: serio_set_drvdata(serio, NULL); 12932b03b60eSDmitry Torokhov fail1: input_free_device(dev); 12943c42f0c3SDmitry Torokhov kfree(atkbd); 12953c42f0c3SDmitry Torokhov return err; 12961da177e4SLinus Torvalds } 12971da177e4SLinus Torvalds 12981da177e4SLinus Torvalds /* 12991da177e4SLinus Torvalds * atkbd_reconnect() tries to restore keyboard into a sane state and is 13001da177e4SLinus Torvalds * most likely called on resume. 13011da177e4SLinus Torvalds */ 13021da177e4SLinus Torvalds 13031da177e4SLinus Torvalds static int atkbd_reconnect(struct serio *serio) 13041da177e4SLinus Torvalds { 1305*100e1695SDmitry Torokhov struct atkbd *atkbd = atkbd_from_serio(serio); 13061da177e4SLinus Torvalds struct serio_driver *drv = serio->drv; 130759b01513SEric W. Biederman int retval = -1; 13081da177e4SLinus Torvalds 13091da177e4SLinus Torvalds if (!atkbd || !drv) { 1310a9a1f9c3SDmitry Torokhov dev_dbg(&serio->dev, 1311a9a1f9c3SDmitry Torokhov "reconnect request, but serio is disconnected, ignoring...\n"); 13121da177e4SLinus Torvalds return -1; 13131da177e4SLinus Torvalds } 13141da177e4SLinus Torvalds 131559b01513SEric W. Biederman mutex_lock(&atkbd->mutex); 131659b01513SEric W. Biederman 13171da177e4SLinus Torvalds atkbd_disable(atkbd); 13181da177e4SLinus Torvalds 13191da177e4SLinus Torvalds if (atkbd->write) { 13201da177e4SLinus Torvalds if (atkbd_probe(atkbd)) 132159b01513SEric W. Biederman goto out; 132259b01513SEric W. Biederman 13231da177e4SLinus Torvalds if (atkbd->set != atkbd_select_set(atkbd, atkbd->set, atkbd->extra)) 132459b01513SEric W. Biederman goto out; 13251da177e4SLinus Torvalds 1326d4119bdaSDmitry Torokhov /* 1327d4119bdaSDmitry Torokhov * Restore LED state and repeat rate. While input core 1328d4119bdaSDmitry Torokhov * will do this for us at resume time reconnect may happen 1329d4119bdaSDmitry Torokhov * because user requested it via sysfs or simply because 1330d4119bdaSDmitry Torokhov * keyboard was unplugged and plugged in again so we need 1331d4119bdaSDmitry Torokhov * to do it ourselves here. 1332d4119bdaSDmitry Torokhov */ 1333d4119bdaSDmitry Torokhov atkbd_set_leds(atkbd); 1334d4119bdaSDmitry Torokhov if (!atkbd->softrepeat) 1335d4119bdaSDmitry Torokhov atkbd_set_repeat_rate(atkbd); 1336d4119bdaSDmitry Torokhov 13371da177e4SLinus Torvalds } 13381da177e4SLinus Torvalds 1339be2d7e42SShawn Nematbakhsh /* 1340be2d7e42SShawn Nematbakhsh * Reset our state machine in case reconnect happened in the middle 1341be2d7e42SShawn Nematbakhsh * of multi-byte scancode. 1342be2d7e42SShawn Nematbakhsh */ 1343be2d7e42SShawn Nematbakhsh atkbd->xl_bit = 0; 1344be2d7e42SShawn Nematbakhsh atkbd->emul = 0; 1345be2d7e42SShawn Nematbakhsh 13461da177e4SLinus Torvalds atkbd_enable(atkbd); 1347be2d7e42SShawn Nematbakhsh if (atkbd->write) 1348be2d7e42SShawn Nematbakhsh atkbd_activate(atkbd); 1349be2d7e42SShawn Nematbakhsh 135059b01513SEric W. Biederman retval = 0; 13511da177e4SLinus Torvalds 135259b01513SEric W. Biederman out: 135359b01513SEric W. Biederman mutex_unlock(&atkbd->mutex); 135459b01513SEric W. Biederman return retval; 13551da177e4SLinus Torvalds } 13561da177e4SLinus Torvalds 1357af2e7d77SArvind Yadav static const struct serio_device_id atkbd_serio_ids[] = { 13581da177e4SLinus Torvalds { 13591da177e4SLinus Torvalds .type = SERIO_8042, 13601da177e4SLinus Torvalds .proto = SERIO_ANY, 13611da177e4SLinus Torvalds .id = SERIO_ANY, 13621da177e4SLinus Torvalds .extra = SERIO_ANY, 13631da177e4SLinus Torvalds }, 13641da177e4SLinus Torvalds { 13651da177e4SLinus Torvalds .type = SERIO_8042_XL, 13661da177e4SLinus Torvalds .proto = SERIO_ANY, 13671da177e4SLinus Torvalds .id = SERIO_ANY, 13681da177e4SLinus Torvalds .extra = SERIO_ANY, 13691da177e4SLinus Torvalds }, 13701da177e4SLinus Torvalds { 13711da177e4SLinus Torvalds .type = SERIO_RS232, 13721da177e4SLinus Torvalds .proto = SERIO_PS2SER, 13731da177e4SLinus Torvalds .id = SERIO_ANY, 13741da177e4SLinus Torvalds .extra = SERIO_ANY, 13751da177e4SLinus Torvalds }, 13761da177e4SLinus Torvalds { 0 } 13771da177e4SLinus Torvalds }; 13781da177e4SLinus Torvalds 13791da177e4SLinus Torvalds MODULE_DEVICE_TABLE(serio, atkbd_serio_ids); 13801da177e4SLinus Torvalds 13811da177e4SLinus Torvalds static struct serio_driver atkbd_drv = { 13821da177e4SLinus Torvalds .driver = { 13831da177e4SLinus Torvalds .name = "atkbd", 1384c99e3ac6SDmitry Torokhov .dev_groups = atkbd_attribute_groups, 13851da177e4SLinus Torvalds }, 13861da177e4SLinus Torvalds .description = DRIVER_DESC, 13871da177e4SLinus Torvalds .id_table = atkbd_serio_ids, 13881da177e4SLinus Torvalds .interrupt = atkbd_interrupt, 13891da177e4SLinus Torvalds .connect = atkbd_connect, 13901da177e4SLinus Torvalds .reconnect = atkbd_reconnect, 13911da177e4SLinus Torvalds .disconnect = atkbd_disconnect, 13921da177e4SLinus Torvalds .cleanup = atkbd_cleanup, 13931da177e4SLinus Torvalds }; 13941da177e4SLinus Torvalds 13951da177e4SLinus Torvalds static ssize_t atkbd_attr_show_helper(struct device *dev, char *buf, 13961da177e4SLinus Torvalds ssize_t (*handler)(struct atkbd *, char *)) 13971da177e4SLinus Torvalds { 13981da177e4SLinus Torvalds struct serio *serio = to_serio_port(dev); 1399*100e1695SDmitry Torokhov struct atkbd *atkbd = atkbd_from_serio(serio); 14001da177e4SLinus Torvalds 140159b01513SEric W. Biederman return handler(atkbd, buf); 14021da177e4SLinus Torvalds } 14031da177e4SLinus Torvalds 14041da177e4SLinus Torvalds static ssize_t atkbd_attr_set_helper(struct device *dev, const char *buf, size_t count, 14051da177e4SLinus Torvalds ssize_t (*handler)(struct atkbd *, const char *, size_t)) 14061da177e4SLinus Torvalds { 14071da177e4SLinus Torvalds struct serio *serio = to_serio_port(dev); 1408*100e1695SDmitry Torokhov struct atkbd *atkbd = atkbd_from_serio(serio); 14091da177e4SLinus Torvalds int retval; 14101da177e4SLinus Torvalds 141159b01513SEric W. Biederman retval = mutex_lock_interruptible(&atkbd->mutex); 14121da177e4SLinus Torvalds if (retval) 14131da177e4SLinus Torvalds return retval; 14141da177e4SLinus Torvalds 14151da177e4SLinus Torvalds atkbd_disable(atkbd); 14161da177e4SLinus Torvalds retval = handler(atkbd, buf, count); 14171da177e4SLinus Torvalds atkbd_enable(atkbd); 14181da177e4SLinus Torvalds 141959b01513SEric W. Biederman mutex_unlock(&atkbd->mutex); 142059b01513SEric W. Biederman 14211da177e4SLinus Torvalds return retval; 14221da177e4SLinus Torvalds } 14231da177e4SLinus Torvalds 14241da177e4SLinus Torvalds static ssize_t atkbd_show_extra(struct atkbd *atkbd, char *buf) 14251da177e4SLinus Torvalds { 14261da177e4SLinus Torvalds return sprintf(buf, "%d\n", atkbd->extra ? 1 : 0); 14271da177e4SLinus Torvalds } 14281da177e4SLinus Torvalds 14291da177e4SLinus Torvalds static ssize_t atkbd_set_extra(struct atkbd *atkbd, const char *buf, size_t count) 14301da177e4SLinus Torvalds { 14312b03b60eSDmitry Torokhov struct input_dev *old_dev, *new_dev; 143276496e7aSJJ Ding unsigned int value; 14332b03b60eSDmitry Torokhov int err; 1434a9a1f9c3SDmitry Torokhov bool old_extra; 1435a9a1f9c3SDmitry Torokhov unsigned char old_set; 14361da177e4SLinus Torvalds 14371da177e4SLinus Torvalds if (!atkbd->write) 14381da177e4SLinus Torvalds return -EIO; 14391da177e4SLinus Torvalds 144076496e7aSJJ Ding err = kstrtouint(buf, 10, &value); 144176496e7aSJJ Ding if (err) 144276496e7aSJJ Ding return err; 144376496e7aSJJ Ding 144476496e7aSJJ Ding if (value > 1) 14451da177e4SLinus Torvalds return -EINVAL; 14461da177e4SLinus Torvalds 14471da177e4SLinus Torvalds if (atkbd->extra != value) { 14483c42f0c3SDmitry Torokhov /* 14493c42f0c3SDmitry Torokhov * Since device's properties will change we need to 14502b03b60eSDmitry Torokhov * unregister old device. But allocate and register 14512b03b60eSDmitry Torokhov * new one first to make sure we have it. 14523c42f0c3SDmitry Torokhov */ 14532b03b60eSDmitry Torokhov old_dev = atkbd->dev; 14542b03b60eSDmitry Torokhov old_extra = atkbd->extra; 14552b03b60eSDmitry Torokhov old_set = atkbd->set; 14562b03b60eSDmitry Torokhov 14572b03b60eSDmitry Torokhov new_dev = input_allocate_device(); 14582b03b60eSDmitry Torokhov if (!new_dev) 14593c42f0c3SDmitry Torokhov return -ENOMEM; 14602b03b60eSDmitry Torokhov 14613c42f0c3SDmitry Torokhov atkbd->dev = new_dev; 14621da177e4SLinus Torvalds atkbd->set = atkbd_select_set(atkbd, atkbd->set, value); 1463fc0eb28cSDmitry Torokhov atkbd_reset_state(atkbd); 14641da177e4SLinus Torvalds atkbd_activate(atkbd); 14652b03b60eSDmitry Torokhov atkbd_set_keycode_table(atkbd); 14661da177e4SLinus Torvalds atkbd_set_device_attrs(atkbd); 14672b03b60eSDmitry Torokhov 14682b03b60eSDmitry Torokhov err = input_register_device(atkbd->dev); 14692b03b60eSDmitry Torokhov if (err) { 14702b03b60eSDmitry Torokhov input_free_device(new_dev); 14712b03b60eSDmitry Torokhov 14722b03b60eSDmitry Torokhov atkbd->dev = old_dev; 14732b03b60eSDmitry Torokhov atkbd->set = atkbd_select_set(atkbd, old_set, old_extra); 14742b03b60eSDmitry Torokhov atkbd_set_keycode_table(atkbd); 14752b03b60eSDmitry Torokhov atkbd_set_device_attrs(atkbd); 14762b03b60eSDmitry Torokhov 14772b03b60eSDmitry Torokhov return err; 14782b03b60eSDmitry Torokhov } 14792b03b60eSDmitry Torokhov input_unregister_device(old_dev); 14802b03b60eSDmitry Torokhov 14811da177e4SLinus Torvalds } 14821da177e4SLinus Torvalds return count; 14831da177e4SLinus Torvalds } 14841da177e4SLinus Torvalds 14851ba36e11SDmitry Torokhov static ssize_t atkbd_show_force_release(struct atkbd *atkbd, char *buf) 14861ba36e11SDmitry Torokhov { 14870b480037STejun Heo size_t len = scnprintf(buf, PAGE_SIZE - 1, "%*pbl", 14880b480037STejun Heo ATKBD_KEYMAP_SIZE, atkbd->force_release_mask); 14891ba36e11SDmitry Torokhov 14901ba36e11SDmitry Torokhov buf[len++] = '\n'; 14911ba36e11SDmitry Torokhov buf[len] = '\0'; 14921ba36e11SDmitry Torokhov 14931ba36e11SDmitry Torokhov return len; 14941ba36e11SDmitry Torokhov } 14951ba36e11SDmitry Torokhov 14961ba36e11SDmitry Torokhov static ssize_t atkbd_set_force_release(struct atkbd *atkbd, 14971ba36e11SDmitry Torokhov const char *buf, size_t count) 14981ba36e11SDmitry Torokhov { 14991ba36e11SDmitry Torokhov /* 64 bytes on stack should be acceptable */ 15001ba36e11SDmitry Torokhov DECLARE_BITMAP(new_mask, ATKBD_KEYMAP_SIZE); 15011ba36e11SDmitry Torokhov int err; 15021ba36e11SDmitry Torokhov 15031ba36e11SDmitry Torokhov err = bitmap_parselist(buf, new_mask, ATKBD_KEYMAP_SIZE); 15041ba36e11SDmitry Torokhov if (err) 15051ba36e11SDmitry Torokhov return err; 15061ba36e11SDmitry Torokhov 15071ba36e11SDmitry Torokhov memcpy(atkbd->force_release_mask, new_mask, sizeof(atkbd->force_release_mask)); 15081ba36e11SDmitry Torokhov return count; 15091ba36e11SDmitry Torokhov } 15101ba36e11SDmitry Torokhov 15111ba36e11SDmitry Torokhov 15121da177e4SLinus Torvalds static ssize_t atkbd_show_scroll(struct atkbd *atkbd, char *buf) 15131da177e4SLinus Torvalds { 15141da177e4SLinus Torvalds return sprintf(buf, "%d\n", atkbd->scroll ? 1 : 0); 15151da177e4SLinus Torvalds } 15161da177e4SLinus Torvalds 15171da177e4SLinus Torvalds static ssize_t atkbd_set_scroll(struct atkbd *atkbd, const char *buf, size_t count) 15181da177e4SLinus Torvalds { 15192b03b60eSDmitry Torokhov struct input_dev *old_dev, *new_dev; 152076496e7aSJJ Ding unsigned int value; 15212b03b60eSDmitry Torokhov int err; 1522a9a1f9c3SDmitry Torokhov bool old_scroll; 15231da177e4SLinus Torvalds 152476496e7aSJJ Ding err = kstrtouint(buf, 10, &value); 152576496e7aSJJ Ding if (err) 152676496e7aSJJ Ding return err; 152776496e7aSJJ Ding 152876496e7aSJJ Ding if (value > 1) 15291da177e4SLinus Torvalds return -EINVAL; 15301da177e4SLinus Torvalds 15311da177e4SLinus Torvalds if (atkbd->scroll != value) { 15322b03b60eSDmitry Torokhov old_dev = atkbd->dev; 15332b03b60eSDmitry Torokhov old_scroll = atkbd->scroll; 15342b03b60eSDmitry Torokhov 15352b03b60eSDmitry Torokhov new_dev = input_allocate_device(); 15362b03b60eSDmitry Torokhov if (!new_dev) 15373c42f0c3SDmitry Torokhov return -ENOMEM; 15382b03b60eSDmitry Torokhov 15393c42f0c3SDmitry Torokhov atkbd->dev = new_dev; 15401da177e4SLinus Torvalds atkbd->scroll = value; 15411da177e4SLinus Torvalds atkbd_set_keycode_table(atkbd); 15421da177e4SLinus Torvalds atkbd_set_device_attrs(atkbd); 15432b03b60eSDmitry Torokhov 15442b03b60eSDmitry Torokhov err = input_register_device(atkbd->dev); 15452b03b60eSDmitry Torokhov if (err) { 15462b03b60eSDmitry Torokhov input_free_device(new_dev); 15472b03b60eSDmitry Torokhov 15482b03b60eSDmitry Torokhov atkbd->scroll = old_scroll; 15492b03b60eSDmitry Torokhov atkbd->dev = old_dev; 15502b03b60eSDmitry Torokhov atkbd_set_keycode_table(atkbd); 15512b03b60eSDmitry Torokhov atkbd_set_device_attrs(atkbd); 15522b03b60eSDmitry Torokhov 15532b03b60eSDmitry Torokhov return err; 15542b03b60eSDmitry Torokhov } 15552b03b60eSDmitry Torokhov input_unregister_device(old_dev); 15561da177e4SLinus Torvalds } 15571da177e4SLinus Torvalds return count; 15581da177e4SLinus Torvalds } 15591da177e4SLinus Torvalds 15601da177e4SLinus Torvalds static ssize_t atkbd_show_set(struct atkbd *atkbd, char *buf) 15611da177e4SLinus Torvalds { 15621da177e4SLinus Torvalds return sprintf(buf, "%d\n", atkbd->set); 15631da177e4SLinus Torvalds } 15641da177e4SLinus Torvalds 15651da177e4SLinus Torvalds static ssize_t atkbd_set_set(struct atkbd *atkbd, const char *buf, size_t count) 15661da177e4SLinus Torvalds { 15672b03b60eSDmitry Torokhov struct input_dev *old_dev, *new_dev; 156876496e7aSJJ Ding unsigned int value; 15692b03b60eSDmitry Torokhov int err; 1570a9a1f9c3SDmitry Torokhov unsigned char old_set; 1571a9a1f9c3SDmitry Torokhov bool old_extra; 15721da177e4SLinus Torvalds 15731da177e4SLinus Torvalds if (!atkbd->write) 15741da177e4SLinus Torvalds return -EIO; 15751da177e4SLinus Torvalds 157676496e7aSJJ Ding err = kstrtouint(buf, 10, &value); 157776496e7aSJJ Ding if (err) 157876496e7aSJJ Ding return err; 157976496e7aSJJ Ding 158076496e7aSJJ Ding if (value != 2 && value != 3) 15811da177e4SLinus Torvalds return -EINVAL; 15821da177e4SLinus Torvalds 15831da177e4SLinus Torvalds if (atkbd->set != value) { 15842b03b60eSDmitry Torokhov old_dev = atkbd->dev; 15852b03b60eSDmitry Torokhov old_extra = atkbd->extra; 15862b03b60eSDmitry Torokhov old_set = atkbd->set; 15872b03b60eSDmitry Torokhov 15882b03b60eSDmitry Torokhov new_dev = input_allocate_device(); 15892b03b60eSDmitry Torokhov if (!new_dev) 15903c42f0c3SDmitry Torokhov return -ENOMEM; 15912b03b60eSDmitry Torokhov 15923c42f0c3SDmitry Torokhov atkbd->dev = new_dev; 15931da177e4SLinus Torvalds atkbd->set = atkbd_select_set(atkbd, value, atkbd->extra); 1594d4119bdaSDmitry Torokhov atkbd_reset_state(atkbd); 15951da177e4SLinus Torvalds atkbd_activate(atkbd); 15961da177e4SLinus Torvalds atkbd_set_keycode_table(atkbd); 15971da177e4SLinus Torvalds atkbd_set_device_attrs(atkbd); 15982b03b60eSDmitry Torokhov 15992b03b60eSDmitry Torokhov err = input_register_device(atkbd->dev); 16002b03b60eSDmitry Torokhov if (err) { 16012b03b60eSDmitry Torokhov input_free_device(new_dev); 16022b03b60eSDmitry Torokhov 16032b03b60eSDmitry Torokhov atkbd->dev = old_dev; 16042b03b60eSDmitry Torokhov atkbd->set = atkbd_select_set(atkbd, old_set, old_extra); 16052b03b60eSDmitry Torokhov atkbd_set_keycode_table(atkbd); 16062b03b60eSDmitry Torokhov atkbd_set_device_attrs(atkbd); 16072b03b60eSDmitry Torokhov 16082b03b60eSDmitry Torokhov return err; 16092b03b60eSDmitry Torokhov } 16102b03b60eSDmitry Torokhov input_unregister_device(old_dev); 16111da177e4SLinus Torvalds } 16121da177e4SLinus Torvalds return count; 16131da177e4SLinus Torvalds } 16141da177e4SLinus Torvalds 16151da177e4SLinus Torvalds static ssize_t atkbd_show_softrepeat(struct atkbd *atkbd, char *buf) 16161da177e4SLinus Torvalds { 16171da177e4SLinus Torvalds return sprintf(buf, "%d\n", atkbd->softrepeat ? 1 : 0); 16181da177e4SLinus Torvalds } 16191da177e4SLinus Torvalds 16201da177e4SLinus Torvalds static ssize_t atkbd_set_softrepeat(struct atkbd *atkbd, const char *buf, size_t count) 16211da177e4SLinus Torvalds { 16222b03b60eSDmitry Torokhov struct input_dev *old_dev, *new_dev; 162376496e7aSJJ Ding unsigned int value; 16242b03b60eSDmitry Torokhov int err; 1625a9a1f9c3SDmitry Torokhov bool old_softrepeat, old_softraw; 16261da177e4SLinus Torvalds 16271da177e4SLinus Torvalds if (!atkbd->write) 16281da177e4SLinus Torvalds return -EIO; 16291da177e4SLinus Torvalds 163076496e7aSJJ Ding err = kstrtouint(buf, 10, &value); 163176496e7aSJJ Ding if (err) 163276496e7aSJJ Ding return err; 163376496e7aSJJ Ding 163476496e7aSJJ Ding if (value > 1) 16351da177e4SLinus Torvalds return -EINVAL; 16361da177e4SLinus Torvalds 16371da177e4SLinus Torvalds if (atkbd->softrepeat != value) { 16382b03b60eSDmitry Torokhov old_dev = atkbd->dev; 16392b03b60eSDmitry Torokhov old_softrepeat = atkbd->softrepeat; 16402b03b60eSDmitry Torokhov old_softraw = atkbd->softraw; 16412b03b60eSDmitry Torokhov 16422b03b60eSDmitry Torokhov new_dev = input_allocate_device(); 16432b03b60eSDmitry Torokhov if (!new_dev) 16443c42f0c3SDmitry Torokhov return -ENOMEM; 16452b03b60eSDmitry Torokhov 16463c42f0c3SDmitry Torokhov atkbd->dev = new_dev; 16471da177e4SLinus Torvalds atkbd->softrepeat = value; 16481da177e4SLinus Torvalds if (atkbd->softrepeat) 1649a9a1f9c3SDmitry Torokhov atkbd->softraw = true; 16501da177e4SLinus Torvalds atkbd_set_device_attrs(atkbd); 16512b03b60eSDmitry Torokhov 16522b03b60eSDmitry Torokhov err = input_register_device(atkbd->dev); 16532b03b60eSDmitry Torokhov if (err) { 16542b03b60eSDmitry Torokhov input_free_device(new_dev); 16552b03b60eSDmitry Torokhov 16562b03b60eSDmitry Torokhov atkbd->dev = old_dev; 16572b03b60eSDmitry Torokhov atkbd->softrepeat = old_softrepeat; 16582b03b60eSDmitry Torokhov atkbd->softraw = old_softraw; 16592b03b60eSDmitry Torokhov atkbd_set_device_attrs(atkbd); 16602b03b60eSDmitry Torokhov 16612b03b60eSDmitry Torokhov return err; 16622b03b60eSDmitry Torokhov } 16632b03b60eSDmitry Torokhov input_unregister_device(old_dev); 16641da177e4SLinus Torvalds } 16651da177e4SLinus Torvalds return count; 16661da177e4SLinus Torvalds } 16671da177e4SLinus Torvalds 16681da177e4SLinus Torvalds 16691da177e4SLinus Torvalds static ssize_t atkbd_show_softraw(struct atkbd *atkbd, char *buf) 16701da177e4SLinus Torvalds { 16711da177e4SLinus Torvalds return sprintf(buf, "%d\n", atkbd->softraw ? 1 : 0); 16721da177e4SLinus Torvalds } 16731da177e4SLinus Torvalds 16741da177e4SLinus Torvalds static ssize_t atkbd_set_softraw(struct atkbd *atkbd, const char *buf, size_t count) 16751da177e4SLinus Torvalds { 16762b03b60eSDmitry Torokhov struct input_dev *old_dev, *new_dev; 167776496e7aSJJ Ding unsigned int value; 16782b03b60eSDmitry Torokhov int err; 1679a9a1f9c3SDmitry Torokhov bool old_softraw; 16801da177e4SLinus Torvalds 168176496e7aSJJ Ding err = kstrtouint(buf, 10, &value); 168276496e7aSJJ Ding if (err) 168376496e7aSJJ Ding return err; 168476496e7aSJJ Ding 168576496e7aSJJ Ding if (value > 1) 16861da177e4SLinus Torvalds return -EINVAL; 16871da177e4SLinus Torvalds 16881da177e4SLinus Torvalds if (atkbd->softraw != value) { 16892b03b60eSDmitry Torokhov old_dev = atkbd->dev; 16902b03b60eSDmitry Torokhov old_softraw = atkbd->softraw; 16912b03b60eSDmitry Torokhov 16922b03b60eSDmitry Torokhov new_dev = input_allocate_device(); 16932b03b60eSDmitry Torokhov if (!new_dev) 16943c42f0c3SDmitry Torokhov return -ENOMEM; 16952b03b60eSDmitry Torokhov 16963c42f0c3SDmitry Torokhov atkbd->dev = new_dev; 16971da177e4SLinus Torvalds atkbd->softraw = value; 16981da177e4SLinus Torvalds atkbd_set_device_attrs(atkbd); 16992b03b60eSDmitry Torokhov 17002b03b60eSDmitry Torokhov err = input_register_device(atkbd->dev); 17012b03b60eSDmitry Torokhov if (err) { 17022b03b60eSDmitry Torokhov input_free_device(new_dev); 17032b03b60eSDmitry Torokhov 17042b03b60eSDmitry Torokhov atkbd->dev = old_dev; 17052b03b60eSDmitry Torokhov atkbd->softraw = old_softraw; 17062b03b60eSDmitry Torokhov atkbd_set_device_attrs(atkbd); 17072b03b60eSDmitry Torokhov 17082b03b60eSDmitry Torokhov return err; 17092b03b60eSDmitry Torokhov } 17102b03b60eSDmitry Torokhov input_unregister_device(old_dev); 17111da177e4SLinus Torvalds } 17121da177e4SLinus Torvalds return count; 17131da177e4SLinus Torvalds } 17141da177e4SLinus Torvalds 171586255d9dSDmitry Torokhov static ssize_t atkbd_show_err_count(struct atkbd *atkbd, char *buf) 171686255d9dSDmitry Torokhov { 171786255d9dSDmitry Torokhov return sprintf(buf, "%lu\n", atkbd->err_count); 171886255d9dSDmitry Torokhov } 171986255d9dSDmitry Torokhov 172039191698SDaniel Mierswa static int __init atkbd_setup_forced_release(const struct dmi_system_id *id) 1721554101e3SGiel de Nijs { 172239191698SDaniel Mierswa atkbd_platform_fixup = atkbd_apply_forced_release_keylist; 172339191698SDaniel Mierswa atkbd_platform_fixup_data = id->driver_data; 172439191698SDaniel Mierswa 1725c388b2c6SAxel Lin return 1; 1726554101e3SGiel de Nijs } 1727554101e3SGiel de Nijs 1728e5713069SJamie Lentin static int __init atkbd_setup_scancode_fixup(const struct dmi_system_id *id) 1729e5713069SJamie Lentin { 1730e5713069SJamie Lentin atkbd_platform_scancode_fixup = id->driver_data; 1731e5713069SJamie Lentin 1732c388b2c6SAxel Lin return 1; 1733e5713069SJamie Lentin } 1734e5713069SJamie Lentin 17353d725caaSSheng-Liang Song static int __init atkbd_deactivate_fixup(const struct dmi_system_id *id) 17363d725caaSSheng-Liang Song { 17373d725caaSSheng-Liang Song atkbd_skip_deactivate = true; 17383d725caaSSheng-Liang Song return 1; 17393d725caaSSheng-Liang Song } 17403d725caaSSheng-Liang Song 17418b8a518eSDmitry Torokhov /* 17428b8a518eSDmitry Torokhov * NOTE: do not add any more "force release" quirks to this table. The 17438b8a518eSDmitry Torokhov * task of adjusting list of keys that should be "released" automatically 17448b8a518eSDmitry Torokhov * by the driver is now delegated to userspace tools, such as udev, so 17458b8a518eSDmitry Torokhov * submit such quirks there. 17468b8a518eSDmitry Torokhov */ 1747c45fc81eSDmitry Torokhov static const struct dmi_system_id atkbd_dmi_quirk_table[] __initconst = { 1748554101e3SGiel de Nijs { 1749554101e3SGiel de Nijs .matches = { 1750554101e3SGiel de Nijs DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 175161579ba8SMatthew Garrett DMI_MATCH(DMI_CHASSIS_TYPE, "8"), /* Portable */ 1752554101e3SGiel de Nijs }, 175339191698SDaniel Mierswa .callback = atkbd_setup_forced_release, 175439191698SDaniel Mierswa .driver_data = atkbd_dell_laptop_forced_release_keys, 1755554101e3SGiel de Nijs }, 17565a54c011SJiri Kosina { 17572a3ec326SMatthew Garrett .matches = { 17582a3ec326SMatthew Garrett DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"), 17592a3ec326SMatthew Garrett DMI_MATCH(DMI_CHASSIS_TYPE, "8"), /* Portable */ 17602a3ec326SMatthew Garrett }, 176139191698SDaniel Mierswa .callback = atkbd_setup_forced_release, 176239191698SDaniel Mierswa .driver_data = atkbd_dell_laptop_forced_release_keys, 17632a3ec326SMatthew Garrett }, 17642a3ec326SMatthew Garrett { 17655a54c011SJiri Kosina .matches = { 17665a54c011SJiri Kosina DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), 17675a54c011SJiri Kosina DMI_MATCH(DMI_PRODUCT_NAME, "HP 2133"), 17685a54c011SJiri Kosina }, 176939191698SDaniel Mierswa .callback = atkbd_setup_forced_release, 177039191698SDaniel Mierswa .driver_data = atkbd_hp_forced_release_keys, 17715a54c011SJiri Kosina }, 1772a8215b81SMatthew Garrett { 1773181f6382SRikard Ljungstrand .matches = { 1774181f6382SRikard Ljungstrand DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), 1775181f6382SRikard Ljungstrand DMI_MATCH(DMI_PRODUCT_NAME, "Pavilion ZV6100"), 1776181f6382SRikard Ljungstrand }, 177739191698SDaniel Mierswa .callback = atkbd_setup_forced_release, 1778000c2a35SHerton Ronaldo Krzesinski .driver_data = atkbd_volume_forced_release_keys, 1779181f6382SRikard Ljungstrand }, 1780181f6382SRikard Ljungstrand { 17812bcaa6a4SDave Andrews .matches = { 17822bcaa6a4SDave Andrews DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), 17832bcaa6a4SDave Andrews DMI_MATCH(DMI_PRODUCT_NAME, "Presario R4000"), 17842bcaa6a4SDave Andrews }, 17852bcaa6a4SDave Andrews .callback = atkbd_setup_forced_release, 1786000c2a35SHerton Ronaldo Krzesinski .driver_data = atkbd_volume_forced_release_keys, 17872bcaa6a4SDave Andrews }, 17882bcaa6a4SDave Andrews { 17892bcaa6a4SDave Andrews .matches = { 17902bcaa6a4SDave Andrews DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), 17912bcaa6a4SDave Andrews DMI_MATCH(DMI_PRODUCT_NAME, "Presario R4100"), 17922bcaa6a4SDave Andrews }, 17932bcaa6a4SDave Andrews .callback = atkbd_setup_forced_release, 1794000c2a35SHerton Ronaldo Krzesinski .driver_data = atkbd_volume_forced_release_keys, 17952bcaa6a4SDave Andrews }, 17962bcaa6a4SDave Andrews { 17972bcaa6a4SDave Andrews .matches = { 17982bcaa6a4SDave Andrews DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), 17992bcaa6a4SDave Andrews DMI_MATCH(DMI_PRODUCT_NAME, "Presario R4200"), 18002bcaa6a4SDave Andrews }, 18012bcaa6a4SDave Andrews .callback = atkbd_setup_forced_release, 1802000c2a35SHerton Ronaldo Krzesinski .driver_data = atkbd_volume_forced_release_keys, 18032bcaa6a4SDave Andrews }, 18042bcaa6a4SDave Andrews { 1805c45fc81eSDmitry Torokhov /* Inventec Symphony */ 1806a8215b81SMatthew Garrett .matches = { 1807a8215b81SMatthew Garrett DMI_MATCH(DMI_SYS_VENDOR, "INVENTEC"), 1808a8215b81SMatthew Garrett DMI_MATCH(DMI_PRODUCT_NAME, "SYMPHONY 6.0/7.0"), 1809a8215b81SMatthew Garrett }, 181039191698SDaniel Mierswa .callback = atkbd_setup_forced_release, 1811000c2a35SHerton Ronaldo Krzesinski .driver_data = atkbd_volume_forced_release_keys, 1812a8215b81SMatthew Garrett }, 18134200844bSStuart Hopkins { 1814c45fc81eSDmitry Torokhov /* Samsung NC10 */ 18154200844bSStuart Hopkins .matches = { 18164200844bSStuart Hopkins DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."), 18174200844bSStuart Hopkins DMI_MATCH(DMI_PRODUCT_NAME, "NC10"), 18184200844bSStuart Hopkins }, 181939191698SDaniel Mierswa .callback = atkbd_setup_forced_release, 182039191698SDaniel Mierswa .driver_data = atkbd_samsung_forced_release_keys, 18214200844bSStuart Hopkins }, 1822adcb523eSDaniel Mierswa { 1823c45fc81eSDmitry Torokhov /* Samsung NC20 */ 1824e04126c7SBarry Carroll .matches = { 1825e04126c7SBarry Carroll DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."), 1826e04126c7SBarry Carroll DMI_MATCH(DMI_PRODUCT_NAME, "NC20"), 1827e04126c7SBarry Carroll }, 1828e04126c7SBarry Carroll .callback = atkbd_setup_forced_release, 1829e04126c7SBarry Carroll .driver_data = atkbd_samsung_forced_release_keys, 1830e04126c7SBarry Carroll }, 1831e04126c7SBarry Carroll { 1832c45fc81eSDmitry Torokhov /* Samsung SQ45S70S */ 1833157f3a3eSDmitry Torokhov .matches = { 1834157f3a3eSDmitry Torokhov DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."), 1835157f3a3eSDmitry Torokhov DMI_MATCH(DMI_PRODUCT_NAME, "SQ45S70S"), 1836157f3a3eSDmitry Torokhov }, 1837157f3a3eSDmitry Torokhov .callback = atkbd_setup_forced_release, 1838157f3a3eSDmitry Torokhov .driver_data = atkbd_samsung_forced_release_keys, 1839157f3a3eSDmitry Torokhov }, 1840157f3a3eSDmitry Torokhov { 1841c45fc81eSDmitry Torokhov /* Fujitsu Amilo PA 1510 */ 1842adcb523eSDaniel Mierswa .matches = { 1843adcb523eSDaniel Mierswa DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), 1844adcb523eSDaniel Mierswa DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Pa 1510"), 1845adcb523eSDaniel Mierswa }, 1846adcb523eSDaniel Mierswa .callback = atkbd_setup_forced_release, 1847000c2a35SHerton Ronaldo Krzesinski .driver_data = atkbd_volume_forced_release_keys, 1848adcb523eSDaniel Mierswa }, 18499166d0f6SAdrian Batzill { 1850c45fc81eSDmitry Torokhov /* Fujitsu Amilo Pi 3525 */ 1851f0a14de2SSimon Davie .matches = { 1852f0a14de2SSimon Davie DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), 1853f0a14de2SSimon Davie DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Pi 3525"), 1854f0a14de2SSimon Davie }, 1855f0a14de2SSimon Davie .callback = atkbd_setup_forced_release, 1856f0a14de2SSimon Davie .driver_data = atkbd_amilo_pi3525_forced_release_keys, 1857f0a14de2SSimon Davie }, 1858f0a14de2SSimon Davie { 1859c45fc81eSDmitry Torokhov /* Fujitsu Amilo Xi 3650 */ 18609166d0f6SAdrian Batzill .matches = { 18619166d0f6SAdrian Batzill DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), 18629166d0f6SAdrian Batzill DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Xi 3650"), 18639166d0f6SAdrian Batzill }, 18649166d0f6SAdrian Batzill .callback = atkbd_setup_forced_release, 18659166d0f6SAdrian Batzill .driver_data = atkbd_amilo_xi3650_forced_release_keys, 18669166d0f6SAdrian Batzill }, 1867032e46cbSJerone Young { 1868032e46cbSJerone Young .matches = { 1869032e46cbSJerone Young DMI_MATCH(DMI_SYS_VENDOR, "Soltech Corporation"), 1870032e46cbSJerone Young DMI_MATCH(DMI_PRODUCT_NAME, "TA12"), 1871032e46cbSJerone Young }, 1872032e46cbSJerone Young .callback = atkbd_setup_forced_release, 1873032e46cbSJerone Young .driver_data = atkdb_soltech_ta12_forced_release_keys, 1874032e46cbSJerone Young }, 1875e5713069SJamie Lentin { 1876c45fc81eSDmitry Torokhov /* OQO Model 01+ */ 1877e5713069SJamie Lentin .matches = { 1878e5713069SJamie Lentin DMI_MATCH(DMI_SYS_VENDOR, "OQO"), 1879e5713069SJamie Lentin DMI_MATCH(DMI_PRODUCT_NAME, "ZEPTO"), 1880e5713069SJamie Lentin }, 1881e5713069SJamie Lentin .callback = atkbd_setup_scancode_fixup, 1882e5713069SJamie Lentin .driver_data = atkbd_oqo_01plus_scancode_fixup, 1883e5713069SJamie Lentin }, 18843d725caaSSheng-Liang Song { 18853d725caaSSheng-Liang Song .matches = { 18863d725caaSSheng-Liang Song DMI_MATCH(DMI_SYS_VENDOR, "LG Electronics"), 18873d725caaSSheng-Liang Song }, 18883d725caaSSheng-Liang Song .callback = atkbd_deactivate_fixup, 18893d725caaSSheng-Liang Song }, 1890554101e3SGiel de Nijs { } 1891554101e3SGiel de Nijs }; 18921da177e4SLinus Torvalds 18931da177e4SLinus Torvalds static int __init atkbd_init(void) 18941da177e4SLinus Torvalds { 1895554101e3SGiel de Nijs dmi_check_system(atkbd_dmi_quirk_table); 1896554101e3SGiel de Nijs 1897153a9df0SAkinobu Mita return serio_register_driver(&atkbd_drv); 18981da177e4SLinus Torvalds } 18991da177e4SLinus Torvalds 19001da177e4SLinus Torvalds static void __exit atkbd_exit(void) 19011da177e4SLinus Torvalds { 19021da177e4SLinus Torvalds serio_unregister_driver(&atkbd_drv); 19031da177e4SLinus Torvalds } 19041da177e4SLinus Torvalds 19051da177e4SLinus Torvalds module_init(atkbd_init); 19061da177e4SLinus Torvalds module_exit(atkbd_exit); 1907