Signed-off-by: Masaki Ota <[email protected]>
- 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 [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to