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> 22*45ceaf14SStephen 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 239*45ceaf14SStephen 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 { 309*45ceaf14SStephen Boyd return vivaldi_function_row_physmap_show(&atkbd->vdata, buf); 3108f7b057aSRajat Jain } 3118f7b057aSRajat Jain 3128f7b057aSRajat Jain static umode_t atkbd_attr_is_visible(struct kobject *kobj, 3138f7b057aSRajat Jain struct attribute *attr, int i) 3148f7b057aSRajat Jain { 31550221b0bSYueHaibing struct device *dev = kobj_to_dev(kobj); 3168f7b057aSRajat Jain struct serio *serio = to_serio_port(dev); 3178f7b057aSRajat Jain struct atkbd *atkbd = serio_get_drvdata(serio); 3188f7b057aSRajat Jain 3198f7b057aSRajat Jain if (attr == &atkbd_attr_function_row_physmap.attr && 320*45ceaf14SStephen Boyd !atkbd->vdata.num_function_row_keys) 3218f7b057aSRajat Jain return 0; 3228f7b057aSRajat Jain 3238f7b057aSRajat Jain return attr->mode; 3248f7b057aSRajat Jain } 3258f7b057aSRajat Jain 32686255d9dSDmitry Torokhov static struct attribute_group atkbd_attribute_group = { 32786255d9dSDmitry Torokhov .attrs = atkbd_attributes, 3288f7b057aSRajat Jain .is_visible = atkbd_attr_is_visible, 32986255d9dSDmitry Torokhov }; 33086255d9dSDmitry Torokhov 3310ae051a1SDmitry Torokhov static const unsigned int xl_table[] = { 3320ae051a1SDmitry Torokhov ATKBD_RET_BAT, ATKBD_RET_ERR, ATKBD_RET_ACK, 3330ae051a1SDmitry Torokhov ATKBD_RET_NAK, ATKBD_RET_HANJA, ATKBD_RET_HANGEUL, 3340ae051a1SDmitry Torokhov }; 3351da177e4SLinus Torvalds 3360ae051a1SDmitry Torokhov /* 3370ae051a1SDmitry Torokhov * Checks if we should mangle the scancode to extract 'release' bit 3380ae051a1SDmitry Torokhov * in translated mode. 3390ae051a1SDmitry Torokhov */ 340a9a1f9c3SDmitry Torokhov static bool atkbd_need_xlate(unsigned long xl_bit, unsigned char code) 3411da177e4SLinus Torvalds { 3420ae051a1SDmitry Torokhov int i; 3430ae051a1SDmitry Torokhov 3440ae051a1SDmitry Torokhov if (code == ATKBD_RET_EMUL0 || code == ATKBD_RET_EMUL1) 345a9a1f9c3SDmitry Torokhov return false; 3460ae051a1SDmitry Torokhov 3470ae051a1SDmitry Torokhov for (i = 0; i < ARRAY_SIZE(xl_table); i++) 3480ae051a1SDmitry Torokhov if (code == xl_table[i]) 3490ae051a1SDmitry Torokhov return test_bit(i, &xl_bit); 3500ae051a1SDmitry Torokhov 351a9a1f9c3SDmitry Torokhov return true; 3520ae051a1SDmitry Torokhov } 3530ae051a1SDmitry Torokhov 3540ae051a1SDmitry Torokhov /* 3550ae051a1SDmitry Torokhov * Calculates new value of xl_bit so the driver can distinguish 3560ae051a1SDmitry Torokhov * between make/break pair of scancodes for select keys and PS/2 3570ae051a1SDmitry Torokhov * protocol responses. 3580ae051a1SDmitry Torokhov */ 3590ae051a1SDmitry Torokhov static void atkbd_calculate_xl_bit(struct atkbd *atkbd, unsigned char code) 3600ae051a1SDmitry Torokhov { 3610ae051a1SDmitry Torokhov int i; 3620ae051a1SDmitry Torokhov 3630ae051a1SDmitry Torokhov for (i = 0; i < ARRAY_SIZE(xl_table); i++) { 3640ae051a1SDmitry Torokhov if (!((code ^ xl_table[i]) & 0x7f)) { 3650ae051a1SDmitry Torokhov if (code & 0x80) 3660ae051a1SDmitry Torokhov __clear_bit(i, &atkbd->xl_bit); 3670ae051a1SDmitry Torokhov else 3680ae051a1SDmitry Torokhov __set_bit(i, &atkbd->xl_bit); 3690ae051a1SDmitry Torokhov break; 3700ae051a1SDmitry Torokhov } 3710ae051a1SDmitry Torokhov } 3720ae051a1SDmitry Torokhov } 3730ae051a1SDmitry Torokhov 3740ae051a1SDmitry Torokhov /* 3750ae051a1SDmitry Torokhov * Encode the scancode, 0xe0 prefix, and high bit into a single integer, 3760ae051a1SDmitry Torokhov * keeping kernel 2.4 compatibility for set 2 3770ae051a1SDmitry Torokhov */ 3780ae051a1SDmitry Torokhov static unsigned int atkbd_compat_scancode(struct atkbd *atkbd, unsigned int code) 3790ae051a1SDmitry Torokhov { 3800ae051a1SDmitry Torokhov if (atkbd->set == 3) { 3810ae051a1SDmitry Torokhov if (atkbd->emul == 1) 3820ae051a1SDmitry Torokhov code |= 0x100; 3830ae051a1SDmitry Torokhov } else { 3840ae051a1SDmitry Torokhov code = (code & 0x7f) | ((code & 0x80) << 1); 3850ae051a1SDmitry Torokhov if (atkbd->emul == 1) 3860ae051a1SDmitry Torokhov code |= 0x80; 3870ae051a1SDmitry Torokhov } 3880ae051a1SDmitry Torokhov 3890ae051a1SDmitry Torokhov return code; 3901da177e4SLinus Torvalds } 3911da177e4SLinus Torvalds 3921da177e4SLinus Torvalds /* 3931da177e4SLinus Torvalds * atkbd_interrupt(). Here takes place processing of data received from 3941da177e4SLinus Torvalds * the keyboard into events. 3951da177e4SLinus Torvalds */ 3961da177e4SLinus Torvalds 3971da177e4SLinus Torvalds static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data, 3987d12e780SDavid Howells unsigned int flags) 3991da177e4SLinus Torvalds { 4001da177e4SLinus Torvalds struct atkbd *atkbd = serio_get_drvdata(serio); 4010ae051a1SDmitry Torokhov struct input_dev *dev = atkbd->dev; 4021da177e4SLinus Torvalds unsigned int code = data; 403554101e3SGiel de Nijs int scroll = 0, hscroll = 0, click = -1; 4041da177e4SLinus Torvalds int value; 405f6d65610SDmitry Torokhov unsigned short keycode; 4061da177e4SLinus Torvalds 407a9a1f9c3SDmitry Torokhov dev_dbg(&serio->dev, "Received %02x flags %02x\n", data, flags); 4081da177e4SLinus Torvalds 4091da177e4SLinus Torvalds #if !defined(__i386__) && !defined (__x86_64__) 4101da177e4SLinus Torvalds if ((flags & (SERIO_FRAME | SERIO_PARITY)) && (~flags & SERIO_TIMEOUT) && !atkbd->resend && atkbd->write) { 411a9a1f9c3SDmitry Torokhov dev_warn(&serio->dev, "Frame/parity error: %02x\n", flags); 4121da177e4SLinus Torvalds serio_write(serio, ATKBD_CMD_RESEND); 413a9a1f9c3SDmitry Torokhov atkbd->resend = true; 4141da177e4SLinus Torvalds goto out; 4151da177e4SLinus Torvalds } 4161da177e4SLinus Torvalds 4171da177e4SLinus Torvalds if (!flags && data == ATKBD_RET_ACK) 418a9a1f9c3SDmitry Torokhov atkbd->resend = false; 4191da177e4SLinus Torvalds #endif 4201da177e4SLinus Torvalds 4211da177e4SLinus Torvalds if (unlikely(atkbd->ps2dev.flags & PS2_FLAG_ACK)) 4221da177e4SLinus Torvalds if (ps2_handle_ack(&atkbd->ps2dev, data)) 4231da177e4SLinus Torvalds goto out; 4241da177e4SLinus Torvalds 4251da177e4SLinus Torvalds if (unlikely(atkbd->ps2dev.flags & PS2_FLAG_CMD)) 4261da177e4SLinus Torvalds if (ps2_handle_response(&atkbd->ps2dev, data)) 4271da177e4SLinus Torvalds goto out; 4281da177e4SLinus Torvalds 429aaca981eSDmitry Torokhov pm_wakeup_event(&serio->dev, 0); 430aaca981eSDmitry Torokhov 4311da177e4SLinus Torvalds if (!atkbd->enabled) 4321da177e4SLinus Torvalds goto out; 4331da177e4SLinus Torvalds 4340ae051a1SDmitry Torokhov input_event(dev, EV_MSC, MSC_RAW, code); 4351da177e4SLinus Torvalds 436e5713069SJamie Lentin if (atkbd_platform_scancode_fixup) 437e5713069SJamie Lentin code = atkbd_platform_scancode_fixup(atkbd, code); 438e5713069SJamie Lentin 4391da177e4SLinus Torvalds if (atkbd->translated) { 4401da177e4SLinus Torvalds 4410ae051a1SDmitry Torokhov if (atkbd->emul || atkbd_need_xlate(atkbd->xl_bit, code)) { 4421da177e4SLinus Torvalds atkbd->release = code >> 7; 4431da177e4SLinus Torvalds code &= 0x7f; 4441da177e4SLinus Torvalds } 4451da177e4SLinus Torvalds 4460ae051a1SDmitry Torokhov if (!atkbd->emul) 4470ae051a1SDmitry Torokhov atkbd_calculate_xl_bit(atkbd, data); 4481da177e4SLinus Torvalds } 4491da177e4SLinus Torvalds 4501da177e4SLinus Torvalds switch (code) { 4511da177e4SLinus Torvalds case ATKBD_RET_BAT: 452a9a1f9c3SDmitry Torokhov atkbd->enabled = false; 453dbc26344SDmitry Torokhov serio_reconnect(atkbd->ps2dev.serio); 4541da177e4SLinus Torvalds goto out; 4551da177e4SLinus Torvalds case ATKBD_RET_EMUL0: 4561da177e4SLinus Torvalds atkbd->emul = 1; 4571da177e4SLinus Torvalds goto out; 4581da177e4SLinus Torvalds case ATKBD_RET_EMUL1: 4591da177e4SLinus Torvalds atkbd->emul = 2; 4601da177e4SLinus Torvalds goto out; 4611da177e4SLinus Torvalds case ATKBD_RET_RELEASE: 462a9a1f9c3SDmitry Torokhov atkbd->release = true; 4631da177e4SLinus Torvalds goto out; 4640ae051a1SDmitry Torokhov case ATKBD_RET_ACK: 4650ae051a1SDmitry Torokhov case ATKBD_RET_NAK: 4669f7a60d6SQi Yong if (printk_ratelimit()) 467a9a1f9c3SDmitry Torokhov dev_warn(&serio->dev, 468a9a1f9c3SDmitry Torokhov "Spurious %s on %s. " 469f57fe78eSJesper Juhl "Some program might be trying to access hardware directly.\n", 4700ae051a1SDmitry Torokhov data == ATKBD_RET_ACK ? "ACK" : "NAK", serio->phys); 4710ae051a1SDmitry Torokhov goto out; 4721da177e4SLinus Torvalds case ATKBD_RET_ERR: 47386255d9dSDmitry Torokhov atkbd->err_count++; 474a9a1f9c3SDmitry Torokhov dev_dbg(&serio->dev, "Keyboard on %s reports too many keys pressed.\n", 475a9a1f9c3SDmitry Torokhov serio->phys); 4761da177e4SLinus Torvalds goto out; 4771da177e4SLinus Torvalds } 4781da177e4SLinus Torvalds 4790ae051a1SDmitry Torokhov code = atkbd_compat_scancode(atkbd, code); 4800ae051a1SDmitry Torokhov 4810ae051a1SDmitry Torokhov if (atkbd->emul && --atkbd->emul) 4821da177e4SLinus Torvalds goto out; 4831da177e4SLinus Torvalds 4840ae051a1SDmitry Torokhov keycode = atkbd->keycode[code]; 4851da177e4SLinus Torvalds 4865447326fSStefan Brüns if (!(atkbd->release && test_bit(code, atkbd->force_release_mask))) 4870ae051a1SDmitry Torokhov if (keycode != ATKBD_KEY_NULL) 4880ae051a1SDmitry Torokhov input_event(dev, EV_MSC, MSC_SCAN, code); 4890ae051a1SDmitry Torokhov 4900ae051a1SDmitry Torokhov switch (keycode) { 4911da177e4SLinus Torvalds case ATKBD_KEY_NULL: 4921da177e4SLinus Torvalds break; 4931da177e4SLinus Torvalds case ATKBD_KEY_UNKNOWN: 494a9a1f9c3SDmitry Torokhov dev_warn(&serio->dev, 495a9a1f9c3SDmitry Torokhov "Unknown key %s (%s set %d, code %#x on %s).\n", 4961da177e4SLinus Torvalds atkbd->release ? "released" : "pressed", 4971da177e4SLinus Torvalds atkbd->translated ? "translated" : "raw", 4981da177e4SLinus Torvalds atkbd->set, code, serio->phys); 499a9a1f9c3SDmitry Torokhov dev_warn(&serio->dev, 500a9a1f9c3SDmitry Torokhov "Use 'setkeycodes %s%02x <keycode>' to make it known.\n", 5011da177e4SLinus Torvalds code & 0x80 ? "e0" : "", code & 0x7f); 5020ae051a1SDmitry Torokhov input_sync(dev); 5031da177e4SLinus Torvalds break; 5041da177e4SLinus Torvalds case ATKBD_SCR_1: 505a9a1f9c3SDmitry Torokhov scroll = 1; 5061da177e4SLinus Torvalds break; 5071da177e4SLinus Torvalds case ATKBD_SCR_2: 508a9a1f9c3SDmitry Torokhov scroll = 2; 5091da177e4SLinus Torvalds break; 5101da177e4SLinus Torvalds case ATKBD_SCR_4: 511a9a1f9c3SDmitry Torokhov scroll = 4; 5121da177e4SLinus Torvalds break; 5131da177e4SLinus Torvalds case ATKBD_SCR_8: 514a9a1f9c3SDmitry Torokhov scroll = 8; 5151da177e4SLinus Torvalds break; 5161da177e4SLinus Torvalds case ATKBD_SCR_CLICK: 5171da177e4SLinus Torvalds click = !atkbd->release; 5181da177e4SLinus Torvalds break; 5191da177e4SLinus Torvalds case ATKBD_SCR_LEFT: 5201da177e4SLinus Torvalds hscroll = -1; 5211da177e4SLinus Torvalds break; 5221da177e4SLinus Torvalds case ATKBD_SCR_RIGHT: 5231da177e4SLinus Torvalds hscroll = 1; 5241da177e4SLinus Torvalds break; 5251da177e4SLinus Torvalds default: 5260ae051a1SDmitry Torokhov if (atkbd->release) { 5270ae051a1SDmitry Torokhov value = 0; 5281da177e4SLinus Torvalds atkbd->last = 0; 5290ae051a1SDmitry Torokhov } else if (!atkbd->softrepeat && test_bit(keycode, dev->key)) { 5300ae051a1SDmitry Torokhov /* Workaround Toshiba laptop multiple keypress */ 5310ae051a1SDmitry Torokhov value = time_before(jiffies, atkbd->time) && atkbd->last == code ? 1 : 2; 5320ae051a1SDmitry Torokhov } else { 5331da177e4SLinus Torvalds value = 1; 5340ae051a1SDmitry Torokhov atkbd->last = code; 5350ae051a1SDmitry Torokhov atkbd->time = jiffies + msecs_to_jiffies(dev->rep[REP_DELAY]) / 2; 5361da177e4SLinus Torvalds } 5371da177e4SLinus Torvalds 538f8b4c46cSDmitry Torokhov input_event(dev, EV_KEY, keycode, value); 5390ae051a1SDmitry Torokhov input_sync(dev); 5400ae051a1SDmitry Torokhov 541554101e3SGiel de Nijs if (value && test_bit(code, atkbd->force_release_mask)) { 5425447326fSStefan Brüns input_event(dev, EV_MSC, MSC_SCAN, code); 5430ae051a1SDmitry Torokhov input_report_key(dev, keycode, 0); 5440ae051a1SDmitry Torokhov input_sync(dev); 5450ae051a1SDmitry Torokhov } 5461da177e4SLinus Torvalds } 5471da177e4SLinus Torvalds 5481da177e4SLinus Torvalds if (atkbd->scroll) { 5491da177e4SLinus Torvalds if (click != -1) 5500ae051a1SDmitry Torokhov input_report_key(dev, BTN_MIDDLE, click); 551a9a1f9c3SDmitry Torokhov input_report_rel(dev, REL_WHEEL, 552a9a1f9c3SDmitry Torokhov atkbd->release ? -scroll : scroll); 5530ae051a1SDmitry Torokhov input_report_rel(dev, REL_HWHEEL, hscroll); 5540ae051a1SDmitry Torokhov input_sync(dev); 5551da177e4SLinus Torvalds } 5561da177e4SLinus Torvalds 557a9a1f9c3SDmitry Torokhov atkbd->release = false; 5581da177e4SLinus Torvalds out: 5591da177e4SLinus Torvalds return IRQ_HANDLED; 5601da177e4SLinus Torvalds } 5611da177e4SLinus Torvalds 5623d0f0fa0SDmitry Torokhov static int atkbd_set_repeat_rate(struct atkbd *atkbd) 5631da177e4SLinus Torvalds { 5641da177e4SLinus Torvalds const short period[32] = 5651da177e4SLinus Torvalds { 33, 37, 42, 46, 50, 54, 58, 63, 67, 75, 83, 92, 100, 109, 116, 125, 5661da177e4SLinus Torvalds 133, 149, 167, 182, 200, 217, 232, 250, 270, 303, 333, 370, 400, 435, 470, 500 }; 5671da177e4SLinus Torvalds const short delay[4] = 5681da177e4SLinus Torvalds { 250, 500, 750, 1000 }; 5690d4c8597SDmitry Torokhov 5703d0f0fa0SDmitry Torokhov struct input_dev *dev = atkbd->dev; 5713d0f0fa0SDmitry Torokhov unsigned char param; 5723d0f0fa0SDmitry Torokhov int i = 0, j = 0; 5733d0f0fa0SDmitry Torokhov 5743d0f0fa0SDmitry Torokhov while (i < ARRAY_SIZE(period) - 1 && period[i] < dev->rep[REP_PERIOD]) 5753d0f0fa0SDmitry Torokhov i++; 5763d0f0fa0SDmitry Torokhov dev->rep[REP_PERIOD] = period[i]; 5773d0f0fa0SDmitry Torokhov 5788ea371fbSFlorin Malita while (j < ARRAY_SIZE(delay) - 1 && delay[j] < dev->rep[REP_DELAY]) 5793d0f0fa0SDmitry Torokhov j++; 5803d0f0fa0SDmitry Torokhov dev->rep[REP_DELAY] = delay[j]; 5813d0f0fa0SDmitry Torokhov 5823d0f0fa0SDmitry Torokhov param = i | (j << 5); 5833d0f0fa0SDmitry Torokhov return ps2_command(&atkbd->ps2dev, ¶m, ATKBD_CMD_SETREP); 5843d0f0fa0SDmitry Torokhov } 5853d0f0fa0SDmitry Torokhov 5863d0f0fa0SDmitry Torokhov static int atkbd_set_leds(struct atkbd *atkbd) 5873d0f0fa0SDmitry Torokhov { 5880d4c8597SDmitry Torokhov struct input_dev *dev = atkbd->dev; 5891da177e4SLinus Torvalds unsigned char param[2]; 5901da177e4SLinus Torvalds 5911da177e4SLinus Torvalds param[0] = (test_bit(LED_SCROLLL, dev->led) ? 1 : 0) 5921da177e4SLinus Torvalds | (test_bit(LED_NUML, dev->led) ? 2 : 0) 5931da177e4SLinus Torvalds | (test_bit(LED_CAPSL, dev->led) ? 4 : 0); 5943d0f0fa0SDmitry Torokhov if (ps2_command(&atkbd->ps2dev, param, ATKBD_CMD_SETLEDS)) 5953d0f0fa0SDmitry Torokhov return -1; 5961da177e4SLinus Torvalds 5971da177e4SLinus Torvalds if (atkbd->extra) { 5981da177e4SLinus Torvalds param[0] = 0; 5991da177e4SLinus Torvalds param[1] = (test_bit(LED_COMPOSE, dev->led) ? 0x01 : 0) 6001da177e4SLinus Torvalds | (test_bit(LED_SLEEP, dev->led) ? 0x02 : 0) 6011da177e4SLinus Torvalds | (test_bit(LED_SUSPEND, dev->led) ? 0x04 : 0) 6021da177e4SLinus Torvalds | (test_bit(LED_MISC, dev->led) ? 0x10 : 0) 6031da177e4SLinus Torvalds | (test_bit(LED_MUTE, dev->led) ? 0x20 : 0); 6043d0f0fa0SDmitry Torokhov if (ps2_command(&atkbd->ps2dev, param, ATKBD_CMD_EX_SETLEDS)) 6053d0f0fa0SDmitry Torokhov return -1; 6061da177e4SLinus Torvalds } 6071da177e4SLinus Torvalds 6083d0f0fa0SDmitry Torokhov return 0; 6090d4c8597SDmitry Torokhov } 6100d4c8597SDmitry Torokhov 6113d0f0fa0SDmitry Torokhov /* 6123d0f0fa0SDmitry Torokhov * atkbd_event_work() is used to complete processing of events that 6133d0f0fa0SDmitry Torokhov * can not be processed by input_event() which is often called from 6143d0f0fa0SDmitry Torokhov * interrupt context. 6153d0f0fa0SDmitry Torokhov */ 6163d0f0fa0SDmitry Torokhov 61765f27f38SDavid Howells static void atkbd_event_work(struct work_struct *work) 6183d0f0fa0SDmitry Torokhov { 619da4249c9SDmitry Torokhov struct atkbd *atkbd = container_of(work, struct atkbd, event_work.work); 6203d0f0fa0SDmitry Torokhov 62159b01513SEric W. Biederman mutex_lock(&atkbd->mutex); 6223d0f0fa0SDmitry Torokhov 62394dfb0d6SDmitry Torokhov if (!atkbd->enabled) { 62494dfb0d6SDmitry Torokhov /* 62594dfb0d6SDmitry Torokhov * Serio ports are resumed asynchronously so while driver core 62694dfb0d6SDmitry Torokhov * thinks that device is already fully operational in reality 62794dfb0d6SDmitry Torokhov * it may not be ready yet. In this case we need to keep 62894dfb0d6SDmitry Torokhov * rescheduling till reconnect completes. 62994dfb0d6SDmitry Torokhov */ 63094dfb0d6SDmitry Torokhov schedule_delayed_work(&atkbd->event_work, 63194dfb0d6SDmitry Torokhov msecs_to_jiffies(100)); 63294dfb0d6SDmitry Torokhov } else { 6333d0f0fa0SDmitry Torokhov if (test_and_clear_bit(ATKBD_LED_EVENT_BIT, &atkbd->event_mask)) 6343d0f0fa0SDmitry Torokhov atkbd_set_leds(atkbd); 6353d0f0fa0SDmitry Torokhov 6363d0f0fa0SDmitry Torokhov if (test_and_clear_bit(ATKBD_REP_EVENT_BIT, &atkbd->event_mask)) 6373d0f0fa0SDmitry Torokhov atkbd_set_repeat_rate(atkbd); 63894dfb0d6SDmitry Torokhov } 6393d0f0fa0SDmitry Torokhov 64059b01513SEric W. Biederman mutex_unlock(&atkbd->mutex); 6410d4c8597SDmitry Torokhov } 6420d4c8597SDmitry Torokhov 6430d4c8597SDmitry Torokhov /* 644da4249c9SDmitry Torokhov * Schedule switch for execution. We need to throttle requests, 645da4249c9SDmitry Torokhov * otherwise keyboard may become unresponsive. 646da4249c9SDmitry Torokhov */ 647da4249c9SDmitry Torokhov static void atkbd_schedule_event_work(struct atkbd *atkbd, int event_bit) 648da4249c9SDmitry Torokhov { 649da4249c9SDmitry Torokhov unsigned long delay = msecs_to_jiffies(50); 650da4249c9SDmitry Torokhov 651da4249c9SDmitry Torokhov if (time_after(jiffies, atkbd->event_jiffies + delay)) 652da4249c9SDmitry Torokhov delay = 0; 653da4249c9SDmitry Torokhov 654da4249c9SDmitry Torokhov atkbd->event_jiffies = jiffies; 655da4249c9SDmitry Torokhov set_bit(event_bit, &atkbd->event_mask); 65659b01513SEric W. Biederman mb(); 657da4249c9SDmitry Torokhov schedule_delayed_work(&atkbd->event_work, delay); 658da4249c9SDmitry Torokhov } 659da4249c9SDmitry Torokhov 660da4249c9SDmitry Torokhov /* 6610d4c8597SDmitry Torokhov * Event callback from the input module. Events that change the state of 6620d4c8597SDmitry Torokhov * the hardware are processed here. If action can not be performed in 6630d4c8597SDmitry Torokhov * interrupt context it is offloaded to atkbd_event_work. 6640d4c8597SDmitry Torokhov */ 6650d4c8597SDmitry Torokhov 666da4249c9SDmitry Torokhov static int atkbd_event(struct input_dev *dev, 667da4249c9SDmitry Torokhov unsigned int type, unsigned int code, int value) 6680d4c8597SDmitry Torokhov { 669b356872fSDmitry Torokhov struct atkbd *atkbd = input_get_drvdata(dev); 6700d4c8597SDmitry Torokhov 6710d4c8597SDmitry Torokhov if (!atkbd->write) 6720d4c8597SDmitry Torokhov return -1; 6730d4c8597SDmitry Torokhov 6740d4c8597SDmitry Torokhov switch (type) { 6750d4c8597SDmitry Torokhov 6760d4c8597SDmitry Torokhov case EV_LED: 677da4249c9SDmitry Torokhov atkbd_schedule_event_work(atkbd, ATKBD_LED_EVENT_BIT); 6780d4c8597SDmitry Torokhov return 0; 6790d4c8597SDmitry Torokhov 6800d4c8597SDmitry Torokhov case EV_REP: 681da4249c9SDmitry Torokhov if (!atkbd->softrepeat) 682da4249c9SDmitry Torokhov atkbd_schedule_event_work(atkbd, ATKBD_REP_EVENT_BIT); 6831da177e4SLinus Torvalds return 0; 6841da177e4SLinus Torvalds 685a9a1f9c3SDmitry Torokhov default: 6861da177e4SLinus Torvalds return -1; 6871da177e4SLinus Torvalds } 688a9a1f9c3SDmitry Torokhov } 6891da177e4SLinus Torvalds 6901da177e4SLinus Torvalds /* 6911da177e4SLinus Torvalds * atkbd_enable() signals that interrupt handler is allowed to 6921da177e4SLinus Torvalds * generate input events. 6931da177e4SLinus Torvalds */ 6941da177e4SLinus Torvalds 6951da177e4SLinus Torvalds static inline void atkbd_enable(struct atkbd *atkbd) 6961da177e4SLinus Torvalds { 6971da177e4SLinus Torvalds serio_pause_rx(atkbd->ps2dev.serio); 698a9a1f9c3SDmitry Torokhov atkbd->enabled = true; 6991da177e4SLinus Torvalds serio_continue_rx(atkbd->ps2dev.serio); 7001da177e4SLinus Torvalds } 7011da177e4SLinus Torvalds 7021da177e4SLinus Torvalds /* 7031da177e4SLinus Torvalds * atkbd_disable() tells input handler that all incoming data except 7041da177e4SLinus Torvalds * for ACKs and command response should be dropped. 7051da177e4SLinus Torvalds */ 7061da177e4SLinus Torvalds 7071da177e4SLinus Torvalds static inline void atkbd_disable(struct atkbd *atkbd) 7081da177e4SLinus Torvalds { 7091da177e4SLinus Torvalds serio_pause_rx(atkbd->ps2dev.serio); 710a9a1f9c3SDmitry Torokhov atkbd->enabled = false; 7111da177e4SLinus Torvalds serio_continue_rx(atkbd->ps2dev.serio); 7121da177e4SLinus Torvalds } 7131da177e4SLinus Torvalds 714be2d7e42SShawn Nematbakhsh static int atkbd_activate(struct atkbd *atkbd) 715be2d7e42SShawn Nematbakhsh { 716be2d7e42SShawn Nematbakhsh struct ps2dev *ps2dev = &atkbd->ps2dev; 717be2d7e42SShawn Nematbakhsh 718be2d7e42SShawn Nematbakhsh /* 719be2d7e42SShawn Nematbakhsh * Enable the keyboard to receive keystrokes. 720be2d7e42SShawn Nematbakhsh */ 721be2d7e42SShawn Nematbakhsh 722be2d7e42SShawn Nematbakhsh if (ps2_command(ps2dev, NULL, ATKBD_CMD_ENABLE)) { 723be2d7e42SShawn Nematbakhsh dev_err(&ps2dev->serio->dev, 724be2d7e42SShawn Nematbakhsh "Failed to enable keyboard on %s\n", 725be2d7e42SShawn Nematbakhsh ps2dev->serio->phys); 726be2d7e42SShawn Nematbakhsh return -1; 727be2d7e42SShawn Nematbakhsh } 728be2d7e42SShawn Nematbakhsh 729be2d7e42SShawn Nematbakhsh return 0; 730be2d7e42SShawn Nematbakhsh } 731be2d7e42SShawn Nematbakhsh 732be2d7e42SShawn Nematbakhsh /* 733be2d7e42SShawn Nematbakhsh * atkbd_deactivate() resets and disables the keyboard from sending 734be2d7e42SShawn Nematbakhsh * keystrokes. 735be2d7e42SShawn Nematbakhsh */ 736be2d7e42SShawn Nematbakhsh 737be2d7e42SShawn Nematbakhsh static void atkbd_deactivate(struct atkbd *atkbd) 738be2d7e42SShawn Nematbakhsh { 739be2d7e42SShawn Nematbakhsh struct ps2dev *ps2dev = &atkbd->ps2dev; 740be2d7e42SShawn Nematbakhsh 741be2d7e42SShawn Nematbakhsh if (ps2_command(ps2dev, NULL, ATKBD_CMD_RESET_DIS)) 742be2d7e42SShawn Nematbakhsh dev_err(&ps2dev->serio->dev, 743be2d7e42SShawn Nematbakhsh "Failed to deactivate keyboard on %s\n", 744be2d7e42SShawn Nematbakhsh ps2dev->serio->phys); 745be2d7e42SShawn Nematbakhsh } 746be2d7e42SShawn Nematbakhsh 7471da177e4SLinus Torvalds /* 7481da177e4SLinus Torvalds * atkbd_probe() probes for an AT keyboard on a serio port. 7491da177e4SLinus Torvalds */ 7501da177e4SLinus Torvalds 7511da177e4SLinus Torvalds static int atkbd_probe(struct atkbd *atkbd) 7521da177e4SLinus Torvalds { 7531da177e4SLinus Torvalds struct ps2dev *ps2dev = &atkbd->ps2dev; 7541da177e4SLinus Torvalds unsigned char param[2]; 7551da177e4SLinus Torvalds 7561da177e4SLinus Torvalds /* 7571da177e4SLinus Torvalds * Some systems, where the bit-twiddling when testing the io-lines of the 7581da177e4SLinus Torvalds * controller may confuse the keyboard need a full reset of the keyboard. On 7591da177e4SLinus Torvalds * these systems the BIOS also usually doesn't do it for us. 7601da177e4SLinus Torvalds */ 7611da177e4SLinus Torvalds 7621da177e4SLinus Torvalds if (atkbd_reset) 7631da177e4SLinus Torvalds if (ps2_command(ps2dev, NULL, ATKBD_CMD_RESET_BAT)) 764a9a1f9c3SDmitry Torokhov dev_warn(&ps2dev->serio->dev, 765a9a1f9c3SDmitry Torokhov "keyboard reset failed on %s\n", 766a9a1f9c3SDmitry Torokhov ps2dev->serio->phys); 7671da177e4SLinus Torvalds 7681da177e4SLinus Torvalds /* 7691da177e4SLinus Torvalds * Then we check the keyboard ID. We should get 0xab83 under normal conditions. 7701da177e4SLinus Torvalds * Some keyboards report different values, but the first byte is always 0xab or 7711da177e4SLinus Torvalds * 0xac. Some old AT keyboards don't report anything. If a mouse is connected, this 7721da177e4SLinus Torvalds * should make sure we don't try to set the LEDs on it. 7731da177e4SLinus Torvalds */ 7741da177e4SLinus Torvalds 7751da177e4SLinus Torvalds param[0] = param[1] = 0xa5; /* initialize with invalid values */ 7761da177e4SLinus Torvalds if (ps2_command(ps2dev, param, ATKBD_CMD_GETID)) { 7771da177e4SLinus Torvalds 7781da177e4SLinus Torvalds /* 7791da177e4SLinus Torvalds * If the get ID command failed, we check if we can at least set the LEDs on 7801da177e4SLinus Torvalds * the keyboard. This should work on every keyboard out there. It also turns 7811da177e4SLinus Torvalds * the LEDs off, which we want anyway. 7821da177e4SLinus Torvalds */ 7831da177e4SLinus Torvalds param[0] = 0; 7841da177e4SLinus Torvalds if (ps2_command(ps2dev, param, ATKBD_CMD_SETLEDS)) 7851da177e4SLinus Torvalds return -1; 7861da177e4SLinus Torvalds atkbd->id = 0xabba; 7871da177e4SLinus Torvalds return 0; 7881da177e4SLinus Torvalds } 7891da177e4SLinus Torvalds 7909807879bSDmitry Torokhov if (!ps2_is_keyboard_id(param[0])) 7911da177e4SLinus Torvalds return -1; 7921da177e4SLinus Torvalds 7931da177e4SLinus Torvalds atkbd->id = (param[0] << 8) | param[1]; 7941da177e4SLinus Torvalds 7951da177e4SLinus Torvalds if (atkbd->id == 0xaca1 && atkbd->translated) { 796a9a1f9c3SDmitry Torokhov dev_err(&ps2dev->serio->dev, 797236d6a77SDmitry Torokhov "NCD terminal keyboards are only supported on non-translating controllers. " 798a9a1f9c3SDmitry Torokhov "Use i8042.direct=1 to disable translation.\n"); 7991da177e4SLinus Torvalds return -1; 8001da177e4SLinus Torvalds } 8011da177e4SLinus Torvalds 802be2d7e42SShawn Nematbakhsh /* 803be2d7e42SShawn Nematbakhsh * Make sure nothing is coming from the keyboard and disturbs our 804be2d7e42SShawn Nematbakhsh * internal state. 805be2d7e42SShawn Nematbakhsh */ 8063d725caaSSheng-Liang Song if (!atkbd_skip_deactivate) 807be2d7e42SShawn Nematbakhsh atkbd_deactivate(atkbd); 808be2d7e42SShawn Nematbakhsh 8091da177e4SLinus Torvalds return 0; 8101da177e4SLinus Torvalds } 8111da177e4SLinus Torvalds 8121da177e4SLinus Torvalds /* 8131da177e4SLinus Torvalds * atkbd_select_set checks if a keyboard has a working Set 3 support, and 8141da177e4SLinus Torvalds * sets it into that. Unfortunately there are keyboards that can be switched 8151da177e4SLinus Torvalds * to Set 3, but don't work well in that (BTC Multimedia ...) 8161da177e4SLinus Torvalds */ 8171da177e4SLinus Torvalds 8181da177e4SLinus Torvalds static int atkbd_select_set(struct atkbd *atkbd, int target_set, int allow_extra) 8191da177e4SLinus Torvalds { 8201da177e4SLinus Torvalds struct ps2dev *ps2dev = &atkbd->ps2dev; 8211da177e4SLinus Torvalds unsigned char param[2]; 8221da177e4SLinus Torvalds 823a9a1f9c3SDmitry Torokhov atkbd->extra = false; 8241da177e4SLinus Torvalds /* 8251da177e4SLinus Torvalds * For known special keyboards we can go ahead and set the correct set. 8261da177e4SLinus Torvalds * We check for NCD PS/2 Sun, NorthGate OmniKey 101 and 8271da177e4SLinus Torvalds * IBM RapidAccess / IBM EzButton / Chicony KBP-8993 keyboards. 8281da177e4SLinus Torvalds */ 8291da177e4SLinus Torvalds 8301da177e4SLinus Torvalds if (atkbd->translated) 8311da177e4SLinus Torvalds return 2; 8321da177e4SLinus Torvalds 8331da177e4SLinus Torvalds if (atkbd->id == 0xaca1) { 8341da177e4SLinus Torvalds param[0] = 3; 8351da177e4SLinus Torvalds ps2_command(ps2dev, param, ATKBD_CMD_SSCANSET); 8361da177e4SLinus Torvalds return 3; 8371da177e4SLinus Torvalds } 8381da177e4SLinus Torvalds 8391da177e4SLinus Torvalds if (allow_extra) { 8401da177e4SLinus Torvalds param[0] = 0x71; 8411da177e4SLinus Torvalds if (!ps2_command(ps2dev, param, ATKBD_CMD_EX_ENABLE)) { 842a9a1f9c3SDmitry Torokhov atkbd->extra = true; 8431da177e4SLinus Torvalds return 2; 8441da177e4SLinus Torvalds } 8451da177e4SLinus Torvalds } 8461da177e4SLinus Torvalds 8478c5188b6SBenjamin LaHaise if (atkbd_terminal) { 8488c5188b6SBenjamin LaHaise ps2_command(ps2dev, param, ATKBD_CMD_SETALL_MB); 8498c5188b6SBenjamin LaHaise return 3; 8508c5188b6SBenjamin LaHaise } 8518c5188b6SBenjamin LaHaise 8521da177e4SLinus Torvalds if (target_set != 3) 8531da177e4SLinus Torvalds return 2; 8541da177e4SLinus Torvalds 8551da177e4SLinus Torvalds if (!ps2_command(ps2dev, param, ATKBD_CMD_OK_GETID)) { 8561da177e4SLinus Torvalds atkbd->id = param[0] << 8 | param[1]; 8571da177e4SLinus Torvalds return 2; 8581da177e4SLinus Torvalds } 8591da177e4SLinus Torvalds 8601da177e4SLinus Torvalds param[0] = 3; 8611da177e4SLinus Torvalds if (ps2_command(ps2dev, param, ATKBD_CMD_SSCANSET)) 8621da177e4SLinus Torvalds return 2; 8631da177e4SLinus Torvalds 8641da177e4SLinus Torvalds param[0] = 0; 8651da177e4SLinus Torvalds if (ps2_command(ps2dev, param, ATKBD_CMD_GSCANSET)) 8661da177e4SLinus Torvalds return 2; 8671da177e4SLinus Torvalds 8681da177e4SLinus Torvalds if (param[0] != 3) { 8691da177e4SLinus Torvalds param[0] = 2; 8701da177e4SLinus Torvalds if (ps2_command(ps2dev, param, ATKBD_CMD_SSCANSET)) 8711da177e4SLinus Torvalds return 2; 8721da177e4SLinus Torvalds } 8731da177e4SLinus Torvalds 8741da177e4SLinus Torvalds ps2_command(ps2dev, param, ATKBD_CMD_SETALL_MBR); 8751da177e4SLinus Torvalds 8761da177e4SLinus Torvalds return 3; 8771da177e4SLinus Torvalds } 8781da177e4SLinus Torvalds 879fc0eb28cSDmitry Torokhov static int atkbd_reset_state(struct atkbd *atkbd) 880fc0eb28cSDmitry Torokhov { 881fc0eb28cSDmitry Torokhov struct ps2dev *ps2dev = &atkbd->ps2dev; 882fc0eb28cSDmitry Torokhov unsigned char param[1]; 883fc0eb28cSDmitry Torokhov 884fc0eb28cSDmitry Torokhov /* 885fc0eb28cSDmitry Torokhov * Set the LEDs to a predefined state (all off). 886fc0eb28cSDmitry Torokhov */ 887fc0eb28cSDmitry Torokhov 888fc0eb28cSDmitry Torokhov param[0] = 0; 889fc0eb28cSDmitry Torokhov if (ps2_command(ps2dev, param, ATKBD_CMD_SETLEDS)) 890fc0eb28cSDmitry Torokhov return -1; 891fc0eb28cSDmitry Torokhov 892fc0eb28cSDmitry Torokhov /* 893fc0eb28cSDmitry Torokhov * Set autorepeat to fastest possible. 894fc0eb28cSDmitry Torokhov */ 895fc0eb28cSDmitry Torokhov 896fc0eb28cSDmitry Torokhov param[0] = 0; 897fc0eb28cSDmitry Torokhov if (ps2_command(ps2dev, param, ATKBD_CMD_SETREP)) 898fc0eb28cSDmitry Torokhov return -1; 899fc0eb28cSDmitry Torokhov 900fc0eb28cSDmitry Torokhov return 0; 901fc0eb28cSDmitry Torokhov } 902fc0eb28cSDmitry Torokhov 9031da177e4SLinus Torvalds /* 9041da177e4SLinus Torvalds * atkbd_cleanup() restores the keyboard state so that BIOS is happy after a 9051da177e4SLinus Torvalds * reboot. 9061da177e4SLinus Torvalds */ 9071da177e4SLinus Torvalds 9081da177e4SLinus Torvalds static void atkbd_cleanup(struct serio *serio) 9091da177e4SLinus Torvalds { 9101da177e4SLinus Torvalds struct atkbd *atkbd = serio_get_drvdata(serio); 91157f5b159SDmitry Torokhov 91257f5b159SDmitry Torokhov atkbd_disable(atkbd); 9134a299bf5SDmitry Torokhov ps2_command(&atkbd->ps2dev, NULL, ATKBD_CMD_RESET_DEF); 9141da177e4SLinus Torvalds } 9151da177e4SLinus Torvalds 9161da177e4SLinus Torvalds 9171da177e4SLinus Torvalds /* 9181da177e4SLinus Torvalds * atkbd_disconnect() closes and frees. 9191da177e4SLinus Torvalds */ 9201da177e4SLinus Torvalds 9211da177e4SLinus Torvalds static void atkbd_disconnect(struct serio *serio) 9221da177e4SLinus Torvalds { 9231da177e4SLinus Torvalds struct atkbd *atkbd = serio_get_drvdata(serio); 9241da177e4SLinus Torvalds 92559b01513SEric W. Biederman sysfs_remove_group(&serio->dev.kobj, &atkbd_attribute_group); 92659b01513SEric W. Biederman 9271da177e4SLinus Torvalds atkbd_disable(atkbd); 9281da177e4SLinus Torvalds 9290ef7a26aSDmitry Torokhov input_unregister_device(atkbd->dev); 9300ef7a26aSDmitry Torokhov 9310ef7a26aSDmitry Torokhov /* 9320ef7a26aSDmitry Torokhov * Make sure we don't have a command in flight. 9330ef7a26aSDmitry Torokhov * Note that since atkbd->enabled is false event work will keep 9340ef7a26aSDmitry Torokhov * rescheduling itself until it gets canceled and will not try 9350ef7a26aSDmitry Torokhov * accessing freed input device or serio port. 9360ef7a26aSDmitry Torokhov */ 937d6d79a78SJiri Pirko cancel_delayed_work_sync(&atkbd->event_work); 9381da177e4SLinus Torvalds 9391da177e4SLinus Torvalds serio_close(serio); 9401da177e4SLinus Torvalds serio_set_drvdata(serio, NULL); 9411da177e4SLinus Torvalds kfree(atkbd); 9421da177e4SLinus Torvalds } 9431da177e4SLinus Torvalds 944554101e3SGiel de Nijs /* 94539191698SDaniel Mierswa * generate release events for the keycodes given in data 94639191698SDaniel Mierswa */ 94739191698SDaniel Mierswa static void atkbd_apply_forced_release_keylist(struct atkbd* atkbd, 94839191698SDaniel Mierswa const void *data) 94939191698SDaniel Mierswa { 95039191698SDaniel Mierswa const unsigned int *keys = data; 95139191698SDaniel Mierswa unsigned int i; 95239191698SDaniel Mierswa 95339191698SDaniel Mierswa if (atkbd->set == 2) 95439191698SDaniel Mierswa for (i = 0; keys[i] != -1U; i++) 95539191698SDaniel Mierswa __set_bit(keys[i], atkbd->force_release_mask); 95639191698SDaniel Mierswa } 95739191698SDaniel Mierswa 95839191698SDaniel Mierswa /* 95961579ba8SMatthew Garrett * Most special keys (Fn+F?) on Dell laptops do not generate release 960554101e3SGiel de Nijs * events so we have to do it ourselves. 961554101e3SGiel de Nijs */ 96239191698SDaniel Mierswa static unsigned int atkbd_dell_laptop_forced_release_keys[] = { 96339191698SDaniel Mierswa 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8f, 0x93, -1U 964554101e3SGiel de Nijs }; 9651da177e4SLinus Torvalds 9661da177e4SLinus Torvalds /* 9675a54c011SJiri Kosina * Perform fixup for HP system that doesn't generate release 9685a54c011SJiri Kosina * for its video switch 9695a54c011SJiri Kosina */ 97039191698SDaniel Mierswa static unsigned int atkbd_hp_forced_release_keys[] = { 97139191698SDaniel Mierswa 0x94, -1U 9725a54c011SJiri Kosina }; 9735a54c011SJiri Kosina 9745a54c011SJiri Kosina /* 975e04126c7SBarry Carroll * Samsung NC10,NC20 with Fn+F? key release not working 9764200844bSStuart Hopkins */ 97739191698SDaniel Mierswa static unsigned int atkbd_samsung_forced_release_keys[] = { 97839191698SDaniel Mierswa 0x82, 0x83, 0x84, 0x86, 0x88, 0x89, 0xb3, 0xf7, 0xf9, -1U 9794200844bSStuart Hopkins }; 9804200844bSStuart Hopkins 9814200844bSStuart Hopkins /* 982f0a14de2SSimon Davie * Amilo Pi 3525 key release for Fn+Volume keys not working 983f0a14de2SSimon Davie */ 984f0a14de2SSimon Davie static unsigned int atkbd_amilo_pi3525_forced_release_keys[] = { 985f0a14de2SSimon Davie 0x20, 0xa0, 0x2e, 0xae, 0x30, 0xb0, -1U 986f0a14de2SSimon Davie }; 987f0a14de2SSimon Davie 988f0a14de2SSimon Davie /* 9899166d0f6SAdrian Batzill * Amilo Xi 3650 key release for light touch bar not working 9909166d0f6SAdrian Batzill */ 9919166d0f6SAdrian Batzill static unsigned int atkbd_amilo_xi3650_forced_release_keys[] = { 9929166d0f6SAdrian Batzill 0x67, 0xed, 0x90, 0xa2, 0x99, 0xa4, 0xae, 0xb0, -1U 9939166d0f6SAdrian Batzill }; 9949166d0f6SAdrian Batzill 9959166d0f6SAdrian Batzill /* 996032e46cbSJerone Young * Soltech TA12 system with broken key release on volume keys and mute key 997032e46cbSJerone Young */ 998032e46cbSJerone Young static unsigned int atkdb_soltech_ta12_forced_release_keys[] = { 999032e46cbSJerone Young 0xa0, 0xae, 0xb0, -1U 1000032e46cbSJerone Young }; 1001032e46cbSJerone Young 1002032e46cbSJerone Young /* 1003000c2a35SHerton Ronaldo Krzesinski * Many notebooks don't send key release event for volume up/down 1004000c2a35SHerton Ronaldo Krzesinski * keys, with key list below common among them 1005000c2a35SHerton Ronaldo Krzesinski */ 1006000c2a35SHerton Ronaldo Krzesinski static unsigned int atkbd_volume_forced_release_keys[] = { 1007000c2a35SHerton Ronaldo Krzesinski 0xae, 0xb0, -1U 1008000c2a35SHerton Ronaldo Krzesinski }; 1009000c2a35SHerton Ronaldo Krzesinski 1010000c2a35SHerton Ronaldo Krzesinski /* 1011e5713069SJamie Lentin * OQO 01+ multimedia keys (64--66) generate e0 6x upon release whereas 1012e5713069SJamie Lentin * they should be generating e4-e6 (0x80 | code). 1013e5713069SJamie Lentin */ 1014e5713069SJamie Lentin static unsigned int atkbd_oqo_01plus_scancode_fixup(struct atkbd *atkbd, 1015e5713069SJamie Lentin unsigned int code) 1016e5713069SJamie Lentin { 1017e5713069SJamie Lentin if (atkbd->translated && atkbd->emul == 1 && 1018e5713069SJamie Lentin (code == 0x64 || code == 0x65 || code == 0x66)) { 1019e5713069SJamie Lentin atkbd->emul = 0; 1020e5713069SJamie Lentin code |= 0x80; 1021e5713069SJamie Lentin } 1022e5713069SJamie Lentin 1023e5713069SJamie Lentin return code; 1024e5713069SJamie Lentin } 1025e5713069SJamie Lentin 10269d17ad23SRajat Jain static int atkbd_get_keymap_from_fwnode(struct atkbd *atkbd) 10279d17ad23SRajat Jain { 10289d17ad23SRajat Jain struct device *dev = &atkbd->ps2dev.serio->dev; 10299d17ad23SRajat Jain int i, n; 10309d17ad23SRajat Jain u32 *ptr; 10319d17ad23SRajat Jain u16 scancode, keycode; 10329d17ad23SRajat Jain 10339d17ad23SRajat Jain /* Parse "linux,keymap" property */ 10349d17ad23SRajat Jain n = device_property_count_u32(dev, "linux,keymap"); 10359d17ad23SRajat Jain if (n <= 0 || n > ATKBD_KEYMAP_SIZE) 10369d17ad23SRajat Jain return -ENXIO; 10379d17ad23SRajat Jain 10389d17ad23SRajat Jain ptr = kcalloc(n, sizeof(u32), GFP_KERNEL); 10399d17ad23SRajat Jain if (!ptr) 10409d17ad23SRajat Jain return -ENOMEM; 10419d17ad23SRajat Jain 10429d17ad23SRajat Jain if (device_property_read_u32_array(dev, "linux,keymap", ptr, n)) { 10439d17ad23SRajat Jain dev_err(dev, "problem parsing FW keymap property\n"); 10449d17ad23SRajat Jain kfree(ptr); 10459d17ad23SRajat Jain return -EINVAL; 10469d17ad23SRajat Jain } 10479d17ad23SRajat Jain 10489d17ad23SRajat Jain memset(atkbd->keycode, 0, sizeof(atkbd->keycode)); 10499d17ad23SRajat Jain for (i = 0; i < n; i++) { 10509d17ad23SRajat Jain scancode = SCANCODE(ptr[i]); 10519d17ad23SRajat Jain keycode = KEYCODE(ptr[i]); 10529d17ad23SRajat Jain atkbd->keycode[scancode] = keycode; 10539d17ad23SRajat Jain } 10549d17ad23SRajat Jain 10559d17ad23SRajat Jain kfree(ptr); 10569d17ad23SRajat Jain return 0; 10579d17ad23SRajat Jain } 10589d17ad23SRajat Jain 1059e5713069SJamie Lentin /* 10603c42f0c3SDmitry Torokhov * atkbd_set_keycode_table() initializes keyboard's keycode table 10611da177e4SLinus Torvalds * according to the selected scancode set 10621da177e4SLinus Torvalds */ 10631da177e4SLinus Torvalds 10641da177e4SLinus Torvalds static void atkbd_set_keycode_table(struct atkbd *atkbd) 10651da177e4SLinus Torvalds { 10669d17ad23SRajat Jain struct device *dev = &atkbd->ps2dev.serio->dev; 1067554101e3SGiel de Nijs unsigned int scancode; 10681da177e4SLinus Torvalds int i, j; 10691da177e4SLinus Torvalds 10701da177e4SLinus Torvalds memset(atkbd->keycode, 0, sizeof(atkbd->keycode)); 10711ba36e11SDmitry Torokhov bitmap_zero(atkbd->force_release_mask, ATKBD_KEYMAP_SIZE); 10721da177e4SLinus Torvalds 10739d17ad23SRajat Jain if (!atkbd_get_keymap_from_fwnode(atkbd)) { 10749d17ad23SRajat Jain dev_dbg(dev, "Using FW keymap\n"); 10759d17ad23SRajat Jain } else if (atkbd->translated) { 10761da177e4SLinus Torvalds for (i = 0; i < 128; i++) { 1077554101e3SGiel de Nijs scancode = atkbd_unxlate_table[i]; 1078554101e3SGiel de Nijs atkbd->keycode[i] = atkbd_set2_keycode[scancode]; 1079554101e3SGiel de Nijs atkbd->keycode[i | 0x80] = atkbd_set2_keycode[scancode | 0x80]; 10801da177e4SLinus Torvalds if (atkbd->scroll) 10811da177e4SLinus Torvalds for (j = 0; j < ARRAY_SIZE(atkbd_scroll_keys); j++) 1082554101e3SGiel de Nijs if ((scancode | 0x80) == atkbd_scroll_keys[j].set2) 10831da177e4SLinus Torvalds atkbd->keycode[i | 0x80] = atkbd_scroll_keys[j].keycode; 10841da177e4SLinus Torvalds } 10851da177e4SLinus Torvalds } else if (atkbd->set == 3) { 10861da177e4SLinus Torvalds memcpy(atkbd->keycode, atkbd_set3_keycode, sizeof(atkbd->keycode)); 10871da177e4SLinus Torvalds } else { 10881da177e4SLinus Torvalds memcpy(atkbd->keycode, atkbd_set2_keycode, sizeof(atkbd->keycode)); 10891da177e4SLinus Torvalds 10901da177e4SLinus Torvalds if (atkbd->scroll) 1091554101e3SGiel de Nijs for (i = 0; i < ARRAY_SIZE(atkbd_scroll_keys); i++) { 1092554101e3SGiel de Nijs scancode = atkbd_scroll_keys[i].set2; 1093554101e3SGiel de Nijs atkbd->keycode[scancode] = atkbd_scroll_keys[i].keycode; 1094554101e3SGiel de Nijs } 10951da177e4SLinus Torvalds } 10960ae051a1SDmitry Torokhov 1097554101e3SGiel de Nijs /* 1098554101e3SGiel de Nijs * HANGEUL and HANJA keys do not send release events so we need to 1099554101e3SGiel de Nijs * generate such events ourselves 1100554101e3SGiel de Nijs */ 1101554101e3SGiel de Nijs scancode = atkbd_compat_scancode(atkbd, ATKBD_RET_HANGEUL); 1102554101e3SGiel de Nijs atkbd->keycode[scancode] = KEY_HANGEUL; 1103554101e3SGiel de Nijs __set_bit(scancode, atkbd->force_release_mask); 1104554101e3SGiel de Nijs 1105554101e3SGiel de Nijs scancode = atkbd_compat_scancode(atkbd, ATKBD_RET_HANJA); 1106554101e3SGiel de Nijs atkbd->keycode[scancode] = KEY_HANJA; 1107554101e3SGiel de Nijs __set_bit(scancode, atkbd->force_release_mask); 1108554101e3SGiel de Nijs 1109554101e3SGiel de Nijs /* 1110554101e3SGiel de Nijs * Perform additional fixups 1111554101e3SGiel de Nijs */ 1112554101e3SGiel de Nijs if (atkbd_platform_fixup) 111339191698SDaniel Mierswa atkbd_platform_fixup(atkbd, atkbd_platform_fixup_data); 11141da177e4SLinus Torvalds } 11151da177e4SLinus Torvalds 11161da177e4SLinus Torvalds /* 11171da177e4SLinus Torvalds * atkbd_set_device_attrs() sets up keyboard's input device structure 11181da177e4SLinus Torvalds */ 11191da177e4SLinus Torvalds 11201da177e4SLinus Torvalds static void atkbd_set_device_attrs(struct atkbd *atkbd) 11211da177e4SLinus Torvalds { 11223c42f0c3SDmitry Torokhov struct input_dev *input_dev = atkbd->dev; 11231da177e4SLinus Torvalds int i; 11241da177e4SLinus Torvalds 11253c42f0c3SDmitry Torokhov if (atkbd->extra) 1126ea08c6faSDmitry Torokhov snprintf(atkbd->name, sizeof(atkbd->name), 1127ea08c6faSDmitry Torokhov "AT Set 2 Extra keyboard"); 11283c42f0c3SDmitry Torokhov else 1129ea08c6faSDmitry Torokhov snprintf(atkbd->name, sizeof(atkbd->name), 1130ea08c6faSDmitry Torokhov "AT %s Set %d keyboard", 11313c42f0c3SDmitry Torokhov atkbd->translated ? "Translated" : "Raw", atkbd->set); 11321da177e4SLinus Torvalds 1133ea08c6faSDmitry Torokhov snprintf(atkbd->phys, sizeof(atkbd->phys), 1134ea08c6faSDmitry Torokhov "%s/input0", atkbd->ps2dev.serio->phys); 11351da177e4SLinus Torvalds 11363c42f0c3SDmitry Torokhov input_dev->name = atkbd->name; 11373c42f0c3SDmitry Torokhov input_dev->phys = atkbd->phys; 11383c42f0c3SDmitry Torokhov input_dev->id.bustype = BUS_I8042; 11393c42f0c3SDmitry Torokhov input_dev->id.vendor = 0x0001; 11403c42f0c3SDmitry Torokhov input_dev->id.product = atkbd->translated ? 1 : atkbd->set; 11413c42f0c3SDmitry Torokhov input_dev->id.version = atkbd->id; 11423c42f0c3SDmitry Torokhov input_dev->event = atkbd_event; 1143469ba4dfSDmitry Torokhov input_dev->dev.parent = &atkbd->ps2dev.serio->dev; 11441da177e4SLinus Torvalds 1145b356872fSDmitry Torokhov input_set_drvdata(input_dev, atkbd); 1146b356872fSDmitry Torokhov 11477b19ada2SJiri Slaby input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP) | 11487b19ada2SJiri Slaby BIT_MASK(EV_MSC); 11491da177e4SLinus Torvalds 11501da177e4SLinus Torvalds if (atkbd->write) { 11517b19ada2SJiri Slaby input_dev->evbit[0] |= BIT_MASK(EV_LED); 11527b19ada2SJiri Slaby input_dev->ledbit[0] = BIT_MASK(LED_NUML) | 11537b19ada2SJiri Slaby BIT_MASK(LED_CAPSL) | BIT_MASK(LED_SCROLLL); 11541da177e4SLinus Torvalds } 11551da177e4SLinus Torvalds 11561da177e4SLinus Torvalds if (atkbd->extra) 11577b19ada2SJiri Slaby input_dev->ledbit[0] |= BIT_MASK(LED_COMPOSE) | 11587b19ada2SJiri Slaby BIT_MASK(LED_SUSPEND) | BIT_MASK(LED_SLEEP) | 11597b19ada2SJiri Slaby BIT_MASK(LED_MUTE) | BIT_MASK(LED_MISC); 11601da177e4SLinus Torvalds 11611da177e4SLinus Torvalds if (!atkbd->softrepeat) { 11623c42f0c3SDmitry Torokhov input_dev->rep[REP_DELAY] = 250; 11633c42f0c3SDmitry Torokhov input_dev->rep[REP_PERIOD] = 33; 11641da177e4SLinus Torvalds } 11651da177e4SLinus Torvalds 11667b19ada2SJiri Slaby input_dev->mscbit[0] = atkbd->softraw ? BIT_MASK(MSC_SCAN) : 11677b19ada2SJiri Slaby BIT_MASK(MSC_RAW) | BIT_MASK(MSC_SCAN); 11681da177e4SLinus Torvalds 11691da177e4SLinus Torvalds if (atkbd->scroll) { 11707b19ada2SJiri Slaby input_dev->evbit[0] |= BIT_MASK(EV_REL); 11717b19ada2SJiri Slaby input_dev->relbit[0] = BIT_MASK(REL_WHEEL) | 11727b19ada2SJiri Slaby BIT_MASK(REL_HWHEEL); 1173f6d65610SDmitry Torokhov __set_bit(BTN_MIDDLE, input_dev->keybit); 11741da177e4SLinus Torvalds } 11751da177e4SLinus Torvalds 11763c42f0c3SDmitry Torokhov input_dev->keycode = atkbd->keycode; 1177f6d65610SDmitry Torokhov input_dev->keycodesize = sizeof(unsigned short); 11783c42f0c3SDmitry Torokhov input_dev->keycodemax = ARRAY_SIZE(atkbd_set2_keycode); 11791da177e4SLinus Torvalds 11804b70858bSDmitry Torokhov for (i = 0; i < ATKBD_KEYMAP_SIZE; i++) { 11814b70858bSDmitry Torokhov if (atkbd->keycode[i] != KEY_RESERVED && 11824b70858bSDmitry Torokhov atkbd->keycode[i] != ATKBD_KEY_NULL && 11834b70858bSDmitry Torokhov atkbd->keycode[i] < ATKBD_SPECIAL) { 1184f6d65610SDmitry Torokhov __set_bit(atkbd->keycode[i], input_dev->keybit); 11851da177e4SLinus Torvalds } 11864b70858bSDmitry Torokhov } 11874b70858bSDmitry Torokhov } 11881da177e4SLinus Torvalds 11898f7b057aSRajat Jain static void atkbd_parse_fwnode_data(struct serio *serio) 11908f7b057aSRajat Jain { 11918f7b057aSRajat Jain struct atkbd *atkbd = serio_get_drvdata(serio); 11928f7b057aSRajat Jain struct device *dev = &serio->dev; 11938f7b057aSRajat Jain int n; 11948f7b057aSRajat Jain 11958f7b057aSRajat Jain /* Parse "function-row-physmap" property */ 11968f7b057aSRajat Jain n = device_property_count_u32(dev, "function-row-physmap"); 1197*45ceaf14SStephen Boyd if (n > 0 && n <= VIVALDI_MAX_FUNCTION_ROW_KEYS && 11988f7b057aSRajat Jain !device_property_read_u32_array(dev, "function-row-physmap", 1199*45ceaf14SStephen Boyd atkbd->vdata.function_row_physmap, 1200*45ceaf14SStephen Boyd n)) { 1201*45ceaf14SStephen Boyd atkbd->vdata.num_function_row_keys = n; 12028f7b057aSRajat Jain dev_dbg(dev, "FW reported %d function-row key locations\n", n); 12038f7b057aSRajat Jain } 12048f7b057aSRajat Jain } 12058f7b057aSRajat Jain 12061da177e4SLinus Torvalds /* 12071da177e4SLinus Torvalds * atkbd_connect() is called when the serio module finds an interface 12081da177e4SLinus Torvalds * that isn't handled yet by an appropriate device driver. We check if 12091da177e4SLinus Torvalds * there is an AT keyboard out there and if yes, we register ourselves 12101da177e4SLinus Torvalds * to the input module. 12111da177e4SLinus Torvalds */ 12121da177e4SLinus Torvalds 12131da177e4SLinus Torvalds static int atkbd_connect(struct serio *serio, struct serio_driver *drv) 12141da177e4SLinus Torvalds { 12151da177e4SLinus Torvalds struct atkbd *atkbd; 12163c42f0c3SDmitry Torokhov struct input_dev *dev; 12173c42f0c3SDmitry Torokhov int err = -ENOMEM; 12181da177e4SLinus Torvalds 12193c42f0c3SDmitry Torokhov atkbd = kzalloc(sizeof(struct atkbd), GFP_KERNEL); 12203c42f0c3SDmitry Torokhov dev = input_allocate_device(); 12213c42f0c3SDmitry Torokhov if (!atkbd || !dev) 12222b03b60eSDmitry Torokhov goto fail1; 12231da177e4SLinus Torvalds 12243c42f0c3SDmitry Torokhov atkbd->dev = dev; 12251da177e4SLinus Torvalds ps2_init(&atkbd->ps2dev, serio); 1226da4249c9SDmitry Torokhov INIT_DELAYED_WORK(&atkbd->event_work, atkbd_event_work); 122759b01513SEric W. Biederman mutex_init(&atkbd->mutex); 12281da177e4SLinus Torvalds 12291da177e4SLinus Torvalds switch (serio->id.type) { 12301da177e4SLinus Torvalds 12311da177e4SLinus Torvalds case SERIO_8042_XL: 1232a9a1f9c3SDmitry Torokhov atkbd->translated = true; 12336f49c4f5SGustavo A. R. Silva fallthrough; 1234a9a1f9c3SDmitry Torokhov 12351da177e4SLinus Torvalds case SERIO_8042: 12361da177e4SLinus Torvalds if (serio->write) 1237a9a1f9c3SDmitry Torokhov atkbd->write = true; 12381da177e4SLinus Torvalds break; 12391da177e4SLinus Torvalds } 12401da177e4SLinus Torvalds 12411da177e4SLinus Torvalds atkbd->softraw = atkbd_softraw; 12421da177e4SLinus Torvalds atkbd->softrepeat = atkbd_softrepeat; 12431da177e4SLinus Torvalds atkbd->scroll = atkbd_scroll; 12441da177e4SLinus Torvalds 12451da177e4SLinus Torvalds if (atkbd->softrepeat) 1246a9a1f9c3SDmitry Torokhov atkbd->softraw = true; 12471da177e4SLinus Torvalds 12481da177e4SLinus Torvalds serio_set_drvdata(serio, atkbd); 12491da177e4SLinus Torvalds 12501da177e4SLinus Torvalds err = serio_open(serio, drv); 12513c42f0c3SDmitry Torokhov if (err) 12522b03b60eSDmitry Torokhov goto fail2; 12531da177e4SLinus Torvalds 12541da177e4SLinus Torvalds if (atkbd->write) { 12551da177e4SLinus Torvalds 12561da177e4SLinus Torvalds if (atkbd_probe(atkbd)) { 12573c42f0c3SDmitry Torokhov err = -ENODEV; 12582b03b60eSDmitry Torokhov goto fail3; 12591da177e4SLinus Torvalds } 12601da177e4SLinus Torvalds 12611da177e4SLinus Torvalds atkbd->set = atkbd_select_set(atkbd, atkbd_set, atkbd_extra); 1262fc0eb28cSDmitry Torokhov atkbd_reset_state(atkbd); 12631da177e4SLinus Torvalds 12641da177e4SLinus Torvalds } else { 12651da177e4SLinus Torvalds atkbd->set = 2; 12661da177e4SLinus Torvalds atkbd->id = 0xab00; 12671da177e4SLinus Torvalds } 12681da177e4SLinus Torvalds 12698f7b057aSRajat Jain atkbd_parse_fwnode_data(serio); 12708f7b057aSRajat Jain 12711da177e4SLinus Torvalds atkbd_set_keycode_table(atkbd); 12721da177e4SLinus Torvalds atkbd_set_device_attrs(atkbd); 12731da177e4SLinus Torvalds 12742b03b60eSDmitry Torokhov err = sysfs_create_group(&serio->dev.kobj, &atkbd_attribute_group); 12752b03b60eSDmitry Torokhov if (err) 12762b03b60eSDmitry Torokhov goto fail3; 12771da177e4SLinus Torvalds 12781da177e4SLinus Torvalds atkbd_enable(atkbd); 1279be2d7e42SShawn Nematbakhsh if (serio->write) 1280be2d7e42SShawn Nematbakhsh atkbd_activate(atkbd); 12811da177e4SLinus Torvalds 12822b03b60eSDmitry Torokhov err = input_register_device(atkbd->dev); 12832b03b60eSDmitry Torokhov if (err) 12842b03b60eSDmitry Torokhov goto fail4; 12851da177e4SLinus Torvalds 12861da177e4SLinus Torvalds return 0; 12873c42f0c3SDmitry Torokhov 12882b03b60eSDmitry Torokhov fail4: sysfs_remove_group(&serio->dev.kobj, &atkbd_attribute_group); 12892b03b60eSDmitry Torokhov fail3: serio_close(serio); 12902b03b60eSDmitry Torokhov fail2: serio_set_drvdata(serio, NULL); 12912b03b60eSDmitry Torokhov fail1: input_free_device(dev); 12923c42f0c3SDmitry Torokhov kfree(atkbd); 12933c42f0c3SDmitry Torokhov return err; 12941da177e4SLinus Torvalds } 12951da177e4SLinus Torvalds 12961da177e4SLinus Torvalds /* 12971da177e4SLinus Torvalds * atkbd_reconnect() tries to restore keyboard into a sane state and is 12981da177e4SLinus Torvalds * most likely called on resume. 12991da177e4SLinus Torvalds */ 13001da177e4SLinus Torvalds 13011da177e4SLinus Torvalds static int atkbd_reconnect(struct serio *serio) 13021da177e4SLinus Torvalds { 13031da177e4SLinus Torvalds struct atkbd *atkbd = serio_get_drvdata(serio); 13041da177e4SLinus Torvalds struct serio_driver *drv = serio->drv; 130559b01513SEric W. Biederman int retval = -1; 13061da177e4SLinus Torvalds 13071da177e4SLinus Torvalds if (!atkbd || !drv) { 1308a9a1f9c3SDmitry Torokhov dev_dbg(&serio->dev, 1309a9a1f9c3SDmitry Torokhov "reconnect request, but serio is disconnected, ignoring...\n"); 13101da177e4SLinus Torvalds return -1; 13111da177e4SLinus Torvalds } 13121da177e4SLinus Torvalds 131359b01513SEric W. Biederman mutex_lock(&atkbd->mutex); 131459b01513SEric W. Biederman 13151da177e4SLinus Torvalds atkbd_disable(atkbd); 13161da177e4SLinus Torvalds 13171da177e4SLinus Torvalds if (atkbd->write) { 13181da177e4SLinus Torvalds if (atkbd_probe(atkbd)) 131959b01513SEric W. Biederman goto out; 132059b01513SEric W. Biederman 13211da177e4SLinus Torvalds if (atkbd->set != atkbd_select_set(atkbd, atkbd->set, atkbd->extra)) 132259b01513SEric W. Biederman goto out; 13231da177e4SLinus Torvalds 1324d4119bdaSDmitry Torokhov /* 1325d4119bdaSDmitry Torokhov * Restore LED state and repeat rate. While input core 1326d4119bdaSDmitry Torokhov * will do this for us at resume time reconnect may happen 1327d4119bdaSDmitry Torokhov * because user requested it via sysfs or simply because 1328d4119bdaSDmitry Torokhov * keyboard was unplugged and plugged in again so we need 1329d4119bdaSDmitry Torokhov * to do it ourselves here. 1330d4119bdaSDmitry Torokhov */ 1331d4119bdaSDmitry Torokhov atkbd_set_leds(atkbd); 1332d4119bdaSDmitry Torokhov if (!atkbd->softrepeat) 1333d4119bdaSDmitry Torokhov atkbd_set_repeat_rate(atkbd); 1334d4119bdaSDmitry Torokhov 13351da177e4SLinus Torvalds } 13361da177e4SLinus Torvalds 1337be2d7e42SShawn Nematbakhsh /* 1338be2d7e42SShawn Nematbakhsh * Reset our state machine in case reconnect happened in the middle 1339be2d7e42SShawn Nematbakhsh * of multi-byte scancode. 1340be2d7e42SShawn Nematbakhsh */ 1341be2d7e42SShawn Nematbakhsh atkbd->xl_bit = 0; 1342be2d7e42SShawn Nematbakhsh atkbd->emul = 0; 1343be2d7e42SShawn Nematbakhsh 13441da177e4SLinus Torvalds atkbd_enable(atkbd); 1345be2d7e42SShawn Nematbakhsh if (atkbd->write) 1346be2d7e42SShawn Nematbakhsh atkbd_activate(atkbd); 1347be2d7e42SShawn Nematbakhsh 134859b01513SEric W. Biederman retval = 0; 13491da177e4SLinus Torvalds 135059b01513SEric W. Biederman out: 135159b01513SEric W. Biederman mutex_unlock(&atkbd->mutex); 135259b01513SEric W. Biederman return retval; 13531da177e4SLinus Torvalds } 13541da177e4SLinus Torvalds 1355af2e7d77SArvind Yadav static const struct serio_device_id atkbd_serio_ids[] = { 13561da177e4SLinus Torvalds { 13571da177e4SLinus Torvalds .type = SERIO_8042, 13581da177e4SLinus Torvalds .proto = SERIO_ANY, 13591da177e4SLinus Torvalds .id = SERIO_ANY, 13601da177e4SLinus Torvalds .extra = SERIO_ANY, 13611da177e4SLinus Torvalds }, 13621da177e4SLinus Torvalds { 13631da177e4SLinus Torvalds .type = SERIO_8042_XL, 13641da177e4SLinus Torvalds .proto = SERIO_ANY, 13651da177e4SLinus Torvalds .id = SERIO_ANY, 13661da177e4SLinus Torvalds .extra = SERIO_ANY, 13671da177e4SLinus Torvalds }, 13681da177e4SLinus Torvalds { 13691da177e4SLinus Torvalds .type = SERIO_RS232, 13701da177e4SLinus Torvalds .proto = SERIO_PS2SER, 13711da177e4SLinus Torvalds .id = SERIO_ANY, 13721da177e4SLinus Torvalds .extra = SERIO_ANY, 13731da177e4SLinus Torvalds }, 13741da177e4SLinus Torvalds { 0 } 13751da177e4SLinus Torvalds }; 13761da177e4SLinus Torvalds 13771da177e4SLinus Torvalds MODULE_DEVICE_TABLE(serio, atkbd_serio_ids); 13781da177e4SLinus Torvalds 13791da177e4SLinus Torvalds static struct serio_driver atkbd_drv = { 13801da177e4SLinus Torvalds .driver = { 13811da177e4SLinus Torvalds .name = "atkbd", 13821da177e4SLinus Torvalds }, 13831da177e4SLinus Torvalds .description = DRIVER_DESC, 13841da177e4SLinus Torvalds .id_table = atkbd_serio_ids, 13851da177e4SLinus Torvalds .interrupt = atkbd_interrupt, 13861da177e4SLinus Torvalds .connect = atkbd_connect, 13871da177e4SLinus Torvalds .reconnect = atkbd_reconnect, 13881da177e4SLinus Torvalds .disconnect = atkbd_disconnect, 13891da177e4SLinus Torvalds .cleanup = atkbd_cleanup, 13901da177e4SLinus Torvalds }; 13911da177e4SLinus Torvalds 13921da177e4SLinus Torvalds static ssize_t atkbd_attr_show_helper(struct device *dev, char *buf, 13931da177e4SLinus Torvalds ssize_t (*handler)(struct atkbd *, char *)) 13941da177e4SLinus Torvalds { 13951da177e4SLinus Torvalds struct serio *serio = to_serio_port(dev); 139659b01513SEric W. Biederman struct atkbd *atkbd = serio_get_drvdata(serio); 13971da177e4SLinus Torvalds 139859b01513SEric W. Biederman return handler(atkbd, buf); 13991da177e4SLinus Torvalds } 14001da177e4SLinus Torvalds 14011da177e4SLinus Torvalds static ssize_t atkbd_attr_set_helper(struct device *dev, const char *buf, size_t count, 14021da177e4SLinus Torvalds ssize_t (*handler)(struct atkbd *, const char *, size_t)) 14031da177e4SLinus Torvalds { 14041da177e4SLinus Torvalds struct serio *serio = to_serio_port(dev); 140559b01513SEric W. Biederman struct atkbd *atkbd = serio_get_drvdata(serio); 14061da177e4SLinus Torvalds int retval; 14071da177e4SLinus Torvalds 140859b01513SEric W. Biederman retval = mutex_lock_interruptible(&atkbd->mutex); 14091da177e4SLinus Torvalds if (retval) 14101da177e4SLinus Torvalds return retval; 14111da177e4SLinus Torvalds 14121da177e4SLinus Torvalds atkbd_disable(atkbd); 14131da177e4SLinus Torvalds retval = handler(atkbd, buf, count); 14141da177e4SLinus Torvalds atkbd_enable(atkbd); 14151da177e4SLinus Torvalds 141659b01513SEric W. Biederman mutex_unlock(&atkbd->mutex); 141759b01513SEric W. Biederman 14181da177e4SLinus Torvalds return retval; 14191da177e4SLinus Torvalds } 14201da177e4SLinus Torvalds 14211da177e4SLinus Torvalds static ssize_t atkbd_show_extra(struct atkbd *atkbd, char *buf) 14221da177e4SLinus Torvalds { 14231da177e4SLinus Torvalds return sprintf(buf, "%d\n", atkbd->extra ? 1 : 0); 14241da177e4SLinus Torvalds } 14251da177e4SLinus Torvalds 14261da177e4SLinus Torvalds static ssize_t atkbd_set_extra(struct atkbd *atkbd, const char *buf, size_t count) 14271da177e4SLinus Torvalds { 14282b03b60eSDmitry Torokhov struct input_dev *old_dev, *new_dev; 142976496e7aSJJ Ding unsigned int value; 14302b03b60eSDmitry Torokhov int err; 1431a9a1f9c3SDmitry Torokhov bool old_extra; 1432a9a1f9c3SDmitry Torokhov unsigned char old_set; 14331da177e4SLinus Torvalds 14341da177e4SLinus Torvalds if (!atkbd->write) 14351da177e4SLinus Torvalds return -EIO; 14361da177e4SLinus Torvalds 143776496e7aSJJ Ding err = kstrtouint(buf, 10, &value); 143876496e7aSJJ Ding if (err) 143976496e7aSJJ Ding return err; 144076496e7aSJJ Ding 144176496e7aSJJ Ding if (value > 1) 14421da177e4SLinus Torvalds return -EINVAL; 14431da177e4SLinus Torvalds 14441da177e4SLinus Torvalds if (atkbd->extra != value) { 14453c42f0c3SDmitry Torokhov /* 14463c42f0c3SDmitry Torokhov * Since device's properties will change we need to 14472b03b60eSDmitry Torokhov * unregister old device. But allocate and register 14482b03b60eSDmitry Torokhov * new one first to make sure we have it. 14493c42f0c3SDmitry Torokhov */ 14502b03b60eSDmitry Torokhov old_dev = atkbd->dev; 14512b03b60eSDmitry Torokhov old_extra = atkbd->extra; 14522b03b60eSDmitry Torokhov old_set = atkbd->set; 14532b03b60eSDmitry Torokhov 14542b03b60eSDmitry Torokhov new_dev = input_allocate_device(); 14552b03b60eSDmitry Torokhov if (!new_dev) 14563c42f0c3SDmitry Torokhov return -ENOMEM; 14572b03b60eSDmitry Torokhov 14583c42f0c3SDmitry Torokhov atkbd->dev = new_dev; 14591da177e4SLinus Torvalds atkbd->set = atkbd_select_set(atkbd, atkbd->set, value); 1460fc0eb28cSDmitry Torokhov atkbd_reset_state(atkbd); 14611da177e4SLinus Torvalds atkbd_activate(atkbd); 14622b03b60eSDmitry Torokhov atkbd_set_keycode_table(atkbd); 14631da177e4SLinus Torvalds atkbd_set_device_attrs(atkbd); 14642b03b60eSDmitry Torokhov 14652b03b60eSDmitry Torokhov err = input_register_device(atkbd->dev); 14662b03b60eSDmitry Torokhov if (err) { 14672b03b60eSDmitry Torokhov input_free_device(new_dev); 14682b03b60eSDmitry Torokhov 14692b03b60eSDmitry Torokhov atkbd->dev = old_dev; 14702b03b60eSDmitry Torokhov atkbd->set = atkbd_select_set(atkbd, old_set, old_extra); 14712b03b60eSDmitry Torokhov atkbd_set_keycode_table(atkbd); 14722b03b60eSDmitry Torokhov atkbd_set_device_attrs(atkbd); 14732b03b60eSDmitry Torokhov 14742b03b60eSDmitry Torokhov return err; 14752b03b60eSDmitry Torokhov } 14762b03b60eSDmitry Torokhov input_unregister_device(old_dev); 14772b03b60eSDmitry Torokhov 14781da177e4SLinus Torvalds } 14791da177e4SLinus Torvalds return count; 14801da177e4SLinus Torvalds } 14811da177e4SLinus Torvalds 14821ba36e11SDmitry Torokhov static ssize_t atkbd_show_force_release(struct atkbd *atkbd, char *buf) 14831ba36e11SDmitry Torokhov { 14840b480037STejun Heo size_t len = scnprintf(buf, PAGE_SIZE - 1, "%*pbl", 14850b480037STejun Heo ATKBD_KEYMAP_SIZE, atkbd->force_release_mask); 14861ba36e11SDmitry Torokhov 14871ba36e11SDmitry Torokhov buf[len++] = '\n'; 14881ba36e11SDmitry Torokhov buf[len] = '\0'; 14891ba36e11SDmitry Torokhov 14901ba36e11SDmitry Torokhov return len; 14911ba36e11SDmitry Torokhov } 14921ba36e11SDmitry Torokhov 14931ba36e11SDmitry Torokhov static ssize_t atkbd_set_force_release(struct atkbd *atkbd, 14941ba36e11SDmitry Torokhov const char *buf, size_t count) 14951ba36e11SDmitry Torokhov { 14961ba36e11SDmitry Torokhov /* 64 bytes on stack should be acceptable */ 14971ba36e11SDmitry Torokhov DECLARE_BITMAP(new_mask, ATKBD_KEYMAP_SIZE); 14981ba36e11SDmitry Torokhov int err; 14991ba36e11SDmitry Torokhov 15001ba36e11SDmitry Torokhov err = bitmap_parselist(buf, new_mask, ATKBD_KEYMAP_SIZE); 15011ba36e11SDmitry Torokhov if (err) 15021ba36e11SDmitry Torokhov return err; 15031ba36e11SDmitry Torokhov 15041ba36e11SDmitry Torokhov memcpy(atkbd->force_release_mask, new_mask, sizeof(atkbd->force_release_mask)); 15051ba36e11SDmitry Torokhov return count; 15061ba36e11SDmitry Torokhov } 15071ba36e11SDmitry Torokhov 15081ba36e11SDmitry Torokhov 15091da177e4SLinus Torvalds static ssize_t atkbd_show_scroll(struct atkbd *atkbd, char *buf) 15101da177e4SLinus Torvalds { 15111da177e4SLinus Torvalds return sprintf(buf, "%d\n", atkbd->scroll ? 1 : 0); 15121da177e4SLinus Torvalds } 15131da177e4SLinus Torvalds 15141da177e4SLinus Torvalds static ssize_t atkbd_set_scroll(struct atkbd *atkbd, const char *buf, size_t count) 15151da177e4SLinus Torvalds { 15162b03b60eSDmitry Torokhov struct input_dev *old_dev, *new_dev; 151776496e7aSJJ Ding unsigned int value; 15182b03b60eSDmitry Torokhov int err; 1519a9a1f9c3SDmitry Torokhov bool old_scroll; 15201da177e4SLinus Torvalds 152176496e7aSJJ Ding err = kstrtouint(buf, 10, &value); 152276496e7aSJJ Ding if (err) 152376496e7aSJJ Ding return err; 152476496e7aSJJ Ding 152576496e7aSJJ Ding if (value > 1) 15261da177e4SLinus Torvalds return -EINVAL; 15271da177e4SLinus Torvalds 15281da177e4SLinus Torvalds if (atkbd->scroll != value) { 15292b03b60eSDmitry Torokhov old_dev = atkbd->dev; 15302b03b60eSDmitry Torokhov old_scroll = atkbd->scroll; 15312b03b60eSDmitry Torokhov 15322b03b60eSDmitry Torokhov new_dev = input_allocate_device(); 15332b03b60eSDmitry Torokhov if (!new_dev) 15343c42f0c3SDmitry Torokhov return -ENOMEM; 15352b03b60eSDmitry Torokhov 15363c42f0c3SDmitry Torokhov atkbd->dev = new_dev; 15371da177e4SLinus Torvalds atkbd->scroll = value; 15381da177e4SLinus Torvalds atkbd_set_keycode_table(atkbd); 15391da177e4SLinus Torvalds atkbd_set_device_attrs(atkbd); 15402b03b60eSDmitry Torokhov 15412b03b60eSDmitry Torokhov err = input_register_device(atkbd->dev); 15422b03b60eSDmitry Torokhov if (err) { 15432b03b60eSDmitry Torokhov input_free_device(new_dev); 15442b03b60eSDmitry Torokhov 15452b03b60eSDmitry Torokhov atkbd->scroll = old_scroll; 15462b03b60eSDmitry Torokhov atkbd->dev = old_dev; 15472b03b60eSDmitry Torokhov atkbd_set_keycode_table(atkbd); 15482b03b60eSDmitry Torokhov atkbd_set_device_attrs(atkbd); 15492b03b60eSDmitry Torokhov 15502b03b60eSDmitry Torokhov return err; 15512b03b60eSDmitry Torokhov } 15522b03b60eSDmitry Torokhov input_unregister_device(old_dev); 15531da177e4SLinus Torvalds } 15541da177e4SLinus Torvalds return count; 15551da177e4SLinus Torvalds } 15561da177e4SLinus Torvalds 15571da177e4SLinus Torvalds static ssize_t atkbd_show_set(struct atkbd *atkbd, char *buf) 15581da177e4SLinus Torvalds { 15591da177e4SLinus Torvalds return sprintf(buf, "%d\n", atkbd->set); 15601da177e4SLinus Torvalds } 15611da177e4SLinus Torvalds 15621da177e4SLinus Torvalds static ssize_t atkbd_set_set(struct atkbd *atkbd, const char *buf, size_t count) 15631da177e4SLinus Torvalds { 15642b03b60eSDmitry Torokhov struct input_dev *old_dev, *new_dev; 156576496e7aSJJ Ding unsigned int value; 15662b03b60eSDmitry Torokhov int err; 1567a9a1f9c3SDmitry Torokhov unsigned char old_set; 1568a9a1f9c3SDmitry Torokhov bool old_extra; 15691da177e4SLinus Torvalds 15701da177e4SLinus Torvalds if (!atkbd->write) 15711da177e4SLinus Torvalds return -EIO; 15721da177e4SLinus Torvalds 157376496e7aSJJ Ding err = kstrtouint(buf, 10, &value); 157476496e7aSJJ Ding if (err) 157576496e7aSJJ Ding return err; 157676496e7aSJJ Ding 157776496e7aSJJ Ding if (value != 2 && value != 3) 15781da177e4SLinus Torvalds return -EINVAL; 15791da177e4SLinus Torvalds 15801da177e4SLinus Torvalds if (atkbd->set != value) { 15812b03b60eSDmitry Torokhov old_dev = atkbd->dev; 15822b03b60eSDmitry Torokhov old_extra = atkbd->extra; 15832b03b60eSDmitry Torokhov old_set = atkbd->set; 15842b03b60eSDmitry Torokhov 15852b03b60eSDmitry Torokhov new_dev = input_allocate_device(); 15862b03b60eSDmitry Torokhov if (!new_dev) 15873c42f0c3SDmitry Torokhov return -ENOMEM; 15882b03b60eSDmitry Torokhov 15893c42f0c3SDmitry Torokhov atkbd->dev = new_dev; 15901da177e4SLinus Torvalds atkbd->set = atkbd_select_set(atkbd, value, atkbd->extra); 1591d4119bdaSDmitry Torokhov atkbd_reset_state(atkbd); 15921da177e4SLinus Torvalds atkbd_activate(atkbd); 15931da177e4SLinus Torvalds atkbd_set_keycode_table(atkbd); 15941da177e4SLinus Torvalds atkbd_set_device_attrs(atkbd); 15952b03b60eSDmitry Torokhov 15962b03b60eSDmitry Torokhov err = input_register_device(atkbd->dev); 15972b03b60eSDmitry Torokhov if (err) { 15982b03b60eSDmitry Torokhov input_free_device(new_dev); 15992b03b60eSDmitry Torokhov 16002b03b60eSDmitry Torokhov atkbd->dev = old_dev; 16012b03b60eSDmitry Torokhov atkbd->set = atkbd_select_set(atkbd, old_set, old_extra); 16022b03b60eSDmitry Torokhov atkbd_set_keycode_table(atkbd); 16032b03b60eSDmitry Torokhov atkbd_set_device_attrs(atkbd); 16042b03b60eSDmitry Torokhov 16052b03b60eSDmitry Torokhov return err; 16062b03b60eSDmitry Torokhov } 16072b03b60eSDmitry Torokhov input_unregister_device(old_dev); 16081da177e4SLinus Torvalds } 16091da177e4SLinus Torvalds return count; 16101da177e4SLinus Torvalds } 16111da177e4SLinus Torvalds 16121da177e4SLinus Torvalds static ssize_t atkbd_show_softrepeat(struct atkbd *atkbd, char *buf) 16131da177e4SLinus Torvalds { 16141da177e4SLinus Torvalds return sprintf(buf, "%d\n", atkbd->softrepeat ? 1 : 0); 16151da177e4SLinus Torvalds } 16161da177e4SLinus Torvalds 16171da177e4SLinus Torvalds static ssize_t atkbd_set_softrepeat(struct atkbd *atkbd, const char *buf, size_t count) 16181da177e4SLinus Torvalds { 16192b03b60eSDmitry Torokhov struct input_dev *old_dev, *new_dev; 162076496e7aSJJ Ding unsigned int value; 16212b03b60eSDmitry Torokhov int err; 1622a9a1f9c3SDmitry Torokhov bool old_softrepeat, old_softraw; 16231da177e4SLinus Torvalds 16241da177e4SLinus Torvalds if (!atkbd->write) 16251da177e4SLinus Torvalds return -EIO; 16261da177e4SLinus Torvalds 162776496e7aSJJ Ding err = kstrtouint(buf, 10, &value); 162876496e7aSJJ Ding if (err) 162976496e7aSJJ Ding return err; 163076496e7aSJJ Ding 163176496e7aSJJ Ding if (value > 1) 16321da177e4SLinus Torvalds return -EINVAL; 16331da177e4SLinus Torvalds 16341da177e4SLinus Torvalds if (atkbd->softrepeat != value) { 16352b03b60eSDmitry Torokhov old_dev = atkbd->dev; 16362b03b60eSDmitry Torokhov old_softrepeat = atkbd->softrepeat; 16372b03b60eSDmitry Torokhov old_softraw = atkbd->softraw; 16382b03b60eSDmitry Torokhov 16392b03b60eSDmitry Torokhov new_dev = input_allocate_device(); 16402b03b60eSDmitry Torokhov if (!new_dev) 16413c42f0c3SDmitry Torokhov return -ENOMEM; 16422b03b60eSDmitry Torokhov 16433c42f0c3SDmitry Torokhov atkbd->dev = new_dev; 16441da177e4SLinus Torvalds atkbd->softrepeat = value; 16451da177e4SLinus Torvalds if (atkbd->softrepeat) 1646a9a1f9c3SDmitry Torokhov atkbd->softraw = true; 16471da177e4SLinus Torvalds atkbd_set_device_attrs(atkbd); 16482b03b60eSDmitry Torokhov 16492b03b60eSDmitry Torokhov err = input_register_device(atkbd->dev); 16502b03b60eSDmitry Torokhov if (err) { 16512b03b60eSDmitry Torokhov input_free_device(new_dev); 16522b03b60eSDmitry Torokhov 16532b03b60eSDmitry Torokhov atkbd->dev = old_dev; 16542b03b60eSDmitry Torokhov atkbd->softrepeat = old_softrepeat; 16552b03b60eSDmitry Torokhov atkbd->softraw = old_softraw; 16562b03b60eSDmitry Torokhov atkbd_set_device_attrs(atkbd); 16572b03b60eSDmitry Torokhov 16582b03b60eSDmitry Torokhov return err; 16592b03b60eSDmitry Torokhov } 16602b03b60eSDmitry Torokhov input_unregister_device(old_dev); 16611da177e4SLinus Torvalds } 16621da177e4SLinus Torvalds return count; 16631da177e4SLinus Torvalds } 16641da177e4SLinus Torvalds 16651da177e4SLinus Torvalds 16661da177e4SLinus Torvalds static ssize_t atkbd_show_softraw(struct atkbd *atkbd, char *buf) 16671da177e4SLinus Torvalds { 16681da177e4SLinus Torvalds return sprintf(buf, "%d\n", atkbd->softraw ? 1 : 0); 16691da177e4SLinus Torvalds } 16701da177e4SLinus Torvalds 16711da177e4SLinus Torvalds static ssize_t atkbd_set_softraw(struct atkbd *atkbd, const char *buf, size_t count) 16721da177e4SLinus Torvalds { 16732b03b60eSDmitry Torokhov struct input_dev *old_dev, *new_dev; 167476496e7aSJJ Ding unsigned int value; 16752b03b60eSDmitry Torokhov int err; 1676a9a1f9c3SDmitry Torokhov bool old_softraw; 16771da177e4SLinus Torvalds 167876496e7aSJJ Ding err = kstrtouint(buf, 10, &value); 167976496e7aSJJ Ding if (err) 168076496e7aSJJ Ding return err; 168176496e7aSJJ Ding 168276496e7aSJJ Ding if (value > 1) 16831da177e4SLinus Torvalds return -EINVAL; 16841da177e4SLinus Torvalds 16851da177e4SLinus Torvalds if (atkbd->softraw != value) { 16862b03b60eSDmitry Torokhov old_dev = atkbd->dev; 16872b03b60eSDmitry Torokhov old_softraw = atkbd->softraw; 16882b03b60eSDmitry Torokhov 16892b03b60eSDmitry Torokhov new_dev = input_allocate_device(); 16902b03b60eSDmitry Torokhov if (!new_dev) 16913c42f0c3SDmitry Torokhov return -ENOMEM; 16922b03b60eSDmitry Torokhov 16933c42f0c3SDmitry Torokhov atkbd->dev = new_dev; 16941da177e4SLinus Torvalds atkbd->softraw = value; 16951da177e4SLinus Torvalds atkbd_set_device_attrs(atkbd); 16962b03b60eSDmitry Torokhov 16972b03b60eSDmitry Torokhov err = input_register_device(atkbd->dev); 16982b03b60eSDmitry Torokhov if (err) { 16992b03b60eSDmitry Torokhov input_free_device(new_dev); 17002b03b60eSDmitry Torokhov 17012b03b60eSDmitry Torokhov atkbd->dev = old_dev; 17022b03b60eSDmitry Torokhov atkbd->softraw = old_softraw; 17032b03b60eSDmitry Torokhov atkbd_set_device_attrs(atkbd); 17042b03b60eSDmitry Torokhov 17052b03b60eSDmitry Torokhov return err; 17062b03b60eSDmitry Torokhov } 17072b03b60eSDmitry Torokhov input_unregister_device(old_dev); 17081da177e4SLinus Torvalds } 17091da177e4SLinus Torvalds return count; 17101da177e4SLinus Torvalds } 17111da177e4SLinus Torvalds 171286255d9dSDmitry Torokhov static ssize_t atkbd_show_err_count(struct atkbd *atkbd, char *buf) 171386255d9dSDmitry Torokhov { 171486255d9dSDmitry Torokhov return sprintf(buf, "%lu\n", atkbd->err_count); 171586255d9dSDmitry Torokhov } 171686255d9dSDmitry Torokhov 171739191698SDaniel Mierswa static int __init atkbd_setup_forced_release(const struct dmi_system_id *id) 1718554101e3SGiel de Nijs { 171939191698SDaniel Mierswa atkbd_platform_fixup = atkbd_apply_forced_release_keylist; 172039191698SDaniel Mierswa atkbd_platform_fixup_data = id->driver_data; 172139191698SDaniel Mierswa 1722c388b2c6SAxel Lin return 1; 1723554101e3SGiel de Nijs } 1724554101e3SGiel de Nijs 1725e5713069SJamie Lentin static int __init atkbd_setup_scancode_fixup(const struct dmi_system_id *id) 1726e5713069SJamie Lentin { 1727e5713069SJamie Lentin atkbd_platform_scancode_fixup = id->driver_data; 1728e5713069SJamie Lentin 1729c388b2c6SAxel Lin return 1; 1730e5713069SJamie Lentin } 1731e5713069SJamie Lentin 17323d725caaSSheng-Liang Song static int __init atkbd_deactivate_fixup(const struct dmi_system_id *id) 17333d725caaSSheng-Liang Song { 17343d725caaSSheng-Liang Song atkbd_skip_deactivate = true; 17353d725caaSSheng-Liang Song return 1; 17363d725caaSSheng-Liang Song } 17373d725caaSSheng-Liang Song 17388b8a518eSDmitry Torokhov /* 17398b8a518eSDmitry Torokhov * NOTE: do not add any more "force release" quirks to this table. The 17408b8a518eSDmitry Torokhov * task of adjusting list of keys that should be "released" automatically 17418b8a518eSDmitry Torokhov * by the driver is now delegated to userspace tools, such as udev, so 17428b8a518eSDmitry Torokhov * submit such quirks there. 17438b8a518eSDmitry Torokhov */ 1744c45fc81eSDmitry Torokhov static const struct dmi_system_id atkbd_dmi_quirk_table[] __initconst = { 1745554101e3SGiel de Nijs { 1746554101e3SGiel de Nijs .matches = { 1747554101e3SGiel de Nijs DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 174861579ba8SMatthew Garrett DMI_MATCH(DMI_CHASSIS_TYPE, "8"), /* Portable */ 1749554101e3SGiel de Nijs }, 175039191698SDaniel Mierswa .callback = atkbd_setup_forced_release, 175139191698SDaniel Mierswa .driver_data = atkbd_dell_laptop_forced_release_keys, 1752554101e3SGiel de Nijs }, 17535a54c011SJiri Kosina { 17542a3ec326SMatthew Garrett .matches = { 17552a3ec326SMatthew Garrett DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"), 17562a3ec326SMatthew Garrett DMI_MATCH(DMI_CHASSIS_TYPE, "8"), /* Portable */ 17572a3ec326SMatthew Garrett }, 175839191698SDaniel Mierswa .callback = atkbd_setup_forced_release, 175939191698SDaniel Mierswa .driver_data = atkbd_dell_laptop_forced_release_keys, 17602a3ec326SMatthew Garrett }, 17612a3ec326SMatthew Garrett { 17625a54c011SJiri Kosina .matches = { 17635a54c011SJiri Kosina DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), 17645a54c011SJiri Kosina DMI_MATCH(DMI_PRODUCT_NAME, "HP 2133"), 17655a54c011SJiri Kosina }, 176639191698SDaniel Mierswa .callback = atkbd_setup_forced_release, 176739191698SDaniel Mierswa .driver_data = atkbd_hp_forced_release_keys, 17685a54c011SJiri Kosina }, 1769a8215b81SMatthew Garrett { 1770181f6382SRikard Ljungstrand .matches = { 1771181f6382SRikard Ljungstrand DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), 1772181f6382SRikard Ljungstrand DMI_MATCH(DMI_PRODUCT_NAME, "Pavilion ZV6100"), 1773181f6382SRikard Ljungstrand }, 177439191698SDaniel Mierswa .callback = atkbd_setup_forced_release, 1775000c2a35SHerton Ronaldo Krzesinski .driver_data = atkbd_volume_forced_release_keys, 1776181f6382SRikard Ljungstrand }, 1777181f6382SRikard Ljungstrand { 17782bcaa6a4SDave Andrews .matches = { 17792bcaa6a4SDave Andrews DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), 17802bcaa6a4SDave Andrews DMI_MATCH(DMI_PRODUCT_NAME, "Presario R4000"), 17812bcaa6a4SDave Andrews }, 17822bcaa6a4SDave Andrews .callback = atkbd_setup_forced_release, 1783000c2a35SHerton Ronaldo Krzesinski .driver_data = atkbd_volume_forced_release_keys, 17842bcaa6a4SDave Andrews }, 17852bcaa6a4SDave Andrews { 17862bcaa6a4SDave Andrews .matches = { 17872bcaa6a4SDave Andrews DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), 17882bcaa6a4SDave Andrews DMI_MATCH(DMI_PRODUCT_NAME, "Presario R4100"), 17892bcaa6a4SDave Andrews }, 17902bcaa6a4SDave Andrews .callback = atkbd_setup_forced_release, 1791000c2a35SHerton Ronaldo Krzesinski .driver_data = atkbd_volume_forced_release_keys, 17922bcaa6a4SDave Andrews }, 17932bcaa6a4SDave Andrews { 17942bcaa6a4SDave Andrews .matches = { 17952bcaa6a4SDave Andrews DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), 17962bcaa6a4SDave Andrews DMI_MATCH(DMI_PRODUCT_NAME, "Presario R4200"), 17972bcaa6a4SDave Andrews }, 17982bcaa6a4SDave Andrews .callback = atkbd_setup_forced_release, 1799000c2a35SHerton Ronaldo Krzesinski .driver_data = atkbd_volume_forced_release_keys, 18002bcaa6a4SDave Andrews }, 18012bcaa6a4SDave Andrews { 1802c45fc81eSDmitry Torokhov /* Inventec Symphony */ 1803a8215b81SMatthew Garrett .matches = { 1804a8215b81SMatthew Garrett DMI_MATCH(DMI_SYS_VENDOR, "INVENTEC"), 1805a8215b81SMatthew Garrett DMI_MATCH(DMI_PRODUCT_NAME, "SYMPHONY 6.0/7.0"), 1806a8215b81SMatthew Garrett }, 180739191698SDaniel Mierswa .callback = atkbd_setup_forced_release, 1808000c2a35SHerton Ronaldo Krzesinski .driver_data = atkbd_volume_forced_release_keys, 1809a8215b81SMatthew Garrett }, 18104200844bSStuart Hopkins { 1811c45fc81eSDmitry Torokhov /* Samsung NC10 */ 18124200844bSStuart Hopkins .matches = { 18134200844bSStuart Hopkins DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."), 18144200844bSStuart Hopkins DMI_MATCH(DMI_PRODUCT_NAME, "NC10"), 18154200844bSStuart Hopkins }, 181639191698SDaniel Mierswa .callback = atkbd_setup_forced_release, 181739191698SDaniel Mierswa .driver_data = atkbd_samsung_forced_release_keys, 18184200844bSStuart Hopkins }, 1819adcb523eSDaniel Mierswa { 1820c45fc81eSDmitry Torokhov /* Samsung NC20 */ 1821e04126c7SBarry Carroll .matches = { 1822e04126c7SBarry Carroll DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."), 1823e04126c7SBarry Carroll DMI_MATCH(DMI_PRODUCT_NAME, "NC20"), 1824e04126c7SBarry Carroll }, 1825e04126c7SBarry Carroll .callback = atkbd_setup_forced_release, 1826e04126c7SBarry Carroll .driver_data = atkbd_samsung_forced_release_keys, 1827e04126c7SBarry Carroll }, 1828e04126c7SBarry Carroll { 1829c45fc81eSDmitry Torokhov /* Samsung SQ45S70S */ 1830157f3a3eSDmitry Torokhov .matches = { 1831157f3a3eSDmitry Torokhov DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."), 1832157f3a3eSDmitry Torokhov DMI_MATCH(DMI_PRODUCT_NAME, "SQ45S70S"), 1833157f3a3eSDmitry Torokhov }, 1834157f3a3eSDmitry Torokhov .callback = atkbd_setup_forced_release, 1835157f3a3eSDmitry Torokhov .driver_data = atkbd_samsung_forced_release_keys, 1836157f3a3eSDmitry Torokhov }, 1837157f3a3eSDmitry Torokhov { 1838c45fc81eSDmitry Torokhov /* Fujitsu Amilo PA 1510 */ 1839adcb523eSDaniel Mierswa .matches = { 1840adcb523eSDaniel Mierswa DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), 1841adcb523eSDaniel Mierswa DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Pa 1510"), 1842adcb523eSDaniel Mierswa }, 1843adcb523eSDaniel Mierswa .callback = atkbd_setup_forced_release, 1844000c2a35SHerton Ronaldo Krzesinski .driver_data = atkbd_volume_forced_release_keys, 1845adcb523eSDaniel Mierswa }, 18469166d0f6SAdrian Batzill { 1847c45fc81eSDmitry Torokhov /* Fujitsu Amilo Pi 3525 */ 1848f0a14de2SSimon Davie .matches = { 1849f0a14de2SSimon Davie DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), 1850f0a14de2SSimon Davie DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Pi 3525"), 1851f0a14de2SSimon Davie }, 1852f0a14de2SSimon Davie .callback = atkbd_setup_forced_release, 1853f0a14de2SSimon Davie .driver_data = atkbd_amilo_pi3525_forced_release_keys, 1854f0a14de2SSimon Davie }, 1855f0a14de2SSimon Davie { 1856c45fc81eSDmitry Torokhov /* Fujitsu Amilo Xi 3650 */ 18579166d0f6SAdrian Batzill .matches = { 18589166d0f6SAdrian Batzill DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), 18599166d0f6SAdrian Batzill DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Xi 3650"), 18609166d0f6SAdrian Batzill }, 18619166d0f6SAdrian Batzill .callback = atkbd_setup_forced_release, 18629166d0f6SAdrian Batzill .driver_data = atkbd_amilo_xi3650_forced_release_keys, 18639166d0f6SAdrian Batzill }, 1864032e46cbSJerone Young { 1865032e46cbSJerone Young .matches = { 1866032e46cbSJerone Young DMI_MATCH(DMI_SYS_VENDOR, "Soltech Corporation"), 1867032e46cbSJerone Young DMI_MATCH(DMI_PRODUCT_NAME, "TA12"), 1868032e46cbSJerone Young }, 1869032e46cbSJerone Young .callback = atkbd_setup_forced_release, 1870032e46cbSJerone Young .driver_data = atkdb_soltech_ta12_forced_release_keys, 1871032e46cbSJerone Young }, 1872e5713069SJamie Lentin { 1873c45fc81eSDmitry Torokhov /* OQO Model 01+ */ 1874e5713069SJamie Lentin .matches = { 1875e5713069SJamie Lentin DMI_MATCH(DMI_SYS_VENDOR, "OQO"), 1876e5713069SJamie Lentin DMI_MATCH(DMI_PRODUCT_NAME, "ZEPTO"), 1877e5713069SJamie Lentin }, 1878e5713069SJamie Lentin .callback = atkbd_setup_scancode_fixup, 1879e5713069SJamie Lentin .driver_data = atkbd_oqo_01plus_scancode_fixup, 1880e5713069SJamie Lentin }, 18813d725caaSSheng-Liang Song { 18823d725caaSSheng-Liang Song .matches = { 18833d725caaSSheng-Liang Song DMI_MATCH(DMI_SYS_VENDOR, "LG Electronics"), 18843d725caaSSheng-Liang Song }, 18853d725caaSSheng-Liang Song .callback = atkbd_deactivate_fixup, 18863d725caaSSheng-Liang Song }, 1887554101e3SGiel de Nijs { } 1888554101e3SGiel de Nijs }; 18891da177e4SLinus Torvalds 18901da177e4SLinus Torvalds static int __init atkbd_init(void) 18911da177e4SLinus Torvalds { 1892554101e3SGiel de Nijs dmi_check_system(atkbd_dmi_quirk_table); 1893554101e3SGiel de Nijs 1894153a9df0SAkinobu Mita return serio_register_driver(&atkbd_drv); 18951da177e4SLinus Torvalds } 18961da177e4SLinus Torvalds 18971da177e4SLinus Torvalds static void __exit atkbd_exit(void) 18981da177e4SLinus Torvalds { 18991da177e4SLinus Torvalds serio_unregister_driver(&atkbd_drv); 19001da177e4SLinus Torvalds } 19011da177e4SLinus Torvalds 19021da177e4SLinus Torvalds module_init(atkbd_init); 19031da177e4SLinus Torvalds module_exit(atkbd_exit); 1904