Hi, Dmitry, Waiting for the reviewing of the patch. Is there some steps I missed before our patch being reviewed? Please tell me. Thank you! 2014-04-14 11:05 GMT+08:00 Elaine Chen <elaineee66@xxxxxxxxx>: > Hi, Dmitry, > > Would you please send your suggestions for this patch? Thank you! > > 2014-03-19 16:55 GMT+08:00 Qiting Chen <elaineee66@xxxxxxxxx>: >> Here is a patch of supporting ALPS v7 protocol device. >> ALPS v7 protocol device is a clickpad that is currently used on >> Lenovo S430/S435/S530, Lenovo Z410/Z510, HP Odie, HP Revolve 810 G1, >> as well as other machines with ALPS Touchpad of following infomation: >> Device ID = 0x73, 0x03, 0x0a >> Firmware ID = 0x88, 0xb*, 0x** >>suggestion > >> A v7 protocol support patch is first relesed 2 months ago: >> http://www.spinics.net/lists/linux-input/msg29084.html >> After that some feedbacks were received from end user. Now this patch fixed the bugs >> reported by them: >> 1) Fix cursor jump when doing a right click drag >> 2) Fix cursor jitter when button clicking >> >> Signed-off-by: Qiting Chen <qiting.chen@xxxxxxxxxxx> >> --- >> drivers/input/mouse/alps.c | 560 ++++++++++++++++++++++++++++++++++++++++++--- >> drivers/input/mouse/alps.h | 132 +++++++++-- >> 2 files changed, 641 insertions(+), 51 deletions(-) >> >> diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c >> index fb15c64..383281f 100644 >> --- a/drivers/input/mouse/alps.c >> +++ b/drivers/input/mouse/alps.c >> @@ -32,6 +32,13 @@ >> #define ALPS_REG_BASE_RUSHMORE 0xc2c0 >> #define ALPS_REG_BASE_PINNACLE 0x0000 >> >> +#define LEFT_BUTTON_BIT 0x01 >> +#define RIGHT_BUTTON_BIT 0x02 >> + >> +#define V7_LARGE_MOVEMENT 130 >> +#define V7_DEAD_ZONE_OFFSET_X 72 >> +#define V7_DEAD_ZONE_OFFSET_Y 72 >> + >> static const struct alps_nibble_commands alps_v3_nibble_commands[] = { >> { PSMOUSE_CMD_SETPOLL, 0x00 }, /* 0 */ >> { PSMOUSE_CMD_RESET_DIS, 0x00 }, /* 1 */ >> @@ -99,6 +106,7 @@ 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_BTNLESS 0x100 /* ALPS ClickPad flag */ >> >> 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 */ >> @@ -140,6 +148,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, >> @@ -320,8 +342,8 @@ 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)); >> - *x1 = fields->x; >> - *y1 = fields->y; >> + *x1 = fields->pt.x; >> + *y1 = fields->pt.y; >> *x2 = 2 * box_middle_x - *x1; >> *y2 = 2 * box_middle_y - *y1; >> } >> @@ -461,6 +483,38 @@ static void alps_report_semi_mt_data(struct input_dev *dev, int num_fingers, >> alps_set_slot(dev, 1, num_fingers == 2, x2, y2); >> } >> >> +static void alps_report_coord_and_btn(struct psmouse *psmouse, >> + struct alps_fields *f) >> +{ >> + struct input_dev *dev; >> + >> + if (!psmouse || !f) >> + return; >> + >> + dev = psmouse->dev; >> + >> + 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_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_key(dev, BTN_LEFT, f->btn.left); >> + input_report_key(dev, BTN_RIGHT, f->btn.right); >> + >> + input_sync(dev); >> +} >> + >> static void alps_process_trackstick_packet_v3(struct psmouse *psmouse) >> { >> struct alps_data *priv = psmouse->private; >> @@ -523,13 +577,13 @@ 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 void alps_decode_pinnacle(struct alps_fields *f, unsigned char *p, >> @@ -546,10 +600,10 @@ static void alps_decode_pinnacle(struct alps_fields *f, unsigned char *p, >> ((p[2] & 0x7f) << 1) | >> (p[4] & 0x01); >> >> - f->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->y = ((p[2] & 0x7f) << 4) | (p[4] & 0x0f); >> - f->z = 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); >> } >> @@ -573,9 +627,9 @@ static void alps_decode_dolphin(struct alps_fields *f, unsigned char *p, >> f->is_mp = !!(p[0] & 0x20); >> >> if (!f->is_mp) { >> - f->x = ((p[1] & 0x7f) | ((p[4] & 0x0f) << 7)); >> - f->y = ((p[2] & 0x7f) | ((p[4] & 0xf0) << 3)); >> - f->z = (p[0] & 4) ? 0 : p[5] & 0x7f; >> + f->pt.x = ((p[1] & 0x7f) | ((p[4] & 0x0f) << 7)); >> + f->pt.y = ((p[2] & 0x7f) | ((p[4] & 0xf0) << 3)); >> + f->pt.z = (p[0] & 4) ? 0 : p[5] & 0x7f; >> alps_decode_buttons_v3(f, p); >> } else { >> f->fingers = ((p[0] & 0x6) >> 1 | >> @@ -687,7 +741,7 @@ 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.x && f.y && !f.z) >> + if (f.pt.x && f.pt.y && !f.pt.z) >> return; >> >> /* >> @@ -695,12 +749,12 @@ static void alps_process_touchpad_packet_v3_v5(struct psmouse *psmouse) >> * to rely on ST data. >> */ >> if (!fingers) { >> - x1 = f.x; >> - y1 = f.y; >> - fingers = f.z > 0 ? 1 : 0; >> + x1 = f.pt.x; >> + y1 = f.pt.y; >> + fingers = f.pt.z > 0 ? 1 : 0; >> } >> >> - if (f.z >= 64) >> + if (f.pt.z >= 64) >> input_report_key(dev, BTN_TOUCH, 1); >> else >> input_report_key(dev, BTN_TOUCH, 0); >> @@ -709,22 +763,22 @@ static void alps_process_touchpad_packet_v3_v5(struct psmouse *psmouse) >> >> input_mt_report_finger_count(dev, 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_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.z > 0) { >> - input_report_abs(dev, ABS_X, f.x); >> - input_report_abs(dev, ABS_Y, f.y); >> + 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.z); >> + 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); >> } >> } >> @@ -916,6 +970,364 @@ static void alps_process_packet_v4(struct psmouse *psmouse) >> input_sync(dev); >> } >> >> +static bool alps_is_valid_package_v7(struct psmouse *psmouse) >> +{ >> + 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; >> + >> + if (byte[4] & 0x40) >> + packet_id = V7_PACKET_ID_TWO; >> + else if (byte[4] & 0x01) >> + packet_id = V7_PACKET_ID_MULTI; >> + else if ((byte[0] & 0x10) && !(byte[4] & 0x43)) >> + packet_id = V7_PACKET_ID_NEW; >> + else >> + packet_id = V7_PACKET_ID_IDLE; >> + >> + 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; >> + static struct v7_raw prev_r; >> + >> + 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; >> + priv->phy_btn = 0; >> + >> + if (priv->r.v7.pkt_id == V7_PACKET_ID_TWO || >> + priv->r.v7.pkt_id == V7_PACKET_ID_MULTI) { >> + priv->r.v7.rest_left = (p[0] & 0x10) >> 4; >> + priv->r.v7.rest_right = (p[0] & 0x20) >> 5; >> + } >> + >> + if (priv->r.v7.pkt_id == V7_PACKET_ID_MULTI) >> + priv->r.v7.additional_fingers = p[5] & 0x03; >> + >> + priv->phy_btn = (p[0] & 0x80) >> 7; >> + >> + if (priv->r.v7.pkt_id == V7_PACKET_ID_TWO) { >> + if (f->pt_img[0].z != 0 && f->pt_img[1].z != 0) >> + priv->r.v7.raw_fn = 2; >> + else >> + priv->r.v7.raw_fn = 1; >> + } else if (priv->r.v7.pkt_id == V7_PACKET_ID_MULTI) >> + priv->r.v7.raw_fn = 3 + priv->r.v7.additional_fingers; >> + else if (priv->r.v7.pkt_id == V7_PACKET_ID_IDLE) >> + priv->r.v7.raw_fn = 0; >> + else if (priv->r.v7.pkt_id == V7_PACKET_ID_NEW) >> + priv->r.v7.raw_fn = prev_r.raw_fn; >> + >> + /* It is a trick to bypass firmware bug of older version >> + that 'New' Packet is missed when finger number changed. >> + We fake a 'New' Packet in such cases.*/ >> + if (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) { >> + if (priv->r.v7.raw_fn != prev_r.raw_fn) >> + priv->r.v7.pkt_id = V7_PACKET_ID_NEW; >> + } >> + >> + memcpy(&prev_r, &priv->r.v7, sizeof(struct v7_raw)); >> +} >> + >> +static void alps_set_each_pt_attr_v7(struct psmouse *psmouse, >> + struct alps_abs_data *pt, >> + struct alps_bl_pt_attr *pt_attr) >> +{ >> + struct alps_data *priv = psmouse->private; >> + unsigned int dist; >> + >> + 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)); >> + } >> + >> + 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; >> + } >> + } >> + } >> +} >> + >> +static void alps_set_pt_attr_v7(struct psmouse *psmouse, >> + struct alps_fields *f) >> +{ >> + struct alps_data *priv = psmouse->private; >> + int i; >> + >> + 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]) * 2); >> + break; >> + } >> +} >> + >> +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; >> + >> + 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; >> + } >> + >> + f->fingers = fn; >> +} >> + >> +static void alps_button_dead_zone_filter(struct psmouse *psmouse, >> + struct alps_fields *f, >> + struct alps_fields *prev_f) >> +{ >> + struct alps_data *priv = psmouse->private; >> + int dx, dy; >> + >> + if (priv->prev_phy_btn == 0 && priv->phy_btn != 0) { >> + memcpy(&priv->pt_attr[0].init_dead_pt, >> + &f->pt_img[0], >> + sizeof(struct alps_abs_data)); >> + } >> + >> + if (priv->pt_attr[0].init_dead_pt.x != 0 && >> + priv->pt_attr[0].init_dead_pt.x != 0) { >> + dx = f->pt_img[0].x - priv->pt_attr[0].init_dead_pt.x; >> + dy = f->pt_img[0].y - priv->pt_attr[0].init_dead_pt.y; >> + if ((abs(dx) > V7_DEAD_ZONE_OFFSET_X) || >> + (abs(dy) > V7_DEAD_ZONE_OFFSET_Y)) { >> + memset(&priv->pt_attr[0].init_dead_pt, 0, >> + sizeof(struct alps_abs_data)); >> + priv->btn_delay_cnt = 0; >> + } else { >> + memcpy(&f->pt_img[0], >> + &prev_f->pt_img[0], >> + sizeof(struct alps_abs_data)); >> + if (priv->prev_phy_btn == 0 && priv->phy_btn != 0) >> + priv->btn_delay_cnt = 2; >> + } >> + } >> + >> + if (priv->btn_delay_cnt > 0) { >> + f->btn.left = 0; >> + f->btn.right = 0; >> + priv->btn_delay_cnt--; >> + } >> +} >> + >> +static void alps_assign_buttons_v7(struct psmouse *psmouse, >> + struct alps_fields *f, >> + struct alps_fields *prev_f) >> +{ >> + struct alps_data *priv = psmouse->private; >> + >> + if (priv->phy_btn) { >> + if (!priv->prev_phy_btn) { >> + /* Report a right click as long as there's finger on >> + right button zone. Othrewise, report a left click.*/ >> + 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; >> + priv->pressed_btn_bits |= RIGHT_BUTTON_BIT; >> + } else { >> + f->btn.left = 1; >> + priv->pressed_btn_bits |= LEFT_BUTTON_BIT; >> + } >> + } else { >> + if (priv->pressed_btn_bits & RIGHT_BUTTON_BIT) >> + f->btn.right = 1; >> + if (priv->pressed_btn_bits & LEFT_BUTTON_BIT) >> + f->btn.left = 1; >> + } >> + } else { >> + priv->pressed_btn_bits = 0; >> + f->btn.right = 0; >> + f->btn.left = 0; >> + } >> + >> + alps_button_dead_zone_filter(psmouse, f, prev_f); >> + >> + priv->prev_phy_btn = priv->phy_btn; >> +} >> + >> +static void alps_process_packet_v7(struct psmouse *psmouse) >> +{ >> + struct alps_data *priv = psmouse->private; >> + struct alps_fields f = {0}; >> + static struct alps_fields prev_f; >> + unsigned char *packet = psmouse->packet; >> + >> + priv->decode_fields(&f, packet, psmouse); >> + >> + if (alps_drop_unsupported_packet_v7(psmouse)) >> + return; >> + >> + alps_set_pt_attr_v7(psmouse, &f); >> + >> + alps_cal_output_finger_num_v7(psmouse, &f); >> + >> + alps_assign_buttons_v7(psmouse, &f, &prev_f); >> + >> + alps_report_coord_and_btn(psmouse, &f); >> + >> + memcpy(&prev_f, &f, sizeof(struct alps_fields)); >> +} >> + >> static void alps_report_bare_ps2_packet(struct psmouse *psmouse, >> unsigned char packet[], >> bool report_buttons) >> @@ -1080,6 +1492,14 @@ 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))) { >> + psmouse_dbg(psmouse, "refusing packet[%i] = %x\n", >> + psmouse->pktcnt - 1, >> + psmouse->packet[psmouse->pktcnt - 1]); >> + return PSMOUSE_BAD_DATA; >> + } >> + >> if (psmouse->pktcnt == psmouse->pktsize) { >> priv->process_packet(psmouse); >> return PSMOUSE_FULL_PACKET; >> @@ -1192,6 +1612,22 @@ static int alps_rpt_cmd(struct psmouse *psmouse, int init_command, >> return 0; >> } >> >> +static int alps_check_valid_firmware_id(unsigned char id[]) >> +{ >> + int valid = 1; >> + >> + 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 valid; >> +} >> + >> static int alps_enter_command_mode(struct psmouse *psmouse) >> { >> unsigned char param[4]; >> @@ -1201,8 +1637,7 @@ static int alps_enter_command_mode(struct psmouse *psmouse) >> return -1; >> } >> >> - if ((param[0] != 0x88 || (param[1] != 0x07 && param[1] != 0x08)) && >> - param[0] != 0x73) { >> + if (!alps_check_valid_firmware_id(param)) { >> psmouse_dbg(psmouse, >> "unknown response while entering command mode\n"); >> return -1; >> @@ -1704,6 +2139,36 @@ 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)) >> + goto error; >> + >> + reg_val = alps_command_mode_read_reg(psmouse, 0xc2d9); >> + if (reg_val == -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) >> { >> @@ -1875,6 +2340,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; >> @@ -1883,6 +2349,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; >> @@ -1890,6 +2357,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; >> @@ -1905,6 +2373,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; >> @@ -1913,6 +2382,28 @@ 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 = 2; >> + break; >> + case ALPS_PROTO_V7: >> + priv->hw_init = alps_hw_init_v7; >> + priv->process_packet = alps_process_packet_v7; >> + priv->decode_fields = alps_decode_packet_v7; >> + 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->resting_zone_y_min = 0x654; >> + priv->byte0 = 0x48; >> + priv->mask0 = 0x48; >> + priv->flags = 0; >> + priv->slot_number = 2; >> + >> + priv->phy_btn = 0; >> + priv->prev_phy_btn = 0; >> + priv->btn_delay_cnt = 0; >> + priv->pressed_btn_bits = 0; >> + memset(priv->pt_attr, 0, sizeof(priv->pt_attr[0]) * 2); >> break; >> } >> } >> @@ -1982,6 +2473,11 @@ static int alps_identify(struct psmouse *psmouse, struct alps_data *priv) >> return -EIO; >> else >> return 0; >> + } else if (ec[0] == 0x88 && (ec[1] & 0xf0) == 0xB0) { >> + priv->proto_version = ALPS_PROTO_V7; >> + alps_set_defaults(priv); >> + >> + return 0; >> } else if (ec[0] == 0x88 && ec[1] == 0x08) { >> priv->proto_version = ALPS_PROTO_V3; >> alps_set_defaults(priv); >> @@ -2045,7 +2541,7 @@ 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, 2, 0); >> + 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); >> >> diff --git a/drivers/input/mouse/alps.h b/drivers/input/mouse/alps.h >> index 03f88b6..dedbd27 100644 >> --- a/drivers/input/mouse/alps.h >> +++ b/drivers/input/mouse/alps.h >> @@ -18,11 +18,36 @@ >> #define ALPS_PROTO_V4 4 >> #define ALPS_PROTO_V5 5 >> #define ALPS_PROTO_V6 6 >> +#define ALPS_PROTO_V7 7 >> + >> +#define MAX_IMG_PT_NUM 5 >> +#define V7_IMG_PT_NUM 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 */ >> #define DOLPHIN_PROFILE_YOFFSET 1 /* y-electrode offset */ >> >> +/* >> + * enum V7_PACKET_ID - defines the packet type for V7 >> + * V7_PACKET_ID_IDLE: There's no finger and no button activity. >> + * V7_PACKET_ID_TWO: There's one or two non-resting fingers on touchpad >> + * or there's button activities. >> + * V7_PACKET_ID_MULTI: There are at least three non-resting fingers. >> + * V7_PACKET_ID_NEW: The finger position in slot is not continues from >> + * previous packet. >> +*/ >> +enum V7_PACKET_ID { >> + V7_PACKET_ID_IDLE, >> + V7_PACKET_ID_TWO, >> + V7_PACKET_ID_MULTI, >> + V7_PACKET_ID_NEW, >> +}; >> + >> /** >> * struct alps_model_info - touchpad ID table >> * @signature: E7 response string to match. >> @@ -66,15 +91,7 @@ struct alps_nibble_commands { >> }; >> >> /** >> - * struct alps_fields - decoded version of the report packet >> - * @x_map: Bitmap of active X positions for MT. >> - * @y_map: Bitmap of active Y positions for MT. >> - * @fingers: Number of fingers for MT. >> - * @x: X position for ST. >> - * @y: Y position for ST. >> - * @z: Z position for ST. >> - * @first_mp: Packet is the first of a multi-packet report. >> - * @is_mp: Packet is part of a multi-packet report. >> + * 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. >> @@ -82,16 +99,7 @@ struct alps_nibble_commands { >> * @ts_right: Right trackstick button is active. >> * @ts_middle: Middle trackstick button is active. >> */ >> -struct alps_fields { >> - unsigned int x_map; >> - unsigned int y_map; >> - unsigned int fingers; >> - unsigned int x; >> - unsigned int y; >> - unsigned int z; >> - unsigned int first_mp:1; >> - unsigned int is_mp:1; >> - >> +struct alps_btn { >> unsigned int left:1; >> unsigned int right:1; >> unsigned int middle:1; >> @@ -102,6 +110,73 @@ struct alps_fields { >> }; >> >> /** >> + * 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; >> +}; >> + >> +/** >> + * 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. >> + * @first_mp: Packet is the first of a multi-packet report. >> + * @is_mp: Packet is part of a multi-packet report. >> + * @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 first_mp:1; >> + unsigned int is_mp:1; >> + struct alps_btn btn; >> +}; >> + >> +/** >> + * 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. >> + * @raw_fn: The number of finger on touchpad. >> + */ >> +struct v7_raw { >> + unsigned char pkt_id; >> + unsigned int additional_fingers; >> + unsigned char rest_left; >> + unsigned char rest_right; >> + unsigned char raw_fn; >> +}; >> + >> +/** >> + * 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. >> + * @init_dead_pt: The touch down point of a finger used by dead zone process. >> + */ >> +struct alps_bl_pt_attr { >> + unsigned char zone; >> + unsigned char is_counted; >> + unsigned char is_init_pt_got; >> + struct alps_abs_data init_pt; >> + struct alps_abs_data init_dead_pt; >> +}; >> + >> +/** >> * struct alps_data - private data structure for the ALPS driver >> * @dev2: "Relative" device used to report trackstick or mouse activity. >> * @phys: Physical path for the relative device. >> @@ -116,8 +191,10 @@ struct alps_fields { >> * @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. >> @@ -132,6 +209,11 @@ struct alps_fields { >> * @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; >> @@ -145,8 +227,10 @@ struct alps_data { >> unsigned char flags; >> int x_max; >> int y_max; >> + int resting_zone_y_min; >> int x_bits; >> int y_bits; >> + unsigned char slot_number; >> >> int (*hw_init)(struct psmouse *psmouse); >> void (*process_packet)(struct psmouse *psmouse); >> @@ -161,6 +245,16 @@ struct alps_data { >> int fingers; >> u8 quirks; >> struct timer_list timer; >> + >> + /* these are used for buttonless touchpad*/ >> + union { >> + struct v7_raw v7; >> + } r; >> + unsigned char phy_btn; >> + unsigned char prev_phy_btn; >> + unsigned char btn_delay_cnt; >> + unsigned char pressed_btn_bits; >> + struct alps_bl_pt_attr pt_attr[MAX_IMG_PT_NUM]; >> }; >> >> #define ALPS_QUIRK_TRACKSTICK_BUTTONS 1 /* trakcstick buttons in trackstick packet */ >> -- >> 1.8.3.2 >> -- To unsubscribe from this list: send the line "unsubscribe linux-input" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html