aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/input
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/input')
-rw-r--r--drivers/input/keyboard/atkbd.c208
1 files changed, 131 insertions, 77 deletions
diff --git a/drivers/input/keyboard/atkbd.c b/drivers/input/keyboard/atkbd.c
index 1bf61f00cbd2..ffde8f86e0fb 100644
--- a/drivers/input/keyboard/atkbd.c
+++ b/drivers/input/keyboard/atkbd.c
@@ -55,7 +55,7 @@ static int atkbd_softraw = 1;
55module_param_named(softraw, atkbd_softraw, bool, 0); 55module_param_named(softraw, atkbd_softraw, bool, 0);
56MODULE_PARM_DESC(softraw, "Use software generated rawmode"); 56MODULE_PARM_DESC(softraw, "Use software generated rawmode");
57 57
58static int atkbd_scroll = 0; 58static int atkbd_scroll;
59module_param_named(scroll, atkbd_scroll, bool, 0); 59module_param_named(scroll, atkbd_scroll, bool, 0);
60MODULE_PARM_DESC(scroll, "Enable scroll-wheel on MS Office and similar keyboards"); 60MODULE_PARM_DESC(scroll, "Enable scroll-wheel on MS Office and similar keyboards");
61 61
@@ -150,8 +150,8 @@ static unsigned char atkbd_unxlate_table[128] = {
150#define ATKBD_RET_EMUL0 0xe0 150#define ATKBD_RET_EMUL0 0xe0
151#define ATKBD_RET_EMUL1 0xe1 151#define ATKBD_RET_EMUL1 0xe1
152#define ATKBD_RET_RELEASE 0xf0 152#define ATKBD_RET_RELEASE 0xf0
153#define ATKBD_RET_HANGEUL 0xf1 153#define ATKBD_RET_HANJA 0xf1
154#define ATKBD_RET_HANJA 0xf2 154#define ATKBD_RET_HANGEUL 0xf2
155#define ATKBD_RET_ERR 0xff 155#define ATKBD_RET_ERR 0xff
156 156
157#define ATKBD_KEY_UNKNOWN 0 157#define ATKBD_KEY_UNKNOWN 0
@@ -170,6 +170,13 @@ static unsigned char atkbd_unxlate_table[128] = {
170#define ATKBD_LED_EVENT_BIT 0 170#define ATKBD_LED_EVENT_BIT 0
171#define ATKBD_REP_EVENT_BIT 1 171#define ATKBD_REP_EVENT_BIT 1
172 172
173#define ATKBD_XL_ERR 0x01
174#define ATKBD_XL_BAT 0x02
175#define ATKBD_XL_ACK 0x04
176#define ATKBD_XL_NAK 0x08
177#define ATKBD_XL_HANGEUL 0x10
178#define ATKBD_XL_HANJA 0x20
179
173static struct { 180static struct {
174 unsigned char keycode; 181 unsigned char keycode;
175 unsigned char set2; 182 unsigned char set2;
@@ -211,8 +218,7 @@ struct atkbd {
211 unsigned char emul; 218 unsigned char emul;
212 unsigned char resend; 219 unsigned char resend;
213 unsigned char release; 220 unsigned char release;
214 unsigned char bat_xl; 221 unsigned long xl_bit;
215 unsigned char err_xl;
216 unsigned int last; 222 unsigned int last;
217 unsigned long time; 223 unsigned long time;
218 224
@@ -245,17 +251,65 @@ ATKBD_DEFINE_ATTR(set);
245ATKBD_DEFINE_ATTR(softrepeat); 251ATKBD_DEFINE_ATTR(softrepeat);
246ATKBD_DEFINE_ATTR(softraw); 252ATKBD_DEFINE_ATTR(softraw);
247 253
254static const unsigned int xl_table[] = {
255 ATKBD_RET_BAT, ATKBD_RET_ERR, ATKBD_RET_ACK,
256 ATKBD_RET_NAK, ATKBD_RET_HANJA, ATKBD_RET_HANGEUL,
257};
248 258
249static void atkbd_report_key(struct input_dev *dev, struct pt_regs *regs, int code, int value) 259/*
260 * Checks if we should mangle the scancode to extract 'release' bit
261 * in translated mode.
262 */
263static int atkbd_need_xlate(unsigned long xl_bit, unsigned char code)
250{ 264{
251 input_regs(dev, regs); 265 int i;
252 if (value == 3) { 266
253 input_report_key(dev, code, 1); 267 if (code == ATKBD_RET_EMUL0 || code == ATKBD_RET_EMUL1)
254 input_sync(dev); 268 return 0;
255 input_report_key(dev, code, 0); 269
256 } else 270 for (i = 0; i < ARRAY_SIZE(xl_table); i++)
257 input_event(dev, EV_KEY, code, value); 271 if (code == xl_table[i])
258 input_sync(dev); 272 return test_bit(i, &xl_bit);
273
274 return 1;
275}
276
277/*
278 * Calculates new value of xl_bit so the driver can distinguish
279 * between make/break pair of scancodes for select keys and PS/2
280 * protocol responses.
281 */
282static void atkbd_calculate_xl_bit(struct atkbd *atkbd, unsigned char code)
283{
284 int i;
285
286 for (i = 0; i < ARRAY_SIZE(xl_table); i++) {
287 if (!((code ^ xl_table[i]) & 0x7f)) {
288 if (code & 0x80)
289 __clear_bit(i, &atkbd->xl_bit);
290 else
291 __set_bit(i, &atkbd->xl_bit);
292 break;
293 }
294 }
295}
296
297/*
298 * Encode the scancode, 0xe0 prefix, and high bit into a single integer,
299 * keeping kernel 2.4 compatibility for set 2
300 */
301static unsigned int atkbd_compat_scancode(struct atkbd *atkbd, unsigned int code)
302{
303 if (atkbd->set == 3) {
304 if (atkbd->emul == 1)
305 code |= 0x100;
306 } else {
307 code = (code & 0x7f) | ((code & 0x80) << 1);
308 if (atkbd->emul == 1)
309 code |= 0x80;
310 }
311
312 return code;
259} 313}
260 314
261/* 315/*
@@ -267,9 +321,11 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data,
267 unsigned int flags, struct pt_regs *regs) 321 unsigned int flags, struct pt_regs *regs)
268{ 322{
269 struct atkbd *atkbd = serio_get_drvdata(serio); 323 struct atkbd *atkbd = serio_get_drvdata(serio);
324 struct input_dev *dev = atkbd->dev;
270 unsigned int code = data; 325 unsigned int code = data;
271 int scroll = 0, hscroll = 0, click = -1; 326 int scroll = 0, hscroll = 0, click = -1, add_release_event = 0;
272 int value; 327 int value;
328 unsigned char keycode;
273 329
274#ifdef ATKBD_DEBUG 330#ifdef ATKBD_DEBUG
275 printk(KERN_DEBUG "atkbd.c: Received %02x flags %02x\n", data, flags); 331 printk(KERN_DEBUG "atkbd.c: Received %02x flags %02x\n", data, flags);
@@ -298,25 +354,17 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data,
298 if (!atkbd->enabled) 354 if (!atkbd->enabled)
299 goto out; 355 goto out;
300 356
301 input_event(atkbd->dev, EV_MSC, MSC_RAW, code); 357 input_event(dev, EV_MSC, MSC_RAW, code);
302 358
303 if (atkbd->translated) { 359 if (atkbd->translated) {
304 360
305 if (atkbd->emul || 361 if (atkbd->emul || atkbd_need_xlate(atkbd->xl_bit, code)) {
306 (code != ATKBD_RET_EMUL0 && code != ATKBD_RET_EMUL1 &&
307 code != ATKBD_RET_HANGEUL && code != ATKBD_RET_HANJA &&
308 (code != ATKBD_RET_ERR || atkbd->err_xl) &&
309 (code != ATKBD_RET_BAT || atkbd->bat_xl))) {
310 atkbd->release = code >> 7; 362 atkbd->release = code >> 7;
311 code &= 0x7f; 363 code &= 0x7f;
312 } 364 }
313 365
314 if (!atkbd->emul) { 366 if (!atkbd->emul)
315 if ((code & 0x7f) == (ATKBD_RET_BAT & 0x7f)) 367 atkbd_calculate_xl_bit(atkbd, data);
316 atkbd->bat_xl = !(data >> 7);
317 if ((code & 0x7f) == (ATKBD_RET_ERR & 0x7f))
318 atkbd->err_xl = !(data >> 7);
319 }
320 } 368 }
321 369
322 switch (code) { 370 switch (code) {
@@ -333,47 +381,48 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data,
333 case ATKBD_RET_RELEASE: 381 case ATKBD_RET_RELEASE:
334 atkbd->release = 1; 382 atkbd->release = 1;
335 goto out; 383 goto out;
336 case ATKBD_RET_HANGEUL: 384 case ATKBD_RET_ACK:
337 atkbd_report_key(atkbd->dev, regs, KEY_HANGEUL, 3); 385 case ATKBD_RET_NAK:
386 printk(KERN_WARNING "atkbd.c: Spurious %s on %s. "
387 "Some program might be trying access hardware directly.\n",
388 data == ATKBD_RET_ACK ? "ACK" : "NAK", serio->phys);
338 goto out; 389 goto out;
390 case ATKBD_RET_HANGEUL:
339 case ATKBD_RET_HANJA: 391 case ATKBD_RET_HANJA:
340 atkbd_report_key(atkbd->dev, regs, KEY_HANJA, 3); 392 /*
341 goto out; 393 * These keys do not report release and thus need to be
394 * flagged properly
395 */
396 add_release_event = 1;
397 break;
342 case ATKBD_RET_ERR: 398 case ATKBD_RET_ERR:
343 printk(KERN_DEBUG "atkbd.c: Keyboard on %s reports too many keys pressed.\n", serio->phys); 399 printk(KERN_DEBUG "atkbd.c: Keyboard on %s reports too many keys pressed.\n", serio->phys);
344 goto out; 400 goto out;
345 } 401 }
346 402
347 if (atkbd->set != 3) 403 code = atkbd_compat_scancode(atkbd, code);
348 code = (code & 0x7f) | ((code & 0x80) << 1); 404
349 if (atkbd->emul) { 405 if (atkbd->emul && --atkbd->emul)
350 if (--atkbd->emul) 406 goto out;
351 goto out; 407
352 code |= (atkbd->set != 3) ? 0x80 : 0x100; 408 keycode = atkbd->keycode[code];
353 }
354 409
355 if (atkbd->keycode[code] != ATKBD_KEY_NULL) 410 if (keycode != ATKBD_KEY_NULL)
356 input_event(atkbd->dev, EV_MSC, MSC_SCAN, code); 411 input_event(dev, EV_MSC, MSC_SCAN, code);
357 412
358 switch (atkbd->keycode[code]) { 413 switch (keycode) {
359 case ATKBD_KEY_NULL: 414 case ATKBD_KEY_NULL:
360 break; 415 break;
361 case ATKBD_KEY_UNKNOWN: 416 case ATKBD_KEY_UNKNOWN:
362 if (data == ATKBD_RET_ACK || data == ATKBD_RET_NAK) { 417 printk(KERN_WARNING
363 printk(KERN_WARNING "atkbd.c: Spurious %s on %s. Some program, " 418 "atkbd.c: Unknown key %s (%s set %d, code %#x on %s).\n",
364 "like XFree86, might be trying access hardware directly.\n", 419 atkbd->release ? "released" : "pressed",
365 data == ATKBD_RET_ACK ? "ACK" : "NAK", serio->phys); 420 atkbd->translated ? "translated" : "raw",
366 } else { 421 atkbd->set, code, serio->phys);
367 printk(KERN_WARNING "atkbd.c: Unknown key %s " 422 printk(KERN_WARNING
368 "(%s set %d, code %#x on %s).\n", 423 "atkbd.c: Use 'setkeycodes %s%02x <keycode>' to make it known.\n",
369 atkbd->release ? "released" : "pressed", 424 code & 0x80 ? "e0" : "", code & 0x7f);
370 atkbd->translated ? "translated" : "raw", 425 input_sync(dev);
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 }
376 input_sync(atkbd->dev);
377 break; 426 break;
378 case ATKBD_SCR_1: 427 case ATKBD_SCR_1:
379 scroll = 1 - atkbd->release * 2; 428 scroll = 1 - atkbd->release * 2;
@@ -397,33 +446,35 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data,
397 hscroll = 1; 446 hscroll = 1;
398 break; 447 break;
399 default: 448 default:
400 value = atkbd->release ? 0 : 449 if (atkbd->release) {
401 (1 + (!atkbd->softrepeat && test_bit(atkbd->keycode[code], atkbd->dev->key))); 450 value = 0;
402 451 atkbd->last = 0;
403 switch (value) { /* Workaround Toshiba laptop multiple keypress */ 452 } else if (!atkbd->softrepeat && test_bit(keycode, dev->key)) {
404 case 0: 453 /* Workaround Toshiba laptop multiple keypress */
405 atkbd->last = 0; 454 value = time_before(jiffies, atkbd->time) && atkbd->last == code ? 1 : 2;
406 break; 455 } else {
407 case 1: 456 value = 1;
408 atkbd->last = code; 457 atkbd->last = code;
409 atkbd->time = jiffies + msecs_to_jiffies(atkbd->dev->rep[REP_DELAY]) / 2; 458 atkbd->time = jiffies + msecs_to_jiffies(dev->rep[REP_DELAY]) / 2;
410 break;
411 case 2:
412 if (!time_after(jiffies, atkbd->time) && atkbd->last == code)
413 value = 1;
414 break;
415 } 459 }
416 460
417 atkbd_report_key(atkbd->dev, regs, atkbd->keycode[code], value); 461 input_regs(dev, regs);
462 input_report_key(dev, keycode, value);
463 input_sync(dev);
464
465 if (value && add_release_event) {
466 input_report_key(dev, keycode, 0);
467 input_sync(dev);
468 }
418 } 469 }
419 470
420 if (atkbd->scroll) { 471 if (atkbd->scroll) {
421 input_regs(atkbd->dev, regs); 472 input_regs(dev, regs);
422 if (click != -1) 473 if (click != -1)
423 input_report_key(atkbd->dev, BTN_MIDDLE, click); 474 input_report_key(dev, BTN_MIDDLE, click);
424 input_report_rel(atkbd->dev, REL_WHEEL, scroll); 475 input_report_rel(dev, REL_WHEEL, scroll);
425 input_report_rel(atkbd->dev, REL_HWHEEL, hscroll); 476 input_report_rel(dev, REL_HWHEEL, hscroll);
426 input_sync(atkbd->dev); 477 input_sync(dev);
427 } 478 }
428 479
429 atkbd->release = 0; 480 atkbd->release = 0;
@@ -764,6 +815,9 @@ static void atkbd_set_keycode_table(struct atkbd *atkbd)
764 for (i = 0; i < ARRAY_SIZE(atkbd_scroll_keys); i++) 815 for (i = 0; i < ARRAY_SIZE(atkbd_scroll_keys); i++)
765 atkbd->keycode[atkbd_scroll_keys[i].set2] = atkbd_scroll_keys[i].keycode; 816 atkbd->keycode[atkbd_scroll_keys[i].set2] = atkbd_scroll_keys[i].keycode;
766 } 817 }
818
819 atkbd->keycode[atkbd_compat_scancode(atkbd, ATKBD_RET_HANGEUL)] = KEY_HANGUEL;
820 atkbd->keycode[atkbd_compat_scancode(atkbd, ATKBD_RET_HANJA)] = KEY_HANJA;
767} 821}
768 822
769/* 823/*