diff options
Diffstat (limited to 'drivers/input/keyboard/atkbd.c')
| -rw-r--r-- | drivers/input/keyboard/atkbd.c | 219 |
1 files changed, 138 insertions, 81 deletions
diff --git a/drivers/input/keyboard/atkbd.c b/drivers/input/keyboard/atkbd.c index fad04b66d268..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_HANGUEL 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_HANGUEL && 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_HANGUEL: | 384 | case ATKBD_RET_ACK: |
| 337 | atkbd_report_key(atkbd->dev, regs, KEY_HANGUEL, 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; | ||
| 352 | code |= (atkbd->set != 3) ? 0x80 : 0x100; | ||
| 353 | } | ||
| 354 | 407 | ||
| 355 | if (atkbd->keycode[code] != ATKBD_KEY_NULL) | 408 | keycode = atkbd->keycode[code]; |
| 356 | input_event(atkbd->dev, EV_MSC, MSC_SCAN, code); | ||
| 357 | 409 | ||
| 358 | switch (atkbd->keycode[code]) { | 410 | if (keycode != ATKBD_KEY_NULL) |
| 411 | input_event(dev, EV_MSC, MSC_SCAN, code); | ||
| 412 | |||
| 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 | /* |
| @@ -776,12 +830,15 @@ static void atkbd_set_device_attrs(struct atkbd *atkbd) | |||
| 776 | int i; | 830 | int i; |
| 777 | 831 | ||
| 778 | if (atkbd->extra) | 832 | if (atkbd->extra) |
| 779 | sprintf(atkbd->name, "AT Set 2 Extra keyboard"); | 833 | snprintf(atkbd->name, sizeof(atkbd->name), |
| 834 | "AT Set 2 Extra keyboard"); | ||
| 780 | else | 835 | else |
| 781 | sprintf(atkbd->name, "AT %s Set %d keyboard", | 836 | snprintf(atkbd->name, sizeof(atkbd->name), |
| 782 | atkbd->translated ? "Translated" : "Raw", atkbd->set); | 837 | "AT %s Set %d keyboard", |
| 838 | atkbd->translated ? "Translated" : "Raw", atkbd->set); | ||
| 783 | 839 | ||
| 784 | sprintf(atkbd->phys, "%s/input0", atkbd->ps2dev.serio->phys); | 840 | snprintf(atkbd->phys, sizeof(atkbd->phys), |
| 841 | "%s/input0", atkbd->ps2dev.serio->phys); | ||
| 785 | 842 | ||
| 786 | input_dev->name = atkbd->name; | 843 | input_dev->name = atkbd->name; |
| 787 | input_dev->phys = atkbd->phys; | 844 | input_dev->phys = atkbd->phys; |
