diff options
| author | Maxim Levitsky <maximlevitsky@gmail.com> | 2009-11-17 01:12:22 -0500 |
|---|---|---|
| committer | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2009-11-20 03:52:13 -0500 |
| commit | 71bb21b677e89a2b438b804231f92b779beda5d7 (patch) | |
| tree | 4bd0e84c5bd2010907022ec11eb3995bfbef57fe /drivers/input/mouse | |
| parent | 315eb996d5505112b22452ccbc7e01fb02eaae81 (diff) | |
Input: ALPS - add support for touchpads with 4-directional button
The touchpad on Acer Aspire 5720, 5520 and some other Aspire models
(signature 0x73, 0x02, 0x50) has a button that can be rocked in 4
different directions. Make the driver to generate BTN_0..BTN_3 events
in response. The Synaptics driver by default maps BTN_0 and BTN_1 to
up and down, so there should be no visible changes with the old setup
that generated BTN_FORWARD and BTN_BACK (also mapped to up and down).
Signed-off-by: Maxim Levitsky <maximlevitsky@gmail.com>
Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
Diffstat (limited to 'drivers/input/mouse')
| -rw-r--r-- | drivers/input/mouse/alps.c | 100 |
1 files changed, 65 insertions, 35 deletions
diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c index f36110689aae..a3f492a50850 100644 --- a/drivers/input/mouse/alps.c +++ b/drivers/input/mouse/alps.c | |||
| @@ -28,13 +28,16 @@ | |||
| 28 | #define dbg(format, arg...) do {} while (0) | 28 | #define dbg(format, arg...) do {} while (0) |
| 29 | #endif | 29 | #endif |
| 30 | 30 | ||
| 31 | #define ALPS_DUALPOINT 0x01 | 31 | |
| 32 | #define ALPS_WHEEL 0x02 | 32 | #define ALPS_OLDPROTO 0x01 /* old style input */ |
| 33 | #define ALPS_FW_BK_1 0x04 | 33 | #define ALPS_DUALPOINT 0x02 /* touchpad has trackstick */ |
| 34 | #define ALPS_4BTN 0x08 | 34 | #define ALPS_PASS 0x04 /* device has a pass-through port */ |
| 35 | #define ALPS_OLDPROTO 0x10 | 35 | |
| 36 | #define ALPS_PASS 0x20 | 36 | #define ALPS_WHEEL 0x08 /* hardware wheel present */ |
| 37 | #define ALPS_FW_BK_2 0x40 | 37 | #define ALPS_FW_BK_1 0x10 /* front & back buttons present */ |
| 38 | #define ALPS_FW_BK_2 0x20 /* front & back buttons present */ | ||
| 39 | #define ALPS_FOUR_BUTTONS 0x40 /* 4 direction button present */ | ||
| 40 | |||
| 38 | 41 | ||
| 39 | static const struct alps_model_info alps_model_data[] = { | 42 | static const struct alps_model_info alps_model_data[] = { |
| 40 | { { 0x32, 0x02, 0x14 }, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT }, /* Toshiba Salellite Pro M10 */ | 43 | { { 0x32, 0x02, 0x14 }, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT }, /* Toshiba Salellite Pro M10 */ |
| @@ -56,7 +59,7 @@ static const struct alps_model_info alps_model_data[] = { | |||
| 56 | { { 0x22, 0x02, 0x0a }, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT }, | 59 | { { 0x22, 0x02, 0x0a }, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT }, |
| 57 | { { 0x22, 0x02, 0x14 }, 0xff, 0xff, ALPS_PASS | ALPS_DUALPOINT }, /* Dell Latitude D600 */ | 60 | { { 0x22, 0x02, 0x14 }, 0xff, 0xff, ALPS_PASS | ALPS_DUALPOINT }, /* Dell Latitude D600 */ |
| 58 | { { 0x62, 0x02, 0x14 }, 0xcf, 0xcf, ALPS_PASS | ALPS_DUALPOINT }, /* Dell Latitude E6500 */ | 61 | { { 0x62, 0x02, 0x14 }, 0xcf, 0xcf, ALPS_PASS | ALPS_DUALPOINT }, /* Dell Latitude E6500 */ |
| 59 | { { 0x73, 0x02, 0x50 }, 0xcf, 0xcf, ALPS_FW_BK_1 }, /* Dell Vostro 1400 */ | 62 | { { 0x73, 0x02, 0x50 }, 0xcf, 0xcf, ALPS_FOUR_BUTTONS }, /* Dell Vostro 1400 */ |
| 60 | }; | 63 | }; |
| 61 | 64 | ||
| 62 | /* | 65 | /* |
| @@ -83,6 +86,7 @@ static const struct alps_model_info alps_model_data[] = { | |||
| 83 | static void alps_process_packet(struct psmouse *psmouse) | 86 | static void alps_process_packet(struct psmouse *psmouse) |
| 84 | { | 87 | { |
| 85 | struct alps_data *priv = psmouse->private; | 88 | struct alps_data *priv = psmouse->private; |
| 89 | const struct alps_model_info *model = priv->i; | ||
| 86 | unsigned char *packet = psmouse->packet; | 90 | unsigned char *packet = psmouse->packet; |
| 87 | struct input_dev *dev = psmouse->dev; | 91 | struct input_dev *dev = psmouse->dev; |
| 88 | struct input_dev *dev2 = priv->dev2; | 92 | struct input_dev *dev2 = priv->dev2; |
| @@ -101,7 +105,7 @@ static void alps_process_packet(struct psmouse *psmouse) | |||
| 101 | return; | 105 | return; |
| 102 | } | 106 | } |
| 103 | 107 | ||
| 104 | if (priv->i->flags & ALPS_OLDPROTO) { | 108 | if (model->flags & ALPS_OLDPROTO) { |
| 105 | left = packet[2] & 0x10; | 109 | left = packet[2] & 0x10; |
| 106 | right = packet[2] & 0x08; | 110 | right = packet[2] & 0x08; |
| 107 | middle = 0; | 111 | middle = 0; |
| @@ -117,12 +121,12 @@ static void alps_process_packet(struct psmouse *psmouse) | |||
| 117 | z = packet[5]; | 121 | z = packet[5]; |
| 118 | } | 122 | } |
| 119 | 123 | ||
| 120 | if (priv->i->flags & ALPS_FW_BK_1) { | 124 | if (model->flags & ALPS_FW_BK_1) { |
| 121 | back = packet[0] & 0x10; | 125 | back = packet[0] & 0x10; |
| 122 | forward = packet[2] & 4; | 126 | forward = packet[2] & 4; |
| 123 | } | 127 | } |
| 124 | 128 | ||
| 125 | if (priv->i->flags & ALPS_FW_BK_2) { | 129 | if (model->flags & ALPS_FW_BK_2) { |
| 126 | back = packet[3] & 4; | 130 | back = packet[3] & 4; |
| 127 | forward = packet[2] & 4; | 131 | forward = packet[2] & 4; |
| 128 | if ((middle = forward && back)) | 132 | if ((middle = forward && back)) |
| @@ -132,7 +136,7 @@ static void alps_process_packet(struct psmouse *psmouse) | |||
| 132 | ges = packet[2] & 1; | 136 | ges = packet[2] & 1; |
| 133 | fin = packet[2] & 2; | 137 | fin = packet[2] & 2; |
| 134 | 138 | ||
| 135 | if ((priv->i->flags & ALPS_DUALPOINT) && z == 127) { | 139 | if ((model->flags & ALPS_DUALPOINT) && z == 127) { |
| 136 | input_report_rel(dev2, REL_X, (x > 383 ? (x - 768) : x)); | 140 | input_report_rel(dev2, REL_X, (x > 383 ? (x - 768) : x)); |
| 137 | input_report_rel(dev2, REL_Y, -(y > 255 ? (y - 512) : y)); | 141 | input_report_rel(dev2, REL_Y, -(y > 255 ? (y - 512) : y)); |
| 138 | 142 | ||
| @@ -150,7 +154,8 @@ static void alps_process_packet(struct psmouse *psmouse) | |||
| 150 | input_report_key(dev, BTN_MIDDLE, middle); | 154 | input_report_key(dev, BTN_MIDDLE, middle); |
| 151 | 155 | ||
| 152 | /* Convert hardware tap to a reasonable Z value */ | 156 | /* Convert hardware tap to a reasonable Z value */ |
| 153 | if (ges && !fin) z = 40; | 157 | if (ges && !fin) |
| 158 | z = 40; | ||
| 154 | 159 | ||
| 155 | /* | 160 | /* |
| 156 | * A "tap and drag" operation is reported by the hardware as a transition | 161 | * A "tap and drag" operation is reported by the hardware as a transition |
| @@ -166,8 +171,10 @@ static void alps_process_packet(struct psmouse *psmouse) | |||
| 166 | } | 171 | } |
| 167 | priv->prev_fin = fin; | 172 | priv->prev_fin = fin; |
| 168 | 173 | ||
| 169 | if (z > 30) input_report_key(dev, BTN_TOUCH, 1); | 174 | if (z > 30) |
| 170 | if (z < 25) input_report_key(dev, BTN_TOUCH, 0); | 175 | input_report_key(dev, BTN_TOUCH, 1); |
| 176 | if (z < 25) | ||
| 177 | input_report_key(dev, BTN_TOUCH, 0); | ||
| 171 | 178 | ||
| 172 | if (z > 0) { | 179 | if (z > 0) { |
| 173 | input_report_abs(dev, ABS_X, x); | 180 | input_report_abs(dev, ABS_X, x); |
| @@ -177,14 +184,21 @@ static void alps_process_packet(struct psmouse *psmouse) | |||
| 177 | input_report_abs(dev, ABS_PRESSURE, z); | 184 | input_report_abs(dev, ABS_PRESSURE, z); |
| 178 | input_report_key(dev, BTN_TOOL_FINGER, z > 0); | 185 | input_report_key(dev, BTN_TOOL_FINGER, z > 0); |
| 179 | 186 | ||
| 180 | if (priv->i->flags & ALPS_WHEEL) | 187 | if (model->flags & ALPS_WHEEL) |
| 181 | input_report_rel(dev, REL_WHEEL, ((packet[2] << 1) & 0x08) - ((packet[0] >> 4) & 0x07)); | 188 | input_report_rel(dev, REL_WHEEL, ((packet[2] << 1) & 0x08) - ((packet[0] >> 4) & 0x07)); |
| 182 | 189 | ||
| 183 | if (priv->i->flags & (ALPS_FW_BK_1 | ALPS_FW_BK_2)) { | 190 | if (model->flags & (ALPS_FW_BK_1 | ALPS_FW_BK_2)) { |
| 184 | input_report_key(dev, BTN_FORWARD, forward); | 191 | input_report_key(dev, BTN_FORWARD, forward); |
| 185 | input_report_key(dev, BTN_BACK, back); | 192 | input_report_key(dev, BTN_BACK, back); |
| 186 | } | 193 | } |
| 187 | 194 | ||
| 195 | if (model->flags & ALPS_FOUR_BUTTONS) { | ||
| 196 | input_report_key(dev, BTN_0, packet[2] & 4); | ||
| 197 | input_report_key(dev, BTN_1, packet[0] & 0x10); | ||
| 198 | input_report_key(dev, BTN_2, packet[3] & 4); | ||
| 199 | input_report_key(dev, BTN_3, packet[0] & 0x20); | ||
| 200 | } | ||
| 201 | |||
| 188 | input_sync(dev); | 202 | input_sync(dev); |
| 189 | } | 203 | } |
| 190 | 204 | ||
| @@ -393,15 +407,12 @@ static int alps_poll(struct psmouse *psmouse) | |||
| 393 | return 0; | 407 | return 0; |
| 394 | } | 408 | } |
| 395 | 409 | ||
| 396 | static int alps_hw_init(struct psmouse *psmouse, int *version) | 410 | static int alps_hw_init(struct psmouse *psmouse) |
| 397 | { | 411 | { |
| 398 | struct alps_data *priv = psmouse->private; | 412 | struct alps_data *priv = psmouse->private; |
| 413 | const struct alps_model_info *model = priv->i; | ||
| 399 | 414 | ||
| 400 | priv->i = alps_get_model(psmouse, version); | 415 | if ((model->flags & ALPS_PASS) && |
| 401 | if (!priv->i) | ||
| 402 | return -1; | ||
| 403 | |||
| 404 | if ((priv->i->flags & ALPS_PASS) && | ||
| 405 | alps_passthrough_mode(psmouse, true)) { | 416 | alps_passthrough_mode(psmouse, true)) { |
| 406 | return -1; | 417 | return -1; |
| 407 | } | 418 | } |
| @@ -416,7 +427,7 @@ static int alps_hw_init(struct psmouse *psmouse, int *version) | |||
| 416 | return -1; | 427 | return -1; |
| 417 | } | 428 | } |
| 418 | 429 | ||
| 419 | if ((priv->i->flags & ALPS_PASS) && | 430 | if ((model->flags & ALPS_PASS) && |
| 420 | alps_passthrough_mode(psmouse, false)) { | 431 | alps_passthrough_mode(psmouse, false)) { |
| 421 | return -1; | 432 | return -1; |
| 422 | } | 433 | } |
| @@ -432,12 +443,15 @@ static int alps_hw_init(struct psmouse *psmouse, int *version) | |||
| 432 | 443 | ||
| 433 | static int alps_reconnect(struct psmouse *psmouse) | 444 | static int alps_reconnect(struct psmouse *psmouse) |
| 434 | { | 445 | { |
| 446 | const struct alps_model_info *model; | ||
| 447 | |||
| 435 | psmouse_reset(psmouse); | 448 | psmouse_reset(psmouse); |
| 436 | 449 | ||
| 437 | if (alps_hw_init(psmouse, NULL)) | 450 | model = alps_get_model(psmouse, NULL); |
| 451 | if (!model) | ||
| 438 | return -1; | 452 | return -1; |
| 439 | 453 | ||
| 440 | return 0; | 454 | return alps_hw_init(psmouse); |
| 441 | } | 455 | } |
| 442 | 456 | ||
| 443 | static void alps_disconnect(struct psmouse *psmouse) | 457 | static void alps_disconnect(struct psmouse *psmouse) |
| @@ -452,6 +466,7 @@ static void alps_disconnect(struct psmouse *psmouse) | |||
| 452 | int alps_init(struct psmouse *psmouse) | 466 | int alps_init(struct psmouse *psmouse) |
| 453 | { | 467 | { |
| 454 | struct alps_data *priv; | 468 | struct alps_data *priv; |
| 469 | const struct alps_model_info *model; | ||
| 455 | struct input_dev *dev1 = psmouse->dev, *dev2; | 470 | struct input_dev *dev1 = psmouse->dev, *dev2; |
| 456 | int version; | 471 | int version; |
| 457 | 472 | ||
| @@ -463,33 +478,48 @@ int alps_init(struct psmouse *psmouse) | |||
| 463 | priv->dev2 = dev2; | 478 | priv->dev2 = dev2; |
| 464 | psmouse->private = priv; | 479 | psmouse->private = priv; |
| 465 | 480 | ||
| 466 | if (alps_hw_init(psmouse, &version)) | 481 | model = alps_get_model(psmouse, &version); |
| 482 | if (!model) | ||
| 483 | goto init_fail; | ||
| 484 | |||
| 485 | priv->i = model; | ||
| 486 | |||
| 487 | if (alps_hw_init(psmouse)) | ||
| 467 | goto init_fail; | 488 | goto init_fail; |
| 468 | 489 | ||
| 469 | dev1->evbit[BIT_WORD(EV_KEY)] |= BIT_MASK(EV_KEY); | 490 | dev1->evbit[BIT_WORD(EV_KEY)] |= BIT_MASK(EV_KEY); |
| 470 | dev1->keybit[BIT_WORD(BTN_TOUCH)] |= BIT_MASK(BTN_TOUCH); | 491 | dev1->keybit[BIT_WORD(BTN_TOUCH)] |= BIT_MASK(BTN_TOUCH); |
| 471 | dev1->keybit[BIT_WORD(BTN_TOOL_FINGER)] |= BIT_MASK(BTN_TOOL_FINGER); | 492 | dev1->keybit[BIT_WORD(BTN_TOOL_FINGER)] |= BIT_MASK(BTN_TOOL_FINGER); |
| 472 | dev1->keybit[BIT_WORD(BTN_LEFT)] |= BIT_MASK(BTN_LEFT) | | 493 | dev1->keybit[BIT_WORD(BTN_LEFT)] |= |
| 473 | BIT_MASK(BTN_MIDDLE) | BIT_MASK(BTN_RIGHT); | 494 | BIT_MASK(BTN_LEFT) | BIT_MASK(BTN_RIGHT); |
| 474 | 495 | ||
| 475 | dev1->evbit[BIT_WORD(EV_ABS)] |= BIT_MASK(EV_ABS); | 496 | dev1->evbit[BIT_WORD(EV_ABS)] |= BIT_MASK(EV_ABS); |
| 476 | input_set_abs_params(dev1, ABS_X, 0, 1023, 0, 0); | 497 | input_set_abs_params(dev1, ABS_X, 0, 1023, 0, 0); |
| 477 | input_set_abs_params(dev1, ABS_Y, 0, 767, 0, 0); | 498 | input_set_abs_params(dev1, ABS_Y, 0, 767, 0, 0); |
| 478 | input_set_abs_params(dev1, ABS_PRESSURE, 0, 127, 0, 0); | 499 | input_set_abs_params(dev1, ABS_PRESSURE, 0, 127, 0, 0); |
| 479 | 500 | ||
| 480 | if (priv->i->flags & ALPS_WHEEL) { | 501 | if (model->flags & ALPS_WHEEL) { |
| 481 | dev1->evbit[BIT_WORD(EV_REL)] |= BIT_MASK(EV_REL); | 502 | dev1->evbit[BIT_WORD(EV_REL)] |= BIT_MASK(EV_REL); |
| 482 | dev1->relbit[BIT_WORD(REL_WHEEL)] |= BIT_MASK(REL_WHEEL); | 503 | dev1->relbit[BIT_WORD(REL_WHEEL)] |= BIT_MASK(REL_WHEEL); |
| 483 | } | 504 | } |
| 484 | 505 | ||
| 485 | if (priv->i->flags & (ALPS_FW_BK_1 | ALPS_FW_BK_2)) { | 506 | if (model->flags & (ALPS_FW_BK_1 | ALPS_FW_BK_2)) { |
| 486 | dev1->keybit[BIT_WORD(BTN_FORWARD)] |= BIT_MASK(BTN_FORWARD); | 507 | dev1->keybit[BIT_WORD(BTN_FORWARD)] |= BIT_MASK(BTN_FORWARD); |
| 487 | dev1->keybit[BIT_WORD(BTN_BACK)] |= BIT_MASK(BTN_BACK); | 508 | dev1->keybit[BIT_WORD(BTN_BACK)] |= BIT_MASK(BTN_BACK); |
| 488 | } | 509 | } |
| 489 | 510 | ||
| 511 | if (model->flags & ALPS_FOUR_BUTTONS) { | ||
| 512 | dev1->keybit[BIT_WORD(BTN_0)] |= BIT_MASK(BTN_0); | ||
| 513 | dev1->keybit[BIT_WORD(BTN_1)] |= BIT_MASK(BTN_1); | ||
| 514 | dev1->keybit[BIT_WORD(BTN_2)] |= BIT_MASK(BTN_2); | ||
| 515 | dev1->keybit[BIT_WORD(BTN_3)] |= BIT_MASK(BTN_3); | ||
| 516 | } else { | ||
| 517 | dev1->keybit[BIT_WORD(BTN_MIDDLE)] |= BIT_MASK(BTN_MIDDLE); | ||
| 518 | } | ||
| 519 | |||
| 490 | snprintf(priv->phys, sizeof(priv->phys), "%s/input1", psmouse->ps2dev.serio->phys); | 520 | snprintf(priv->phys, sizeof(priv->phys), "%s/input1", psmouse->ps2dev.serio->phys); |
| 491 | dev2->phys = priv->phys; | 521 | dev2->phys = priv->phys; |
| 492 | dev2->name = (priv->i->flags & ALPS_DUALPOINT) ? "DualPoint Stick" : "PS/2 Mouse"; | 522 | dev2->name = (model->flags & ALPS_DUALPOINT) ? "DualPoint Stick" : "PS/2 Mouse"; |
| 493 | dev2->id.bustype = BUS_I8042; | 523 | dev2->id.bustype = BUS_I8042; |
| 494 | dev2->id.vendor = 0x0002; | 524 | dev2->id.vendor = 0x0002; |
| 495 | dev2->id.product = PSMOUSE_ALPS; | 525 | dev2->id.product = PSMOUSE_ALPS; |
| @@ -497,9 +527,9 @@ int alps_init(struct psmouse *psmouse) | |||
| 497 | dev2->dev.parent = &psmouse->ps2dev.serio->dev; | 527 | dev2->dev.parent = &psmouse->ps2dev.serio->dev; |
| 498 | 528 | ||
| 499 | dev2->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL); | 529 | dev2->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL); |
| 500 | dev2->relbit[BIT_WORD(REL_X)] |= BIT_MASK(REL_X) | BIT_MASK(REL_Y); | 530 | dev2->relbit[BIT_WORD(REL_X)] = BIT_MASK(REL_X) | BIT_MASK(REL_Y); |
| 501 | dev2->keybit[BIT_WORD(BTN_LEFT)] |= BIT_MASK(BTN_LEFT) | | 531 | dev2->keybit[BIT_WORD(BTN_LEFT)] = |
| 502 | BIT_MASK(BTN_MIDDLE) | BIT_MASK(BTN_RIGHT); | 532 | BIT_MASK(BTN_LEFT) | BIT_MASK(BTN_MIDDLE) | BIT_MASK(BTN_RIGHT); |
| 503 | 533 | ||
| 504 | if (input_register_device(priv->dev2)) | 534 | if (input_register_device(priv->dev2)) |
| 505 | goto init_fail; | 535 | goto init_fail; |
