On Sat, 28 Jan 2012, Dmitry Torokhov wrote:
Hi Oskari,
On Wed, Jan 25, 2012 at 01:22:54AM +0200, Oskari Saarenmaa wrote:
- Implement absolute position mode and multitouch support for Cx+ revision
hardware based on latest documentation provided by Sentelic.
- Supports two-finger horizontal and vertical scrolling, edge scrolling and
clicks on the clickpad. Hardware click-on-tap is disabled.
The patch was developed and tested on an ASUS Zenbook UX21E.
Signed-off-by: Oskari Saarenmaa <os@xxxxxxx>
Adding Tai-hwa Liang so he has a chance to comment. Also some comments
below...
Sorry for the late response. Just returned from Chinese lunar New Year
holiday...
---
drivers/input/mouse/sentelic.c | 149 +++++++++++++++++++++++++++++++++++++---
drivers/input/mouse/sentelic.h | 8 ++
2 files changed, 148 insertions(+), 9 deletions(-)
diff --git a/drivers/input/mouse/sentelic.c b/drivers/input/mouse/sentelic.c
index 87c910d..e851cf5 100644
--- a/drivers/input/mouse/sentelic.c
+++ b/drivers/input/mouse/sentelic.c
@@ -21,6 +21,7 @@
#include <linux/module.h>
#include <linux/input.h>
+#include <linux/input/mt.h>
#include <linux/ctype.h>
#include <linux/libps2.h>
#include <linux/serio.h>
@@ -37,7 +38,7 @@
#define FSP_CMD_TIMEOUT2 30
/** Driver version. */
-static const char fsp_drv_ver[] = "1.0.0-K";
+static const char fsp_drv_ver[] = "1.0.0-K-OS1";
/*
* Make sure that the value being sent to FSP will not conflict with
@@ -671,8 +672,11 @@ static psmouse_ret_t fsp_process_byte(struct psmouse *psmouse)
struct input_dev *dev = psmouse->dev;
struct fsp_data *ad = psmouse->private;
unsigned char *packet = psmouse->packet;
- unsigned char button_status = 0, lscroll = 0, rscroll = 0;
+ unsigned short abs_x, abs_y, fingers = 0;
+ unsigned short vscroll = 0, hscroll = 0, lscroll = 0, rscroll = 0;
+ unsigned short l_btn, r_btn, m_btn;
int rel_x, rel_y;
+ static bool lifted;
if (psmouse->pktcnt < 4)
return PSMOUSE_GOOD_DATA;
@@ -684,9 +688,97 @@ static psmouse_ret_t fsp_process_byte(struct psmouse *psmouse)
fsp_packet_debug(psmouse, packet);
switch (psmouse->packet[0] >> FSP_PKT_TYPE_SHIFT) {
+ case FSP_PKT_TYPE_NOTIFY:
+ /* Notify packets are sent with Cx and newer
+ * touchpads if register 0x90 bit 1 is set.
+ */
+ switch (packet[2]) {
+ case 0x86:
+ vscroll = 1;
+ break;
+ case 0x82:
+ vscroll = -1;
+ break;
+ case 0x84:
+ hscroll = 1;
+ break;
+ case 0x80:
Based on Oskari's version, the attached patch also turns these magic
numbers into pre-defined constants(patch against Dmitry's master branch).
Perhaps you guys could have some time to take a look at it?
Note that I only tested the compilation part as I don't have the real
hardware due to holiday shutdown. Will need to test these after getting
back to the office.
+ hscroll = -1;
+ break;
+ }
+ input_report_rel(dev, REL_WHEEL, vscroll);
+ input_report_rel(dev, REL_HWHEEL, hscroll);
+ break;
Do we need to support the non-absolute mode if we can support absolute
mode for the device? Users expect to have true multi-touch support
nowadays, I think we should keep the driver as simple as possible and
support only absolute mode for MT devices.
This is true for newer hardware; however, it would be better to stick
with relative mode for older hardware(ex: FSP found on OLPC) since the
relative coordination outputs are much better on them when compared with
abs. outputs.
+
case FSP_PKT_TYPE_ABS:
- dev_warn(&psmouse->ps2dev.serio->dev,
- "Unexpected absolute mode packet, ignored.\n");
+ /* Absolute packets are sent with version Cx and newer
+ * touchpads if register 0x90 bit 0 is set.
+ */
+ abs_x = (packet[1] << 2) | ((packet[3] >> 2) & 0x03);
+ abs_y = (packet[2] << 2) | (packet[3] & 0x03);
+
+ l_btn = packet[0] & BIT(0);
+ r_btn = packet[0] & BIT(1);
+ m_btn = packet[0] & BIT(2);
+
+ if (packet[1] || packet[2] || packet[3]) {
+ /* at least one finger is down */
+ fingers++;
+ lifted = false;
+ } else {
+ if (lifted == false) {
+ lifted = true;
+ return PSMOUSE_FULL_PACKET;
+ }
+ }
+
+ if ((packet[0] & (BIT(4)|BIT(5))) == 0 && l_btn) {
+ /* on pad click, let other components handle this.
+ * NOTE: do not filter out on-pad clicks when
+ * we're in multitouch mode, BIT(5), they are real
+ * clickpad-clicks, not just single finger taps.
+ */
+ l_btn = 0;
Hmm, so this is a clickpad device? We need to set clickpad property
then.
I presume you're talking about something like SYN_CAP_CLICKPAD() in
synaptics.c? Given that retrieving capability information would incur
more register reading overhead, I'm wondering about if there's any
way to read PnP ID in psmouse.c such that sentelic.c can take advantage
of these vendor specific tags to identify the hardware capability?
+ }
+
+ if (packet[0] & BIT(5)) {
+ /* multitouch mode: two fingers down */
+ fingers++;
+ if ((packet[0] & BIT(4)) == 0 && l_btn && r_btn) {
+ /* middle-click in multitouch mode */
+ l_btn = 0;
+ r_btn = 0;
+ m_btn = 1;
+ }
The middle button emulation should be handled in userspace. Let
synaptics X driver deal with it.
Agreed.
+ if (packet[0] & BIT(2)) {
+ /* right finger down, ignore the event */
Needs better comment.
+ return PSMOUSE_FULL_PACKET;
+ }
+ }
+
+ input_report_key(dev, BTN_TOUCH, fingers > 0);
+ input_report_abs(dev, ABS_X, abs_x);
+ input_report_abs(dev, ABS_Y, abs_y);
+
+ input_mt_slot(dev, 0);
+ input_mt_report_slot_state(dev, MT_TOOL_FINGER, fingers >= 1);
+ if (fingers >= 1) {
+ input_report_abs(dev, ABS_MT_POSITION_X, abs_x);
+ input_report_abs(dev, ABS_MT_POSITION_Y, abs_y);
+ }
+
+ input_mt_slot(dev, 1);
+ input_mt_report_slot_state(dev, MT_TOOL_FINGER, fingers >= 2);
+ if (fingers >= 2) {
+ input_report_abs(dev, ABS_MT_POSITION_X, abs_x);
+ input_report_abs(dev, ABS_MT_POSITION_Y, abs_y);
+ }
+
+ input_report_key(dev, BTN_TOOL_FINGER, fingers == 1);
+ input_report_key(dev, BTN_TOOL_DOUBLETAP, fingers == 2);
+ input_report_key(dev, BTN_LEFT, l_btn);
+ input_report_key(dev, BTN_MIDDLE, m_btn);
+ input_report_key(dev, BTN_RIGHT, r_btn);
break;
case FSP_PKT_TYPE_NORMAL_OPC:
@@ -699,6 +791,7 @@ static psmouse_ret_t fsp_process_byte(struct psmouse *psmouse)
/* normal packet */
/* special packet data translation from on-pad packets */
if (packet[3] != 0) {
+ unsigned char button_status = 0;
if (packet[3] & BIT(0))
button_status |= 0x01; /* wheel down */
if (packet[3] & BIT(1))
@@ -776,6 +869,7 @@ static int fsp_activate_protocol(struct psmouse *psmouse)
val &= ~(FSP_BIT_EN_MSID7 | FSP_BIT_EN_MSID8 | FSP_BIT_EN_AUTO_MSID8);
/* Ensure we are not in absolute mode */
val &= ~FSP_BIT_EN_PKT_G0;
+
if (pad->buttons == 0x06) {
/* Left/Middle/Right & Scroll Up/Down/Right/Left */
val |= FSP_BIT_EN_MSID6;
@@ -799,6 +893,19 @@ static int fsp_activate_protocol(struct psmouse *psmouse)
fsp_onpad_vscr(psmouse, true);
fsp_onpad_hscr(psmouse, true);
+ /* Enable absolute positioning, two finger mode and continuous output
+ * on Cx and newer pads (version ID 0xE0+)
+ */
+ if (pad->ver >= 0xE0) {
+ val = FSP_CX_ABSOLUTE_MODE |
+ FSP_CX_2FINGERS_OUTPUT |
+ FSP_CX_CONTINUOUS_MODE;
+ if (fsp_reg_write(psmouse, FSP_REG_SWREG1, val)) {
+ dev_warn(&psmouse->ps2dev.serio->dev,
+ "Failed to enable multitouch settings.\n");
+ }
+ }
+
return 0;
}
@@ -854,6 +961,7 @@ static int fsp_reconnect(struct psmouse *psmouse)
int fsp_init(struct psmouse *psmouse)
{
+ struct input_dev *dev = psmouse->dev;
struct fsp_data *priv;
int ver, rev, buttons;
int error;
@@ -880,11 +988,34 @@ int fsp_init(struct psmouse *psmouse)
priv->flags |= FSPDRV_FLAG_EN_OPC;
/* Set up various supported input event bits */
- __set_bit(BTN_MIDDLE, psmouse->dev->keybit);
- __set_bit(BTN_BACK, psmouse->dev->keybit);
- __set_bit(BTN_FORWARD, psmouse->dev->keybit);
- __set_bit(REL_WHEEL, psmouse->dev->relbit);
- __set_bit(REL_HWHEEL, psmouse->dev->relbit);
+ __set_bit(BTN_MIDDLE, dev->keybit);
+ __set_bit(BTN_BACK, dev->keybit);
+ __set_bit(BTN_FORWARD, dev->keybit);
+ __set_bit(REL_WHEEL, dev->relbit);
+ __set_bit(REL_HWHEEL, dev->relbit);
+
+ /* Set up multitouch mode on Cx+ version hardware (reg value 0xE0+)
+ * for example ASUS Zenbook UX21E has Sentelic touchpad version 0xE3
+ */
+ if (ver >= 0xE0) {
+ /* NOTE: maximum values are not documented anywhere and are
+ * not available in any register, these are the maximum
+ * values reported by a Zenbook.
+ */
+ int abs_x = 965, abs_y = 705;
+
+ __set_bit(EV_ABS, dev->evbit);
+ __clear_bit(EV_REL, dev->evbit);
+ __set_bit(BTN_TOUCH, dev->keybit);
+ __set_bit(BTN_TOOL_FINGER, dev->keybit);
+ __set_bit(BTN_TOOL_DOUBLETAP, dev->keybit);
+
+ input_set_abs_params(dev, ABS_X, 0, abs_x, 0, 0);
+ input_set_abs_params(dev, ABS_Y, 0, abs_y, 0, 0);
+ input_mt_init_slots(dev, 2);
+ input_set_abs_params(dev, ABS_MT_POSITION_X, 0, abs_x, 0, 0);
+ input_set_abs_params(dev, ABS_MT_POSITION_Y, 0, abs_y, 0, 0);
+ }
psmouse->protocol_handler = fsp_process_byte;
psmouse->disconnect = fsp_disconnect;
diff --git a/drivers/input/mouse/sentelic.h b/drivers/input/mouse/sentelic.h
index 2e4af24..c72ca5e 100644
--- a/drivers/input/mouse/sentelic.h
+++ b/drivers/input/mouse/sentelic.h
@@ -41,6 +41,7 @@
#define FSP_REG_OPTZ_YLO 0x36
#define FSP_REG_OPTZ_YHI 0x37
#define FSP_REG_SYSCTL5 0x40
+#define FSP_REG_SWREG1 0x90
#define FSP_BIT_90_DEGREE BIT(0)
#define FSP_BIT_EN_MSID6 BIT(1)
#define FSP_BIT_EN_MSID7 BIT(2)
@@ -64,6 +65,13 @@
#define FSP_PKT_TYPE_NORMAL_OPC (0x03)
#define FSP_PKT_TYPE_SHIFT (6)
+/* swreg1 values, supported in Cx hardware */
+#define FSP_CX_ABSOLUTE_MODE BIT(0)
+#define FSP_CX_GESTURE_OUTPUT BIT(1)
+#define FSP_CX_2FINGERS_OUTPUT BIT(2)
+#define FSP_CX_FINGER_UP_OUTPUT BIT(3)
+#define FSP_CX_CONTINUOUS_MODE BIT(4)
+
#ifdef __KERNEL__
struct fsp_data {
--
1.7.7.6
Thanks.
--
Sincerely yours,
Tai-hwa Liang
diff --git a/drivers/input/mouse/sentelic.c b/drivers/input/mouse/sentelic.c
index 5babc47..1f1f023 100644
--- a/drivers/input/mouse/sentelic.c
+++ b/drivers/input/mouse/sentelic.c
@@ -2,7 +2,7 @@
* Finger Sensing Pad PS/2 mouse driver.
*
* Copyright (C) 2005-2007 Asia Vital Components Co., Ltd.
- * Copyright (C) 2005-2010 Tai-hwa Liang, Sentelic Corporation.
+ * Copyright (C) 2005-2012 Tai-hwa Liang, Sentelic Corporation.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -20,7 +20,9 @@
*/
#include <linux/module.h>
+#include <linux/version.h>
#include <linux/input.h>
+#include <linux/input/mt.h>
#include <linux/ctype.h>
#include <linux/libps2.h>
#include <linux/serio.h>
@@ -162,7 +164,7 @@ static int fsp_reg_write(struct psmouse *psmouse, int reg_addr, int reg_val)
ps2_sendbyte(ps2dev, v, FSP_CMD_TIMEOUT2);
if (ps2_sendbyte(ps2dev, 0xf3, FSP_CMD_TIMEOUT) < 0)
- return -1;
+ goto out;
if ((v = fsp_test_invert_cmd(reg_val)) != reg_val) {
/* inversion is required */
@@ -261,7 +263,7 @@ static int fsp_page_reg_write(struct psmouse *psmouse, int reg_val)
ps2_sendbyte(ps2dev, 0x88, FSP_CMD_TIMEOUT2);
if (ps2_sendbyte(ps2dev, 0xf3, FSP_CMD_TIMEOUT) < 0)
- return -1;
+ goto out;
if ((v = fsp_test_invert_cmd(reg_val)) != reg_val) {
ps2_sendbyte(ps2dev, 0x47, FSP_CMD_TIMEOUT2);
@@ -309,7 +311,7 @@ static int fsp_get_buttons(struct psmouse *psmouse, int *btn)
};
int val;
- if (fsp_reg_read(psmouse, FSP_REG_TMOD_STATUS1, &val) == -1)
+ if (fsp_reg_read(psmouse, FSP_REG_TMOD_STATUS, &val) == -1)
return -EIO;
*btn = buttons[(val & 0x30) >> 4];
@@ -620,17 +622,35 @@ static struct attribute_group fsp_attribute_group = {
};
#ifdef FSP_DEBUG
-static void fsp_packet_debug(unsigned char packet[])
+static void fsp_packet_debug(struct psmouse *psmouse, unsigned char packet[])
{
static unsigned int ps2_packet_cnt;
static unsigned int ps2_last_second;
unsigned int jiffies_msec;
+ const char *packet_type = "UNKNOWN";
+
+ /* Interpret & dump the packet data. */
+ switch (psmouse->packet[0] >> FSP_PKT_TYPE_SHIFT) {
+ case FSP_PKT_TYPE_ABS:
+ packet_type = "Absolute";
+ break;
+ case FSP_PKT_TYPE_NORMAL:
+ packet_type = "Normal";
+ break;
+ case FSP_PKT_TYPE_NOTIFY:
+ packet_type = "Notify";
+ break;
+ case FSP_PKT_TYPE_NORMAL_OPC:
+ packet_type = "Normal-OPC";
+ break;
+ }
ps2_packet_cnt++;
jiffies_msec = jiffies_to_msecs(jiffies);
psmouse_dbg(psmouse,
- "%08dms PS/2 packets: %02x, %02x, %02x, %02x\n",
- jiffies_msec, packet[0], packet[1], packet[2], packet[3]);
+ "%08dms %s packet: %02x, %02x, %02x, %02x\n",
+ jiffies_msec, packet_type,
+ packet[0], packet[1], packet[2], packet[3]);
if (jiffies_msec - ps2_last_second > 1000) {
psmouse_dbg(psmouse, "PS/2 packets/sec = %d\n", ps2_packet_cnt);
@@ -639,17 +659,29 @@ static void fsp_packet_debug(unsigned char packet[])
}
}
#else
-static void fsp_packet_debug(unsigned char packet[])
+static void fsp_packet_debug(struct psmouse *psmouse, unsigned char packet[])
{
}
#endif
+static void fsp_set_slot(struct input_dev *dev, int slot, bool active,
+ unsigned int x, unsigned int y)
+{
+ input_mt_slot(dev, slot);
+ input_mt_report_slot_state(dev, MT_TOOL_FINGER, active);
+ if (active) {
+ input_report_abs(dev, ABS_MT_POSITION_X, x);
+ input_report_abs(dev, ABS_MT_POSITION_Y, y);
+ }
+}
+
static psmouse_ret_t fsp_process_byte(struct psmouse *psmouse)
{
struct input_dev *dev = psmouse->dev;
struct fsp_data *ad = psmouse->private;
unsigned char *packet = psmouse->packet;
- unsigned char button_status = 0, lscroll = 0, rscroll = 0;
+ unsigned short abs_x, abs_y, fgrs = 0;
+ unsigned short vscroll = 0, hscroll = 0, lscroll = 0, rscroll = 0;
int rel_x, rel_y;
if (psmouse->pktcnt < 4)
@@ -660,21 +692,107 @@ static psmouse_ret_t fsp_process_byte(struct psmouse *psmouse)
*/
switch (psmouse->packet[0] >> FSP_PKT_TYPE_SHIFT) {
+ case FSP_PKT_TYPE_NOTIFY:
+ if (packet[1] != FSP_NOTIFY_MSG_GID)
+ break; /* unsupported message types */
+
+ switch (packet[2]) {
+ case FSP_GID_SP_UP:
+ vscroll = 1;
+ break;
+ case FSP_GID_SP_DOWN:
+ vscroll = -1;
+ break;
+ case FSP_GID_SP_LEFT:
+ hscroll = 1;
+ break;
+ case FSP_GID_SP_RIGHT:
+ hscroll = -1;
+ break;
+ default:
+ dev_dbg(&psmouse->ps2dev.serio->dev,
+ "GID 0x%x\n", packet[2]);
+ break;
+ }
+ input_report_rel(dev, REL_WHEEL, vscroll);
+ input_report_rel(dev, REL_HWHEEL, hscroll);
+ input_event(dev, EV_MSC, MSC_GESTURE, packet[2]);
+ break;
+
case FSP_PKT_TYPE_ABS:
- dev_warn(&psmouse->ps2dev.serio->dev,
- "Unexpected absolute mode packet, ignored.\n");
+ abs_x = (packet[1] << 2) | ((packet[3] >> 2) & 0x03);
+ abs_y = (packet[2] << 2) | (packet[3] & 0x03);
+
+ if (packet[0] & FSP_PB0_MFMC) {
+ /*
+ * MFMC packet: assume that there are two fingers on
+ * pad
+ */
+ fgrs = 2;
+
+ /* MFMC packet */
+ if (packet[0] & FSP_PB0_MFMC_FGR2) {
+ /* 2nd finger */
+ if (ad->last_mt_fgr == 2) {
+ /*
+ * workaround for buggy firmware
+ * which doesn't clear MFMC bit if
+ * the 1st finger is up
+ */
+ fgrs = 1;
+ fsp_set_slot(dev, 0, false, 0, 0);
+ }
+ ad->last_mt_fgr = 2;
+
+ fsp_set_slot(dev, 1, fgrs == 2, abs_x, abs_y);
+ } else {
+ /* 1st finger */
+ if (ad->last_mt_fgr == 1) {
+ /*
+ * workaround for buggy firmware
+ * which doesn't clear MFMC bit if
+ * the 2nd finger is up
+ */
+ fgrs = 1;
+ fsp_set_slot(dev, 1, false, 0, 0);
+ }
+ ad->last_mt_fgr = 1;
+ fsp_set_slot(dev, 0, fgrs != 0, abs_x, abs_y);
+ }
+ } else {
+ /* SFAC packet */
+
+ /* no multi-finger information */
+ ad->last_mt_fgr = 0;
+
+ if (abs_x != 0 && abs_y != 0)
+ fgrs = 1;
+
+ fsp_set_slot(dev, 0, fgrs > 0, abs_x, abs_y);
+ fsp_set_slot(dev, 1, false, 0, 0);
+ }
+ if (fgrs > 0) {
+ input_report_abs(dev, ABS_X, abs_x);
+ input_report_abs(dev, ABS_Y, abs_y);
+ }
+ input_report_key(dev, BTN_LEFT, packet[0] & 0x01);
+ input_report_key(dev, BTN_RIGHT, packet[0] & 0x02);
+ input_report_key(dev, BTN_TOUCH, fgrs);
+ input_report_key(dev, BTN_TOOL_FINGER, fgrs == 1);
+ input_report_key(dev, BTN_TOOL_DOUBLETAP, fgrs == 2);
break;
case FSP_PKT_TYPE_NORMAL_OPC:
/* on-pad click, filter it if necessary */
if ((ad->flags & FSPDRV_FLAG_EN_OPC) != FSPDRV_FLAG_EN_OPC)
- packet[0] &= ~BIT(0);
+ packet[0] &= ~FSP_PB0_LBTN;
/* fall through */
case FSP_PKT_TYPE_NORMAL:
/* normal packet */
/* special packet data translation from on-pad packets */
if (packet[3] != 0) {
+ unsigned char button_status = 0;
if (packet[3] & BIT(0))
button_status |= 0x01; /* wheel down */
if (packet[3] & BIT(1))
@@ -715,7 +833,7 @@ static psmouse_ret_t fsp_process_byte(struct psmouse *psmouse)
input_sync(dev);
- fsp_packet_debug(packet);
+ fsp_packet_debug(psmouse, packet);
return PSMOUSE_FULL_PACKET;
}
@@ -754,6 +872,7 @@ static int fsp_activate_protocol(struct psmouse *psmouse)
val &= ~(FSP_BIT_EN_MSID7 | FSP_BIT_EN_MSID8 | FSP_BIT_EN_AUTO_MSID8);
/* Ensure we are not in absolute mode */
val &= ~FSP_BIT_EN_PKT_G0;
+
if (pad->buttons == 0x06) {
/* Left/Middle/Right & Scroll Up/Down/Right/Left */
val |= FSP_BIT_EN_MSID6;
@@ -777,6 +896,17 @@ static int fsp_activate_protocol(struct psmouse *psmouse)
fsp_onpad_vscr(psmouse, true);
fsp_onpad_hscr(psmouse, true);
+ /* Enable absolute coordinates output for Cx/Dx hardware */
+ if (pad->ver >= FSP_VER_STL3888_C0) {
+ if (fsp_reg_write(psmouse, FSP_REG_SWC1,
+ FSP_BIT_SWC1_EN_ABS_1F |
+ FSP_BIT_SWC1_EN_GID |
+ FSP_BIT_SWC1_EN_ABS_2F)) {
+ dev_warn(&psmouse->ps2dev.serio->dev,
+ "Failed to enable absolute coordinates output.\n");
+ }
+ }
+
return 0;
}
@@ -832,6 +962,7 @@ static int fsp_reconnect(struct psmouse *psmouse)
int fsp_init(struct psmouse *psmouse)
{
+ struct input_dev *dev = psmouse->dev;
struct fsp_data *priv;
int ver, rev, buttons;
int error;
@@ -864,6 +995,31 @@ int fsp_init(struct psmouse *psmouse)
__set_bit(REL_WHEEL, psmouse->dev->relbit);
__set_bit(REL_HWHEEL, psmouse->dev->relbit);
+ if (ver >= FSP_VER_STL3888_C0) {
+ /*
+ * Hardware prior to Cx performs much better in relative mode;
+ * hence, only enable absolute coordinates output as well as
+ * multi-touch output for Dx hardware.
+ */
+ int abs_x = 1024, abs_y = 768;
+
+ __set_bit(EV_ABS, dev->evbit);
+ __clear_bit(EV_REL, dev->evbit);
+ __set_bit(BTN_TOUCH, dev->keybit);
+ __set_bit(BTN_TOOL_FINGER, dev->keybit);
+ __set_bit(BTN_TOOL_DOUBLETAP, dev->keybit);
+ __set_bit(INPUT_PROP_SEMI_MT, dev->propbit);
+
+ input_set_abs_params(dev, ABS_X, 0, abs_x, 0, 0);
+ input_set_abs_params(dev, ABS_Y, 0, abs_y, 0, 0);
+ input_mt_init_slots(dev, 2);
+ input_set_abs_params(dev, ABS_MT_POSITION_X, 0, abs_x, 0, 0);
+ input_set_abs_params(dev, ABS_MT_POSITION_Y, 0, abs_y, 0, 0);
+
+ /* device generated gesture ID events */
+ input_set_capability(dev, EV_MSC, MSC_GESTURE);
+ }
+
psmouse->protocol_handler = fsp_process_byte;
psmouse->disconnect = fsp_disconnect;
psmouse->reconnect = fsp_reconnect;
diff --git a/drivers/input/mouse/sentelic.h b/drivers/input/mouse/sentelic.h
index ed1395a..05caf11 100644
--- a/drivers/input/mouse/sentelic.h
+++ b/drivers/input/mouse/sentelic.h
@@ -2,7 +2,7 @@
* Finger Sensing Pad PS/2 mouse driver.
*
* Copyright (C) 2005-2007 Asia Vital Components Co., Ltd.
- * Copyright (C) 2005-2009 Tai-hwa Liang, Sentelic Corporation.
+ * Copyright (C) 2005-2012 Tai-hwa Liang, Sentelic Corporation.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -33,6 +33,7 @@
/* Finger-sensing Pad control registers */
#define FSP_REG_SYSCTL1 0x10
#define FSP_BIT_EN_REG_CLK BIT(5)
+#define FSP_REG_TMOD_STATUS 0x20
#define FSP_REG_OPC_QDOWN 0x31
#define FSP_BIT_EN_OPC_TAG BIT(7)
#define FSP_REG_OPTZ_XLO 0x34
@@ -54,6 +55,16 @@
#define FSP_BIT_FIX_HSCR BIT(5)
#define FSP_BIT_DRAG_LOCK BIT(6)
+#define FSP_REG_SWC1 (0x90)
+#define FSP_BIT_SWC1_EN_ABS_1F BIT(0)
+#define FSP_BIT_SWC1_EN_GID BIT(1)
+#define FSP_BIT_SWC1_EN_ABS_2F BIT(2)
+#define FSP_BIT_SWC1_EN_FUP_OUT BIT(3)
+#define FSP_BIT_SWC1_EN_ABS_CON BIT(4)
+#define FSP_BIT_SWC1_GST_GRP0 BIT(5)
+#define FSP_BIT_SWC1_GST_GRP1 BIT(6)
+#define FSP_BIT_SWC1_BX_COMPAT BIT(7)
+
/* Finger-sensing Pad packet formating related definitions */
/* absolute packet type */
@@ -63,6 +74,99 @@
#define FSP_PKT_TYPE_NORMAL_OPC (0x03)
#define FSP_PKT_TYPE_SHIFT (6)
+/* bit definitions for the first byte of report packet */
+#define FSP_PB0_LBTN BIT(0)
+#define FSP_PB0_RBTN BIT(1)
+#define FSP_PB0_MBTN BIT(2)
+#define FSP_PB0_MFMC_FGR2 FSP_PB0_MBTN
+#define FSP_PB0_MUST_SET BIT(3)
+#define FSP_PB0_PHY_BTN BIT(4)
+#define FSP_PB0_MFMC BIT(5)
+
+/* notification message types */
+#define FSP_NOTIFY_MSG_GID (0xba)
+#define FSP_NOTIFY_MSG_HX_GST (0xc0)
+
+/* gesture IDs */
+/** GID for 2F Straight Up */
+#define FSP_GID_SP1 (0x86)
+#define FSP_GID_SP_UP FSP_GID_SP1
+
+/** GID for 2F Straight Down */
+#define FSP_GID_SP5 (0x82)
+#define FSP_GID_SP_DOWN FSP_GID_SP5
+
+/** GID for 2F Straight Right */
+#define FSP_GID_SP2 (0x80)
+#define FSP_GID_SP_RIGHT FSP_GID_SP2
+
+/** GID for 2F Straight Left */
+#define FSP_GID_SP6 (0x84)
+#define FSP_GID_SP_LEFT FSP_GID_SP6
+
+/** GID for 2F Zoom In */
+#define FSP_GID_SC6 (0x8F)
+#define FSP_GID_SC_ZOOM_IN FSP_GID_SC6
+
+/** GID for 2F Zoom Out */
+#define FSP_GID_SC3 (0x8B)
+#define FSP_GID_SC_ZOOM_OUT FSP_GID_SC3
+
+/** GID for 2F Curve CW */
+#define FSP_GID_DC1 (0xC4)
+#define FSP_GID_DC_ROT_CW FSP_GID_DC1
+
+/** GID for 2F Curve CCW */
+#define FSP_GID_DC2 (0xC0)
+#define FSP_GID_DC_ROT_CCW FSP_GID_DC2
+
+/** GID for 3F Straight Up */
+#define FSP_GID_TS4 (0x2E)
+#define FSP_GID_TS_UP FSP_GID_TS4
+
+/** GID for 3F Straight Down */
+#define FSP_GID_TS2 (0x2A)
+#define FSP_GID_TS_DOWN FSP_GID_TS2
+
+/** GID for 3F Straight Right */
+#define FSP_GID_TS1 (0x28)
+#define FSP_GID_TS_RIGHT FSP_GID_TS1
+
+/** GID for 3F Straight Left */
+#define FSP_GID_TS3 (0x2C)
+#define FSP_GID_TS_LEFT FSP_GID_TS3
+
+/** GID for 2F Click */
+#define FSP_GID_DF1 (0x11)
+#define FSP_GID_DF_CLICK FSP_GID_DF1
+
+/** GID for 2F Double Click */
+#define FSP_GID_DF2 (0x12)
+#define FSP_GID_DF_DBLCLICK FSP_GID_DF2
+
+/** GID for 3F Click */
+#define FSP_GID_TF1 (0x19)
+#define FSP_GID_TF_CLICK FSP_GID_TF1
+
+/** GID for 3F Double Click */
+#define FSP_GID_TF2 (0x1A)
+#define FSP_GID_TF_DBLCLICK FSP_GID_TF2
+
+/** GID for Palm */
+#define FSP_GID_PM1 (0x38)
+#define FSP_GID_PALM FSP_GID_PM1
+
+/* hardware revisions */
+#define FSP_VER_STL3888_A4 (0xC1)
+#define FSP_VER_STL3888_B0 (0xD0)
+#define FSP_VER_STL3888_B1 (0xD1)
+#define FSP_VER_STL3888_B2 (0xD2)
+#define FSP_VER_STL3888_C0 (0xE0)
+#define FSP_VER_STL3888_C1 (0xE1)
+#define FSP_VER_STL3888_D0 (0xE2)
+#define FSP_VER_STL3888_D1 (0xE3)
+#define FSP_VER_STL3888_E0 (0xE4)
+
#ifdef __KERNEL__
struct fsp_data {
@@ -77,6 +181,7 @@ struct fsp_data {
unsigned char last_reg; /* Last register we requested read from */
unsigned char last_val;
+ unsigned int last_mt_fgr; /* Last seen finger(multitouch) */
};
#ifdef CONFIG_MOUSE_PS2_SENTELIC