[PATCH] Alps source code update

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

 



Signed-off-by: Masaki Ota <masaki.ota@xxxxxxxxxxx>
- Support Alps Button-less Touchpad device(Rushmore and SS4). New device type and a data decode logic were added.
---
 drivers/input/mouse/alps.c | 1680 +++++++++++++++++++++++++++++++++++---------
 drivers/input/mouse/alps.h |  263 ++++++-
 2 files changed, 1574 insertions(+), 369 deletions(-)

diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c
index a59a1a6..d4fc568 100644
--- a/drivers/input/mouse/alps.c
+++ b/drivers/input/mouse/alps.c
@@ -20,6 +20,7 @@
 #include <linux/input/mt.h>
 #include <linux/serio.h>
 #include <linux/libps2.h>
+#include <linux/kernel.h>
 
 #include "psmouse.h"
 #include "alps.h"
@@ -32,6 +33,8 @@
 #define ALPS_REG_BASE_RUSHMORE	0xc2c0
 #define ALPS_REG_BASE_PINNACLE	0x0000
 
+#define V7_LARGE_MOVEMENT		130
+
 static const struct alps_nibble_commands alps_v3_nibble_commands[] = {
 	{ PSMOUSE_CMD_SETPOLL,		0x00 }, /* 0 */
 	{ PSMOUSE_CMD_RESET_DIS,	0x00 }, /* 1 */
@@ -99,8 +102,10 @@ static const struct alps_nibble_commands alps_v6_nibble_commands[] = {
 #define ALPS_FOUR_BUTTONS	0x40	/* 4 direction button present */
 #define ALPS_PS2_INTERLEAVED	0x80	/* 3-byte PS/2 packet interleaved with
 					   6-byte ALPS packet */
-#define ALPS_IS_RUSHMORE	0x100	/* device is a rushmore */
-#define ALPS_BUTTONPAD		0x200	/* device is a clickpad */
+#define ALPS_BTNLESS			0x100	/* ALPS ClickPad flag */
+
+#define	DOL_IS_APDATA(_BY)			((_BY[0]&0x01) == 0x01)
+#define	DOL_IS_PROFDATA(_BY)		((_BY[0]&0x20) == 0x20)
 
 static const struct alps_model_info alps_model_data[] = {
 	{ { 0x32, 0x02, 0x14 },	0x00, ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT },	/* Toshiba Salellite Pro M10 */
@@ -142,6 +147,20 @@ static void alps_set_abs_params_mt(struct alps_data *priv,
  * isn't valid per PS/2 spec.
  */
 
+static unsigned int alps_pt_distance(struct alps_abs_data *pt0,
+				    struct alps_abs_data *pt1)
+{
+	int vect_x, vect_y;
+
+	if (!pt0 || !pt1)
+		return 0;
+
+	vect_x = pt0->x - pt1->x;
+	vect_y = pt0->y - pt1->y;
+
+	return int_sqrt(vect_x * vect_x + vect_y * vect_y);
+}
+
 /* Packet formats are described in Documentation/input/alps.txt */
 
 static bool alps_is_valid_first_byte(struct alps_data *priv,
@@ -283,10 +302,11 @@ static void alps_process_packet_v1_v2(struct psmouse *psmouse)
  *
  * The bitmaps don't have enough data to track fingers, so this function
  * only generates points representing a bounding box of at most two contacts.
- * These two points are returned in fields->mt.
+ * These two points are returned in x1, y1, x2, and y2.
  */
 static void alps_process_bitmap_dolphin(struct alps_data *priv,
-					struct alps_fields *fields)
+					struct alps_fields *fields,
+					int *x1, int *y1, int *x2, int *y2)
 {
 	int box_middle_x, box_middle_y;
 	unsigned int x_map, y_map;
@@ -309,6 +329,8 @@ static void alps_process_bitmap_dolphin(struct alps_data *priv,
 	if (x_msb > priv->x_bits || y_msb > priv->y_bits)
 		return;
 
+	*x1 = *y1 = *x2 = *y2 = 0;
+
 	if (fields->fingers > 1) {
 		start_bit = priv->x_bits - x_msb;
 		end_bit = priv->x_bits - x_lsb;
@@ -319,35 +341,10 @@ static void alps_process_bitmap_dolphin(struct alps_data *priv,
 		end_bit = y_msb - 1;
 		box_middle_y = (priv->y_max * (start_bit + end_bit)) /
 				(2 * (priv->y_bits - 1));
-		fields->mt[0] = fields->st;
-		fields->mt[1].x = 2 * box_middle_x - fields->mt[0].x;
-		fields->mt[1].y = 2 * box_middle_y - fields->mt[0].y;
-	}
-}
-
-static void alps_get_bitmap_points(unsigned int map,
-				   struct alps_bitmap_point *low,
-				   struct alps_bitmap_point *high,
-				   int *fingers)
-{
-	struct alps_bitmap_point *point;
-	int i, bit, prev_bit = 0;
-
-	point = low;
-	for (i = 0; map != 0; i++, map >>= 1) {
-		bit = map & 1;
-		if (bit) {
-			if (!prev_bit) {
-				point->start_bit = i;
-				point->num_bits = 0;
-				(*fingers)++;
-			}
-			point->num_bits++;
-		} else {
-			if (prev_bit)
-				point = high;
-		}
-		prev_bit = bit;
+		*x1 = fields->pt.x;
+		*y1 = fields->pt.y;
+		*x2 = 2 * box_middle_x - *x1;
+		*y2 = 2 * box_middle_y - *y1;
 	}
 }
 
@@ -358,21 +355,71 @@ static void alps_get_bitmap_points(unsigned int map,
  *
  * The bitmaps don't have enough data to track fingers, so this function
  * only generates points representing a bounding box of all contacts.
- * These points are returned in fields->mt when the return value
+ * These points are returned in x1, y1, x2, and y2 when the return value
  * is greater than 0.
  */
 static int alps_process_bitmap(struct alps_data *priv,
-			       struct alps_fields *fields)
+			       unsigned int x_map, unsigned int y_map,
+			       int *x1, int *y1, int *x2, int *y2)
 {
-	int i, fingers_x = 0, fingers_y = 0, fingers;
+	struct alps_bitmap_point {
+		int start_bit;
+		int num_bits;
+	};
+
+	int fingers_x = 0, fingers_y = 0, fingers;
+	int i, bit, prev_bit;
 	struct alps_bitmap_point x_low = {0,}, x_high = {0,};
 	struct alps_bitmap_point y_low = {0,}, y_high = {0,};
+	struct alps_bitmap_point *point;
 
-	if (!fields->x_map || !fields->y_map)
+	if (!x_map || !y_map)
 		return 0;
 
-	alps_get_bitmap_points(fields->x_map, &x_low, &x_high, &fingers_x);
-	alps_get_bitmap_points(fields->y_map, &y_low, &y_high, &fingers_y);
+	*x1 = *y1 = *x2 = *y2 = 0;
+
+	prev_bit = 0;
+	point = &x_low;
+	for (i = 0; x_map != 0; i++, x_map >>= 1) {
+		bit = x_map & 1;
+		if (bit) {
+			if (!prev_bit) {
+				point->start_bit = i;
+				fingers_x++;
+			}
+			point->num_bits++;
+		} else {
+			if (prev_bit)
+				point = &x_high;
+			else
+				point->num_bits = 0;
+		}
+		prev_bit = bit;
+	}
+
+	/*
+	 * y bitmap is reversed for what we need (lower positions are in
+	 * higher bits), so we process from the top end.
+	 */
+	y_map = y_map << (sizeof(y_map) * BITS_PER_BYTE - priv->y_bits);
+	prev_bit = 0;
+	point = &y_low;
+	for (i = 0; y_map != 0; i++, y_map <<= 1) {
+		bit = y_map & (1 << (sizeof(y_map) * BITS_PER_BYTE - 1));
+		if (bit) {
+			if (!prev_bit) {
+				point->start_bit = i;
+				fingers_y++;
+			}
+			point->num_bits++;
+		} else {
+			if (prev_bit)
+				point = &y_high;
+			else
+				point->num_bits = 0;
+		}
+		prev_bit = bit;
+	}
 
 	/*
 	 * Fingers can overlap, so we use the maximum count of fingers
@@ -381,89 +428,103 @@ static int alps_process_bitmap(struct alps_data *priv,
 	fingers = max(fingers_x, fingers_y);
 
 	/*
-	 * If an axis reports only a single contact, we have overlapping or
-	 * adjacent fingers. Divide the single contact between the two points.
+	 * If total fingers is > 1 but either axis reports only a single
+	 * contact, we have overlapping or adjacent fingers. For the
+	 * purposes of creating a bounding box, divide the single contact
+	 * (roughly) equally between the two points.
 	 */
-	if (fingers_x == 1) {
-		i = (x_low.num_bits - 1) / 2;
-		x_low.num_bits = x_low.num_bits - i;
-		x_high.start_bit = x_low.start_bit + i;
-		x_high.num_bits = max(i, 1);
-	}
-	if (fingers_y == 1) {
-		i = (y_low.num_bits - 1) / 2;
-		y_low.num_bits = y_low.num_bits - i;
-		y_high.start_bit = y_low.start_bit + i;
-		y_high.num_bits = max(i, 1);
-	}
-
-	fields->mt[0].x =
-		(priv->x_max * (2 * x_low.start_bit + x_low.num_bits - 1)) /
-		(2 * (priv->x_bits - 1));
-	fields->mt[0].y =
-		(priv->y_max * (2 * y_low.start_bit + y_low.num_bits - 1)) /
-		(2 * (priv->y_bits - 1));
-
-	fields->mt[1].x =
-		(priv->x_max * (2 * x_high.start_bit + x_high.num_bits - 1)) /
-		(2 * (priv->x_bits - 1));
-	fields->mt[1].y =
-		(priv->y_max * (2 * y_high.start_bit + y_high.num_bits - 1)) /
-		(2 * (priv->y_bits - 1));
-
-	/* y-bitmap order is reversed, except on rushmore */
-	if (!(priv->flags & ALPS_IS_RUSHMORE)) {
-		fields->mt[0].y = priv->y_max - fields->mt[0].y;
-		fields->mt[1].y = priv->y_max - fields->mt[1].y;
+	if (fingers > 1) {
+		if (fingers_x == 1) {
+			i = x_low.num_bits / 2;
+			x_low.num_bits = x_low.num_bits - i;
+			x_high.start_bit = x_low.start_bit + i;
+			x_high.num_bits = max(i, 1);
+		} else if (fingers_y == 1) {
+			i = y_low.num_bits / 2;
+			y_low.num_bits = y_low.num_bits - i;
+			y_high.start_bit = y_low.start_bit + i;
+			y_high.num_bits = max(i, 1);
+		}
+	}
+
+	*x1 = (priv->x_max * (2 * x_low.start_bit + x_low.num_bits - 1)) /
+	      (2 * (priv->x_bits - 1));
+	*y1 = (priv->y_max * (2 * y_low.start_bit + y_low.num_bits - 1)) /
+	      (2 * (priv->y_bits - 1));
+
+	if (fingers > 1) {
+		*x2 = (priv->x_max *
+		       (2 * x_high.start_bit + x_high.num_bits - 1)) /
+		      (2 * (priv->x_bits - 1));
+		*y2 = (priv->y_max *
+		       (2 * y_high.start_bit + y_high.num_bits - 1)) /
+		      (2 * (priv->y_bits - 1));
 	}
 
 	return fingers;
 }
 
-static void alps_set_slot(struct input_dev *dev, int slot, int x, int y)
+static void alps_set_slot(struct input_dev *dev, int slot, bool active,
+			  int x, int y)
 {
 	input_mt_slot(dev, slot);
-	input_mt_report_slot_state(dev, MT_TOOL_FINGER, true);
-	input_report_abs(dev, ABS_MT_POSITION_X, x);
-	input_report_abs(dev, ABS_MT_POSITION_Y, y);
+	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 void alps_report_mt_data(struct psmouse *psmouse, int n)
+static void alps_report_semi_mt_data(struct input_dev *dev, int num_fingers,
+				     int x1, int y1, int x2, int y2)
 {
-	struct alps_data *priv = psmouse->private;
-	struct input_dev *dev = psmouse->dev;
-	struct alps_fields *f = &priv->f;
-	int i, slot[MAX_TOUCHES];
+	alps_set_slot(dev, 0, num_fingers != 0, x1, y1);
+	alps_set_slot(dev, 1, num_fingers == 2, x2, y2);
+}
 
-	input_mt_assign_slots(dev, slot, f->mt, n);
-	for (i = 0; i < n; i++)
-		alps_set_slot(dev, slot[i], f->mt[i].x, f->mt[i].y);
+static void alps_report_semi_mt_data_ex(struct input_dev *dev, int num_fingers,
+				     struct alps_abs_data coord[])
+{
+	unsigned char i;
 
-	input_mt_sync_frame(dev);
+	for (i = 0; i < num_fingers; i++) {
+		if (!coord[i].x || !coord[i].y || !coord[i].z)
+			alps_set_slot(dev, i, 0, coord[i].x, coord[i].y);
+		else
+			alps_set_slot(dev, i, 1, coord[i].x, coord[i].y);
+	}
 }
 
-static void alps_report_semi_mt_data(struct psmouse *psmouse, int fingers)
+static void alps_report_coord_and_btn(struct psmouse *psmouse,
+				      struct alps_fields *f)
 {
-	struct alps_data *priv = psmouse->private;
-	struct input_dev *dev = psmouse->dev;
-	struct alps_fields *f = &priv->f;
+	struct input_dev *dev;
 
-	/* Use st data when we don't have mt data */
-	if (fingers < 2) {
-		f->mt[0].x = f->st.x;
-		f->mt[0].y = f->st.y;
-		fingers = f->pressure > 0 ? 1 : 0;
-	}
+	if (!psmouse || !f)
+		return;
 
-	alps_report_mt_data(psmouse, (fingers <= 2) ? fingers : 2);
+	dev = psmouse->dev;
 
-	input_mt_report_finger_count(dev, fingers);
+	if (f->fingers) {
+		input_report_key(dev, BTN_TOUCH, 1);
+
+		alps_report_semi_mt_data(dev, f->fingers,
+			f->pt_img[0].x, f->pt_img[0].y,
+			f->pt_img[1].x, f->pt_img[1].y);
+		input_mt_report_finger_count(dev, f->fingers);
 
-	input_report_key(dev, BTN_LEFT, f->left);
-	input_report_key(dev, BTN_RIGHT, f->right);
-	input_report_key(dev, BTN_MIDDLE, f->middle);
+		input_report_abs(dev, ABS_X, f->pt_img[0].x);
+		input_report_abs(dev, ABS_Y, f->pt_img[0].y);
+		input_report_abs(dev, ABS_PRESSURE, f->pt_img[0].z);
+	} else {
+		input_report_key(dev, BTN_TOUCH, 0);
+		input_mt_report_finger_count(dev, 0);
+		input_report_abs(dev, ABS_PRESSURE, 0);
+	}
 
-	input_report_abs(dev, ABS_PRESSURE, f->pressure);
+	input_report_key(dev, BTN_LEFT, f->btn.left);
+	input_report_key(dev, BTN_RIGHT, f->btn.right);
+	input_report_key(dev, BTN_MIDDLE, f->btn.middle);
 
 	input_sync(dev);
 }
@@ -530,16 +591,25 @@ static void alps_process_trackstick_packet_v3(struct psmouse *psmouse)
 
 static void alps_decode_buttons_v3(struct alps_fields *f, unsigned char *p)
 {
-	f->left = !!(p[3] & 0x01);
-	f->right = !!(p[3] & 0x02);
-	f->middle = !!(p[3] & 0x04);
+	f->btn.left = !!(p[3] & 0x01);
+	f->btn.right = !!(p[3] & 0x02);
+	f->btn.middle = !!(p[3] & 0x04);
 
-	f->ts_left = !!(p[3] & 0x10);
-	f->ts_right = !!(p[3] & 0x20);
-	f->ts_middle = !!(p[3] & 0x40);
+	f->btn.ts_left = !!(p[3] & 0x10);
+	f->btn.ts_right = !!(p[3] & 0x20);
+	f->btn.ts_middle = !!(p[3] & 0x40);
 }
 
-static int alps_decode_pinnacle(struct alps_fields *f, unsigned char *p,
+/* proto_v9 */
+static void alps_decode_button_ss3(struct alps_fields *f, unsigned char *p,
+				struct alps_data *priv)
+{
+	if (f->dol_packet_type == DOL_GPDATA ||
+		f->dol_packet_type == DOL_APDATA)
+		f->btn.left = !!(p[3]&0x01);
+}
+
+static void alps_decode_pinnacle(struct alps_fields *f, unsigned char *p,
 				 struct psmouse *psmouse)
 {
 	f->first_mp = !!(p[4] & 0x40);
@@ -553,17 +623,15 @@ static int alps_decode_pinnacle(struct alps_fields *f, unsigned char *p,
 		   ((p[2] & 0x7f) << 1) |
 		   (p[4] & 0x01);
 
-	f->st.x = ((p[1] & 0x7f) << 4) | ((p[4] & 0x30) >> 2) |
+	f->pt.x = ((p[1] & 0x7f) << 4) | ((p[4] & 0x30) >> 2) |
 	       ((p[0] & 0x30) >> 4);
-	f->st.y = ((p[2] & 0x7f) << 4) | (p[4] & 0x0f);
-	f->pressure = p[5] & 0x7f;
+	f->pt.y = ((p[2] & 0x7f) << 4) | (p[4] & 0x0f);
+	f->pt.z = p[5] & 0x7f;
 
 	alps_decode_buttons_v3(f, p);
-
-	return 0;
 }
 
-static int alps_decode_rushmore(struct alps_fields *f, unsigned char *p,
+static void alps_decode_rushmore(struct alps_fields *f, unsigned char *p,
 				 struct psmouse *psmouse)
 {
 	alps_decode_pinnacle(f, p, psmouse);
@@ -573,25 +641,20 @@ static int alps_decode_rushmore(struct alps_fields *f, unsigned char *p,
 	f->fingers = max((p[5] & 0x3), ((p[5] >> 2) & 0x3)) + 1;
 	f->x_map |= (p[5] & 0x10) << 11;
 	f->y_map |= (p[5] & 0x20) << 6;
-
-	return 0;
 }
 
-static int alps_decode_dolphin(struct alps_fields *f, unsigned char *p,
+static void alps_decode_dolphin(struct alps_fields *f, unsigned char *p,
 				struct psmouse *psmouse)
 {
 	u64 palm_data = 0;
 	struct alps_data *priv = psmouse->private;
 
-	f->first_mp = !!(p[0] & 0x02);
-	f->is_mp = !!(p[0] & 0x20);
+	f->is_mp = 0;
+	f->first_mp = 0;
 
-	if (!f->is_mp) {
-		f->st.x = ((p[1] & 0x7f) | ((p[4] & 0x0f) << 7));
-		f->st.y = ((p[2] & 0x7f) | ((p[4] & 0xf0) << 3));
-		f->pressure = (p[0] & 4) ? 0 : p[5] & 0x7f;
-		alps_decode_buttons_v3(f, p);
-	} else {
+	if (DOL_IS_PROFDATA(p)) {
+		f->is_mp = 1;
+		f->dol_packet_type = DOL_PROFDATA;
 		f->fingers = ((p[0] & 0x6) >> 1 |
 		     (p[0] & 0x10) >> 2);
 
@@ -609,22 +672,415 @@ static int alps_decode_dolphin(struct alps_fields *f, unsigned char *p,
 		/* X-profile is stored in p(n) to p(n+m-1), m = x_bits; */
 		f->x_map = (palm_data >> priv->y_bits) &
 			   (BIT(priv->x_bits) - 1);
+	} else {
+		if (DOL_IS_APDATA(p)) {
+			f->dol_packet_type = DOL_APDATA;
+			f->fingers = 2;
+			f->pt_img[0].x = p[1]<<3;
+			f->pt_img[0].y = p[2]<<2;
+			f->pt_img[0].z = 64;
+			f->pt_img[1].x = p[4]<<3;
+			f->pt_img[1].y = p[5]<<2;
+			f->pt_img[1].z = 64;
+		} else {/* is gp data */
+			f->dol_packet_type = DOL_GPDATA;
+			f->first_mp = !!(p[0]&0x02);
+			f->pt.x = f->pt_img[0].x =
+				((p[1] & 0x7f) | ((p[4] & 0x0f) << 7));
+			f->pt.y = f->pt_img[0].y =
+				((p[2] & 0x7f) | ((p[4] & 0xf0) << 3));
+			f->pt.z = f->pt_img[0].z =
+				min(((p[0] & 0x04) ? 0 : p[5] & 0x7f) * 2, 127);
+
+			/*
+				Button number will be included in
+				the PROFILE data for a 3-f packet.
+				So do not change .fingers because
+				it will be updated in Profile data packet.
+			*/
+			if (!f->first_mp)
+				f->fingers = (f->pt_img[0].x &&
+					f->pt_img[0].y && f->pt_img[0].z)?1:0;
+		}
+
+		if (priv->proto_version == ALPS_PROTO_V9)
+			alps_decode_button_ss3(f, p, priv);
+		else
+			alps_decode_buttons_v3(f, p);
 	}
+}
 
-	return 0;
+unsigned char alps_get_pkt_id_ss4_v1(char *byte)
+{
+	unsigned char pkt_id = SS4_PACKET_ID_IDLE;
+
+	if (((byte[0] & 0xFF) == 0x08) && ((byte[1] & 0xFF) == 0x10) &&
+	     ((byte[2] & 0xFF) == 0x00) && ((byte[3] & 0x8F) == 0x08) &&
+	     ((byte[4] & 0xFF) == 0x01) && ((byte[5] & 0xFF) == 0x00)) {
+		pkt_id = SS4_PACKET_ID_IDLE;
+	} else if (((byte[0] & 0x08) == 0x08) && ((byte[1] & 0x10) == 0x10) &&
+		((byte[3] & 0x8E) == 0x08) && ((byte[4] & 0x81) == 0x01)) {
+		pkt_id = SS4_PACKET_ID_ONE;
+	} else if (((byte[0] & 0x08) == 0x08) && ((byte[3] & 0x08) == 0x08) &&
+		  ((byte[4] & 0x01) == 0x01)) {
+		if (((byte[5] & 0x01) == 0x01))
+			pkt_id = SS4_PACKET_ID_TWO;
+		else
+			pkt_id = SS4_PACKET_ID_MULTI;
+	}
+
+	return pkt_id;
+}
+
+unsigned char alps_get_pkt_id_ss4_v2(char *byte)
+{
+	unsigned char pkt_id = SS4_PACKET_ID_IDLE;
+
+	if (((byte[0] & 0xFF) == 0x18) && ((byte[1] & 0xFF) == 0x10) &&
+	     ((byte[2] & 0xFF) == 0x00) && ((byte[3] & 0x88) == 0x08) &&
+	     ((byte[4] & 0xFF) == 0x10) && ((byte[5] & 0xFF) == 0x00)) {
+		pkt_id = SS4_PACKET_ID_IDLE;
+	} else if (!(byte[3] & 0x10)) {
+		pkt_id = SS4_PACKET_ID_ONE;
+	} else {
+		if (!(byte[3] & 0x20))
+			pkt_id = SS4_PACKET_ID_TWO;
+		else
+			pkt_id = SS4_PACKET_ID_MULTI;
+	}
+
+	return pkt_id;
+}
+
+static void alps_process_btnless_click(struct psmouse *psmouse,
+				struct alps_fields *f)
+{
+	struct alps_data *priv = psmouse->private;
+
+	if (!f->btn.left)
+		return;
+
+	/* Clear button flag */
+	f->btn.left = 0;
+
+	switch (f->fingers) {
+	case 1:
+		/* In Left Resting Area */
+		if (PT_IN_LEFT_BTN_AREA(f->pt_img[0].x,
+				f->pt_img[0].y, priv->x_max, priv->y_max)) {
+			f->btn.left = 1;
+		} else if (PT_IN_RIGHT_BTN_AREA(f->pt_img[0].x,
+				f->pt_img[0].y, priv->x_max, priv->y_max)) {
+			/* In Right Resting Area */
+			f->btn.right = 1;
+		} else {
+			/* In Normal area */
+			f->btn.left = 1;
+		}
+		break;
+
+	case 2:
+		/* Both two fingers are in Normal area */
+		if (!PT_IN_BTN_AREA(f->pt_img[0].x,
+				f->pt_img[0].y, priv->x_max, priv->y_max) &&
+				!PT_IN_BTN_AREA(f->pt_img[1].x,
+				f->pt_img[1].y, priv->x_max, priv->y_max)) {
+			f->btn.right = 1;
+		} else if (PT_IN_RIGHT_BTN_AREA(f->pt_img[0].x,
+				f->pt_img[0].y, priv->x_max, priv->y_max) ||
+				PT_IN_RIGHT_BTN_AREA(f->pt_img[1].x,
+				f->pt_img[1].y, priv->x_max, priv->y_max)) {
+			/* Either one finger is in Right Area */
+			f->btn.right = 1;
+		} else {
+			f->btn.left = 1;
+		}
+		break;
+
+	case 3:
+		f->btn.middle = 1;
+		break;
+
+	case 0:
+	default:
+		break;
+	}
+}
+
+static void alps_process_resting_finger(struct psmouse *psmouse,
+	struct alps_fields *f, struct alps_abs_data *output,
+	unsigned char *p_fn)
+{
+	struct alps_data *priv = psmouse->private;
+	static struct alps_abs_data prev_pt[10];
+	static struct alps_abs_data init_pt[10];
+	static unsigned char is_moved[10];
+	static unsigned char prev_fn;
+	static unsigned char prev_coord_is_output[10];
+	unsigned char cur_coord_is_output[10];
+	unsigned char in_resting_area[10];
+	unsigned char i, index;
+	unsigned char output_fn = 0;
+
+	memset(in_resting_area, 0, sizeof(in_resting_area));
+	memset(cur_coord_is_output, 0, sizeof(cur_coord_is_output));
+
+	/* Clear "is_moved" flag when finger number changed */
+	if (f->fingers != prev_fn) {
+		memset(is_moved, 0, sizeof(is_moved));
+		memcpy(init_pt, f->pt_img, sizeof(f->pt_img));
+	}
+
+	/* Calculate output finger */
+	for (i = 0, index = 0; i < f->fingers; i++) {
+		if (is_moved[i] == 0 &&
+			(abs(f->pt_img[i].x - init_pt[i].x)
+				> RESTING_FN_LARGE_MOVEMENT)) {
+			is_moved[i] = 1;
+		}
+
+		/* Check if in resting area */
+		if (PT_IN_BTN_AREA(f->pt_img[i].x,
+				f->pt_img[i].y, priv->x_max, priv->y_max))
+			in_resting_area[i] = 1;
+
+		if (!in_resting_area[i] ||
+			(in_resting_area[i] && is_moved[i])) {
+			memcpy(&output[index++], &f->pt_img[i],
+				sizeof(struct alps_abs_data));
+			cur_coord_is_output[i] = 1;
+			output_fn++;
+		}
+	}
+
+	/* A normal finger becomes a resting finger */
+	for (i = 0; i < f->fingers; i++) {
+		if (prev_coord_is_output[i] &&
+			!cur_coord_is_output[i] && f->pt_img[i].z) {
+			output_fn = 0;
+			memset(output, 0,
+				sizeof(struct alps_abs_data)*f->fingers);
+		}
+	}
+
+	memcpy(prev_pt, f->pt_img, sizeof(f->pt_img));
+	memcpy(prev_coord_is_output, cur_coord_is_output,
+		sizeof(cur_coord_is_output));
+	prev_fn = f->fingers;
+	*p_fn = output_fn;
+}
+
+static void alps_decode_ss4_v1(struct alps_fields *f,
+			unsigned char *p, struct psmouse *psmouse)
+{
+	struct alps_data *priv = psmouse->private;
+	unsigned char pkt_id;
+	unsigned int no_data_x, no_data_y;
+
+	if (!psmouse || !f || !p)
+		return;
+
+	pkt_id = alps_get_pkt_id_ss4_v1(p);
+
+	/* Current packet is 1Finger coordinate packet */
+	switch (pkt_id) {
+	case SS4_PACKET_ID_ONE:
+		f->pt_img[0].x = SS4_1F_X_V1(p);
+		f->pt_img[0].y = SS4_1F_Y_V1(p);
+		/* Keep Z-value in 0-127 */
+		f->pt_img[0].z = min(((SS4_1F_Z_V1(p)) * 2), 127);
+		f->large_fn |= SS4_1F_LFB(p) ? 0x01 : 0x00;
+		f->fingers = 1;
+		f->first_mp = 0;
+		f->is_mp = 0;
+		break;
+
+	case SS4_PACKET_ID_TWO:
+		if (priv->flags & ALPS_BTNLESS) {
+			f->pt_img[0].x = SS4_BTL_MF_X_V1(p, 0);
+			f->pt_img[0].y = SS4_BTL_MF_Y_V1(p, 0);
+			f->pt_img[1].x = SS4_BTL_MF_X_V1(p, 1);
+			f->pt_img[1].y = SS4_BTL_MF_Y_V1(p, 1);
+		} else {
+			f->pt_img[0].x = SS4_STD_MF_X_V1(p, 0);
+			f->pt_img[0].y = SS4_STD_MF_Y_V1(p, 0);
+			f->pt_img[1].x = SS4_STD_MF_X_V1(p, 1);
+			f->pt_img[1].y = SS4_STD_MF_Y_V1(p, 1);
+		}
+		f->pt_img[0].z = SS4_MF_Z_V1(p, 0) ? 0x30 : 0;
+		f->pt_img[1].z = SS4_MF_Z_V1(p, 1) ? 0x30 : 0;
+
+		if (SS4_IS_MF_CONTINUE_V1(p)) {
+			f->first_mp = 1;
+		} else {
+			f->fingers = 2;
+			f->first_mp = 0;
+		}
+		f->is_mp = 0;
+
+		break;
+
+	case SS4_PACKET_ID_MULTI:
+		if (priv->flags & ALPS_BTNLESS) {
+			f->pt_img[2].x = SS4_BTL_MF_X_V1(p, 0);
+			f->pt_img[2].y = SS4_BTL_MF_Y_V1(p, 0);
+			f->pt_img[3].x = SS4_BTL_MF_X_V1(p, 1);
+			f->pt_img[3].y = SS4_BTL_MF_Y_V1(p, 1);
+			no_data_x = SS4_MFPACKET_NO_AX_BL;
+			no_data_y = SS4_MFPACKET_NO_AY_BL;
+		} else {
+			f->pt_img[2].x = SS4_STD_MF_X_V1(p, 0);
+			f->pt_img[2].y = SS4_STD_MF_Y_V1(p, 0);
+			f->pt_img[3].x = SS4_STD_MF_X_V1(p, 1);
+			f->pt_img[3].y = SS4_STD_MF_Y_V1(p, 1);
+			no_data_x = SS4_MFPACKET_NO_AX;
+			no_data_y = SS4_MFPACKET_NO_AY;
+		}
+		f->pt_img[2].z = SS4_MF_Z_V1(p, 0) ? 0x30 : 0;
+		f->pt_img[3].z = SS4_MF_Z_V1(p, 1) ? 0x30 : 0;
+
+		f->first_mp = 0;
+		f->is_mp = 1;
+
+		if (SS4_IS_5F_DETECTED_V1(p)) {
+			f->fingers = 5;
+		} else if (f->pt_img[3].x == no_data_x &&
+			     f->pt_img[3].y == no_data_y) {
+			f->fingers = 3;
+			f->pt_img[3].x = 0;
+			f->pt_img[3].y = 0;
+			f->pt_img[3].z = 0;
+		} else {
+			f->fingers = 4;
+		}
+		break;
+
+	case SS4_PACKET_ID_IDLE:
+	default:
+		memset(f, 0, sizeof(struct alps_fields));
+		break;
+	}
+
+	f->btn.left = !!(SS4_BTN_V1(p) & 0x01);
+	if (!(priv->flags & ALPS_BTNLESS)) {
+		f->btn.right = !!(SS4_BTN_V1(p) & 0x02);
+		f->btn.middle = !!(SS4_BTN_V1(p) & 0x04);
+	}
+}
+
+static void alps_decode_ss4_v2(struct alps_fields *f,
+			unsigned char *p, struct psmouse *psmouse)
+{
+	struct alps_data *priv = psmouse->private;
+	unsigned char pkt_id;
+	unsigned int no_data_x, no_data_y;
+
+	if (!psmouse || !f || !p)
+		return;
+
+	pkt_id = alps_get_pkt_id_ss4_v2(p);
+
+	/* Current packet is 1Finger coordinate packet */
+	switch (pkt_id) {
+	case SS4_PACKET_ID_ONE:
+		f->pt_img[0].x = SS4_1F_X_V2(p);
+		f->pt_img[0].y = SS4_1F_Y_V2(p);
+		/* Keep Z-value in 0-127 */
+		f->pt_img[0].z = min(((SS4_1F_Z_V2(p)) * 2), 127);
+		f->large_fn |= SS4_1F_LFB_V2(p) ? 0x01 : 0x00;
+		f->fingers = 1;
+		f->first_mp = 0;
+		f->is_mp = 0;
+		break;
+
+	case SS4_PACKET_ID_TWO:
+		if (priv->flags & ALPS_BTNLESS) {
+			f->pt_img[0].x = SS4_BTL_MF_X_V2(p, 0);
+			f->pt_img[0].y = SS4_BTL_MF_Y_V2(p, 0);
+			f->pt_img[1].x = SS4_BTL_MF_X_V2(p, 1);
+			f->pt_img[1].y = SS4_BTL_MF_Y_V2(p, 1);
+		} else {
+			f->pt_img[0].x = SS4_STD_MF_X_V2(p, 0);
+			f->pt_img[0].y = SS4_STD_MF_Y_V2(p, 0);
+			f->pt_img[1].x = SS4_STD_MF_X_V2(p, 1);
+			f->pt_img[1].y = SS4_STD_MF_Y_V2(p, 1);
+		}
+		f->pt_img[0].z = SS4_MF_Z_V2(p, 0) ? 0x30 : 0;
+		f->pt_img[1].z = SS4_MF_Z_V2(p, 1) ? 0x30 : 0;
+
+		f->large_fn |= SS4_MF_LF_V2(p, 0) ? 0x01 : 0;
+		f->large_fn |= SS4_MF_LF_V2(p, 1) ? 0x02 : 0;
+
+		if (SS4_IS_MF_CONTINUE_V2(p)) {
+			f->first_mp = 1;
+		} else {
+			f->fingers = 2;
+			f->first_mp = 0;
+		}
+		f->is_mp = 0;
+		break;
+
+	case SS4_PACKET_ID_MULTI:
+		if (priv->flags & ALPS_BTNLESS) {
+			f->pt_img[2].x = SS4_BTL_MF_X_V2(p, 0);
+			f->pt_img[2].y = SS4_BTL_MF_Y_V2(p, 0);
+			f->pt_img[3].x = SS4_BTL_MF_X_V2(p, 1);
+			f->pt_img[3].y = SS4_BTL_MF_Y_V2(p, 1);
+			no_data_x = SS4_MFPACKET_NO_AX_BL;
+			no_data_y = SS4_MFPACKET_NO_AY_BL;
+		} else {
+			f->pt_img[2].x = SS4_STD_MF_X_V2(p, 0);
+			f->pt_img[2].y = SS4_STD_MF_Y_V2(p, 0);
+			f->pt_img[3].x = SS4_STD_MF_X_V2(p, 1);
+			f->pt_img[3].y = SS4_STD_MF_Y_V2(p, 1);
+			no_data_x = SS4_MFPACKET_NO_AX;
+			no_data_y = SS4_MFPACKET_NO_AY;
+		}
+		f->pt_img[2].z = SS4_MF_Z_V2(p, 0) ? 0x30 : 0;
+		f->pt_img[3].z = SS4_MF_Z_V2(p, 1) ? 0x30 : 0;
+
+		f->large_fn |= SS4_MF_LF_V2(p, 0) ? 0x04 : 0;
+		f->large_fn |= SS4_MF_LF_V2(p, 1) ? 0x08 : 0;
+		f->first_mp = 0;
+		f->is_mp = 1;
+
+		if (SS4_IS_5F_DETECTED_V2(p)) {
+			f->fingers = 5;
+		} else if (f->pt_img[3].x == no_data_x &&
+			     f->pt_img[3].y == no_data_y) {
+			f->fingers = 3;
+			f->pt_img[3].x = 0;
+			f->pt_img[3].y = 0;
+			f->pt_img[3].z = 0;
+		} else {
+			f->fingers = 4;
+		}
+		break;
+
+	case SS4_PACKET_ID_IDLE:
+	default:
+		memset(f, 0, sizeof(struct alps_fields));
+		break;
+	}
+
+	f->btn.left = !!(SS4_BTN_V2(p) & 0x01);
+	if (!(priv->flags & ALPS_BTNLESS)) {
+		f->btn.right = !!(SS4_BTN_V2(p) & 0x02);
+		f->btn.middle = !!(SS4_BTN_V2(p) & 0x04);
+	}
 }
 
 static void alps_process_touchpad_packet_v3_v5(struct psmouse *psmouse)
 {
 	struct alps_data *priv = psmouse->private;
 	unsigned char *packet = psmouse->packet;
+	struct input_dev *dev = psmouse->dev;
 	struct input_dev *dev2 = priv->dev2;
-	struct alps_fields *f = &priv->f;
-	int fingers = 0;
+	int x1 = 0, y1 = 0, x2 = 0, y2 = 0;
+	int fingers = 0, bmap_fn;
+	struct alps_fields f = {0};
 
-	memset(f, 0, sizeof(*f));
-
-	priv->decode_fields(f, packet, psmouse);
+	priv->decode_fields(&f, packet, psmouse);
 
 	/*
 	 * There's no single feature of touchpad position and bitmap packets
@@ -639,14 +1095,22 @@ static void alps_process_touchpad_packet_v3_v5(struct psmouse *psmouse)
 		 * packet. Check for this, and when it happens process the
 		 * position packet as usual.
 		 */
-		if (f->is_mp) {
-			fingers = f->fingers;
+		if (f.is_mp) {
+			fingers = f.fingers;
 			if (priv->proto_version == ALPS_PROTO_V3) {
-				if (alps_process_bitmap(priv, f) == 0)
-					fingers = 0; /* Use st data */
+				bmap_fn = alps_process_bitmap(priv, f.x_map,
+							      f.y_map, &x1, &y1,
+							      &x2, &y2);
+
+				/*
+				 * We shouldn't report more than one finger if
+				 * we don't have two coordinates.
+				 */
+				if (fingers > 1 && bmap_fn < 2)
+					fingers = bmap_fn;
 
 				/* Now process position packet */
-				priv->decode_fields(f, priv->multi_data,
+				priv->decode_fields(&f, priv->multi_data,
 						    psmouse);
 			} else {
 				/*
@@ -655,14 +1119,15 @@ static void alps_process_touchpad_packet_v3_v5(struct psmouse *psmouse)
 				 * calculate Pt2, so we need to do position
 				 * packet decode first.
 				 */
-				priv->decode_fields(f, priv->multi_data,
+				priv->decode_fields(&f, priv->multi_data,
 						    psmouse);
 
 				/*
 				 * Since Dolphin's finger number is reliable,
 				 * there is no need to compare with bmap_fn.
 				 */
-				alps_process_bitmap_dolphin(priv, f);
+				alps_process_bitmap_dolphin(priv, &f, &x1, &y1,
+					&x2, &y2);
 			}
 		} else {
 			priv->multi_packet = 0;
@@ -677,10 +1142,10 @@ static void alps_process_touchpad_packet_v3_v5(struct psmouse *psmouse)
 	 * out misidentified bitmap packets, we reject anything with this
 	 * bit set.
 	 */
-	if (f->is_mp)
+	if (f.is_mp)
 		return;
 
-	if (!priv->multi_packet && f->first_mp) {
+	if (!priv->multi_packet && f.first_mp) {
 		priv->multi_packet = 1;
 		memcpy(priv->multi_data, packet, sizeof(priv->multi_data));
 		return;
@@ -694,15 +1159,44 @@ static void alps_process_touchpad_packet_v3_v5(struct psmouse *psmouse)
 	 * with x, y, and z all zero, so these seem to be flukes.
 	 * Ignore them.
 	 */
-	if (f->st.x && f->st.y && !f->pressure)
+	if (f.pt.x && f.pt.y && !f.pt.z)
 		return;
 
-	alps_report_semi_mt_data(psmouse, fingers);
+	/*
+	 * If we don't have MT data or the bitmaps were empty, we have
+	 * to rely on ST data.
+	 */
+	if (!fingers) {
+		x1 = f.pt.x;
+		y1 = f.pt.y;
+		fingers = f.pt.z > 0 ? 1 : 0;
+	}
+
+	if (f.pt.z > 0)
+		input_report_key(dev, BTN_TOUCH, 1);
+	else
+		input_report_key(dev, BTN_TOUCH, 0);
+
+	alps_report_semi_mt_data(dev, fingers, x1, y1, x2, y2);
+
+	input_mt_report_finger_count(dev, fingers);
+
+	input_report_key(dev, BTN_LEFT, f.btn.left);
+	input_report_key(dev, BTN_RIGHT, f.btn.right);
+	input_report_key(dev, BTN_MIDDLE, f.btn.middle);
+
+	if (f.pt.z > 0) {
+		input_report_abs(dev, ABS_X, f.pt.x);
+		input_report_abs(dev, ABS_Y, f.pt.y);
+	}
+	input_report_abs(dev, ABS_PRESSURE, f.pt.z);
+
+	input_sync(dev);
 
 	if (!(priv->quirks & ALPS_QUIRK_TRACKSTICK_BUTTONS)) {
-		input_report_key(dev2, BTN_LEFT, f->ts_left);
-		input_report_key(dev2, BTN_RIGHT, f->ts_right);
-		input_report_key(dev2, BTN_MIDDLE, f->ts_middle);
+		input_report_key(dev2, BTN_LEFT, f.btn.ts_left);
+		input_report_key(dev2, BTN_RIGHT, f.btn.ts_right);
+		input_report_key(dev2, BTN_MIDDLE, f.btn.ts_middle);
 		input_sync(dev2);
 	}
 }
@@ -727,6 +1221,64 @@ static void alps_process_packet_v3(struct psmouse *psmouse)
 	alps_process_touchpad_packet_v3_v5(psmouse);
 }
 
+/* proto_v9 */
+static void alps_process_touchpad_packet_ss3(struct psmouse *psmouse)
+{
+	struct alps_data *priv = psmouse->private;
+	unsigned char *packet = psmouse->packet;
+	struct input_dev *dev = psmouse->dev;
+	int fingers = 0;
+	struct alps_fields f = {0};
+	struct alps_abs_data	pt_output[2] = { {0, 0, 0}, {0, 0, 0} };
+	unsigned char output_fn_num = 0;
+
+	priv->decode_fields(&f, packet, psmouse);
+
+	if ((!!priv->multi_packet) != (!!f.is_mp)) {
+		priv->multi_packet = 0;
+		return;
+	}
+
+	/* When f.first_mp is 1, next packet should be a
+	 *	bitmap packet(when there is no error).
+	 */
+	priv->multi_packet = f.first_mp;
+
+	/* Don't process any 3-f data */
+	if (f.first_mp || f.is_mp)
+		return;
+
+	/*
+	 * If we don't have MT data or the bitmaps were empty, we have
+	 * to rely on ST data.
+	 */
+	fingers = f.fingers;
+
+	alps_process_resting_finger(psmouse, &f, pt_output, &output_fn_num);
+	alps_process_btnless_click(psmouse, &f);
+
+	if (pt_output[0].z || pt_output[1].z)
+		input_report_key(dev, BTN_TOUCH, 1);
+	else
+		input_report_key(dev, BTN_TOUCH, 0);
+
+	alps_report_semi_mt_data_ex(dev, 2, pt_output);
+
+	input_mt_report_finger_count(dev, output_fn_num);
+
+	input_report_key(dev, BTN_LEFT, f.btn.left);
+	input_report_key(dev, BTN_RIGHT, f.btn.right);
+	input_report_key(dev, BTN_MIDDLE, f.btn.middle);
+
+	if (pt_output[0].z > 0) {
+		input_report_abs(dev, ABS_X, pt_output[0].x);
+		input_report_abs(dev, ABS_Y, pt_output[0].y);
+	}
+	input_report_abs(dev, ABS_PRESSURE, pt_output[0].z ? 30 : 0);
+
+	input_sync(dev);
+}
+
 static void alps_process_packet_v6(struct psmouse *psmouse)
 {
 	struct alps_data *priv = psmouse->private;
@@ -801,8 +1353,13 @@ static void alps_process_packet_v4(struct psmouse *psmouse)
 {
 	struct alps_data *priv = psmouse->private;
 	unsigned char *packet = psmouse->packet;
-	struct alps_fields *f = &priv->f;
+	struct input_dev *dev = psmouse->dev;
 	int offset;
+	int x, y, z;
+	int left, right;
+	int x1, y1, x2, y2;
+	int fingers = 0;
+	unsigned int x_bitmap, y_bitmap;
 
 	/*
 	 * v4 has a 6-byte encoding for bitmap data, but this data is
@@ -824,41 +1381,96 @@ static void alps_process_packet_v4(struct psmouse *psmouse)
 	if (++priv->multi_packet > 2) {
 		priv->multi_packet = 0;
 
-		f->x_map = ((priv->multi_data[2] & 0x1f) << 10) |
+		x_bitmap = ((priv->multi_data[2] & 0x1f) << 10) |
 			   ((priv->multi_data[3] & 0x60) << 3) |
 			   ((priv->multi_data[0] & 0x3f) << 2) |
 			   ((priv->multi_data[1] & 0x60) >> 5);
-		f->y_map = ((priv->multi_data[5] & 0x01) << 10) |
+		y_bitmap = ((priv->multi_data[5] & 0x01) << 10) |
 			   ((priv->multi_data[3] & 0x1f) << 5) |
 			    (priv->multi_data[1] & 0x1f);
 
-		f->fingers = alps_process_bitmap(priv, f);
+		fingers = alps_process_bitmap(priv, x_bitmap, y_bitmap,
+					      &x1, &y1, &x2, &y2);
+
+		/* Store MT data.*/
+		priv->fingers = fingers;
+		priv->x1 = x1;
+		priv->x2 = x2;
+		priv->y1 = y1;
+		priv->y2 = y2;
 	}
 
-	f->left = packet[4] & 0x01;
-	f->right = packet[4] & 0x02;
+	left = packet[4] & 0x01;
+	right = packet[4] & 0x02;
+
+	x = ((packet[1] & 0x7f) << 4) | ((packet[3] & 0x30) >> 2) |
+	    ((packet[0] & 0x30) >> 4);
+	y = ((packet[2] & 0x7f) << 4) | (packet[3] & 0x0f);
+	z = packet[5] & 0x7f;
+
+	/*
+	 * If there were no contacts in the bitmap, use ST
+	 * points in MT reports.
+	 * If there were two contacts or more, report MT data.
+	 */
+	if (priv->fingers < 2) {
+		x1 = x;
+		y1 = y;
+		fingers = z > 0 ? 1 : 0;
+	} else {
+		fingers = priv->fingers;
+		x1 = priv->x1;
+		x2 = priv->x2;
+		y1 = priv->y1;
+		y2 = priv->y2;
+	}
+
+	if (z >= 64)
+		input_report_key(dev, BTN_TOUCH, 1);
+	else
+		input_report_key(dev, BTN_TOUCH, 0);
+
+	alps_report_semi_mt_data(dev, fingers, x1, y1, x2, y2);
+
+	input_mt_report_finger_count(dev, fingers);
+
+	input_report_key(dev, BTN_LEFT, left);
+	input_report_key(dev, BTN_RIGHT, right);
 
-	f->st.x = ((packet[1] & 0x7f) << 4) | ((packet[3] & 0x30) >> 2) |
-		  ((packet[0] & 0x30) >> 4);
-	f->st.y = ((packet[2] & 0x7f) << 4) | (packet[3] & 0x0f);
-	f->pressure = packet[5] & 0x7f;
+	if (z > 0) {
+		input_report_abs(dev, ABS_X, x);
+		input_report_abs(dev, ABS_Y, y);
+	}
+	input_report_abs(dev, ABS_PRESSURE, z);
 
-	alps_report_semi_mt_data(psmouse, f->fingers);
+	input_sync(dev);
 }
 
 static bool alps_is_valid_package_v7(struct psmouse *psmouse)
 {
-	switch (psmouse->pktcnt) {
-	case 3:
-		return (psmouse->packet[2] & 0x40) == 0x40;
-	case 4:
-		return (psmouse->packet[3] & 0x48) == 0x48;
-	case 6:
-		return (psmouse->packet[5] & 0x40) == 0x00;
-	}
+	if ((psmouse->pktcnt == 3) && ((psmouse->packet[2] & 0x40) != 0x40))
+		return false;
+	if ((psmouse->pktcnt == 4) && ((psmouse->packet[3] & 0x48) != 0x48))
+		return false;
+	if ((psmouse->pktcnt == 6) && ((psmouse->packet[5] & 0x40) != 0x0))
+		return false;
 	return true;
 }
 
+static int alps_drop_unsupported_packet_v7(struct psmouse *psmouse)
+{
+	struct alps_data *priv = psmouse->private;
+	int drop = 1;
+
+	if (priv->r.v7.pkt_id == V7_PACKET_ID_NEW ||
+	    priv->r.v7.pkt_id == V7_PACKET_ID_TWO ||
+	    priv->r.v7.pkt_id == V7_PACKET_ID_MULTI ||
+	    priv->r.v7.pkt_id == V7_PACKET_ID_IDLE)
+		drop = 0;
+
+	return drop;
+}
+
 static unsigned char alps_get_packet_id_v7(char *byte)
 {
 	unsigned char packet_id;
@@ -874,85 +1486,251 @@ static unsigned char alps_get_packet_id_v7(char *byte)
 	else
 		packet_id = V7_PACKET_ID_UNKNOWN;
 
-	return packet_id;
+	return packet_id;
+}
+
+static void alps_get_finger_coordinate_v7(struct alps_abs_data *pt,
+					  unsigned char *pkt,
+					  unsigned char pkt_id)
+{
+	if ((pkt_id == V7_PACKET_ID_TWO) ||
+	   (pkt_id == V7_PACKET_ID_MULTI) ||
+	   (pkt_id == V7_PACKET_ID_NEW)) {
+		pt[0].x = ((pkt[2] & 0x80) << 4);
+		pt[0].x |= ((pkt[2] & 0x3F) << 5);
+		pt[0].x |= ((pkt[3] & 0x30) >> 1);
+		pt[0].x |= (pkt[3] & 0x07);
+		pt[0].y = (pkt[1] << 3) | (pkt[0] & 0x07);
+
+		pt[1].x = ((pkt[3] & 0x80) << 4);
+		pt[1].x |= ((pkt[4] & 0x80) << 3);
+		pt[1].x |= ((pkt[4] & 0x3F) << 4);
+		pt[1].y = ((pkt[5] & 0x80) << 3);
+		pt[1].y |= ((pkt[5] & 0x3F) << 4);
+
+		if (pkt_id == V7_PACKET_ID_TWO) {
+			pt[1].x &= ~0x000F;
+			pt[1].y |= 0x000F;
+		} else if (pkt_id == V7_PACKET_ID_MULTI) {
+			pt[1].x &= ~0x003F;
+			pt[1].y &= ~0x0020;
+			pt[1].y |= ((pkt[4] & 0x02) << 4);
+			pt[1].y |= 0x001F;
+		} else if (pkt_id == V7_PACKET_ID_NEW) {
+			pt[1].x &= ~0x003F;
+			pt[1].x |= (pkt[0] & 0x20);
+			pt[1].y |= 0x000F;
+		}
+
+		pt[0].y = 0x7FF - pt[0].y;
+		pt[1].y = 0x7FF - pt[1].y;
+
+		pt[0].z = (pt[0].x && pt[0].y) ? 62 : 0;
+		pt[1].z = (pt[1].x && pt[1].y) ? 62 : 0;
+	}
+}
+
+static void alps_decode_packet_v7(struct alps_fields *f,
+				  unsigned char *p,
+				  struct psmouse *psmouse)
+{
+	struct alps_data *priv = psmouse->private;
+
+	priv->r.v7.pkt_id = alps_get_packet_id_v7(p);
+
+	alps_get_finger_coordinate_v7(f->pt_img, p, priv->r.v7.pkt_id);
+
+	priv->r.v7.rest_left = 0;
+	priv->r.v7.rest_right = 0;
+	priv->r.v7.additional_fingers = 0;
+	memset(&f->btn, 0, sizeof(struct alps_btn));
+
+	if (priv->r.v7.pkt_id == V7_PACKET_ID_TWO ||
+	    priv->r.v7.pkt_id == V7_PACKET_ID_MULTI) {
+
+		if (priv->flags & ALPS_BTNLESS) {
+			priv->r.v7.rest_left = (p[0] & 0x10) >> 4;
+			priv->r.v7.rest_right = (p[0] & 0x20) >> 5;
+			f->btn.middle = (p[0] & 0x80) >> 7;
+		} else {
+			f->btn.left = (p[0] & 0x80) >> 7;
+			f->btn.right = (p[0] & 0x20) >> 5;
+			f->btn.middle = (p[0] & 0x10) >> 4;
+		}
+	}
+
+	if (priv->r.v7.pkt_id == V7_PACKET_ID_MULTI)
+		priv->r.v7.additional_fingers = p[5] & 0x03;
 }
 
-static void alps_get_finger_coordinate_v7(struct input_mt_pos *mt,
-					  unsigned char *pkt,
-					  unsigned char pkt_id)
+static void alps_set_each_pt_attr_v7(struct psmouse *psmouse,
+				     struct alps_abs_data *pt,
+				     struct alps_bl_pt_attr *pt_attr)
 {
-	mt[0].x = ((pkt[2] & 0x80) << 4);
-	mt[0].x |= ((pkt[2] & 0x3F) << 5);
-	mt[0].x |= ((pkt[3] & 0x30) >> 1);
-	mt[0].x |= (pkt[3] & 0x07);
-	mt[0].y = (pkt[1] << 3) | (pkt[0] & 0x07);
+	struct alps_data *priv = psmouse->private;
+	unsigned int dist;
 
-	mt[1].x = ((pkt[3] & 0x80) << 4);
-	mt[1].x |= ((pkt[4] & 0x80) << 3);
-	mt[1].x |= ((pkt[4] & 0x3F) << 4);
-	mt[1].y = ((pkt[5] & 0x80) << 3);
-	mt[1].y |= ((pkt[5] & 0x3F) << 4);
+	if (!pt_attr->is_init_pt_got && pt->z != 0) {
+		pt_attr->is_init_pt_got = 1;
+		pt_attr->is_counted = 0;
+		memcpy(&pt_attr->init_pt, pt, sizeof(pt_attr->init_pt));
+	}
 
-	switch (pkt_id) {
-	case V7_PACKET_ID_TWO:
-		mt[1].x &= ~0x000F;
-		mt[1].y |= 0x000F;
-		break;
+	if (pt->z != 0) {
+		if (pt->y < priv->resting_zone_y_min) {
+			/* A finger is recognized as
+			a non-resting finger if it's
+			position is outside the resting finger zone.*/
+			pt_attr->zone = ZONE_NORMAL;
+			pt_attr->is_counted = 1;
+		} else {
+			/* A finger is recognized as
+			a resting finger if it's position
+			is inside the resting finger zone and
+			there's no large movement
+			from it's touch down position.*/
+			pt_attr->zone = ZONE_RESTING;
+
+			if (pt->x > priv->x_max / 2)
+				pt_attr->zone |= ZONE_RIGHT_BTN;
+			else
+				pt_attr->zone |= ZONE_LEFT_BTN;
+
+			/* A resting finger will turn to
+			be a non-resting finger if it
+			has made large movement from it's touch down position. A
+			non-resting finger will never turn to
+			a resting finger before
+			it leaves the touchpad surface.*/
+			if (pt_attr->is_init_pt_got) {
+				dist = alps_pt_distance(pt, &pt_attr->init_pt);
+
+				if (dist > V7_LARGE_MOVEMENT)
+					pt_attr->is_counted = 1;
+			}
+		}
+	}
+}
 
-	case V7_PACKET_ID_MULTI:
-		mt[1].x &= ~0x003F;
-		mt[1].y &= ~0x0020;
-		mt[1].y |= ((pkt[4] & 0x02) << 4);
-		mt[1].y |= 0x001F;
-		break;
+static void alps_set_pt_attr_v7(struct psmouse *psmouse,
+				       struct alps_fields *f)
+{
+	struct alps_data *priv = psmouse->private;
+	int i;
 
-	case V7_PACKET_ID_NEW:
-		mt[1].x &= ~0x003F;
-		mt[1].x |= (pkt[0] & 0x20);
-		mt[1].y |= 0x000F;
+	switch (priv->r.v7.pkt_id) {
+	case  V7_PACKET_ID_TWO:
+	case  V7_PACKET_ID_MULTI:
+		for (i = 0; i < V7_IMG_PT_NUM; i++)
+			alps_set_each_pt_attr_v7(psmouse,
+						 &f->pt_img[i],
+						 &priv->pt_attr[i]);
+		break;
+	default:
+		/*All finger attributes are cleared
+		when packet ID is 'IDLE', 'New'or
+		other unknown IDs. An 'IDLE' packet indicates
+		that there's no finger and no button activity.
+		A 'NEW' packet indicates the finger position
+		in packet is not continues from previous packet.
+		Such as the condition there's finger placed or lifted.
+		In these cases, finger attributes will be reset.*/
+
+		memset(priv->pt_attr, 0,
+			sizeof(priv->pt_attr[0]) * V7_IMG_PT_NUM);
 		break;
 	}
-
-	mt[0].y = 0x7FF - mt[0].y;
-	mt[1].y = 0x7FF - mt[1].y;
 }
 
-static int alps_get_mt_count(struct input_mt_pos *mt)
+static void alps_cal_output_finger_num_v7(struct psmouse *psmouse,
+					struct alps_fields *f)
 {
+	struct alps_data *priv = psmouse->private;
+	unsigned int fn = 0;
 	int i;
 
-	for (i = 0; i < MAX_TOUCHES && mt[i].x != 0 && mt[i].y != 0; i++)
-		/* empty */;
+	switch (priv->r.v7.pkt_id) {
+	case V7_PACKET_ID_IDLE:
+	case V7_PACKET_ID_NEW:
+		/*No finger is reported when packet ID is
+		'IDLE' or 'New'. An 'IDLE' packet indicates
+		that there's no finger on touchpad.
+		A 'NEW' packet indicates there's finger placed
+		or lifted. Finger position of 'New' packet is
+		not continues from the previous packet.*/
+		fn = 0;
+		break;
+	case V7_PACKET_ID_TWO:
+		if (f->pt_img[0].z == 0) {
+			/*The first finger slot is zero when
+			a non-resting finger lifted and remaining
+			only one resting finger on touchpad.
+			Hardware report the remaining resting finger
+			in second slot.This resting is ignored*/
+			fn = 0;
+		} else if (f->pt_img[1].z == 0) {
+			/* The second finger slot is zero
+			if there's only one finger*/
+			fn = 1;
+		} else {
+			/*All non-resting fingers will be counted to report*/
+			fn = 0;
+			for (i = 0; i < V7_IMG_PT_NUM; i++) {
+				if (priv->pt_attr[i].is_counted)
+					fn++;
+			}
+
+			/*In the case that both fingers are
+			resting fingers, report the first one*/
+			if (!priv->pt_attr[0].is_counted &&
+			    !priv->pt_attr[1].is_counted) {
+				fn = 1;
+			}
+		}
+		break;
+	case V7_PACKET_ID_MULTI:
+		/*A packet ID 'MULTI' indicats that at least 3 non-resting
+		finger exist.*/
+		fn = 3 + priv->r.v7.additional_fingers;
+		break;
+	}
 
-	return i;
+	f->fingers = fn;
 }
 
-static int alps_decode_packet_v7(struct alps_fields *f,
-				  unsigned char *p,
-				  struct psmouse *psmouse)
+static void alps_assign_buttons_v7(struct psmouse *psmouse,
+				   struct alps_fields *f)
 {
-	unsigned char pkt_id;
+	struct alps_data *priv = psmouse->private;
 
-	pkt_id = alps_get_packet_id_v7(p);
-	if (pkt_id == V7_PACKET_ID_IDLE)
-		return 0;
-	if (pkt_id == V7_PACKET_ID_UNKNOWN)
-		return -1;
+	/* It's ClickPad */
+	if (priv->flags & ALPS_BTNLESS) {
+		if (!f->btn.middle)
+			goto exit;
+
+		f->btn.middle = 0;
+		if (priv->prev_btn.left || priv->prev_btn.middle ||
+			priv->prev_btn.right) {
+			memcpy(&f->btn, &priv->prev_btn,
+				sizeof(struct alps_btn));
+			goto exit;
+		}
 
-	alps_get_finger_coordinate_v7(f->mt, p, pkt_id);
+		if (priv->r.v7.rest_right ||
+		    priv->pt_attr[0].zone & ZONE_RIGHT_BTN ||
+		    priv->pt_attr[1].zone & ZONE_RIGHT_BTN) {
+			f->btn.right = 1;
+		} else {
+			f->btn.left = 1;
+		}
 
-	if (pkt_id == V7_PACKET_ID_TWO || pkt_id == V7_PACKET_ID_MULTI) {
-		f->left = (p[0] & 0x80) >> 7;
-		f->right = (p[0] & 0x20) >> 5;
-		f->middle = (p[0] & 0x10) >> 4;
+		goto exit;
 	}
 
-	if (pkt_id == V7_PACKET_ID_TWO)
-		f->fingers = alps_get_mt_count(f->mt);
-	else if (pkt_id == V7_PACKET_ID_MULTI)
-		f->fingers = 3 + (p[5] & 0x03);
+	/* It's Standard, do nothing */
 
-	return 0;
+exit:
+	memcpy(&priv->prev_btn, &f->btn, sizeof(struct alps_btn));
 }
 
 static void alps_process_trackstick_packet_v7(struct psmouse *psmouse)
@@ -962,21 +1740,9 @@ static void alps_process_trackstick_packet_v7(struct psmouse *psmouse)
 	struct input_dev *dev2 = priv->dev2;
 	int x, y, z, left, right, middle;
 
-	/*
-	 *        b7 b6 b5 b4 b3 b2 b1 b0
-	 * Byte0   0  1  0  0  1  0  0  0
-	 * Byte1   1  1  *  *  1  M  R  L
-	 * Byte2  X7  1 X5 X4 X3 X2 X1 X0
-	 * Byte3  Z6  1 Y6 X6  1 Y2 Y1 Y0
-	 * Byte4  Y7  0 Y5 Y4 Y3  1  1  0
-	 * Byte5 T&P  0 Z5 Z4 Z3 Z2 Z1 Z0
-	 * M / R / L: Middle / Right / Left button
-	 */
-
-	x = ((packet[2] & 0xbf)) | ((packet[3] & 0x10) << 2);
-	y = (packet[3] & 0x07) | (packet[4] & 0xb8) |
-	    ((packet[3] & 0x20) << 1);
-	z = (packet[5] & 0x3f) | ((packet[3] & 0x80) >> 1);
+	x = ((packet[2] & 0xBF)) | ((packet[3] & 0x10) << 2);
+	y = (packet[3] & 0x03) | (packet[4] & 0xB8) | ((packet[3] & 0x20) << 1);
+	z = (packet[5] & 0x3F) | ((packet[3] & 0x80) >> 1);
 
 	left = (packet[1] & 0x01);
 	right = (packet[1] & 0x02) >> 1;
@@ -996,35 +1762,115 @@ static void alps_process_trackstick_packet_v7(struct psmouse *psmouse)
 static void alps_process_touchpad_packet_v7(struct psmouse *psmouse)
 {
 	struct alps_data *priv = psmouse->private;
-	struct input_dev *dev = psmouse->dev;
-	struct alps_fields *f = &priv->f;
+	struct alps_fields f = {0};
+	unsigned char *packet = psmouse->packet;
 
-	memset(f, 0, sizeof(*f));
+	priv->decode_fields(&f, packet, psmouse);
 
-	if (priv->decode_fields(f, psmouse->packet, psmouse))
+	if (alps_drop_unsupported_packet_v7(psmouse))
 		return;
 
-	alps_report_mt_data(psmouse, alps_get_mt_count(f->mt));
+	alps_set_pt_attr_v7(psmouse, &f);
 
-	input_mt_report_finger_count(dev, f->fingers);
+	alps_cal_output_finger_num_v7(psmouse, &f);
 
-	input_report_key(dev, BTN_LEFT, f->left);
-	input_report_key(dev, BTN_RIGHT, f->right);
-	input_report_key(dev, BTN_MIDDLE, f->middle);
+	alps_assign_buttons_v7(psmouse, &f);
 
-	input_sync(dev);
+	alps_report_coord_and_btn(psmouse, &f);
 }
 
 static void alps_process_packet_v7(struct psmouse *psmouse)
 {
 	unsigned char *packet = psmouse->packet;
 
-	if (packet[0] == 0x48 && (packet[4] & 0x47) == 0x06)
+	if ((packet[0] == 0x48) && ((packet[4] & 0x47) == 0x06))
 		alps_process_trackstick_packet_v7(psmouse);
 	else
 		alps_process_touchpad_packet_v7(psmouse);
 }
 
+static void alps_process_packet_ss4(struct psmouse *psmouse)
+{
+	struct alps_data *priv = psmouse->private;
+	unsigned char *packet = psmouse->packet;
+	struct input_dev *dev = psmouse->dev;
+	struct alps_fields f;
+	struct alps_abs_data output_data[5];
+	unsigned char output_fn;
+
+	memset(&f, 0, sizeof(struct alps_fields));
+	priv->decode_fields(&f, packet, psmouse);
+
+	if (priv->multi_packet) {
+		/*
+		 * Sometimes the first packet will indicate a multi-packet
+		 * sequence, but sometimes the next multi-packet would not come.
+		 * Check for this, and when it happens process the
+		 * position packet as usual.
+		 */
+		if (f.is_mp) {
+			/* Now process the 1st packet */
+			priv->decode_fields(&f, priv->multi_data, psmouse);
+		} else {
+			priv->multi_packet = 0;
+		}
+	}
+
+	/*
+	 * "f.is_mp" would always be '0' after merging the 1st and 2nd packet.
+	 * When it is set, it means 2nd packet comes without 1st packet come.
+	 */
+	if (f.is_mp)
+		return;
+
+	/* Save the first packet */
+	if (!priv->multi_packet && f.first_mp) {
+		priv->multi_packet = 1;
+		memcpy(priv->multi_data, packet, sizeof(priv->multi_data));
+		return;
+	}
+
+	priv->multi_packet = 0;
+
+	/* Set "output_data" and "output_fn" */
+	memset(&output_data[0], 0, sizeof(output_data));
+	if (priv->flags & ALPS_BTNLESS) {
+		alps_process_resting_finger(psmouse, &f,
+			output_data, &output_fn);
+		alps_process_btnless_click(psmouse, &f);
+	} else {
+		memcpy(&output_data[0], &f.pt_img[0],
+			sizeof(struct alps_abs_data) * f.fingers);
+		output_fn = f.fingers;
+	}
+
+	f.pt.x = output_data[0].x;
+	f.pt.y = output_data[0].y;
+	f.pt.z = output_data[0].z;
+
+	if (output_data[0].z || output_data[1].z ||
+		output_data[2].z || output_data[3].z)
+		input_report_key(dev, BTN_TOUCH, 1);
+	else
+		input_report_key(dev, BTN_TOUCH, 0);
+
+	alps_report_semi_mt_data_ex(dev, 4, output_data);
+
+	input_mt_report_finger_count(dev, output_fn);
+
+	input_report_key(dev, BTN_LEFT, f.btn.left);
+	input_report_key(dev, BTN_RIGHT, f.btn.right);
+	input_report_key(dev, BTN_MIDDLE, f.btn.middle);
+
+	if (f.pt.z > 0) {
+		input_report_abs(dev, ABS_X, f.pt.x);
+		input_report_abs(dev, ABS_Y, f.pt.y);
+	}
+	input_report_abs(dev, ABS_PRESSURE, f.pt.z);
+
+	input_sync(dev);
+}
+
 static void alps_report_bare_ps2_packet(struct psmouse *psmouse,
 					unsigned char packet[],
 					bool report_buttons)
@@ -1152,11 +1998,22 @@ static void alps_flush_packet(unsigned long data)
 	serio_continue_rx(psmouse->ps2dev.serio);
 }
 
+static bool alps_is_valid_package_ss4(struct psmouse *psmouse)
+{
+	if (psmouse->pktcnt == 4 && ((psmouse->packet[3] & 0x08) != 0x08))
+		return false;
+	if (psmouse->pktcnt == 6 && ((psmouse->packet[5] & 0x10) != 0x0))
+		return false;
+	return true;
+}
+
 static psmouse_ret_t alps_process_byte(struct psmouse *psmouse)
 {
 	struct alps_data *priv = psmouse->private;
 
-	if ((psmouse->packet[0] & 0xc8) == 0x08) { /* PS/2 packet */
+	/* Can not distinguish V8's first byte from PS/2 packet's */
+	if ((psmouse->packet[0] & 0xc8) == 0x08 &&
+			priv->proto_version != ALPS_PROTO_V8) {
 		if (psmouse->pktcnt == 3) {
 			alps_report_bare_ps2_packet(psmouse, psmouse->packet,
 						    true);
@@ -1189,8 +2046,10 @@ static psmouse_ret_t alps_process_byte(struct psmouse *psmouse)
 		return PSMOUSE_BAD_DATA;
 	}
 
-	if (priv->proto_version == ALPS_PROTO_V7 &&
-	    !alps_is_valid_package_v7(psmouse)) {
+	if ((priv->proto_version == ALPS_PROTO_V7 &&
+		!alps_is_valid_package_v7(psmouse)) ||
+		(priv->proto_version == ALPS_PROTO_V8 &&
+		!alps_is_valid_package_ss4(psmouse))) {
 		psmouse_dbg(psmouse, "refusing packet[%i] = %x\n",
 			    psmouse->pktcnt - 1,
 			    psmouse->packet[psmouse->pktcnt - 1]);
@@ -1309,20 +2168,20 @@ static int alps_rpt_cmd(struct psmouse *psmouse, int init_command,
 	return 0;
 }
 
-static bool alps_check_valid_firmware_id(unsigned char id[])
+static int alps_check_valid_firmware_id(unsigned char id[])
 {
-	if (id[0] == 0x73)
-		return true;
+	int valid = 1;
 
-	if (id[0] == 0x88 &&
-	    (id[1] == 0x07 ||
-	     id[1] == 0x08 ||
-	     (id[1] & 0xf0) == 0xb0 ||
-	     (id[1] & 0xf0) == 0xc0)) {
-		return true;
+	if (id[0] == 0x73)
+		valid = 1;
+	else if (id[0] == 0x88) {
+		if ((id[1] == 0x07) ||
+		    (id[1] == 0x08) ||
+		    ((id[1] & 0xf0) == 0xB0))
+			valid = 1;
 	}
 
-	return false;
+	return valid;
 }
 
 static int alps_enter_command_mode(struct psmouse *psmouse)
@@ -1792,45 +2651,6 @@ error:
 	return -1;
 }
 
-static int alps_get_v3_v7_resolution(struct psmouse *psmouse, int reg_pitch)
-{
-	int reg, x_pitch, y_pitch, x_electrode, y_electrode, x_phys, y_phys;
-	struct alps_data *priv = psmouse->private;
-
-	reg = alps_command_mode_read_reg(psmouse, reg_pitch);
-	if (reg < 0)
-		return reg;
-
-	x_pitch = (char)(reg << 4) >> 4; /* sign extend lower 4 bits */
-	x_pitch = 50 + 2 * x_pitch; /* In 0.1 mm units */
-
-	y_pitch = (char)reg >> 4; /* sign extend upper 4 bits */
-	y_pitch = 36 + 2 * y_pitch; /* In 0.1 mm units */
-
-	reg = alps_command_mode_read_reg(psmouse, reg_pitch + 1);
-	if (reg < 0)
-		return reg;
-
-	x_electrode = (char)(reg << 4) >> 4; /* sign extend lower 4 bits */
-	x_electrode = 17 + x_electrode;
-
-	y_electrode = (char)reg >> 4; /* sign extend upper 4 bits */
-	y_electrode = 13 + y_electrode;
-
-	x_phys = x_pitch * (x_electrode - 1); /* In 0.1 mm units */
-	y_phys = y_pitch * (y_electrode - 1); /* In 0.1 mm units */
-
-	priv->x_res = priv->x_max * 10 / x_phys; /* units / mm */
-	priv->y_res = priv->y_max * 10 / y_phys; /* units / mm */
-
-	psmouse_dbg(psmouse,
-		    "pitch %dx%d num-electrodes %dx%d physical size %dx%d mm res %dx%d\n",
-		    x_pitch, y_pitch, x_electrode, y_electrode,
-		    x_phys / 10, y_phys / 10, priv->x_res, priv->y_res);
-
-	return 0;
-}
-
 static int alps_hw_init_rushmore_v3(struct psmouse *psmouse)
 {
 	struct alps_data *priv = psmouse->private;
@@ -1851,9 +2671,6 @@ static int alps_hw_init_rushmore_v3(struct psmouse *psmouse)
 	    alps_command_mode_write_reg(psmouse, 0xc2cb, 0x00))
 		goto error;
 
-	if (alps_get_v3_v7_resolution(psmouse, 0xc2da))
-		goto error;
-
 	reg_val = alps_command_mode_read_reg(psmouse, 0xc2c6);
 	if (reg_val == -1)
 		goto error;
@@ -1878,6 +2695,32 @@ error:
 	return ret;
 }
 
+static int alps_hw_init_v7(struct psmouse *psmouse)
+{
+	struct ps2dev *ps2dev = &psmouse->ps2dev;
+	int reg_val, ret = -1;
+
+	if (alps_enter_command_mode(psmouse) ||
+	    alps_command_mode_read_reg(psmouse, 0xc2d9) == -1)
+		goto error;
+
+	if (alps_command_mode_write_reg(psmouse, 0xc2c9, 0x64))
+		goto error;
+
+	reg_val = alps_command_mode_read_reg(psmouse, 0xc2c4);
+	if (reg_val == -1)
+		goto error;
+	if (__alps_command_mode_write_reg(psmouse, reg_val | 0x02))
+		goto error;
+
+	alps_exit_command_mode(psmouse);
+	return ps2_command(ps2dev, NULL, PSMOUSE_CMD_ENABLE);
+
+error:
+	alps_exit_command_mode(psmouse);
+	return ret;
+}
+
 /* Must be in command mode when calling this function */
 static int alps_absolute_mode_v4(struct psmouse *psmouse)
 {
@@ -1967,6 +2810,102 @@ error:
 	return -1;
 }
 
+static int alps_get_otp_values_ss4(struct psmouse *psmouse,
+	unsigned char index, unsigned char otp[])
+{
+	struct ps2dev *ps2dev = &psmouse->ps2dev;
+
+	switch (index) {
+	case 0:
+		if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSTREAM)  ||
+		    ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSTREAM)  ||
+		    ps2_command(ps2dev, otp, PSMOUSE_CMD_GETINFO))
+			return -1;
+
+		break;
+
+	case 1:
+		if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETPOLL)  ||
+		    ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETPOLL)  ||
+		    ps2_command(ps2dev, otp, PSMOUSE_CMD_GETINFO))
+			return -1;
+
+		break;
+	}
+
+	return 0;
+}
+
+int alps_update_device_area_ss4_v1(
+	unsigned char otp[][4], struct alps_data *priv)
+{
+	int	num_x_electrode;
+	int	num_y_electrode;
+
+	num_x_electrode = SS4_NUMSENSOR_XOFFSET + (otp[1][0]		& 0x0F);
+	num_y_electrode = ((otp[1][0] >> 4)	& 0x0F);
+
+	priv->x_max = (num_x_electrode - 1) * SS4_COUNT_PER_ELECTRODE;
+	priv->y_max = (num_y_electrode - 1) * SS4_COUNT_PER_ELECTRODE;
+
+	return 0;
+}
+
+int alps_update_device_area_ss4_v2(
+	unsigned char otp[][4], struct alps_data *priv)
+{
+	int	num_x_electrode;
+	int	num_y_electrode;
+
+	num_x_electrode = SS4_NUMSENSOR_XOFFSET + (otp[1][0] & 0x0F);
+	if ((priv->fw_ver[1] > 2) ||
+		(priv->fw_ver[1] == 2 && priv->fw_ver[2] > 0x33)) {
+		num_y_electrode =
+			SS4_NUMSENSOR_YOFFSET + ((otp[1][0] >> 4) & 0x07);
+	} else {
+		num_y_electrode = ((otp[1][0] >> 4) & 0x0F);
+	}
+
+	priv->x_max = (num_x_electrode - 1) * SS4_COUNT_PER_ELECTRODE;
+	priv->y_max = (num_y_electrode - 1) * SS4_COUNT_PER_ELECTRODE;
+
+	return 0;
+}
+
+int alps_update_btn_info_ss4(unsigned char otp[][4], struct alps_data *priv)
+{
+
+	unsigned char is_btnless = 0;
+
+	is_btnless = (otp[1][1] >> 3) &  0x01;
+
+	if (is_btnless)
+		priv->flags |= ALPS_BTNLESS;
+
+	return 0;
+}
+
+static int alps_set_defaults_ss4(struct psmouse *psmouse,
+					struct alps_data *priv)
+{
+	unsigned char otp[2][4];
+
+	memset(otp, 0, sizeof(otp));
+
+	if (alps_get_otp_values_ss4(psmouse, 0, &otp[0][0]) ||
+	    alps_get_otp_values_ss4(psmouse, 1, &otp[1][0]))
+		return -1;
+
+	if (priv->fw_ver[1] >= 2)
+		alps_update_device_area_ss4_v2(otp, priv);
+	else
+		alps_update_device_area_ss4_v1(otp, priv);
+
+	alps_update_btn_info_ss4(otp, priv);
+
+	return 0;
+}
+
 static int alps_dolphin_get_device_area(struct psmouse *psmouse,
 					struct alps_data *priv)
 {
@@ -2030,28 +2969,54 @@ static int alps_hw_init_dolphin_v1(struct psmouse *psmouse)
 	return 0;
 }
 
-static int alps_hw_init_v7(struct psmouse *psmouse)
+static int alps_hw_init_ss3(struct psmouse *psmouse)
 {
 	struct ps2dev *ps2dev = &psmouse->ps2dev;
-	int reg_val, ret = -1;
+	unsigned char	f3param0 = 0x00,
+					f3param1 = 0x00;
 
-	if (alps_enter_command_mode(psmouse) ||
-	    alps_command_mode_read_reg(psmouse, 0xc2d9) == -1)
+	if (alps_enter_command_mode(psmouse))
 		goto error;
 
-	if (alps_get_v3_v7_resolution(psmouse, 0xc397))
+	/* Set to 2 pt-mode */
+	f3param0 = 0x50;
+	f3param1 = 0x3c;
+	if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSTREAM) ||
+	    ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSTREAM) ||
+	    ps2_command(ps2dev, &f3param0, PSMOUSE_CMD_SETRATE) ||
+	    ps2_command(ps2dev, &f3param1, PSMOUSE_CMD_SETRATE))
 		goto error;
 
-	if (alps_command_mode_write_reg(psmouse, 0xc2c9, 0x64))
-		goto error;
+	/* output APDATA when 1 finger is in resting area */
+	f3param0 = 0xc8;
+	f3param1 = 0x28;
+	if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSTREAM) ||
+	    ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSTREAM) ||
+	    ps2_command(ps2dev, &f3param0, PSMOUSE_CMD_SETRATE) ||
+	    ps2_command(ps2dev, &f3param1, PSMOUSE_CMD_SETRATE))
+			goto error;
 
-	reg_val = alps_command_mode_read_reg(psmouse, 0xc2c4);
-	if (reg_val == -1)
-		goto error;
-	if (__alps_command_mode_write_reg(psmouse, reg_val | 0x02))
+	return 0;
+
+error:
+	return -1;
+}
+
+
+static int alps_hw_init_ss4(struct psmouse *psmouse)
+{
+	struct ps2dev *ps2dev = &psmouse->ps2dev;
+	char param[2] = {0x64, 0x28};
+	int ret = -1;
+
+	/* enter absolute mode */
+	if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSTREAM) ||
+	    ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSTREAM) ||
+	    ps2_command(ps2dev, &param[0], PSMOUSE_CMD_SETRATE) ||
+	    ps2_command(ps2dev, &param[1], PSMOUSE_CMD_SETRATE)) {
 		goto error;
+	}
 
-	alps_exit_command_mode(psmouse);
 	return ps2_command(ps2dev, NULL, PSMOUSE_CMD_ENABLE);
 
 error:
@@ -2078,6 +3043,7 @@ static void alps_set_defaults(struct alps_data *priv)
 		priv->set_abs_params = alps_set_abs_params_st;
 		priv->x_max = 1023;
 		priv->y_max = 767;
+		priv->slot_number = 1;
 		break;
 	case ALPS_PROTO_V3:
 		priv->hw_init = alps_hw_init_v3;
@@ -2086,6 +3052,7 @@ static void alps_set_defaults(struct alps_data *priv)
 		priv->decode_fields = alps_decode_pinnacle;
 		priv->nibble_commands = alps_v3_nibble_commands;
 		priv->addr_command = PSMOUSE_CMD_RESET_WRAP;
+		priv->slot_number = 2;
 		break;
 	case ALPS_PROTO_V4:
 		priv->hw_init = alps_hw_init_v4;
@@ -2093,6 +3060,7 @@ static void alps_set_defaults(struct alps_data *priv)
 		priv->set_abs_params = alps_set_abs_params_mt;
 		priv->nibble_commands = alps_v4_nibble_commands;
 		priv->addr_command = PSMOUSE_CMD_DISABLE;
+		priv->slot_number = 2;
 		break;
 	case ALPS_PROTO_V5:
 		priv->hw_init = alps_hw_init_dolphin_v1;
@@ -2108,6 +3076,7 @@ static void alps_set_defaults(struct alps_data *priv)
 		priv->y_max = 660;
 		priv->x_bits = 23;
 		priv->y_bits = 12;
+		priv->slot_number = 2;
 		break;
 	case ALPS_PROTO_V6:
 		priv->hw_init = alps_hw_init_v6;
@@ -2116,6 +3085,7 @@ static void alps_set_defaults(struct alps_data *priv)
 		priv->nibble_commands = alps_v6_nibble_commands;
 		priv->x_max = 2047;
 		priv->y_max = 1535;
+		priv->slot_number = 1;
 		break;
 	case ALPS_PROTO_V7:
 		priv->hw_init = alps_hw_init_v7;
@@ -2129,8 +3099,44 @@ static void alps_set_defaults(struct alps_data *priv)
 		priv->byte0 = 0x48;
 		priv->mask0 = 0x48;
 
-		if (priv->fw_ver[1] != 0xba)
-			priv->flags |= ALPS_BUTTONPAD;
+		if (priv->fw_ver[1] == 0xBA) {
+			priv->flags = 0;
+			/* No resting finger area */
+			priv->resting_zone_y_min = priv->y_max;
+		} else {
+			priv->flags = ALPS_BTNLESS;
+			priv->resting_zone_y_min = 0x654;
+		}
+
+		priv->slot_number = 2;
+		break;
+	case ALPS_PROTO_V8:
+		if (priv->fw_ver[1] >= 2)
+			priv->decode_fields = alps_decode_ss4_v2;
+		else
+			priv->decode_fields = alps_decode_ss4_v1;
+
+		priv->hw_init = alps_hw_init_ss4;
+		priv->process_packet = alps_process_packet_ss4;
+		priv->set_abs_params = alps_set_abs_params_mt;
+		priv->nibble_commands = alps_v3_nibble_commands;
+		priv->addr_command = PSMOUSE_CMD_RESET_WRAP;
+		priv->x_max = 0xfff;
+		priv->y_max = 0x7ff;
+		priv->byte0 = 0x18;
+		priv->mask0 = 0x18;
+		priv->flags = 0;
+		priv->slot_number = 4;
+		break;
+	case ALPS_PROTO_V9:
+		priv->hw_init = alps_hw_init_ss3;
+		priv->process_packet = alps_process_touchpad_packet_ss3;
+		priv->decode_fields = alps_decode_dolphin;
+		priv->set_abs_params = alps_set_abs_params_mt;
+		priv->nibble_commands = alps_v3_nibble_commands;
+		priv->byte0 = 0xc8;
+		priv->mask0 = 0xc8;
+		priv->slot_number = 2;
 		break;
 	}
 }
@@ -2204,7 +3210,7 @@ static int alps_identify(struct psmouse *psmouse, struct alps_data *priv)
 		else
 			return 0;
 	} else if (ec[0] == 0x88 &&
-		   ((ec[1] & 0xf0) == 0xb0 || (ec[1] & 0xf0) == 0xc0)) {
+		((ec[1] & 0xf0) == 0xB0 || (ec[1] & 0xf0) == 0xC0)) {
 		priv->proto_version = ALPS_PROTO_V7;
 		alps_set_defaults(priv);
 
@@ -2217,7 +3223,6 @@ static int alps_identify(struct psmouse *psmouse, struct alps_data *priv)
 		priv->decode_fields = alps_decode_rushmore;
 		priv->x_bits = 16;
 		priv->y_bits = 12;
-		priv->flags |= ALPS_IS_RUSHMORE;
 
 		/* hack to make addr_command, nibble_command available */
 		psmouse->private = priv;
@@ -2232,6 +3237,22 @@ static int alps_identify(struct psmouse *psmouse, struct alps_data *priv)
 		alps_set_defaults(priv);
 
 		return 0;
+	} else if (e7[0] == 0x73 && e7[1] == 0x03 && e7[2] == 0x14) {
+		priv->proto_version = ALPS_PROTO_V8;
+		alps_set_defaults(priv);
+
+		if (alps_set_defaults_ss4(psmouse, priv))
+			return -EIO;
+
+		return 0;
+	} else if (e7[0] == 0x73 && e7[1] == 0x03 && e7[2] == 0xc8) {
+		priv->proto_version = ALPS_PROTO_V9;
+		alps_set_defaults(priv);
+
+		if (alps_dolphin_get_device_area(psmouse, priv))
+			return -EIO;
+
+		return 0;
 	}
 
 	psmouse_info(psmouse,
@@ -2272,21 +3293,17 @@ static void alps_set_abs_params_st(struct alps_data *priv,
 static void alps_set_abs_params_mt(struct alps_data *priv,
 				   struct input_dev *dev1)
 {
+	set_bit(INPUT_PROP_SEMI_MT, dev1->propbit);
+	input_mt_init_slots(dev1, priv->slot_number, 0);
 	input_set_abs_params(dev1, ABS_MT_POSITION_X, 0, priv->x_max, 0, 0);
 	input_set_abs_params(dev1, ABS_MT_POSITION_Y, 0, priv->y_max, 0, 0);
 
-	input_abs_set_res(dev1, ABS_MT_POSITION_X, priv->x_res);
-	input_abs_set_res(dev1, ABS_MT_POSITION_Y, priv->y_res);
-
-	input_mt_init_slots(dev1, MAX_TOUCHES, INPUT_MT_POINTER |
-		INPUT_MT_DROP_UNUSED | INPUT_MT_TRACK | INPUT_MT_SEMI_MT);
-
+	set_bit(BTN_TOOL_DOUBLETAP, dev1->keybit);
 	set_bit(BTN_TOOL_TRIPLETAP, dev1->keybit);
 	set_bit(BTN_TOOL_QUADTAP, dev1->keybit);
 
-	/* V7 is real multi-touch */
-	if (priv->proto_version == ALPS_PROTO_V7)
-		clear_bit(INPUT_PROP_SEMI_MT, dev1->propbit);
+	input_set_abs_params(dev1, ABS_X, 0, priv->x_max, 0, 0);
+	input_set_abs_params(dev1, ABS_Y, 0, priv->y_max, 0, 0);
 }
 
 int alps_init(struct psmouse *psmouse)
@@ -2332,9 +3349,7 @@ int alps_init(struct psmouse *psmouse)
 	dev1->evbit[BIT_WORD(EV_ABS)] |= BIT_MASK(EV_ABS);
 
 	priv->set_abs_params(priv, dev1);
-	/* No pressure on V7 */
-	if (priv->proto_version != ALPS_PROTO_V7)
-		input_set_abs_params(dev1, ABS_PRESSURE, 0, 127, 0, 0);
+	input_set_abs_params(dev1, ABS_PRESSURE, 0, 127, 0, 0);
 
 	if (priv->flags & ALPS_WHEEL) {
 		dev1->evbit[BIT_WORD(EV_REL)] |= BIT_MASK(EV_REL);
@@ -2351,14 +3366,12 @@ int alps_init(struct psmouse *psmouse)
 		dev1->keybit[BIT_WORD(BTN_1)] |= BIT_MASK(BTN_1);
 		dev1->keybit[BIT_WORD(BTN_2)] |= BIT_MASK(BTN_2);
 		dev1->keybit[BIT_WORD(BTN_3)] |= BIT_MASK(BTN_3);
-	} else if (priv->flags & ALPS_BUTTONPAD) {
-		set_bit(INPUT_PROP_BUTTONPAD, dev1->propbit);
-		clear_bit(BTN_RIGHT, dev1->keybit);
 	} else {
 		dev1->keybit[BIT_WORD(BTN_MIDDLE)] |= BIT_MASK(BTN_MIDDLE);
 	}
 
-	snprintf(priv->phys, sizeof(priv->phys), "%s/input1", psmouse->ps2dev.serio->phys);
+	snprintf(priv->phys, sizeof(priv->phys),
+		"%s/input1", psmouse->ps2dev.serio->phys);
 	dev2->phys = priv->phys;
 	dev2->name = (priv->flags & ALPS_DUALPOINT) ?
 		     "DualPoint Stick" : "ALPS PS/2 Device";
@@ -2382,7 +3395,8 @@ int alps_init(struct psmouse *psmouse)
 	psmouse->reconnect = alps_reconnect;
 	psmouse->pktsize = priv->proto_version == ALPS_PROTO_V4 ? 8 : 6;
 
-	/* We are having trouble resyncing ALPS touchpads so disable it for now */
+	/* We are having trouble resyncing ALPS touchpads
+		so disable it for now */
 	psmouse->resync_time = 0;
 
 	return 0;
diff --git a/drivers/input/mouse/alps.h b/drivers/input/mouse/alps.h
index 66240b4..55f5193 100644
--- a/drivers/input/mouse/alps.h
+++ b/drivers/input/mouse/alps.h
@@ -12,8 +12,6 @@
 #ifndef _ALPS_H
 #define _ALPS_H
 
-#include <linux/input/mt.h>
-
 #define ALPS_PROTO_V1	1
 #define ALPS_PROTO_V2	2
 #define ALPS_PROTO_V3	3
@@ -21,8 +19,17 @@
 #define ALPS_PROTO_V5	5
 #define ALPS_PROTO_V6	6
 #define ALPS_PROTO_V7	7	/* t3btl t4s */
+#define ALPS_PROTO_V8	8	/* ss4 */
+#define ALPS_PROTO_V9	9	/* ss3btl */
+
+
+#define MAX_IMG_PT_NUM		5
+#define V7_IMG_PT_NUM		2
 
-#define MAX_TOUCHES	2
+#define ZONE_NORMAL				0x01
+#define ZONE_RESTING			0x02
+#define ZONE_LEFT_BTN			0x04
+#define ZONE_RIGHT_BTN			0x08
 
 #define DOLPHIN_COUNT_PER_ELECTRODE	64
 #define DOLPHIN_PROFILE_XOFFSET		8	/* x-electrode offset */
@@ -45,6 +52,124 @@ enum V7_PACKET_ID {
 	 V7_PACKET_ID_UNKNOWN,
 };
 
+enum SS4_PACKET_ID {
+	SS4_PACKET_ID_IDLE = 0,
+	SS4_PACKET_ID_ONE,
+	SS4_PACKET_ID_TWO,
+	SS4_PACKET_ID_MULTI,
+};
+
+#define SS4_COUNT_PER_ELECTRODE			256
+#define SS4_NUMSENSOR_XOFFSET			7
+#define SS4_NUMSENSOR_YOFFSET			7
+
+/* SWC status( 0:SW OFF, 1: SW ON) */
+#define SS4_BUTTONLESS_BUTTONS	0x01
+
+#define SS4_MASK_NORMAL_BUTTONS	0x07
+
+#define SS4_1F_X_V1(_b)	(((_b[0] << 5) & 0x1E00) | \
+		((_b[0] << 6) & 0x01C0) | \
+		((_b[1] >> 2) & 0x0038) | \
+		((_b[1] >> 1) & 0x0007) \
+		)
+
+#define SS4_1F_Y_V1(_b)	(((_b[2] >> 1) & 0x007F) | \
+		((_b[4] << 5) & 0x0F80) \
+		)
+
+#define SS4_1F_Z_V1(_b)		(_b[5] & 0xFF)
+
+#define	SS4_1F_LFB(_b)		((_b[4] >> 1) & 0x01)
+
+#define SS4_BTN_V1(_b)		(_b[3] & SS4_BUTTONLESS_BUTTONS)
+
+#define SS4_STD_MF_X_V1(_b, _i)	(((_b[0 + _i * 3] >> 2) & 0x0020) | \
+		((_b[1 + _i * 3] << 5) & 0x1FC0) \
+		)
+
+#define SS4_STD_MF_Y_V1(_b, _i)	(((_b[0 + _i * 3] >> 2) & 0x0010) | \
+		((_b[2 + _i * 3] << 4) & 0x0FE0) \
+		)
+
+#define SS4_BTL_BTN_V1(_b)		(_b[3] & SS4_BUTTONLESS_BUTTONS)
+
+#define SS4_BTL_MF_X_V1(_b, _i) (SS4_STD_MF_X_V1(_b, _i) | \
+		((_b[0 + _i * 3] << 2) & 0x0010))
+
+#define SS4_BTL_MF_Y_V1(_b, _i) (SS4_STD_MF_Y_V1(_b, _i) | \
+		((_b[0 + _i * 3] << 2) & 0x0008))
+
+#define SS4_MF_Z_V1(_b, _i)		((_b[0 + _i * 3] >> 4) & 0x0003)
+
+#define SS4_IS_MF_CONTINUE_V1(_b)	((_b[0] & 0x01) == 0x01)
+#define SS4_IS_5F_DETECTED_V1(_b)	((_b[0] & 0x01) == 0x01)
+
+#define SS4_1F_X_V2(_b)	((_b[0] & 0x0007) | \
+		((_b[1] << 3) & 0x0078) | \
+		((_b[1] << 2) & 0x0380) | \
+		((_b[2] << 5) & 0x1C00) \
+		)
+
+#define SS4_1F_Y_V2(_b)	(((_b[2]) & 0x000F) | \
+		((_b[3] >> 2) & 0x0030) | \
+		((_b[4] << 6) & 0x03C0) | \
+		((_b[4] << 5) & 0x0C00) \
+		)
+
+#define SS4_1F_Z_V2(_b)	(((_b[5]) & 0x0F) | \
+		((_b[5] >> 1) & 0x70) | \
+		((_b[4]) & 0x80) \
+		)
+
+#define	SS4_1F_LFB_V2(_b)	(((_b[2] >> 4) & 0x01) == 0x01)
+
+#define	SS4_MF_LF_V2(_b, _i)	((_b[1 + _i * 3] & 0x0004) == 0x0004)
+
+#define SS4_BTN_V2(_b)		((_b[0] >> 5) & SS4_MASK_NORMAL_BUTTONS)
+
+#define SS4_STD_MF_X_V2(_b, _i)	(((_b[0 + _i * 3]  << 5) & 0x00E0) | \
+		((_b[1 + _i * 3]  << 5) & 0x1F00) \
+		)
+
+#define SS4_STD_MF_Y_V2(_b, _i)	(((_b[1 + _i * 3] << 3) & 0x0010) | \
+		((_b[2 + _i * 3] << 5) & 0x01E0) | \
+		((_b[2 + _i * 3] << 4) & 0x0E00) \
+		)
+
+#define SS4_BTL_MF_X_V2(_b, _i)	(SS4_STD_MF_X_V2(_b, _i) | \
+		((_b[0 + _i * 3] >> 3) & 0x0010))
+
+#define SS4_BTL_MF_Y_V2(_b, _i)	(SS4_STD_MF_Y_V2(_b, _i) | \
+		((_b[0 + _i * 3] >> 3) & 0x0008))
+
+#define SS4_MF_Z_V2(_b, _i)	(((_b[1 + _i * 3]) & 0x0001) | \
+		((_b[1 + _i * 3] >> 1) & 0x0002) \
+		)
+
+#define SS4_IS_MF_CONTINUE_V2(_b)	((_b[2] & 0x10) == 0x10)
+#define SS4_IS_5F_DETECTED_V2(_b)	((_b[2] & 0x10) == 0x10)
+
+
+#define SS4_MFPACKET_NO_AX		8160	/* X-Coordinate value */
+#define SS4_MFPACKET_NO_AY		4080	/* Y-Coordinate value */
+#define SS4_MFPACKET_NO_AX_BL	8176	/* Buttonless X-Coordinate value */
+#define SS4_MFPACKET_NO_AY_BL	4088	/* Buttonless Y-Coordinate value */
+
+/* Threshold for resting finger's large movement */
+#define RESTING_FN_LARGE_MOVEMENT	50
+
+#define PT_IN_LEFT_BTN_AREA(_x, _y, _x_max, _y_max)
+		(((_x) < (_x_max)/2) && ((_y) > (_y_max)*4/5))
+
+#define PT_IN_RIGHT_BTN_AREA(_x, _y, _x_max, _y_max)
+		(((_x) >= (_x_max)/2) && ((_y) > (_y_max)*4/5))
+
+#define PT_IN_BTN_AREA(_x, _y, _x_max, _y_max)
+		(PT_IN_LEFT_BTN_AREA(_x, _y, _x_max, _y_max) ||
+		PT_IN_RIGHT_BTN_AREA(_x, _y, _x_max, _y_max)
+		)
+
 /**
  * struct alps_model_info - touchpad ID table
  * @signature: E7 response string to match.
@@ -68,7 +193,7 @@ struct alps_model_info {
 	unsigned char command_mode_resp;
 	unsigned char proto_version;
 	unsigned char byte0, mask0;
-	int flags;
+	unsigned int flags;
 };
 
 /**
@@ -87,47 +212,95 @@ struct alps_nibble_commands {
 	unsigned char data;
 };
 
-struct alps_bitmap_point {
-	int start_bit;
-	int num_bits;
+/**
+ * struct alps_btn - decoded version of the button status
+ * @left: Left touchpad button is active.
+ * @right: Right touchpad button is active.
+ * @middle: Middle touchpad button is active.
+ * @ts_left: Left trackstick button is active.
+ * @ts_right: Right trackstick button is active.
+ * @ts_middle: Middle trackstick button is active.
+ */
+struct alps_btn {
+	unsigned int left:1;
+	unsigned int right:1;
+	unsigned int middle:1;
+
+	unsigned int ts_left:1;
+	unsigned int ts_right:1;
+	unsigned int ts_middle:1;
+};
+
+/**
+ * struct alps_btn - decoded version of the X Y Z postion for ST.
+ * @x: X position for ST.
+ * @y: Y position for ST.
+ * @z: Z position for ST.
+ */
+struct alps_abs_data {
+	unsigned int x;
+	unsigned int y;
+	unsigned int z;
+};
+
+enum dol_Packet {
+	DOL_UNKNOWN,
+	DOL_GPDATA,
+	DOL_PROFDATA,
+	DOL_APDATA
 };
 
 /**
  * struct alps_fields - decoded version of the report packet
+ * @fingers: Number of fingers for MT.
+ * @pt: X Y Z postion for ST.
+ * @pt: X Y Z postion for image MT.
  * @x_map: Bitmap of active X positions for MT.
  * @y_map: Bitmap of active Y positions for MT.
- * @fingers: Number of fingers for MT.
- * @pressure: Pressure.
- * @st: position for ST.
- * @mt: position for MT.
  * @first_mp: Packet is the first of a multi-packet report.
  * @is_mp: Packet is part of a multi-packet report.
- * @left: Left touchpad button is active.
- * @right: Right touchpad button is active.
- * @middle: Middle touchpad button is active.
- * @ts_left: Left trackstick button is active.
- * @ts_right: Right trackstick button is active.
- * @ts_middle: Middle trackstick button is active.
+ * @btn: Button activity status
  */
 struct alps_fields {
+	unsigned int fingers;
+	struct alps_abs_data pt;
+	struct alps_abs_data pt_img[MAX_IMG_PT_NUM];
 	unsigned int x_map;
 	unsigned int y_map;
-	unsigned int fingers;
-
-	int pressure;
-	struct input_mt_pos st;
-	struct input_mt_pos mt[MAX_TOUCHES];
-
+	unsigned int large_fn;
 	unsigned int first_mp:1;
 	unsigned int is_mp:1;
+	enum dol_Packet	dol_packet_type;
+	struct alps_btn btn;
+};
 
