blob: 7c235013dba3e4d2d94f9b55968967b79355fbb0 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * AT and PS/2 keyboard driver
3 *
4 * Copyright (c) 1999-2002 Vojtech Pavlik
5 */
6
7/*
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License version 2 as published by
10 * the Free Software Foundation.
11 */
12
13/*
14 * This driver can handle standard AT keyboards and PS/2 keyboards in
15 * Translated and Raw Set 2 and Set 3, as well as AT keyboards on dumb
16 * input-only controllers and AT keyboards connected over a one way RS232
17 * converter.
18 */
19
20#include <linux/delay.h>
21#include <linux/module.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070022#include <linux/slab.h>
23#include <linux/interrupt.h>
24#include <linux/init.h>
25#include <linux/input.h>
26#include <linux/serio.h>
27#include <linux/workqueue.h>
28#include <linux/libps2.h>
Ingo Molnar33d3f072006-02-19 00:22:18 -050029#include <linux/mutex.h>
Giel de Nijs554101e2007-11-02 09:08:02 -040030#include <linux/dmi.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070031
32#define DRIVER_DESC "AT and PS/2 keyboard driver"
33
34MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
35MODULE_DESCRIPTION(DRIVER_DESC);
36MODULE_LICENSE("GPL");
37
38static int atkbd_set = 2;
39module_param_named(set, atkbd_set, int, 0);
40MODULE_PARM_DESC(set, "Select keyboard code set (2 = default, 3 = PS/2 native)");
41
42#if defined(__i386__) || defined(__x86_64__) || defined(__hppa__)
Dmitry Torokhova9a1f9c2010-01-06 23:51:47 -080043static bool atkbd_reset;
Linus Torvalds1da177e2005-04-16 15:20:36 -070044#else
Dmitry Torokhova9a1f9c2010-01-06 23:51:47 -080045static bool atkbd_reset = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -070046#endif
47module_param_named(reset, atkbd_reset, bool, 0);
48MODULE_PARM_DESC(reset, "Reset keyboard during initialization");
49
Dmitry Torokhova9a1f9c2010-01-06 23:51:47 -080050static bool atkbd_softrepeat;
Linus Torvalds1da177e2005-04-16 15:20:36 -070051module_param_named(softrepeat, atkbd_softrepeat, bool, 0);
52MODULE_PARM_DESC(softrepeat, "Use software keyboard repeat");
53
Dmitry Torokhova9a1f9c2010-01-06 23:51:47 -080054static bool atkbd_softraw = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -070055module_param_named(softraw, atkbd_softraw, bool, 0);
56MODULE_PARM_DESC(softraw, "Use software generated rawmode");
57
Dmitry Torokhova9a1f9c2010-01-06 23:51:47 -080058static bool atkbd_scroll;
Linus Torvalds1da177e2005-04-16 15:20:36 -070059module_param_named(scroll, atkbd_scroll, bool, 0);
60MODULE_PARM_DESC(scroll, "Enable scroll-wheel on MS Office and similar keyboards");
61
Dmitry Torokhova9a1f9c2010-01-06 23:51:47 -080062static bool atkbd_extra;
Linus Torvalds1da177e2005-04-16 15:20:36 -070063module_param_named(extra, atkbd_extra, bool, 0);
64MODULE_PARM_DESC(extra, "Enable extra LEDs and keys on IBM RapidAcces, EzKey and similar keyboards");
65
Linus Torvalds1da177e2005-04-16 15:20:36 -070066/*
67 * Scancode to keycode tables. These are just the default setting, and
Frederik Schwarzer0211a9c2008-12-29 22:14:56 +010068 * are loadable via a userland utility.
Linus Torvalds1da177e2005-04-16 15:20:36 -070069 */
70
Dmitry Torokhov1ba36e12009-09-03 17:22:04 -070071#define ATKBD_KEYMAP_SIZE 512
72
73static const unsigned short atkbd_set2_keycode[ATKBD_KEYMAP_SIZE] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -070074
75#ifdef CONFIG_KEYBOARD_ATKBD_HP_KEYCODES
76
77/* XXX: need a more general approach */
78
79#include "hpps2atkbd.h" /* include the keyboard scancodes */
80
81#else
82 0, 67, 65, 63, 61, 59, 60, 88, 0, 68, 66, 64, 62, 15, 41,117,
83 0, 56, 42, 93, 29, 16, 2, 0, 0, 0, 44, 31, 30, 17, 3, 0,
84 0, 46, 45, 32, 18, 5, 4, 95, 0, 57, 47, 33, 20, 19, 6,183,
85 0, 49, 48, 35, 34, 21, 7,184, 0, 0, 50, 36, 22, 8, 9,185,
86 0, 51, 37, 23, 24, 11, 10, 0, 0, 52, 53, 38, 39, 25, 12, 0,
87 0, 89, 40, 0, 26, 13, 0, 0, 58, 54, 28, 27, 0, 43, 0, 85,
88 0, 86, 91, 90, 92, 0, 14, 94, 0, 79,124, 75, 71,121, 0, 0,
89 82, 83, 80, 76, 77, 72, 1, 69, 87, 78, 81, 74, 55, 73, 70, 99,
90
91 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
92 217,100,255, 0, 97,165, 0, 0,156, 0, 0, 0, 0, 0, 0,125,
93 173,114, 0,113, 0, 0, 0,126,128, 0, 0,140, 0, 0, 0,127,
Hans de Goede72a42f22007-07-03 01:55:18 -040094 159, 0,115, 0,164, 0, 0,116,158, 0,172,166, 0, 0, 0,142,
Linus Torvalds1da177e2005-04-16 15:20:36 -070095 157, 0, 0, 0, 0, 0, 0, 0,155, 0, 98, 0, 0,163, 0, 0,
96 226, 0, 0, 0, 0, 0, 0, 0, 0,255, 96, 0, 0, 0,143, 0,
97 0, 0, 0, 0, 0, 0, 0, 0, 0,107, 0,105,102, 0, 0,112,
98 110,111,108,112,106,103, 0,119, 0,118,109, 0, 99,104,119, 0,
99
100 0, 0, 0, 65, 99,
101#endif
102};
103
Dmitry Torokhov1ba36e12009-09-03 17:22:04 -0700104static const unsigned short atkbd_set3_keycode[ATKBD_KEYMAP_SIZE] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700105
106 0, 0, 0, 0, 0, 0, 0, 59, 1,138,128,129,130, 15, 41, 60,
107 131, 29, 42, 86, 58, 16, 2, 61,133, 56, 44, 31, 30, 17, 3, 62,
108 134, 46, 45, 32, 18, 5, 4, 63,135, 57, 47, 33, 20, 19, 6, 64,
109 136, 49, 48, 35, 34, 21, 7, 65,137,100, 50, 36, 22, 8, 9, 66,
110 125, 51, 37, 23, 24, 11, 10, 67,126, 52, 53, 38, 39, 25, 12, 68,
111 113,114, 40, 43, 26, 13, 87, 99, 97, 54, 28, 27, 43, 43, 88, 70,
112 108,105,119,103,111,107, 14,110, 0, 79,106, 75, 71,109,102,104,
113 82, 83, 80, 76, 77, 72, 69, 98, 0, 96, 81, 0, 78, 73, 55,183,
114
115 184,185,186,187, 74, 94, 92, 93, 0, 0, 0,125,126,127,112, 0,
Hans de Goede72a42f22007-07-03 01:55:18 -0400116 0,139,172,163,165,115,152,172,166,140,160,154,113,114,167,168,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700117 148,149,147,140
118};
119
Dmitry Torokhovf6d65612008-06-02 00:39:45 -0400120static const unsigned short atkbd_unxlate_table[128] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700121 0,118, 22, 30, 38, 37, 46, 54, 61, 62, 70, 69, 78, 85,102, 13,
122 21, 29, 36, 45, 44, 53, 60, 67, 68, 77, 84, 91, 90, 20, 28, 27,
123 35, 43, 52, 51, 59, 66, 75, 76, 82, 14, 18, 93, 26, 34, 33, 42,
124 50, 49, 58, 65, 73, 74, 89,124, 17, 41, 88, 5, 6, 4, 12, 3,
125 11, 2, 10, 1, 9,119,126,108,117,125,123,107,115,116,121,105,
126 114,122,112,113,127, 96, 97,120, 7, 15, 23, 31, 39, 47, 55, 63,
127 71, 79, 86, 94, 8, 16, 24, 32, 40, 48, 56, 64, 72, 80, 87,111,
128 19, 25, 57, 81, 83, 92, 95, 98, 99,100,101,103,104,106,109,110
129};
130
131#define ATKBD_CMD_SETLEDS 0x10ed
132#define ATKBD_CMD_GSCANSET 0x11f0
133#define ATKBD_CMD_SSCANSET 0x10f0
134#define ATKBD_CMD_GETID 0x02f2
135#define ATKBD_CMD_SETREP 0x10f3
136#define ATKBD_CMD_ENABLE 0x00f4
137#define ATKBD_CMD_RESET_DIS 0x00f5
138#define ATKBD_CMD_SETALL_MBR 0x00fa
139#define ATKBD_CMD_RESET_BAT 0x02ff
140#define ATKBD_CMD_RESEND 0x00fe
141#define ATKBD_CMD_EX_ENABLE 0x10ea
142#define ATKBD_CMD_EX_SETLEDS 0x20eb
143#define ATKBD_CMD_OK_GETID 0x02e8
144
145#define ATKBD_RET_ACK 0xfa
146#define ATKBD_RET_NAK 0xfe
147#define ATKBD_RET_BAT 0xaa
148#define ATKBD_RET_EMUL0 0xe0
149#define ATKBD_RET_EMUL1 0xe1
150#define ATKBD_RET_RELEASE 0xf0
Dmitry Torokhov0ae051a2006-06-26 01:52:34 -0400151#define ATKBD_RET_HANJA 0xf1
152#define ATKBD_RET_HANGEUL 0xf2
Linus Torvalds1da177e2005-04-16 15:20:36 -0700153#define ATKBD_RET_ERR 0xff
154
155#define ATKBD_KEY_UNKNOWN 0
156#define ATKBD_KEY_NULL 255
157
158#define ATKBD_SCR_1 254
159#define ATKBD_SCR_2 253
160#define ATKBD_SCR_4 252
161#define ATKBD_SCR_8 251
162#define ATKBD_SCR_CLICK 250
163#define ATKBD_SCR_LEFT 249
164#define ATKBD_SCR_RIGHT 248
165
Dmitry Torokhovf6d65612008-06-02 00:39:45 -0400166#define ATKBD_SPECIAL ATKBD_SCR_RIGHT
Linus Torvalds1da177e2005-04-16 15:20:36 -0700167
Dmitry Torokhov0d4c8592005-11-20 00:49:42 -0500168#define ATKBD_LED_EVENT_BIT 0
169#define ATKBD_REP_EVENT_BIT 1
170
Dmitry Torokhov0ae051a2006-06-26 01:52:34 -0400171#define ATKBD_XL_ERR 0x01
172#define ATKBD_XL_BAT 0x02
173#define ATKBD_XL_ACK 0x04
174#define ATKBD_XL_NAK 0x08
175#define ATKBD_XL_HANGEUL 0x10
176#define ATKBD_XL_HANJA 0x20
177
Dmitry Torokhovf6d65612008-06-02 00:39:45 -0400178static const struct {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700179 unsigned char keycode;
180 unsigned char set2;
181} atkbd_scroll_keys[] = {
182 { ATKBD_SCR_1, 0xc5 },
Vojtech Pavlik5212dd52005-05-28 15:51:47 -0700183 { ATKBD_SCR_2, 0x9d },
184 { ATKBD_SCR_4, 0xa4 },
185 { ATKBD_SCR_8, 0x9b },
Linus Torvalds1da177e2005-04-16 15:20:36 -0700186 { ATKBD_SCR_CLICK, 0xe0 },
187 { ATKBD_SCR_LEFT, 0xcb },
188 { ATKBD_SCR_RIGHT, 0xd2 },
189};
190
191/*
192 * The atkbd control structure
193 */
194
195struct atkbd {
196
Dmitry Torokhov3c42f0c2005-09-15 02:01:45 -0500197 struct ps2dev ps2dev;
198 struct input_dev *dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700199
200 /* Written only during init */
201 char name[64];
202 char phys[32];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700203
204 unsigned short id;
Dmitry Torokhov1ba36e12009-09-03 17:22:04 -0700205 unsigned short keycode[ATKBD_KEYMAP_SIZE];
206 DECLARE_BITMAP(force_release_mask, ATKBD_KEYMAP_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700207 unsigned char set;
Dmitry Torokhova9a1f9c2010-01-06 23:51:47 -0800208 bool translated;
209 bool extra;
210 bool write;
211 bool softrepeat;
212 bool softraw;
213 bool scroll;
214 bool enabled;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700215
216 /* Accessed only from interrupt */
217 unsigned char emul;
Dmitry Torokhova9a1f9c2010-01-06 23:51:47 -0800218 bool resend;
219 bool release;
Dmitry Torokhov0ae051a2006-06-26 01:52:34 -0400220 unsigned long xl_bit;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700221 unsigned int last;
222 unsigned long time;
Dmitry Torokhov86255d92006-10-11 01:44:46 -0400223 unsigned long err_count;
Dmitry Torokhov0d4c8592005-11-20 00:49:42 -0500224
Dmitry Torokhovda4249c2007-06-28 00:46:56 -0400225 struct delayed_work event_work;
226 unsigned long event_jiffies;
Ingo Molnar33d3f072006-02-19 00:22:18 -0500227 struct mutex event_mutex;
Dmitry Torokhov0d4c8592005-11-20 00:49:42 -0500228 unsigned long event_mask;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700229};
230
Giel de Nijs554101e2007-11-02 09:08:02 -0400231/*
Thadeu Lima de Souza Cascardo36726dd2009-07-21 15:57:47 -0300232 * System-specific keymap fixup routine
Giel de Nijs554101e2007-11-02 09:08:02 -0400233 */
Daniel Mierswa39191692009-03-04 23:27:15 -0800234static void (*atkbd_platform_fixup)(struct atkbd *, const void *data);
235static void *atkbd_platform_fixup_data;
Jamie Lentine5713062009-10-20 14:36:49 -0700236static unsigned int (*atkbd_platform_scancode_fixup)(struct atkbd *, unsigned int);
Giel de Nijs554101e2007-11-02 09:08:02 -0400237
Linus Torvalds1da177e2005-04-16 15:20:36 -0700238static ssize_t atkbd_attr_show_helper(struct device *dev, char *buf,
239 ssize_t (*handler)(struct atkbd *, char *));
240static ssize_t atkbd_attr_set_helper(struct device *dev, const char *buf, size_t count,
241 ssize_t (*handler)(struct atkbd *, const char *, size_t));
242#define ATKBD_DEFINE_ATTR(_name) \
243static ssize_t atkbd_show_##_name(struct atkbd *, char *); \
244static ssize_t atkbd_set_##_name(struct atkbd *, const char *, size_t); \
Dmitry Torokhov86255d92006-10-11 01:44:46 -0400245static ssize_t atkbd_do_show_##_name(struct device *d, \
246 struct device_attribute *attr, char *b) \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700247{ \
248 return atkbd_attr_show_helper(d, b, atkbd_show_##_name); \
249} \
Dmitry Torokhov86255d92006-10-11 01:44:46 -0400250static ssize_t atkbd_do_set_##_name(struct device *d, \
251 struct device_attribute *attr, const char *b, size_t s) \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700252{ \
253 return atkbd_attr_set_helper(d, b, s, atkbd_set_##_name); \
254} \
Dmitry Torokhovd083e902005-05-29 02:28:42 -0500255static struct device_attribute atkbd_attr_##_name = \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700256 __ATTR(_name, S_IWUSR | S_IRUGO, atkbd_do_show_##_name, atkbd_do_set_##_name);
257
258ATKBD_DEFINE_ATTR(extra);
Dmitry Torokhov1ba36e12009-09-03 17:22:04 -0700259ATKBD_DEFINE_ATTR(force_release);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700260ATKBD_DEFINE_ATTR(scroll);
261ATKBD_DEFINE_ATTR(set);
262ATKBD_DEFINE_ATTR(softrepeat);
263ATKBD_DEFINE_ATTR(softraw);
264
Dmitry Torokhov86255d92006-10-11 01:44:46 -0400265#define ATKBD_DEFINE_RO_ATTR(_name) \
266static ssize_t atkbd_show_##_name(struct atkbd *, char *); \
267static ssize_t atkbd_do_show_##_name(struct device *d, \
268 struct device_attribute *attr, char *b) \
269{ \
270 return atkbd_attr_show_helper(d, b, atkbd_show_##_name); \
271} \
272static struct device_attribute atkbd_attr_##_name = \
273 __ATTR(_name, S_IRUGO, atkbd_do_show_##_name, NULL);
274
275ATKBD_DEFINE_RO_ATTR(err_count);
276
277static struct attribute *atkbd_attributes[] = {
278 &atkbd_attr_extra.attr,
Dmitry Torokhov1ba36e12009-09-03 17:22:04 -0700279 &atkbd_attr_force_release.attr,
Dmitry Torokhov86255d92006-10-11 01:44:46 -0400280 &atkbd_attr_scroll.attr,
281 &atkbd_attr_set.attr,
282 &atkbd_attr_softrepeat.attr,
283 &atkbd_attr_softraw.attr,
284 &atkbd_attr_err_count.attr,
285 NULL
286};
287
288static struct attribute_group atkbd_attribute_group = {
289 .attrs = atkbd_attributes,
290};
291
Dmitry Torokhov0ae051a2006-06-26 01:52:34 -0400292static const unsigned int xl_table[] = {
293 ATKBD_RET_BAT, ATKBD_RET_ERR, ATKBD_RET_ACK,
294 ATKBD_RET_NAK, ATKBD_RET_HANJA, ATKBD_RET_HANGEUL,
295};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700296
Dmitry Torokhov0ae051a2006-06-26 01:52:34 -0400297/*
298 * Checks if we should mangle the scancode to extract 'release' bit
299 * in translated mode.
300 */
Dmitry Torokhova9a1f9c2010-01-06 23:51:47 -0800301static bool atkbd_need_xlate(unsigned long xl_bit, unsigned char code)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700302{
Dmitry Torokhov0ae051a2006-06-26 01:52:34 -0400303 int i;
304
305 if (code == ATKBD_RET_EMUL0 || code == ATKBD_RET_EMUL1)
Dmitry Torokhova9a1f9c2010-01-06 23:51:47 -0800306 return false;
Dmitry Torokhov0ae051a2006-06-26 01:52:34 -0400307
308 for (i = 0; i < ARRAY_SIZE(xl_table); i++)
309 if (code == xl_table[i])
310 return test_bit(i, &xl_bit);
311
Dmitry Torokhova9a1f9c2010-01-06 23:51:47 -0800312 return true;
Dmitry Torokhov0ae051a2006-06-26 01:52:34 -0400313}
314
315/*
316 * Calculates new value of xl_bit so the driver can distinguish
317 * between make/break pair of scancodes for select keys and PS/2
318 * protocol responses.
319 */
320static void atkbd_calculate_xl_bit(struct atkbd *atkbd, unsigned char code)
321{
322 int i;
323
324 for (i = 0; i < ARRAY_SIZE(xl_table); i++) {
325 if (!((code ^ xl_table[i]) & 0x7f)) {
326 if (code & 0x80)
327 __clear_bit(i, &atkbd->xl_bit);
328 else
329 __set_bit(i, &atkbd->xl_bit);
330 break;
331 }
332 }
333}
334
335/*
336 * Encode the scancode, 0xe0 prefix, and high bit into a single integer,
337 * keeping kernel 2.4 compatibility for set 2
338 */
339static unsigned int atkbd_compat_scancode(struct atkbd *atkbd, unsigned int code)
340{
341 if (atkbd->set == 3) {
342 if (atkbd->emul == 1)
343 code |= 0x100;
344 } else {
345 code = (code & 0x7f) | ((code & 0x80) << 1);
346 if (atkbd->emul == 1)
347 code |= 0x80;
348 }
349
350 return code;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700351}
352
353/*
354 * atkbd_interrupt(). Here takes place processing of data received from
355 * the keyboard into events.
356 */
357
358static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data,
Dmitry Torokhova9a1f9c2010-01-06 23:51:47 -0800359 unsigned int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700360{
361 struct atkbd *atkbd = serio_get_drvdata(serio);
Dmitry Torokhov0ae051a2006-06-26 01:52:34 -0400362 struct input_dev *dev = atkbd->dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700363 unsigned int code = data;
Giel de Nijs554101e2007-11-02 09:08:02 -0400364 int scroll = 0, hscroll = 0, click = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700365 int value;
Dmitry Torokhovf6d65612008-06-02 00:39:45 -0400366 unsigned short keycode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700367
Dmitry Torokhova9a1f9c2010-01-06 23:51:47 -0800368 dev_dbg(&serio->dev, "Received %02x flags %02x\n", data, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700369
370#if !defined(__i386__) && !defined (__x86_64__)
371 if ((flags & (SERIO_FRAME | SERIO_PARITY)) && (~flags & SERIO_TIMEOUT) && !atkbd->resend && atkbd->write) {
Dmitry Torokhova9a1f9c2010-01-06 23:51:47 -0800372 dev_warn(&serio->dev, "Frame/parity error: %02x\n", flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700373 serio_write(serio, ATKBD_CMD_RESEND);
Dmitry Torokhova9a1f9c2010-01-06 23:51:47 -0800374 atkbd->resend = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700375 goto out;
376 }
377
378 if (!flags && data == ATKBD_RET_ACK)
Dmitry Torokhova9a1f9c2010-01-06 23:51:47 -0800379 atkbd->resend = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700380#endif
381
382 if (unlikely(atkbd->ps2dev.flags & PS2_FLAG_ACK))
383 if (ps2_handle_ack(&atkbd->ps2dev, data))
384 goto out;
385
386 if (unlikely(atkbd->ps2dev.flags & PS2_FLAG_CMD))
387 if (ps2_handle_response(&atkbd->ps2dev, data))
388 goto out;
389
390 if (!atkbd->enabled)
391 goto out;
392
Dmitry Torokhov0ae051a2006-06-26 01:52:34 -0400393 input_event(dev, EV_MSC, MSC_RAW, code);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700394
Jamie Lentine5713062009-10-20 14:36:49 -0700395 if (atkbd_platform_scancode_fixup)
396 code = atkbd_platform_scancode_fixup(atkbd, code);
397
Linus Torvalds1da177e2005-04-16 15:20:36 -0700398 if (atkbd->translated) {
399
Dmitry Torokhov0ae051a2006-06-26 01:52:34 -0400400 if (atkbd->emul || atkbd_need_xlate(atkbd->xl_bit, code)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700401 atkbd->release = code >> 7;
402 code &= 0x7f;
403 }
404
Dmitry Torokhov0ae051a2006-06-26 01:52:34 -0400405 if (!atkbd->emul)
406 atkbd_calculate_xl_bit(atkbd, data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700407 }
408
409 switch (code) {
Dmitry Torokhova9a1f9c2010-01-06 23:51:47 -0800410 case ATKBD_RET_BAT:
411 atkbd->enabled = false;
412 serio_reconnect(atkbd->ps2dev.serio);
413 goto out;
414 case ATKBD_RET_EMUL0:
415 atkbd->emul = 1;
416 goto out;
417 case ATKBD_RET_EMUL1:
418 atkbd->emul = 2;
419 goto out;
420 case ATKBD_RET_RELEASE:
421 atkbd->release = true;
422 goto out;
423 case ATKBD_RET_ACK:
424 case ATKBD_RET_NAK:
425 if (printk_ratelimit())
426 dev_warn(&serio->dev,
427 "Spurious %s on %s. "
428 "Some program might be trying access hardware directly.\n",
429 data == ATKBD_RET_ACK ? "ACK" : "NAK", serio->phys);
430 goto out;
431 case ATKBD_RET_ERR:
432 atkbd->err_count++;
433 dev_dbg(&serio->dev, "Keyboard on %s reports too many keys pressed.\n",
434 serio->phys);
435 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700436 }
437
Dmitry Torokhov0ae051a2006-06-26 01:52:34 -0400438 code = atkbd_compat_scancode(atkbd, code);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700439
Dmitry Torokhov0ae051a2006-06-26 01:52:34 -0400440 if (atkbd->emul && --atkbd->emul)
441 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700442
Dmitry Torokhov0ae051a2006-06-26 01:52:34 -0400443 keycode = atkbd->keycode[code];
444
445 if (keycode != ATKBD_KEY_NULL)
446 input_event(dev, EV_MSC, MSC_SCAN, code);
447
448 switch (keycode) {
Dmitry Torokhova9a1f9c2010-01-06 23:51:47 -0800449 case ATKBD_KEY_NULL:
450 break;
451 case ATKBD_KEY_UNKNOWN:
452 dev_warn(&serio->dev,
453 "Unknown key %s (%s set %d, code %#x on %s).\n",
454 atkbd->release ? "released" : "pressed",
455 atkbd->translated ? "translated" : "raw",
456 atkbd->set, code, serio->phys);
457 dev_warn(&serio->dev,
458 "Use 'setkeycodes %s%02x <keycode>' to make it known.\n",
459 code & 0x80 ? "e0" : "", code & 0x7f);
460 input_sync(dev);
461 break;
462 case ATKBD_SCR_1:
463 scroll = 1;
464 break;
465 case ATKBD_SCR_2:
466 scroll = 2;
467 break;
468 case ATKBD_SCR_4:
469 scroll = 4;
470 break;
471 case ATKBD_SCR_8:
472 scroll = 8;
473 break;
474 case ATKBD_SCR_CLICK:
475 click = !atkbd->release;
476 break;
477 case ATKBD_SCR_LEFT:
478 hscroll = -1;
479 break;
480 case ATKBD_SCR_RIGHT:
481 hscroll = 1;
482 break;
483 default:
484 if (atkbd->release) {
485 value = 0;
486 atkbd->last = 0;
487 } else if (!atkbd->softrepeat && test_bit(keycode, dev->key)) {
488 /* Workaround Toshiba laptop multiple keypress */
489 value = time_before(jiffies, atkbd->time) && atkbd->last == code ? 1 : 2;
490 } else {
491 value = 1;
492 atkbd->last = code;
493 atkbd->time = jiffies + msecs_to_jiffies(dev->rep[REP_DELAY]) / 2;
494 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700495
Dmitry Torokhova9a1f9c2010-01-06 23:51:47 -0800496 input_event(dev, EV_KEY, keycode, value);
497 input_sync(dev);
Dmitry Torokhov0ae051a2006-06-26 01:52:34 -0400498
Dmitry Torokhova9a1f9c2010-01-06 23:51:47 -0800499 if (value && test_bit(code, atkbd->force_release_mask)) {
500 input_report_key(dev, keycode, 0);
501 input_sync(dev);
502 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700503 }
504
505 if (atkbd->scroll) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700506 if (click != -1)
Dmitry Torokhov0ae051a2006-06-26 01:52:34 -0400507 input_report_key(dev, BTN_MIDDLE, click);
Dmitry Torokhova9a1f9c2010-01-06 23:51:47 -0800508 input_report_rel(dev, REL_WHEEL,
509 atkbd->release ? -scroll : scroll);
Dmitry Torokhov0ae051a2006-06-26 01:52:34 -0400510 input_report_rel(dev, REL_HWHEEL, hscroll);
511 input_sync(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700512 }
513
Dmitry Torokhova9a1f9c2010-01-06 23:51:47 -0800514 atkbd->release = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700515out:
516 return IRQ_HANDLED;
517}
518
Dmitry Torokhov3d0f0fa2006-08-04 22:52:46 -0400519static int atkbd_set_repeat_rate(struct atkbd *atkbd)
520{
521 const short period[32] =
522 { 33, 37, 42, 46, 50, 54, 58, 63, 67, 75, 83, 92, 100, 109, 116, 125,
523 133, 149, 167, 182, 200, 217, 232, 250, 270, 303, 333, 370, 400, 435, 470, 500 };
524 const short delay[4] =
525 { 250, 500, 750, 1000 };
526
527 struct input_dev *dev = atkbd->dev;
528 unsigned char param;
529 int i = 0, j = 0;
530
531 while (i < ARRAY_SIZE(period) - 1 && period[i] < dev->rep[REP_PERIOD])
532 i++;
533 dev->rep[REP_PERIOD] = period[i];
534
Florin Malita8ea371f2006-08-23 00:45:33 -0400535 while (j < ARRAY_SIZE(delay) - 1 && delay[j] < dev->rep[REP_DELAY])
Dmitry Torokhov3d0f0fa2006-08-04 22:52:46 -0400536 j++;
537 dev->rep[REP_DELAY] = delay[j];
538
539 param = i | (j << 5);
540 return ps2_command(&atkbd->ps2dev, &param, ATKBD_CMD_SETREP);
541}
542
543static int atkbd_set_leds(struct atkbd *atkbd)
544{
545 struct input_dev *dev = atkbd->dev;
546 unsigned char param[2];
547
548 param[0] = (test_bit(LED_SCROLLL, dev->led) ? 1 : 0)
549 | (test_bit(LED_NUML, dev->led) ? 2 : 0)
550 | (test_bit(LED_CAPSL, dev->led) ? 4 : 0);
551 if (ps2_command(&atkbd->ps2dev, param, ATKBD_CMD_SETLEDS))
552 return -1;
553
554 if (atkbd->extra) {
555 param[0] = 0;
556 param[1] = (test_bit(LED_COMPOSE, dev->led) ? 0x01 : 0)
557 | (test_bit(LED_SLEEP, dev->led) ? 0x02 : 0)
558 | (test_bit(LED_SUSPEND, dev->led) ? 0x04 : 0)
559 | (test_bit(LED_MISC, dev->led) ? 0x10 : 0)
560 | (test_bit(LED_MUTE, dev->led) ? 0x20 : 0);
561 if (ps2_command(&atkbd->ps2dev, param, ATKBD_CMD_EX_SETLEDS))
562 return -1;
563 }
564
565 return 0;
566}
567
Linus Torvalds1da177e2005-04-16 15:20:36 -0700568/*
Dmitry Torokhov0d4c8592005-11-20 00:49:42 -0500569 * atkbd_event_work() is used to complete processing of events that
570 * can not be processed by input_event() which is often called from
571 * interrupt context.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700572 */
573
David Howells65f27f32006-11-22 14:55:48 +0000574static void atkbd_event_work(struct work_struct *work)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700575{
Dmitry Torokhovda4249c2007-06-28 00:46:56 -0400576 struct atkbd *atkbd = container_of(work, struct atkbd, event_work.work);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700577
Ingo Molnar33d3f072006-02-19 00:22:18 -0500578 mutex_lock(&atkbd->event_mutex);
Dmitry Torokhov0d4c8592005-11-20 00:49:42 -0500579
Dmitry Torokhov94dfb0d2009-10-13 23:39:17 -0700580 if (!atkbd->enabled) {
581 /*
582 * Serio ports are resumed asynchronously so while driver core
583 * thinks that device is already fully operational in reality
584 * it may not be ready yet. In this case we need to keep
585 * rescheduling till reconnect completes.
586 */
587 schedule_delayed_work(&atkbd->event_work,
588 msecs_to_jiffies(100));
589 } else {
590 if (test_and_clear_bit(ATKBD_LED_EVENT_BIT, &atkbd->event_mask))
591 atkbd_set_leds(atkbd);
Dmitry Torokhov0d4c8592005-11-20 00:49:42 -0500592
Dmitry Torokhov94dfb0d2009-10-13 23:39:17 -0700593 if (test_and_clear_bit(ATKBD_REP_EVENT_BIT, &atkbd->event_mask))
594 atkbd_set_repeat_rate(atkbd);
595 }
Dmitry Torokhov0d4c8592005-11-20 00:49:42 -0500596
Ingo Molnar33d3f072006-02-19 00:22:18 -0500597 mutex_unlock(&atkbd->event_mutex);
Dmitry Torokhov0d4c8592005-11-20 00:49:42 -0500598}
599
600/*
Dmitry Torokhovda4249c2007-06-28 00:46:56 -0400601 * Schedule switch for execution. We need to throttle requests,
602 * otherwise keyboard may become unresponsive.
603 */
604static void atkbd_schedule_event_work(struct atkbd *atkbd, int event_bit)
605{
606 unsigned long delay = msecs_to_jiffies(50);
607
608 if (time_after(jiffies, atkbd->event_jiffies + delay))
609 delay = 0;
610
611 atkbd->event_jiffies = jiffies;
612 set_bit(event_bit, &atkbd->event_mask);
613 wmb();
614 schedule_delayed_work(&atkbd->event_work, delay);
615}
616
617/*
Dmitry Torokhov0d4c8592005-11-20 00:49:42 -0500618 * Event callback from the input module. Events that change the state of
619 * the hardware are processed here. If action can not be performed in
620 * interrupt context it is offloaded to atkbd_event_work.
621 */
622
Dmitry Torokhovda4249c2007-06-28 00:46:56 -0400623static int atkbd_event(struct input_dev *dev,
624 unsigned int type, unsigned int code, int value)
Dmitry Torokhov0d4c8592005-11-20 00:49:42 -0500625{
Dmitry Torokhovb3568722007-04-12 01:34:20 -0400626 struct atkbd *atkbd = input_get_drvdata(dev);
Dmitry Torokhov0d4c8592005-11-20 00:49:42 -0500627
Linus Torvalds1da177e2005-04-16 15:20:36 -0700628 if (!atkbd->write)
629 return -1;
630
631 switch (type) {
632
Dmitry Torokhova9a1f9c2010-01-06 23:51:47 -0800633 case EV_LED:
634 atkbd_schedule_event_work(atkbd, ATKBD_LED_EVENT_BIT);
635 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700636
Dmitry Torokhova9a1f9c2010-01-06 23:51:47 -0800637 case EV_REP:
638 if (!atkbd->softrepeat)
639 atkbd_schedule_event_work(atkbd, ATKBD_REP_EVENT_BIT);
640 return 0;
641
642 default:
643 return -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700644 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700645}
646
647/*
648 * atkbd_enable() signals that interrupt handler is allowed to
649 * generate input events.
650 */
651
652static inline void atkbd_enable(struct atkbd *atkbd)
653{
654 serio_pause_rx(atkbd->ps2dev.serio);
Dmitry Torokhova9a1f9c2010-01-06 23:51:47 -0800655 atkbd->enabled = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700656 serio_continue_rx(atkbd->ps2dev.serio);
657}
658
659/*
660 * atkbd_disable() tells input handler that all incoming data except
661 * for ACKs and command response should be dropped.
662 */
663
664static inline void atkbd_disable(struct atkbd *atkbd)
665{
666 serio_pause_rx(atkbd->ps2dev.serio);
Dmitry Torokhova9a1f9c2010-01-06 23:51:47 -0800667 atkbd->enabled = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700668 serio_continue_rx(atkbd->ps2dev.serio);
669}
670
671/*
672 * atkbd_probe() probes for an AT keyboard on a serio port.
673 */
674
675static int atkbd_probe(struct atkbd *atkbd)
676{
677 struct ps2dev *ps2dev = &atkbd->ps2dev;
678 unsigned char param[2];
679
680/*
681 * Some systems, where the bit-twiddling when testing the io-lines of the
682 * controller may confuse the keyboard need a full reset of the keyboard. On
683 * these systems the BIOS also usually doesn't do it for us.
684 */
685
686 if (atkbd_reset)
687 if (ps2_command(ps2dev, NULL, ATKBD_CMD_RESET_BAT))
Dmitry Torokhova9a1f9c2010-01-06 23:51:47 -0800688 dev_warn(&ps2dev->serio->dev,
689 "keyboard reset failed on %s\n",
690 ps2dev->serio->phys);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700691
692/*
693 * Then we check the keyboard ID. We should get 0xab83 under normal conditions.
694 * Some keyboards report different values, but the first byte is always 0xab or
695 * 0xac. Some old AT keyboards don't report anything. If a mouse is connected, this
696 * should make sure we don't try to set the LEDs on it.
697 */
698
699 param[0] = param[1] = 0xa5; /* initialize with invalid values */
700 if (ps2_command(ps2dev, param, ATKBD_CMD_GETID)) {
701
702/*
703 * If the get ID command failed, we check if we can at least set the LEDs on
704 * the keyboard. This should work on every keyboard out there. It also turns
705 * the LEDs off, which we want anyway.
706 */
707 param[0] = 0;
708 if (ps2_command(ps2dev, param, ATKBD_CMD_SETLEDS))
709 return -1;
710 atkbd->id = 0xabba;
711 return 0;
712 }
713
Dmitry Torokhov98078792006-09-14 01:31:27 -0400714 if (!ps2_is_keyboard_id(param[0]))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700715 return -1;
716
717 atkbd->id = (param[0] << 8) | param[1];
718
719 if (atkbd->id == 0xaca1 && atkbd->translated) {
Dmitry Torokhova9a1f9c2010-01-06 23:51:47 -0800720 dev_err(&ps2dev->serio->dev,
721 "NCD terminal keyboards are only supported on non-translating controlelrs. "
722 "Use i8042.direct=1 to disable translation.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700723 return -1;
724 }
725
726 return 0;
727}
728
729/*
730 * atkbd_select_set checks if a keyboard has a working Set 3 support, and
731 * sets it into that. Unfortunately there are keyboards that can be switched
732 * to Set 3, but don't work well in that (BTC Multimedia ...)
733 */
734
735static int atkbd_select_set(struct atkbd *atkbd, int target_set, int allow_extra)
736{
737 struct ps2dev *ps2dev = &atkbd->ps2dev;
738 unsigned char param[2];
739
Dmitry Torokhova9a1f9c2010-01-06 23:51:47 -0800740 atkbd->extra = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700741/*
742 * For known special keyboards we can go ahead and set the correct set.
743 * We check for NCD PS/2 Sun, NorthGate OmniKey 101 and
744 * IBM RapidAccess / IBM EzButton / Chicony KBP-8993 keyboards.
745 */
746
747 if (atkbd->translated)
748 return 2;
749
750 if (atkbd->id == 0xaca1) {
751 param[0] = 3;
752 ps2_command(ps2dev, param, ATKBD_CMD_SSCANSET);
753 return 3;
754 }
755
756 if (allow_extra) {
757 param[0] = 0x71;
758 if (!ps2_command(ps2dev, param, ATKBD_CMD_EX_ENABLE)) {
Dmitry Torokhova9a1f9c2010-01-06 23:51:47 -0800759 atkbd->extra = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700760 return 2;
761 }
762 }
763
764 if (target_set != 3)
765 return 2;
766
767 if (!ps2_command(ps2dev, param, ATKBD_CMD_OK_GETID)) {
768 atkbd->id = param[0] << 8 | param[1];
769 return 2;
770 }
771
772 param[0] = 3;
773 if (ps2_command(ps2dev, param, ATKBD_CMD_SSCANSET))
774 return 2;
775
776 param[0] = 0;
777 if (ps2_command(ps2dev, param, ATKBD_CMD_GSCANSET))
778 return 2;
779
780 if (param[0] != 3) {
781 param[0] = 2;
782 if (ps2_command(ps2dev, param, ATKBD_CMD_SSCANSET))
783 return 2;
784 }
785
786 ps2_command(ps2dev, param, ATKBD_CMD_SETALL_MBR);
787
788 return 3;
789}
790
Dmitry Torokhovfc0eb282009-10-12 22:47:25 -0700791static int atkbd_reset_state(struct atkbd *atkbd)
792{
793 struct ps2dev *ps2dev = &atkbd->ps2dev;
794 unsigned char param[1];
795
796/*
797 * Set the LEDs to a predefined state (all off).
798 */
799
800 param[0] = 0;
801 if (ps2_command(ps2dev, param, ATKBD_CMD_SETLEDS))
802 return -1;
803
804/*
805 * Set autorepeat to fastest possible.
806 */
807
808 param[0] = 0;
809 if (ps2_command(ps2dev, param, ATKBD_CMD_SETREP))
810 return -1;
811
812 return 0;
813}
814
Linus Torvalds1da177e2005-04-16 15:20:36 -0700815static int atkbd_activate(struct atkbd *atkbd)
816{
817 struct ps2dev *ps2dev = &atkbd->ps2dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700818
819/*
820 * Enable the keyboard to receive keystrokes.
821 */
822
823 if (ps2_command(ps2dev, NULL, ATKBD_CMD_ENABLE)) {
Dmitry Torokhova9a1f9c2010-01-06 23:51:47 -0800824 dev_err(&ps2dev->serio->dev,
825 "Failed to enable keyboard on %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700826 ps2dev->serio->phys);
827 return -1;
828 }
829
830 return 0;
831}
832
833/*
834 * atkbd_cleanup() restores the keyboard state so that BIOS is happy after a
835 * reboot.
836 */
837
838static void atkbd_cleanup(struct serio *serio)
839{
840 struct atkbd *atkbd = serio_get_drvdata(serio);
Dmitry Torokhov57f5b152008-05-28 00:54:01 -0400841
842 atkbd_disable(atkbd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700843 ps2_command(&atkbd->ps2dev, NULL, ATKBD_CMD_RESET_BAT);
844}
845
846
847/*
848 * atkbd_disconnect() closes and frees.
849 */
850
851static void atkbd_disconnect(struct serio *serio)
852{
853 struct atkbd *atkbd = serio_get_drvdata(serio);
854
855 atkbd_disable(atkbd);
856
857 /* make sure we don't have a command in flight */
Jiri Pirkod6d79a72008-11-11 09:43:21 -0500858 cancel_delayed_work_sync(&atkbd->event_work);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700859
Dmitry Torokhov86255d92006-10-11 01:44:46 -0400860 sysfs_remove_group(&serio->dev.kobj, &atkbd_attribute_group);
Dmitry Torokhov3c42f0c2005-09-15 02:01:45 -0500861 input_unregister_device(atkbd->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700862 serio_close(serio);
863 serio_set_drvdata(serio, NULL);
864 kfree(atkbd);
865}
866
Giel de Nijs554101e2007-11-02 09:08:02 -0400867/*
Daniel Mierswa39191692009-03-04 23:27:15 -0800868 * generate release events for the keycodes given in data
869 */
870static void atkbd_apply_forced_release_keylist(struct atkbd* atkbd,
871 const void *data)
872{
873 const unsigned int *keys = data;
874 unsigned int i;
875
876 if (atkbd->set == 2)
877 for (i = 0; keys[i] != -1U; i++)
878 __set_bit(keys[i], atkbd->force_release_mask);
879}
880
881/*
Matthew Garrett61579ba2008-08-15 13:54:51 -0400882 * Most special keys (Fn+F?) on Dell laptops do not generate release
Giel de Nijs554101e2007-11-02 09:08:02 -0400883 * events so we have to do it ourselves.
884 */
Daniel Mierswa39191692009-03-04 23:27:15 -0800885static unsigned int atkbd_dell_laptop_forced_release_keys[] = {
886 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8f, 0x93, -1U
887};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700888
889/*
Jiri Kosina5a54c012008-06-26 10:46:38 -0400890 * Perform fixup for HP system that doesn't generate release
891 * for its video switch
892 */
Daniel Mierswa39191692009-03-04 23:27:15 -0800893static unsigned int atkbd_hp_forced_release_keys[] = {
894 0x94, -1U
895};
Jiri Kosina5a54c012008-06-26 10:46:38 -0400896
897/*
Barry Carrolle04126c2009-04-14 10:38:34 -0700898 * Samsung NC10,NC20 with Fn+F? key release not working
Stuart Hopkins42008442008-12-20 04:12:33 -0500899 */
Daniel Mierswa39191692009-03-04 23:27:15 -0800900static unsigned int atkbd_samsung_forced_release_keys[] = {
901 0x82, 0x83, 0x84, 0x86, 0x88, 0x89, 0xb3, 0xf7, 0xf9, -1U
902};
Stuart Hopkins42008442008-12-20 04:12:33 -0500903
904/*
Simon Davief0a14de2009-07-12 20:44:09 -0700905 * Amilo Pi 3525 key release for Fn+Volume keys not working
906 */
907static unsigned int atkbd_amilo_pi3525_forced_release_keys[] = {
908 0x20, 0xa0, 0x2e, 0xae, 0x30, 0xb0, -1U
909};
910
911/*
Adrian Batzill9166d0f2009-05-11 15:22:16 -0700912 * Amilo Xi 3650 key release for light touch bar not working
913 */
914static unsigned int atkbd_amilo_xi3650_forced_release_keys[] = {
915 0x67, 0xed, 0x90, 0xa2, 0x99, 0xa4, 0xae, 0xb0, -1U
916};
917
918/*
Jerone Young032e46c2009-07-20 22:14:59 -0700919 * Soltech TA12 system with broken key release on volume keys and mute key
920 */
921static unsigned int atkdb_soltech_ta12_forced_release_keys[] = {
922 0xa0, 0xae, 0xb0, -1U
923};
924
925/*
Herton Ronaldo Krzesinski000c2a32009-10-16 16:13:59 -0700926 * Many notebooks don't send key release event for volume up/down
927 * keys, with key list below common among them
928 */
929static unsigned int atkbd_volume_forced_release_keys[] = {
930 0xae, 0xb0, -1U
931};
932
933/*
Jamie Lentine5713062009-10-20 14:36:49 -0700934 * OQO 01+ multimedia keys (64--66) generate e0 6x upon release whereas
935 * they should be generating e4-e6 (0x80 | code).
936 */
937static unsigned int atkbd_oqo_01plus_scancode_fixup(struct atkbd *atkbd,
938 unsigned int code)
939{
940 if (atkbd->translated && atkbd->emul == 1 &&
941 (code == 0x64 || code == 0x65 || code == 0x66)) {
942 atkbd->emul = 0;
943 code |= 0x80;
944 }
945
946 return code;
947}
948
949/*
Dmitry Torokhov3c42f0c2005-09-15 02:01:45 -0500950 * atkbd_set_keycode_table() initializes keyboard's keycode table
Linus Torvalds1da177e2005-04-16 15:20:36 -0700951 * according to the selected scancode set
952 */
953
954static void atkbd_set_keycode_table(struct atkbd *atkbd)
955{
Giel de Nijs554101e2007-11-02 09:08:02 -0400956 unsigned int scancode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700957 int i, j;
958
959 memset(atkbd->keycode, 0, sizeof(atkbd->keycode));
Dmitry Torokhov1ba36e12009-09-03 17:22:04 -0700960 bitmap_zero(atkbd->force_release_mask, ATKBD_KEYMAP_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700961
962 if (atkbd->translated) {
963 for (i = 0; i < 128; i++) {
Giel de Nijs554101e2007-11-02 09:08:02 -0400964 scancode = atkbd_unxlate_table[i];
965 atkbd->keycode[i] = atkbd_set2_keycode[scancode];
966 atkbd->keycode[i | 0x80] = atkbd_set2_keycode[scancode | 0x80];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700967 if (atkbd->scroll)
968 for (j = 0; j < ARRAY_SIZE(atkbd_scroll_keys); j++)
Giel de Nijs554101e2007-11-02 09:08:02 -0400969 if ((scancode | 0x80) == atkbd_scroll_keys[j].set2)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700970 atkbd->keycode[i | 0x80] = atkbd_scroll_keys[j].keycode;
971 }
972 } else if (atkbd->set == 3) {
973 memcpy(atkbd->keycode, atkbd_set3_keycode, sizeof(atkbd->keycode));
974 } else {
975 memcpy(atkbd->keycode, atkbd_set2_keycode, sizeof(atkbd->keycode));
976
977 if (atkbd->scroll)
Giel de Nijs554101e2007-11-02 09:08:02 -0400978 for (i = 0; i < ARRAY_SIZE(atkbd_scroll_keys); i++) {
979 scancode = atkbd_scroll_keys[i].set2;
980 atkbd->keycode[scancode] = atkbd_scroll_keys[i].keycode;
981 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700982 }
Dmitry Torokhov0ae051a2006-06-26 01:52:34 -0400983
Giel de Nijs554101e2007-11-02 09:08:02 -0400984/*
985 * HANGEUL and HANJA keys do not send release events so we need to
986 * generate such events ourselves
987 */
988 scancode = atkbd_compat_scancode(atkbd, ATKBD_RET_HANGEUL);
989 atkbd->keycode[scancode] = KEY_HANGEUL;
990 __set_bit(scancode, atkbd->force_release_mask);
991
992 scancode = atkbd_compat_scancode(atkbd, ATKBD_RET_HANJA);
993 atkbd->keycode[scancode] = KEY_HANJA;
994 __set_bit(scancode, atkbd->force_release_mask);
995
996/*
997 * Perform additional fixups
998 */
999 if (atkbd_platform_fixup)
Daniel Mierswa39191692009-03-04 23:27:15 -08001000 atkbd_platform_fixup(atkbd, atkbd_platform_fixup_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001001}
1002
1003/*
1004 * atkbd_set_device_attrs() sets up keyboard's input device structure
1005 */
1006
1007static void atkbd_set_device_attrs(struct atkbd *atkbd)
1008{
Dmitry Torokhov3c42f0c2005-09-15 02:01:45 -05001009 struct input_dev *input_dev = atkbd->dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001010 int i;
1011
Dmitry Torokhov3c42f0c2005-09-15 02:01:45 -05001012 if (atkbd->extra)
Dmitry Torokhovea08c6f2006-06-26 01:46:17 -04001013 snprintf(atkbd->name, sizeof(atkbd->name),
1014 "AT Set 2 Extra keyboard");
Dmitry Torokhov3c42f0c2005-09-15 02:01:45 -05001015 else
Dmitry Torokhovea08c6f2006-06-26 01:46:17 -04001016 snprintf(atkbd->name, sizeof(atkbd->name),
1017 "AT %s Set %d keyboard",
1018 atkbd->translated ? "Translated" : "Raw", atkbd->set);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001019
Dmitry Torokhovea08c6f2006-06-26 01:46:17 -04001020 snprintf(atkbd->phys, sizeof(atkbd->phys),
1021 "%s/input0", atkbd->ps2dev.serio->phys);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001022
Dmitry Torokhov3c42f0c2005-09-15 02:01:45 -05001023 input_dev->name = atkbd->name;
1024 input_dev->phys = atkbd->phys;
1025 input_dev->id.bustype = BUS_I8042;
1026 input_dev->id.vendor = 0x0001;
1027 input_dev->id.product = atkbd->translated ? 1 : atkbd->set;
1028 input_dev->id.version = atkbd->id;
1029 input_dev->event = atkbd_event;
Dmitry Torokhov469ba4d2007-04-12 01:34:58 -04001030 input_dev->dev.parent = &atkbd->ps2dev.serio->dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001031
Dmitry Torokhovb3568722007-04-12 01:34:20 -04001032 input_set_drvdata(input_dev, atkbd);
1033
Jiri Slaby7b19ada2007-10-18 23:40:32 -07001034 input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP) |
1035 BIT_MASK(EV_MSC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001036
1037 if (atkbd->write) {
Jiri Slaby7b19ada2007-10-18 23:40:32 -07001038 input_dev->evbit[0] |= BIT_MASK(EV_LED);
1039 input_dev->ledbit[0] = BIT_MASK(LED_NUML) |
1040 BIT_MASK(LED_CAPSL) | BIT_MASK(LED_SCROLLL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001041 }
1042
1043 if (atkbd->extra)
Jiri Slaby7b19ada2007-10-18 23:40:32 -07001044 input_dev->ledbit[0] |= BIT_MASK(LED_COMPOSE) |
1045 BIT_MASK(LED_SUSPEND) | BIT_MASK(LED_SLEEP) |
1046 BIT_MASK(LED_MUTE) | BIT_MASK(LED_MISC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001047
1048 if (!atkbd->softrepeat) {
Dmitry Torokhov3c42f0c2005-09-15 02:01:45 -05001049 input_dev->rep[REP_DELAY] = 250;
1050 input_dev->rep[REP_PERIOD] = 33;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001051 }
1052
Jiri Slaby7b19ada2007-10-18 23:40:32 -07001053 input_dev->mscbit[0] = atkbd->softraw ? BIT_MASK(MSC_SCAN) :
1054 BIT_MASK(MSC_RAW) | BIT_MASK(MSC_SCAN);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001055
1056 if (atkbd->scroll) {
Jiri Slaby7b19ada2007-10-18 23:40:32 -07001057 input_dev->evbit[0] |= BIT_MASK(EV_REL);
1058 input_dev->relbit[0] = BIT_MASK(REL_WHEEL) |
1059 BIT_MASK(REL_HWHEEL);
Dmitry Torokhovf6d65612008-06-02 00:39:45 -04001060 __set_bit(BTN_MIDDLE, input_dev->keybit);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001061 }
1062
Dmitry Torokhov3c42f0c2005-09-15 02:01:45 -05001063 input_dev->keycode = atkbd->keycode;
Dmitry Torokhovf6d65612008-06-02 00:39:45 -04001064 input_dev->keycodesize = sizeof(unsigned short);
Dmitry Torokhov3c42f0c2005-09-15 02:01:45 -05001065 input_dev->keycodemax = ARRAY_SIZE(atkbd_set2_keycode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001066
Dmitry Torokhov1ba36e12009-09-03 17:22:04 -07001067 for (i = 0; i < ATKBD_KEYMAP_SIZE; i++)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001068 if (atkbd->keycode[i] && atkbd->keycode[i] < ATKBD_SPECIAL)
Dmitry Torokhovf6d65612008-06-02 00:39:45 -04001069 __set_bit(atkbd->keycode[i], input_dev->keybit);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001070}
1071
1072/*
1073 * atkbd_connect() is called when the serio module finds an interface
1074 * that isn't handled yet by an appropriate device driver. We check if
1075 * there is an AT keyboard out there and if yes, we register ourselves
1076 * to the input module.
1077 */
1078
1079static int atkbd_connect(struct serio *serio, struct serio_driver *drv)
1080{
1081 struct atkbd *atkbd;
Dmitry Torokhov3c42f0c2005-09-15 02:01:45 -05001082 struct input_dev *dev;
1083 int err = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001084
Dmitry Torokhov3c42f0c2005-09-15 02:01:45 -05001085 atkbd = kzalloc(sizeof(struct atkbd), GFP_KERNEL);
1086 dev = input_allocate_device();
1087 if (!atkbd || !dev)
Dmitry Torokhov2b03b602006-11-05 22:39:56 -05001088 goto fail1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001089
Dmitry Torokhov3c42f0c2005-09-15 02:01:45 -05001090 atkbd->dev = dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001091 ps2_init(&atkbd->ps2dev, serio);
Dmitry Torokhovda4249c2007-06-28 00:46:56 -04001092 INIT_DELAYED_WORK(&atkbd->event_work, atkbd_event_work);
Ingo Molnar33d3f072006-02-19 00:22:18 -05001093 mutex_init(&atkbd->event_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001094
1095 switch (serio->id.type) {
1096
Dmitry Torokhova9a1f9c2010-01-06 23:51:47 -08001097 case SERIO_8042_XL:
1098 atkbd->translated = true;
1099 /* Fall through */
1100
1101 case SERIO_8042:
1102 if (serio->write)
1103 atkbd->write = true;
1104 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001105 }
1106
1107 atkbd->softraw = atkbd_softraw;
1108 atkbd->softrepeat = atkbd_softrepeat;
1109 atkbd->scroll = atkbd_scroll;
1110
Linus Torvalds1da177e2005-04-16 15:20:36 -07001111 if (atkbd->softrepeat)
Dmitry Torokhova9a1f9c2010-01-06 23:51:47 -08001112 atkbd->softraw = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001113
1114 serio_set_drvdata(serio, atkbd);
1115
1116 err = serio_open(serio, drv);
Dmitry Torokhov3c42f0c2005-09-15 02:01:45 -05001117 if (err)
Dmitry Torokhov2b03b602006-11-05 22:39:56 -05001118 goto fail2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001119
1120 if (atkbd->write) {
1121
1122 if (atkbd_probe(atkbd)) {
Dmitry Torokhov3c42f0c2005-09-15 02:01:45 -05001123 err = -ENODEV;
Dmitry Torokhov2b03b602006-11-05 22:39:56 -05001124 goto fail3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001125 }
1126
1127 atkbd->set = atkbd_select_set(atkbd, atkbd_set, atkbd_extra);
Dmitry Torokhovfc0eb282009-10-12 22:47:25 -07001128 atkbd_reset_state(atkbd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001129 atkbd_activate(atkbd);
1130
1131 } else {
1132 atkbd->set = 2;
1133 atkbd->id = 0xab00;
1134 }
1135
Linus Torvalds1da177e2005-04-16 15:20:36 -07001136 atkbd_set_keycode_table(atkbd);
1137 atkbd_set_device_attrs(atkbd);
1138
Dmitry Torokhov2b03b602006-11-05 22:39:56 -05001139 err = sysfs_create_group(&serio->dev.kobj, &atkbd_attribute_group);
1140 if (err)
1141 goto fail3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001142
1143 atkbd_enable(atkbd);
1144
Dmitry Torokhov2b03b602006-11-05 22:39:56 -05001145 err = input_register_device(atkbd->dev);
1146 if (err)
1147 goto fail4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001148
1149 return 0;
Dmitry Torokhov3c42f0c2005-09-15 02:01:45 -05001150
Dmitry Torokhov2b03b602006-11-05 22:39:56 -05001151 fail4: sysfs_remove_group(&serio->dev.kobj, &atkbd_attribute_group);
1152 fail3: serio_close(serio);
1153 fail2: serio_set_drvdata(serio, NULL);
1154 fail1: input_free_device(dev);
Dmitry Torokhov3c42f0c2005-09-15 02:01:45 -05001155 kfree(atkbd);
1156 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001157}
1158
1159/*
1160 * atkbd_reconnect() tries to restore keyboard into a sane state and is
1161 * most likely called on resume.
1162 */
1163
1164static int atkbd_reconnect(struct serio *serio)
1165{
1166 struct atkbd *atkbd = serio_get_drvdata(serio);
1167 struct serio_driver *drv = serio->drv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001168
1169 if (!atkbd || !drv) {
Dmitry Torokhova9a1f9c2010-01-06 23:51:47 -08001170 dev_dbg(&serio->dev,
1171 "reconnect request, but serio is disconnected, ignoring...\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001172 return -1;
1173 }
1174
1175 atkbd_disable(atkbd);
1176
1177 if (atkbd->write) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001178 if (atkbd_probe(atkbd))
1179 return -1;
1180 if (atkbd->set != atkbd_select_set(atkbd, atkbd->set, atkbd->extra))
1181 return -1;
1182
1183 atkbd_activate(atkbd);
Dmitry Torokhovd4119bd2009-11-12 23:19:05 -08001184
1185 /*
1186 * Restore LED state and repeat rate. While input core
1187 * will do this for us at resume time reconnect may happen
1188 * because user requested it via sysfs or simply because
1189 * keyboard was unplugged and plugged in again so we need
1190 * to do it ourselves here.
1191 */
1192 atkbd_set_leds(atkbd);
1193 if (!atkbd->softrepeat)
1194 atkbd_set_repeat_rate(atkbd);
1195
Linus Torvalds1da177e2005-04-16 15:20:36 -07001196 }
1197
1198 atkbd_enable(atkbd);
1199
1200 return 0;
1201}
1202
1203static struct serio_device_id atkbd_serio_ids[] = {
1204 {
1205 .type = SERIO_8042,
1206 .proto = SERIO_ANY,
1207 .id = SERIO_ANY,
1208 .extra = SERIO_ANY,
1209 },
1210 {
1211 .type = SERIO_8042_XL,
1212 .proto = SERIO_ANY,
1213 .id = SERIO_ANY,
1214 .extra = SERIO_ANY,
1215 },
1216 {
1217 .type = SERIO_RS232,
1218 .proto = SERIO_PS2SER,
1219 .id = SERIO_ANY,
1220 .extra = SERIO_ANY,
1221 },
1222 { 0 }
1223};
1224
1225MODULE_DEVICE_TABLE(serio, atkbd_serio_ids);
1226
1227static struct serio_driver atkbd_drv = {
1228 .driver = {
1229 .name = "atkbd",
1230 },
1231 .description = DRIVER_DESC,
1232 .id_table = atkbd_serio_ids,
1233 .interrupt = atkbd_interrupt,
1234 .connect = atkbd_connect,
1235 .reconnect = atkbd_reconnect,
1236 .disconnect = atkbd_disconnect,
1237 .cleanup = atkbd_cleanup,
1238};
1239
1240static ssize_t atkbd_attr_show_helper(struct device *dev, char *buf,
1241 ssize_t (*handler)(struct atkbd *, char *))
1242{
1243 struct serio *serio = to_serio_port(dev);
1244 int retval;
1245
1246 retval = serio_pin_driver(serio);
1247 if (retval)
1248 return retval;
1249
1250 if (serio->drv != &atkbd_drv) {
1251 retval = -ENODEV;
1252 goto out;
1253 }
1254
1255 retval = handler((struct atkbd *)serio_get_drvdata(serio), buf);
1256
1257out:
1258 serio_unpin_driver(serio);
1259 return retval;
1260}
1261
1262static ssize_t atkbd_attr_set_helper(struct device *dev, const char *buf, size_t count,
1263 ssize_t (*handler)(struct atkbd *, const char *, size_t))
1264{
1265 struct serio *serio = to_serio_port(dev);
1266 struct atkbd *atkbd;
1267 int retval;
1268
1269 retval = serio_pin_driver(serio);
1270 if (retval)
1271 return retval;
1272
1273 if (serio->drv != &atkbd_drv) {
1274 retval = -ENODEV;
1275 goto out;
1276 }
1277
1278 atkbd = serio_get_drvdata(serio);
1279 atkbd_disable(atkbd);
1280 retval = handler(atkbd, buf, count);
1281 atkbd_enable(atkbd);
1282
1283out:
1284 serio_unpin_driver(serio);
1285 return retval;
1286}
1287
1288static ssize_t atkbd_show_extra(struct atkbd *atkbd, char *buf)
1289{
1290 return sprintf(buf, "%d\n", atkbd->extra ? 1 : 0);
1291}
1292
1293static ssize_t atkbd_set_extra(struct atkbd *atkbd, const char *buf, size_t count)
1294{
Dmitry Torokhov2b03b602006-11-05 22:39:56 -05001295 struct input_dev *old_dev, *new_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001296 unsigned long value;
Dmitry Torokhov2b03b602006-11-05 22:39:56 -05001297 int err;
Dmitry Torokhova9a1f9c2010-01-06 23:51:47 -08001298 bool old_extra;
1299 unsigned char old_set;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001300
1301 if (!atkbd->write)
1302 return -EIO;
1303
Joe Rouvier160f1fe2008-08-10 00:29:25 -04001304 if (strict_strtoul(buf, 10, &value) || value > 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001305 return -EINVAL;
1306
1307 if (atkbd->extra != value) {
Dmitry Torokhov3c42f0c2005-09-15 02:01:45 -05001308 /*
1309 * Since device's properties will change we need to
Dmitry Torokhov2b03b602006-11-05 22:39:56 -05001310 * unregister old device. But allocate and register
1311 * new one first to make sure we have it.
Dmitry Torokhov3c42f0c2005-09-15 02:01:45 -05001312 */
Dmitry Torokhov2b03b602006-11-05 22:39:56 -05001313 old_dev = atkbd->dev;
1314 old_extra = atkbd->extra;
1315 old_set = atkbd->set;
1316
1317 new_dev = input_allocate_device();
1318 if (!new_dev)
Dmitry Torokhov3c42f0c2005-09-15 02:01:45 -05001319 return -ENOMEM;
Dmitry Torokhov2b03b602006-11-05 22:39:56 -05001320
Dmitry Torokhov3c42f0c2005-09-15 02:01:45 -05001321 atkbd->dev = new_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001322 atkbd->set = atkbd_select_set(atkbd, atkbd->set, value);
Dmitry Torokhovfc0eb282009-10-12 22:47:25 -07001323 atkbd_reset_state(atkbd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001324 atkbd_activate(atkbd);
Dmitry Torokhov2b03b602006-11-05 22:39:56 -05001325 atkbd_set_keycode_table(atkbd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001326 atkbd_set_device_attrs(atkbd);
Dmitry Torokhov2b03b602006-11-05 22:39:56 -05001327
1328 err = input_register_device(atkbd->dev);
1329 if (err) {
1330 input_free_device(new_dev);
1331
1332 atkbd->dev = old_dev;
1333 atkbd->set = atkbd_select_set(atkbd, old_set, old_extra);
1334 atkbd_set_keycode_table(atkbd);
1335 atkbd_set_device_attrs(atkbd);
1336
1337 return err;
1338 }
1339 input_unregister_device(old_dev);
1340
Linus Torvalds1da177e2005-04-16 15:20:36 -07001341 }
1342 return count;
1343}
1344
Dmitry Torokhov1ba36e12009-09-03 17:22:04 -07001345static ssize_t atkbd_show_force_release(struct atkbd *atkbd, char *buf)
1346{
1347 size_t len = bitmap_scnlistprintf(buf, PAGE_SIZE - 2,
1348 atkbd->force_release_mask, ATKBD_KEYMAP_SIZE);
1349
1350 buf[len++] = '\n';
1351 buf[len] = '\0';
1352
1353 return len;
1354}
1355
1356static ssize_t atkbd_set_force_release(struct atkbd *atkbd,
1357 const char *buf, size_t count)
1358{
1359 /* 64 bytes on stack should be acceptable */
1360 DECLARE_BITMAP(new_mask, ATKBD_KEYMAP_SIZE);
1361 int err;
1362
1363 err = bitmap_parselist(buf, new_mask, ATKBD_KEYMAP_SIZE);
1364 if (err)
1365 return err;
1366
1367 memcpy(atkbd->force_release_mask, new_mask, sizeof(atkbd->force_release_mask));
1368 return count;
1369}
1370
1371
Linus Torvalds1da177e2005-04-16 15:20:36 -07001372static ssize_t atkbd_show_scroll(struct atkbd *atkbd, char *buf)
1373{
1374 return sprintf(buf, "%d\n", atkbd->scroll ? 1 : 0);
1375}
1376
1377static ssize_t atkbd_set_scroll(struct atkbd *atkbd, const char *buf, size_t count)
1378{
Dmitry Torokhov2b03b602006-11-05 22:39:56 -05001379 struct input_dev *old_dev, *new_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001380 unsigned long value;
Dmitry Torokhov2b03b602006-11-05 22:39:56 -05001381 int err;
Dmitry Torokhova9a1f9c2010-01-06 23:51:47 -08001382 bool old_scroll;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001383
Joe Rouvier160f1fe2008-08-10 00:29:25 -04001384 if (strict_strtoul(buf, 10, &value) || value > 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001385 return -EINVAL;
1386
1387 if (atkbd->scroll != value) {
Dmitry Torokhov2b03b602006-11-05 22:39:56 -05001388 old_dev = atkbd->dev;
1389 old_scroll = atkbd->scroll;
1390
1391 new_dev = input_allocate_device();
1392 if (!new_dev)
Dmitry Torokhov3c42f0c2005-09-15 02:01:45 -05001393 return -ENOMEM;
Dmitry Torokhov2b03b602006-11-05 22:39:56 -05001394
Dmitry Torokhov3c42f0c2005-09-15 02:01:45 -05001395 atkbd->dev = new_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001396 atkbd->scroll = value;
1397 atkbd_set_keycode_table(atkbd);
1398 atkbd_set_device_attrs(atkbd);
Dmitry Torokhov2b03b602006-11-05 22:39:56 -05001399
1400 err = input_register_device(atkbd->dev);
1401 if (err) {
1402 input_free_device(new_dev);
1403
1404 atkbd->scroll = old_scroll;
1405 atkbd->dev = old_dev;
1406 atkbd_set_keycode_table(atkbd);
1407 atkbd_set_device_attrs(atkbd);
1408
1409 return err;
1410 }
1411 input_unregister_device(old_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001412 }
1413 return count;
1414}
1415
1416static ssize_t atkbd_show_set(struct atkbd *atkbd, char *buf)
1417{
1418 return sprintf(buf, "%d\n", atkbd->set);
1419}
1420
1421static ssize_t atkbd_set_set(struct atkbd *atkbd, const char *buf, size_t count)
1422{
Dmitry Torokhov2b03b602006-11-05 22:39:56 -05001423 struct input_dev *old_dev, *new_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001424 unsigned long value;
Dmitry Torokhov2b03b602006-11-05 22:39:56 -05001425 int err;
Dmitry Torokhova9a1f9c2010-01-06 23:51:47 -08001426 unsigned char old_set;
1427 bool old_extra;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001428
1429 if (!atkbd->write)
1430 return -EIO;
1431
Joe Rouvier160f1fe2008-08-10 00:29:25 -04001432 if (strict_strtoul(buf, 10, &value) || (value != 2 && value != 3))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001433 return -EINVAL;
1434
1435 if (atkbd->set != value) {
Dmitry Torokhov2b03b602006-11-05 22:39:56 -05001436 old_dev = atkbd->dev;
1437 old_extra = atkbd->extra;
1438 old_set = atkbd->set;
1439
1440 new_dev = input_allocate_device();
1441 if (!new_dev)
Dmitry Torokhov3c42f0c2005-09-15 02:01:45 -05001442 return -ENOMEM;
Dmitry Torokhov2b03b602006-11-05 22:39:56 -05001443
Dmitry Torokhov3c42f0c2005-09-15 02:01:45 -05001444 atkbd->dev = new_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001445 atkbd->set = atkbd_select_set(atkbd, value, atkbd->extra);
Dmitry Torokhovd4119bd2009-11-12 23:19:05 -08001446 atkbd_reset_state(atkbd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001447 atkbd_activate(atkbd);
1448 atkbd_set_keycode_table(atkbd);
1449 atkbd_set_device_attrs(atkbd);
Dmitry Torokhov2b03b602006-11-05 22:39:56 -05001450
1451 err = input_register_device(atkbd->dev);
1452 if (err) {
1453 input_free_device(new_dev);
1454
1455 atkbd->dev = old_dev;
1456 atkbd->set = atkbd_select_set(atkbd, old_set, old_extra);
1457 atkbd_set_keycode_table(atkbd);
1458 atkbd_set_device_attrs(atkbd);
1459
1460 return err;
1461 }
1462 input_unregister_device(old_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001463 }
1464 return count;
1465}
1466
1467static ssize_t atkbd_show_softrepeat(struct atkbd *atkbd, char *buf)
1468{
1469 return sprintf(buf, "%d\n", atkbd->softrepeat ? 1 : 0);
1470}
1471
1472static ssize_t atkbd_set_softrepeat(struct atkbd *atkbd, const char *buf, size_t count)
1473{
Dmitry Torokhov2b03b602006-11-05 22:39:56 -05001474 struct input_dev *old_dev, *new_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001475 unsigned long value;
Dmitry Torokhov2b03b602006-11-05 22:39:56 -05001476 int err;
Dmitry Torokhova9a1f9c2010-01-06 23:51:47 -08001477 bool old_softrepeat, old_softraw;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001478
1479 if (!atkbd->write)
1480 return -EIO;
1481
Joe Rouvier160f1fe2008-08-10 00:29:25 -04001482 if (strict_strtoul(buf, 10, &value) || value > 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001483 return -EINVAL;
1484
1485 if (atkbd->softrepeat != value) {
Dmitry Torokhov2b03b602006-11-05 22:39:56 -05001486 old_dev = atkbd->dev;
1487 old_softrepeat = atkbd->softrepeat;
1488 old_softraw = atkbd->softraw;
1489
1490 new_dev = input_allocate_device();
1491 if (!new_dev)
Dmitry Torokhov3c42f0c2005-09-15 02:01:45 -05001492 return -ENOMEM;
Dmitry Torokhov2b03b602006-11-05 22:39:56 -05001493
Dmitry Torokhov3c42f0c2005-09-15 02:01:45 -05001494 atkbd->dev = new_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001495 atkbd->softrepeat = value;
1496 if (atkbd->softrepeat)
Dmitry Torokhova9a1f9c2010-01-06 23:51:47 -08001497 atkbd->softraw = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001498 atkbd_set_device_attrs(atkbd);
Dmitry Torokhov2b03b602006-11-05 22:39:56 -05001499
1500 err = input_register_device(atkbd->dev);
1501 if (err) {
1502 input_free_device(new_dev);
1503
1504 atkbd->dev = old_dev;
1505 atkbd->softrepeat = old_softrepeat;
1506 atkbd->softraw = old_softraw;
1507 atkbd_set_device_attrs(atkbd);
1508
1509 return err;
1510 }
1511 input_unregister_device(old_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001512 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001513 return count;
1514}
1515
1516
1517static ssize_t atkbd_show_softraw(struct atkbd *atkbd, char *buf)
1518{
1519 return sprintf(buf, "%d\n", atkbd->softraw ? 1 : 0);
1520}
1521
1522static ssize_t atkbd_set_softraw(struct atkbd *atkbd, const char *buf, size_t count)
1523{
Dmitry Torokhov2b03b602006-11-05 22:39:56 -05001524 struct input_dev *old_dev, *new_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001525 unsigned long value;
Dmitry Torokhov2b03b602006-11-05 22:39:56 -05001526 int err;
Dmitry Torokhova9a1f9c2010-01-06 23:51:47 -08001527 bool old_softraw;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001528
Joe Rouvier160f1fe2008-08-10 00:29:25 -04001529 if (strict_strtoul(buf, 10, &value) || value > 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001530 return -EINVAL;
1531
1532 if (atkbd->softraw != value) {
Dmitry Torokhov2b03b602006-11-05 22:39:56 -05001533 old_dev = atkbd->dev;
1534 old_softraw = atkbd->softraw;
1535
1536 new_dev = input_allocate_device();
1537 if (!new_dev)
Dmitry Torokhov3c42f0c2005-09-15 02:01:45 -05001538 return -ENOMEM;
Dmitry Torokhov2b03b602006-11-05 22:39:56 -05001539
Dmitry Torokhov3c42f0c2005-09-15 02:01:45 -05001540 atkbd->dev = new_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001541 atkbd->softraw = value;
1542 atkbd_set_device_attrs(atkbd);
Dmitry Torokhov2b03b602006-11-05 22:39:56 -05001543
1544 err = input_register_device(atkbd->dev);
1545 if (err) {
1546 input_free_device(new_dev);
1547
1548 atkbd->dev = old_dev;
1549 atkbd->softraw = old_softraw;
1550 atkbd_set_device_attrs(atkbd);
1551
1552 return err;
1553 }
1554 input_unregister_device(old_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001555 }
1556 return count;
1557}
1558
Dmitry Torokhov86255d92006-10-11 01:44:46 -04001559static ssize_t atkbd_show_err_count(struct atkbd *atkbd, char *buf)
1560{
1561 return sprintf(buf, "%lu\n", atkbd->err_count);
1562}
1563
Daniel Mierswa39191692009-03-04 23:27:15 -08001564static int __init atkbd_setup_forced_release(const struct dmi_system_id *id)
Giel de Nijs554101e2007-11-02 09:08:02 -04001565{
Daniel Mierswa39191692009-03-04 23:27:15 -08001566 atkbd_platform_fixup = atkbd_apply_forced_release_keylist;
1567 atkbd_platform_fixup_data = id->driver_data;
1568
Giel de Nijs554101e2007-11-02 09:08:02 -04001569 return 0;
1570}
1571
Jamie Lentine5713062009-10-20 14:36:49 -07001572static int __init atkbd_setup_scancode_fixup(const struct dmi_system_id *id)
1573{
1574 atkbd_platform_scancode_fixup = id->driver_data;
1575
1576 return 0;
1577}
1578
Dmitry Torokhovc45fc812009-12-04 10:24:19 -08001579static const struct dmi_system_id atkbd_dmi_quirk_table[] __initconst = {
Giel de Nijs554101e2007-11-02 09:08:02 -04001580 {
Giel de Nijs554101e2007-11-02 09:08:02 -04001581 .matches = {
1582 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
Matthew Garrett61579ba2008-08-15 13:54:51 -04001583 DMI_MATCH(DMI_CHASSIS_TYPE, "8"), /* Portable */
Giel de Nijs554101e2007-11-02 09:08:02 -04001584 },
Daniel Mierswa39191692009-03-04 23:27:15 -08001585 .callback = atkbd_setup_forced_release,
1586 .driver_data = atkbd_dell_laptop_forced_release_keys,
Giel de Nijs554101e2007-11-02 09:08:02 -04001587 },
Jiri Kosina5a54c012008-06-26 10:46:38 -04001588 {
Matthew Garrett2a3ec322008-12-30 00:43:11 -08001589 .matches = {
1590 DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"),
1591 DMI_MATCH(DMI_CHASSIS_TYPE, "8"), /* Portable */
1592 },
Daniel Mierswa39191692009-03-04 23:27:15 -08001593 .callback = atkbd_setup_forced_release,
1594 .driver_data = atkbd_dell_laptop_forced_release_keys,
Matthew Garrett2a3ec322008-12-30 00:43:11 -08001595 },
1596 {
Jiri Kosina5a54c012008-06-26 10:46:38 -04001597 .matches = {
1598 DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
1599 DMI_MATCH(DMI_PRODUCT_NAME, "HP 2133"),
1600 },
Daniel Mierswa39191692009-03-04 23:27:15 -08001601 .callback = atkbd_setup_forced_release,
1602 .driver_data = atkbd_hp_forced_release_keys,
Jiri Kosina5a54c012008-06-26 10:46:38 -04001603 },
Matthew Garretta8215b82008-11-11 09:40:42 -05001604 {
Rikard Ljungstrand181f6382008-12-19 21:59:20 -05001605 .matches = {
1606 DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
1607 DMI_MATCH(DMI_PRODUCT_NAME, "Pavilion ZV6100"),
1608 },
Daniel Mierswa39191692009-03-04 23:27:15 -08001609 .callback = atkbd_setup_forced_release,
Herton Ronaldo Krzesinski000c2a32009-10-16 16:13:59 -07001610 .driver_data = atkbd_volume_forced_release_keys,
Rikard Ljungstrand181f6382008-12-19 21:59:20 -05001611 },
1612 {
Dave Andrews2bcaa6a2009-09-03 17:21:27 -07001613 .matches = {
1614 DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
1615 DMI_MATCH(DMI_PRODUCT_NAME, "Presario R4000"),
1616 },
1617 .callback = atkbd_setup_forced_release,
Herton Ronaldo Krzesinski000c2a32009-10-16 16:13:59 -07001618 .driver_data = atkbd_volume_forced_release_keys,
Dave Andrews2bcaa6a2009-09-03 17:21:27 -07001619 },
1620 {
Dave Andrews2bcaa6a2009-09-03 17:21:27 -07001621 .matches = {
1622 DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
1623 DMI_MATCH(DMI_PRODUCT_NAME, "Presario R4100"),
1624 },
1625 .callback = atkbd_setup_forced_release,
Herton Ronaldo Krzesinski000c2a32009-10-16 16:13:59 -07001626 .driver_data = atkbd_volume_forced_release_keys,
Dave Andrews2bcaa6a2009-09-03 17:21:27 -07001627 },
1628 {
Dave Andrews2bcaa6a2009-09-03 17:21:27 -07001629 .matches = {
1630 DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
1631 DMI_MATCH(DMI_PRODUCT_NAME, "Presario R4200"),
1632 },
1633 .callback = atkbd_setup_forced_release,
Herton Ronaldo Krzesinski000c2a32009-10-16 16:13:59 -07001634 .driver_data = atkbd_volume_forced_release_keys,
Dave Andrews2bcaa6a2009-09-03 17:21:27 -07001635 },
1636 {
Dmitry Torokhovc45fc812009-12-04 10:24:19 -08001637 /* Inventec Symphony */
Matthew Garretta8215b82008-11-11 09:40:42 -05001638 .matches = {
1639 DMI_MATCH(DMI_SYS_VENDOR, "INVENTEC"),
1640 DMI_MATCH(DMI_PRODUCT_NAME, "SYMPHONY 6.0/7.0"),
1641 },
Daniel Mierswa39191692009-03-04 23:27:15 -08001642 .callback = atkbd_setup_forced_release,
Herton Ronaldo Krzesinski000c2a32009-10-16 16:13:59 -07001643 .driver_data = atkbd_volume_forced_release_keys,
Matthew Garretta8215b82008-11-11 09:40:42 -05001644 },
Stuart Hopkins42008442008-12-20 04:12:33 -05001645 {
Dmitry Torokhovc45fc812009-12-04 10:24:19 -08001646 /* Samsung NC10 */
Stuart Hopkins42008442008-12-20 04:12:33 -05001647 .matches = {
1648 DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
1649 DMI_MATCH(DMI_PRODUCT_NAME, "NC10"),
1650 },
Daniel Mierswa39191692009-03-04 23:27:15 -08001651 .callback = atkbd_setup_forced_release,
1652 .driver_data = atkbd_samsung_forced_release_keys,
Stuart Hopkins42008442008-12-20 04:12:33 -05001653 },
Daniel Mierswaadcb5232009-03-04 23:27:15 -08001654 {
Dmitry Torokhovc45fc812009-12-04 10:24:19 -08001655 /* Samsung NC20 */
Barry Carrolle04126c2009-04-14 10:38:34 -07001656 .matches = {
1657 DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
1658 DMI_MATCH(DMI_PRODUCT_NAME, "NC20"),
1659 },
1660 .callback = atkbd_setup_forced_release,
1661 .driver_data = atkbd_samsung_forced_release_keys,
1662 },
1663 {
Dmitry Torokhovc45fc812009-12-04 10:24:19 -08001664 /* Samsung SQ45S70S */
Dmitry Torokhov157f3a32009-04-13 15:27:50 -07001665 .matches = {
1666 DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
1667 DMI_MATCH(DMI_PRODUCT_NAME, "SQ45S70S"),
1668 },
1669 .callback = atkbd_setup_forced_release,
1670 .driver_data = atkbd_samsung_forced_release_keys,
1671 },
1672 {
Dmitry Torokhovc45fc812009-12-04 10:24:19 -08001673 /* Fujitsu Amilo PA 1510 */
Daniel Mierswaadcb5232009-03-04 23:27:15 -08001674 .matches = {
1675 DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
1676 DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Pa 1510"),
1677 },
1678 .callback = atkbd_setup_forced_release,
Herton Ronaldo Krzesinski000c2a32009-10-16 16:13:59 -07001679 .driver_data = atkbd_volume_forced_release_keys,
Daniel Mierswaadcb5232009-03-04 23:27:15 -08001680 },
Adrian Batzill9166d0f2009-05-11 15:22:16 -07001681 {
Dmitry Torokhovc45fc812009-12-04 10:24:19 -08001682 /* Fujitsu Amilo Pi 3525 */
Simon Davief0a14de2009-07-12 20:44:09 -07001683 .matches = {
1684 DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
1685 DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Pi 3525"),
1686 },
1687 .callback = atkbd_setup_forced_release,
1688 .driver_data = atkbd_amilo_pi3525_forced_release_keys,
1689 },
1690 {
Dmitry Torokhovc45fc812009-12-04 10:24:19 -08001691 /* Fujitsu Amilo Xi 3650 */
Adrian Batzill9166d0f2009-05-11 15:22:16 -07001692 .matches = {
1693 DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
1694 DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Xi 3650"),
1695 },
1696 .callback = atkbd_setup_forced_release,
1697 .driver_data = atkbd_amilo_xi3650_forced_release_keys,
1698 },
Jerone Young032e46c2009-07-20 22:14:59 -07001699 {
Jerone Young032e46c2009-07-20 22:14:59 -07001700 .matches = {
1701 DMI_MATCH(DMI_SYS_VENDOR, "Soltech Corporation"),
1702 DMI_MATCH(DMI_PRODUCT_NAME, "TA12"),
1703 },
1704 .callback = atkbd_setup_forced_release,
1705 .driver_data = atkdb_soltech_ta12_forced_release_keys,
1706 },
Jamie Lentine5713062009-10-20 14:36:49 -07001707 {
Dmitry Torokhovc45fc812009-12-04 10:24:19 -08001708 /* OQO Model 01+ */
Jamie Lentine5713062009-10-20 14:36:49 -07001709 .matches = {
1710 DMI_MATCH(DMI_SYS_VENDOR, "OQO"),
1711 DMI_MATCH(DMI_PRODUCT_NAME, "ZEPTO"),
1712 },
1713 .callback = atkbd_setup_scancode_fixup,
1714 .driver_data = atkbd_oqo_01plus_scancode_fixup,
1715 },
Giel de Nijs554101e2007-11-02 09:08:02 -04001716 { }
1717};
Linus Torvalds1da177e2005-04-16 15:20:36 -07001718
1719static int __init atkbd_init(void)
1720{
Giel de Nijs554101e2007-11-02 09:08:02 -04001721 dmi_check_system(atkbd_dmi_quirk_table);
1722
Akinobu Mita153a9df02006-11-23 23:35:10 -05001723 return serio_register_driver(&atkbd_drv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001724}
1725
1726static void __exit atkbd_exit(void)
1727{
1728 serio_unregister_driver(&atkbd_drv);
1729}
1730
1731module_init(atkbd_init);
1732module_exit(atkbd_exit);