blob: b45981870c7a6e31ce9bfcfdd6cecaa1051155b2 [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>
22#include <linux/moduleparam.h>
23#include <linux/slab.h>
24#include <linux/interrupt.h>
25#include <linux/init.h>
26#include <linux/input.h>
27#include <linux/serio.h>
28#include <linux/workqueue.h>
29#include <linux/libps2.h>
Ingo Molnar33d3f072006-02-19 00:22:18 -050030#include <linux/mutex.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__)
43static int atkbd_reset;
44#else
45static int atkbd_reset = 1;
46#endif
47module_param_named(reset, atkbd_reset, bool, 0);
48MODULE_PARM_DESC(reset, "Reset keyboard during initialization");
49
50static int atkbd_softrepeat;
51module_param_named(softrepeat, atkbd_softrepeat, bool, 0);
52MODULE_PARM_DESC(softrepeat, "Use software keyboard repeat");
53
54static int atkbd_softraw = 1;
55module_param_named(softraw, atkbd_softraw, bool, 0);
56MODULE_PARM_DESC(softraw, "Use software generated rawmode");
57
Vojtech Pavlika86d1f42005-06-07 13:22:14 -070058static int atkbd_scroll = 0;
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
62static int atkbd_extra;
63module_param_named(extra, atkbd_extra, bool, 0);
64MODULE_PARM_DESC(extra, "Enable extra LEDs and keys on IBM RapidAcces, EzKey and similar keyboards");
65
66__obsolete_setup("atkbd_set=");
67__obsolete_setup("atkbd_reset");
68__obsolete_setup("atkbd_softrepeat=");
69
70/*
71 * Scancode to keycode tables. These are just the default setting, and
72 * are loadable via an userland utility.
73 */
74
75static unsigned char atkbd_set2_keycode[512] = {
76
77#ifdef CONFIG_KEYBOARD_ATKBD_HP_KEYCODES
78
79/* XXX: need a more general approach */
80
81#include "hpps2atkbd.h" /* include the keyboard scancodes */
82
83#else
84 0, 67, 65, 63, 61, 59, 60, 88, 0, 68, 66, 64, 62, 15, 41,117,
85 0, 56, 42, 93, 29, 16, 2, 0, 0, 0, 44, 31, 30, 17, 3, 0,
86 0, 46, 45, 32, 18, 5, 4, 95, 0, 57, 47, 33, 20, 19, 6,183,
87 0, 49, 48, 35, 34, 21, 7,184, 0, 0, 50, 36, 22, 8, 9,185,
88 0, 51, 37, 23, 24, 11, 10, 0, 0, 52, 53, 38, 39, 25, 12, 0,
89 0, 89, 40, 0, 26, 13, 0, 0, 58, 54, 28, 27, 0, 43, 0, 85,
90 0, 86, 91, 90, 92, 0, 14, 94, 0, 79,124, 75, 71,121, 0, 0,
91 82, 83, 80, 76, 77, 72, 1, 69, 87, 78, 81, 74, 55, 73, 70, 99,
92
93 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
94 217,100,255, 0, 97,165, 0, 0,156, 0, 0, 0, 0, 0, 0,125,
95 173,114, 0,113, 0, 0, 0,126,128, 0, 0,140, 0, 0, 0,127,
96 159, 0,115, 0,164, 0, 0,116,158, 0,150,166, 0, 0, 0,142,
97 157, 0, 0, 0, 0, 0, 0, 0,155, 0, 98, 0, 0,163, 0, 0,
98 226, 0, 0, 0, 0, 0, 0, 0, 0,255, 96, 0, 0, 0,143, 0,
99 0, 0, 0, 0, 0, 0, 0, 0, 0,107, 0,105,102, 0, 0,112,
100 110,111,108,112,106,103, 0,119, 0,118,109, 0, 99,104,119, 0,
101
102 0, 0, 0, 65, 99,
103#endif
104};
105
106static unsigned char atkbd_set3_keycode[512] = {
107
108 0, 0, 0, 0, 0, 0, 0, 59, 1,138,128,129,130, 15, 41, 60,
109 131, 29, 42, 86, 58, 16, 2, 61,133, 56, 44, 31, 30, 17, 3, 62,
110 134, 46, 45, 32, 18, 5, 4, 63,135, 57, 47, 33, 20, 19, 6, 64,
111 136, 49, 48, 35, 34, 21, 7, 65,137,100, 50, 36, 22, 8, 9, 66,
112 125, 51, 37, 23, 24, 11, 10, 67,126, 52, 53, 38, 39, 25, 12, 68,
113 113,114, 40, 43, 26, 13, 87, 99, 97, 54, 28, 27, 43, 43, 88, 70,
114 108,105,119,103,111,107, 14,110, 0, 79,106, 75, 71,109,102,104,
115 82, 83, 80, 76, 77, 72, 69, 98, 0, 96, 81, 0, 78, 73, 55,183,
116
117 184,185,186,187, 74, 94, 92, 93, 0, 0, 0,125,126,127,112, 0,
118 0,139,150,163,165,115,152,150,166,140,160,154,113,114,167,168,
119 148,149,147,140
120};
121
122static unsigned char atkbd_unxlate_table[128] = {
123 0,118, 22, 30, 38, 37, 46, 54, 61, 62, 70, 69, 78, 85,102, 13,
124 21, 29, 36, 45, 44, 53, 60, 67, 68, 77, 84, 91, 90, 20, 28, 27,
125 35, 43, 52, 51, 59, 66, 75, 76, 82, 14, 18, 93, 26, 34, 33, 42,
126 50, 49, 58, 65, 73, 74, 89,124, 17, 41, 88, 5, 6, 4, 12, 3,
127 11, 2, 10, 1, 9,119,126,108,117,125,123,107,115,116,121,105,
128 114,122,112,113,127, 96, 97,120, 7, 15, 23, 31, 39, 47, 55, 63,
129 71, 79, 86, 94, 8, 16, 24, 32, 40, 48, 56, 64, 72, 80, 87,111,
130 19, 25, 57, 81, 83, 92, 95, 98, 99,100,101,103,104,106,109,110
131};
132
133#define ATKBD_CMD_SETLEDS 0x10ed
134#define ATKBD_CMD_GSCANSET 0x11f0
135#define ATKBD_CMD_SSCANSET 0x10f0
136#define ATKBD_CMD_GETID 0x02f2
137#define ATKBD_CMD_SETREP 0x10f3
138#define ATKBD_CMD_ENABLE 0x00f4
139#define ATKBD_CMD_RESET_DIS 0x00f5
140#define ATKBD_CMD_SETALL_MBR 0x00fa
141#define ATKBD_CMD_RESET_BAT 0x02ff
142#define ATKBD_CMD_RESEND 0x00fe
143#define ATKBD_CMD_EX_ENABLE 0x10ea
144#define ATKBD_CMD_EX_SETLEDS 0x20eb
145#define ATKBD_CMD_OK_GETID 0x02e8
146
147#define ATKBD_RET_ACK 0xfa
148#define ATKBD_RET_NAK 0xfe
149#define ATKBD_RET_BAT 0xaa
150#define ATKBD_RET_EMUL0 0xe0
151#define ATKBD_RET_EMUL1 0xe1
152#define ATKBD_RET_RELEASE 0xf0
153#define ATKBD_RET_HANGUEL 0xf1
154#define ATKBD_RET_HANJA 0xf2
155#define ATKBD_RET_ERR 0xff
156
157#define ATKBD_KEY_UNKNOWN 0
158#define ATKBD_KEY_NULL 255
159
160#define ATKBD_SCR_1 254
161#define ATKBD_SCR_2 253
162#define ATKBD_SCR_4 252
163#define ATKBD_SCR_8 251
164#define ATKBD_SCR_CLICK 250
165#define ATKBD_SCR_LEFT 249
166#define ATKBD_SCR_RIGHT 248
167
168#define ATKBD_SPECIAL 248
169
Dmitry Torokhov0d4c8592005-11-20 00:49:42 -0500170#define ATKBD_LED_EVENT_BIT 0
171#define ATKBD_REP_EVENT_BIT 1
172
Linus Torvalds1da177e2005-04-16 15:20:36 -0700173static struct {
174 unsigned char keycode;
175 unsigned char set2;
176} atkbd_scroll_keys[] = {
177 { ATKBD_SCR_1, 0xc5 },
Vojtech Pavlik5212dd52005-05-28 15:51:47 -0700178 { ATKBD_SCR_2, 0x9d },
179 { ATKBD_SCR_4, 0xa4 },
180 { ATKBD_SCR_8, 0x9b },
Linus Torvalds1da177e2005-04-16 15:20:36 -0700181 { ATKBD_SCR_CLICK, 0xe0 },
182 { ATKBD_SCR_LEFT, 0xcb },
183 { ATKBD_SCR_RIGHT, 0xd2 },
184};
185
186/*
187 * The atkbd control structure
188 */
189
190struct atkbd {
191
Dmitry Torokhov3c42f0c2005-09-15 02:01:45 -0500192 struct ps2dev ps2dev;
193 struct input_dev *dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700194
195 /* Written only during init */
196 char name[64];
197 char phys[32];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700198
199 unsigned short id;
200 unsigned char keycode[512];
201 unsigned char set;
202 unsigned char translated;
203 unsigned char extra;
204 unsigned char write;
205 unsigned char softrepeat;
206 unsigned char softraw;
207 unsigned char scroll;
208 unsigned char enabled;
209
210 /* Accessed only from interrupt */
211 unsigned char emul;
212 unsigned char resend;
213 unsigned char release;
214 unsigned char bat_xl;
Vojtech Pavlik903b1262005-09-05 00:11:41 -0500215 unsigned char err_xl;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700216 unsigned int last;
217 unsigned long time;
Dmitry Torokhov0d4c8592005-11-20 00:49:42 -0500218
219 struct work_struct event_work;
Ingo Molnar33d3f072006-02-19 00:22:18 -0500220 struct mutex event_mutex;
Dmitry Torokhov0d4c8592005-11-20 00:49:42 -0500221 unsigned long event_mask;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700222};
223
224static ssize_t atkbd_attr_show_helper(struct device *dev, char *buf,
225 ssize_t (*handler)(struct atkbd *, char *));
226static ssize_t atkbd_attr_set_helper(struct device *dev, const char *buf, size_t count,
227 ssize_t (*handler)(struct atkbd *, const char *, size_t));
228#define ATKBD_DEFINE_ATTR(_name) \
229static ssize_t atkbd_show_##_name(struct atkbd *, char *); \
230static ssize_t atkbd_set_##_name(struct atkbd *, const char *, size_t); \
Yani Ioannoue404e272005-05-17 06:42:58 -0400231static ssize_t atkbd_do_show_##_name(struct device *d, struct device_attribute *attr, char *b) \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700232{ \
233 return atkbd_attr_show_helper(d, b, atkbd_show_##_name); \
234} \
Yani Ioannoue404e272005-05-17 06:42:58 -0400235static ssize_t atkbd_do_set_##_name(struct device *d, struct device_attribute *attr, const char *b, size_t s) \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700236{ \
237 return atkbd_attr_set_helper(d, b, s, atkbd_set_##_name); \
238} \
Dmitry Torokhovd083e902005-05-29 02:28:42 -0500239static struct device_attribute atkbd_attr_##_name = \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700240 __ATTR(_name, S_IWUSR | S_IRUGO, atkbd_do_show_##_name, atkbd_do_set_##_name);
241
242ATKBD_DEFINE_ATTR(extra);
243ATKBD_DEFINE_ATTR(scroll);
244ATKBD_DEFINE_ATTR(set);
245ATKBD_DEFINE_ATTR(softrepeat);
246ATKBD_DEFINE_ATTR(softraw);
247
248
249static void atkbd_report_key(struct input_dev *dev, struct pt_regs *regs, int code, int value)
250{
251 input_regs(dev, regs);
252 if (value == 3) {
253 input_report_key(dev, code, 1);
254 input_sync(dev);
255 input_report_key(dev, code, 0);
256 } else
257 input_event(dev, EV_KEY, code, value);
258 input_sync(dev);
259}
260
261/*
262 * atkbd_interrupt(). Here takes place processing of data received from
263 * the keyboard into events.
264 */
265
266static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data,
267 unsigned int flags, struct pt_regs *regs)
268{
269 struct atkbd *atkbd = serio_get_drvdata(serio);
270 unsigned int code = data;
271 int scroll = 0, hscroll = 0, click = -1;
272 int value;
273
274#ifdef ATKBD_DEBUG
275 printk(KERN_DEBUG "atkbd.c: Received %02x flags %02x\n", data, flags);
276#endif
277
278#if !defined(__i386__) && !defined (__x86_64__)
279 if ((flags & (SERIO_FRAME | SERIO_PARITY)) && (~flags & SERIO_TIMEOUT) && !atkbd->resend && atkbd->write) {
280 printk(KERN_WARNING "atkbd.c: frame/parity error: %02x\n", flags);
281 serio_write(serio, ATKBD_CMD_RESEND);
282 atkbd->resend = 1;
283 goto out;
284 }
285
286 if (!flags && data == ATKBD_RET_ACK)
287 atkbd->resend = 0;
288#endif
289
290 if (unlikely(atkbd->ps2dev.flags & PS2_FLAG_ACK))
291 if (ps2_handle_ack(&atkbd->ps2dev, data))
292 goto out;
293
294 if (unlikely(atkbd->ps2dev.flags & PS2_FLAG_CMD))
295 if (ps2_handle_response(&atkbd->ps2dev, data))
296 goto out;
297
298 if (!atkbd->enabled)
299 goto out;
300
Dmitry Torokhov3c42f0c2005-09-15 02:01:45 -0500301 input_event(atkbd->dev, EV_MSC, MSC_RAW, code);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700302
303 if (atkbd->translated) {
304
305 if (atkbd->emul ||
306 !(code == ATKBD_RET_EMUL0 || code == ATKBD_RET_EMUL1 ||
307 code == ATKBD_RET_HANGUEL || code == ATKBD_RET_HANJA ||
Vojtech Pavlik903b1262005-09-05 00:11:41 -0500308 (code == ATKBD_RET_ERR && !atkbd->err_xl) ||
Linus Torvalds1da177e2005-04-16 15:20:36 -0700309 (code == ATKBD_RET_BAT && !atkbd->bat_xl))) {
310 atkbd->release = code >> 7;
311 code &= 0x7f;
312 }
313
Vojtech Pavlik903b1262005-09-05 00:11:41 -0500314 if (!atkbd->emul) {
315 if ((code & 0x7f) == (ATKBD_RET_BAT & 0x7f))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700316 atkbd->bat_xl = !atkbd->release;
Vojtech Pavlik903b1262005-09-05 00:11:41 -0500317 if ((code & 0x7f) == (ATKBD_RET_ERR & 0x7f))
318 atkbd->err_xl = !atkbd->release;
319 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700320 }
321
322 switch (code) {
323 case ATKBD_RET_BAT:
324 atkbd->enabled = 0;
Dmitry Torokhovdbc26342006-01-05 23:00:13 -0500325 serio_reconnect(atkbd->ps2dev.serio);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700326 goto out;
327 case ATKBD_RET_EMUL0:
328 atkbd->emul = 1;
329 goto out;
330 case ATKBD_RET_EMUL1:
331 atkbd->emul = 2;
332 goto out;
333 case ATKBD_RET_RELEASE:
334 atkbd->release = 1;
335 goto out;
336 case ATKBD_RET_HANGUEL:
Dmitry Torokhov3c42f0c2005-09-15 02:01:45 -0500337 atkbd_report_key(atkbd->dev, regs, KEY_HANGUEL, 3);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700338 goto out;
339 case ATKBD_RET_HANJA:
Dmitry Torokhov3c42f0c2005-09-15 02:01:45 -0500340 atkbd_report_key(atkbd->dev, regs, KEY_HANJA, 3);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700341 goto out;
342 case ATKBD_RET_ERR:
343 printk(KERN_DEBUG "atkbd.c: Keyboard on %s reports too many keys pressed.\n", serio->phys);
344 goto out;
345 }
346
347 if (atkbd->set != 3)
348 code = (code & 0x7f) | ((code & 0x80) << 1);
349 if (atkbd->emul) {
350 if (--atkbd->emul)
351 goto out;
352 code |= (atkbd->set != 3) ? 0x80 : 0x100;
353 }
354
355 if (atkbd->keycode[code] != ATKBD_KEY_NULL)
Dmitry Torokhov3c42f0c2005-09-15 02:01:45 -0500356 input_event(atkbd->dev, EV_MSC, MSC_SCAN, code);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700357
358 switch (atkbd->keycode[code]) {
359 case ATKBD_KEY_NULL:
360 break;
361 case ATKBD_KEY_UNKNOWN:
362 if (data == ATKBD_RET_ACK || data == ATKBD_RET_NAK) {
363 printk(KERN_WARNING "atkbd.c: Spurious %s on %s. Some program, "
364 "like XFree86, might be trying access hardware directly.\n",
365 data == ATKBD_RET_ACK ? "ACK" : "NAK", serio->phys);
366 } else {
367 printk(KERN_WARNING "atkbd.c: Unknown key %s "
368 "(%s set %d, code %#x on %s).\n",
369 atkbd->release ? "released" : "pressed",
370 atkbd->translated ? "translated" : "raw",
371 atkbd->set, code, serio->phys);
372 printk(KERN_WARNING "atkbd.c: Use 'setkeycodes %s%02x <keycode>' "
373 "to make it known.\n",
374 code & 0x80 ? "e0" : "", code & 0x7f);
375 }
Dmitry Torokhov3c42f0c2005-09-15 02:01:45 -0500376 input_sync(atkbd->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700377 break;
378 case ATKBD_SCR_1:
379 scroll = 1 - atkbd->release * 2;
380 break;
381 case ATKBD_SCR_2:
382 scroll = 2 - atkbd->release * 4;
383 break;
384 case ATKBD_SCR_4:
385 scroll = 4 - atkbd->release * 8;
386 break;
387 case ATKBD_SCR_8:
388 scroll = 8 - atkbd->release * 16;
389 break;
390 case ATKBD_SCR_CLICK:
391 click = !atkbd->release;
392 break;
393 case ATKBD_SCR_LEFT:
394 hscroll = -1;
395 break;
396 case ATKBD_SCR_RIGHT:
397 hscroll = 1;
398 break;
399 default:
400 value = atkbd->release ? 0 :
Dmitry Torokhov3c42f0c2005-09-15 02:01:45 -0500401 (1 + (!atkbd->softrepeat && test_bit(atkbd->keycode[code], atkbd->dev->key)));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700402
Dmitry Torokhovd083e902005-05-29 02:28:42 -0500403 switch (value) { /* Workaround Toshiba laptop multiple keypress */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700404 case 0:
405 atkbd->last = 0;
406 break;
407 case 1:
408 atkbd->last = code;
Dmitry Torokhov3c42f0c2005-09-15 02:01:45 -0500409 atkbd->time = jiffies + msecs_to_jiffies(atkbd->dev->rep[REP_DELAY]) / 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700410 break;
411 case 2:
412 if (!time_after(jiffies, atkbd->time) && atkbd->last == code)
413 value = 1;
414 break;
415 }
416
Dmitry Torokhov3c42f0c2005-09-15 02:01:45 -0500417 atkbd_report_key(atkbd->dev, regs, atkbd->keycode[code], value);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700418 }
419
420 if (atkbd->scroll) {
Dmitry Torokhov3c42f0c2005-09-15 02:01:45 -0500421 input_regs(atkbd->dev, regs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700422 if (click != -1)
Dmitry Torokhov3c42f0c2005-09-15 02:01:45 -0500423 input_report_key(atkbd->dev, BTN_MIDDLE, click);
424 input_report_rel(atkbd->dev, REL_WHEEL, scroll);
425 input_report_rel(atkbd->dev, REL_HWHEEL, hscroll);
426 input_sync(atkbd->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700427 }
428
429 atkbd->release = 0;
430out:
431 return IRQ_HANDLED;
432}
433
434/*
Dmitry Torokhov0d4c8592005-11-20 00:49:42 -0500435 * atkbd_event_work() is used to complete processing of events that
436 * can not be processed by input_event() which is often called from
437 * interrupt context.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700438 */
439
Dmitry Torokhov0d4c8592005-11-20 00:49:42 -0500440static void atkbd_event_work(void *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700441{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700442 const short period[32] =
443 { 33, 37, 42, 46, 50, 54, 58, 63, 67, 75, 83, 92, 100, 109, 116, 125,
444 133, 149, 167, 182, 200, 217, 232, 250, 270, 303, 333, 370, 400, 435, 470, 500 };
445 const short delay[4] =
446 { 250, 500, 750, 1000 };
Dmitry Torokhov0d4c8592005-11-20 00:49:42 -0500447
448 struct atkbd *atkbd = data;
449 struct input_dev *dev = atkbd->dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700450 unsigned char param[2];
451 int i, j;
452
Ingo Molnar33d3f072006-02-19 00:22:18 -0500453 mutex_lock(&atkbd->event_mutex);
Dmitry Torokhov0d4c8592005-11-20 00:49:42 -0500454
455 if (test_and_clear_bit(ATKBD_LED_EVENT_BIT, &atkbd->event_mask)) {
456 param[0] = (test_bit(LED_SCROLLL, dev->led) ? 1 : 0)
457 | (test_bit(LED_NUML, dev->led) ? 2 : 0)
458 | (test_bit(LED_CAPSL, dev->led) ? 4 : 0);
459 ps2_command(&atkbd->ps2dev, param, ATKBD_CMD_SETLEDS);
460
461 if (atkbd->extra) {
462 param[0] = 0;
463 param[1] = (test_bit(LED_COMPOSE, dev->led) ? 0x01 : 0)
464 | (test_bit(LED_SLEEP, dev->led) ? 0x02 : 0)
465 | (test_bit(LED_SUSPEND, dev->led) ? 0x04 : 0)
466 | (test_bit(LED_MISC, dev->led) ? 0x10 : 0)
467 | (test_bit(LED_MUTE, dev->led) ? 0x20 : 0);
468 ps2_command(&atkbd->ps2dev, param, ATKBD_CMD_EX_SETLEDS);
469 }
470 }
471
472 if (test_and_clear_bit(ATKBD_REP_EVENT_BIT, &atkbd->event_mask)) {
473 i = j = 0;
474 while (i < 31 && period[i] < dev->rep[REP_PERIOD])
475 i++;
476 while (j < 3 && delay[j] < dev->rep[REP_DELAY])
477 j++;
478 dev->rep[REP_PERIOD] = period[i];
479 dev->rep[REP_DELAY] = delay[j];
480 param[0] = i | (j << 5);
481 ps2_command(&atkbd->ps2dev, param, ATKBD_CMD_SETREP);
482 }
483
Ingo Molnar33d3f072006-02-19 00:22:18 -0500484 mutex_unlock(&atkbd->event_mutex);
Dmitry Torokhov0d4c8592005-11-20 00:49:42 -0500485}
486
487/*
488 * Event callback from the input module. Events that change the state of
489 * the hardware are processed here. If action can not be performed in
490 * interrupt context it is offloaded to atkbd_event_work.
491 */
492
493static int atkbd_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
494{
495 struct atkbd *atkbd = dev->private;
496
Linus Torvalds1da177e2005-04-16 15:20:36 -0700497 if (!atkbd->write)
498 return -1;
499
500 switch (type) {
501
502 case EV_LED:
Dmitry Torokhov0d4c8592005-11-20 00:49:42 -0500503 set_bit(ATKBD_LED_EVENT_BIT, &atkbd->event_mask);
504 wmb();
505 schedule_work(&atkbd->event_work);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700506 return 0;
507
Linus Torvalds1da177e2005-04-16 15:20:36 -0700508 case EV_REP:
509
Dmitry Torokhov0d4c8592005-11-20 00:49:42 -0500510 if (!atkbd->softrepeat) {
511 set_bit(ATKBD_REP_EVENT_BIT, &atkbd->event_mask);
512 wmb();
513 schedule_work(&atkbd->event_work);
514 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700515
516 return 0;
517 }
518
519 return -1;
520}
521
522/*
523 * atkbd_enable() signals that interrupt handler is allowed to
524 * generate input events.
525 */
526
527static inline void atkbd_enable(struct atkbd *atkbd)
528{
529 serio_pause_rx(atkbd->ps2dev.serio);
530 atkbd->enabled = 1;
531 serio_continue_rx(atkbd->ps2dev.serio);
532}
533
534/*
535 * atkbd_disable() tells input handler that all incoming data except
536 * for ACKs and command response should be dropped.
537 */
538
539static inline void atkbd_disable(struct atkbd *atkbd)
540{
541 serio_pause_rx(atkbd->ps2dev.serio);
542 atkbd->enabled = 0;
543 serio_continue_rx(atkbd->ps2dev.serio);
544}
545
546/*
547 * atkbd_probe() probes for an AT keyboard on a serio port.
548 */
549
550static int atkbd_probe(struct atkbd *atkbd)
551{
552 struct ps2dev *ps2dev = &atkbd->ps2dev;
553 unsigned char param[2];
554
555/*
556 * Some systems, where the bit-twiddling when testing the io-lines of the
557 * controller may confuse the keyboard need a full reset of the keyboard. On
558 * these systems the BIOS also usually doesn't do it for us.
559 */
560
561 if (atkbd_reset)
562 if (ps2_command(ps2dev, NULL, ATKBD_CMD_RESET_BAT))
563 printk(KERN_WARNING "atkbd.c: keyboard reset failed on %s\n", ps2dev->serio->phys);
564
565/*
566 * Then we check the keyboard ID. We should get 0xab83 under normal conditions.
567 * Some keyboards report different values, but the first byte is always 0xab or
568 * 0xac. Some old AT keyboards don't report anything. If a mouse is connected, this
569 * should make sure we don't try to set the LEDs on it.
570 */
571
572 param[0] = param[1] = 0xa5; /* initialize with invalid values */
573 if (ps2_command(ps2dev, param, ATKBD_CMD_GETID)) {
574
575/*
576 * If the get ID command failed, we check if we can at least set the LEDs on
577 * the keyboard. This should work on every keyboard out there. It also turns
578 * the LEDs off, which we want anyway.
579 */
580 param[0] = 0;
581 if (ps2_command(ps2dev, param, ATKBD_CMD_SETLEDS))
582 return -1;
583 atkbd->id = 0xabba;
584 return 0;
585 }
586
587 if (param[0] != 0xab && param[0] != 0xac && /* Regular and NCD Sun keyboards */
588 param[0] != 0x2b && param[0] != 0x5d && /* Trust keyboard, raw and translated */
589 param[0] != 0x60 && param[0] != 0x47) /* NMB SGI keyboard, raw and translated */
590 return -1;
591
592 atkbd->id = (param[0] << 8) | param[1];
593
594 if (atkbd->id == 0xaca1 && atkbd->translated) {
595 printk(KERN_ERR "atkbd.c: NCD terminal keyboards are only supported on non-translating\n");
596 printk(KERN_ERR "atkbd.c: controllers. Use i8042.direct=1 to disable translation.\n");
597 return -1;
598 }
599
600 return 0;
601}
602
603/*
604 * atkbd_select_set checks if a keyboard has a working Set 3 support, and
605 * sets it into that. Unfortunately there are keyboards that can be switched
606 * to Set 3, but don't work well in that (BTC Multimedia ...)
607 */
608
609static int atkbd_select_set(struct atkbd *atkbd, int target_set, int allow_extra)
610{
611 struct ps2dev *ps2dev = &atkbd->ps2dev;
612 unsigned char param[2];
613
614 atkbd->extra = 0;
615/*
616 * For known special keyboards we can go ahead and set the correct set.
617 * We check for NCD PS/2 Sun, NorthGate OmniKey 101 and
618 * IBM RapidAccess / IBM EzButton / Chicony KBP-8993 keyboards.
619 */
620
621 if (atkbd->translated)
622 return 2;
623
624 if (atkbd->id == 0xaca1) {
625 param[0] = 3;
626 ps2_command(ps2dev, param, ATKBD_CMD_SSCANSET);
627 return 3;
628 }
629
630 if (allow_extra) {
631 param[0] = 0x71;
632 if (!ps2_command(ps2dev, param, ATKBD_CMD_EX_ENABLE)) {
633 atkbd->extra = 1;
634 return 2;
635 }
636 }
637
638 if (target_set != 3)
639 return 2;
640
641 if (!ps2_command(ps2dev, param, ATKBD_CMD_OK_GETID)) {
642 atkbd->id = param[0] << 8 | param[1];
643 return 2;
644 }
645
646 param[0] = 3;
647 if (ps2_command(ps2dev, param, ATKBD_CMD_SSCANSET))
648 return 2;
649
650 param[0] = 0;
651 if (ps2_command(ps2dev, param, ATKBD_CMD_GSCANSET))
652 return 2;
653
654 if (param[0] != 3) {
655 param[0] = 2;
656 if (ps2_command(ps2dev, param, ATKBD_CMD_SSCANSET))
657 return 2;
658 }
659
660 ps2_command(ps2dev, param, ATKBD_CMD_SETALL_MBR);
661
662 return 3;
663}
664
665static int atkbd_activate(struct atkbd *atkbd)
666{
667 struct ps2dev *ps2dev = &atkbd->ps2dev;
668 unsigned char param[1];
669
670/*
671 * Set the LEDs to a defined state.
672 */
673
674 param[0] = 0;
675 if (ps2_command(ps2dev, param, ATKBD_CMD_SETLEDS))
676 return -1;
677
678/*
679 * Set autorepeat to fastest possible.
680 */
681
682 param[0] = 0;
683 if (ps2_command(ps2dev, param, ATKBD_CMD_SETREP))
684 return -1;
685
686/*
687 * Enable the keyboard to receive keystrokes.
688 */
689
690 if (ps2_command(ps2dev, NULL, ATKBD_CMD_ENABLE)) {
691 printk(KERN_ERR "atkbd.c: Failed to enable keyboard on %s\n",
692 ps2dev->serio->phys);
693 return -1;
694 }
695
696 return 0;
697}
698
699/*
700 * atkbd_cleanup() restores the keyboard state so that BIOS is happy after a
701 * reboot.
702 */
703
704static void atkbd_cleanup(struct serio *serio)
705{
706 struct atkbd *atkbd = serio_get_drvdata(serio);
707 ps2_command(&atkbd->ps2dev, NULL, ATKBD_CMD_RESET_BAT);
708}
709
710
711/*
712 * atkbd_disconnect() closes and frees.
713 */
714
715static void atkbd_disconnect(struct serio *serio)
716{
717 struct atkbd *atkbd = serio_get_drvdata(serio);
718
719 atkbd_disable(atkbd);
720
721 /* make sure we don't have a command in flight */
Paul E. McKenneyfbd568a3e2005-05-01 08:59:04 -0700722 synchronize_sched(); /* Allow atkbd_interrupt()s to complete. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700723 flush_scheduled_work();
724
725 device_remove_file(&serio->dev, &atkbd_attr_extra);
726 device_remove_file(&serio->dev, &atkbd_attr_scroll);
727 device_remove_file(&serio->dev, &atkbd_attr_set);
728 device_remove_file(&serio->dev, &atkbd_attr_softrepeat);
729 device_remove_file(&serio->dev, &atkbd_attr_softraw);
730
Dmitry Torokhov3c42f0c2005-09-15 02:01:45 -0500731 input_unregister_device(atkbd->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700732 serio_close(serio);
733 serio_set_drvdata(serio, NULL);
734 kfree(atkbd);
735}
736
737
738/*
Dmitry Torokhov3c42f0c2005-09-15 02:01:45 -0500739 * atkbd_set_keycode_table() initializes keyboard's keycode table
Linus Torvalds1da177e2005-04-16 15:20:36 -0700740 * according to the selected scancode set
741 */
742
743static void atkbd_set_keycode_table(struct atkbd *atkbd)
744{
745 int i, j;
746
747 memset(atkbd->keycode, 0, sizeof(atkbd->keycode));
748
749 if (atkbd->translated) {
750 for (i = 0; i < 128; i++) {
751 atkbd->keycode[i] = atkbd_set2_keycode[atkbd_unxlate_table[i]];
752 atkbd->keycode[i | 0x80] = atkbd_set2_keycode[atkbd_unxlate_table[i] | 0x80];
753 if (atkbd->scroll)
754 for (j = 0; j < ARRAY_SIZE(atkbd_scroll_keys); j++)
755 if ((atkbd_unxlate_table[i] | 0x80) == atkbd_scroll_keys[j].set2)
756 atkbd->keycode[i | 0x80] = atkbd_scroll_keys[j].keycode;
757 }
758 } else if (atkbd->set == 3) {
759 memcpy(atkbd->keycode, atkbd_set3_keycode, sizeof(atkbd->keycode));
760 } else {
761 memcpy(atkbd->keycode, atkbd_set2_keycode, sizeof(atkbd->keycode));
762
763 if (atkbd->scroll)
764 for (i = 0; i < ARRAY_SIZE(atkbd_scroll_keys); i++)
765 atkbd->keycode[atkbd_scroll_keys[i].set2] = atkbd_scroll_keys[i].keycode;
766 }
767}
768
769/*
770 * atkbd_set_device_attrs() sets up keyboard's input device structure
771 */
772
773static void atkbd_set_device_attrs(struct atkbd *atkbd)
774{
Dmitry Torokhov3c42f0c2005-09-15 02:01:45 -0500775 struct input_dev *input_dev = atkbd->dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700776 int i;
777
Dmitry Torokhov3c42f0c2005-09-15 02:01:45 -0500778 if (atkbd->extra)
779 sprintf(atkbd->name, "AT Set 2 Extra keyboard");
780 else
781 sprintf(atkbd->name, "AT %s Set %d keyboard",
782 atkbd->translated ? "Translated" : "Raw", atkbd->set);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700783
Dmitry Torokhov3c42f0c2005-09-15 02:01:45 -0500784 sprintf(atkbd->phys, "%s/input0", atkbd->ps2dev.serio->phys);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700785
Dmitry Torokhov3c42f0c2005-09-15 02:01:45 -0500786 input_dev->name = atkbd->name;
787 input_dev->phys = atkbd->phys;
788 input_dev->id.bustype = BUS_I8042;
789 input_dev->id.vendor = 0x0001;
790 input_dev->id.product = atkbd->translated ? 1 : atkbd->set;
791 input_dev->id.version = atkbd->id;
792 input_dev->event = atkbd_event;
793 input_dev->private = atkbd;
794 input_dev->cdev.dev = &atkbd->ps2dev.serio->dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700795
Dmitry Torokhov3c42f0c2005-09-15 02:01:45 -0500796 input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP) | BIT(EV_MSC);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700797
798 if (atkbd->write) {
Dmitry Torokhov3c42f0c2005-09-15 02:01:45 -0500799 input_dev->evbit[0] |= BIT(EV_LED);
800 input_dev->ledbit[0] = BIT(LED_NUML) | BIT(LED_CAPSL) | BIT(LED_SCROLLL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700801 }
802
803 if (atkbd->extra)
Dmitry Torokhov3c42f0c2005-09-15 02:01:45 -0500804 input_dev->ledbit[0] |= BIT(LED_COMPOSE) | BIT(LED_SUSPEND) |
Linus Torvalds1da177e2005-04-16 15:20:36 -0700805 BIT(LED_SLEEP) | BIT(LED_MUTE) | BIT(LED_MISC);
806
807 if (!atkbd->softrepeat) {
Dmitry Torokhov3c42f0c2005-09-15 02:01:45 -0500808 input_dev->rep[REP_DELAY] = 250;
809 input_dev->rep[REP_PERIOD] = 33;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700810 }
811
Dmitry Torokhov3c42f0c2005-09-15 02:01:45 -0500812 input_dev->mscbit[0] = atkbd->softraw ? BIT(MSC_SCAN) : BIT(MSC_RAW) | BIT(MSC_SCAN);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700813
814 if (atkbd->scroll) {
Dmitry Torokhov3c42f0c2005-09-15 02:01:45 -0500815 input_dev->evbit[0] |= BIT(EV_REL);
816 input_dev->relbit[0] = BIT(REL_WHEEL) | BIT(REL_HWHEEL);
817 set_bit(BTN_MIDDLE, input_dev->keybit);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700818 }
819
Dmitry Torokhov3c42f0c2005-09-15 02:01:45 -0500820 input_dev->keycode = atkbd->keycode;
821 input_dev->keycodesize = sizeof(unsigned char);
822 input_dev->keycodemax = ARRAY_SIZE(atkbd_set2_keycode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700823
824 for (i = 0; i < 512; i++)
825 if (atkbd->keycode[i] && atkbd->keycode[i] < ATKBD_SPECIAL)
Dmitry Torokhov3c42f0c2005-09-15 02:01:45 -0500826 set_bit(atkbd->keycode[i], input_dev->keybit);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700827}
828
829/*
830 * atkbd_connect() is called when the serio module finds an interface
831 * that isn't handled yet by an appropriate device driver. We check if
832 * there is an AT keyboard out there and if yes, we register ourselves
833 * to the input module.
834 */
835
836static int atkbd_connect(struct serio *serio, struct serio_driver *drv)
837{
838 struct atkbd *atkbd;
Dmitry Torokhov3c42f0c2005-09-15 02:01:45 -0500839 struct input_dev *dev;
840 int err = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700841
Dmitry Torokhov3c42f0c2005-09-15 02:01:45 -0500842 atkbd = kzalloc(sizeof(struct atkbd), GFP_KERNEL);
843 dev = input_allocate_device();
844 if (!atkbd || !dev)
845 goto fail;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700846
Dmitry Torokhov3c42f0c2005-09-15 02:01:45 -0500847 atkbd->dev = dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700848 ps2_init(&atkbd->ps2dev, serio);
Dmitry Torokhov0d4c8592005-11-20 00:49:42 -0500849 INIT_WORK(&atkbd->event_work, atkbd_event_work, atkbd);
Ingo Molnar33d3f072006-02-19 00:22:18 -0500850 mutex_init(&atkbd->event_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700851
852 switch (serio->id.type) {
853
854 case SERIO_8042_XL:
855 atkbd->translated = 1;
856 case SERIO_8042:
857 if (serio->write)
858 atkbd->write = 1;
859 break;
860 }
861
862 atkbd->softraw = atkbd_softraw;
863 atkbd->softrepeat = atkbd_softrepeat;
864 atkbd->scroll = atkbd_scroll;
865
866 if (!atkbd->write)
867 atkbd->softrepeat = 1;
868
869 if (atkbd->softrepeat)
870 atkbd->softraw = 1;
871
872 serio_set_drvdata(serio, atkbd);
873
874 err = serio_open(serio, drv);
Dmitry Torokhov3c42f0c2005-09-15 02:01:45 -0500875 if (err)
876 goto fail;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700877
878 if (atkbd->write) {
879
880 if (atkbd_probe(atkbd)) {
881 serio_close(serio);
Dmitry Torokhov3c42f0c2005-09-15 02:01:45 -0500882 err = -ENODEV;
883 goto fail;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700884 }
885
886 atkbd->set = atkbd_select_set(atkbd, atkbd_set, atkbd_extra);
887 atkbd_activate(atkbd);
888
889 } else {
890 atkbd->set = 2;
891 atkbd->id = 0xab00;
892 }
893
Linus Torvalds1da177e2005-04-16 15:20:36 -0700894 atkbd_set_keycode_table(atkbd);
895 atkbd_set_device_attrs(atkbd);
896
Linus Torvalds1da177e2005-04-16 15:20:36 -0700897 device_create_file(&serio->dev, &atkbd_attr_extra);
898 device_create_file(&serio->dev, &atkbd_attr_scroll);
899 device_create_file(&serio->dev, &atkbd_attr_set);
900 device_create_file(&serio->dev, &atkbd_attr_softrepeat);
901 device_create_file(&serio->dev, &atkbd_attr_softraw);
902
903 atkbd_enable(atkbd);
904
Dmitry Torokhov3c42f0c2005-09-15 02:01:45 -0500905 input_register_device(atkbd->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700906
907 return 0;
Dmitry Torokhov3c42f0c2005-09-15 02:01:45 -0500908
909 fail: serio_set_drvdata(serio, NULL);
910 input_free_device(dev);
911 kfree(atkbd);
912 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700913}
914
915/*
916 * atkbd_reconnect() tries to restore keyboard into a sane state and is
917 * most likely called on resume.
918 */
919
920static int atkbd_reconnect(struct serio *serio)
921{
922 struct atkbd *atkbd = serio_get_drvdata(serio);
923 struct serio_driver *drv = serio->drv;
924 unsigned char param[1];
925
926 if (!atkbd || !drv) {
927 printk(KERN_DEBUG "atkbd: reconnect request, but serio is disconnected, ignoring...\n");
928 return -1;
929 }
930
931 atkbd_disable(atkbd);
932
933 if (atkbd->write) {
Dmitry Torokhov3c42f0c2005-09-15 02:01:45 -0500934 param[0] = (test_bit(LED_SCROLLL, atkbd->dev->led) ? 1 : 0)
935 | (test_bit(LED_NUML, atkbd->dev->led) ? 2 : 0)
936 | (test_bit(LED_CAPSL, atkbd->dev->led) ? 4 : 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700937
938 if (atkbd_probe(atkbd))
939 return -1;
940 if (atkbd->set != atkbd_select_set(atkbd, atkbd->set, atkbd->extra))
941 return -1;
942
943 atkbd_activate(atkbd);
944
945 if (ps2_command(&atkbd->ps2dev, param, ATKBD_CMD_SETLEDS))
946 return -1;
947 }
948
949 atkbd_enable(atkbd);
950
951 return 0;
952}
953
954static struct serio_device_id atkbd_serio_ids[] = {
955 {
956 .type = SERIO_8042,
957 .proto = SERIO_ANY,
958 .id = SERIO_ANY,
959 .extra = SERIO_ANY,
960 },
961 {
962 .type = SERIO_8042_XL,
963 .proto = SERIO_ANY,
964 .id = SERIO_ANY,
965 .extra = SERIO_ANY,
966 },
967 {
968 .type = SERIO_RS232,
969 .proto = SERIO_PS2SER,
970 .id = SERIO_ANY,
971 .extra = SERIO_ANY,
972 },
973 { 0 }
974};
975
976MODULE_DEVICE_TABLE(serio, atkbd_serio_ids);
977
978static struct serio_driver atkbd_drv = {
979 .driver = {
980 .name = "atkbd",
981 },
982 .description = DRIVER_DESC,
983 .id_table = atkbd_serio_ids,
984 .interrupt = atkbd_interrupt,
985 .connect = atkbd_connect,
986 .reconnect = atkbd_reconnect,
987 .disconnect = atkbd_disconnect,
988 .cleanup = atkbd_cleanup,
989};
990
991static ssize_t atkbd_attr_show_helper(struct device *dev, char *buf,
992 ssize_t (*handler)(struct atkbd *, char *))
993{
994 struct serio *serio = to_serio_port(dev);
995 int retval;
996
997 retval = serio_pin_driver(serio);
998 if (retval)
999 return retval;
1000
1001 if (serio->drv != &atkbd_drv) {
1002 retval = -ENODEV;
1003 goto out;
1004 }
1005
1006 retval = handler((struct atkbd *)serio_get_drvdata(serio), buf);
1007
1008out:
1009 serio_unpin_driver(serio);
1010 return retval;
1011}
1012
1013static ssize_t atkbd_attr_set_helper(struct device *dev, const char *buf, size_t count,
1014 ssize_t (*handler)(struct atkbd *, const char *, size_t))
1015{
1016 struct serio *serio = to_serio_port(dev);
1017 struct atkbd *atkbd;
1018 int retval;
1019
1020 retval = serio_pin_driver(serio);
1021 if (retval)
1022 return retval;
1023
1024 if (serio->drv != &atkbd_drv) {
1025 retval = -ENODEV;
1026 goto out;
1027 }
1028
1029 atkbd = serio_get_drvdata(serio);
1030 atkbd_disable(atkbd);
1031 retval = handler(atkbd, buf, count);
1032 atkbd_enable(atkbd);
1033
1034out:
1035 serio_unpin_driver(serio);
1036 return retval;
1037}
1038
1039static ssize_t atkbd_show_extra(struct atkbd *atkbd, char *buf)
1040{
1041 return sprintf(buf, "%d\n", atkbd->extra ? 1 : 0);
1042}
1043
1044static ssize_t atkbd_set_extra(struct atkbd *atkbd, const char *buf, size_t count)
1045{
Dmitry Torokhov3c42f0c2005-09-15 02:01:45 -05001046 struct input_dev *new_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001047 unsigned long value;
1048 char *rest;
1049
1050 if (!atkbd->write)
1051 return -EIO;
1052
1053 value = simple_strtoul(buf, &rest, 10);
1054 if (*rest || value > 1)
1055 return -EINVAL;
1056
1057 if (atkbd->extra != value) {
Dmitry Torokhov3c42f0c2005-09-15 02:01:45 -05001058 /*
1059 * Since device's properties will change we need to
1060 * unregister old device. But allocate new one first
1061 * to make sure we have it.
1062 */
1063 if (!(new_dev = input_allocate_device()))
1064 return -ENOMEM;
1065 input_unregister_device(atkbd->dev);
1066 atkbd->dev = new_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001067 atkbd->set = atkbd_select_set(atkbd, atkbd->set, value);
1068 atkbd_activate(atkbd);
1069 atkbd_set_device_attrs(atkbd);
Dmitry Torokhov3c42f0c2005-09-15 02:01:45 -05001070 input_register_device(atkbd->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001071 }
1072 return count;
1073}
1074
1075static ssize_t atkbd_show_scroll(struct atkbd *atkbd, char *buf)
1076{
1077 return sprintf(buf, "%d\n", atkbd->scroll ? 1 : 0);
1078}
1079
1080static ssize_t atkbd_set_scroll(struct atkbd *atkbd, const char *buf, size_t count)
1081{
Dmitry Torokhov3c42f0c2005-09-15 02:01:45 -05001082 struct input_dev *new_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001083 unsigned long value;
1084 char *rest;
1085
1086 value = simple_strtoul(buf, &rest, 10);
1087 if (*rest || value > 1)
1088 return -EINVAL;
1089
1090 if (atkbd->scroll != value) {
Dmitry Torokhov3c42f0c2005-09-15 02:01:45 -05001091 if (!(new_dev = input_allocate_device()))
1092 return -ENOMEM;
1093 input_unregister_device(atkbd->dev);
1094 atkbd->dev = new_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001095 atkbd->scroll = value;
1096 atkbd_set_keycode_table(atkbd);
1097 atkbd_set_device_attrs(atkbd);
Dmitry Torokhov3c42f0c2005-09-15 02:01:45 -05001098 input_register_device(atkbd->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001099 }
1100 return count;
1101}
1102
1103static ssize_t atkbd_show_set(struct atkbd *atkbd, char *buf)
1104{
1105 return sprintf(buf, "%d\n", atkbd->set);
1106}
1107
1108static ssize_t atkbd_set_set(struct atkbd *atkbd, const char *buf, size_t count)
1109{
Dmitry Torokhov3c42f0c2005-09-15 02:01:45 -05001110 struct input_dev *new_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001111 unsigned long value;
1112 char *rest;
1113
1114 if (!atkbd->write)
1115 return -EIO;
1116
1117 value = simple_strtoul(buf, &rest, 10);
1118 if (*rest || (value != 2 && value != 3))
1119 return -EINVAL;
1120
1121 if (atkbd->set != value) {
Dmitry Torokhov3c42f0c2005-09-15 02:01:45 -05001122 if (!(new_dev = input_allocate_device()))
1123 return -ENOMEM;
1124 input_unregister_device(atkbd->dev);
1125 atkbd->dev = new_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001126 atkbd->set = atkbd_select_set(atkbd, value, atkbd->extra);
1127 atkbd_activate(atkbd);
1128 atkbd_set_keycode_table(atkbd);
1129 atkbd_set_device_attrs(atkbd);
Dmitry Torokhov3c42f0c2005-09-15 02:01:45 -05001130 input_register_device(atkbd->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001131 }
1132 return count;
1133}
1134
1135static ssize_t atkbd_show_softrepeat(struct atkbd *atkbd, char *buf)
1136{
1137 return sprintf(buf, "%d\n", atkbd->softrepeat ? 1 : 0);
1138}
1139
1140static ssize_t atkbd_set_softrepeat(struct atkbd *atkbd, const char *buf, size_t count)
1141{
Dmitry Torokhov3c42f0c2005-09-15 02:01:45 -05001142 struct input_dev *new_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001143 unsigned long value;
1144 char *rest;
1145
1146 if (!atkbd->write)
1147 return -EIO;
1148
1149 value = simple_strtoul(buf, &rest, 10);
1150 if (*rest || value > 1)
1151 return -EINVAL;
1152
1153 if (atkbd->softrepeat != value) {
Dmitry Torokhov3c42f0c2005-09-15 02:01:45 -05001154 if (!(new_dev = input_allocate_device()))
1155 return -ENOMEM;
1156 input_unregister_device(atkbd->dev);
1157 atkbd->dev = new_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001158 atkbd->softrepeat = value;
1159 if (atkbd->softrepeat)
1160 atkbd->softraw = 1;
1161 atkbd_set_device_attrs(atkbd);
Dmitry Torokhov3c42f0c2005-09-15 02:01:45 -05001162 input_register_device(atkbd->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001163 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001164 return count;
1165}
1166
1167
1168static ssize_t atkbd_show_softraw(struct atkbd *atkbd, char *buf)
1169{
1170 return sprintf(buf, "%d\n", atkbd->softraw ? 1 : 0);
1171}
1172
1173static ssize_t atkbd_set_softraw(struct atkbd *atkbd, const char *buf, size_t count)
1174{
Dmitry Torokhov3c42f0c2005-09-15 02:01:45 -05001175 struct input_dev *new_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001176 unsigned long value;
1177 char *rest;
1178
1179 value = simple_strtoul(buf, &rest, 10);
1180 if (*rest || value > 1)
1181 return -EINVAL;
1182
1183 if (atkbd->softraw != value) {
Dmitry Torokhov3c42f0c2005-09-15 02:01:45 -05001184 if (!(new_dev = input_allocate_device()))
1185 return -ENOMEM;
1186 input_unregister_device(atkbd->dev);
1187 atkbd->dev = new_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001188 atkbd->softraw = value;
1189 atkbd_set_device_attrs(atkbd);
Dmitry Torokhov3c42f0c2005-09-15 02:01:45 -05001190 input_register_device(atkbd->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001191 }
1192 return count;
1193}
1194
1195
1196static int __init atkbd_init(void)
1197{
1198 serio_register_driver(&atkbd_drv);
1199 return 0;
1200}
1201
1202static void __exit atkbd_exit(void)
1203{
1204 serio_unregister_driver(&atkbd_drv);
1205}
1206
1207module_init(atkbd_init);
1208module_exit(atkbd_exit);