diff options
Diffstat (limited to 'drivers/input')
-rw-r--r-- | drivers/input/keyboard/atkbd.c | 208 |
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; | |||
55 | module_param_named(softraw, atkbd_softraw, bool, 0); | 55 | module_param_named(softraw, atkbd_softraw, bool, 0); |
56 | MODULE_PARM_DESC(softraw, "Use software generated rawmode"); | 56 | MODULE_PARM_DESC(softraw, "Use software generated rawmode"); |
57 | 57 | ||
58 | static int atkbd_scroll = 0; | 58 | static int atkbd_scroll; |
59 | module_param_named(scroll, atkbd_scroll, bool, 0); | 59 | module_param_named(scroll, atkbd_scroll, bool, 0); |
60 | MODULE_PARM_DESC(scroll, "Enable scroll-wheel on MS Office and similar keyboards"); | 60 | MODULE_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 | |||
173 | static struct { | 180 | static 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); | |||
245 | ATKBD_DEFINE_ATTR(softrepeat); | 251 | ATKBD_DEFINE_ATTR(softrepeat); |
246 | ATKBD_DEFINE_ATTR(softraw); | 252 | ATKBD_DEFINE_ATTR(softraw); |
247 | 253 | ||
254 | static 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 | ||
249 | static 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 | */ | ||
263 | static 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 | */ | ||
282 | static 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 | */ | ||
301 | static 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 | /* |