summaryrefslogtreecommitdiff
path: root/usr/src/dkms_source_tree/synaptics.c
diff options
context:
space:
mode:
authorHenrik Rydberg <rydberg@euromail.se>2010-11-16 14:25:19 +0100
committerHenrik Rydberg <rydberg@euromail.se>2010-11-16 14:25:19 +0100
commit5bd76821fca3d6422a586b691436583224158b01 (patch)
tree96ffe55bb1ca8402d0d4be47c85915466c85817d /usr/src/dkms_source_tree/synaptics.c
parente56d270d5dd472219864c1735d8eee16d6f1ccdb (diff)
Experimental mainline MT supportHEADmaster
This patchset is in flux, and a cooperative effort between Takashi Iwai, Chase Douglas, Chris Bagwell and myself. Signed-off-by: Henrik Rydberg <rydberg@euromail.se>
Diffstat (limited to 'usr/src/dkms_source_tree/synaptics.c')
-rw-r--r--usr/src/dkms_source_tree/synaptics.c247
1 files changed, 161 insertions, 86 deletions
diff --git a/usr/src/dkms_source_tree/synaptics.c b/usr/src/dkms_source_tree/synaptics.c
index ae9891c..c19d39f 100644
--- a/usr/src/dkms_source_tree/synaptics.c
+++ b/usr/src/dkms_source_tree/synaptics.c
@@ -279,6 +279,24 @@ static void synaptics_set_rate(struct psmouse *psmouse, unsigned int rate)
279 synaptics_mode_cmd(psmouse, priv->mode); 279 synaptics_mode_cmd(psmouse, priv->mode);
280} 280}
281 281
282static int synaptics_set_multitouch_mode(struct psmouse *psmouse)
283{
284 static unsigned char param = 0xc8;
285 struct synaptics_data *priv = psmouse->private;
286
287 if (!SYN_CAP_MULTITOUCH(priv->ext_cap_0c))
288 return 0;
289
290 if (psmouse_sliced_command(psmouse, SYN_QUE_MODEL))
291 return -1;
292 if (ps2_command(&psmouse->ps2dev, &param, PSMOUSE_CMD_SETRATE))
293 return -1;
294
295 priv->multitouch = 1;
296 printk(KERN_INFO "Synaptics: Multitouch mode enabled\n");
297 return 0;
298}
299
282/***************************************************************************** 300/*****************************************************************************
283 * Synaptics pass-through PS/2 port support 301 * Synaptics pass-through PS/2 port support
284 ****************************************************************************/ 302 ****************************************************************************/
@@ -294,7 +312,29 @@ static int synaptics_pt_write(struct serio *serio, unsigned char c)
294 return 0; 312 return 0;
295} 313}
296 314
297static inline int synaptics_is_pt_packet(unsigned char *buf) 315static int synaptics_pt_start(struct serio *serio)
316{
317 struct psmouse *parent = serio_get_drvdata(serio->parent);
318 struct synaptics_data *priv = parent->private;
319
320 serio_pause_rx(parent->ps2dev.serio);
321 priv->pt_port = serio;
322 serio_continue_rx(parent->ps2dev.serio);
323
324 return 0;
325}
326
327static void synaptics_pt_stop(struct serio *serio)
328{
329 struct psmouse *parent = serio_get_drvdata(serio->parent);
330 struct synaptics_data *priv = parent->private;
331
332 serio_pause_rx(parent->ps2dev.serio);
333 priv->pt_port = NULL;
334 serio_continue_rx(parent->ps2dev.serio);
335}
336
337static int synaptics_is_pt_packet(unsigned char *buf)
298{ 338{
299 return (buf[0] & 0xFC) == 0x84 && (buf[3] & 0xCC) == 0xC4; 339 return (buf[0] & 0xFC) == 0x84 && (buf[3] & 0xCC) == 0xC4;
300} 340}
@@ -315,9 +355,8 @@ static void synaptics_pass_pt_packet(struct serio *ptport, unsigned char *packet
315 355
316static void synaptics_pt_activate(struct psmouse *psmouse) 356static void synaptics_pt_activate(struct psmouse *psmouse)
317{ 357{
318 struct serio *ptport = psmouse->ps2dev.serio->child;
319 struct psmouse *child = serio_get_drvdata(ptport);
320 struct synaptics_data *priv = psmouse->private; 358 struct synaptics_data *priv = psmouse->private;
359 struct psmouse *child = serio_get_drvdata(priv->pt_port);
321 360
322 /* adjust the touchpad to child's choice of protocol */ 361 /* adjust the touchpad to child's choice of protocol */
323 if (child) { 362 if (child) {
@@ -345,6 +384,8 @@ static void synaptics_pt_create(struct psmouse *psmouse)
345 strlcpy(serio->name, "Synaptics pass-through", sizeof(serio->name)); 384 strlcpy(serio->name, "Synaptics pass-through", sizeof(serio->name));
346 strlcpy(serio->phys, "synaptics-pt/serio0", sizeof(serio->name)); 385 strlcpy(serio->phys, "synaptics-pt/serio0", sizeof(serio->name));
347 serio->write = synaptics_pt_write; 386 serio->write = synaptics_pt_write;
387 serio->start = synaptics_pt_start;
388 serio->stop = synaptics_pt_stop;
348 serio->parent = psmouse->ps2dev.serio; 389 serio->parent = psmouse->ps2dev.serio;
349 390
350 psmouse->pt_activate = synaptics_pt_activate; 391 psmouse->pt_activate = synaptics_pt_activate;
@@ -357,62 +398,38 @@ static void synaptics_pt_create(struct psmouse *psmouse)
357 * Functions to interpret the absolute mode packets 398 * Functions to interpret the absolute mode packets
358 ****************************************************************************/ 399 ****************************************************************************/
359 400
360/* left and right clickpad button ranges; 401static int synaptics_parse_hw_state(unsigned char buf[], struct synaptics_data *priv, struct synaptics_hw_state *hw)
361 * the gap between them is interpreted as a middle-button click
362 */
363#define CLICKPAD_LEFT_BTN_X \
364 ((XMAX_NOMINAL - XMIN_NOMINAL) * 2 / 5 + XMIN_NOMINAL)
365#define CLICKPAD_RIGHT_BTN_X \
366 ((XMAX_NOMINAL - XMIN_NOMINAL) * 3 / 5 + XMIN_NOMINAL)
367
368/* handle clickpad events */
369static void clickpad_process_packet(struct synaptics_data *priv,
370 struct synaptics_hw_state *hw)
371{
372 /* clickpad mode reports Y range from 0 to YMAX_NOMINAL,
373 * where the area Y < YMIN_NOMINAL is used as click buttons
374 */
375 if (hw->y < YMIN_NOMINAL) {
376 /* button area */
377 hw->z = 0; /* don't move pointer */
378 /* clickpad reports only the middle button, and we need
379 * to fake left/right buttons depending on the touch position
380 */
381 if (hw->middle) { /* clicked? */
382 hw->middle = 0;
383 if (hw->x < CLICKPAD_LEFT_BTN_X)
384 hw->left = 1;
385 else if (hw->x > CLICKPAD_RIGHT_BTN_X)
386 hw->right = 1;
387 else
388 hw->middle = 1;
389 }
390 } else if (hw->middle) {
391 /* dragging */
392 hw->left = priv->prev_hw.left;
393 hw->right = priv->prev_hw.right;
394 hw->middle = priv->prev_hw.middle;
395 }
396 priv->prev_hw = *hw;
397}
398
399static void synaptics_parse_hw_state(unsigned char buf[], struct synaptics_data *priv, struct synaptics_hw_state *hw)
400{ 402{
401 memset(hw, 0, sizeof(struct synaptics_hw_state)); 403 memset(hw, 0, sizeof(struct synaptics_hw_state));
402 404
403 if (SYN_MODEL_NEWABS(priv->model_id)) { 405 if (SYN_MODEL_NEWABS(priv->model_id)) {
404 hw->x = (((buf[3] & 0x10) << 8) |
405 ((buf[1] & 0x0f) << 8) |
406 buf[4]);
407 hw->y = (((buf[3] & 0x20) << 7) |
408 ((buf[1] & 0xf0) << 4) |
409 buf[5]);
410
411 hw->z = buf[2];
412 hw->w = (((buf[0] & 0x30) >> 2) | 406 hw->w = (((buf[0] & 0x30) >> 2) |
413 ((buf[0] & 0x04) >> 1) | 407 ((buf[0] & 0x04) >> 1) |
414 ((buf[3] & 0x04) >> 2)); 408 ((buf[3] & 0x04) >> 2));
415 409
410 if (priv->multitouch && hw->w == 2) {
411 /* Multitouch data is half normal resolution */
412 hw->x = (((buf[4] & 0x0f) << 8) |
413 buf[1]) << 1;
414 hw->y = (((buf[4] & 0xf0) << 4) |
415 buf[2]) << 1;
416
417 hw->z = ((buf[3] & 0x30) |
418 (buf[5] & 0x0f)) << 1;
419
420 /* Only look at x, y, and z for MT */
421 return 1;
422 } else {
423 hw->x = (((buf[3] & 0x10) << 8) |
424 ((buf[1] & 0x0f) << 8) |
425 buf[4]);
426 hw->y = (((buf[3] & 0x20) << 7) |
427 ((buf[1] & 0xf0) << 4) |
428 buf[5]);
429
430 hw->z = buf[2];
431 }
432
416 hw->left = (buf[0] & 0x01) ? 1 : 0; 433 hw->left = (buf[0] & 0x01) ? 1 : 0;
417 hw->right = (buf[0] & 0x02) ? 1 : 0; 434 hw->right = (buf[0] & 0x02) ? 1 : 0;
418 435
@@ -468,6 +485,8 @@ static void synaptics_parse_hw_state(unsigned char buf[], struct synaptics_data
468 hw->left = (buf[0] & 0x01) ? 1 : 0; 485 hw->left = (buf[0] & 0x01) ? 1 : 0;
469 hw->right = (buf[0] & 0x02) ? 1 : 0; 486 hw->right = (buf[0] & 0x02) ? 1 : 0;
470 } 487 }
488
489 return 0;
471} 490}
472 491
473/* 492/*
@@ -482,10 +501,11 @@ static void synaptics_process_packet(struct psmouse *psmouse)
482 int finger_width; 501 int finger_width;
483 int i; 502 int i;
484 503
485 synaptics_parse_hw_state(psmouse->packet, priv, &hw); 504 if (synaptics_parse_hw_state(psmouse->packet, priv, &hw)) {
486 505 priv->mt_pkt = 1;
487 if (SYN_CAP_CLICKPAD(priv->ext_cap)) 506 priv->mt = hw;
488 clickpad_process_packet(priv, &hw); 507 return;
508 }
489 509
490 if (hw.scroll) { 510 if (hw.scroll) {
491 priv->scroll += hw.scroll; 511 priv->scroll += hw.scroll;
@@ -513,7 +533,8 @@ static void synaptics_process_packet(struct psmouse *psmouse)
513 if (SYN_CAP_EXTENDED(priv->capabilities)) { 533 if (SYN_CAP_EXTENDED(priv->capabilities)) {
514 switch (hw.w) { 534 switch (hw.w) {
515 case 0 ... 1: 535 case 0 ... 1:
516 if (SYN_CAP_MULTIFINGER(priv->capabilities)) 536 if (SYN_CAP_MULTIFINGER(priv->capabilities) ||
537 priv->multitouch)
517 num_fingers = hw.w + 2; 538 num_fingers = hw.w + 2;
518 break; 539 break;
519 case 2: 540 case 2:
@@ -531,28 +552,64 @@ static void synaptics_process_packet(struct psmouse *psmouse)
531 finger_width = 0; 552 finger_width = 0;
532 } 553 }
533 554
534 /* Post events 555 if (priv->multitouch) {
535 * BTN_TOUCH has to be first as mousedev relies on it when doing 556 struct trk_coord pos[2];
536 * absolute -> relative conversion 557 int slots[2];
537 */ 558 int npos;
538 if (hw.z > 30) input_report_key(dev, BTN_TOUCH, 1); 559
539 if (hw.z < 25) input_report_key(dev, BTN_TOUCH, 0); 560 pos[0].x = hw.x;
561 pos[0].y = YMAX_NOMINAL + YMIN_NOMINAL - hw.y;
562 pos[1].x = priv->mt.x;
563 pos[1].y = YMAX_NOMINAL + YMIN_NOMINAL - priv->mt.y;
564 npos = priv->mt_pkt ? 2 : 1;
565 input_mt_assign_slots_by_coord(dev, slots, pos, npos);
566
567 for (i = 0; i < npos; i++) {
568 int x = pos[i].x;
569 int y = pos[i].y;
570 int z = i == 0 ? hw.z : priv->mt.z;
571 int s = z > 0 && x > 1;
572
573 input_mt_slot(dev, slots[i]);
574 input_mt_report_state(dev, s);
575
576 if (s) {
577 input_report_abs(dev, ABS_MT_POSITION_X, x);
578 input_report_abs(dev, ABS_MT_POSITION_Y, y);
579 input_report_abs(dev, ABS_MT_PRESSURE, z);
580 }
581 }
540 582
541 if (hw.z > 0) { 583 input_mt_sync_slot_complement(dev, slots, npos);
542 input_report_abs(dev, ABS_X, hw.x); 584 input_mt_report_emulation(dev);
543 input_report_abs(dev, ABS_Y, YMAX_NOMINAL + YMIN_NOMINAL - hw.y); 585 } else {
586
587 /* Post events
588 * BTN_TOUCH has to be first as mousedev relies on it when doing
589 * absolute -> relative conversion
590 */
591 if (hw.z > 30) input_report_key(dev, BTN_TOUCH, 1);
592 if (hw.z < 25) input_report_key(dev, BTN_TOUCH, 0);
593
594 if (hw.z > 0) {
595 input_report_abs(dev, ABS_X, hw.x);
596 input_report_abs(dev, ABS_Y, YMAX_NOMINAL + YMIN_NOMINAL - hw.y);
597 }
598 input_report_abs(dev, ABS_PRESSURE, hw.z);
599
600 input_report_key(dev, BTN_TOOL_FINGER, num_fingers == 1);
601
602 if (SYN_CAP_MULTIFINGER(priv->capabilities) || priv->multitouch) {
603 input_report_key(dev, BTN_TOOL_DOUBLETAP, num_fingers == 2);
604 input_report_key(dev, BTN_TOOL_TRIPLETAP, num_fingers == 3);
605 }
544 } 606 }
545 input_report_abs(dev, ABS_PRESSURE, hw.z);
546 607
547 input_report_abs(dev, ABS_TOOL_WIDTH, finger_width);
548 input_report_key(dev, BTN_TOOL_FINGER, num_fingers == 1);
549 input_report_key(dev, BTN_LEFT, hw.left); 608 input_report_key(dev, BTN_LEFT, hw.left);
550 input_report_key(dev, BTN_RIGHT, hw.right); 609 input_report_key(dev, BTN_RIGHT, hw.right);
551 610
552 if (SYN_CAP_MULTIFINGER(priv->capabilities)) { 611 if (SYN_CAP_PALMDETECT(priv->capabilities))
553 input_report_key(dev, BTN_TOOL_DOUBLETAP, num_fingers == 2); 612 input_report_abs(dev, ABS_TOOL_WIDTH, finger_width);
554 input_report_key(dev, BTN_TOOL_TRIPLETAP, num_fingers == 3);
555 }
556 613
557 if (SYN_CAP_MIDDLE_BUTTON(priv->capabilities)) 614 if (SYN_CAP_MIDDLE_BUTTON(priv->capabilities))
558 input_report_key(dev, BTN_MIDDLE, hw.middle); 615 input_report_key(dev, BTN_MIDDLE, hw.middle);
@@ -566,6 +623,8 @@ static void synaptics_process_packet(struct psmouse *psmouse)
566 input_report_key(dev, BTN_0 + i, hw.ext_buttons & (1 << i)); 623 input_report_key(dev, BTN_0 + i, hw.ext_buttons & (1 << i));
567 624
568 input_sync(dev); 625 input_sync(dev);
626
627 priv->mt_pkt = 0;
569} 628}
570 629
571static int synaptics_validate_byte(unsigned char packet[], int idx, unsigned char pkt_type) 630static int synaptics_validate_byte(unsigned char packet[], int idx, unsigned char pkt_type)
@@ -618,9 +677,10 @@ static psmouse_ret_t synaptics_process_byte(struct psmouse *psmouse)
618 if (unlikely(priv->pkt_type == SYN_NEWABS)) 677 if (unlikely(priv->pkt_type == SYN_NEWABS))
619 priv->pkt_type = synaptics_detect_pkt_type(psmouse); 678 priv->pkt_type = synaptics_detect_pkt_type(psmouse);
620 679
621 if (SYN_CAP_PASS_THROUGH(priv->capabilities) && synaptics_is_pt_packet(psmouse->packet)) { 680 if (SYN_CAP_PASS_THROUGH(priv->capabilities) &&
622 if (psmouse->ps2dev.serio->child) 681 synaptics_is_pt_packet(psmouse->packet)) {
623 synaptics_pass_pt_packet(psmouse->ps2dev.serio->child, psmouse->packet); 682 if (priv->pt_port)
683 synaptics_pass_pt_packet(priv->pt_port, psmouse->packet);
624 } else 684 } else
625 synaptics_process_packet(psmouse); 685 synaptics_process_packet(psmouse);
626 686
@@ -644,7 +704,18 @@ static void set_input_params(struct input_dev *dev, struct synaptics_data *priv)
644 input_set_abs_params(dev, ABS_Y, 704 input_set_abs_params(dev, ABS_Y,
645 YMIN_NOMINAL, priv->y_max ?: YMAX_NOMINAL, 0, 0); 705 YMIN_NOMINAL, priv->y_max ?: YMAX_NOMINAL, 0, 0);
646 input_set_abs_params(dev, ABS_PRESSURE, 0, 255, 0, 0); 706 input_set_abs_params(dev, ABS_PRESSURE, 0, 255, 0, 0);
647 __set_bit(ABS_TOOL_WIDTH, dev->absbit); 707
708 if (priv->multitouch) {
709 input_mt_create_slots_new(dev, 2);
710 input_set_abs_params(dev, ABS_MT_POSITION_X, XMIN_NOMINAL,
711 priv->x_max ?: XMAX_NOMINAL, 0, 0);
712 input_set_abs_params(dev, ABS_MT_POSITION_Y, YMIN_NOMINAL,
713 priv->y_max ?: YMAX_NOMINAL, 0, 0);
714 input_set_abs_params(dev, ABS_MT_PRESSURE, 0, 255, 0, 0);
715 }
716
717 if (SYN_CAP_PALMDETECT(priv->capabilities))
718 input_set_abs_params(dev, ABS_TOOL_WIDTH, 0, 15, 0, 0);
648 719
649 __set_bit(EV_KEY, dev->evbit); 720 __set_bit(EV_KEY, dev->evbit);
650 __set_bit(BTN_TOUCH, dev->keybit); 721 __set_bit(BTN_TOUCH, dev->keybit);
@@ -652,7 +723,7 @@ static void set_input_params(struct input_dev *dev, struct synaptics_data *priv)
652 __set_bit(BTN_LEFT, dev->keybit); 723 __set_bit(BTN_LEFT, dev->keybit);
653 __set_bit(BTN_RIGHT, dev->keybit); 724 __set_bit(BTN_RIGHT, dev->keybit);
654 725
655 if (SYN_CAP_MULTIFINGER(priv->capabilities)) { 726 if (SYN_CAP_MULTIFINGER(priv->capabilities) | priv->multitouch) {
656 __set_bit(BTN_TOOL_DOUBLETAP, dev->keybit); 727 __set_bit(BTN_TOOL_DOUBLETAP, dev->keybit);
657 __set_bit(BTN_TOOL_TRIPLETAP, dev->keybit); 728 __set_bit(BTN_TOOL_TRIPLETAP, dev->keybit);
658 } 729 }
@@ -673,8 +744,8 @@ static void set_input_params(struct input_dev *dev, struct synaptics_data *priv)
673 __clear_bit(REL_X, dev->relbit); 744 __clear_bit(REL_X, dev->relbit);
674 __clear_bit(REL_Y, dev->relbit); 745 __clear_bit(REL_Y, dev->relbit);
675 746
676 dev->absres[ABS_X] = priv->x_res; 747 input_abs_set_res(dev, ABS_X, priv->x_res);
677 dev->absres[ABS_Y] = priv->y_res; 748 input_abs_set_res(dev, ABS_Y, priv->y_res);
678 749
679 if (SYN_CAP_CLICKPAD(priv->ext_cap_0c)) { 750 if (SYN_CAP_CLICKPAD(priv->ext_cap_0c)) {
680 /* Clickpads report only left button */ 751 /* Clickpads report only left button */
@@ -716,6 +787,11 @@ static int synaptics_reconnect(struct psmouse *psmouse)
716 return -1; 787 return -1;
717 } 788 }
718 789
790 if (synaptics_set_multitouch_mode(psmouse)) {
791 printk(KERN_ERR "Unable to initialize Synaptics Multitouch.\n");
792 return -1;
793 }
794
719 return 0; 795 return 0;
720} 796}
721 797
@@ -769,7 +845,7 @@ int synaptics_init(struct psmouse *psmouse)
769 845
770 psmouse->private = priv = kzalloc(sizeof(struct synaptics_data), GFP_KERNEL); 846 psmouse->private = priv = kzalloc(sizeof(struct synaptics_data), GFP_KERNEL);
771 if (!priv) 847 if (!priv)
772 return -1; 848 return -ENOMEM;
773 849
774 psmouse_reset(psmouse); 850 psmouse_reset(psmouse);
775 851
@@ -783,6 +859,11 @@ int synaptics_init(struct psmouse *psmouse)
783 goto init_fail; 859 goto init_fail;
784 } 860 }
785 861
862 if (synaptics_set_multitouch_mode(psmouse)) {
863 printk(KERN_ERR "Unable to initialize Synaptics Multitouch.\n");
864 goto init_fail;
865 }
866
786 priv->pkt_type = SYN_MODEL_NEWABS(priv->model_id) ? SYN_NEWABS : SYN_OLDABS; 867 priv->pkt_type = SYN_MODEL_NEWABS(priv->model_id) ? SYN_NEWABS : SYN_OLDABS;
787 868
788 printk(KERN_INFO "Synaptics Touchpad, model: %ld, fw: %ld.%ld, id: %#lx, caps: %#lx/%#lx/%#lx\n", 869 printk(KERN_INFO "Synaptics Touchpad, model: %ld, fw: %ld.%ld, id: %#lx, caps: %#lx/%#lx/%#lx\n",
@@ -790,12 +871,6 @@ int synaptics_init(struct psmouse *psmouse)
790 SYN_ID_MAJOR(priv->identity), SYN_ID_MINOR(priv->identity), 871 SYN_ID_MAJOR(priv->identity), SYN_ID_MINOR(priv->identity),
791 priv->model_id, priv->capabilities, priv->ext_cap, priv->ext_cap_0c); 872 priv->model_id, priv->capabilities, priv->ext_cap, priv->ext_cap_0c);
792 873
793 if (SYN_CAP_CLICKPAD(priv->ext_cap)) {
794 printk(KERN_INFO "Synaptics: Clickpad mode enabled\n");
795 /* force to enable the middle button */
796 priv->capabilities |= (1 << 18);
797 }
798
799 set_input_params(psmouse->dev, priv); 874 set_input_params(psmouse->dev, priv);
800 875
801 /* 876 /*