diff options
author | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2013-02-20 01:05:39 -0500 |
---|---|---|
committer | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2013-02-20 01:05:39 -0500 |
commit | 2d9f0d964be94fd51c7303288c6f9c88bf2381fe (patch) | |
tree | 2631c3e82abc145a6e9c8e2c18687833c71de012 /drivers/input/mouse | |
parent | 9937c026820baabd1e908a9c1e6bdc846293000a (diff) | |
parent | 005a69d632cd8694061c2dd27492fe874780b5ee (diff) |
Merge branch 'next' into for-linus
Prepare first set of updates for 3.9 merge window.
Diffstat (limited to 'drivers/input/mouse')
-rw-r--r-- | drivers/input/mouse/Kconfig | 22 | ||||
-rw-r--r-- | drivers/input/mouse/Makefile | 2 | ||||
-rw-r--r-- | drivers/input/mouse/alps.c | 773 | ||||
-rw-r--r-- | drivers/input/mouse/alps.h | 145 | ||||
-rw-r--r-- | drivers/input/mouse/cyapa.c | 973 | ||||
-rw-r--r-- | drivers/input/mouse/cypress_ps2.c | 725 | ||||
-rw-r--r-- | drivers/input/mouse/cypress_ps2.h | 191 | ||||
-rw-r--r-- | drivers/input/mouse/psmouse-base.c | 32 | ||||
-rw-r--r-- | drivers/input/mouse/psmouse.h | 1 | ||||
-rw-r--r-- | drivers/input/mouse/synaptics.c | 32 |
10 files changed, 2528 insertions, 368 deletions
diff --git a/drivers/input/mouse/Kconfig b/drivers/input/mouse/Kconfig index cd6268cf7cd5..802bd6a72d73 100644 --- a/drivers/input/mouse/Kconfig +++ b/drivers/input/mouse/Kconfig | |||
@@ -68,6 +68,16 @@ config MOUSE_PS2_SYNAPTICS | |||
68 | 68 | ||
69 | If unsure, say Y. | 69 | If unsure, say Y. |
70 | 70 | ||
71 | config MOUSE_PS2_CYPRESS | ||
72 | bool "Cypress PS/2 mouse protocol extension" if EXPERT | ||
73 | default y | ||
74 | depends on MOUSE_PS2 | ||
75 | help | ||
76 | Say Y here if you have a Cypress PS/2 Trackpad connected to | ||
77 | your system. | ||
78 | |||
79 | If unsure, say Y. | ||
80 | |||
71 | config MOUSE_PS2_LIFEBOOK | 81 | config MOUSE_PS2_LIFEBOOK |
72 | bool "Fujitsu Lifebook PS/2 mouse protocol extension" if EXPERT | 82 | bool "Fujitsu Lifebook PS/2 mouse protocol extension" if EXPERT |
73 | default y | 83 | default y |
@@ -193,6 +203,18 @@ config MOUSE_BCM5974 | |||
193 | To compile this driver as a module, choose M here: the | 203 | To compile this driver as a module, choose M here: the |
194 | module will be called bcm5974. | 204 | module will be called bcm5974. |
195 | 205 | ||
206 | config MOUSE_CYAPA | ||
207 | tristate "Cypress APA I2C Trackpad support" | ||
208 | depends on I2C | ||
209 | help | ||
210 | This driver adds support for Cypress All Points Addressable (APA) | ||
211 | I2C Trackpads, including the ones used in 2012 Samsung Chromebooks. | ||
212 | |||
213 | Say Y here if you have a Cypress APA I2C Trackpad. | ||
214 | |||
215 | To compile this driver as a module, choose M here: the module will be | ||
216 | called cyapa. | ||
217 | |||
196 | config MOUSE_INPORT | 218 | config MOUSE_INPORT |
197 | tristate "InPort/MS/ATIXL busmouse" | 219 | tristate "InPort/MS/ATIXL busmouse" |
198 | depends on ISA | 220 | depends on ISA |
diff --git a/drivers/input/mouse/Makefile b/drivers/input/mouse/Makefile index 46ba7556fd4f..c25efdb3f288 100644 --- a/drivers/input/mouse/Makefile +++ b/drivers/input/mouse/Makefile | |||
@@ -8,6 +8,7 @@ obj-$(CONFIG_MOUSE_AMIGA) += amimouse.o | |||
8 | obj-$(CONFIG_MOUSE_APPLETOUCH) += appletouch.o | 8 | obj-$(CONFIG_MOUSE_APPLETOUCH) += appletouch.o |
9 | obj-$(CONFIG_MOUSE_ATARI) += atarimouse.o | 9 | obj-$(CONFIG_MOUSE_ATARI) += atarimouse.o |
10 | obj-$(CONFIG_MOUSE_BCM5974) += bcm5974.o | 10 | obj-$(CONFIG_MOUSE_BCM5974) += bcm5974.o |
11 | obj-$(CONFIG_MOUSE_CYAPA) += cyapa.o | ||
11 | obj-$(CONFIG_MOUSE_GPIO) += gpio_mouse.o | 12 | obj-$(CONFIG_MOUSE_GPIO) += gpio_mouse.o |
12 | obj-$(CONFIG_MOUSE_INPORT) += inport.o | 13 | obj-$(CONFIG_MOUSE_INPORT) += inport.o |
13 | obj-$(CONFIG_MOUSE_LOGIBM) += logibm.o | 14 | obj-$(CONFIG_MOUSE_LOGIBM) += logibm.o |
@@ -32,3 +33,4 @@ psmouse-$(CONFIG_MOUSE_PS2_LIFEBOOK) += lifebook.o | |||
32 | psmouse-$(CONFIG_MOUSE_PS2_SENTELIC) += sentelic.o | 33 | psmouse-$(CONFIG_MOUSE_PS2_SENTELIC) += sentelic.o |
33 | psmouse-$(CONFIG_MOUSE_PS2_TRACKPOINT) += trackpoint.o | 34 | psmouse-$(CONFIG_MOUSE_PS2_TRACKPOINT) += trackpoint.o |
34 | psmouse-$(CONFIG_MOUSE_PS2_TOUCHKIT) += touchkit_ps2.o | 35 | psmouse-$(CONFIG_MOUSE_PS2_TOUCHKIT) += touchkit_ps2.o |
36 | psmouse-$(CONFIG_MOUSE_PS2_CYPRESS) += cypress_ps2.o | ||
diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c index e229fa3cad96..7b99fc7c9438 100644 --- a/drivers/input/mouse/alps.c +++ b/drivers/input/mouse/alps.c | |||
@@ -27,14 +27,11 @@ | |||
27 | /* | 27 | /* |
28 | * Definitions for ALPS version 3 and 4 command mode protocol | 28 | * Definitions for ALPS version 3 and 4 command mode protocol |
29 | */ | 29 | */ |
30 | #define ALPS_V3_X_MAX 2000 | ||
31 | #define ALPS_V3_Y_MAX 1400 | ||
32 | |||
33 | #define ALPS_BITMAP_X_BITS 15 | ||
34 | #define ALPS_BITMAP_Y_BITS 11 | ||
35 | |||
36 | #define ALPS_CMD_NIBBLE_10 0x01f2 | 30 | #define ALPS_CMD_NIBBLE_10 0x01f2 |
37 | 31 | ||
32 | #define ALPS_REG_BASE_RUSHMORE 0xc2c0 | ||
33 | #define ALPS_REG_BASE_PINNACLE 0x0000 | ||
34 | |||
38 | static const struct alps_nibble_commands alps_v3_nibble_commands[] = { | 35 | static const struct alps_nibble_commands alps_v3_nibble_commands[] = { |
39 | { PSMOUSE_CMD_SETPOLL, 0x00 }, /* 0 */ | 36 | { PSMOUSE_CMD_SETPOLL, 0x00 }, /* 0 */ |
40 | { PSMOUSE_CMD_RESET_DIS, 0x00 }, /* 1 */ | 37 | { PSMOUSE_CMD_RESET_DIS, 0x00 }, /* 1 */ |
@@ -109,11 +106,14 @@ static const struct alps_model_info alps_model_data[] = { | |||
109 | { { 0x73, 0x02, 0x50 }, 0x00, ALPS_PROTO_V2, 0xcf, 0xcf, ALPS_FOUR_BUTTONS }, /* Dell Vostro 1400 */ | 106 | { { 0x73, 0x02, 0x50 }, 0x00, ALPS_PROTO_V2, 0xcf, 0xcf, ALPS_FOUR_BUTTONS }, /* Dell Vostro 1400 */ |
110 | { { 0x52, 0x01, 0x14 }, 0x00, ALPS_PROTO_V2, 0xff, 0xff, | 107 | { { 0x52, 0x01, 0x14 }, 0x00, ALPS_PROTO_V2, 0xff, 0xff, |
111 | ALPS_PASS | ALPS_DUALPOINT | ALPS_PS2_INTERLEAVED }, /* Toshiba Tecra A11-11L */ | 108 | ALPS_PASS | ALPS_DUALPOINT | ALPS_PS2_INTERLEAVED }, /* Toshiba Tecra A11-11L */ |
112 | { { 0x73, 0x02, 0x64 }, 0x9b, ALPS_PROTO_V3, 0x8f, 0x8f, ALPS_DUALPOINT }, | ||
113 | { { 0x73, 0x02, 0x64 }, 0x9d, ALPS_PROTO_V3, 0x8f, 0x8f, ALPS_DUALPOINT }, | ||
114 | { { 0x73, 0x02, 0x64 }, 0x8a, ALPS_PROTO_V4, 0x8f, 0x8f, 0 }, | 109 | { { 0x73, 0x02, 0x64 }, 0x8a, ALPS_PROTO_V4, 0x8f, 0x8f, 0 }, |
115 | }; | 110 | }; |
116 | 111 | ||
112 | static void alps_set_abs_params_st(struct alps_data *priv, | ||
113 | struct input_dev *dev1); | ||
114 | static void alps_set_abs_params_mt(struct alps_data *priv, | ||
115 | struct input_dev *dev1); | ||
116 | |||
117 | /* | 117 | /* |
118 | * XXX - this entry is suspicious. First byte has zero lower nibble, | 118 | * XXX - this entry is suspicious. First byte has zero lower nibble, |
119 | * which is what a normal mouse would report. Also, the value 0x0e | 119 | * which is what a normal mouse would report. Also, the value 0x0e |
@@ -122,10 +122,10 @@ static const struct alps_model_info alps_model_data[] = { | |||
122 | 122 | ||
123 | /* Packet formats are described in Documentation/input/alps.txt */ | 123 | /* Packet formats are described in Documentation/input/alps.txt */ |
124 | 124 | ||
125 | static bool alps_is_valid_first_byte(const struct alps_model_info *model, | 125 | static bool alps_is_valid_first_byte(struct alps_data *priv, |
126 | unsigned char data) | 126 | unsigned char data) |
127 | { | 127 | { |
128 | return (data & model->mask0) == model->byte0; | 128 | return (data & priv->mask0) == priv->byte0; |
129 | } | 129 | } |
130 | 130 | ||
131 | static void alps_report_buttons(struct psmouse *psmouse, | 131 | static void alps_report_buttons(struct psmouse *psmouse, |
@@ -158,14 +158,13 @@ static void alps_report_buttons(struct psmouse *psmouse, | |||
158 | static void alps_process_packet_v1_v2(struct psmouse *psmouse) | 158 | static void alps_process_packet_v1_v2(struct psmouse *psmouse) |
159 | { | 159 | { |
160 | struct alps_data *priv = psmouse->private; | 160 | struct alps_data *priv = psmouse->private; |
161 | const struct alps_model_info *model = priv->i; | ||
162 | unsigned char *packet = psmouse->packet; | 161 | unsigned char *packet = psmouse->packet; |
163 | struct input_dev *dev = psmouse->dev; | 162 | struct input_dev *dev = psmouse->dev; |
164 | struct input_dev *dev2 = priv->dev2; | 163 | struct input_dev *dev2 = priv->dev2; |
165 | int x, y, z, ges, fin, left, right, middle; | 164 | int x, y, z, ges, fin, left, right, middle; |
166 | int back = 0, forward = 0; | 165 | int back = 0, forward = 0; |
167 | 166 | ||
168 | if (model->proto_version == ALPS_PROTO_V1) { | 167 | if (priv->proto_version == ALPS_PROTO_V1) { |
169 | left = packet[2] & 0x10; | 168 | left = packet[2] & 0x10; |
170 | right = packet[2] & 0x08; | 169 | right = packet[2] & 0x08; |
171 | middle = 0; | 170 | middle = 0; |
@@ -181,12 +180,12 @@ static void alps_process_packet_v1_v2(struct psmouse *psmouse) | |||
181 | z = packet[5]; | 180 | z = packet[5]; |
182 | } | 181 | } |
183 | 182 | ||
184 | if (model->flags & ALPS_FW_BK_1) { | 183 | if (priv->flags & ALPS_FW_BK_1) { |
185 | back = packet[0] & 0x10; | 184 | back = packet[0] & 0x10; |
186 | forward = packet[2] & 4; | 185 | forward = packet[2] & 4; |
187 | } | 186 | } |
188 | 187 | ||
189 | if (model->flags & ALPS_FW_BK_2) { | 188 | if (priv->flags & ALPS_FW_BK_2) { |
190 | back = packet[3] & 4; | 189 | back = packet[3] & 4; |
191 | forward = packet[2] & 4; | 190 | forward = packet[2] & 4; |
192 | if ((middle = forward && back)) | 191 | if ((middle = forward && back)) |
@@ -196,7 +195,7 @@ static void alps_process_packet_v1_v2(struct psmouse *psmouse) | |||
196 | ges = packet[2] & 1; | 195 | ges = packet[2] & 1; |
197 | fin = packet[2] & 2; | 196 | fin = packet[2] & 2; |
198 | 197 | ||
199 | if ((model->flags & ALPS_DUALPOINT) && z == 127) { | 198 | if ((priv->flags & ALPS_DUALPOINT) && z == 127) { |
200 | input_report_rel(dev2, REL_X, (x > 383 ? (x - 768) : x)); | 199 | input_report_rel(dev2, REL_X, (x > 383 ? (x - 768) : x)); |
201 | input_report_rel(dev2, REL_Y, -(y > 255 ? (y - 512) : y)); | 200 | input_report_rel(dev2, REL_Y, -(y > 255 ? (y - 512) : y)); |
202 | 201 | ||
@@ -239,15 +238,15 @@ static void alps_process_packet_v1_v2(struct psmouse *psmouse) | |||
239 | input_report_abs(dev, ABS_PRESSURE, z); | 238 | input_report_abs(dev, ABS_PRESSURE, z); |
240 | input_report_key(dev, BTN_TOOL_FINGER, z > 0); | 239 | input_report_key(dev, BTN_TOOL_FINGER, z > 0); |
241 | 240 | ||
242 | if (model->flags & ALPS_WHEEL) | 241 | if (priv->flags & ALPS_WHEEL) |
243 | input_report_rel(dev, REL_WHEEL, ((packet[2] << 1) & 0x08) - ((packet[0] >> 4) & 0x07)); | 242 | input_report_rel(dev, REL_WHEEL, ((packet[2] << 1) & 0x08) - ((packet[0] >> 4) & 0x07)); |
244 | 243 | ||
245 | if (model->flags & (ALPS_FW_BK_1 | ALPS_FW_BK_2)) { | 244 | if (priv->flags & (ALPS_FW_BK_1 | ALPS_FW_BK_2)) { |
246 | input_report_key(dev, BTN_FORWARD, forward); | 245 | input_report_key(dev, BTN_FORWARD, forward); |
247 | input_report_key(dev, BTN_BACK, back); | 246 | input_report_key(dev, BTN_BACK, back); |
248 | } | 247 | } |
249 | 248 | ||
250 | if (model->flags & ALPS_FOUR_BUTTONS) { | 249 | if (priv->flags & ALPS_FOUR_BUTTONS) { |
251 | input_report_key(dev, BTN_0, packet[2] & 4); | 250 | input_report_key(dev, BTN_0, packet[2] & 4); |
252 | input_report_key(dev, BTN_1, packet[0] & 0x10); | 251 | input_report_key(dev, BTN_1, packet[0] & 0x10); |
253 | input_report_key(dev, BTN_2, packet[3] & 4); | 252 | input_report_key(dev, BTN_2, packet[3] & 4); |
@@ -267,7 +266,8 @@ static void alps_process_packet_v1_v2(struct psmouse *psmouse) | |||
267 | * These points are returned in x1, y1, x2, and y2 when the return value | 266 | * These points are returned in x1, y1, x2, and y2 when the return value |
268 | * is greater than 0. | 267 | * is greater than 0. |
269 | */ | 268 | */ |
270 | static int alps_process_bitmap(unsigned int x_map, unsigned int y_map, | 269 | static int alps_process_bitmap(struct alps_data *priv, |
270 | unsigned int x_map, unsigned int y_map, | ||
271 | int *x1, int *y1, int *x2, int *y2) | 271 | int *x1, int *y1, int *x2, int *y2) |
272 | { | 272 | { |
273 | struct alps_bitmap_point { | 273 | struct alps_bitmap_point { |
@@ -309,7 +309,7 @@ static int alps_process_bitmap(unsigned int x_map, unsigned int y_map, | |||
309 | * y bitmap is reversed for what we need (lower positions are in | 309 | * y bitmap is reversed for what we need (lower positions are in |
310 | * higher bits), so we process from the top end. | 310 | * higher bits), so we process from the top end. |
311 | */ | 311 | */ |
312 | y_map = y_map << (sizeof(y_map) * BITS_PER_BYTE - ALPS_BITMAP_Y_BITS); | 312 | y_map = y_map << (sizeof(y_map) * BITS_PER_BYTE - priv->y_bits); |
313 | prev_bit = 0; | 313 | prev_bit = 0; |
314 | point = &y_low; | 314 | point = &y_low; |
315 | for (i = 0; y_map != 0; i++, y_map <<= 1) { | 315 | for (i = 0; y_map != 0; i++, y_map <<= 1) { |
@@ -355,16 +355,18 @@ static int alps_process_bitmap(unsigned int x_map, unsigned int y_map, | |||
355 | } | 355 | } |
356 | } | 356 | } |
357 | 357 | ||
358 | *x1 = (ALPS_V3_X_MAX * (2 * x_low.start_bit + x_low.num_bits - 1)) / | 358 | *x1 = (priv->x_max * (2 * x_low.start_bit + x_low.num_bits - 1)) / |
359 | (2 * (ALPS_BITMAP_X_BITS - 1)); | 359 | (2 * (priv->x_bits - 1)); |
360 | *y1 = (ALPS_V3_Y_MAX * (2 * y_low.start_bit + y_low.num_bits - 1)) / | 360 | *y1 = (priv->y_max * (2 * y_low.start_bit + y_low.num_bits - 1)) / |
361 | (2 * (ALPS_BITMAP_Y_BITS - 1)); | 361 | (2 * (priv->y_bits - 1)); |
362 | 362 | ||
363 | if (fingers > 1) { | 363 | if (fingers > 1) { |
364 | *x2 = (ALPS_V3_X_MAX * (2 * x_high.start_bit + x_high.num_bits - 1)) / | 364 | *x2 = (priv->x_max * |
365 | (2 * (ALPS_BITMAP_X_BITS - 1)); | 365 | (2 * x_high.start_bit + x_high.num_bits - 1)) / |
366 | *y2 = (ALPS_V3_Y_MAX * (2 * y_high.start_bit + y_high.num_bits - 1)) / | 366 | (2 * (priv->x_bits - 1)); |
367 | (2 * (ALPS_BITMAP_Y_BITS - 1)); | 367 | *y2 = (priv->y_max * |
368 | (2 * y_high.start_bit + y_high.num_bits - 1)) / | ||
369 | (2 * (priv->y_bits - 1)); | ||
368 | } | 370 | } |
369 | 371 | ||
370 | return fingers; | 372 | return fingers; |
@@ -448,17 +450,57 @@ static void alps_process_trackstick_packet_v3(struct psmouse *psmouse) | |||
448 | return; | 450 | return; |
449 | } | 451 | } |
450 | 452 | ||
453 | static void alps_decode_buttons_v3(struct alps_fields *f, unsigned char *p) | ||
454 | { | ||
455 | f->left = !!(p[3] & 0x01); | ||
456 | f->right = !!(p[3] & 0x02); | ||
457 | f->middle = !!(p[3] & 0x04); | ||
458 | |||
459 | f->ts_left = !!(p[3] & 0x10); | ||
460 | f->ts_right = !!(p[3] & 0x20); | ||
461 | f->ts_middle = !!(p[3] & 0x40); | ||
462 | } | ||
463 | |||
464 | static void alps_decode_pinnacle(struct alps_fields *f, unsigned char *p) | ||
465 | { | ||
466 | f->first_mp = !!(p[4] & 0x40); | ||
467 | f->is_mp = !!(p[0] & 0x40); | ||
468 | |||
469 | f->fingers = (p[5] & 0x3) + 1; | ||
470 | f->x_map = ((p[4] & 0x7e) << 8) | | ||
471 | ((p[1] & 0x7f) << 2) | | ||
472 | ((p[0] & 0x30) >> 4); | ||
473 | f->y_map = ((p[3] & 0x70) << 4) | | ||
474 | ((p[2] & 0x7f) << 1) | | ||
475 | (p[4] & 0x01); | ||
476 | |||
477 | f->x = ((p[1] & 0x7f) << 4) | ((p[4] & 0x30) >> 2) | | ||
478 | ((p[0] & 0x30) >> 4); | ||
479 | f->y = ((p[2] & 0x7f) << 4) | (p[4] & 0x0f); | ||
480 | f->z = p[5] & 0x7f; | ||
481 | |||
482 | alps_decode_buttons_v3(f, p); | ||
483 | } | ||
484 | |||
485 | static void alps_decode_rushmore(struct alps_fields *f, unsigned char *p) | ||
486 | { | ||
487 | alps_decode_pinnacle(f, p); | ||
488 | |||
489 | f->x_map |= (p[5] & 0x10) << 11; | ||
490 | f->y_map |= (p[5] & 0x20) << 6; | ||
491 | } | ||
492 | |||
451 | static void alps_process_touchpad_packet_v3(struct psmouse *psmouse) | 493 | static void alps_process_touchpad_packet_v3(struct psmouse *psmouse) |
452 | { | 494 | { |
453 | struct alps_data *priv = psmouse->private; | 495 | struct alps_data *priv = psmouse->private; |
454 | unsigned char *packet = psmouse->packet; | 496 | unsigned char *packet = psmouse->packet; |
455 | struct input_dev *dev = psmouse->dev; | 497 | struct input_dev *dev = psmouse->dev; |
456 | struct input_dev *dev2 = priv->dev2; | 498 | struct input_dev *dev2 = priv->dev2; |
457 | int x, y, z; | ||
458 | int left, right, middle; | ||
459 | int x1 = 0, y1 = 0, x2 = 0, y2 = 0; | 499 | int x1 = 0, y1 = 0, x2 = 0, y2 = 0; |
460 | int fingers = 0, bmap_fingers; | 500 | int fingers = 0, bmap_fingers; |
461 | unsigned int x_bitmap, y_bitmap; | 501 | struct alps_fields f; |
502 | |||
503 | priv->decode_fields(&f, packet); | ||
462 | 504 | ||
463 | /* | 505 | /* |
464 | * There's no single feature of touchpad position and bitmap packets | 506 | * There's no single feature of touchpad position and bitmap packets |
@@ -473,16 +515,10 @@ static void alps_process_touchpad_packet_v3(struct psmouse *psmouse) | |||
473 | * packet. Check for this, and when it happens process the | 515 | * packet. Check for this, and when it happens process the |
474 | * position packet as usual. | 516 | * position packet as usual. |
475 | */ | 517 | */ |
476 | if (packet[0] & 0x40) { | 518 | if (f.is_mp) { |
477 | fingers = (packet[5] & 0x3) + 1; | 519 | fingers = f.fingers; |
478 | x_bitmap = ((packet[4] & 0x7e) << 8) | | 520 | bmap_fingers = alps_process_bitmap(priv, |
479 | ((packet[1] & 0x7f) << 2) | | 521 | f.x_map, f.y_map, |
480 | ((packet[0] & 0x30) >> 4); | ||
481 | y_bitmap = ((packet[3] & 0x70) << 4) | | ||
482 | ((packet[2] & 0x7f) << 1) | | ||
483 | (packet[4] & 0x01); | ||
484 | |||
485 | bmap_fingers = alps_process_bitmap(x_bitmap, y_bitmap, | ||
486 | &x1, &y1, &x2, &y2); | 522 | &x1, &y1, &x2, &y2); |
487 | 523 | ||
488 | /* | 524 | /* |
@@ -493,7 +529,7 @@ static void alps_process_touchpad_packet_v3(struct psmouse *psmouse) | |||
493 | fingers = bmap_fingers; | 529 | fingers = bmap_fingers; |
494 | 530 | ||
495 | /* Now process position packet */ | 531 | /* Now process position packet */ |
496 | packet = priv->multi_data; | 532 | priv->decode_fields(&f, priv->multi_data); |
497 | } else { | 533 | } else { |
498 | priv->multi_packet = 0; | 534 | priv->multi_packet = 0; |
499 | } | 535 | } |
@@ -507,10 +543,10 @@ static void alps_process_touchpad_packet_v3(struct psmouse *psmouse) | |||
507 | * out misidentified bitmap packets, we reject anything with this | 543 | * out misidentified bitmap packets, we reject anything with this |
508 | * bit set. | 544 | * bit set. |
509 | */ | 545 | */ |
510 | if (packet[0] & 0x40) | 546 | if (f.is_mp) |
511 | return; | 547 | return; |
512 | 548 | ||
513 | if (!priv->multi_packet && (packet[4] & 0x40)) { | 549 | if (!priv->multi_packet && f.first_mp) { |
514 | priv->multi_packet = 1; | 550 | priv->multi_packet = 1; |
515 | memcpy(priv->multi_data, packet, sizeof(priv->multi_data)); | 551 | memcpy(priv->multi_data, packet, sizeof(priv->multi_data)); |
516 | return; | 552 | return; |
@@ -518,22 +554,13 @@ static void alps_process_touchpad_packet_v3(struct psmouse *psmouse) | |||
518 | 554 | ||
519 | priv->multi_packet = 0; | 555 | priv->multi_packet = 0; |
520 | 556 | ||
521 | left = packet[3] & 0x01; | ||
522 | right = packet[3] & 0x02; | ||
523 | middle = packet[3] & 0x04; | ||
524 | |||
525 | x = ((packet[1] & 0x7f) << 4) | ((packet[4] & 0x30) >> 2) | | ||
526 | ((packet[0] & 0x30) >> 4); | ||
527 | y = ((packet[2] & 0x7f) << 4) | (packet[4] & 0x0f); | ||
528 | z = packet[5] & 0x7f; | ||
529 | |||
530 | /* | 557 | /* |
531 | * Sometimes the hardware sends a single packet with z = 0 | 558 | * Sometimes the hardware sends a single packet with z = 0 |
532 | * in the middle of a stream. Real releases generate packets | 559 | * in the middle of a stream. Real releases generate packets |
533 | * with x, y, and z all zero, so these seem to be flukes. | 560 | * with x, y, and z all zero, so these seem to be flukes. |
534 | * Ignore them. | 561 | * Ignore them. |
535 | */ | 562 | */ |
536 | if (x && y && !z) | 563 | if (f.x && f.y && !f.z) |
537 | return; | 564 | return; |
538 | 565 | ||
539 | /* | 566 | /* |
@@ -541,12 +568,12 @@ static void alps_process_touchpad_packet_v3(struct psmouse *psmouse) | |||
541 | * to rely on ST data. | 568 | * to rely on ST data. |
542 | */ | 569 | */ |
543 | if (!fingers) { | 570 | if (!fingers) { |
544 | x1 = x; | 571 | x1 = f.x; |
545 | y1 = y; | 572 | y1 = f.y; |
546 | fingers = z > 0 ? 1 : 0; | 573 | fingers = f.z > 0 ? 1 : 0; |
547 | } | 574 | } |
548 | 575 | ||
549 | if (z >= 64) | 576 | if (f.z >= 64) |
550 | input_report_key(dev, BTN_TOUCH, 1); | 577 | input_report_key(dev, BTN_TOUCH, 1); |
551 | else | 578 | else |
552 | input_report_key(dev, BTN_TOUCH, 0); | 579 | input_report_key(dev, BTN_TOUCH, 0); |
@@ -555,26 +582,22 @@ static void alps_process_touchpad_packet_v3(struct psmouse *psmouse) | |||
555 | 582 | ||
556 | input_mt_report_finger_count(dev, fingers); | 583 | input_mt_report_finger_count(dev, fingers); |
557 | 584 | ||
558 | input_report_key(dev, BTN_LEFT, left); | 585 | input_report_key(dev, BTN_LEFT, f.left); |
559 | input_report_key(dev, BTN_RIGHT, right); | 586 | input_report_key(dev, BTN_RIGHT, f.right); |
560 | input_report_key(dev, BTN_MIDDLE, middle); | 587 | input_report_key(dev, BTN_MIDDLE, f.middle); |
561 | 588 | ||
562 | if (z > 0) { | 589 | if (f.z > 0) { |
563 | input_report_abs(dev, ABS_X, x); | 590 | input_report_abs(dev, ABS_X, f.x); |
564 | input_report_abs(dev, ABS_Y, y); | 591 | input_report_abs(dev, ABS_Y, f.y); |
565 | } | 592 | } |
566 | input_report_abs(dev, ABS_PRESSURE, z); | 593 | input_report_abs(dev, ABS_PRESSURE, f.z); |
567 | 594 | ||
568 | input_sync(dev); | 595 | input_sync(dev); |
569 | 596 | ||
570 | if (!(priv->quirks & ALPS_QUIRK_TRACKSTICK_BUTTONS)) { | 597 | if (!(priv->quirks & ALPS_QUIRK_TRACKSTICK_BUTTONS)) { |
571 | left = packet[3] & 0x10; | 598 | input_report_key(dev2, BTN_LEFT, f.ts_left); |
572 | right = packet[3] & 0x20; | 599 | input_report_key(dev2, BTN_RIGHT, f.ts_right); |
573 | middle = packet[3] & 0x40; | 600 | input_report_key(dev2, BTN_MIDDLE, f.ts_middle); |
574 | |||
575 | input_report_key(dev2, BTN_LEFT, left); | ||
576 | input_report_key(dev2, BTN_RIGHT, right); | ||
577 | input_report_key(dev2, BTN_MIDDLE, middle); | ||
578 | input_sync(dev2); | 601 | input_sync(dev2); |
579 | } | 602 | } |
580 | } | 603 | } |
@@ -639,7 +662,7 @@ static void alps_process_packet_v4(struct psmouse *psmouse) | |||
639 | ((priv->multi_data[3] & 0x1f) << 5) | | 662 | ((priv->multi_data[3] & 0x1f) << 5) | |
640 | (priv->multi_data[1] & 0x1f); | 663 | (priv->multi_data[1] & 0x1f); |
641 | 664 | ||
642 | fingers = alps_process_bitmap(x_bitmap, y_bitmap, | 665 | fingers = alps_process_bitmap(priv, x_bitmap, y_bitmap, |
643 | &x1, &y1, &x2, &y2); | 666 | &x1, &y1, &x2, &y2); |
644 | 667 | ||
645 | /* Store MT data.*/ | 668 | /* Store MT data.*/ |
@@ -696,25 +719,6 @@ static void alps_process_packet_v4(struct psmouse *psmouse) | |||
696 | input_sync(dev); | 719 | input_sync(dev); |
697 | } | 720 | } |
698 | 721 | ||
699 | static void alps_process_packet(struct psmouse *psmouse) | ||
700 | { | ||
701 | struct alps_data *priv = psmouse->private; | ||
702 | const struct alps_model_info *model = priv->i; | ||
703 | |||
704 | switch (model->proto_version) { | ||
705 | case ALPS_PROTO_V1: | ||
706 | case ALPS_PROTO_V2: | ||
707 | alps_process_packet_v1_v2(psmouse); | ||
708 | break; | ||
709 | case ALPS_PROTO_V3: | ||
710 | alps_process_packet_v3(psmouse); | ||
711 | break; | ||
712 | case ALPS_PROTO_V4: | ||
713 | alps_process_packet_v4(psmouse); | ||
714 | break; | ||
715 | } | ||
716 | } | ||
717 | |||
718 | static void alps_report_bare_ps2_packet(struct psmouse *psmouse, | 722 | static void alps_report_bare_ps2_packet(struct psmouse *psmouse, |
719 | unsigned char packet[], | 723 | unsigned char packet[], |
720 | bool report_buttons) | 724 | bool report_buttons) |
@@ -765,14 +769,14 @@ static psmouse_ret_t alps_handle_interleaved_ps2(struct psmouse *psmouse) | |||
765 | if (((psmouse->packet[3] | | 769 | if (((psmouse->packet[3] | |
766 | psmouse->packet[4] | | 770 | psmouse->packet[4] | |
767 | psmouse->packet[5]) & 0x80) || | 771 | psmouse->packet[5]) & 0x80) || |
768 | (!alps_is_valid_first_byte(priv->i, psmouse->packet[6]))) { | 772 | (!alps_is_valid_first_byte(priv, psmouse->packet[6]))) { |
769 | psmouse_dbg(psmouse, | 773 | psmouse_dbg(psmouse, |
770 | "refusing packet %4ph (suspected interleaved ps/2)\n", | 774 | "refusing packet %4ph (suspected interleaved ps/2)\n", |
771 | psmouse->packet + 3); | 775 | psmouse->packet + 3); |
772 | return PSMOUSE_BAD_DATA; | 776 | return PSMOUSE_BAD_DATA; |
773 | } | 777 | } |
774 | 778 | ||
775 | alps_process_packet(psmouse); | 779 | priv->process_packet(psmouse); |
776 | 780 | ||
777 | /* Continue with the next packet */ | 781 | /* Continue with the next packet */ |
778 | psmouse->packet[0] = psmouse->packet[6]; | 782 | psmouse->packet[0] = psmouse->packet[6]; |
@@ -816,6 +820,7 @@ static psmouse_ret_t alps_handle_interleaved_ps2(struct psmouse *psmouse) | |||
816 | static void alps_flush_packet(unsigned long data) | 820 | static void alps_flush_packet(unsigned long data) |
817 | { | 821 | { |
818 | struct psmouse *psmouse = (struct psmouse *)data; | 822 | struct psmouse *psmouse = (struct psmouse *)data; |
823 | struct alps_data *priv = psmouse->private; | ||
819 | 824 | ||
820 | serio_pause_rx(psmouse->ps2dev.serio); | 825 | serio_pause_rx(psmouse->ps2dev.serio); |
821 | 826 | ||
@@ -833,7 +838,7 @@ static void alps_flush_packet(unsigned long data) | |||
833 | "refusing packet %3ph (suspected interleaved ps/2)\n", | 838 | "refusing packet %3ph (suspected interleaved ps/2)\n", |
834 | psmouse->packet + 3); | 839 | psmouse->packet + 3); |
835 | } else { | 840 | } else { |
836 | alps_process_packet(psmouse); | 841 | priv->process_packet(psmouse); |
837 | } | 842 | } |
838 | psmouse->pktcnt = 0; | 843 | psmouse->pktcnt = 0; |
839 | } | 844 | } |
@@ -844,7 +849,6 @@ static void alps_flush_packet(unsigned long data) | |||
844 | static psmouse_ret_t alps_process_byte(struct psmouse *psmouse) | 849 | static psmouse_ret_t alps_process_byte(struct psmouse *psmouse) |
845 | { | 850 | { |
846 | struct alps_data *priv = psmouse->private; | 851 | struct alps_data *priv = psmouse->private; |
847 | const struct alps_model_info *model = priv->i; | ||
848 | 852 | ||
849 | if ((psmouse->packet[0] & 0xc8) == 0x08) { /* PS/2 packet */ | 853 | if ((psmouse->packet[0] & 0xc8) == 0x08) { /* PS/2 packet */ |
850 | if (psmouse->pktcnt == 3) { | 854 | if (psmouse->pktcnt == 3) { |
@@ -857,15 +861,15 @@ static psmouse_ret_t alps_process_byte(struct psmouse *psmouse) | |||
857 | 861 | ||
858 | /* Check for PS/2 packet stuffed in the middle of ALPS packet. */ | 862 | /* Check for PS/2 packet stuffed in the middle of ALPS packet. */ |
859 | 863 | ||
860 | if ((model->flags & ALPS_PS2_INTERLEAVED) && | 864 | if ((priv->flags & ALPS_PS2_INTERLEAVED) && |
861 | psmouse->pktcnt >= 4 && (psmouse->packet[3] & 0x0f) == 0x0f) { | 865 | psmouse->pktcnt >= 4 && (psmouse->packet[3] & 0x0f) == 0x0f) { |
862 | return alps_handle_interleaved_ps2(psmouse); | 866 | return alps_handle_interleaved_ps2(psmouse); |
863 | } | 867 | } |
864 | 868 | ||
865 | if (!alps_is_valid_first_byte(model, psmouse->packet[0])) { | 869 | if (!alps_is_valid_first_byte(priv, psmouse->packet[0])) { |
866 | psmouse_dbg(psmouse, | 870 | psmouse_dbg(psmouse, |
867 | "refusing packet[0] = %x (mask0 = %x, byte0 = %x)\n", | 871 | "refusing packet[0] = %x (mask0 = %x, byte0 = %x)\n", |
868 | psmouse->packet[0], model->mask0, model->byte0); | 872 | psmouse->packet[0], priv->mask0, priv->byte0); |
869 | return PSMOUSE_BAD_DATA; | 873 | return PSMOUSE_BAD_DATA; |
870 | } | 874 | } |
871 | 875 | ||
@@ -879,7 +883,7 @@ static psmouse_ret_t alps_process_byte(struct psmouse *psmouse) | |||
879 | } | 883 | } |
880 | 884 | ||
881 | if (psmouse->pktcnt == psmouse->pktsize) { | 885 | if (psmouse->pktcnt == psmouse->pktsize) { |
882 | alps_process_packet(psmouse); | 886 | priv->process_packet(psmouse); |
883 | return PSMOUSE_FULL_PACKET; | 887 | return PSMOUSE_FULL_PACKET; |
884 | } | 888 | } |
885 | 889 | ||
@@ -967,24 +971,42 @@ static int alps_command_mode_write_reg(struct psmouse *psmouse, int addr, | |||
967 | return __alps_command_mode_write_reg(psmouse, value); | 971 | return __alps_command_mode_write_reg(psmouse, value); |
968 | } | 972 | } |
969 | 973 | ||
974 | static int alps_rpt_cmd(struct psmouse *psmouse, int init_command, | ||
975 | int repeated_command, unsigned char *param) | ||
976 | { | ||
977 | struct ps2dev *ps2dev = &psmouse->ps2dev; | ||
978 | |||
979 | param[0] = 0; | ||
980 | if (init_command && ps2_command(ps2dev, param, init_command)) | ||
981 | return -EIO; | ||
982 | |||
983 | if (ps2_command(ps2dev, NULL, repeated_command) || | ||
984 | ps2_command(ps2dev, NULL, repeated_command) || | ||
985 | ps2_command(ps2dev, NULL, repeated_command)) | ||
986 | return -EIO; | ||
987 | |||
988 | param[0] = param[1] = param[2] = 0xff; | ||
989 | if (ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO)) | ||
990 | return -EIO; | ||
991 | |||
992 | psmouse_dbg(psmouse, "%2.2X report: %2.2x %2.2x %2.2x\n", | ||
993 | repeated_command, param[0], param[1], param[2]); | ||
994 | return 0; | ||
995 | } | ||
996 | |||
970 | static int alps_enter_command_mode(struct psmouse *psmouse, | 997 | static int alps_enter_command_mode(struct psmouse *psmouse, |
971 | unsigned char *resp) | 998 | unsigned char *resp) |
972 | { | 999 | { |
973 | unsigned char param[4]; | 1000 | unsigned char param[4]; |
974 | struct ps2dev *ps2dev = &psmouse->ps2dev; | ||
975 | 1001 | ||
976 | if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_RESET_WRAP) || | 1002 | if (alps_rpt_cmd(psmouse, 0, PSMOUSE_CMD_RESET_WRAP, param)) { |
977 | ps2_command(ps2dev, NULL, PSMOUSE_CMD_RESET_WRAP) || | ||
978 | ps2_command(ps2dev, NULL, PSMOUSE_CMD_RESET_WRAP) || | ||
979 | ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO)) { | ||
980 | psmouse_err(psmouse, "failed to enter command mode\n"); | 1003 | psmouse_err(psmouse, "failed to enter command mode\n"); |
981 | return -1; | 1004 | return -1; |
982 | } | 1005 | } |
983 | 1006 | ||
984 | if (param[0] != 0x88 && param[1] != 0x07) { | 1007 | if (param[0] != 0x88 || (param[1] != 0x07 && param[1] != 0x08)) { |
985 | psmouse_dbg(psmouse, | 1008 | psmouse_dbg(psmouse, |
986 | "unknown response while entering command mode: %2.2x %2.2x %2.2x\n", | 1009 | "unknown response while entering command mode\n"); |
987 | param[0], param[1], param[2]); | ||
988 | return -1; | 1010 | return -1; |
989 | } | 1011 | } |
990 | 1012 | ||
@@ -1001,99 +1023,6 @@ static inline int alps_exit_command_mode(struct psmouse *psmouse) | |||
1001 | return 0; | 1023 | return 0; |
1002 | } | 1024 | } |
1003 | 1025 | ||
1004 | static const struct alps_model_info *alps_get_model(struct psmouse *psmouse, int *version) | ||
1005 | { | ||
1006 | struct ps2dev *ps2dev = &psmouse->ps2dev; | ||
1007 | static const unsigned char rates[] = { 0, 10, 20, 40, 60, 80, 100, 200 }; | ||
1008 | unsigned char param[4]; | ||
1009 | const struct alps_model_info *model = NULL; | ||
1010 | int i; | ||
1011 | |||
1012 | /* | ||
1013 | * First try "E6 report". | ||
1014 | * ALPS should return 0,0,10 or 0,0,100 if no buttons are pressed. | ||
1015 | * The bits 0-2 of the first byte will be 1s if some buttons are | ||
1016 | * pressed. | ||
1017 | */ | ||
1018 | param[0] = 0; | ||
1019 | if (ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES) || | ||
1020 | ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11) || | ||
1021 | ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11) || | ||
1022 | ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11)) | ||
1023 | return NULL; | ||
1024 | |||
1025 | param[0] = param[1] = param[2] = 0xff; | ||
1026 | if (ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO)) | ||
1027 | return NULL; | ||
1028 | |||
1029 | psmouse_dbg(psmouse, "E6 report: %2.2x %2.2x %2.2x", | ||
1030 | param[0], param[1], param[2]); | ||
1031 | |||
1032 | if ((param[0] & 0xf8) != 0 || param[1] != 0 || | ||
1033 | (param[2] != 10 && param[2] != 100)) | ||
1034 | return NULL; | ||
1035 | |||
1036 | /* | ||
1037 | * Now try "E7 report". Allowed responses are in | ||
1038 | * alps_model_data[].signature | ||
1039 | */ | ||
1040 | param[0] = 0; | ||
1041 | if (ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES) || | ||
1042 | ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE21) || | ||
1043 | ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE21) || | ||
1044 | ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE21)) | ||
1045 | return NULL; | ||
1046 | |||
1047 | param[0] = param[1] = param[2] = 0xff; | ||
1048 | if (ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO)) | ||
1049 | return NULL; | ||
1050 | |||
1051 | psmouse_dbg(psmouse, "E7 report: %2.2x %2.2x %2.2x", | ||
1052 | param[0], param[1], param[2]); | ||
1053 | |||
1054 | if (version) { | ||
1055 | for (i = 0; i < ARRAY_SIZE(rates) && param[2] != rates[i]; i++) | ||
1056 | /* empty */; | ||
1057 | *version = (param[0] << 8) | (param[1] << 4) | i; | ||
1058 | } | ||
1059 | |||
1060 | for (i = 0; i < ARRAY_SIZE(alps_model_data); i++) { | ||
1061 | if (!memcmp(param, alps_model_data[i].signature, | ||
1062 | sizeof(alps_model_data[i].signature))) { | ||
1063 | model = alps_model_data + i; | ||
1064 | break; | ||
1065 | } | ||
1066 | } | ||
1067 | |||
1068 | if (model && model->proto_version > ALPS_PROTO_V2) { | ||
1069 | /* | ||
1070 | * Need to check command mode response to identify | ||
1071 | * model | ||
1072 | */ | ||
1073 | model = NULL; | ||
1074 | if (alps_enter_command_mode(psmouse, param)) { | ||
1075 | psmouse_warn(psmouse, | ||
1076 | "touchpad failed to enter command mode\n"); | ||
1077 | } else { | ||
1078 | for (i = 0; i < ARRAY_SIZE(alps_model_data); i++) { | ||
1079 | if (alps_model_data[i].proto_version > ALPS_PROTO_V2 && | ||
1080 | alps_model_data[i].command_mode_resp == param[0]) { | ||
1081 | model = alps_model_data + i; | ||
1082 | break; | ||
1083 | } | ||
1084 | } | ||
1085 | alps_exit_command_mode(psmouse); | ||
1086 | |||
1087 | if (!model) | ||
1088 | psmouse_dbg(psmouse, | ||
1089 | "Unknown command mode response %2.2x\n", | ||
1090 | param[0]); | ||
1091 | } | ||
1092 | } | ||
1093 | |||
1094 | return model; | ||
1095 | } | ||
1096 | |||
1097 | /* | 1026 | /* |
1098 | * For DualPoint devices select the device that should respond to | 1027 | * For DualPoint devices select the device that should respond to |
1099 | * subsequent commands. It looks like glidepad is behind stickpointer, | 1028 | * subsequent commands. It looks like glidepad is behind stickpointer, |
@@ -1137,18 +1066,10 @@ static int alps_absolute_mode_v1_v2(struct psmouse *psmouse) | |||
1137 | 1066 | ||
1138 | static int alps_get_status(struct psmouse *psmouse, char *param) | 1067 | static int alps_get_status(struct psmouse *psmouse, char *param) |
1139 | { | 1068 | { |
1140 | struct ps2dev *ps2dev = &psmouse->ps2dev; | ||
1141 | |||
1142 | /* Get status: 0xF5 0xF5 0xF5 0xE9 */ | 1069 | /* Get status: 0xF5 0xF5 0xF5 0xE9 */ |
1143 | if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE) || | 1070 | if (alps_rpt_cmd(psmouse, 0, PSMOUSE_CMD_DISABLE, param)) |
1144 | ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE) || | ||
1145 | ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE) || | ||
1146 | ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO)) | ||
1147 | return -1; | 1071 | return -1; |
1148 | 1072 | ||
1149 | psmouse_dbg(psmouse, "Status: %2.2x %2.2x %2.2x", | ||
1150 | param[0], param[1], param[2]); | ||
1151 | |||
1152 | return 0; | 1073 | return 0; |
1153 | } | 1074 | } |
1154 | 1075 | ||
@@ -1190,16 +1111,16 @@ static int alps_poll(struct psmouse *psmouse) | |||
1190 | unsigned char buf[sizeof(psmouse->packet)]; | 1111 | unsigned char buf[sizeof(psmouse->packet)]; |
1191 | bool poll_failed; | 1112 | bool poll_failed; |
1192 | 1113 | ||
1193 | if (priv->i->flags & ALPS_PASS) | 1114 | if (priv->flags & ALPS_PASS) |
1194 | alps_passthrough_mode_v2(psmouse, true); | 1115 | alps_passthrough_mode_v2(psmouse, true); |
1195 | 1116 | ||
1196 | poll_failed = ps2_command(&psmouse->ps2dev, buf, | 1117 | poll_failed = ps2_command(&psmouse->ps2dev, buf, |
1197 | PSMOUSE_CMD_POLL | (psmouse->pktsize << 8)) < 0; | 1118 | PSMOUSE_CMD_POLL | (psmouse->pktsize << 8)) < 0; |
1198 | 1119 | ||
1199 | if (priv->i->flags & ALPS_PASS) | 1120 | if (priv->flags & ALPS_PASS) |
1200 | alps_passthrough_mode_v2(psmouse, false); | 1121 | alps_passthrough_mode_v2(psmouse, false); |
1201 | 1122 | ||
1202 | if (poll_failed || (buf[0] & priv->i->mask0) != priv->i->byte0) | 1123 | if (poll_failed || (buf[0] & priv->mask0) != priv->byte0) |
1203 | return -1; | 1124 | return -1; |
1204 | 1125 | ||
1205 | if ((psmouse->badbyte & 0xc8) == 0x08) { | 1126 | if ((psmouse->badbyte & 0xc8) == 0x08) { |
@@ -1217,9 +1138,8 @@ static int alps_poll(struct psmouse *psmouse) | |||
1217 | static int alps_hw_init_v1_v2(struct psmouse *psmouse) | 1138 | static int alps_hw_init_v1_v2(struct psmouse *psmouse) |
1218 | { | 1139 | { |
1219 | struct alps_data *priv = psmouse->private; | 1140 | struct alps_data *priv = psmouse->private; |
1220 | const struct alps_model_info *model = priv->i; | ||
1221 | 1141 | ||
1222 | if ((model->flags & ALPS_PASS) && | 1142 | if ((priv->flags & ALPS_PASS) && |
1223 | alps_passthrough_mode_v2(psmouse, true)) { | 1143 | alps_passthrough_mode_v2(psmouse, true)) { |
1224 | return -1; | 1144 | return -1; |
1225 | } | 1145 | } |
@@ -1234,7 +1154,7 @@ static int alps_hw_init_v1_v2(struct psmouse *psmouse) | |||
1234 | return -1; | 1154 | return -1; |
1235 | } | 1155 | } |
1236 | 1156 | ||
1237 | if ((model->flags & ALPS_PASS) && | 1157 | if ((priv->flags & ALPS_PASS) && |
1238 | alps_passthrough_mode_v2(psmouse, false)) { | 1158 | alps_passthrough_mode_v2(psmouse, false)) { |
1239 | return -1; | 1159 | return -1; |
1240 | } | 1160 | } |
@@ -1249,26 +1169,31 @@ static int alps_hw_init_v1_v2(struct psmouse *psmouse) | |||
1249 | } | 1169 | } |
1250 | 1170 | ||
1251 | /* | 1171 | /* |
1252 | * Enable or disable passthrough mode to the trackstick. Must be in | 1172 | * Enable or disable passthrough mode to the trackstick. |
1253 | * command mode when calling this function. | ||
1254 | */ | 1173 | */ |
1255 | static int alps_passthrough_mode_v3(struct psmouse *psmouse, bool enable) | 1174 | static int alps_passthrough_mode_v3(struct psmouse *psmouse, |
1175 | int reg_base, bool enable) | ||
1256 | { | 1176 | { |
1257 | int reg_val; | 1177 | int reg_val, ret = -1; |
1258 | 1178 | ||
1259 | reg_val = alps_command_mode_read_reg(psmouse, 0x0008); | 1179 | if (alps_enter_command_mode(psmouse, NULL)) |
1260 | if (reg_val == -1) | ||
1261 | return -1; | 1180 | return -1; |
1262 | 1181 | ||
1182 | reg_val = alps_command_mode_read_reg(psmouse, reg_base + 0x0008); | ||
1183 | if (reg_val == -1) | ||
1184 | goto error; | ||
1185 | |||
1263 | if (enable) | 1186 | if (enable) |
1264 | reg_val |= 0x01; | 1187 | reg_val |= 0x01; |
1265 | else | 1188 | else |
1266 | reg_val &= ~0x01; | 1189 | reg_val &= ~0x01; |
1267 | 1190 | ||
1268 | if (__alps_command_mode_write_reg(psmouse, reg_val)) | 1191 | ret = __alps_command_mode_write_reg(psmouse, reg_val); |
1269 | return -1; | ||
1270 | 1192 | ||
1271 | return 0; | 1193 | error: |
1194 | if (alps_exit_command_mode(psmouse)) | ||
1195 | ret = -1; | ||
1196 | return ret; | ||
1272 | } | 1197 | } |
1273 | 1198 | ||
1274 | /* Must be in command mode when calling this function */ | 1199 | /* Must be in command mode when calling this function */ |
@@ -1287,73 +1212,102 @@ static int alps_absolute_mode_v3(struct psmouse *psmouse) | |||
1287 | return 0; | 1212 | return 0; |
1288 | } | 1213 | } |
1289 | 1214 | ||
1290 | static int alps_hw_init_v3(struct psmouse *psmouse) | 1215 | static int alps_probe_trackstick_v3(struct psmouse *psmouse, int reg_base) |
1291 | { | 1216 | { |
1292 | struct alps_data *priv = psmouse->private; | 1217 | int ret = -EIO, reg_val; |
1293 | struct ps2dev *ps2dev = &psmouse->ps2dev; | ||
1294 | int reg_val; | ||
1295 | unsigned char param[4]; | ||
1296 | |||
1297 | priv->nibble_commands = alps_v3_nibble_commands; | ||
1298 | priv->addr_command = PSMOUSE_CMD_RESET_WRAP; | ||
1299 | 1218 | ||
1300 | if (alps_enter_command_mode(psmouse, NULL)) | 1219 | if (alps_enter_command_mode(psmouse, NULL)) |
1301 | goto error; | 1220 | goto error; |
1302 | 1221 | ||
1303 | /* Check for trackstick */ | 1222 | reg_val = alps_command_mode_read_reg(psmouse, reg_base + 0x08); |
1304 | reg_val = alps_command_mode_read_reg(psmouse, 0x0008); | ||
1305 | if (reg_val == -1) | 1223 | if (reg_val == -1) |
1306 | goto error; | 1224 | goto error; |
1307 | if (reg_val & 0x80) { | 1225 | |
1308 | if (alps_passthrough_mode_v3(psmouse, true)) | 1226 | /* bit 7: trackstick is present */ |
1309 | goto error; | 1227 | ret = reg_val & 0x80 ? 0 : -ENODEV; |
1310 | if (alps_exit_command_mode(psmouse)) | 1228 | |
1311 | goto error; | 1229 | error: |
1230 | alps_exit_command_mode(psmouse); | ||
1231 | return ret; | ||
1232 | } | ||
1233 | |||
1234 | static int alps_setup_trackstick_v3(struct psmouse *psmouse, int reg_base) | ||
1235 | { | ||
1236 | struct ps2dev *ps2dev = &psmouse->ps2dev; | ||
1237 | int ret = 0; | ||
1238 | unsigned char param[4]; | ||
1239 | |||
1240 | if (alps_passthrough_mode_v3(psmouse, reg_base, true)) | ||
1241 | return -EIO; | ||
1242 | |||
1243 | /* | ||
1244 | * E7 report for the trackstick | ||
1245 | * | ||
1246 | * There have been reports of failures to seem to trace back | ||
1247 | * to the above trackstick check failing. When these occur | ||
1248 | * this E7 report fails, so when that happens we continue | ||
1249 | * with the assumption that there isn't a trackstick after | ||
1250 | * all. | ||
1251 | */ | ||
1252 | if (alps_rpt_cmd(psmouse, 0, PSMOUSE_CMD_SETSCALE21, param)) { | ||
1253 | psmouse_warn(psmouse, "trackstick E7 report failed\n"); | ||
1254 | ret = -ENODEV; | ||
1255 | } else { | ||
1256 | psmouse_dbg(psmouse, | ||
1257 | "trackstick E7 report: %2.2x %2.2x %2.2x\n", | ||
1258 | param[0], param[1], param[2]); | ||
1312 | 1259 | ||
1313 | /* | 1260 | /* |
1314 | * E7 report for the trackstick | 1261 | * Not sure what this does, but it is absolutely |
1315 | * | 1262 | * essential. Without it, the touchpad does not |
1316 | * There have been reports of failures to seem to trace back | 1263 | * work at all and the trackstick just emits normal |
1317 | * to the above trackstick check failing. When these occur | 1264 | * PS/2 packets. |
1318 | * this E7 report fails, so when that happens we continue | ||
1319 | * with the assumption that there isn't a trackstick after | ||
1320 | * all. | ||
1321 | */ | 1265 | */ |
1322 | param[0] = 0x64; | 1266 | if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11) || |
1323 | if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE21) || | 1267 | ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11) || |
1324 | ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE21) || | 1268 | ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11) || |
1325 | ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE21) || | 1269 | alps_command_mode_send_nibble(psmouse, 0x9) || |
1326 | ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO)) { | 1270 | alps_command_mode_send_nibble(psmouse, 0x4)) { |
1327 | psmouse_warn(psmouse, "trackstick E7 report failed\n"); | 1271 | psmouse_err(psmouse, |
1328 | } else { | 1272 | "Error sending magic E6 sequence\n"); |
1329 | psmouse_dbg(psmouse, | 1273 | ret = -EIO; |
1330 | "trackstick E7 report: %2.2x %2.2x %2.2x\n", | 1274 | goto error; |
1331 | param[0], param[1], param[2]); | ||
1332 | |||
1333 | /* | ||
1334 | * Not sure what this does, but it is absolutely | ||
1335 | * essential. Without it, the touchpad does not | ||
1336 | * work at all and the trackstick just emits normal | ||
1337 | * PS/2 packets. | ||
1338 | */ | ||
1339 | if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11) || | ||
1340 | ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11) || | ||
1341 | ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11) || | ||
1342 | alps_command_mode_send_nibble(psmouse, 0x9) || | ||
1343 | alps_command_mode_send_nibble(psmouse, 0x4)) { | ||
1344 | psmouse_err(psmouse, | ||
1345 | "Error sending magic E6 sequence\n"); | ||
1346 | goto error_passthrough; | ||
1347 | } | ||
1348 | } | 1275 | } |
1349 | 1276 | ||
1350 | if (alps_enter_command_mode(psmouse, NULL)) | 1277 | /* |
1351 | goto error_passthrough; | 1278 | * This ensures the trackstick packets are in the format |
1352 | if (alps_passthrough_mode_v3(psmouse, false)) | 1279 | * supported by this driver. If bit 1 isn't set the packet |
1353 | goto error; | 1280 | * format is different. |
1281 | */ | ||
1282 | if (alps_enter_command_mode(psmouse, NULL) || | ||
1283 | alps_command_mode_write_reg(psmouse, | ||
1284 | reg_base + 0x08, 0x82) || | ||
1285 | alps_exit_command_mode(psmouse)) | ||
1286 | ret = -EIO; | ||
1354 | } | 1287 | } |
1355 | 1288 | ||
1356 | if (alps_absolute_mode_v3(psmouse)) { | 1289 | error: |
1290 | if (alps_passthrough_mode_v3(psmouse, reg_base, false)) | ||
1291 | ret = -EIO; | ||
1292 | |||
1293 | return ret; | ||
1294 | } | ||
1295 | |||
1296 | static int alps_hw_init_v3(struct psmouse *psmouse) | ||
1297 | { | ||
1298 | struct ps2dev *ps2dev = &psmouse->ps2dev; | ||
1299 | int reg_val; | ||
1300 | unsigned char param[4]; | ||
1301 | |||
1302 | reg_val = alps_probe_trackstick_v3(psmouse, ALPS_REG_BASE_PINNACLE); | ||
1303 | if (reg_val == -EIO) | ||
1304 | goto error; | ||
1305 | if (reg_val == 0 && | ||
1306 | alps_setup_trackstick_v3(psmouse, ALPS_REG_BASE_PINNACLE) == -EIO) | ||
1307 | goto error; | ||
1308 | |||
1309 | if (alps_enter_command_mode(psmouse, NULL) || | ||
1310 | alps_absolute_mode_v3(psmouse)) { | ||
1357 | psmouse_err(psmouse, "Failed to enter absolute mode\n"); | 1311 | psmouse_err(psmouse, "Failed to enter absolute mode\n"); |
1358 | goto error; | 1312 | goto error; |
1359 | } | 1313 | } |
@@ -1390,14 +1344,6 @@ static int alps_hw_init_v3(struct psmouse *psmouse) | |||
1390 | if (alps_command_mode_write_reg(psmouse, 0x0162, 0x04)) | 1344 | if (alps_command_mode_write_reg(psmouse, 0x0162, 0x04)) |
1391 | goto error; | 1345 | goto error; |
1392 | 1346 | ||
1393 | /* | ||
1394 | * This ensures the trackstick packets are in the format | ||
1395 | * supported by this driver. If bit 1 isn't set the packet | ||
1396 | * format is different. | ||
1397 | */ | ||
1398 | if (alps_command_mode_write_reg(psmouse, 0x0008, 0x82)) | ||
1399 | goto error; | ||
1400 | |||
1401 | alps_exit_command_mode(psmouse); | 1347 | alps_exit_command_mode(psmouse); |
1402 | 1348 | ||
1403 | /* Set rate and enable data reporting */ | 1349 | /* Set rate and enable data reporting */ |
@@ -1410,10 +1356,6 @@ static int alps_hw_init_v3(struct psmouse *psmouse) | |||
1410 | 1356 | ||
1411 | return 0; | 1357 | return 0; |
1412 | 1358 | ||
1413 | error_passthrough: | ||
1414 | /* Something failed while in passthrough mode, so try to get out */ | ||
1415 | if (!alps_enter_command_mode(psmouse, NULL)) | ||
1416 | alps_passthrough_mode_v3(psmouse, false); | ||
1417 | error: | 1359 | error: |
1418 | /* | 1360 | /* |
1419 | * Leaving the touchpad in command mode will essentially render | 1361 | * Leaving the touchpad in command mode will essentially render |
@@ -1424,6 +1366,50 @@ error: | |||
1424 | return -1; | 1366 | return -1; |
1425 | } | 1367 | } |
1426 | 1368 | ||
1369 | static int alps_hw_init_rushmore_v3(struct psmouse *psmouse) | ||
1370 | { | ||
1371 | struct alps_data *priv = psmouse->private; | ||
1372 | struct ps2dev *ps2dev = &psmouse->ps2dev; | ||
1373 | int reg_val, ret = -1; | ||
1374 | |||
1375 | if (priv->flags & ALPS_DUALPOINT) { | ||
1376 | reg_val = alps_setup_trackstick_v3(psmouse, | ||
1377 | ALPS_REG_BASE_RUSHMORE); | ||
1378 | if (reg_val == -EIO) | ||
1379 | goto error; | ||
1380 | if (reg_val == -ENODEV) | ||
1381 | priv->flags &= ~ALPS_DUALPOINT; | ||
1382 | } | ||
1383 | |||
1384 | if (alps_enter_command_mode(psmouse, NULL) || | ||
1385 | alps_command_mode_read_reg(psmouse, 0xc2d9) == -1 || | ||
1386 | alps_command_mode_write_reg(psmouse, 0xc2cb, 0x00)) | ||
1387 | goto error; | ||
1388 | |||
1389 | reg_val = alps_command_mode_read_reg(psmouse, 0xc2c6); | ||
1390 | if (reg_val == -1) | ||
1391 | goto error; | ||
1392 | if (__alps_command_mode_write_reg(psmouse, reg_val & 0xfd)) | ||
1393 | goto error; | ||
1394 | |||
1395 | if (alps_command_mode_write_reg(psmouse, 0xc2c9, 0x64)) | ||
1396 | goto error; | ||
1397 | |||
1398 | /* enter absolute mode */ | ||
1399 | reg_val = alps_command_mode_read_reg(psmouse, 0xc2c4); | ||
1400 | if (reg_val == -1) | ||
1401 | goto error; | ||
1402 | if (__alps_command_mode_write_reg(psmouse, reg_val | 0x02)) | ||
1403 | goto error; | ||
1404 | |||
1405 | alps_exit_command_mode(psmouse); | ||
1406 | return ps2_command(ps2dev, NULL, PSMOUSE_CMD_ENABLE); | ||
1407 | |||
1408 | error: | ||
1409 | alps_exit_command_mode(psmouse); | ||
1410 | return ret; | ||
1411 | } | ||
1412 | |||
1427 | /* Must be in command mode when calling this function */ | 1413 | /* Must be in command mode when calling this function */ |
1428 | static int alps_absolute_mode_v4(struct psmouse *psmouse) | 1414 | static int alps_absolute_mode_v4(struct psmouse *psmouse) |
1429 | { | 1415 | { |
@@ -1442,13 +1428,9 @@ static int alps_absolute_mode_v4(struct psmouse *psmouse) | |||
1442 | 1428 | ||
1443 | static int alps_hw_init_v4(struct psmouse *psmouse) | 1429 | static int alps_hw_init_v4(struct psmouse *psmouse) |
1444 | { | 1430 | { |
1445 | struct alps_data *priv = psmouse->private; | ||
1446 | struct ps2dev *ps2dev = &psmouse->ps2dev; | 1431 | struct ps2dev *ps2dev = &psmouse->ps2dev; |
1447 | unsigned char param[4]; | 1432 | unsigned char param[4]; |
1448 | 1433 | ||
1449 | priv->nibble_commands = alps_v4_nibble_commands; | ||
1450 | priv->addr_command = PSMOUSE_CMD_DISABLE; | ||
1451 | |||
1452 | if (alps_enter_command_mode(psmouse, NULL)) | 1434 | if (alps_enter_command_mode(psmouse, NULL)) |
1453 | goto error; | 1435 | goto error; |
1454 | 1436 | ||
@@ -1517,39 +1499,140 @@ error: | |||
1517 | return -1; | 1499 | return -1; |
1518 | } | 1500 | } |
1519 | 1501 | ||
1520 | static int alps_hw_init(struct psmouse *psmouse) | 1502 | static void alps_set_defaults(struct alps_data *priv) |
1521 | { | 1503 | { |
1522 | struct alps_data *priv = psmouse->private; | 1504 | priv->byte0 = 0x8f; |
1523 | const struct alps_model_info *model = priv->i; | 1505 | priv->mask0 = 0x8f; |
1524 | int ret = -1; | 1506 | priv->flags = ALPS_DUALPOINT; |
1507 | |||
1508 | priv->x_max = 2000; | ||
1509 | priv->y_max = 1400; | ||
1510 | priv->x_bits = 15; | ||
1511 | priv->y_bits = 11; | ||
1525 | 1512 | ||
1526 | switch (model->proto_version) { | 1513 | switch (priv->proto_version) { |
1527 | case ALPS_PROTO_V1: | 1514 | case ALPS_PROTO_V1: |
1528 | case ALPS_PROTO_V2: | 1515 | case ALPS_PROTO_V2: |
1529 | ret = alps_hw_init_v1_v2(psmouse); | 1516 | priv->hw_init = alps_hw_init_v1_v2; |
1517 | priv->process_packet = alps_process_packet_v1_v2; | ||
1518 | priv->set_abs_params = alps_set_abs_params_st; | ||
1530 | break; | 1519 | break; |
1531 | case ALPS_PROTO_V3: | 1520 | case ALPS_PROTO_V3: |
1532 | ret = alps_hw_init_v3(psmouse); | 1521 | priv->hw_init = alps_hw_init_v3; |
1522 | priv->process_packet = alps_process_packet_v3; | ||
1523 | priv->set_abs_params = alps_set_abs_params_mt; | ||
1524 | priv->decode_fields = alps_decode_pinnacle; | ||
1525 | priv->nibble_commands = alps_v3_nibble_commands; | ||
1526 | priv->addr_command = PSMOUSE_CMD_RESET_WRAP; | ||
1533 | break; | 1527 | break; |
1534 | case ALPS_PROTO_V4: | 1528 | case ALPS_PROTO_V4: |
1535 | ret = alps_hw_init_v4(psmouse); | 1529 | priv->hw_init = alps_hw_init_v4; |
1530 | priv->process_packet = alps_process_packet_v4; | ||
1531 | priv->set_abs_params = alps_set_abs_params_mt; | ||
1532 | priv->nibble_commands = alps_v4_nibble_commands; | ||
1533 | priv->addr_command = PSMOUSE_CMD_DISABLE; | ||
1536 | break; | 1534 | break; |
1537 | } | 1535 | } |
1536 | } | ||
1538 | 1537 | ||
1539 | return ret; | 1538 | static int alps_match_table(struct psmouse *psmouse, struct alps_data *priv, |
1539 | unsigned char *e7, unsigned char *ec) | ||
1540 | { | ||
1541 | const struct alps_model_info *model; | ||
1542 | int i; | ||
1543 | |||
1544 | for (i = 0; i < ARRAY_SIZE(alps_model_data); i++) { | ||
1545 | model = &alps_model_data[i]; | ||
1546 | |||
1547 | if (!memcmp(e7, model->signature, sizeof(model->signature)) && | ||
1548 | (!model->command_mode_resp || | ||
1549 | model->command_mode_resp == ec[2])) { | ||
1550 | |||
1551 | priv->proto_version = model->proto_version; | ||
1552 | alps_set_defaults(priv); | ||
1553 | |||
1554 | priv->flags = model->flags; | ||
1555 | priv->byte0 = model->byte0; | ||
1556 | priv->mask0 = model->mask0; | ||
1557 | |||
1558 | return 0; | ||
1559 | } | ||
1560 | } | ||
1561 | |||
1562 | return -EINVAL; | ||
1563 | } | ||
1564 | |||
1565 | static int alps_identify(struct psmouse *psmouse, struct alps_data *priv) | ||
1566 | { | ||
1567 | unsigned char e6[4], e7[4], ec[4]; | ||
1568 | |||
1569 | /* | ||
1570 | * First try "E6 report". | ||
1571 | * ALPS should return 0,0,10 or 0,0,100 if no buttons are pressed. | ||
1572 | * The bits 0-2 of the first byte will be 1s if some buttons are | ||
1573 | * pressed. | ||
1574 | */ | ||
1575 | if (alps_rpt_cmd(psmouse, PSMOUSE_CMD_SETRES, | ||
1576 | PSMOUSE_CMD_SETSCALE11, e6)) | ||
1577 | return -EIO; | ||
1578 | |||
1579 | if ((e6[0] & 0xf8) != 0 || e6[1] != 0 || (e6[2] != 10 && e6[2] != 100)) | ||
1580 | return -EINVAL; | ||
1581 | |||
1582 | /* | ||
1583 | * Now get the "E7" and "EC" reports. These will uniquely identify | ||
1584 | * most ALPS touchpads. | ||
1585 | */ | ||
1586 | if (alps_rpt_cmd(psmouse, PSMOUSE_CMD_SETRES, | ||
1587 | PSMOUSE_CMD_SETSCALE21, e7) || | ||
1588 | alps_rpt_cmd(psmouse, PSMOUSE_CMD_SETRES, | ||
1589 | PSMOUSE_CMD_RESET_WRAP, ec) || | ||
1590 | alps_exit_command_mode(psmouse)) | ||
1591 | return -EIO; | ||
1592 | |||
1593 | if (alps_match_table(psmouse, priv, e7, ec) == 0) { | ||
1594 | return 0; | ||
1595 | } else if (ec[0] == 0x88 && ec[1] == 0x08) { | ||
1596 | priv->proto_version = ALPS_PROTO_V3; | ||
1597 | alps_set_defaults(priv); | ||
1598 | |||
1599 | priv->hw_init = alps_hw_init_rushmore_v3; | ||
1600 | priv->decode_fields = alps_decode_rushmore; | ||
1601 | priv->x_bits = 16; | ||
1602 | priv->y_bits = 12; | ||
1603 | |||
1604 | /* hack to make addr_command, nibble_command available */ | ||
1605 | psmouse->private = priv; | ||
1606 | |||
1607 | if (alps_probe_trackstick_v3(psmouse, ALPS_REG_BASE_RUSHMORE)) | ||
1608 | priv->flags &= ~ALPS_DUALPOINT; | ||
1609 | |||
1610 | return 0; | ||
1611 | } else if (ec[0] == 0x88 && ec[1] == 0x07 && | ||
1612 | ec[2] >= 0x90 && ec[2] <= 0x9d) { | ||
1613 | priv->proto_version = ALPS_PROTO_V3; | ||
1614 | alps_set_defaults(priv); | ||
1615 | |||
1616 | return 0; | ||
1617 | } | ||
1618 | |||
1619 | psmouse_info(psmouse, | ||
1620 | "Unknown ALPS touchpad: E7=%2.2x %2.2x %2.2x, EC=%2.2x %2.2x %2.2x\n", | ||
1621 | e7[0], e7[1], e7[2], ec[0], ec[1], ec[2]); | ||
1622 | |||
1623 | return -EINVAL; | ||
1540 | } | 1624 | } |
1541 | 1625 | ||
1542 | static int alps_reconnect(struct psmouse *psmouse) | 1626 | static int alps_reconnect(struct psmouse *psmouse) |
1543 | { | 1627 | { |
1544 | const struct alps_model_info *model; | 1628 | struct alps_data *priv = psmouse->private; |
1545 | 1629 | ||
1546 | psmouse_reset(psmouse); | 1630 | psmouse_reset(psmouse); |
1547 | 1631 | ||
1548 | model = alps_get_model(psmouse, NULL); | 1632 | if (alps_identify(psmouse, priv) < 0) |
1549 | if (!model) | ||
1550 | return -1; | 1633 | return -1; |
1551 | 1634 | ||
1552 | return alps_hw_init(psmouse); | 1635 | return priv->hw_init(psmouse); |
1553 | } | 1636 | } |
1554 | 1637 | ||
1555 | static void alps_disconnect(struct psmouse *psmouse) | 1638 | static void alps_disconnect(struct psmouse *psmouse) |
@@ -1562,12 +1645,33 @@ static void alps_disconnect(struct psmouse *psmouse) | |||
1562 | kfree(priv); | 1645 | kfree(priv); |
1563 | } | 1646 | } |
1564 | 1647 | ||
1648 | static void alps_set_abs_params_st(struct alps_data *priv, | ||
1649 | struct input_dev *dev1) | ||
1650 | { | ||
1651 | input_set_abs_params(dev1, ABS_X, 0, 1023, 0, 0); | ||
1652 | input_set_abs_params(dev1, ABS_Y, 0, 767, 0, 0); | ||
1653 | } | ||
1654 | |||
1655 | static void alps_set_abs_params_mt(struct alps_data *priv, | ||
1656 | struct input_dev *dev1) | ||
1657 | { | ||
1658 | set_bit(INPUT_PROP_SEMI_MT, dev1->propbit); | ||
1659 | input_mt_init_slots(dev1, 2, 0); | ||
1660 | input_set_abs_params(dev1, ABS_MT_POSITION_X, 0, priv->x_max, 0, 0); | ||
1661 | input_set_abs_params(dev1, ABS_MT_POSITION_Y, 0, priv->y_max, 0, 0); | ||
1662 | |||
1663 | set_bit(BTN_TOOL_DOUBLETAP, dev1->keybit); | ||
1664 | set_bit(BTN_TOOL_TRIPLETAP, dev1->keybit); | ||
1665 | set_bit(BTN_TOOL_QUADTAP, dev1->keybit); | ||
1666 | |||
1667 | input_set_abs_params(dev1, ABS_X, 0, priv->x_max, 0, 0); | ||
1668 | input_set_abs_params(dev1, ABS_Y, 0, priv->y_max, 0, 0); | ||
1669 | } | ||
1670 | |||
1565 | int alps_init(struct psmouse *psmouse) | 1671 | int alps_init(struct psmouse *psmouse) |
1566 | { | 1672 | { |
1567 | struct alps_data *priv; | 1673 | struct alps_data *priv; |
1568 | const struct alps_model_info *model; | ||
1569 | struct input_dev *dev1 = psmouse->dev, *dev2; | 1674 | struct input_dev *dev1 = psmouse->dev, *dev2; |
1570 | int version; | ||
1571 | 1675 | ||
1572 | priv = kzalloc(sizeof(struct alps_data), GFP_KERNEL); | 1676 | priv = kzalloc(sizeof(struct alps_data), GFP_KERNEL); |
1573 | dev2 = input_allocate_device(); | 1677 | dev2 = input_allocate_device(); |
@@ -1581,13 +1685,10 @@ int alps_init(struct psmouse *psmouse) | |||
1581 | 1685 | ||
1582 | psmouse_reset(psmouse); | 1686 | psmouse_reset(psmouse); |
1583 | 1687 | ||
1584 | model = alps_get_model(psmouse, &version); | 1688 | if (alps_identify(psmouse, priv) < 0) |
1585 | if (!model) | ||
1586 | goto init_fail; | 1689 | goto init_fail; |
1587 | 1690 | ||
1588 | priv->i = model; | 1691 | if (priv->hw_init(psmouse)) |
1589 | |||
1590 | if (alps_hw_init(psmouse)) | ||
1591 | goto init_fail; | 1692 | goto init_fail; |
1592 | 1693 | ||
1593 | /* | 1694 | /* |
@@ -1609,41 +1710,20 @@ int alps_init(struct psmouse *psmouse) | |||
1609 | 1710 | ||
1610 | dev1->evbit[BIT_WORD(EV_ABS)] |= BIT_MASK(EV_ABS); | 1711 | dev1->evbit[BIT_WORD(EV_ABS)] |= BIT_MASK(EV_ABS); |
1611 | 1712 | ||
1612 | switch (model->proto_version) { | 1713 | priv->set_abs_params(priv, dev1); |
1613 | case ALPS_PROTO_V1: | ||
1614 | case ALPS_PROTO_V2: | ||
1615 | input_set_abs_params(dev1, ABS_X, 0, 1023, 0, 0); | ||
1616 | input_set_abs_params(dev1, ABS_Y, 0, 767, 0, 0); | ||
1617 | break; | ||
1618 | case ALPS_PROTO_V3: | ||
1619 | case ALPS_PROTO_V4: | ||
1620 | set_bit(INPUT_PROP_SEMI_MT, dev1->propbit); | ||
1621 | input_mt_init_slots(dev1, 2, 0); | ||
1622 | input_set_abs_params(dev1, ABS_MT_POSITION_X, 0, ALPS_V3_X_MAX, 0, 0); | ||
1623 | input_set_abs_params(dev1, ABS_MT_POSITION_Y, 0, ALPS_V3_Y_MAX, 0, 0); | ||
1624 | |||
1625 | set_bit(BTN_TOOL_DOUBLETAP, dev1->keybit); | ||
1626 | set_bit(BTN_TOOL_TRIPLETAP, dev1->keybit); | ||
1627 | set_bit(BTN_TOOL_QUADTAP, dev1->keybit); | ||
1628 | |||
1629 | input_set_abs_params(dev1, ABS_X, 0, ALPS_V3_X_MAX, 0, 0); | ||
1630 | input_set_abs_params(dev1, ABS_Y, 0, ALPS_V3_Y_MAX, 0, 0); | ||
1631 | break; | ||
1632 | } | ||
1633 | |||
1634 | input_set_abs_params(dev1, ABS_PRESSURE, 0, 127, 0, 0); | 1714 | input_set_abs_params(dev1, ABS_PRESSURE, 0, 127, 0, 0); |
1635 | 1715 | ||
1636 | if (model->flags & ALPS_WHEEL) { | 1716 | if (priv->flags & ALPS_WHEEL) { |
1637 | dev1->evbit[BIT_WORD(EV_REL)] |= BIT_MASK(EV_REL); | 1717 | dev1->evbit[BIT_WORD(EV_REL)] |= BIT_MASK(EV_REL); |
1638 | dev1->relbit[BIT_WORD(REL_WHEEL)] |= BIT_MASK(REL_WHEEL); | 1718 | dev1->relbit[BIT_WORD(REL_WHEEL)] |= BIT_MASK(REL_WHEEL); |
1639 | } | 1719 | } |
1640 | 1720 | ||
1641 | if (model->flags & (ALPS_FW_BK_1 | ALPS_FW_BK_2)) { | 1721 | if (priv->flags & (ALPS_FW_BK_1 | ALPS_FW_BK_2)) { |
1642 | dev1->keybit[BIT_WORD(BTN_FORWARD)] |= BIT_MASK(BTN_FORWARD); | 1722 | dev1->keybit[BIT_WORD(BTN_FORWARD)] |= BIT_MASK(BTN_FORWARD); |
1643 | dev1->keybit[BIT_WORD(BTN_BACK)] |= BIT_MASK(BTN_BACK); | 1723 | dev1->keybit[BIT_WORD(BTN_BACK)] |= BIT_MASK(BTN_BACK); |
1644 | } | 1724 | } |
1645 | 1725 | ||
1646 | if (model->flags & ALPS_FOUR_BUTTONS) { | 1726 | if (priv->flags & ALPS_FOUR_BUTTONS) { |
1647 | dev1->keybit[BIT_WORD(BTN_0)] |= BIT_MASK(BTN_0); | 1727 | dev1->keybit[BIT_WORD(BTN_0)] |= BIT_MASK(BTN_0); |
1648 | dev1->keybit[BIT_WORD(BTN_1)] |= BIT_MASK(BTN_1); | 1728 | dev1->keybit[BIT_WORD(BTN_1)] |= BIT_MASK(BTN_1); |
1649 | dev1->keybit[BIT_WORD(BTN_2)] |= BIT_MASK(BTN_2); | 1729 | dev1->keybit[BIT_WORD(BTN_2)] |= BIT_MASK(BTN_2); |
@@ -1654,7 +1734,8 @@ int alps_init(struct psmouse *psmouse) | |||
1654 | 1734 | ||
1655 | snprintf(priv->phys, sizeof(priv->phys), "%s/input1", psmouse->ps2dev.serio->phys); | 1735 | snprintf(priv->phys, sizeof(priv->phys), "%s/input1", psmouse->ps2dev.serio->phys); |
1656 | dev2->phys = priv->phys; | 1736 | dev2->phys = priv->phys; |
1657 | dev2->name = (model->flags & ALPS_DUALPOINT) ? "DualPoint Stick" : "PS/2 Mouse"; | 1737 | dev2->name = (priv->flags & ALPS_DUALPOINT) ? |
1738 | "DualPoint Stick" : "PS/2 Mouse"; | ||
1658 | dev2->id.bustype = BUS_I8042; | 1739 | dev2->id.bustype = BUS_I8042; |
1659 | dev2->id.vendor = 0x0002; | 1740 | dev2->id.vendor = 0x0002; |
1660 | dev2->id.product = PSMOUSE_ALPS; | 1741 | dev2->id.product = PSMOUSE_ALPS; |
@@ -1673,7 +1754,7 @@ int alps_init(struct psmouse *psmouse) | |||
1673 | psmouse->poll = alps_poll; | 1754 | psmouse->poll = alps_poll; |
1674 | psmouse->disconnect = alps_disconnect; | 1755 | psmouse->disconnect = alps_disconnect; |
1675 | psmouse->reconnect = alps_reconnect; | 1756 | psmouse->reconnect = alps_reconnect; |
1676 | psmouse->pktsize = model->proto_version == ALPS_PROTO_V4 ? 8 : 6; | 1757 | psmouse->pktsize = priv->proto_version == ALPS_PROTO_V4 ? 8 : 6; |
1677 | 1758 | ||
1678 | /* We are having trouble resyncing ALPS touchpads so disable it for now */ | 1759 | /* We are having trouble resyncing ALPS touchpads so disable it for now */ |
1679 | psmouse->resync_time = 0; | 1760 | psmouse->resync_time = 0; |
@@ -1690,18 +1771,16 @@ init_fail: | |||
1690 | 1771 | ||
1691 | int alps_detect(struct psmouse *psmouse, bool set_properties) | 1772 | int alps_detect(struct psmouse *psmouse, bool set_properties) |
1692 | { | 1773 | { |
1693 | int version; | 1774 | struct alps_data dummy; |
1694 | const struct alps_model_info *model; | ||
1695 | 1775 | ||
1696 | model = alps_get_model(psmouse, &version); | 1776 | if (alps_identify(psmouse, &dummy) < 0) |
1697 | if (!model) | ||
1698 | return -1; | 1777 | return -1; |
1699 | 1778 | ||
1700 | if (set_properties) { | 1779 | if (set_properties) { |
1701 | psmouse->vendor = "ALPS"; | 1780 | psmouse->vendor = "ALPS"; |
1702 | psmouse->name = model->flags & ALPS_DUALPOINT ? | 1781 | psmouse->name = dummy.flags & ALPS_DUALPOINT ? |
1703 | "DualPoint TouchPad" : "GlidePoint"; | 1782 | "DualPoint TouchPad" : "GlidePoint"; |
1704 | psmouse->model = version; | 1783 | psmouse->model = dummy.proto_version << 8; |
1705 | } | 1784 | } |
1706 | return 0; | 1785 | return 0; |
1707 | } | 1786 | } |
diff --git a/drivers/input/mouse/alps.h b/drivers/input/mouse/alps.h index ae1ac354c778..970480551b6e 100644 --- a/drivers/input/mouse/alps.h +++ b/drivers/input/mouse/alps.h | |||
@@ -12,35 +12,146 @@ | |||
12 | #ifndef _ALPS_H | 12 | #ifndef _ALPS_H |
13 | #define _ALPS_H | 13 | #define _ALPS_H |
14 | 14 | ||
15 | #define ALPS_PROTO_V1 0 | 15 | #define ALPS_PROTO_V1 1 |
16 | #define ALPS_PROTO_V2 1 | 16 | #define ALPS_PROTO_V2 2 |
17 | #define ALPS_PROTO_V3 2 | 17 | #define ALPS_PROTO_V3 3 |
18 | #define ALPS_PROTO_V4 3 | 18 | #define ALPS_PROTO_V4 4 |
19 | 19 | ||
20 | /** | ||
21 | * struct alps_model_info - touchpad ID table | ||
22 | * @signature: E7 response string to match. | ||
23 | * @command_mode_resp: For V3/V4 touchpads, the final byte of the EC response | ||
24 | * (aka command mode response) identifies the firmware minor version. This | ||
25 | * can be used to distinguish different hardware models which are not | ||
26 | * uniquely identifiable through their E7 responses. | ||
27 | * @proto_version: Indicates V1/V2/V3/... | ||
28 | * @byte0: Helps figure out whether a position report packet matches the | ||
29 | * known format for this model. The first byte of the report, ANDed with | ||
30 | * mask0, should match byte0. | ||
31 | * @mask0: The mask used to check the first byte of the report. | ||
32 | * @flags: Additional device capabilities (passthrough port, trackstick, etc.). | ||
33 | * | ||
34 | * Many (but not all) ALPS touchpads can be identified by looking at the | ||
35 | * values returned in the "E7 report" and/or the "EC report." This table | ||
36 | * lists a number of such touchpads. | ||
37 | */ | ||
20 | struct alps_model_info { | 38 | struct alps_model_info { |
21 | unsigned char signature[3]; | 39 | unsigned char signature[3]; |
22 | unsigned char command_mode_resp; /* v3/v4 only */ | 40 | unsigned char command_mode_resp; |
23 | unsigned char proto_version; | 41 | unsigned char proto_version; |
24 | unsigned char byte0, mask0; | 42 | unsigned char byte0, mask0; |
25 | unsigned char flags; | 43 | unsigned char flags; |
26 | }; | 44 | }; |
27 | 45 | ||
46 | /** | ||
47 | * struct alps_nibble_commands - encodings for register accesses | ||
48 | * @command: PS/2 command used for the nibble | ||
49 | * @data: Data supplied as an argument to the PS/2 command, if applicable | ||
50 | * | ||
51 | * The ALPS protocol uses magic sequences to transmit binary data to the | ||
52 | * touchpad, as it is generally not OK to send arbitrary bytes out the | ||
53 | * PS/2 port. Each of the sequences in this table sends one nibble of the | ||
54 | * register address or (write) data. Different versions of the ALPS protocol | ||
55 | * use slightly different encodings. | ||
56 | */ | ||
28 | struct alps_nibble_commands { | 57 | struct alps_nibble_commands { |
29 | int command; | 58 | int command; |
30 | unsigned char data; | 59 | unsigned char data; |
31 | }; | 60 | }; |
32 | 61 | ||
62 | /** | ||
63 | * struct alps_fields - decoded version of the report packet | ||
64 | * @x_map: Bitmap of active X positions for MT. | ||
65 | * @y_map: Bitmap of active Y positions for MT. | ||
66 | * @fingers: Number of fingers for MT. | ||
67 | * @x: X position for ST. | ||
68 | * @y: Y position for ST. | ||
69 | * @z: Z position for ST. | ||
70 | * @first_mp: Packet is the first of a multi-packet report. | ||
71 | * @is_mp: Packet is part of a multi-packet report. | ||
72 | * @left: Left touchpad button is active. | ||
73 | * @right: Right touchpad button is active. | ||
74 | * @middle: Middle touchpad button is active. | ||
75 | * @ts_left: Left trackstick button is active. | ||
76 | * @ts_right: Right trackstick button is active. | ||
77 | * @ts_middle: Middle trackstick button is active. | ||
78 | */ | ||
79 | struct alps_fields { | ||
80 | unsigned int x_map; | ||
81 | unsigned int y_map; | ||
82 | unsigned int fingers; | ||
83 | unsigned int x; | ||
84 | unsigned int y; | ||
85 | unsigned int z; | ||
86 | unsigned int first_mp:1; | ||
87 | unsigned int is_mp:1; | ||
88 | |||
89 | unsigned int left:1; | ||
90 | unsigned int right:1; | ||
91 | unsigned int middle:1; | ||
92 | |||
93 | unsigned int ts_left:1; | ||
94 | unsigned int ts_right:1; | ||
95 | unsigned int ts_middle:1; | ||
96 | }; | ||
97 | |||
98 | /** | ||
99 | * struct alps_data - private data structure for the ALPS driver | ||
100 | * @dev2: "Relative" device used to report trackstick or mouse activity. | ||
101 | * @phys: Physical path for the relative device. | ||
102 | * @nibble_commands: Command mapping used for touchpad register accesses. | ||
103 | * @addr_command: Command used to tell the touchpad that a register address | ||
104 | * follows. | ||
105 | * @proto_version: Indicates V1/V2/V3/... | ||
106 | * @byte0: Helps figure out whether a position report packet matches the | ||
107 | * known format for this model. The first byte of the report, ANDed with | ||
108 | * mask0, should match byte0. | ||
109 | * @mask0: The mask used to check the first byte of the report. | ||
110 | * @flags: Additional device capabilities (passthrough port, trackstick, etc.). | ||
111 | * @x_max: Largest possible X position value. | ||
112 | * @y_max: Largest possible Y position value. | ||
113 | * @x_bits: Number of X bits in the MT bitmap. | ||
114 | * @y_bits: Number of Y bits in the MT bitmap. | ||
115 | * @hw_init: Protocol-specific hardware init function. | ||
116 | * @process_packet: Protocol-specific function to process a report packet. | ||
117 | * @decode_fields: Protocol-specific function to read packet bitfields. | ||
118 | * @set_abs_params: Protocol-specific function to configure the input_dev. | ||
119 | * @prev_fin: Finger bit from previous packet. | ||
120 | * @multi_packet: Multi-packet data in progress. | ||
121 | * @multi_data: Saved multi-packet data. | ||
122 | * @x1: First X coordinate from last MT report. | ||
123 | * @x2: Second X coordinate from last MT report. | ||
124 | * @y1: First Y coordinate from last MT report. | ||
125 | * @y2: Second Y coordinate from last MT report. | ||
126 | * @fingers: Number of fingers from last MT report. | ||
127 | * @quirks: Bitmap of ALPS_QUIRK_*. | ||
128 | * @timer: Timer for flushing out the final report packet in the stream. | ||
129 | */ | ||
33 | struct alps_data { | 130 | struct alps_data { |
34 | struct input_dev *dev2; /* Relative device */ | 131 | struct input_dev *dev2; |
35 | char phys[32]; /* Phys */ | 132 | char phys[32]; |
36 | const struct alps_model_info *i;/* Info */ | 133 | |
134 | /* these are autodetected when the device is identified */ | ||
37 | const struct alps_nibble_commands *nibble_commands; | 135 | const struct alps_nibble_commands *nibble_commands; |
38 | int addr_command; /* Command to set register address */ | 136 | int addr_command; |
39 | int prev_fin; /* Finger bit from previous packet */ | 137 | unsigned char proto_version; |
40 | int multi_packet; /* Multi-packet data in progress */ | 138 | unsigned char byte0, mask0; |
41 | unsigned char multi_data[6]; /* Saved multi-packet data */ | 139 | unsigned char flags; |
42 | int x1, x2, y1, y2; /* Coordinates from last MT report */ | 140 | int x_max; |
43 | int fingers; /* Number of fingers from MT report */ | 141 | int y_max; |
142 | int x_bits; | ||
143 | int y_bits; | ||
144 | |||
145 | int (*hw_init)(struct psmouse *psmouse); | ||
146 | void (*process_packet)(struct psmouse *psmouse); | ||
147 | void (*decode_fields)(struct alps_fields *f, unsigned char *p); | ||
148 | void (*set_abs_params)(struct alps_data *priv, struct input_dev *dev1); | ||
149 | |||
150 | int prev_fin; | ||
151 | int multi_packet; | ||
152 | unsigned char multi_data[6]; | ||
153 | int x1, x2, y1, y2; | ||
154 | int fingers; | ||
44 | u8 quirks; | 155 | u8 quirks; |
45 | struct timer_list timer; | 156 | struct timer_list timer; |
46 | }; | 157 | }; |
diff --git a/drivers/input/mouse/cyapa.c b/drivers/input/mouse/cyapa.c new file mode 100644 index 000000000000..b409c3d7d4fb --- /dev/null +++ b/drivers/input/mouse/cyapa.c | |||
@@ -0,0 +1,973 @@ | |||
1 | /* | ||
2 | * Cypress APA trackpad with I2C interface | ||
3 | * | ||
4 | * Author: Dudley Du <dudl@cypress.com> | ||
5 | * Further cleanup and restructuring by: | ||
6 | * Daniel Kurtz <djkurtz@chromium.org> | ||
7 | * Benson Leung <bleung@chromium.org> | ||
8 | * | ||
9 | * Copyright (C) 2011-2012 Cypress Semiconductor, Inc. | ||
10 | * Copyright (C) 2011-2012 Google, Inc. | ||
11 | * | ||
12 | * This file is subject to the terms and conditions of the GNU General Public | ||
13 | * License. See the file COPYING in the main directory of this archive for | ||
14 | * more details. | ||
15 | */ | ||
16 | |||
17 | #include <linux/delay.h> | ||
18 | #include <linux/i2c.h> | ||
19 | #include <linux/input.h> | ||
20 | #include <linux/input/mt.h> | ||
21 | #include <linux/interrupt.h> | ||
22 | #include <linux/module.h> | ||
23 | #include <linux/slab.h> | ||
24 | |||
25 | /* APA trackpad firmware generation */ | ||
26 | #define CYAPA_GEN3 0x03 /* support MT-protocol B with tracking ID. */ | ||
27 | |||
28 | #define CYAPA_NAME "Cypress APA Trackpad (cyapa)" | ||
29 | |||
30 | /* commands for read/write registers of Cypress trackpad */ | ||
31 | #define CYAPA_CMD_SOFT_RESET 0x00 | ||
32 | #define CYAPA_CMD_POWER_MODE 0x01 | ||
33 | #define CYAPA_CMD_DEV_STATUS 0x02 | ||
34 | #define CYAPA_CMD_GROUP_DATA 0x03 | ||
35 | #define CYAPA_CMD_GROUP_CMD 0x04 | ||
36 | #define CYAPA_CMD_GROUP_QUERY 0x05 | ||
37 | #define CYAPA_CMD_BL_STATUS 0x06 | ||
38 | #define CYAPA_CMD_BL_HEAD 0x07 | ||
39 | #define CYAPA_CMD_BL_CMD 0x08 | ||
40 | #define CYAPA_CMD_BL_DATA 0x09 | ||
41 | #define CYAPA_CMD_BL_ALL 0x0a | ||
42 | #define CYAPA_CMD_BLK_PRODUCT_ID 0x0b | ||
43 | #define CYAPA_CMD_BLK_HEAD 0x0c | ||
44 | |||
45 | /* report data start reg offset address. */ | ||
46 | #define DATA_REG_START_OFFSET 0x0000 | ||
47 | |||
48 | #define BL_HEAD_OFFSET 0x00 | ||
49 | #define BL_DATA_OFFSET 0x10 | ||
50 | |||
51 | /* | ||
52 | * Operational Device Status Register | ||
53 | * | ||
54 | * bit 7: Valid interrupt source | ||
55 | * bit 6 - 4: Reserved | ||
56 | * bit 3 - 2: Power status | ||
57 | * bit 1 - 0: Device status | ||
58 | */ | ||
59 | #define REG_OP_STATUS 0x00 | ||
60 | #define OP_STATUS_SRC 0x80 | ||
61 | #define OP_STATUS_POWER 0x0c | ||
62 | #define OP_STATUS_DEV 0x03 | ||
63 | #define OP_STATUS_MASK (OP_STATUS_SRC | OP_STATUS_POWER | OP_STATUS_DEV) | ||
64 | |||
65 | /* | ||
66 | * Operational Finger Count/Button Flags Register | ||
67 | * | ||
68 | * bit 7 - 4: Number of touched finger | ||
69 | * bit 3: Valid data | ||
70 | * bit 2: Middle Physical Button | ||
71 | * bit 1: Right Physical Button | ||
72 | * bit 0: Left physical Button | ||
73 | */ | ||
74 | #define REG_OP_DATA1 0x01 | ||
75 | #define OP_DATA_VALID 0x08 | ||
76 | #define OP_DATA_MIDDLE_BTN 0x04 | ||
77 | #define OP_DATA_RIGHT_BTN 0x02 | ||
78 | #define OP_DATA_LEFT_BTN 0x01 | ||
79 | #define OP_DATA_BTN_MASK (OP_DATA_MIDDLE_BTN | OP_DATA_RIGHT_BTN | \ | ||
80 | OP_DATA_LEFT_BTN) | ||
81 | |||
82 | /* | ||
83 | * Bootloader Status Register | ||
84 | * | ||
85 | * bit 7: Busy | ||
86 | * bit 6 - 5: Reserved | ||
87 | * bit 4: Bootloader running | ||
88 | * bit 3 - 1: Reserved | ||
89 | * bit 0: Checksum valid | ||
90 | */ | ||
91 | #define REG_BL_STATUS 0x01 | ||
92 | #define BL_STATUS_BUSY 0x80 | ||
93 | #define BL_STATUS_RUNNING 0x10 | ||
94 | #define BL_STATUS_DATA_VALID 0x08 | ||
95 | #define BL_STATUS_CSUM_VALID 0x01 | ||
96 | |||
97 | /* | ||
98 | * Bootloader Error Register | ||
99 | * | ||
100 | * bit 7: Invalid | ||
101 | * bit 6: Invalid security key | ||
102 | * bit 5: Bootloading | ||
103 | * bit 4: Command checksum | ||
104 | * bit 3: Flash protection error | ||
105 | * bit 2: Flash checksum error | ||
106 | * bit 1 - 0: Reserved | ||
107 | */ | ||
108 | #define REG_BL_ERROR 0x02 | ||
109 | #define BL_ERROR_INVALID 0x80 | ||
110 | #define BL_ERROR_INVALID_KEY 0x40 | ||
111 | #define BL_ERROR_BOOTLOADING 0x20 | ||
112 | #define BL_ERROR_CMD_CSUM 0x10 | ||
113 | #define BL_ERROR_FLASH_PROT 0x08 | ||
114 | #define BL_ERROR_FLASH_CSUM 0x04 | ||
115 | |||
116 | #define BL_STATUS_SIZE 3 /* length of bootloader status registers */ | ||
117 | #define BLK_HEAD_BYTES 32 | ||
118 | |||
119 | #define PRODUCT_ID_SIZE 16 | ||
120 | #define QUERY_DATA_SIZE 27 | ||
121 | #define REG_PROTOCOL_GEN_QUERY_OFFSET 20 | ||
122 | |||
123 | #define REG_OFFSET_DATA_BASE 0x0000 | ||
124 | #define REG_OFFSET_COMMAND_BASE 0x0028 | ||
125 | #define REG_OFFSET_QUERY_BASE 0x002a | ||
126 | |||
127 | #define CAPABILITY_LEFT_BTN_MASK (0x01 << 3) | ||
128 | #define CAPABILITY_RIGHT_BTN_MASK (0x01 << 4) | ||
129 | #define CAPABILITY_MIDDLE_BTN_MASK (0x01 << 5) | ||
130 | #define CAPABILITY_BTN_MASK (CAPABILITY_LEFT_BTN_MASK | \ | ||
131 | CAPABILITY_RIGHT_BTN_MASK | \ | ||
132 | CAPABILITY_MIDDLE_BTN_MASK) | ||
133 | |||
134 | #define CYAPA_OFFSET_SOFT_RESET REG_OFFSET_COMMAND_BASE | ||
135 | |||
136 | #define REG_OFFSET_POWER_MODE (REG_OFFSET_COMMAND_BASE + 1) | ||
137 | |||
138 | #define PWR_MODE_MASK 0xfc | ||
139 | #define PWR_MODE_FULL_ACTIVE (0x3f << 2) | ||
140 | #define PWR_MODE_IDLE (0x05 << 2) /* default sleep time is 50 ms. */ | ||
141 | #define PWR_MODE_OFF (0x00 << 2) | ||
142 | |||
143 | #define PWR_STATUS_MASK 0x0c | ||
144 | #define PWR_STATUS_ACTIVE (0x03 << 2) | ||
145 | #define PWR_STATUS_IDLE (0x02 << 2) | ||
146 | #define PWR_STATUS_OFF (0x00 << 2) | ||
147 | |||
148 | /* | ||
149 | * CYAPA trackpad device states. | ||
150 | * Used in register 0x00, bit1-0, DeviceStatus field. | ||
151 | * Other values indicate device is in an abnormal state and must be reset. | ||
152 | */ | ||
153 | #define CYAPA_DEV_NORMAL 0x03 | ||
154 | #define CYAPA_DEV_BUSY 0x01 | ||
155 | |||
156 | enum cyapa_state { | ||
157 | CYAPA_STATE_OP, | ||
158 | CYAPA_STATE_BL_IDLE, | ||
159 | CYAPA_STATE_BL_ACTIVE, | ||
160 | CYAPA_STATE_BL_BUSY, | ||
161 | CYAPA_STATE_NO_DEVICE, | ||
162 | }; | ||
163 | |||
164 | |||
165 | struct cyapa_touch { | ||
166 | /* | ||
167 | * high bits or x/y position value | ||
168 | * bit 7 - 4: high 4 bits of x position value | ||
169 | * bit 3 - 0: high 4 bits of y position value | ||
170 | */ | ||
171 | u8 xy_hi; | ||
172 | u8 x_lo; /* low 8 bits of x position value. */ | ||
173 | u8 y_lo; /* low 8 bits of y position value. */ | ||
174 | u8 pressure; | ||
175 | /* id range is 1 - 15. It is incremented with every new touch. */ | ||
176 | u8 id; | ||
177 | } __packed; | ||
178 | |||
179 | /* The touch.id is used as the MT slot id, thus max MT slot is 15 */ | ||
180 | #define CYAPA_MAX_MT_SLOTS 15 | ||
181 | |||
182 | struct cyapa_reg_data { | ||
183 | /* | ||
184 | * bit 0 - 1: device status | ||
185 | * bit 3 - 2: power mode | ||
186 | * bit 6 - 4: reserved | ||
187 | * bit 7: interrupt valid bit | ||
188 | */ | ||
189 | u8 device_status; | ||
190 | /* | ||
191 | * bit 7 - 4: number of fingers currently touching pad | ||
192 | * bit 3: valid data check bit | ||
193 | * bit 2: middle mechanism button state if exists | ||
194 | * bit 1: right mechanism button state if exists | ||
195 | * bit 0: left mechanism button state if exists | ||
196 | */ | ||
197 | u8 finger_btn; | ||
198 | /* CYAPA reports up to 5 touches per packet. */ | ||
199 | struct cyapa_touch touches[5]; | ||
200 | } __packed; | ||
201 | |||
202 | /* The main device structure */ | ||
203 | struct cyapa { | ||
204 | enum cyapa_state state; | ||
205 | |||
206 | struct i2c_client *client; | ||
207 | struct input_dev *input; | ||
208 | char phys[32]; /* device physical location */ | ||
209 | int irq; | ||
210 | bool irq_wake; /* irq wake is enabled */ | ||
211 | bool smbus; | ||
212 | |||
213 | /* read from query data region. */ | ||
214 | char product_id[16]; | ||
215 | u8 btn_capability; | ||
216 | u8 gen; | ||
217 | int max_abs_x; | ||
218 | int max_abs_y; | ||
219 | int physical_size_x; | ||
220 | int physical_size_y; | ||
221 | }; | ||
222 | |||
223 | static const u8 bl_deactivate[] = { 0x00, 0xff, 0x3b, 0x00, 0x01, 0x02, 0x03, | ||
224 | 0x04, 0x05, 0x06, 0x07 }; | ||
225 | static const u8 bl_exit[] = { 0x00, 0xff, 0xa5, 0x00, 0x01, 0x02, 0x03, 0x04, | ||
226 | 0x05, 0x06, 0x07 }; | ||
227 | |||
228 | struct cyapa_cmd_len { | ||
229 | u8 cmd; | ||
230 | u8 len; | ||
231 | }; | ||
232 | |||
233 | #define CYAPA_ADAPTER_FUNC_NONE 0 | ||
234 | #define CYAPA_ADAPTER_FUNC_I2C 1 | ||
235 | #define CYAPA_ADAPTER_FUNC_SMBUS 2 | ||
236 | #define CYAPA_ADAPTER_FUNC_BOTH 3 | ||
237 | |||
238 | /* | ||
239 | * macros for SMBus communication | ||
240 | */ | ||
241 | #define SMBUS_READ 0x01 | ||
242 | #define SMBUS_WRITE 0x00 | ||
243 | #define SMBUS_ENCODE_IDX(cmd, idx) ((cmd) | (((idx) & 0x03) << 1)) | ||
244 | #define SMBUS_ENCODE_RW(cmd, rw) ((cmd) | ((rw) & 0x01)) | ||
245 | #define SMBUS_BYTE_BLOCK_CMD_MASK 0x80 | ||
246 | #define SMBUS_GROUP_BLOCK_CMD_MASK 0x40 | ||
247 | |||
248 | /* for byte read/write command */ | ||
249 | #define CMD_RESET 0 | ||
250 | #define CMD_POWER_MODE 1 | ||
251 | #define CMD_DEV_STATUS 2 | ||
252 | #define SMBUS_BYTE_CMD(cmd) (((cmd) & 0x3f) << 1) | ||
253 | #define CYAPA_SMBUS_RESET SMBUS_BYTE_CMD(CMD_RESET) | ||
254 | #define CYAPA_SMBUS_POWER_MODE SMBUS_BYTE_CMD(CMD_POWER_MODE) | ||
255 | #define CYAPA_SMBUS_DEV_STATUS SMBUS_BYTE_CMD(CMD_DEV_STATUS) | ||
256 | |||
257 | /* for group registers read/write command */ | ||
258 | #define REG_GROUP_DATA 0 | ||
259 | #define REG_GROUP_CMD 2 | ||
260 | #define REG_GROUP_QUERY 3 | ||
261 | #define SMBUS_GROUP_CMD(grp) (0x80 | (((grp) & 0x07) << 3)) | ||
262 | #define CYAPA_SMBUS_GROUP_DATA SMBUS_GROUP_CMD(REG_GROUP_DATA) | ||
263 | #define CYAPA_SMBUS_GROUP_CMD SMBUS_GROUP_CMD(REG_GROUP_CMD) | ||
264 | #define CYAPA_SMBUS_GROUP_QUERY SMBUS_GROUP_CMD(REG_GROUP_QUERY) | ||
265 | |||
266 | /* for register block read/write command */ | ||
267 | #define CMD_BL_STATUS 0 | ||
268 | #define CMD_BL_HEAD 1 | ||
269 | #define CMD_BL_CMD 2 | ||
270 | #define CMD_BL_DATA 3 | ||
271 | #define CMD_BL_ALL 4 | ||
272 | #define CMD_BLK_PRODUCT_ID 5 | ||
273 | #define CMD_BLK_HEAD 6 | ||
274 | #define SMBUS_BLOCK_CMD(cmd) (0xc0 | (((cmd) & 0x1f) << 1)) | ||
275 | |||
276 | /* register block read/write command in bootloader mode */ | ||
277 | #define CYAPA_SMBUS_BL_STATUS SMBUS_BLOCK_CMD(CMD_BL_STATUS) | ||
278 | #define CYAPA_SMBUS_BL_HEAD SMBUS_BLOCK_CMD(CMD_BL_HEAD) | ||
279 | #define CYAPA_SMBUS_BL_CMD SMBUS_BLOCK_CMD(CMD_BL_CMD) | ||
280 | #define CYAPA_SMBUS_BL_DATA SMBUS_BLOCK_CMD(CMD_BL_DATA) | ||
281 | #define CYAPA_SMBUS_BL_ALL SMBUS_BLOCK_CMD(CMD_BL_ALL) | ||
282 | |||
283 | /* register block read/write command in operational mode */ | ||
284 | #define CYAPA_SMBUS_BLK_PRODUCT_ID SMBUS_BLOCK_CMD(CMD_BLK_PRODUCT_ID) | ||
285 | #define CYAPA_SMBUS_BLK_HEAD SMBUS_BLOCK_CMD(CMD_BLK_HEAD) | ||
286 | |||
287 | static const struct cyapa_cmd_len cyapa_i2c_cmds[] = { | ||
288 | { CYAPA_OFFSET_SOFT_RESET, 1 }, | ||
289 | { REG_OFFSET_COMMAND_BASE + 1, 1 }, | ||
290 | { REG_OFFSET_DATA_BASE, 1 }, | ||
291 | { REG_OFFSET_DATA_BASE, sizeof(struct cyapa_reg_data) }, | ||
292 | { REG_OFFSET_COMMAND_BASE, 0 }, | ||
293 | { REG_OFFSET_QUERY_BASE, QUERY_DATA_SIZE }, | ||
294 | { BL_HEAD_OFFSET, 3 }, | ||
295 | { BL_HEAD_OFFSET, 16 }, | ||
296 | { BL_HEAD_OFFSET, 16 }, | ||
297 | { BL_DATA_OFFSET, 16 }, | ||
298 | { BL_HEAD_OFFSET, 32 }, | ||
299 | { REG_OFFSET_QUERY_BASE, PRODUCT_ID_SIZE }, | ||
300 | { REG_OFFSET_DATA_BASE, 32 } | ||
301 | }; | ||
302 | |||
303 | static const struct cyapa_cmd_len cyapa_smbus_cmds[] = { | ||
304 | { CYAPA_SMBUS_RESET, 1 }, | ||
305 | { CYAPA_SMBUS_POWER_MODE, 1 }, | ||
306 | { CYAPA_SMBUS_DEV_STATUS, 1 }, | ||
307 | { CYAPA_SMBUS_GROUP_DATA, sizeof(struct cyapa_reg_data) }, | ||
308 | { CYAPA_SMBUS_GROUP_CMD, 2 }, | ||
309 | { CYAPA_SMBUS_GROUP_QUERY, QUERY_DATA_SIZE }, | ||
310 | { CYAPA_SMBUS_BL_STATUS, 3 }, | ||
311 | { CYAPA_SMBUS_BL_HEAD, 16 }, | ||
312 | { CYAPA_SMBUS_BL_CMD, 16 }, | ||
313 | { CYAPA_SMBUS_BL_DATA, 16 }, | ||
314 | { CYAPA_SMBUS_BL_ALL, 32 }, | ||
315 | { CYAPA_SMBUS_BLK_PRODUCT_ID, PRODUCT_ID_SIZE }, | ||
316 | { CYAPA_SMBUS_BLK_HEAD, 16 }, | ||
317 | }; | ||
318 | |||
319 | static ssize_t cyapa_i2c_reg_read_block(struct cyapa *cyapa, u8 reg, size_t len, | ||
320 | u8 *values) | ||
321 | { | ||
322 | return i2c_smbus_read_i2c_block_data(cyapa->client, reg, len, values); | ||
323 | } | ||
324 | |||
325 | static ssize_t cyapa_i2c_reg_write_block(struct cyapa *cyapa, u8 reg, | ||
326 | size_t len, const u8 *values) | ||
327 | { | ||
328 | return i2c_smbus_write_i2c_block_data(cyapa->client, reg, len, values); | ||
329 | } | ||
330 | |||
331 | /* | ||
332 | * cyapa_smbus_read_block - perform smbus block read command | ||
333 | * @cyapa - private data structure of the driver | ||
334 | * @cmd - the properly encoded smbus command | ||
335 | * @len - expected length of smbus command result | ||
336 | * @values - buffer to store smbus command result | ||
337 | * | ||
338 | * Returns negative errno, else the number of bytes written. | ||
339 | * | ||
340 | * Note: | ||
341 | * In trackpad device, the memory block allocated for I2C register map | ||
342 | * is 256 bytes, so the max read block for I2C bus is 256 bytes. | ||
343 | */ | ||
344 | static ssize_t cyapa_smbus_read_block(struct cyapa *cyapa, u8 cmd, size_t len, | ||
345 | u8 *values) | ||
346 | { | ||
347 | ssize_t ret; | ||
348 | u8 index; | ||
349 | u8 smbus_cmd; | ||
350 | u8 *buf; | ||
351 | struct i2c_client *client = cyapa->client; | ||
352 | |||
353 | if (!(SMBUS_BYTE_BLOCK_CMD_MASK & cmd)) | ||
354 | return -EINVAL; | ||
355 | |||
356 | if (SMBUS_GROUP_BLOCK_CMD_MASK & cmd) { | ||
357 | /* read specific block registers command. */ | ||
358 | smbus_cmd = SMBUS_ENCODE_RW(cmd, SMBUS_READ); | ||
359 | ret = i2c_smbus_read_block_data(client, smbus_cmd, values); | ||
360 | goto out; | ||
361 | } | ||
362 | |||
363 | ret = 0; | ||
364 | for (index = 0; index * I2C_SMBUS_BLOCK_MAX < len; index++) { | ||
365 | smbus_cmd = SMBUS_ENCODE_IDX(cmd, index); | ||
366 | smbus_cmd = SMBUS_ENCODE_RW(smbus_cmd, SMBUS_READ); | ||
367 | buf = values + I2C_SMBUS_BLOCK_MAX * index; | ||
368 | ret = i2c_smbus_read_block_data(client, smbus_cmd, buf); | ||
369 | if (ret < 0) | ||
370 | goto out; | ||
371 | } | ||
372 | |||
373 | out: | ||
374 | return ret > 0 ? len : ret; | ||
375 | } | ||
376 | |||
377 | static s32 cyapa_read_byte(struct cyapa *cyapa, u8 cmd_idx) | ||
378 | { | ||
379 | u8 cmd; | ||
380 | |||
381 | if (cyapa->smbus) { | ||
382 | cmd = cyapa_smbus_cmds[cmd_idx].cmd; | ||
383 | cmd = SMBUS_ENCODE_RW(cmd, SMBUS_READ); | ||
384 | } else { | ||
385 | cmd = cyapa_i2c_cmds[cmd_idx].cmd; | ||
386 | } | ||
387 | return i2c_smbus_read_byte_data(cyapa->client, cmd); | ||
388 | } | ||
389 | |||
390 | static s32 cyapa_write_byte(struct cyapa *cyapa, u8 cmd_idx, u8 value) | ||
391 | { | ||
392 | u8 cmd; | ||
393 | |||
394 | if (cyapa->smbus) { | ||
395 | cmd = cyapa_smbus_cmds[cmd_idx].cmd; | ||
396 | cmd = SMBUS_ENCODE_RW(cmd, SMBUS_WRITE); | ||
397 | } else { | ||
398 | cmd = cyapa_i2c_cmds[cmd_idx].cmd; | ||
399 | } | ||
400 | return i2c_smbus_write_byte_data(cyapa->client, cmd, value); | ||
401 | } | ||
402 | |||
403 | static ssize_t cyapa_read_block(struct cyapa *cyapa, u8 cmd_idx, u8 *values) | ||
404 | { | ||
405 | u8 cmd; | ||
406 | size_t len; | ||
407 | |||
408 | if (cyapa->smbus) { | ||
409 | cmd = cyapa_smbus_cmds[cmd_idx].cmd; | ||
410 | len = cyapa_smbus_cmds[cmd_idx].len; | ||
411 | return cyapa_smbus_read_block(cyapa, cmd, len, values); | ||
412 | } else { | ||
413 | cmd = cyapa_i2c_cmds[cmd_idx].cmd; | ||
414 | len = cyapa_i2c_cmds[cmd_idx].len; | ||
415 | return cyapa_i2c_reg_read_block(cyapa, cmd, len, values); | ||
416 | } | ||
417 | } | ||
418 | |||
419 | /* | ||
420 | * Query device for its current operating state. | ||
421 | * | ||
422 | */ | ||
423 | static int cyapa_get_state(struct cyapa *cyapa) | ||
424 | { | ||
425 | int ret; | ||
426 | u8 status[BL_STATUS_SIZE]; | ||
427 | |||
428 | cyapa->state = CYAPA_STATE_NO_DEVICE; | ||
429 | |||
430 | /* | ||
431 | * Get trackpad status by reading 3 registers starting from 0. | ||
432 | * If the device is in the bootloader, this will be BL_HEAD. | ||
433 | * If the device is in operation mode, this will be the DATA regs. | ||
434 | * | ||
435 | */ | ||
436 | ret = cyapa_i2c_reg_read_block(cyapa, BL_HEAD_OFFSET, BL_STATUS_SIZE, | ||
437 | status); | ||
438 | |||
439 | /* | ||
440 | * On smbus systems in OP mode, the i2c_reg_read will fail with | ||
441 | * -ETIMEDOUT. In this case, try again using the smbus equivalent | ||
442 | * command. This should return a BL_HEAD indicating CYAPA_STATE_OP. | ||
443 | */ | ||
444 | if (cyapa->smbus && (ret == -ETIMEDOUT || ret == -ENXIO)) | ||
445 | ret = cyapa_read_block(cyapa, CYAPA_CMD_BL_STATUS, status); | ||
446 | |||
447 | if (ret != BL_STATUS_SIZE) | ||
448 | goto error; | ||
449 | |||
450 | if ((status[REG_OP_STATUS] & OP_STATUS_SRC) == OP_STATUS_SRC) { | ||
451 | switch (status[REG_OP_STATUS] & OP_STATUS_DEV) { | ||
452 | case CYAPA_DEV_NORMAL: | ||
453 | case CYAPA_DEV_BUSY: | ||
454 | cyapa->state = CYAPA_STATE_OP; | ||
455 | break; | ||
456 | default: | ||
457 | ret = -EAGAIN; | ||
458 | goto error; | ||
459 | } | ||
460 | } else { | ||
461 | if (status[REG_BL_STATUS] & BL_STATUS_BUSY) | ||
462 | cyapa->state = CYAPA_STATE_BL_BUSY; | ||
463 | else if (status[REG_BL_ERROR] & BL_ERROR_BOOTLOADING) | ||
464 | cyapa->state = CYAPA_STATE_BL_ACTIVE; | ||
465 | else | ||
466 | cyapa->state = CYAPA_STATE_BL_IDLE; | ||
467 | } | ||
468 | |||
469 | return 0; | ||
470 | error: | ||
471 | return (ret < 0) ? ret : -EAGAIN; | ||
472 | } | ||
473 | |||
474 | /* | ||
475 | * Poll device for its status in a loop, waiting up to timeout for a response. | ||
476 | * | ||
477 | * When the device switches state, it usually takes ~300 ms. | ||
478 | * However, when running a new firmware image, the device must calibrate its | ||
479 | * sensors, which can take as long as 2 seconds. | ||
480 | * | ||
481 | * Note: The timeout has granularity of the polling rate, which is 100 ms. | ||
482 | * | ||
483 | * Returns: | ||
484 | * 0 when the device eventually responds with a valid non-busy state. | ||
485 | * -ETIMEDOUT if device never responds (too many -EAGAIN) | ||
486 | * < 0 other errors | ||
487 | */ | ||
488 | static int cyapa_poll_state(struct cyapa *cyapa, unsigned int timeout) | ||
489 | { | ||
490 | int ret; | ||
491 | int tries = timeout / 100; | ||
492 | |||
493 | ret = cyapa_get_state(cyapa); | ||
494 | while ((ret || cyapa->state >= CYAPA_STATE_BL_BUSY) && tries--) { | ||
495 | msleep(100); | ||
496 | ret = cyapa_get_state(cyapa); | ||
497 | } | ||
498 | return (ret == -EAGAIN || ret == -ETIMEDOUT) ? -ETIMEDOUT : ret; | ||
499 | } | ||
500 | |||
501 | static int cyapa_bl_deactivate(struct cyapa *cyapa) | ||
502 | { | ||
503 | int ret; | ||
504 | |||
505 | ret = cyapa_i2c_reg_write_block(cyapa, 0, sizeof(bl_deactivate), | ||
506 | bl_deactivate); | ||
507 | if (ret < 0) | ||
508 | return ret; | ||
509 | |||
510 | /* wait for bootloader to switch to idle state; should take < 100ms */ | ||
511 | msleep(100); | ||
512 | ret = cyapa_poll_state(cyapa, 500); | ||
513 | if (ret < 0) | ||
514 | return ret; | ||
515 | if (cyapa->state != CYAPA_STATE_BL_IDLE) | ||
516 | return -EAGAIN; | ||
517 | return 0; | ||
518 | } | ||
519 | |||
520 | /* | ||
521 | * Exit bootloader | ||
522 | * | ||
523 | * Send bl_exit command, then wait 50 - 100 ms to let device transition to | ||
524 | * operational mode. If this is the first time the device's firmware is | ||
525 | * running, it can take up to 2 seconds to calibrate its sensors. So, poll | ||
526 | * the device's new state for up to 2 seconds. | ||
527 | * | ||
528 | * Returns: | ||
529 | * -EIO failure while reading from device | ||
530 | * -EAGAIN device is stuck in bootloader, b/c it has invalid firmware | ||
531 | * 0 device is supported and in operational mode | ||
532 | */ | ||
533 | static int cyapa_bl_exit(struct cyapa *cyapa) | ||
534 | { | ||
535 | int ret; | ||
536 | |||
537 | ret = cyapa_i2c_reg_write_block(cyapa, 0, sizeof(bl_exit), bl_exit); | ||
538 | if (ret < 0) | ||
539 | return ret; | ||
540 | |||
541 | /* | ||
542 | * Wait for bootloader to exit, and operation mode to start. | ||
543 | * Normally, this takes at least 50 ms. | ||
544 | */ | ||
545 | usleep_range(50000, 100000); | ||
546 | /* | ||
547 | * In addition, when a device boots for the first time after being | ||
548 | * updated to new firmware, it must first calibrate its sensors, which | ||
549 | * can take up to an additional 2 seconds. | ||
550 | */ | ||
551 | ret = cyapa_poll_state(cyapa, 2000); | ||
552 | if (ret < 0) | ||
553 | return ret; | ||
554 | if (cyapa->state != CYAPA_STATE_OP) | ||
555 | return -EAGAIN; | ||
556 | |||
557 | return 0; | ||
558 | } | ||
559 | |||
560 | /* | ||
561 | * Set device power mode | ||
562 | * | ||
563 | */ | ||
564 | static int cyapa_set_power_mode(struct cyapa *cyapa, u8 power_mode) | ||
565 | { | ||
566 | struct device *dev = &cyapa->client->dev; | ||
567 | int ret; | ||
568 | u8 power; | ||
569 | |||
570 | if (cyapa->state != CYAPA_STATE_OP) | ||
571 | return 0; | ||
572 | |||
573 | ret = cyapa_read_byte(cyapa, CYAPA_CMD_POWER_MODE); | ||
574 | if (ret < 0) | ||
575 | return ret; | ||
576 | |||
577 | power = ret & ~PWR_MODE_MASK; | ||
578 | power |= power_mode & PWR_MODE_MASK; | ||
579 | ret = cyapa_write_byte(cyapa, CYAPA_CMD_POWER_MODE, power); | ||
580 | if (ret < 0) | ||
581 | dev_err(dev, "failed to set power_mode 0x%02x err = %d\n", | ||
582 | power_mode, ret); | ||
583 | return ret; | ||
584 | } | ||
585 | |||
586 | static int cyapa_get_query_data(struct cyapa *cyapa) | ||
587 | { | ||
588 | u8 query_data[QUERY_DATA_SIZE]; | ||
589 | int ret; | ||
590 | |||
591 | if (cyapa->state != CYAPA_STATE_OP) | ||
592 | return -EBUSY; | ||
593 | |||
594 | ret = cyapa_read_block(cyapa, CYAPA_CMD_GROUP_QUERY, query_data); | ||
595 | if (ret < 0) | ||
596 | return ret; | ||
597 | if (ret != QUERY_DATA_SIZE) | ||
598 | return -EIO; | ||
599 | |||
600 | memcpy(&cyapa->product_id[0], &query_data[0], 5); | ||
601 | cyapa->product_id[5] = '-'; | ||
602 | memcpy(&cyapa->product_id[6], &query_data[5], 6); | ||
603 | cyapa->product_id[12] = '-'; | ||
604 | memcpy(&cyapa->product_id[13], &query_data[11], 2); | ||
605 | cyapa->product_id[15] = '\0'; | ||
606 | |||
607 | cyapa->btn_capability = query_data[19] & CAPABILITY_BTN_MASK; | ||
608 | |||
609 | cyapa->gen = query_data[20] & 0x0f; | ||
610 | |||
611 | cyapa->max_abs_x = ((query_data[21] & 0xf0) << 4) | query_data[22]; | ||
612 | cyapa->max_abs_y = ((query_data[21] & 0x0f) << 8) | query_data[23]; | ||
613 | |||
614 | cyapa->physical_size_x = | ||
615 | ((query_data[24] & 0xf0) << 4) | query_data[25]; | ||
616 | cyapa->physical_size_y = | ||
617 | ((query_data[24] & 0x0f) << 8) | query_data[26]; | ||
618 | |||
619 | return 0; | ||
620 | } | ||
621 | |||
622 | /* | ||
623 | * Check if device is operational. | ||
624 | * | ||
625 | * An operational device is responding, has exited bootloader, and has | ||
626 | * firmware supported by this driver. | ||
627 | * | ||
628 | * Returns: | ||
629 | * -EBUSY no device or in bootloader | ||
630 | * -EIO failure while reading from device | ||
631 | * -EAGAIN device is still in bootloader | ||
632 | * if ->state = CYAPA_STATE_BL_IDLE, device has invalid firmware | ||
633 | * -EINVAL device is in operational mode, but not supported by this driver | ||
634 | * 0 device is supported | ||
635 | */ | ||
636 | static int cyapa_check_is_operational(struct cyapa *cyapa) | ||
637 | { | ||
638 | struct device *dev = &cyapa->client->dev; | ||
639 | static const char unique_str[] = "CYTRA"; | ||
640 | int ret; | ||
641 | |||
642 | ret = cyapa_poll_state(cyapa, 2000); | ||
643 | if (ret < 0) | ||
644 | return ret; | ||
645 | switch (cyapa->state) { | ||
646 | case CYAPA_STATE_BL_ACTIVE: | ||
647 | ret = cyapa_bl_deactivate(cyapa); | ||
648 | if (ret) | ||
649 | return ret; | ||
650 | |||
651 | /* Fallthrough state */ | ||
652 | case CYAPA_STATE_BL_IDLE: | ||
653 | ret = cyapa_bl_exit(cyapa); | ||
654 | if (ret) | ||
655 | return ret; | ||
656 | |||
657 | /* Fallthrough state */ | ||
658 | case CYAPA_STATE_OP: | ||
659 | ret = cyapa_get_query_data(cyapa); | ||
660 | if (ret < 0) | ||
661 | return ret; | ||
662 | |||
663 | /* only support firmware protocol gen3 */ | ||
664 | if (cyapa->gen != CYAPA_GEN3) { | ||
665 | dev_err(dev, "unsupported protocol version (%d)", | ||
666 | cyapa->gen); | ||
667 | return -EINVAL; | ||
668 | } | ||
669 | |||
670 | /* only support product ID starting with CYTRA */ | ||
671 | if (memcmp(cyapa->product_id, unique_str, | ||
672 | sizeof(unique_str) - 1) != 0) { | ||
673 | dev_err(dev, "unsupported product ID (%s)\n", | ||
674 | cyapa->product_id); | ||
675 | return -EINVAL; | ||
676 | } | ||
677 | return 0; | ||
678 | |||
679 | default: | ||
680 | return -EIO; | ||
681 | } | ||
682 | return 0; | ||
683 | } | ||
684 | |||
685 | static irqreturn_t cyapa_irq(int irq, void *dev_id) | ||
686 | { | ||
687 | struct cyapa *cyapa = dev_id; | ||
688 | struct device *dev = &cyapa->client->dev; | ||
689 | struct input_dev *input = cyapa->input; | ||
690 | struct cyapa_reg_data data; | ||
691 | int i; | ||
692 | int ret; | ||
693 | int num_fingers; | ||
694 | |||
695 | if (device_may_wakeup(dev)) | ||
696 | pm_wakeup_event(dev, 0); | ||
697 | |||
698 | ret = cyapa_read_block(cyapa, CYAPA_CMD_GROUP_DATA, (u8 *)&data); | ||
699 | if (ret != sizeof(data)) | ||
700 | goto out; | ||
701 | |||
702 | if ((data.device_status & OP_STATUS_SRC) != OP_STATUS_SRC || | ||
703 | (data.device_status & OP_STATUS_DEV) != CYAPA_DEV_NORMAL || | ||
704 | (data.finger_btn & OP_DATA_VALID) != OP_DATA_VALID) { | ||
705 | goto out; | ||
706 | } | ||
707 | |||
708 | num_fingers = (data.finger_btn >> 4) & 0x0f; | ||
709 | for (i = 0; i < num_fingers; i++) { | ||
710 | const struct cyapa_touch *touch = &data.touches[i]; | ||
711 | /* Note: touch->id range is 1 to 15; slots are 0 to 14. */ | ||
712 | int slot = touch->id - 1; | ||
713 | |||
714 | input_mt_slot(input, slot); | ||
715 | input_mt_report_slot_state(input, MT_TOOL_FINGER, true); | ||
716 | input_report_abs(input, ABS_MT_POSITION_X, | ||
717 | ((touch->xy_hi & 0xf0) << 4) | touch->x_lo); | ||
718 | input_report_abs(input, ABS_MT_POSITION_Y, | ||
719 | ((touch->xy_hi & 0x0f) << 8) | touch->y_lo); | ||
720 | input_report_abs(input, ABS_MT_PRESSURE, touch->pressure); | ||
721 | } | ||
722 | |||
723 | input_mt_sync_frame(input); | ||
724 | |||
725 | if (cyapa->btn_capability & CAPABILITY_LEFT_BTN_MASK) | ||
726 | input_report_key(input, BTN_LEFT, | ||
727 | data.finger_btn & OP_DATA_LEFT_BTN); | ||
728 | |||
729 | if (cyapa->btn_capability & CAPABILITY_MIDDLE_BTN_MASK) | ||
730 | input_report_key(input, BTN_MIDDLE, | ||
731 | data.finger_btn & OP_DATA_MIDDLE_BTN); | ||
732 | |||
733 | if (cyapa->btn_capability & CAPABILITY_RIGHT_BTN_MASK) | ||
734 | input_report_key(input, BTN_RIGHT, | ||
735 | data.finger_btn & OP_DATA_RIGHT_BTN); | ||
736 | |||
737 | input_sync(input); | ||
738 | |||
739 | out: | ||
740 | return IRQ_HANDLED; | ||
741 | } | ||
742 | |||
743 | static u8 cyapa_check_adapter_functionality(struct i2c_client *client) | ||
744 | { | ||
745 | u8 ret = CYAPA_ADAPTER_FUNC_NONE; | ||
746 | |||
747 | if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) | ||
748 | ret |= CYAPA_ADAPTER_FUNC_I2C; | ||
749 | if (i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA | | ||
750 | I2C_FUNC_SMBUS_BLOCK_DATA | | ||
751 | I2C_FUNC_SMBUS_I2C_BLOCK)) | ||
752 | ret |= CYAPA_ADAPTER_FUNC_SMBUS; | ||
753 | return ret; | ||
754 | } | ||
755 | |||
756 | static int cyapa_create_input_dev(struct cyapa *cyapa) | ||
757 | { | ||
758 | struct device *dev = &cyapa->client->dev; | ||
759 | int ret; | ||
760 | struct input_dev *input; | ||
761 | |||
762 | if (!cyapa->physical_size_x || !cyapa->physical_size_y) | ||
763 | return -EINVAL; | ||
764 | |||
765 | input = cyapa->input = input_allocate_device(); | ||
766 | if (!input) { | ||
767 | dev_err(dev, "allocate memory for input device failed\n"); | ||
768 | return -ENOMEM; | ||
769 | } | ||
770 | |||
771 | input->name = CYAPA_NAME; | ||
772 | input->phys = cyapa->phys; | ||
773 | input->id.bustype = BUS_I2C; | ||
774 | input->id.version = 1; | ||
775 | input->id.product = 0; /* means any product in eventcomm. */ | ||
776 | input->dev.parent = &cyapa->client->dev; | ||
777 | |||
778 | input_set_drvdata(input, cyapa); | ||
779 | |||
780 | __set_bit(EV_ABS, input->evbit); | ||
781 | |||
782 | /* finger position */ | ||
783 | input_set_abs_params(input, ABS_MT_POSITION_X, 0, cyapa->max_abs_x, 0, | ||
784 | 0); | ||
785 | input_set_abs_params(input, ABS_MT_POSITION_Y, 0, cyapa->max_abs_y, 0, | ||
786 | 0); | ||
787 | input_set_abs_params(input, ABS_MT_PRESSURE, 0, 255, 0, 0); | ||
788 | |||
789 | input_abs_set_res(input, ABS_MT_POSITION_X, | ||
790 | cyapa->max_abs_x / cyapa->physical_size_x); | ||
791 | input_abs_set_res(input, ABS_MT_POSITION_Y, | ||
792 | cyapa->max_abs_y / cyapa->physical_size_y); | ||
793 | |||
794 | if (cyapa->btn_capability & CAPABILITY_LEFT_BTN_MASK) | ||
795 | __set_bit(BTN_LEFT, input->keybit); | ||
796 | if (cyapa->btn_capability & CAPABILITY_MIDDLE_BTN_MASK) | ||
797 | __set_bit(BTN_MIDDLE, input->keybit); | ||
798 | if (cyapa->btn_capability & CAPABILITY_RIGHT_BTN_MASK) | ||
799 | __set_bit(BTN_RIGHT, input->keybit); | ||
800 | |||
801 | if (cyapa->btn_capability == CAPABILITY_LEFT_BTN_MASK) | ||
802 | __set_bit(INPUT_PROP_BUTTONPAD, input->propbit); | ||
803 | |||
804 | /* handle pointer emulation and unused slots in core */ | ||
805 | ret = input_mt_init_slots(input, CYAPA_MAX_MT_SLOTS, | ||
806 | INPUT_MT_POINTER | INPUT_MT_DROP_UNUSED); | ||
807 | if (ret) { | ||
808 | dev_err(dev, "allocate memory for MT slots failed, %d\n", ret); | ||
809 | goto err_free_device; | ||
810 | } | ||
811 | |||
812 | /* Register the device in input subsystem */ | ||
813 | ret = input_register_device(input); | ||
814 | if (ret) { | ||
815 | dev_err(dev, "input device register failed, %d\n", ret); | ||
816 | goto err_free_device; | ||
817 | } | ||
818 | return 0; | ||
819 | |||
820 | err_free_device: | ||
821 | input_free_device(input); | ||
822 | cyapa->input = NULL; | ||
823 | return ret; | ||
824 | } | ||
825 | |||
826 | static int cyapa_probe(struct i2c_client *client, | ||
827 | const struct i2c_device_id *dev_id) | ||
828 | { | ||
829 | int ret; | ||
830 | u8 adapter_func; | ||
831 | struct cyapa *cyapa; | ||
832 | struct device *dev = &client->dev; | ||
833 | |||
834 | adapter_func = cyapa_check_adapter_functionality(client); | ||
835 | if (adapter_func == CYAPA_ADAPTER_FUNC_NONE) { | ||
836 | dev_err(dev, "not a supported I2C/SMBus adapter\n"); | ||
837 | return -EIO; | ||
838 | } | ||
839 | |||
840 | cyapa = kzalloc(sizeof(struct cyapa), GFP_KERNEL); | ||
841 | if (!cyapa) { | ||
842 | dev_err(dev, "allocate memory for cyapa failed\n"); | ||
843 | return -ENOMEM; | ||
844 | } | ||
845 | |||
846 | cyapa->gen = CYAPA_GEN3; | ||
847 | cyapa->client = client; | ||
848 | i2c_set_clientdata(client, cyapa); | ||
849 | sprintf(cyapa->phys, "i2c-%d-%04x/input0", client->adapter->nr, | ||
850 | client->addr); | ||
851 | |||
852 | /* i2c isn't supported, use smbus */ | ||
853 | if (adapter_func == CYAPA_ADAPTER_FUNC_SMBUS) | ||
854 | cyapa->smbus = true; | ||
855 | cyapa->state = CYAPA_STATE_NO_DEVICE; | ||
856 | ret = cyapa_check_is_operational(cyapa); | ||
857 | if (ret) { | ||
858 | dev_err(dev, "device not operational, %d\n", ret); | ||
859 | goto err_mem_free; | ||
860 | } | ||
861 | |||
862 | ret = cyapa_create_input_dev(cyapa); | ||
863 | if (ret) { | ||
864 | dev_err(dev, "create input_dev instance failed, %d\n", ret); | ||
865 | goto err_mem_free; | ||
866 | } | ||
867 | |||
868 | ret = cyapa_set_power_mode(cyapa, PWR_MODE_FULL_ACTIVE); | ||
869 | if (ret) { | ||
870 | dev_err(dev, "set active power failed, %d\n", ret); | ||
871 | goto err_unregister_device; | ||
872 | } | ||
873 | |||
874 | cyapa->irq = client->irq; | ||
875 | ret = request_threaded_irq(cyapa->irq, | ||
876 | NULL, | ||
877 | cyapa_irq, | ||
878 | IRQF_TRIGGER_FALLING | IRQF_ONESHOT, | ||
879 | "cyapa", | ||
880 | cyapa); | ||
881 | if (ret) { | ||
882 | dev_err(dev, "IRQ request failed: %d\n, ", ret); | ||
883 | goto err_unregister_device; | ||
884 | } | ||
885 | |||
886 | return 0; | ||
887 | |||
888 | err_unregister_device: | ||
889 | input_unregister_device(cyapa->input); | ||
890 | err_mem_free: | ||
891 | kfree(cyapa); | ||
892 | |||
893 | return ret; | ||
894 | } | ||
895 | |||
896 | static int cyapa_remove(struct i2c_client *client) | ||
897 | { | ||
898 | struct cyapa *cyapa = i2c_get_clientdata(client); | ||
899 | |||
900 | free_irq(cyapa->irq, cyapa); | ||
901 | input_unregister_device(cyapa->input); | ||
902 | cyapa_set_power_mode(cyapa, PWR_MODE_OFF); | ||
903 | kfree(cyapa); | ||
904 | |||
905 | return 0; | ||
906 | } | ||
907 | |||
908 | #ifdef CONFIG_PM_SLEEP | ||
909 | static int cyapa_suspend(struct device *dev) | ||
910 | { | ||
911 | int ret; | ||
912 | u8 power_mode; | ||
913 | struct cyapa *cyapa = dev_get_drvdata(dev); | ||
914 | |||
915 | disable_irq(cyapa->irq); | ||
916 | |||
917 | /* | ||
918 | * Set trackpad device to idle mode if wakeup is allowed, | ||
919 | * otherwise turn off. | ||
920 | */ | ||
921 | power_mode = device_may_wakeup(dev) ? PWR_MODE_IDLE | ||
922 | : PWR_MODE_OFF; | ||
923 | ret = cyapa_set_power_mode(cyapa, power_mode); | ||
924 | if (ret < 0) | ||
925 | dev_err(dev, "set power mode failed, %d\n", ret); | ||
926 | |||
927 | if (device_may_wakeup(dev)) | ||
928 | cyapa->irq_wake = (enable_irq_wake(cyapa->irq) == 0); | ||
929 | return 0; | ||
930 | } | ||
931 | |||
932 | static int cyapa_resume(struct device *dev) | ||
933 | { | ||
934 | int ret; | ||
935 | struct cyapa *cyapa = dev_get_drvdata(dev); | ||
936 | |||
937 | if (device_may_wakeup(dev) && cyapa->irq_wake) | ||
938 | disable_irq_wake(cyapa->irq); | ||
939 | |||
940 | ret = cyapa_set_power_mode(cyapa, PWR_MODE_FULL_ACTIVE); | ||
941 | if (ret) | ||
942 | dev_warn(dev, "resume active power failed, %d\n", ret); | ||
943 | |||
944 | enable_irq(cyapa->irq); | ||
945 | return 0; | ||
946 | } | ||
947 | #endif /* CONFIG_PM_SLEEP */ | ||
948 | |||
949 | static SIMPLE_DEV_PM_OPS(cyapa_pm_ops, cyapa_suspend, cyapa_resume); | ||
950 | |||
951 | static const struct i2c_device_id cyapa_id_table[] = { | ||
952 | { "cyapa", 0 }, | ||
953 | { }, | ||
954 | }; | ||
955 | MODULE_DEVICE_TABLE(i2c, cyapa_id_table); | ||
956 | |||
957 | static struct i2c_driver cyapa_driver = { | ||
958 | .driver = { | ||
959 | .name = "cyapa", | ||
960 | .owner = THIS_MODULE, | ||
961 | .pm = &cyapa_pm_ops, | ||
962 | }, | ||
963 | |||
964 | .probe = cyapa_probe, | ||
965 | .remove = cyapa_remove, | ||
966 | .id_table = cyapa_id_table, | ||
967 | }; | ||
968 | |||
969 | module_i2c_driver(cyapa_driver); | ||
970 | |||
971 | MODULE_DESCRIPTION("Cypress APA I2C Trackpad Driver"); | ||
972 | MODULE_AUTHOR("Dudley Du <dudl@cypress.com>"); | ||
973 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/input/mouse/cypress_ps2.c b/drivers/input/mouse/cypress_ps2.c new file mode 100644 index 000000000000..1673dc6c8092 --- /dev/null +++ b/drivers/input/mouse/cypress_ps2.c | |||
@@ -0,0 +1,725 @@ | |||
1 | /* | ||
2 | * Cypress Trackpad PS/2 mouse driver | ||
3 | * | ||
4 | * Copyright (c) 2012 Cypress Semiconductor Corporation. | ||
5 | * | ||
6 | * Author: | ||
7 | * Dudley Du <dudl@cypress.com> | ||
8 | * | ||
9 | * Additional contributors include: | ||
10 | * Kamal Mostafa <kamal@canonical.com> | ||
11 | * Kyle Fazzari <git@status.e4ward.com> | ||
12 | * | ||
13 | * This program is free software; you can redistribute it and/or modify it | ||
14 | * under the terms of the GNU General Public License version 2 as published by | ||
15 | * the Free Software Foundation. | ||
16 | */ | ||
17 | |||
18 | #include <linux/init.h> | ||
19 | #include <linux/module.h> | ||
20 | #include <linux/kernel.h> | ||
21 | #include <linux/slab.h> | ||
22 | #include <linux/serio.h> | ||
23 | #include <linux/libps2.h> | ||
24 | #include <linux/input.h> | ||
25 | #include <linux/input/mt.h> | ||
26 | #include <linux/sched.h> | ||
27 | #include <linux/wait.h> | ||
28 | |||
29 | #include "cypress_ps2.h" | ||
30 | |||
31 | #undef CYTP_DEBUG_VERBOSE /* define this and DEBUG for more verbose dump */ | ||
32 | |||
33 | static void cypress_set_packet_size(struct psmouse *psmouse, unsigned int n) | ||
34 | { | ||
35 | struct cytp_data *cytp = psmouse->private; | ||
36 | cytp->pkt_size = n; | ||
37 | } | ||
38 | |||
39 | static const unsigned char cytp_rate[] = {10, 20, 40, 60, 100, 200}; | ||
40 | static const unsigned char cytp_resolution[] = {0x00, 0x01, 0x02, 0x03}; | ||
41 | |||
42 | static int cypress_ps2_sendbyte(struct psmouse *psmouse, int value) | ||
43 | { | ||
44 | struct ps2dev *ps2dev = &psmouse->ps2dev; | ||
45 | |||
46 | if (ps2_sendbyte(ps2dev, value & 0xff, CYTP_CMD_TIMEOUT) < 0) { | ||
47 | psmouse_dbg(psmouse, | ||
48 | "sending command 0x%02x failed, resp 0x%02x\n", | ||
49 | value & 0xff, ps2dev->nak); | ||
50 | if (ps2dev->nak == CYTP_PS2_RETRY) | ||
51 | return CYTP_PS2_RETRY; | ||
52 | else | ||
53 | return CYTP_PS2_ERROR; | ||
54 | } | ||
55 | |||
56 | #ifdef CYTP_DEBUG_VERBOSE | ||
57 | psmouse_dbg(psmouse, "sending command 0x%02x succeeded, resp 0xfa\n", | ||
58 | value & 0xff); | ||
59 | #endif | ||
60 | |||
61 | return 0; | ||
62 | } | ||
63 | |||
64 | static int cypress_ps2_ext_cmd(struct psmouse *psmouse, unsigned short cmd, | ||
65 | unsigned char data) | ||
66 | { | ||
67 | struct ps2dev *ps2dev = &psmouse->ps2dev; | ||
68 | int tries = CYTP_PS2_CMD_TRIES; | ||
69 | int rc; | ||
70 | |||
71 | ps2_begin_command(ps2dev); | ||
72 | |||
73 | do { | ||
74 | /* | ||
75 | * Send extension command byte (0xE8 or 0xF3). | ||
76 | * If sending the command fails, send recovery command | ||
77 | * to make the device return to the ready state. | ||
78 | */ | ||
79 | rc = cypress_ps2_sendbyte(psmouse, cmd & 0xff); | ||
80 | if (rc == CYTP_PS2_RETRY) { | ||
81 | rc = cypress_ps2_sendbyte(psmouse, 0x00); | ||
82 | if (rc == CYTP_PS2_RETRY) | ||
83 | rc = cypress_ps2_sendbyte(psmouse, 0x0a); | ||
84 | } | ||
85 | if (rc == CYTP_PS2_ERROR) | ||
86 | continue; | ||
87 | |||
88 | rc = cypress_ps2_sendbyte(psmouse, data); | ||
89 | if (rc == CYTP_PS2_RETRY) | ||
90 | rc = cypress_ps2_sendbyte(psmouse, data); | ||
91 | if (rc == CYTP_PS2_ERROR) | ||
92 | continue; | ||
93 | else | ||
94 | break; | ||
95 | } while (--tries > 0); | ||
96 | |||
97 | ps2_end_command(ps2dev); | ||
98 | |||
99 | return rc; | ||
100 | } | ||
101 | |||
102 | static int cypress_ps2_read_cmd_status(struct psmouse *psmouse, | ||
103 | unsigned char cmd, | ||
104 | unsigned char *param) | ||
105 | { | ||
106 | int rc; | ||
107 | struct ps2dev *ps2dev = &psmouse->ps2dev; | ||
108 | enum psmouse_state old_state; | ||
109 | int pktsize; | ||
110 | |||
111 | ps2_begin_command(&psmouse->ps2dev); | ||
112 | |||
113 | old_state = psmouse->state; | ||
114 | psmouse->state = PSMOUSE_CMD_MODE; | ||
115 | psmouse->pktcnt = 0; | ||
116 | |||
117 | pktsize = (cmd == CYTP_CMD_READ_TP_METRICS) ? 8 : 3; | ||
118 | memset(param, 0, pktsize); | ||
119 | |||
120 | rc = cypress_ps2_sendbyte(psmouse, 0xe9); | ||
121 | if (rc < 0) | ||
122 | goto out; | ||
123 | |||
124 | wait_event_timeout(ps2dev->wait, | ||
125 | (psmouse->pktcnt >= pktsize), | ||
126 | msecs_to_jiffies(CYTP_CMD_TIMEOUT)); | ||
127 | |||
128 | memcpy(param, psmouse->packet, pktsize); | ||
129 | |||
130 | psmouse_dbg(psmouse, "Command 0x%02x response data (0x): %*ph\n", | ||
131 | cmd, pktsize, param); | ||
132 | |||
133 | out: | ||
134 | psmouse->state = old_state; | ||
135 | psmouse->pktcnt = 0; | ||
136 | |||
137 | ps2_end_command(&psmouse->ps2dev); | ||
138 | |||
139 | return rc; | ||
140 | } | ||
141 | |||
142 | static bool cypress_verify_cmd_state(struct psmouse *psmouse, | ||
143 | unsigned char cmd, unsigned char *param) | ||
144 | { | ||
145 | bool rate_match = false; | ||
146 | bool resolution_match = false; | ||
147 | int i; | ||
148 | |||
149 | /* callers will do further checking. */ | ||
150 | if (cmd == CYTP_CMD_READ_CYPRESS_ID || | ||
151 | cmd == CYTP_CMD_STANDARD_MODE || | ||
152 | cmd == CYTP_CMD_READ_TP_METRICS) | ||
153 | return true; | ||
154 | |||
155 | if ((~param[0] & DFLT_RESP_BITS_VALID) == DFLT_RESP_BITS_VALID && | ||
156 | (param[0] & DFLT_RESP_BIT_MODE) == DFLT_RESP_STREAM_MODE) { | ||
157 | for (i = 0; i < sizeof(cytp_resolution); i++) | ||
158 | if (cytp_resolution[i] == param[1]) | ||
159 | resolution_match = true; | ||
160 | |||
161 | for (i = 0; i < sizeof(cytp_rate); i++) | ||
162 | if (cytp_rate[i] == param[2]) | ||
163 | rate_match = true; | ||
164 | |||
165 | if (resolution_match && rate_match) | ||
166 | return true; | ||
167 | } | ||
168 | |||
169 | psmouse_dbg(psmouse, "verify cmd state failed.\n"); | ||
170 | return false; | ||
171 | } | ||
172 | |||
173 | static int cypress_send_ext_cmd(struct psmouse *psmouse, unsigned char cmd, | ||
174 | unsigned char *param) | ||
175 | { | ||
176 | int tries = CYTP_PS2_CMD_TRIES; | ||
177 | int rc; | ||
178 | |||
179 | psmouse_dbg(psmouse, "send extension cmd 0x%02x, [%d %d %d %d]\n", | ||
180 | cmd, DECODE_CMD_AA(cmd), DECODE_CMD_BB(cmd), | ||
181 | DECODE_CMD_CC(cmd), DECODE_CMD_DD(cmd)); | ||
182 | |||
183 | do { | ||
184 | cypress_ps2_ext_cmd(psmouse, | ||
185 | PSMOUSE_CMD_SETRES, DECODE_CMD_DD(cmd)); | ||
186 | cypress_ps2_ext_cmd(psmouse, | ||
187 | PSMOUSE_CMD_SETRES, DECODE_CMD_CC(cmd)); | ||
188 | cypress_ps2_ext_cmd(psmouse, | ||
189 | PSMOUSE_CMD_SETRES, DECODE_CMD_BB(cmd)); | ||
190 | cypress_ps2_ext_cmd(psmouse, | ||
191 | PSMOUSE_CMD_SETRES, DECODE_CMD_AA(cmd)); | ||
192 | |||
193 | rc = cypress_ps2_read_cmd_status(psmouse, cmd, param); | ||
194 | if (rc) | ||
195 | continue; | ||
196 | |||
197 | if (cypress_verify_cmd_state(psmouse, cmd, param)) | ||
198 | return 0; | ||
199 | |||
200 | } while (--tries > 0); | ||
201 | |||
202 | return -EIO; | ||
203 | } | ||
204 | |||
205 | int cypress_detect(struct psmouse *psmouse, bool set_properties) | ||
206 | { | ||
207 | unsigned char param[3]; | ||
208 | |||
209 | if (cypress_send_ext_cmd(psmouse, CYTP_CMD_READ_CYPRESS_ID, param)) | ||
210 | return -ENODEV; | ||
211 | |||
212 | /* Check for Cypress Trackpad signature bytes: 0x33 0xCC */ | ||
213 | if (param[0] != 0x33 || param[1] != 0xCC) | ||
214 | return -ENODEV; | ||
215 | |||
216 | if (set_properties) { | ||
217 | psmouse->vendor = "Cypress"; | ||
218 | psmouse->name = "Trackpad"; | ||
219 | } | ||
220 | |||
221 | return 0; | ||
222 | } | ||
223 | |||
224 | static int cypress_read_fw_version(struct psmouse *psmouse) | ||
225 | { | ||
226 | struct cytp_data *cytp = psmouse->private; | ||
227 | unsigned char param[3]; | ||
228 | |||
229 | if (cypress_send_ext_cmd(psmouse, CYTP_CMD_READ_CYPRESS_ID, param)) | ||
230 | return -ENODEV; | ||
231 | |||
232 | /* Check for Cypress Trackpad signature bytes: 0x33 0xCC */ | ||
233 | if (param[0] != 0x33 || param[1] != 0xCC) | ||
234 | return -ENODEV; | ||
235 | |||
236 | cytp->fw_version = param[2] & FW_VERSION_MASX; | ||
237 | cytp->tp_metrics_supported = (param[2] & TP_METRICS_MASK) ? 1 : 0; | ||
238 | |||
239 | psmouse_dbg(psmouse, "cytp->fw_version = %d\n", cytp->fw_version); | ||
240 | psmouse_dbg(psmouse, "cytp->tp_metrics_supported = %d\n", | ||
241 | cytp->tp_metrics_supported); | ||
242 | |||
243 | return 0; | ||
244 | } | ||
245 | |||
246 | static int cypress_read_tp_metrics(struct psmouse *psmouse) | ||
247 | { | ||
248 | struct cytp_data *cytp = psmouse->private; | ||
249 | unsigned char param[8]; | ||
250 | |||
251 | /* set default values for tp metrics. */ | ||
252 | cytp->tp_width = CYTP_DEFAULT_WIDTH; | ||
253 | cytp->tp_high = CYTP_DEFAULT_HIGH; | ||
254 | cytp->tp_max_abs_x = CYTP_ABS_MAX_X; | ||
255 | cytp->tp_max_abs_y = CYTP_ABS_MAX_Y; | ||
256 | cytp->tp_min_pressure = CYTP_MIN_PRESSURE; | ||
257 | cytp->tp_max_pressure = CYTP_MAX_PRESSURE; | ||
258 | cytp->tp_res_x = cytp->tp_max_abs_x / cytp->tp_width; | ||
259 | cytp->tp_res_y = cytp->tp_max_abs_y / cytp->tp_high; | ||
260 | |||
261 | memset(param, 0, sizeof(param)); | ||
262 | if (cypress_send_ext_cmd(psmouse, CYTP_CMD_READ_TP_METRICS, param) == 0) { | ||
263 | /* Update trackpad parameters. */ | ||
264 | cytp->tp_max_abs_x = (param[1] << 8) | param[0]; | ||
265 | cytp->tp_max_abs_y = (param[3] << 8) | param[2]; | ||
266 | cytp->tp_min_pressure = param[4]; | ||
267 | cytp->tp_max_pressure = param[5]; | ||
268 | } | ||
269 | |||
270 | if (!cytp->tp_max_pressure || | ||
271 | cytp->tp_max_pressure < cytp->tp_min_pressure || | ||
272 | !cytp->tp_width || !cytp->tp_high || | ||
273 | !cytp->tp_max_abs_x || | ||
274 | cytp->tp_max_abs_x < cytp->tp_width || | ||
275 | !cytp->tp_max_abs_y || | ||
276 | cytp->tp_max_abs_y < cytp->tp_high) | ||
277 | return -EINVAL; | ||
278 | |||
279 | cytp->tp_res_x = cytp->tp_max_abs_x / cytp->tp_width; | ||
280 | cytp->tp_res_y = cytp->tp_max_abs_y / cytp->tp_high; | ||
281 | |||
282 | #ifdef CYTP_DEBUG_VERBOSE | ||
283 | psmouse_dbg(psmouse, "Dump trackpad hardware configuration as below:\n"); | ||
284 | psmouse_dbg(psmouse, "cytp->tp_width = %d\n", cytp->tp_width); | ||
285 | psmouse_dbg(psmouse, "cytp->tp_high = %d\n", cytp->tp_high); | ||
286 | psmouse_dbg(psmouse, "cytp->tp_max_abs_x = %d\n", cytp->tp_max_abs_x); | ||
287 | psmouse_dbg(psmouse, "cytp->tp_max_abs_y = %d\n", cytp->tp_max_abs_y); | ||
288 | psmouse_dbg(psmouse, "cytp->tp_min_pressure = %d\n", cytp->tp_min_pressure); | ||
289 | psmouse_dbg(psmouse, "cytp->tp_max_pressure = %d\n", cytp->tp_max_pressure); | ||
290 | psmouse_dbg(psmouse, "cytp->tp_res_x = %d\n", cytp->tp_res_x); | ||
291 | psmouse_dbg(psmouse, "cytp->tp_res_y = %d\n", cytp->tp_res_y); | ||
292 | |||
293 | psmouse_dbg(psmouse, "tp_type_APA = %d\n", | ||
294 | (param[6] & TP_METRICS_BIT_APA) ? 1 : 0); | ||
295 | psmouse_dbg(psmouse, "tp_type_MTG = %d\n", | ||
296 | (param[6] & TP_METRICS_BIT_MTG) ? 1 : 0); | ||
297 | psmouse_dbg(psmouse, "tp_palm = %d\n", | ||
298 | (param[6] & TP_METRICS_BIT_PALM) ? 1 : 0); | ||
299 | psmouse_dbg(psmouse, "tp_stubborn = %d\n", | ||
300 | (param[6] & TP_METRICS_BIT_STUBBORN) ? 1 : 0); | ||
301 | psmouse_dbg(psmouse, "tp_1f_jitter = %d\n", | ||
302 | (param[6] & TP_METRICS_BIT_1F_JITTER) >> 2); | ||
303 | psmouse_dbg(psmouse, "tp_2f_jitter = %d\n", | ||
304 | (param[6] & TP_METRICS_BIT_2F_JITTER) >> 4); | ||
305 | psmouse_dbg(psmouse, "tp_1f_spike = %d\n", | ||
306 | param[7] & TP_METRICS_BIT_1F_SPIKE); | ||
307 | psmouse_dbg(psmouse, "tp_2f_spike = %d\n", | ||
308 | (param[7] & TP_METRICS_BIT_2F_SPIKE) >> 2); | ||
309 | psmouse_dbg(psmouse, "tp_abs_packet_format_set = %d\n", | ||
310 | (param[7] & TP_METRICS_BIT_ABS_PKT_FORMAT_SET) >> 4); | ||
311 | #endif | ||
312 | |||
313 | return 0; | ||
314 | } | ||
315 | |||
316 | static int cypress_query_hardware(struct psmouse *psmouse) | ||
317 | { | ||
318 | struct cytp_data *cytp = psmouse->private; | ||
319 | int ret; | ||
320 | |||
321 | ret = cypress_read_fw_version(psmouse); | ||
322 | if (ret) | ||
323 | return ret; | ||
324 | |||
325 | if (cytp->tp_metrics_supported) { | ||
326 | ret = cypress_read_tp_metrics(psmouse); | ||
327 | if (ret) | ||
328 | return ret; | ||
329 | } | ||
330 | |||
331 | return 0; | ||
332 | } | ||
333 | |||
334 | static int cypress_set_absolute_mode(struct psmouse *psmouse) | ||
335 | { | ||
336 | struct cytp_data *cytp = psmouse->private; | ||
337 | unsigned char param[3]; | ||
338 | |||
339 | if (cypress_send_ext_cmd(psmouse, CYTP_CMD_ABS_WITH_PRESSURE_MODE, param) < 0) | ||
340 | return -1; | ||
341 | |||
342 | cytp->mode = (cytp->mode & ~CYTP_BIT_ABS_REL_MASK) | ||
343 | | CYTP_BIT_ABS_PRESSURE; | ||
344 | cypress_set_packet_size(psmouse, 5); | ||
345 | |||
346 | return 0; | ||
347 | } | ||
348 | |||
349 | /* | ||
350 | * Reset trackpad device. | ||
351 | * This is also the default mode when trackpad powered on. | ||
352 | */ | ||
353 | static void cypress_reset(struct psmouse *psmouse) | ||
354 | { | ||
355 | struct cytp_data *cytp = psmouse->private; | ||
356 | |||
357 | cytp->mode = 0; | ||
358 | |||
359 | psmouse_reset(psmouse); | ||
360 | } | ||
361 | |||
362 | static int cypress_set_input_params(struct input_dev *input, | ||
363 | struct cytp_data *cytp) | ||
364 | { | ||
365 | int ret; | ||
366 | |||
367 | if (!cytp->tp_res_x || !cytp->tp_res_y) | ||
368 | return -EINVAL; | ||
369 | |||
370 | __set_bit(EV_ABS, input->evbit); | ||
371 | input_set_abs_params(input, ABS_X, 0, cytp->tp_max_abs_x, 0, 0); | ||
372 | input_set_abs_params(input, ABS_Y, 0, cytp->tp_max_abs_y, 0, 0); | ||
373 | input_set_abs_params(input, ABS_PRESSURE, | ||
374 | cytp->tp_min_pressure, cytp->tp_max_pressure, 0, 0); | ||
375 | input_set_abs_params(input, ABS_TOOL_WIDTH, 0, 255, 0, 0); | ||
376 | |||
377 | /* finger position */ | ||
378 | input_set_abs_params(input, ABS_MT_POSITION_X, 0, cytp->tp_max_abs_x, 0, 0); | ||
379 | input_set_abs_params(input, ABS_MT_POSITION_Y, 0, cytp->tp_max_abs_y, 0, 0); | ||
380 | input_set_abs_params(input, ABS_MT_PRESSURE, 0, 255, 0, 0); | ||
381 | |||
382 | ret = input_mt_init_slots(input, CYTP_MAX_MT_SLOTS, | ||
383 | INPUT_MT_DROP_UNUSED|INPUT_MT_TRACK); | ||
384 | if (ret < 0) | ||
385 | return ret; | ||
386 | |||
387 | __set_bit(INPUT_PROP_SEMI_MT, input->propbit); | ||
388 | |||
389 | input_abs_set_res(input, ABS_X, cytp->tp_res_x); | ||
390 | input_abs_set_res(input, ABS_Y, cytp->tp_res_y); | ||
391 | |||
392 | input_abs_set_res(input, ABS_MT_POSITION_X, cytp->tp_res_x); | ||
393 | input_abs_set_res(input, ABS_MT_POSITION_Y, cytp->tp_res_y); | ||
394 | |||
395 | __set_bit(BTN_TOUCH, input->keybit); | ||
396 | __set_bit(BTN_TOOL_FINGER, input->keybit); | ||
397 | __set_bit(BTN_TOOL_DOUBLETAP, input->keybit); | ||
398 | __set_bit(BTN_TOOL_TRIPLETAP, input->keybit); | ||
399 | __set_bit(BTN_TOOL_QUADTAP, input->keybit); | ||
400 | __set_bit(BTN_TOOL_QUINTTAP, input->keybit); | ||
401 | |||
402 | __clear_bit(EV_REL, input->evbit); | ||
403 | __clear_bit(REL_X, input->relbit); | ||
404 | __clear_bit(REL_Y, input->relbit); | ||
405 | |||
406 | __set_bit(INPUT_PROP_BUTTONPAD, input->propbit); | ||
407 | __set_bit(EV_KEY, input->evbit); | ||
408 | __set_bit(BTN_LEFT, input->keybit); | ||
409 | __set_bit(BTN_RIGHT, input->keybit); | ||
410 | __set_bit(BTN_MIDDLE, input->keybit); | ||
411 | |||
412 | input_set_drvdata(input, cytp); | ||
413 | |||
414 | return 0; | ||
415 | } | ||
416 | |||
417 | static int cypress_get_finger_count(unsigned char header_byte) | ||
418 | { | ||
419 | unsigned char bits6_7; | ||
420 | int finger_count; | ||
421 | |||
422 | bits6_7 = header_byte >> 6; | ||
423 | finger_count = bits6_7 & 0x03; | ||
424 | |||
425 | if (finger_count == 1) | ||
426 | return 1; | ||
427 | |||
428 | if (header_byte & ABS_HSCROLL_BIT) { | ||
429 | /* HSCROLL gets added on to 0 finger count. */ | ||
430 | switch (finger_count) { | ||
431 | case 0: return 4; | ||
432 | case 2: return 5; | ||
433 | default: | ||
434 | /* Invalid contact (e.g. palm). Ignore it. */ | ||
435 | return -1; | ||
436 | } | ||
437 | } | ||
438 | |||
439 | return finger_count; | ||
440 | } | ||
441 | |||
442 | |||
443 | static int cypress_parse_packet(struct psmouse *psmouse, | ||
444 | struct cytp_data *cytp, struct cytp_report_data *report_data) | ||
445 | { | ||
446 | unsigned char *packet = psmouse->packet; | ||
447 | unsigned char header_byte = packet[0]; | ||
448 | int contact_cnt; | ||
449 | |||
450 | memset(report_data, 0, sizeof(struct cytp_report_data)); | ||
451 | |||
452 | contact_cnt = cypress_get_finger_count(header_byte); | ||
453 | |||
454 | if (contact_cnt < 0) /* e.g. palm detect */ | ||
455 | return -EINVAL; | ||
456 | |||
457 | report_data->contact_cnt = contact_cnt; | ||
458 | |||
459 | report_data->tap = (header_byte & ABS_MULTIFINGER_TAP) ? 1 : 0; | ||
460 | |||
461 | if (report_data->contact_cnt == 1) { | ||
462 | report_data->contacts[0].x = | ||
463 | ((packet[1] & 0x70) << 4) | packet[2]; | ||
464 | report_data->contacts[0].y = | ||
465 | ((packet[1] & 0x07) << 8) | packet[3]; | ||
466 | if (cytp->mode & CYTP_BIT_ABS_PRESSURE) | ||
467 | report_data->contacts[0].z = packet[4]; | ||
468 | |||
469 | } else if (report_data->contact_cnt >= 2) { | ||
470 | report_data->contacts[0].x = | ||
471 | ((packet[1] & 0x70) << 4) | packet[2]; | ||
472 | report_data->contacts[0].y = | ||
473 | ((packet[1] & 0x07) << 8) | packet[3]; | ||
474 | if (cytp->mode & CYTP_BIT_ABS_PRESSURE) | ||
475 | report_data->contacts[0].z = packet[4]; | ||
476 | |||
477 | report_data->contacts[1].x = | ||
478 | ((packet[5] & 0xf0) << 4) | packet[6]; | ||
479 | report_data->contacts[1].y = | ||
480 | ((packet[5] & 0x0f) << 8) | packet[7]; | ||
481 | if (cytp->mode & CYTP_BIT_ABS_PRESSURE) | ||
482 | report_data->contacts[1].z = report_data->contacts[0].z; | ||
483 | } | ||
484 | |||
485 | report_data->left = (header_byte & BTN_LEFT_BIT) ? 1 : 0; | ||
486 | report_data->right = (header_byte & BTN_RIGHT_BIT) ? 1 : 0; | ||
487 | |||
488 | /* | ||
489 | * This is only true if one of the mouse buttons were tapped. Make | ||
490 | * sure it doesn't turn into a click. The regular tap-to-click | ||
491 | * functionality will handle that on its own. If we don't do this, | ||
492 | * disabling tap-to-click won't affect the mouse button zones. | ||
493 | */ | ||
494 | if (report_data->tap) | ||
495 | report_data->left = 0; | ||
496 | |||
497 | #ifdef CYTP_DEBUG_VERBOSE | ||
498 | { | ||
499 | int i; | ||
500 | int n = report_data->contact_cnt; | ||
501 | psmouse_dbg(psmouse, "Dump parsed report data as below:\n"); | ||
502 | psmouse_dbg(psmouse, "contact_cnt = %d\n", | ||
503 | report_data->contact_cnt); | ||
504 | if (n > CYTP_MAX_MT_SLOTS) | ||
505 | n = CYTP_MAX_MT_SLOTS; | ||
506 | for (i = 0; i < n; i++) | ||
507 | psmouse_dbg(psmouse, "contacts[%d] = {%d, %d, %d}\n", i, | ||
508 | report_data->contacts[i].x, | ||
509 | report_data->contacts[i].y, | ||
510 | report_data->contacts[i].z); | ||
511 | psmouse_dbg(psmouse, "left = %d\n", report_data->left); | ||
512 | psmouse_dbg(psmouse, "right = %d\n", report_data->right); | ||
513 | psmouse_dbg(psmouse, "middle = %d\n", report_data->middle); | ||
514 | } | ||
515 | #endif | ||
516 | |||
517 | return 0; | ||
518 | } | ||
519 | |||
520 | static void cypress_process_packet(struct psmouse *psmouse, bool zero_pkt) | ||
521 | { | ||
522 | int i; | ||
523 | struct input_dev *input = psmouse->dev; | ||
524 | struct cytp_data *cytp = psmouse->private; | ||
525 | struct cytp_report_data report_data; | ||
526 | struct cytp_contact *contact; | ||
527 | struct input_mt_pos pos[CYTP_MAX_MT_SLOTS]; | ||
528 | int slots[CYTP_MAX_MT_SLOTS]; | ||
529 | int n; | ||
530 | |||
531 | if (cypress_parse_packet(psmouse, cytp, &report_data)) | ||
532 | return; | ||
533 | |||
534 | n = report_data.contact_cnt; | ||
535 | |||
536 | if (n > CYTP_MAX_MT_SLOTS) | ||
537 | n = CYTP_MAX_MT_SLOTS; | ||
538 | |||
539 | for (i = 0; i < n; i++) { | ||
540 | contact = &report_data.contacts[i]; | ||
541 | pos[i].x = contact->x; | ||
542 | pos[i].y = contact->y; | ||
543 | } | ||
544 | |||
545 | input_mt_assign_slots(input, slots, pos, n); | ||
546 | |||
547 | for (i = 0; i < n; i++) { | ||
548 | contact = &report_data.contacts[i]; | ||
549 | input_mt_slot(input, slots[i]); | ||
550 | input_mt_report_slot_state(input, MT_TOOL_FINGER, true); | ||
551 | input_report_abs(input, ABS_MT_POSITION_X, contact->x); | ||
552 | input_report_abs(input, ABS_MT_POSITION_Y, contact->y); | ||
553 | input_report_abs(input, ABS_MT_PRESSURE, contact->z); | ||
554 | } | ||
555 | |||
556 | input_mt_sync_frame(input); | ||
557 | |||
558 | input_mt_report_finger_count(input, report_data.contact_cnt); | ||
559 | |||
560 | input_report_key(input, BTN_LEFT, report_data.left); | ||
561 | input_report_key(input, BTN_RIGHT, report_data.right); | ||
562 | input_report_key(input, BTN_MIDDLE, report_data.middle); | ||
563 | |||
564 | input_sync(input); | ||
565 | } | ||
566 | |||
567 | static psmouse_ret_t cypress_validate_byte(struct psmouse *psmouse) | ||
568 | { | ||
569 | int contact_cnt; | ||
570 | int index = psmouse->pktcnt - 1; | ||
571 | unsigned char *packet = psmouse->packet; | ||
572 | struct cytp_data *cytp = psmouse->private; | ||
573 | |||
574 | if (index < 0 || index > cytp->pkt_size) | ||
575 | return PSMOUSE_BAD_DATA; | ||
576 | |||
577 | if (index == 0 && (packet[0] & 0xfc) == 0) { | ||
578 | /* call packet process for reporting finger leave. */ | ||
579 | cypress_process_packet(psmouse, 1); | ||
580 | return PSMOUSE_FULL_PACKET; | ||
581 | } | ||
582 | |||
583 | /* | ||
584 | * Perform validation (and adjust packet size) based only on the | ||
585 | * first byte; allow all further bytes through. | ||
586 | */ | ||
587 | if (index != 0) | ||
588 | return PSMOUSE_GOOD_DATA; | ||
589 | |||
590 | /* | ||
591 | * If absolute/relative mode bit has not been set yet, just pass | ||
592 | * the byte through. | ||
593 | */ | ||
594 | if ((cytp->mode & CYTP_BIT_ABS_REL_MASK) == 0) | ||
595 | return PSMOUSE_GOOD_DATA; | ||
596 | |||
597 | if ((packet[0] & 0x08) == 0x08) | ||
598 | return PSMOUSE_BAD_DATA; | ||
599 | |||
600 | contact_cnt = cypress_get_finger_count(packet[0]); | ||
601 | |||
602 | if (contact_cnt < 0) | ||
603 | return PSMOUSE_BAD_DATA; | ||
604 | |||
605 | if (cytp->mode & CYTP_BIT_ABS_NO_PRESSURE) | ||
606 | cypress_set_packet_size(psmouse, contact_cnt == 2 ? 7 : 4); | ||
607 | else | ||
608 | cypress_set_packet_size(psmouse, contact_cnt == 2 ? 8 : 5); | ||
609 | |||
610 | return PSMOUSE_GOOD_DATA; | ||
611 | } | ||
612 | |||
613 | static psmouse_ret_t cypress_protocol_handler(struct psmouse *psmouse) | ||
614 | { | ||
615 | struct cytp_data *cytp = psmouse->private; | ||
616 | |||
617 | if (psmouse->pktcnt >= cytp->pkt_size) { | ||
618 | cypress_process_packet(psmouse, 0); | ||
619 | return PSMOUSE_FULL_PACKET; | ||
620 | } | ||
621 | |||
622 | return cypress_validate_byte(psmouse); | ||
623 | } | ||
624 | |||
625 | static void cypress_set_rate(struct psmouse *psmouse, unsigned int rate) | ||
626 | { | ||
627 | struct cytp_data *cytp = psmouse->private; | ||
628 | |||
629 | if (rate >= 80) { | ||
630 | psmouse->rate = 80; | ||
631 | cytp->mode |= CYTP_BIT_HIGH_RATE; | ||
632 | } else { | ||
633 | psmouse->rate = 40; | ||
634 | cytp->mode &= ~CYTP_BIT_HIGH_RATE; | ||
635 | } | ||
636 | |||
637 | ps2_command(&psmouse->ps2dev, (unsigned char *)&psmouse->rate, | ||
638 | PSMOUSE_CMD_SETRATE); | ||
639 | } | ||
640 | |||
641 | static void cypress_disconnect(struct psmouse *psmouse) | ||
642 | { | ||
643 | cypress_reset(psmouse); | ||
644 | kfree(psmouse->private); | ||
645 | psmouse->private = NULL; | ||
646 | } | ||
647 | |||
648 | static int cypress_reconnect(struct psmouse *psmouse) | ||
649 | { | ||
650 | int tries = CYTP_PS2_CMD_TRIES; | ||
651 | int rc; | ||
652 | |||
653 | do { | ||
654 | cypress_reset(psmouse); | ||
655 | rc = cypress_detect(psmouse, false); | ||
656 | } while (rc && (--tries > 0)); | ||
657 | |||
658 | if (rc) { | ||
659 | psmouse_err(psmouse, "Reconnect: unable to detect trackpad.\n"); | ||
660 | return -1; | ||
661 | } | ||
662 | |||
663 | if (cypress_set_absolute_mode(psmouse)) { | ||
664 | psmouse_err(psmouse, "Reconnect: Unable to initialize Cypress absolute mode.\n"); | ||
665 | return -1; | ||
666 | } | ||
667 | |||
668 | return 0; | ||
669 | } | ||
670 | |||
671 | int cypress_init(struct psmouse *psmouse) | ||
672 | { | ||
673 | struct cytp_data *cytp; | ||
674 | |||
675 | cytp = (struct cytp_data *)kzalloc(sizeof(struct cytp_data), GFP_KERNEL); | ||
676 | psmouse->private = (void *)cytp; | ||
677 | if (cytp == NULL) | ||
678 | return -ENOMEM; | ||
679 | |||
680 | cypress_reset(psmouse); | ||
681 | |||
682 | psmouse->pktsize = 8; | ||
683 | |||
684 | if (cypress_query_hardware(psmouse)) { | ||
685 | psmouse_err(psmouse, "Unable to query Trackpad hardware.\n"); | ||
686 | goto err_exit; | ||
687 | } | ||
688 | |||
689 | if (cypress_set_absolute_mode(psmouse)) { | ||
690 | psmouse_err(psmouse, "init: Unable to initialize Cypress absolute mode.\n"); | ||
691 | goto err_exit; | ||
692 | } | ||
693 | |||
694 | if (cypress_set_input_params(psmouse->dev, cytp) < 0) { | ||
695 | psmouse_err(psmouse, "init: Unable to set input params.\n"); | ||
696 | goto err_exit; | ||
697 | } | ||
698 | |||
699 | psmouse->model = 1; | ||
700 | psmouse->protocol_handler = cypress_protocol_handler; | ||
701 | psmouse->set_rate = cypress_set_rate; | ||
702 | psmouse->disconnect = cypress_disconnect; | ||
703 | psmouse->reconnect = cypress_reconnect; | ||
704 | psmouse->cleanup = cypress_reset; | ||
705 | psmouse->resync_time = 0; | ||
706 | |||
707 | return 0; | ||
708 | |||
709 | err_exit: | ||
710 | /* | ||
711 | * Reset Cypress Trackpad as a standard mouse. Then | ||
712 | * let psmouse driver commmunicating with it as default PS2 mouse. | ||
713 | */ | ||
714 | cypress_reset(psmouse); | ||
715 | |||
716 | psmouse->private = NULL; | ||
717 | kfree(cytp); | ||
718 | |||
719 | return -1; | ||
720 | } | ||
721 | |||
722 | bool cypress_supported(void) | ||
723 | { | ||
724 | return true; | ||
725 | } | ||
diff --git a/drivers/input/mouse/cypress_ps2.h b/drivers/input/mouse/cypress_ps2.h new file mode 100644 index 000000000000..4720f21d2d70 --- /dev/null +++ b/drivers/input/mouse/cypress_ps2.h | |||
@@ -0,0 +1,191 @@ | |||
1 | #ifndef _CYPRESS_PS2_H | ||
2 | #define _CYPRESS_PS2_H | ||
3 | |||
4 | #include "psmouse.h" | ||
5 | |||
6 | #define CMD_BITS_MASK 0x03 | ||
7 | #define COMPOSIT(x, s) (((x) & CMD_BITS_MASK) << (s)) | ||
8 | |||
9 | #define ENCODE_CMD(aa, bb, cc, dd) \ | ||
10 | (COMPOSIT((aa), 6) | COMPOSIT((bb), 4) | COMPOSIT((cc), 2) | COMPOSIT((dd), 0)) | ||
11 | #define CYTP_CMD_ABS_NO_PRESSURE_MODE ENCODE_CMD(0, 1, 0, 0) | ||
12 | #define CYTP_CMD_ABS_WITH_PRESSURE_MODE ENCODE_CMD(0, 1, 0, 1) | ||
13 | #define CYTP_CMD_SMBUS_MODE ENCODE_CMD(0, 1, 1, 0) | ||
14 | #define CYTP_CMD_STANDARD_MODE ENCODE_CMD(0, 2, 0, 0) /* not implemented yet. */ | ||
15 | #define CYTP_CMD_CYPRESS_REL_MODE ENCODE_CMD(1, 1, 1, 1) /* not implemented yet. */ | ||
16 | #define CYTP_CMD_READ_CYPRESS_ID ENCODE_CMD(0, 0, 0, 0) | ||
17 | #define CYTP_CMD_READ_TP_METRICS ENCODE_CMD(0, 0, 0, 1) | ||
18 | #define CYTP_CMD_SET_HSCROLL_WIDTH(w) ENCODE_CMD(1, 1, 0, (w)) | ||
19 | #define CYTP_CMD_SET_HSCROLL_MASK ENCODE_CMD(1, 1, 0, 0) | ||
20 | #define CYTP_CMD_SET_VSCROLL_WIDTH(w) ENCODE_CMD(1, 2, 0, (w)) | ||
21 | #define CYTP_CMD_SET_VSCROLL_MASK ENCODE_CMD(1, 2, 0, 0) | ||
22 | #define CYTP_CMD_SET_PALM_GEOMETRY(e) ENCODE_CMD(1, 2, 1, (e)) | ||
23 | #define CYTP_CMD_PALM_GEMMETRY_MASK ENCODE_CMD(1, 2, 1, 0) | ||
24 | #define CYTP_CMD_SET_PALM_SENSITIVITY(s) ENCODE_CMD(1, 2, 2, (s)) | ||
25 | #define CYTP_CMD_PALM_SENSITIVITY_MASK ENCODE_CMD(1, 2, 2, 0) | ||
26 | #define CYTP_CMD_SET_MOUSE_SENSITIVITY(s) ENCODE_CMD(1, 3, ((s) >> 2), (s)) | ||
27 | #define CYTP_CMD_MOUSE_SENSITIVITY_MASK ENCODE_CMD(1, 3, 0, 0) | ||
28 | #define CYTP_CMD_REQUEST_BASELINE_STATUS ENCODE_CMD(2, 0, 0, 1) | ||
29 | #define CYTP_CMD_REQUEST_RECALIBRATION ENCODE_CMD(2, 0, 0, 3) | ||
30 | |||
31 | #define DECODE_CMD_AA(x) (((x) >> 6) & CMD_BITS_MASK) | ||
32 | #define DECODE_CMD_BB(x) (((x) >> 4) & CMD_BITS_MASK) | ||
33 | #define DECODE_CMD_CC(x) (((x) >> 2) & CMD_BITS_MASK) | ||
34 | #define DECODE_CMD_DD(x) ((x) & CMD_BITS_MASK) | ||
35 | |||
36 | /* Cypress trackpad working mode. */ | ||
37 | #define CYTP_BIT_ABS_PRESSURE (1 << 3) | ||
38 | #define CYTP_BIT_ABS_NO_PRESSURE (1 << 2) | ||
39 | #define CYTP_BIT_CYPRESS_REL (1 << 1) | ||
40 | #define CYTP_BIT_STANDARD_REL (1 << 0) | ||
41 | #define CYTP_BIT_REL_MASK (CYTP_BIT_CYPRESS_REL | CYTP_BIT_STANDARD_REL) | ||
42 | #define CYTP_BIT_ABS_MASK (CYTP_BIT_ABS_PRESSURE | CYTP_BIT_ABS_NO_PRESSURE) | ||
43 | #define CYTP_BIT_ABS_REL_MASK (CYTP_BIT_ABS_MASK | CYTP_BIT_REL_MASK) | ||
44 | |||
45 | #define CYTP_BIT_HIGH_RATE (1 << 4) | ||
46 | /* | ||
47 | * report mode bit is set, firmware working in Remote Mode. | ||
48 | * report mode bit is cleared, firmware working in Stream Mode. | ||
49 | */ | ||
50 | #define CYTP_BIT_REPORT_MODE (1 << 5) | ||
51 | |||
52 | /* scrolling width values for set HSCROLL and VSCROLL width command. */ | ||
53 | #define SCROLL_WIDTH_NARROW 1 | ||
54 | #define SCROLL_WIDTH_NORMAL 2 | ||
55 | #define SCROLL_WIDTH_WIDE 3 | ||
56 | |||
57 | #define PALM_GEOMETRY_ENABLE 1 | ||
58 | #define PALM_GEOMETRY_DISABLE 0 | ||
59 | |||
60 | #define TP_METRICS_MASK 0x80 | ||
61 | #define FW_VERSION_MASX 0x7f | ||
62 | #define FW_VER_HIGH_MASK 0x70 | ||
63 | #define FW_VER_LOW_MASK 0x0f | ||
64 | |||
65 | /* Times to retry a ps2_command and millisecond delay between tries. */ | ||
66 | #define CYTP_PS2_CMD_TRIES 3 | ||
67 | #define CYTP_PS2_CMD_DELAY 500 | ||
68 | |||
69 | /* time out for PS/2 command only in milliseconds. */ | ||
70 | #define CYTP_CMD_TIMEOUT 200 | ||
71 | #define CYTP_DATA_TIMEOUT 30 | ||
72 | |||
73 | #define CYTP_EXT_CMD 0xe8 | ||
74 | #define CYTP_PS2_RETRY 0xfe | ||
75 | #define CYTP_PS2_ERROR 0xfc | ||
76 | |||
77 | #define CYTP_RESP_RETRY 0x01 | ||
78 | #define CYTP_RESP_ERROR 0xfe | ||
79 | |||
80 | |||
81 | #define CYTP_105001_WIDTH 97 /* Dell XPS 13 */ | ||
82 | #define CYTP_105001_HIGH 59 | ||
83 | #define CYTP_DEFAULT_WIDTH (CYTP_105001_WIDTH) | ||
84 | #define CYTP_DEFAULT_HIGH (CYTP_105001_HIGH) | ||
85 | |||
86 | #define CYTP_ABS_MAX_X 1600 | ||
87 | #define CYTP_ABS_MAX_Y 900 | ||
88 | #define CYTP_MAX_PRESSURE 255 | ||
89 | #define CYTP_MIN_PRESSURE 0 | ||
90 | |||
91 | /* header byte bits of relative package. */ | ||
92 | #define BTN_LEFT_BIT 0x01 | ||
93 | #define BTN_RIGHT_BIT 0x02 | ||
94 | #define BTN_MIDDLE_BIT 0x04 | ||
95 | #define REL_X_SIGN_BIT 0x10 | ||
96 | #define REL_Y_SIGN_BIT 0x20 | ||
97 | |||
98 | /* header byte bits of absolute package. */ | ||
99 | #define ABS_VSCROLL_BIT 0x10 | ||
100 | #define ABS_HSCROLL_BIT 0x20 | ||
101 | #define ABS_MULTIFINGER_TAP 0x04 | ||
102 | #define ABS_EDGE_MOTION_MASK 0x80 | ||
103 | |||
104 | #define DFLT_RESP_BITS_VALID 0x88 /* SMBus bit should not be set. */ | ||
105 | #define DFLT_RESP_SMBUS_BIT 0x80 | ||
106 | #define DFLT_SMBUS_MODE 0x80 | ||
107 | #define DFLT_PS2_MODE 0x00 | ||
108 | #define DFLT_RESP_BIT_MODE 0x40 | ||
109 | #define DFLT_RESP_REMOTE_MODE 0x40 | ||
110 | #define DFLT_RESP_STREAM_MODE 0x00 | ||
111 | #define DFLT_RESP_BIT_REPORTING 0x20 | ||
112 | #define DFLT_RESP_BIT_SCALING 0x10 | ||
113 | |||
114 | #define TP_METRICS_BIT_PALM 0x80 | ||
115 | #define TP_METRICS_BIT_STUBBORN 0x40 | ||
116 | #define TP_METRICS_BIT_2F_JITTER 0x30 | ||
117 | #define TP_METRICS_BIT_1F_JITTER 0x0c | ||
118 | #define TP_METRICS_BIT_APA 0x02 | ||
119 | #define TP_METRICS_BIT_MTG 0x01 | ||
120 | #define TP_METRICS_BIT_ABS_PKT_FORMAT_SET 0xf0 | ||
121 | #define TP_METRICS_BIT_2F_SPIKE 0x0c | ||
122 | #define TP_METRICS_BIT_1F_SPIKE 0x03 | ||
123 | |||
124 | /* bits of first byte response of E9h-Status Request command. */ | ||
125 | #define RESP_BTN_RIGHT_BIT 0x01 | ||
126 | #define RESP_BTN_MIDDLE_BIT 0x02 | ||
127 | #define RESP_BTN_LEFT_BIT 0x04 | ||
128 | #define RESP_SCALING_BIT 0x10 | ||
129 | #define RESP_ENABLE_BIT 0x20 | ||
130 | #define RESP_REMOTE_BIT 0x40 | ||
131 | #define RESP_SMBUS_BIT 0x80 | ||
132 | |||
133 | #define CYTP_MAX_MT_SLOTS 2 | ||
134 | |||
135 | struct cytp_contact { | ||
136 | int x; | ||
137 | int y; | ||
138 | int z; /* also named as touch pressure. */ | ||
139 | }; | ||
140 | |||
141 | /* The structure of Cypress Trackpad event data. */ | ||
142 | struct cytp_report_data { | ||
143 | int contact_cnt; | ||
144 | struct cytp_contact contacts[CYTP_MAX_MT_SLOTS]; | ||
145 | unsigned int left:1; | ||
146 | unsigned int right:1; | ||
147 | unsigned int middle:1; | ||
148 | unsigned int tap:1; /* multi-finger tap detected. */ | ||
149 | }; | ||
150 | |||
151 | /* The structure of Cypress Trackpad device private data. */ | ||
152 | struct cytp_data { | ||
153 | int fw_version; | ||
154 | |||
155 | int pkt_size; | ||
156 | int mode; | ||
157 | |||
158 | int tp_min_pressure; | ||
159 | int tp_max_pressure; | ||
160 | int tp_width; /* X direction physical size in mm. */ | ||
161 | int tp_high; /* Y direction physical size in mm. */ | ||
162 | int tp_max_abs_x; /* Max X absolute units that can be reported. */ | ||
163 | int tp_max_abs_y; /* Max Y absolute units that can be reported. */ | ||
164 | |||
165 | int tp_res_x; /* X resolution in units/mm. */ | ||
166 | int tp_res_y; /* Y resolution in units/mm. */ | ||
167 | |||
168 | int tp_metrics_supported; | ||
169 | }; | ||
170 | |||
171 | |||
172 | #ifdef CONFIG_MOUSE_PS2_CYPRESS | ||
173 | int cypress_detect(struct psmouse *psmouse, bool set_properties); | ||
174 | int cypress_init(struct psmouse *psmouse); | ||
175 | bool cypress_supported(void); | ||
176 | #else | ||
177 | inline int cypress_detect(struct psmouse *psmouse, bool set_properties) | ||
178 | { | ||
179 | return -ENOSYS; | ||
180 | } | ||
181 | inline int cypress_init(struct psmouse *psmouse) | ||
182 | { | ||
183 | return -ENOSYS; | ||
184 | } | ||
185 | inline bool cypress_supported(void) | ||
186 | { | ||
187 | return 0; | ||
188 | } | ||
189 | #endif /* CONFIG_MOUSE_PS2_CYPRESS */ | ||
190 | |||
191 | #endif /* _CYPRESS_PS2_H */ | ||
diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c index 22fe2547e169..cff065f6261c 100644 --- a/drivers/input/mouse/psmouse-base.c +++ b/drivers/input/mouse/psmouse-base.c | |||
@@ -34,6 +34,7 @@ | |||
34 | #include "touchkit_ps2.h" | 34 | #include "touchkit_ps2.h" |
35 | #include "elantech.h" | 35 | #include "elantech.h" |
36 | #include "sentelic.h" | 36 | #include "sentelic.h" |
37 | #include "cypress_ps2.h" | ||
37 | 38 | ||
38 | #define DRIVER_DESC "PS/2 mouse driver" | 39 | #define DRIVER_DESC "PS/2 mouse driver" |
39 | 40 | ||
@@ -759,6 +760,28 @@ static int psmouse_extensions(struct psmouse *psmouse, | |||
759 | } | 760 | } |
760 | 761 | ||
761 | /* | 762 | /* |
763 | * Try Cypress Trackpad. | ||
764 | * Must try it before Finger Sensing Pad because Finger Sensing Pad probe | ||
765 | * upsets some modules of Cypress Trackpads. | ||
766 | */ | ||
767 | if (max_proto > PSMOUSE_IMEX && | ||
768 | cypress_detect(psmouse, set_properties) == 0) { | ||
769 | if (cypress_supported()) { | ||
770 | if (cypress_init(psmouse) == 0) | ||
771 | return PSMOUSE_CYPRESS; | ||
772 | |||
773 | /* | ||
774 | * Finger Sensing Pad probe upsets some modules of | ||
775 | * Cypress Trackpad, must avoid Finger Sensing Pad | ||
776 | * probe if Cypress Trackpad device detected. | ||
777 | */ | ||
778 | return PSMOUSE_PS2; | ||
779 | } | ||
780 | |||
781 | max_proto = PSMOUSE_IMEX; | ||
782 | } | ||
783 | |||
784 | /* | ||
762 | * Try ALPS TouchPad | 785 | * Try ALPS TouchPad |
763 | */ | 786 | */ |
764 | if (max_proto > PSMOUSE_IMEX) { | 787 | if (max_proto > PSMOUSE_IMEX) { |
@@ -896,6 +919,15 @@ static const struct psmouse_protocol psmouse_protocols[] = { | |||
896 | .alias = "thinkps", | 919 | .alias = "thinkps", |
897 | .detect = thinking_detect, | 920 | .detect = thinking_detect, |
898 | }, | 921 | }, |
922 | #ifdef CONFIG_MOUSE_PS2_CYPRESS | ||
923 | { | ||
924 | .type = PSMOUSE_CYPRESS, | ||
925 | .name = "CyPS/2", | ||
926 | .alias = "cypress", | ||
927 | .detect = cypress_detect, | ||
928 | .init = cypress_init, | ||
929 | }, | ||
930 | #endif | ||
899 | { | 931 | { |
900 | .type = PSMOUSE_GENPS, | 932 | .type = PSMOUSE_GENPS, |
901 | .name = "GenPS/2", | 933 | .name = "GenPS/2", |
diff --git a/drivers/input/mouse/psmouse.h b/drivers/input/mouse/psmouse.h index fe1df231ba4c..2f0b39d59a9b 100644 --- a/drivers/input/mouse/psmouse.h +++ b/drivers/input/mouse/psmouse.h | |||
@@ -95,6 +95,7 @@ enum psmouse_type { | |||
95 | PSMOUSE_ELANTECH, | 95 | PSMOUSE_ELANTECH, |
96 | PSMOUSE_FSP, | 96 | PSMOUSE_FSP, |
97 | PSMOUSE_SYNAPTICS_RELATIVE, | 97 | PSMOUSE_SYNAPTICS_RELATIVE, |
98 | PSMOUSE_CYPRESS, | ||
98 | PSMOUSE_AUTO /* This one should always be last */ | 99 | PSMOUSE_AUTO /* This one should always be last */ |
99 | }; | 100 | }; |
100 | 101 | ||
diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c index 12d12ca3fee0..2f78538e09d0 100644 --- a/drivers/input/mouse/synaptics.c +++ b/drivers/input/mouse/synaptics.c | |||
@@ -722,11 +722,13 @@ static void synaptics_report_mt_data(struct psmouse *psmouse, | |||
722 | default: | 722 | default: |
723 | /* | 723 | /* |
724 | * If the finger slot contained in SGM is valid, and either | 724 | * If the finger slot contained in SGM is valid, and either |
725 | * hasn't changed, or is new, then report SGM in MTB slot 0. | 725 | * hasn't changed, or is new, or the old SGM has now moved to |
726 | * AGM, then report SGM in MTB slot 0. | ||
726 | * Otherwise, empty MTB slot 0. | 727 | * Otherwise, empty MTB slot 0. |
727 | */ | 728 | */ |
728 | if (mt_state->sgm != -1 && | 729 | if (mt_state->sgm != -1 && |
729 | (mt_state->sgm == old->sgm || old->sgm == -1)) | 730 | (mt_state->sgm == old->sgm || |
731 | old->sgm == -1 || mt_state->agm == old->sgm)) | ||
730 | synaptics_report_slot(dev, 0, sgm); | 732 | synaptics_report_slot(dev, 0, sgm); |
731 | else | 733 | else |
732 | synaptics_report_slot(dev, 0, NULL); | 734 | synaptics_report_slot(dev, 0, NULL); |
@@ -735,9 +737,31 @@ static void synaptics_report_mt_data(struct psmouse *psmouse, | |||
735 | * If the finger slot contained in AGM is valid, and either | 737 | * If the finger slot contained in AGM is valid, and either |
736 | * hasn't changed, or is new, then report AGM in MTB slot 1. | 738 | * hasn't changed, or is new, then report AGM in MTB slot 1. |
737 | * Otherwise, empty MTB slot 1. | 739 | * Otherwise, empty MTB slot 1. |
740 | * | ||
741 | * However, in the case where the AGM is new, make sure that | ||
742 | * that it is either the same as the old SGM, or there was no | ||
743 | * SGM. | ||
744 | * | ||
745 | * Otherwise, if the SGM was just 1, and the new AGM is 2, then | ||
746 | * the new AGM will keep the old SGM's tracking ID, which can | ||
747 | * cause apparent drumroll. This happens if in the following | ||
748 | * valid finger sequence: | ||
749 | * | ||
750 | * Action SGM AGM (MTB slot:Contact) | ||
751 | * 1. Touch contact 0 (0:0) | ||
752 | * 2. Touch contact 1 (0:0, 1:1) | ||
753 | * 3. Lift contact 0 (1:1) | ||
754 | * 4. Touch contacts 2,3 (0:2, 1:3) | ||
755 | * | ||
756 | * In step 4, contact 3, in AGM must not be given the same | ||
757 | * tracking ID as contact 1 had in step 3. To avoid this, | ||
758 | * the first agm with contact 3 is dropped and slot 1 is | ||
759 | * invalidated (tracking ID = -1). | ||
738 | */ | 760 | */ |
739 | if (mt_state->agm != -1 && | 761 | if (mt_state->agm != -1 && |
740 | (mt_state->agm == old->agm || old->agm == -1)) | 762 | (mt_state->agm == old->agm || |
763 | (old->agm == -1 && | ||
764 | (old->sgm == -1 || mt_state->agm == old->sgm)))) | ||
741 | synaptics_report_slot(dev, 1, agm); | 765 | synaptics_report_slot(dev, 1, agm); |
742 | else | 766 | else |
743 | synaptics_report_slot(dev, 1, NULL); | 767 | synaptics_report_slot(dev, 1, NULL); |
@@ -1247,11 +1271,11 @@ static void set_input_params(struct input_dev *dev, struct synaptics_data *priv) | |||
1247 | input_set_abs_params(dev, ABS_PRESSURE, 0, 255, 0, 0); | 1271 | input_set_abs_params(dev, ABS_PRESSURE, 0, 255, 0, 0); |
1248 | 1272 | ||
1249 | if (SYN_CAP_IMAGE_SENSOR(priv->ext_cap_0c)) { | 1273 | if (SYN_CAP_IMAGE_SENSOR(priv->ext_cap_0c)) { |
1250 | input_mt_init_slots(dev, 2, 0); | ||
1251 | set_abs_position_params(dev, priv, ABS_MT_POSITION_X, | 1274 | set_abs_position_params(dev, priv, ABS_MT_POSITION_X, |
1252 | ABS_MT_POSITION_Y); | 1275 | ABS_MT_POSITION_Y); |
1253 | /* Image sensors can report per-contact pressure */ | 1276 | /* Image sensors can report per-contact pressure */ |
1254 | input_set_abs_params(dev, ABS_MT_PRESSURE, 0, 255, 0, 0); | 1277 | input_set_abs_params(dev, ABS_MT_PRESSURE, 0, 255, 0, 0); |
1278 | input_mt_init_slots(dev, 2, INPUT_MT_POINTER); | ||
1255 | 1279 | ||
1256 | /* Image sensors can signal 4 and 5 finger clicks */ | 1280 | /* Image sensors can signal 4 and 5 finger clicks */ |
1257 | __set_bit(BTN_TOOL_QUADTAP, dev->keybit); | 1281 | __set_bit(BTN_TOOL_QUADTAP, dev->keybit); |