Re: [PATCH 2/2] Input: sentelic: Absolute mode and multitouch support for Cx+ hardware.

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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

[Index of Archives]     [Linux Media Devel]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Linux Wireless Networking]     [Linux Omap]

  Powered by Linux