diff options
| author | Tai-hwa Liang <avatar@sentelic.com> | 2012-03-25 20:16:36 -0400 |
|---|---|---|
| committer | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2012-03-25 20:18:10 -0400 |
| commit | a4c85075f00d56b38f5c277ab89f9aaad69eb17b (patch) | |
| tree | 572cf90d91ec2315d10a5504191b4f8528bef2ce | |
| parent | 3ac1780f9e6ed212e56d4132e997551297a97112 (diff) | |
Input: sentelic - enabling absolute coordinates output for newer hardware
- Hooking multi-finger coordinates output with kernel multitouch library;
- Enabling absolute coordinates output for Cx+ hardware. The older hardware
performs much better in relative mode; thus relative mode related code
are preserved.
Part of the code is based on the work done by Oskari Saarenmaa <os@ohmu.fi>,
which was used to support the clickpad found on ASUS UX21/31 Ultrabook.
On the other hand, the FSP found on UX21/31 doesn't have hardware capability
register other than PnP ID, which means that we'll have to figure out an
alternative approach to identify such pad correctly; otherwise, blindly
adding INPUT_PROP_BUTTONPAD property may compatability issues amongst
existing FSPs.
Signed-off-by: Tai-hwa Liang <avatar@sentelic.com>
Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
| -rw-r--r-- | drivers/input/mouse/sentelic.c | 114 | ||||
| -rw-r--r-- | drivers/input/mouse/sentelic.h | 22 |
2 files changed, 132 insertions, 4 deletions
diff --git a/drivers/input/mouse/sentelic.c b/drivers/input/mouse/sentelic.c index 62fa69825671..5ea5c689d262 100644 --- a/drivers/input/mouse/sentelic.c +++ b/drivers/input/mouse/sentelic.c | |||
| @@ -2,7 +2,7 @@ | |||
| 2 | * Finger Sensing Pad PS/2 mouse driver. | 2 | * Finger Sensing Pad PS/2 mouse driver. |
| 3 | * | 3 | * |
| 4 | * Copyright (C) 2005-2007 Asia Vital Components Co., Ltd. | 4 | * Copyright (C) 2005-2007 Asia Vital Components Co., Ltd. |
| 5 | * Copyright (C) 2005-2011 Tai-hwa Liang, Sentelic Corporation. | 5 | * Copyright (C) 2005-2012 Tai-hwa Liang, Sentelic Corporation. |
| 6 | * | 6 | * |
| 7 | * This program is free software; you can redistribute it and/or | 7 | * This program is free software; you can redistribute it and/or |
| 8 | * modify it under the terms of the GNU General Public License | 8 | * modify it under the terms of the GNU General Public License |
| @@ -21,6 +21,7 @@ | |||
| 21 | 21 | ||
| 22 | #include <linux/module.h> | 22 | #include <linux/module.h> |
| 23 | #include <linux/input.h> | 23 | #include <linux/input.h> |
| 24 | #include <linux/input/mt.h> | ||
| 24 | #include <linux/ctype.h> | 25 | #include <linux/ctype.h> |
| 25 | #include <linux/libps2.h> | 26 | #include <linux/libps2.h> |
| 26 | #include <linux/serio.h> | 27 | #include <linux/serio.h> |
| @@ -643,12 +644,24 @@ static void fsp_packet_debug(unsigned char packet[]) | |||
| 643 | } | 644 | } |
| 644 | #endif | 645 | #endif |
| 645 | 646 | ||
| 647 | static void fsp_set_slot(struct input_dev *dev, int slot, bool active, | ||
| 648 | unsigned int x, unsigned int y) | ||
| 649 | { | ||
| 650 | input_mt_slot(dev, slot); | ||
| 651 | input_mt_report_slot_state(dev, MT_TOOL_FINGER, active); | ||
| 652 | if (active) { | ||
| 653 | input_report_abs(dev, ABS_MT_POSITION_X, x); | ||
| 654 | input_report_abs(dev, ABS_MT_POSITION_Y, y); | ||
| 655 | } | ||
| 656 | } | ||
| 657 | |||
| 646 | static psmouse_ret_t fsp_process_byte(struct psmouse *psmouse) | 658 | static psmouse_ret_t fsp_process_byte(struct psmouse *psmouse) |
| 647 | { | 659 | { |
| 648 | struct input_dev *dev = psmouse->dev; | 660 | struct input_dev *dev = psmouse->dev; |
| 649 | struct fsp_data *ad = psmouse->private; | 661 | struct fsp_data *ad = psmouse->private; |
| 650 | unsigned char *packet = psmouse->packet; | 662 | unsigned char *packet = psmouse->packet; |
| 651 | unsigned char button_status = 0, lscroll = 0, rscroll = 0; | 663 | unsigned char button_status = 0, lscroll = 0, rscroll = 0; |
| 664 | unsigned short abs_x, abs_y, fgrs = 0; | ||
| 652 | int rel_x, rel_y; | 665 | int rel_x, rel_y; |
| 653 | 666 | ||
| 654 | if (psmouse->pktcnt < 4) | 667 | if (psmouse->pktcnt < 4) |
| @@ -660,8 +673,66 @@ static psmouse_ret_t fsp_process_byte(struct psmouse *psmouse) | |||
| 660 | 673 | ||
| 661 | switch (psmouse->packet[0] >> FSP_PKT_TYPE_SHIFT) { | 674 | switch (psmouse->packet[0] >> FSP_PKT_TYPE_SHIFT) { |
| 662 | case FSP_PKT_TYPE_ABS: | 675 | case FSP_PKT_TYPE_ABS: |
| 663 | psmouse_warn(psmouse, | 676 | abs_x = (packet[1] << 2) | ((packet[3] >> 2) & 0x03); |
| 664 | "Unexpected absolute mode packet, ignored.\n"); | 677 | abs_y = (packet[2] << 2) | (packet[3] & 0x03); |
| 678 | |||
| 679 | if (packet[0] & FSP_PB0_MFMC) { | ||
| 680 | /* | ||
| 681 | * MFMC packet: assume that there are two fingers on | ||
| 682 | * pad | ||
| 683 | */ | ||
| 684 | fgrs = 2; | ||
| 685 | |||
| 686 | /* MFMC packet */ | ||
| 687 | if (packet[0] & FSP_PB0_MFMC_FGR2) { | ||
| 688 | /* 2nd finger */ | ||
| 689 | if (ad->last_mt_fgr == 2) { | ||
| 690 | /* | ||
| 691 | * workaround for buggy firmware | ||
| 692 | * which doesn't clear MFMC bit if | ||
| 693 | * the 1st finger is up | ||
| 694 | */ | ||
| 695 | fgrs = 1; | ||
| 696 | fsp_set_slot(dev, 0, false, 0, 0); | ||
| 697 | } | ||
| 698 | ad->last_mt_fgr = 2; | ||
| 699 | |||
| 700 | fsp_set_slot(dev, 1, fgrs == 2, abs_x, abs_y); | ||
| 701 | } else { | ||
| 702 | /* 1st finger */ | ||
| 703 | if (ad->last_mt_fgr == 1) { | ||
| 704 | /* | ||
| 705 | * workaround for buggy firmware | ||
| 706 | * which doesn't clear MFMC bit if | ||
| 707 | * the 2nd finger is up | ||
| 708 | */ | ||
| 709 | fgrs = 1; | ||
| 710 | fsp_set_slot(dev, 1, false, 0, 0); | ||
| 711 | } | ||
| 712 | ad->last_mt_fgr = 1; | ||
| 713 | fsp_set_slot(dev, 0, fgrs != 0, abs_x, abs_y); | ||
| 714 | } | ||
| 715 | } else { | ||
| 716 | /* SFAC packet */ | ||
| 717 | |||
| 718 | /* no multi-finger information */ | ||
| 719 | ad->last_mt_fgr = 0; | ||
| 720 | |||
| 721 | if (abs_x != 0 && abs_y != 0) | ||
| 722 | fgrs = 1; | ||
| 723 | |||
| 724 | fsp_set_slot(dev, 0, fgrs > 0, abs_x, abs_y); | ||
| 725 | fsp_set_slot(dev, 1, false, 0, 0); | ||
| 726 | } | ||
| 727 | if (fgrs > 0) { | ||
| 728 | input_report_abs(dev, ABS_X, abs_x); | ||
| 729 | input_report_abs(dev, ABS_Y, abs_y); | ||
| 730 | } | ||
| 731 | input_report_key(dev, BTN_LEFT, packet[0] & 0x01); | ||
| 732 | input_report_key(dev, BTN_RIGHT, packet[0] & 0x02); | ||
| 733 | input_report_key(dev, BTN_TOUCH, fgrs); | ||
| 734 | input_report_key(dev, BTN_TOOL_FINGER, fgrs == 1); | ||
| 735 | input_report_key(dev, BTN_TOOL_DOUBLETAP, fgrs == 2); | ||
| 665 | break; | 736 | break; |
| 666 | 737 | ||
| 667 | case FSP_PKT_TYPE_NORMAL_OPC: | 738 | case FSP_PKT_TYPE_NORMAL_OPC: |
| @@ -785,6 +856,17 @@ static int fsp_activate_protocol(struct psmouse *psmouse) | |||
| 785 | /* Enable on-pad vertical and horizontal scrolling */ | 856 | /* Enable on-pad vertical and horizontal scrolling */ |
| 786 | fsp_onpad_vscr(psmouse, true); | 857 | fsp_onpad_vscr(psmouse, true); |
| 787 | fsp_onpad_hscr(psmouse, true); | 858 | fsp_onpad_hscr(psmouse, true); |
| 859 | } else { | ||
| 860 | /* Enable absolute coordinates output for Cx/Dx hardware */ | ||
| 861 | if (fsp_reg_write(psmouse, FSP_REG_SWC1, | ||
| 862 | FSP_BIT_SWC1_EN_ABS_1F | | ||
| 863 | FSP_BIT_SWC1_EN_ABS_2F | | ||
| 864 | FSP_BIT_SWC1_EN_FUP_OUT | | ||
| 865 | FSP_BIT_SWC1_EN_ABS_CON)) { | ||
| 866 | psmouse_err(psmouse, | ||
| 867 | "Unable to enable absolute coordinates output.\n"); | ||
| 868 | return -EIO; | ||
| 869 | } | ||
| 788 | } | 870 | } |
| 789 | 871 | ||
| 790 | return 0; | 872 | return 0; |
| @@ -801,6 +883,32 @@ static int fsp_set_input_params(struct psmouse *psmouse) | |||
| 801 | __set_bit(BTN_FORWARD, dev->keybit); | 883 | __set_bit(BTN_FORWARD, dev->keybit); |
| 802 | __set_bit(REL_WHEEL, dev->relbit); | 884 | __set_bit(REL_WHEEL, dev->relbit); |
| 803 | __set_bit(REL_HWHEEL, dev->relbit); | 885 | __set_bit(REL_HWHEEL, dev->relbit); |
| 886 | } else { | ||
| 887 | /* | ||
| 888 | * Hardware prior to Cx performs much better in relative mode; | ||
| 889 | * hence, only enable absolute coordinates output as well as | ||
| 890 | * multi-touch output for the newer hardware. | ||
| 891 | * | ||
| 892 | * Maximum coordinates can be computed as: | ||
| 893 | * | ||
| 894 | * number of scanlines * 64 - 57 | ||
| 895 | * | ||
| 896 | * where number of X/Y scanline lines are 16/12. | ||
| 897 | */ | ||
| 898 | int abs_x = 967, abs_y = 711; | ||
| 899 | |||
| 900 | __set_bit(EV_ABS, dev->evbit); | ||
| 901 | __clear_bit(EV_REL, dev->evbit); | ||
| 902 | __set_bit(BTN_TOUCH, dev->keybit); | ||
| 903 | __set_bit(BTN_TOOL_FINGER, dev->keybit); | ||
| 904 | __set_bit(BTN_TOOL_DOUBLETAP, dev->keybit); | ||
| 905 | __set_bit(INPUT_PROP_SEMI_MT, dev->propbit); | ||
| 906 | |||
| 907 | input_set_abs_params(dev, ABS_X, 0, abs_x, 0, 0); | ||
| 908 | input_set_abs_params(dev, ABS_Y, 0, abs_y, 0, 0); | ||
| 909 | input_mt_init_slots(dev, 2); | ||
| 910 | input_set_abs_params(dev, ABS_MT_POSITION_X, 0, abs_x, 0, 0); | ||
| 911 | input_set_abs_params(dev, ABS_MT_POSITION_Y, 0, abs_y, 0, 0); | ||
| 804 | } | 912 | } |
| 805 | 913 | ||
| 806 | return 0; | 914 | return 0; |
diff --git a/drivers/input/mouse/sentelic.h b/drivers/input/mouse/sentelic.h index 23bd25e539ba..334de19e5ddb 100644 --- a/drivers/input/mouse/sentelic.h +++ b/drivers/input/mouse/sentelic.h | |||
| @@ -2,7 +2,7 @@ | |||
| 2 | * Finger Sensing Pad PS/2 mouse driver. | 2 | * Finger Sensing Pad PS/2 mouse driver. |
| 3 | * | 3 | * |
| 4 | * Copyright (C) 2005-2007 Asia Vital Components Co., Ltd. | 4 | * Copyright (C) 2005-2007 Asia Vital Components Co., Ltd. |
| 5 | * Copyright (C) 2005-2011 Tai-hwa Liang, Sentelic Corporation. | 5 | * Copyright (C) 2005-2012 Tai-hwa Liang, Sentelic Corporation. |
| 6 | * | 6 | * |
| 7 | * This program is free software; you can redistribute it and/or | 7 | * This program is free software; you can redistribute it and/or |
| 8 | * modify it under the terms of the GNU General Public License | 8 | * modify it under the terms of the GNU General Public License |
| @@ -55,6 +55,16 @@ | |||
| 55 | #define FSP_BIT_FIX_HSCR BIT(5) | 55 | #define FSP_BIT_FIX_HSCR BIT(5) |
| 56 | #define FSP_BIT_DRAG_LOCK BIT(6) | 56 | #define FSP_BIT_DRAG_LOCK BIT(6) |
| 57 | 57 | ||
| 58 | #define FSP_REG_SWC1 (0x90) | ||
| 59 | #define FSP_BIT_SWC1_EN_ABS_1F BIT(0) | ||
| 60 | #define FSP_BIT_SWC1_EN_GID BIT(1) | ||
| 61 | #define FSP_BIT_SWC1_EN_ABS_2F BIT(2) | ||
| 62 | #define FSP_BIT_SWC1_EN_FUP_OUT BIT(3) | ||
| 63 | #define FSP_BIT_SWC1_EN_ABS_CON BIT(4) | ||
| 64 | #define FSP_BIT_SWC1_GST_GRP0 BIT(5) | ||
| 65 | #define FSP_BIT_SWC1_GST_GRP1 BIT(6) | ||
| 66 | #define FSP_BIT_SWC1_BX_COMPAT BIT(7) | ||
| 67 | |||
| 58 | /* Finger-sensing Pad packet formating related definitions */ | 68 | /* Finger-sensing Pad packet formating related definitions */ |
| 59 | 69 | ||
| 60 | /* absolute packet type */ | 70 | /* absolute packet type */ |
| @@ -64,6 +74,15 @@ | |||
| 64 | #define FSP_PKT_TYPE_NORMAL_OPC (0x03) | 74 | #define FSP_PKT_TYPE_NORMAL_OPC (0x03) |
| 65 | #define FSP_PKT_TYPE_SHIFT (6) | 75 | #define FSP_PKT_TYPE_SHIFT (6) |
| 66 | 76 | ||
| 77 | /* bit definitions for the first byte of report packet */ | ||
| 78 | #define FSP_PB0_LBTN BIT(0) | ||
| 79 | #define FSP_PB0_RBTN BIT(1) | ||
| 80 | #define FSP_PB0_MBTN BIT(2) | ||
| 81 | #define FSP_PB0_MFMC_FGR2 FSP_PB0_MBTN | ||
| 82 | #define FSP_PB0_MUST_SET BIT(3) | ||
| 83 | #define FSP_PB0_PHY_BTN BIT(4) | ||
| 84 | #define FSP_PB0_MFMC BIT(5) | ||
| 85 | |||
| 67 | /* hardware revisions */ | 86 | /* hardware revisions */ |
| 68 | #define FSP_VER_STL3888_A4 (0xC1) | 87 | #define FSP_VER_STL3888_A4 (0xC1) |
| 69 | #define FSP_VER_STL3888_B0 (0xD0) | 88 | #define FSP_VER_STL3888_B0 (0xD0) |
| @@ -89,6 +108,7 @@ struct fsp_data { | |||
| 89 | 108 | ||
| 90 | unsigned char last_reg; /* Last register we requested read from */ | 109 | unsigned char last_reg; /* Last register we requested read from */ |
| 91 | unsigned char last_val; | 110 | unsigned char last_val; |
| 111 | unsigned int last_mt_fgr; /* Last seen finger(multitouch) */ | ||
| 92 | }; | 112 | }; |
| 93 | 113 | ||
| 94 | #ifdef CONFIG_MOUSE_PS2_SENTELIC | 114 | #ifdef CONFIG_MOUSE_PS2_SENTELIC |
