Another clue: the odd behaviour described below disappears if I switch tap-to-click off in synaptics X11 driver (but no tap-to-click functionality, then, of course). vencik ______________________________________________________________ > Od: <vencik@xxxxxxxxx> > Komu: Elaine Chen <elaineee66@xxxxxxxxx> > Datum: 27.03.2014 10:58 > Předmět: Re: [PATCH] input: add support for ALPS v7 protocol device > > CC: "Dmitry Torokhov" <dmitry.torokhov@xxxxxxxxx>, "Kevin Cernekee" <cernekee@xxxxxxxxx>, "david turvene" <dturvene@xxxxxxxxxxxx>, linux-input@xxxxxxxxxxxxxxx, "Niels de Vos" <ndevos@xxxxxxxxxx>, jclift@xxxxxxxxxx--cc, "Qiting Chen" <qiting.chen@xxxxxxxxxxx>, "Justin Clift" <justin@xxxxxxxxxxx> >Hi again, Elaine, > >just something to add to the TP driver functionality; >I've experienced something that looked as involuntary left >button clicking. > >Using xev, I deduce that it happens when I remove the finger >after doing just a short motion on the pad; if the motion is longer >(apparently both in in distance and time) the click is not generated >at the end. >But when I do just a short and quite quick move, it produces a click. > >Perhaps it's just necessary to tune the driver a bit; what I'm talking about >is something close to a tap, but past it; the motion may take about 1/2 second >and the cursor moves for about a centimeter... >I'll try to identify the code bit responsible and play with that. > >Regards, > >vencik > > >______________________________________________________________ >> Od: Elaine Chen <elaineee66@xxxxxxxxx> >> Komu: "Václav Krpec" <vencik@xxxxxxxxx> >> Datum: 27.03.2014 08:57 >> Předmět: Re: [PATCH] input: add support for ALPS v7 protocol device >> >> CC: "Dmitry Torokhov" <dmitry.torokhov@xxxxxxxxx>, "Kevin Cernekee" <cernekee@xxxxxxxxx>, "david turvene" <dturvene@xxxxxxxxxxxx>, linux-input@xxxxxxxxxxxxxxx, "Niels de Vos" <ndevos@xxxxxxxxxx>, jclift@xxxxxxxxxx--cc, "Qiting Chen" <qiting.chen@xxxxxxxxxxx>, "Justin Clift" <justin@xxxxxxxxxxx> >>Hello Vencik, >> >>Thank you for evaluating the patch. >> >>1/ About stickpoint support >>Yes, this patch hasn't added stickpoint support for v7 protocol device. >>What's the SP behavior on your Toshiba laptop after >>applying our patch? No function or works abnormally? Please let me know the >>phenomenon as I don't have a v7 TP/SP dual device currently. >>I also checked your stickpoint process code. The SP packet decode seems >>doesn't match the format of Specification. Sorry I haven't tested it as >>lack of >>device.Did it work on your machine? >>I'll get down to support for SP next week I got such a device. And will >>release it with next patch. >> >>2/ This patch is against Dmitry Torokhov's input tree(3.13-rc4) >>https://git.kernel.org/cgit/linux/kernel/git/dtor/input.git/ >>I've checked the alps.(ch) from 3.13-rc4 and 3.14-rc8, they are the same. >>Maybe there are something unmatch with patch format. >>My patch is made from git format-patch. >> >> >> >>2014-03-26 20:20 GMT+08:00 Václav Krpec <vencik@xxxxxxxxx>: >> >>> Hello Qiting, >>> >>> I've applied your patch and tested the driver on my Toshiba Portege >>> Z30-A-12N (device ID is 73 03 0a, FW ver: 88 b3 22). >>> >>> The TP driver works nicely, however, I've observed a few things to note: >>> >>> 1/ >>> There's no support for trackstick; my device has one. >>> Justin has suggested that it may be a Toshiba mod of the device... >>> Nevertheless, since I was in process of RA of the device myself before >>> you've committed the patch, I merged the TS driver to your patch; >>> see alps_process_trackstick_packet_v7 function + tiny bit of >>> refactoring of the packet ID resolving mechanism in the patch attached. >>> I hope it shouldn't break the driver functionality for devices w/o >>> the trackstick, but testing should definitely be done. >>> >>> 2/ >>> I've noticed that your patch wasn't cleanly applicable to current 3.14 >>> kernel; could you be more specific on what branch should it be applied? >>> The patch attached is valid for 3.14-rc8 tree. >>> >>> 3/ >>> I also took the liberty of fixing indentation of your code a bit to put >>> it (hopefully) more in line with the conventions of the alps.[ch] >>> >>> So, could you (or anyone else) test the patch attached? >>> Comments, recommendations etc welcome. >>> >>> Thanks, >>> >>> Best regards >>> >>> vencik >>> >>> >>> >>> On Wed, 2014-03-19 at 16:55 +0800, Qiting Chen wrote: >>> > 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** >>> > >>> > 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 */ >>> >>> >> >-- >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 > -- 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