-	unsigned int left:1;
-	unsigned int right:1;
-	unsigned int middle:1;
+/**
+ * struct v7_raw - data decoded from raw packet for V7.
+ * @pkt_id: An id that specifies the type of packet.
+ * @additional_fingers: Number of additional finger that is neighter included
+ *  in pt slot nor reflected in rest_left and rest_right flag of data packet.
+ * @rest_left: There are fingers on left resting zone.
+ * @rest_right: There are fingers on right resting zone.
+ */
+struct v7_raw {
+	unsigned char pkt_id;
+	unsigned int additional_fingers;
+	unsigned char rest_left;
+	unsigned char rest_right;
+};
 
-	unsigned int ts_left:1;
-	unsigned int ts_right:1;
-	unsigned int ts_middle:1;
+/**
+ * struct alps_bl_pt_attr - generic attributes of touch points for buttonless device
+ * @zone: The part of touchpad that the touch point locates
+ * @is_counted: The touch point is not a resting finger.
+ * @is_init_pt_got: The touch down point is got.
+ * @init_pt: The X Y Z position of the touch down point.
+ */
+struct alps_bl_pt_attr {
+	unsigned char zone;
+	unsigned char is_counted;
+	unsigned char is_init_pt_got;
+	struct alps_abs_data init_pt;
 };
 
 /**
@@ -142,12 +315,13 @@ struct alps_fields {
  *   known format for this model.  The first byte of the report, ANDed with
  *   mask0, should match byte0.
  * @mask0: The mask used to check the first byte of the report.
- * @fw_ver: cached copy of firmware version (EC report)
  * @flags: Additional device capabilities (passthrough port, trackstick, etc.).
  * @x_max: Largest possible X position value.
  * @y_max: Largest possible Y position value.
+ * @resting_zone_y_min: Smallest Y postion value of the bottom resting zone.
  * @x_bits: Number of X bits in the MT bitmap.
  * @y_bits: Number of Y bits in the MT bitmap.
+ * @img_fingers: Number of image fingers.
  * @hw_init: Protocol-specific hardware init function.
  * @process_packet: Protocol-specific function to process a report packet.
  * @decode_fields: Protocol-specific function to read packet bitfields.
@@ -155,9 +329,18 @@ struct alps_fields {
  * @prev_fin: Finger bit from previous packet.
  * @multi_packet: Multi-packet data in progress.
  * @multi_data: Saved multi-packet data.
- * @f: Decoded packet data fields.
+ * @x1: First X coordinate from last MT report.
+ * @x2: Second X coordinate from last MT report.
+ * @y1: First Y coordinate from last MT report.
+ * @y2: Second Y coordinate from last MT report.
+ * @fingers: Number of fingers from last MT report.
  * @quirks: Bitmap of ALPS_QUIRK_*.
  * @timer: Timer for flushing out the final report packet in the stream.
+ * @v7: Data decoded from raw packet for V7
+ * @phy_btn: Physical button is active.
+ * @prev_phy_btn: Physical button of previous packet is active.
+ * @pressed_btn_bits: Pressed positon of button zone
+ * @pt_attr: Generic attributes of touch points for buttonless device.
  */
 struct alps_data {
 	struct input_dev *dev2;
@@ -168,27 +351,35 @@ struct alps_data {
 	int addr_command;
 	unsigned char proto_version;
 	unsigned char byte0, mask0;
+	unsigned int flags;
 	unsigned char fw_ver[3];
-	int flags;
 	int x_max;
 	int y_max;
+	int resting_zone_y_min;
 	int x_bits;
 	int y_bits;
-	unsigned int x_res;
-	unsigned int y_res;
+	unsigned char slot_number;
 
 	int (*hw_init)(struct psmouse *psmouse);
 	void (*process_packet)(struct psmouse *psmouse);
-	int (*decode_fields)(struct alps_fields *f, unsigned char *p,
+	void (*decode_fields)(struct alps_fields *f, unsigned char *p,
 			      struct psmouse *psmouse);
 	void (*set_abs_params)(struct alps_data *priv, struct input_dev *dev1);
 
 	int prev_fin;
 	int multi_packet;
 	unsigned char multi_data[6];
-	struct alps_fields f;
+	int x1, x2, y1, y2;
+	int fingers;
 	u8 quirks;
 	struct timer_list timer;
+
+	/* these are used for buttonless touchpad*/
+	union {
+		struct v7_raw v7;
+	} r;
+	struct alps_btn prev_btn;
+	struct alps_bl_pt_attr pt_attr[MAX_IMG_PT_NUM];
 };
 
 #define ALPS_QUIRK_TRACKSTICK_BUTTONS	1 /* trakcstick buttons in trackstick packet */
-- 
1.9.1

--
To unsubscribe from this list: send the line "unsubscribe linux-input" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[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