diff options
Diffstat (limited to 'drivers/input/mouse')
-rw-r--r-- | drivers/input/mouse/hgpk.c | 695 | ||||
-rw-r--r-- | drivers/input/mouse/hgpk.h | 31 | ||||
-rw-r--r-- | drivers/input/mouse/psmouse-base.c | 1 | ||||
-rw-r--r-- | drivers/input/mouse/synaptics.c | 129 | ||||
-rw-r--r-- | drivers/input/mouse/synaptics.h | 3 |
5 files changed, 770 insertions, 89 deletions
diff --git a/drivers/input/mouse/hgpk.c b/drivers/input/mouse/hgpk.c index 1d2205b24800..95577c15ae56 100644 --- a/drivers/input/mouse/hgpk.c +++ b/drivers/input/mouse/hgpk.c | |||
@@ -40,6 +40,8 @@ | |||
40 | #include "psmouse.h" | 40 | #include "psmouse.h" |
41 | #include "hgpk.h" | 41 | #include "hgpk.h" |
42 | 42 | ||
43 | #define ILLEGAL_XY 999999 | ||
44 | |||
43 | static bool tpdebug; | 45 | static bool tpdebug; |
44 | module_param(tpdebug, bool, 0644); | 46 | module_param(tpdebug, bool, 0644); |
45 | MODULE_PARM_DESC(tpdebug, "enable debugging, dumping packets to KERN_DEBUG."); | 47 | MODULE_PARM_DESC(tpdebug, "enable debugging, dumping packets to KERN_DEBUG."); |
@@ -47,48 +49,150 @@ MODULE_PARM_DESC(tpdebug, "enable debugging, dumping packets to KERN_DEBUG."); | |||
47 | static int recalib_delta = 100; | 49 | static int recalib_delta = 100; |
48 | module_param(recalib_delta, int, 0644); | 50 | module_param(recalib_delta, int, 0644); |
49 | MODULE_PARM_DESC(recalib_delta, | 51 | MODULE_PARM_DESC(recalib_delta, |
50 | "packets containing a delta this large will cause a recalibration."); | 52 | "packets containing a delta this large will be discarded, and a " |
53 | "recalibration may be scheduled."); | ||
51 | 54 | ||
52 | static int jumpy_delay = 1000; | 55 | static int jumpy_delay = 20; |
53 | module_param(jumpy_delay, int, 0644); | 56 | module_param(jumpy_delay, int, 0644); |
54 | MODULE_PARM_DESC(jumpy_delay, | 57 | MODULE_PARM_DESC(jumpy_delay, |
55 | "delay (ms) before recal after jumpiness detected"); | 58 | "delay (ms) before recal after jumpiness detected"); |
56 | 59 | ||
57 | static int spew_delay = 1000; | 60 | static int spew_delay = 1; |
58 | module_param(spew_delay, int, 0644); | 61 | module_param(spew_delay, int, 0644); |
59 | MODULE_PARM_DESC(spew_delay, | 62 | MODULE_PARM_DESC(spew_delay, |
60 | "delay (ms) before recal after packet spew detected"); | 63 | "delay (ms) before recal after packet spew detected"); |
61 | 64 | ||
62 | static int recal_guard_time = 2000; | 65 | static int recal_guard_time; |
63 | module_param(recal_guard_time, int, 0644); | 66 | module_param(recal_guard_time, int, 0644); |
64 | MODULE_PARM_DESC(recal_guard_time, | 67 | MODULE_PARM_DESC(recal_guard_time, |
65 | "interval (ms) during which recal will be restarted if packet received"); | 68 | "interval (ms) during which recal will be restarted if packet received"); |
66 | 69 | ||
67 | static int post_interrupt_delay = 1000; | 70 | static int post_interrupt_delay = 40; |
68 | module_param(post_interrupt_delay, int, 0644); | 71 | module_param(post_interrupt_delay, int, 0644); |
69 | MODULE_PARM_DESC(post_interrupt_delay, | 72 | MODULE_PARM_DESC(post_interrupt_delay, |
70 | "delay (ms) before recal after recal interrupt detected"); | 73 | "delay (ms) before recal after recal interrupt detected"); |
71 | 74 | ||
75 | static bool autorecal = true; | ||
76 | module_param(autorecal, bool, 0644); | ||
77 | MODULE_PARM_DESC(autorecal, "enable recalibration in the driver"); | ||
78 | |||
79 | static char hgpk_mode_name[16]; | ||
80 | module_param_string(hgpk_mode, hgpk_mode_name, sizeof(hgpk_mode_name), 0644); | ||
81 | MODULE_PARM_DESC(hgpk_mode, | ||
82 | "default hgpk mode: mouse, glidesensor or pentablet"); | ||
83 | |||
84 | static int hgpk_default_mode = HGPK_MODE_MOUSE; | ||
85 | |||
86 | static const char * const hgpk_mode_names[] = { | ||
87 | [HGPK_MODE_MOUSE] = "Mouse", | ||
88 | [HGPK_MODE_GLIDESENSOR] = "GlideSensor", | ||
89 | [HGPK_MODE_PENTABLET] = "PenTablet", | ||
90 | }; | ||
91 | |||
92 | static int hgpk_mode_from_name(const char *buf, int len) | ||
93 | { | ||
94 | int i; | ||
95 | |||
96 | for (i = 0; i < ARRAY_SIZE(hgpk_mode_names); i++) { | ||
97 | const char *name = hgpk_mode_names[i]; | ||
98 | if (strlen(name) == len && !strncasecmp(name, buf, len)) | ||
99 | return i; | ||
100 | } | ||
101 | |||
102 | return HGPK_MODE_INVALID; | ||
103 | } | ||
104 | |||
105 | /* | ||
106 | * see if new value is within 20% of half of old value | ||
107 | */ | ||
108 | static int approx_half(int curr, int prev) | ||
109 | { | ||
110 | int belowhalf, abovehalf; | ||
111 | |||
112 | if (curr < 5 || prev < 5) | ||
113 | return 0; | ||
114 | |||
115 | belowhalf = (prev * 8) / 20; | ||
116 | abovehalf = (prev * 12) / 20; | ||
117 | |||
118 | return belowhalf < curr && curr <= abovehalf; | ||
119 | } | ||
120 | |||
72 | /* | 121 | /* |
73 | * When the touchpad gets ultra-sensitive, one can keep their finger 1/2" | 122 | * Throw out oddly large delta packets, and any that immediately follow whose |
74 | * above the pad and still have it send packets. This causes a jump cursor | 123 | * values are each approximately half of the previous. It seems that the ALPS |
75 | * when one places their finger on the pad. We can probably detect the | 124 | * firmware emits errant packets, and they get averaged out slowly. |
76 | * jump as we see a large deltas (>= 100px). In mouse mode, I've been | ||
77 | * unable to even come close to 100px deltas during normal usage, so I think | ||
78 | * this threshold is safe. If a large delta occurs, trigger a recalibration. | ||
79 | */ | 125 | */ |
80 | static void hgpk_jumpy_hack(struct psmouse *psmouse, int x, int y) | 126 | static int hgpk_discard_decay_hack(struct psmouse *psmouse, int x, int y) |
81 | { | 127 | { |
82 | struct hgpk_data *priv = psmouse->private; | 128 | struct hgpk_data *priv = psmouse->private; |
129 | int avx, avy; | ||
130 | bool do_recal = false; | ||
131 | |||
132 | avx = abs(x); | ||
133 | avy = abs(y); | ||
134 | |||
135 | /* discard if too big, or half that but > 4 times the prev delta */ | ||
136 | if (avx > recalib_delta || | ||
137 | (avx > recalib_delta / 2 && ((avx / 4) > priv->xlast))) { | ||
138 | hgpk_err(psmouse, "detected %dpx jump in x\n", x); | ||
139 | priv->xbigj = avx; | ||
140 | } else if (approx_half(avx, priv->xbigj)) { | ||
141 | hgpk_err(psmouse, "detected secondary %dpx jump in x\n", x); | ||
142 | priv->xbigj = avx; | ||
143 | priv->xsaw_secondary++; | ||
144 | } else { | ||
145 | if (priv->xbigj && priv->xsaw_secondary > 1) | ||
146 | do_recal = true; | ||
147 | priv->xbigj = 0; | ||
148 | priv->xsaw_secondary = 0; | ||
149 | } | ||
150 | |||
151 | if (avy > recalib_delta || | ||
152 | (avy > recalib_delta / 2 && ((avy / 4) > priv->ylast))) { | ||
153 | hgpk_err(psmouse, "detected %dpx jump in y\n", y); | ||
154 | priv->ybigj = avy; | ||
155 | } else if (approx_half(avy, priv->ybigj)) { | ||
156 | hgpk_err(psmouse, "detected secondary %dpx jump in y\n", y); | ||
157 | priv->ybigj = avy; | ||
158 | priv->ysaw_secondary++; | ||
159 | } else { | ||
160 | if (priv->ybigj && priv->ysaw_secondary > 1) | ||
161 | do_recal = true; | ||
162 | priv->ybigj = 0; | ||
163 | priv->ysaw_secondary = 0; | ||
164 | } | ||
83 | 165 | ||
84 | if (abs(x) > recalib_delta || abs(y) > recalib_delta) { | 166 | priv->xlast = avx; |
85 | hgpk_err(psmouse, ">%dpx jump detected (%d,%d)\n", | 167 | priv->ylast = avy; |
86 | recalib_delta, x, y); | 168 | |
87 | /* My car gets forty rods to the hogshead and that's the | 169 | if (do_recal && jumpy_delay) { |
88 | * way I likes it! */ | 170 | hgpk_err(psmouse, "scheduling recalibration\n"); |
89 | psmouse_queue_work(psmouse, &priv->recalib_wq, | 171 | psmouse_queue_work(psmouse, &priv->recalib_wq, |
90 | msecs_to_jiffies(jumpy_delay)); | 172 | msecs_to_jiffies(jumpy_delay)); |
91 | } | 173 | } |
174 | |||
175 | return priv->xbigj || priv->ybigj; | ||
176 | } | ||
177 | |||
178 | static void hgpk_reset_spew_detection(struct hgpk_data *priv) | ||
179 | { | ||
180 | priv->spew_count = 0; | ||
181 | priv->dupe_count = 0; | ||
182 | priv->x_tally = 0; | ||
183 | priv->y_tally = 0; | ||
184 | priv->spew_flag = NO_SPEW; | ||
185 | } | ||
186 | |||
187 | static void hgpk_reset_hack_state(struct psmouse *psmouse) | ||
188 | { | ||
189 | struct hgpk_data *priv = psmouse->private; | ||
190 | |||
191 | priv->abs_x = priv->abs_y = -1; | ||
192 | priv->xlast = priv->ylast = ILLEGAL_XY; | ||
193 | priv->xbigj = priv->ybigj = 0; | ||
194 | priv->xsaw_secondary = priv->ysaw_secondary = 0; | ||
195 | hgpk_reset_spew_detection(priv); | ||
92 | } | 196 | } |
93 | 197 | ||
94 | /* | 198 | /* |
@@ -116,20 +220,57 @@ static void hgpk_spewing_hack(struct psmouse *psmouse, | |||
116 | if (l || r) | 220 | if (l || r) |
117 | return; | 221 | return; |
118 | 222 | ||
223 | /* don't track spew if the workaround feature has been turned off */ | ||
224 | if (!spew_delay) | ||
225 | return; | ||
226 | |||
227 | if (abs(x) > 3 || abs(y) > 3) { | ||
228 | /* no spew, or spew ended */ | ||
229 | hgpk_reset_spew_detection(priv); | ||
230 | return; | ||
231 | } | ||
232 | |||
233 | /* Keep a tally of the overall delta to the cursor position caused by | ||
234 | * the spew */ | ||
119 | priv->x_tally += x; | 235 | priv->x_tally += x; |
120 | priv->y_tally += y; | 236 | priv->y_tally += y; |
121 | 237 | ||
122 | if (++priv->count > 100) { | 238 | switch (priv->spew_flag) { |
239 | case NO_SPEW: | ||
240 | /* we're not spewing, but this packet might be the start */ | ||
241 | priv->spew_flag = MAYBE_SPEWING; | ||
242 | |||
243 | /* fall-through */ | ||
244 | |||
245 | case MAYBE_SPEWING: | ||
246 | priv->spew_count++; | ||
247 | |||
248 | if (priv->spew_count < SPEW_WATCH_COUNT) | ||
249 | break; | ||
250 | |||
251 | /* excessive spew detected, request recalibration */ | ||
252 | priv->spew_flag = SPEW_DETECTED; | ||
253 | |||
254 | /* fall-through */ | ||
255 | |||
256 | case SPEW_DETECTED: | ||
257 | /* only recalibrate when the overall delta to the cursor | ||
258 | * is really small. if the spew is causing significant cursor | ||
259 | * movement, it is probably a case of the user moving the | ||
260 | * cursor very slowly across the screen. */ | ||
123 | if (abs(priv->x_tally) < 3 && abs(priv->y_tally) < 3) { | 261 | if (abs(priv->x_tally) < 3 && abs(priv->y_tally) < 3) { |
124 | hgpk_dbg(psmouse, "packet spew detected (%d,%d)\n", | 262 | hgpk_err(psmouse, "packet spew detected (%d,%d)\n", |
125 | priv->x_tally, priv->y_tally); | 263 | priv->x_tally, priv->y_tally); |
264 | priv->spew_flag = RECALIBRATING; | ||
126 | psmouse_queue_work(psmouse, &priv->recalib_wq, | 265 | psmouse_queue_work(psmouse, &priv->recalib_wq, |
127 | msecs_to_jiffies(spew_delay)); | 266 | msecs_to_jiffies(spew_delay)); |
128 | } | 267 | } |
129 | /* reset every 100 packets */ | 268 | |
130 | priv->count = 0; | 269 | break; |
131 | priv->x_tally = 0; | 270 | case RECALIBRATING: |
132 | priv->y_tally = 0; | 271 | /* we already detected a spew and requested a recalibration, |
272 | * just wait for the queue to kick into action. */ | ||
273 | break; | ||
133 | } | 274 | } |
134 | } | 275 | } |
135 | 276 | ||
@@ -143,25 +284,168 @@ static void hgpk_spewing_hack(struct psmouse *psmouse, | |||
143 | * swr/swl are the left/right buttons. | 284 | * swr/swl are the left/right buttons. |
144 | * x-neg/y-neg are the x and y delta negative bits | 285 | * x-neg/y-neg are the x and y delta negative bits |
145 | * x-over/y-over are the x and y overflow bits | 286 | * x-over/y-over are the x and y overflow bits |
287 | * | ||
288 | * --- | ||
289 | * | ||
290 | * HGPK Advanced Mode - single-mode format | ||
291 | * | ||
292 | * byte 0(PT): 1 1 0 0 1 1 1 1 | ||
293 | * byte 0(GS): 1 1 1 1 1 1 1 1 | ||
294 | * byte 1: 0 x6 x5 x4 x3 x2 x1 x0 | ||
295 | * byte 2(PT): 0 0 x9 x8 x7 ? pt-dsw 0 | ||
296 | * byte 2(GS): 0 x10 x9 x8 x7 ? gs-dsw pt-dsw | ||
297 | * byte 3: 0 y9 y8 y7 1 0 swr swl | ||
298 | * byte 4: 0 y6 y5 y4 y3 y2 y1 y0 | ||
299 | * byte 5: 0 z6 z5 z4 z3 z2 z1 z0 | ||
300 | * | ||
301 | * ?'s are not defined in the protocol spec, may vary between models. | ||
302 | * | ||
303 | * swr/swl are the left/right buttons. | ||
304 | * | ||
305 | * pt-dsw/gs-dsw indicate that the pt/gs sensor is detecting a | ||
306 | * pen/finger | ||
146 | */ | 307 | */ |
147 | static int hgpk_validate_byte(unsigned char *packet) | 308 | static bool hgpk_is_byte_valid(struct psmouse *psmouse, unsigned char *packet) |
148 | { | 309 | { |
149 | return (packet[0] & 0x0C) != 0x08; | 310 | struct hgpk_data *priv = psmouse->private; |
311 | int pktcnt = psmouse->pktcnt; | ||
312 | bool valid; | ||
313 | |||
314 | switch (priv->mode) { | ||
315 | case HGPK_MODE_MOUSE: | ||
316 | valid = (packet[0] & 0x0C) == 0x08; | ||
317 | break; | ||
318 | |||
319 | case HGPK_MODE_GLIDESENSOR: | ||
320 | valid = pktcnt == 1 ? | ||
321 | packet[0] == HGPK_GS : !(packet[pktcnt - 1] & 0x80); | ||
322 | break; | ||
323 | |||
324 | case HGPK_MODE_PENTABLET: | ||
325 | valid = pktcnt == 1 ? | ||
326 | packet[0] == HGPK_PT : !(packet[pktcnt - 1] & 0x80); | ||
327 | break; | ||
328 | |||
329 | default: | ||
330 | valid = false; | ||
331 | break; | ||
332 | } | ||
333 | |||
334 | if (!valid) | ||
335 | hgpk_dbg(psmouse, | ||
336 | "bad data, mode %d (%d) %02x %02x %02x %02x %02x %02x\n", | ||
337 | priv->mode, pktcnt, | ||
338 | psmouse->packet[0], psmouse->packet[1], | ||
339 | psmouse->packet[2], psmouse->packet[3], | ||
340 | psmouse->packet[4], psmouse->packet[5]); | ||
341 | |||
342 | return valid; | ||
150 | } | 343 | } |
151 | 344 | ||
152 | static void hgpk_process_packet(struct psmouse *psmouse) | 345 | static void hgpk_process_advanced_packet(struct psmouse *psmouse) |
153 | { | 346 | { |
154 | struct input_dev *dev = psmouse->dev; | 347 | struct hgpk_data *priv = psmouse->private; |
348 | struct input_dev *idev = psmouse->dev; | ||
155 | unsigned char *packet = psmouse->packet; | 349 | unsigned char *packet = psmouse->packet; |
156 | int x, y, left, right; | 350 | int down = !!(packet[2] & 2); |
351 | int left = !!(packet[3] & 1); | ||
352 | int right = !!(packet[3] & 2); | ||
353 | int x = packet[1] | ((packet[2] & 0x78) << 4); | ||
354 | int y = packet[4] | ((packet[3] & 0x70) << 3); | ||
355 | |||
356 | if (priv->mode == HGPK_MODE_GLIDESENSOR) { | ||
357 | int pt_down = !!(packet[2] & 1); | ||
358 | int finger_down = !!(packet[2] & 2); | ||
359 | int z = packet[5]; | ||
360 | |||
361 | input_report_abs(idev, ABS_PRESSURE, z); | ||
362 | if (tpdebug) | ||
363 | hgpk_dbg(psmouse, "pd=%d fd=%d z=%d", | ||
364 | pt_down, finger_down, z); | ||
365 | } else { | ||
366 | /* | ||
367 | * PenTablet mode does not report pressure, so we don't | ||
368 | * report it here | ||
369 | */ | ||
370 | if (tpdebug) | ||
371 | hgpk_dbg(psmouse, "pd=%d ", down); | ||
372 | } | ||
373 | |||
374 | if (tpdebug) | ||
375 | hgpk_dbg(psmouse, "l=%d r=%d x=%d y=%d\n", left, right, x, y); | ||
376 | |||
377 | input_report_key(idev, BTN_TOUCH, down); | ||
378 | input_report_key(idev, BTN_LEFT, left); | ||
379 | input_report_key(idev, BTN_RIGHT, right); | ||
380 | |||
381 | /* | ||
382 | * If this packet says that the finger was removed, reset our position | ||
383 | * tracking so that we don't erroneously detect a jump on next press. | ||
384 | */ | ||
385 | if (!down) { | ||
386 | hgpk_reset_hack_state(psmouse); | ||
387 | goto done; | ||
388 | } | ||
389 | |||
390 | /* | ||
391 | * Weed out duplicate packets (we get quite a few, and they mess up | ||
392 | * our jump detection) | ||
393 | */ | ||
394 | if (x == priv->abs_x && y == priv->abs_y) { | ||
395 | if (++priv->dupe_count > SPEW_WATCH_COUNT) { | ||
396 | if (tpdebug) | ||
397 | hgpk_dbg(psmouse, "hard spew detected\n"); | ||
398 | priv->spew_flag = RECALIBRATING; | ||
399 | psmouse_queue_work(psmouse, &priv->recalib_wq, | ||
400 | msecs_to_jiffies(spew_delay)); | ||
401 | } | ||
402 | goto done; | ||
403 | } | ||
157 | 404 | ||
158 | left = packet[0] & 1; | 405 | /* not a duplicate, continue with position reporting */ |
159 | right = (packet[0] >> 1) & 1; | 406 | priv->dupe_count = 0; |
407 | |||
408 | /* Don't apply hacks in PT mode, it seems reliable */ | ||
409 | if (priv->mode != HGPK_MODE_PENTABLET && priv->abs_x != -1) { | ||
410 | int x_diff = priv->abs_x - x; | ||
411 | int y_diff = priv->abs_y - y; | ||
412 | if (hgpk_discard_decay_hack(psmouse, x_diff, y_diff)) { | ||
413 | if (tpdebug) | ||
414 | hgpk_dbg(psmouse, "discarding\n"); | ||
415 | goto done; | ||
416 | } | ||
417 | hgpk_spewing_hack(psmouse, left, right, x_diff, y_diff); | ||
418 | } | ||
160 | 419 | ||
161 | x = packet[1] - ((packet[0] << 4) & 0x100); | 420 | input_report_abs(idev, ABS_X, x); |
162 | y = ((packet[0] << 3) & 0x100) - packet[2]; | 421 | input_report_abs(idev, ABS_Y, y); |
422 | priv->abs_x = x; | ||
423 | priv->abs_y = y; | ||
424 | |||
425 | done: | ||
426 | input_sync(idev); | ||
427 | } | ||
428 | |||
429 | static void hgpk_process_simple_packet(struct psmouse *psmouse) | ||
430 | { | ||
431 | struct input_dev *dev = psmouse->dev; | ||
432 | unsigned char *packet = psmouse->packet; | ||
433 | int left = packet[0] & 1; | ||
434 | int right = (packet[0] >> 1) & 1; | ||
435 | int x = packet[1] - ((packet[0] << 4) & 0x100); | ||
436 | int y = ((packet[0] << 3) & 0x100) - packet[2]; | ||
437 | |||
438 | if (packet[0] & 0xc0) | ||
439 | hgpk_dbg(psmouse, | ||
440 | "overflow -- 0x%02x 0x%02x 0x%02x\n", | ||
441 | packet[0], packet[1], packet[2]); | ||
442 | |||
443 | if (hgpk_discard_decay_hack(psmouse, x, y)) { | ||
444 | if (tpdebug) | ||
445 | hgpk_dbg(psmouse, "discarding\n"); | ||
446 | return; | ||
447 | } | ||
163 | 448 | ||
164 | hgpk_jumpy_hack(psmouse, x, y); | ||
165 | hgpk_spewing_hack(psmouse, left, right, x, y); | 449 | hgpk_spewing_hack(psmouse, left, right, x, y); |
166 | 450 | ||
167 | if (tpdebug) | 451 | if (tpdebug) |
@@ -180,15 +464,14 @@ static psmouse_ret_t hgpk_process_byte(struct psmouse *psmouse) | |||
180 | { | 464 | { |
181 | struct hgpk_data *priv = psmouse->private; | 465 | struct hgpk_data *priv = psmouse->private; |
182 | 466 | ||
183 | if (hgpk_validate_byte(psmouse->packet)) { | 467 | if (!hgpk_is_byte_valid(psmouse, psmouse->packet)) |
184 | hgpk_dbg(psmouse, "%s: (%d) %02x %02x %02x\n", | ||
185 | __func__, psmouse->pktcnt, psmouse->packet[0], | ||
186 | psmouse->packet[1], psmouse->packet[2]); | ||
187 | return PSMOUSE_BAD_DATA; | 468 | return PSMOUSE_BAD_DATA; |
188 | } | ||
189 | 469 | ||
190 | if (psmouse->pktcnt >= psmouse->pktsize) { | 470 | if (psmouse->pktcnt >= psmouse->pktsize) { |
191 | hgpk_process_packet(psmouse); | 471 | if (priv->mode == HGPK_MODE_MOUSE) |
472 | hgpk_process_simple_packet(psmouse); | ||
473 | else | ||
474 | hgpk_process_advanced_packet(psmouse); | ||
192 | return PSMOUSE_FULL_PACKET; | 475 | return PSMOUSE_FULL_PACKET; |
193 | } | 476 | } |
194 | 477 | ||
@@ -210,33 +493,176 @@ static psmouse_ret_t hgpk_process_byte(struct psmouse *psmouse) | |||
210 | return PSMOUSE_GOOD_DATA; | 493 | return PSMOUSE_GOOD_DATA; |
211 | } | 494 | } |
212 | 495 | ||
496 | static int hgpk_select_mode(struct psmouse *psmouse) | ||
497 | { | ||
498 | struct ps2dev *ps2dev = &psmouse->ps2dev; | ||
499 | struct hgpk_data *priv = psmouse->private; | ||
500 | int i; | ||
501 | int cmd; | ||
502 | |||
503 | /* | ||
504 | * 4 disables to enable advanced mode | ||
505 | * then 3 0xf2 bytes as the preamble for GS/PT selection | ||
506 | */ | ||
507 | const int advanced_init[] = { | ||
508 | PSMOUSE_CMD_DISABLE, PSMOUSE_CMD_DISABLE, | ||
509 | PSMOUSE_CMD_DISABLE, PSMOUSE_CMD_DISABLE, | ||
510 | 0xf2, 0xf2, 0xf2, | ||
511 | }; | ||
512 | |||
513 | switch (priv->mode) { | ||
514 | case HGPK_MODE_MOUSE: | ||
515 | psmouse->pktsize = 3; | ||
516 | break; | ||
517 | |||
518 | case HGPK_MODE_GLIDESENSOR: | ||
519 | case HGPK_MODE_PENTABLET: | ||
520 | psmouse->pktsize = 6; | ||
521 | |||
522 | /* Switch to 'Advanced mode.', four disables in a row. */ | ||
523 | for (i = 0; i < ARRAY_SIZE(advanced_init); i++) | ||
524 | if (ps2_command(ps2dev, NULL, advanced_init[i])) | ||
525 | return -EIO; | ||
526 | |||
527 | /* select between GlideSensor (mouse) or PenTablet */ | ||
528 | cmd = priv->mode == HGPK_MODE_GLIDESENSOR ? | ||
529 | PSMOUSE_CMD_SETSCALE11 : PSMOUSE_CMD_SETSCALE21; | ||
530 | |||
531 | if (ps2_command(ps2dev, NULL, cmd)) | ||
532 | return -EIO; | ||
533 | break; | ||
534 | |||
535 | default: | ||
536 | return -EINVAL; | ||
537 | } | ||
538 | |||
539 | return 0; | ||
540 | } | ||
541 | |||
542 | static void hgpk_setup_input_device(struct input_dev *input, | ||
543 | struct input_dev *old_input, | ||
544 | enum hgpk_mode mode) | ||
545 | { | ||
546 | if (old_input) { | ||
547 | input->name = old_input->name; | ||
548 | input->phys = old_input->phys; | ||
549 | input->id = old_input->id; | ||
550 | input->dev.parent = old_input->dev.parent; | ||
551 | } | ||
552 | |||
553 | memset(input->evbit, 0, sizeof(input->evbit)); | ||
554 | memset(input->relbit, 0, sizeof(input->relbit)); | ||
555 | memset(input->keybit, 0, sizeof(input->keybit)); | ||
556 | |||
557 | /* All modes report left and right buttons */ | ||
558 | __set_bit(EV_KEY, input->evbit); | ||
559 | __set_bit(BTN_LEFT, input->keybit); | ||
560 | __set_bit(BTN_RIGHT, input->keybit); | ||
561 | |||
562 | switch (mode) { | ||
563 | case HGPK_MODE_MOUSE: | ||
564 | __set_bit(EV_REL, input->evbit); | ||
565 | __set_bit(REL_X, input->relbit); | ||
566 | __set_bit(REL_Y, input->relbit); | ||
567 | break; | ||
568 | |||
569 | case HGPK_MODE_GLIDESENSOR: | ||
570 | __set_bit(BTN_TOUCH, input->keybit); | ||
571 | __set_bit(BTN_TOOL_FINGER, input->keybit); | ||
572 | |||
573 | __set_bit(EV_ABS, input->evbit); | ||
574 | |||
575 | /* GlideSensor has pressure sensor, PenTablet does not */ | ||
576 | input_set_abs_params(input, ABS_PRESSURE, 0, 15, 0, 0); | ||
577 | |||
578 | /* From device specs */ | ||
579 | input_set_abs_params(input, ABS_X, 0, 399, 0, 0); | ||
580 | input_set_abs_params(input, ABS_Y, 0, 290, 0, 0); | ||
581 | |||
582 | /* Calculated by hand based on usable size (52mm x 38mm) */ | ||
583 | input_abs_set_res(input, ABS_X, 8); | ||
584 | input_abs_set_res(input, ABS_Y, 8); | ||
585 | break; | ||
586 | |||
587 | case HGPK_MODE_PENTABLET: | ||
588 | __set_bit(BTN_TOUCH, input->keybit); | ||
589 | __set_bit(BTN_TOOL_FINGER, input->keybit); | ||
590 | |||
591 | __set_bit(EV_ABS, input->evbit); | ||
592 | |||
593 | /* From device specs */ | ||
594 | input_set_abs_params(input, ABS_X, 0, 999, 0, 0); | ||
595 | input_set_abs_params(input, ABS_Y, 5, 239, 0, 0); | ||
596 | |||
597 | /* Calculated by hand based on usable size (156mm x 38mm) */ | ||
598 | input_abs_set_res(input, ABS_X, 6); | ||
599 | input_abs_set_res(input, ABS_Y, 8); | ||
600 | break; | ||
601 | |||
602 | default: | ||
603 | BUG(); | ||
604 | } | ||
605 | } | ||
606 | |||
607 | static int hgpk_reset_device(struct psmouse *psmouse, bool recalibrate) | ||
608 | { | ||
609 | int err; | ||
610 | |||
611 | psmouse_reset(psmouse); | ||
612 | |||
613 | if (recalibrate) { | ||
614 | struct ps2dev *ps2dev = &psmouse->ps2dev; | ||
615 | |||
616 | /* send the recalibrate request */ | ||
617 | if (ps2_command(ps2dev, NULL, 0xf5) || | ||
618 | ps2_command(ps2dev, NULL, 0xf5) || | ||
619 | ps2_command(ps2dev, NULL, 0xe6) || | ||
620 | ps2_command(ps2dev, NULL, 0xf5)) { | ||
621 | return -1; | ||
622 | } | ||
623 | |||
624 | /* according to ALPS, 150mS is required for recalibration */ | ||
625 | msleep(150); | ||
626 | } | ||
627 | |||
628 | err = hgpk_select_mode(psmouse); | ||
629 | if (err) { | ||
630 | hgpk_err(psmouse, "failed to select mode\n"); | ||
631 | return err; | ||
632 | } | ||
633 | |||
634 | hgpk_reset_hack_state(psmouse); | ||
635 | |||
636 | return 0; | ||
637 | } | ||
638 | |||
213 | static int hgpk_force_recalibrate(struct psmouse *psmouse) | 639 | static int hgpk_force_recalibrate(struct psmouse *psmouse) |
214 | { | 640 | { |
215 | struct ps2dev *ps2dev = &psmouse->ps2dev; | 641 | struct ps2dev *ps2dev = &psmouse->ps2dev; |
216 | struct hgpk_data *priv = psmouse->private; | 642 | struct hgpk_data *priv = psmouse->private; |
643 | int err; | ||
217 | 644 | ||
218 | /* C-series touchpads added the recalibrate command */ | 645 | /* C-series touchpads added the recalibrate command */ |
219 | if (psmouse->model < HGPK_MODEL_C) | 646 | if (psmouse->model < HGPK_MODEL_C) |
220 | return 0; | 647 | return 0; |
221 | 648 | ||
649 | if (!autorecal) { | ||
650 | hgpk_dbg(psmouse, "recalibrations disabled, ignoring\n"); | ||
651 | return 0; | ||
652 | } | ||
653 | |||
654 | hgpk_dbg(psmouse, "recalibrating touchpad..\n"); | ||
655 | |||
222 | /* we don't want to race with the irq handler, nor with resyncs */ | 656 | /* we don't want to race with the irq handler, nor with resyncs */ |
223 | psmouse_set_state(psmouse, PSMOUSE_INITIALIZING); | 657 | psmouse_set_state(psmouse, PSMOUSE_INITIALIZING); |
224 | 658 | ||
225 | /* start by resetting the device */ | 659 | /* start by resetting the device */ |
226 | psmouse_reset(psmouse); | 660 | err = hgpk_reset_device(psmouse, true); |
227 | 661 | if (err) | |
228 | /* send the recalibrate request */ | 662 | return err; |
229 | if (ps2_command(ps2dev, NULL, 0xf5) || | ||
230 | ps2_command(ps2dev, NULL, 0xf5) || | ||
231 | ps2_command(ps2dev, NULL, 0xe6) || | ||
232 | ps2_command(ps2dev, NULL, 0xf5)) { | ||
233 | return -1; | ||
234 | } | ||
235 | |||
236 | /* according to ALPS, 150mS is required for recalibration */ | ||
237 | msleep(150); | ||
238 | 663 | ||
239 | /* XXX: If a finger is down during this delay, recalibration will | 664 | /* |
665 | * XXX: If a finger is down during this delay, recalibration will | ||
240 | * detect capacitance incorrectly. This is a hardware bug, and | 666 | * detect capacitance incorrectly. This is a hardware bug, and |
241 | * we don't have a good way to deal with it. The 2s window stuff | 667 | * we don't have a good way to deal with it. The 2s window stuff |
242 | * (below) is our best option for now. | 668 | * (below) is our best option for now. |
@@ -247,25 +673,35 @@ static int hgpk_force_recalibrate(struct psmouse *psmouse) | |||
247 | 673 | ||
248 | psmouse_set_state(psmouse, PSMOUSE_ACTIVATED); | 674 | psmouse_set_state(psmouse, PSMOUSE_ACTIVATED); |
249 | 675 | ||
250 | /* After we recalibrate, we shouldn't get any packets for 2s. If | 676 | if (tpdebug) |
251 | * we do, it's likely that someone's finger was on the touchpad. | 677 | hgpk_dbg(psmouse, "touchpad reactivated\n"); |
252 | * If someone's finger *was* on the touchpad, it's probably | 678 | |
253 | * miscalibrated. So, we should schedule another recalibration | 679 | /* |
680 | * If we get packets right away after recalibrating, it's likely | ||
681 | * that a finger was on the touchpad. If so, it's probably | ||
682 | * miscalibrated, so we optionally schedule another. | ||
254 | */ | 683 | */ |
255 | priv->recalib_window = jiffies + msecs_to_jiffies(recal_guard_time); | 684 | if (recal_guard_time) |
685 | priv->recalib_window = jiffies + | ||
686 | msecs_to_jiffies(recal_guard_time); | ||
256 | 687 | ||
257 | return 0; | 688 | return 0; |
258 | } | 689 | } |
259 | 690 | ||
260 | /* | 691 | /* |
261 | * This kills power to the touchpad; according to ALPS, current consumption | 692 | * This puts the touchpad in a power saving mode; according to ALPS, current |
262 | * goes down to 50uA after running this. To turn power back on, we drive | 693 | * consumption goes down to 50uA after running this. To turn power back on, |
263 | * MS-DAT low. | 694 | * we drive MS-DAT low. Measuring with a 1mA resolution ammeter says that |
695 | * the current on the SUS_3.3V rail drops from 3mA or 4mA to 0 when we do this. | ||
696 | * | ||
697 | * We have no formal spec that details this operation -- the low-power | ||
698 | * sequence came from a long-lost email trail. | ||
264 | */ | 699 | */ |
265 | static int hgpk_toggle_power(struct psmouse *psmouse, int enable) | 700 | static int hgpk_toggle_powersave(struct psmouse *psmouse, int enable) |
266 | { | 701 | { |
267 | struct ps2dev *ps2dev = &psmouse->ps2dev; | 702 | struct ps2dev *ps2dev = &psmouse->ps2dev; |
268 | int timeo; | 703 | int timeo; |
704 | int err; | ||
269 | 705 | ||
270 | /* Added on D-series touchpads */ | 706 | /* Added on D-series touchpads */ |
271 | if (psmouse->model < HGPK_MODEL_D) | 707 | if (psmouse->model < HGPK_MODEL_D) |
@@ -279,24 +715,27 @@ static int hgpk_toggle_power(struct psmouse *psmouse, int enable) | |||
279 | * the controller. Once we get an ACK back from it, it | 715 | * the controller. Once we get an ACK back from it, it |
280 | * means we can continue with the touchpad re-init. ALPS | 716 | * means we can continue with the touchpad re-init. ALPS |
281 | * tells us that 1s should be long enough, so set that as | 717 | * tells us that 1s should be long enough, so set that as |
282 | * the upper bound. | 718 | * the upper bound. (in practice, it takes about 3 loops.) |
283 | */ | 719 | */ |
284 | for (timeo = 20; timeo > 0; timeo--) { | 720 | for (timeo = 20; timeo > 0; timeo--) { |
285 | if (!ps2_sendbyte(&psmouse->ps2dev, | 721 | if (!ps2_sendbyte(&psmouse->ps2dev, |
286 | PSMOUSE_CMD_DISABLE, 20)) | 722 | PSMOUSE_CMD_DISABLE, 20)) |
287 | break; | 723 | break; |
288 | msleep(50); | 724 | msleep(25); |
289 | } | 725 | } |
290 | 726 | ||
291 | psmouse_reset(psmouse); | 727 | err = hgpk_reset_device(psmouse, false); |
728 | if (err) { | ||
729 | hgpk_err(psmouse, "Failed to reset device!\n"); | ||
730 | return err; | ||
731 | } | ||
292 | 732 | ||
293 | /* should be all set, enable the touchpad */ | 733 | /* should be all set, enable the touchpad */ |
294 | ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_ENABLE); | 734 | ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_ENABLE); |
295 | psmouse_set_state(psmouse, PSMOUSE_ACTIVATED); | 735 | psmouse_set_state(psmouse, PSMOUSE_ACTIVATED); |
296 | 736 | hgpk_dbg(psmouse, "Touchpad powered up.\n"); | |
297 | } else { | 737 | } else { |
298 | hgpk_dbg(psmouse, "Powering off touchpad.\n"); | 738 | hgpk_dbg(psmouse, "Powering off touchpad.\n"); |
299 | psmouse_set_state(psmouse, PSMOUSE_IGNORE); | ||
300 | 739 | ||
301 | if (ps2_command(ps2dev, NULL, 0xec) || | 740 | if (ps2_command(ps2dev, NULL, 0xec) || |
302 | ps2_command(ps2dev, NULL, 0xec) || | 741 | ps2_command(ps2dev, NULL, 0xec) || |
@@ -304,6 +743,8 @@ static int hgpk_toggle_power(struct psmouse *psmouse, int enable) | |||
304 | return -1; | 743 | return -1; |
305 | } | 744 | } |
306 | 745 | ||
746 | psmouse_set_state(psmouse, PSMOUSE_IGNORE); | ||
747 | |||
307 | /* probably won't see an ACK, the touchpad will be off */ | 748 | /* probably won't see an ACK, the touchpad will be off */ |
308 | ps2_sendbyte(&psmouse->ps2dev, 0xec, 20); | 749 | ps2_sendbyte(&psmouse->ps2dev, 0xec, 20); |
309 | } | 750 | } |
@@ -319,17 +760,20 @@ static int hgpk_poll(struct psmouse *psmouse) | |||
319 | 760 | ||
320 | static int hgpk_reconnect(struct psmouse *psmouse) | 761 | static int hgpk_reconnect(struct psmouse *psmouse) |
321 | { | 762 | { |
322 | /* During suspend/resume the ps2 rails remain powered. We don't want | 763 | struct hgpk_data *priv = psmouse->private; |
764 | |||
765 | /* | ||
766 | * During suspend/resume the ps2 rails remain powered. We don't want | ||
323 | * to do a reset because it's flush data out of buffers; however, | 767 | * to do a reset because it's flush data out of buffers; however, |
324 | * earlier prototypes (B1) had some brokenness that required a reset. */ | 768 | * earlier prototypes (B1) had some brokenness that required a reset. |
769 | */ | ||
325 | if (olpc_board_at_least(olpc_board(0xb2))) | 770 | if (olpc_board_at_least(olpc_board(0xb2))) |
326 | if (psmouse->ps2dev.serio->dev.power.power_state.event != | 771 | if (psmouse->ps2dev.serio->dev.power.power_state.event != |
327 | PM_EVENT_ON) | 772 | PM_EVENT_ON) |
328 | return 0; | 773 | return 0; |
329 | 774 | ||
330 | psmouse_reset(psmouse); | 775 | priv->powered = 1; |
331 | 776 | return hgpk_reset_device(psmouse, false); | |
332 | return 0; | ||
333 | } | 777 | } |
334 | 778 | ||
335 | static ssize_t hgpk_show_powered(struct psmouse *psmouse, void *data, char *buf) | 779 | static ssize_t hgpk_show_powered(struct psmouse *psmouse, void *data, char *buf) |
@@ -355,7 +799,7 @@ static ssize_t hgpk_set_powered(struct psmouse *psmouse, void *data, | |||
355 | * hgpk_toggle_power will deal w/ state so | 799 | * hgpk_toggle_power will deal w/ state so |
356 | * we're not racing w/ irq | 800 | * we're not racing w/ irq |
357 | */ | 801 | */ |
358 | err = hgpk_toggle_power(psmouse, value); | 802 | err = hgpk_toggle_powersave(psmouse, value); |
359 | if (!err) | 803 | if (!err) |
360 | priv->powered = value; | 804 | priv->powered = value; |
361 | } | 805 | } |
@@ -366,6 +810,65 @@ static ssize_t hgpk_set_powered(struct psmouse *psmouse, void *data, | |||
366 | __PSMOUSE_DEFINE_ATTR(powered, S_IWUSR | S_IRUGO, NULL, | 810 | __PSMOUSE_DEFINE_ATTR(powered, S_IWUSR | S_IRUGO, NULL, |
367 | hgpk_show_powered, hgpk_set_powered, false); | 811 | hgpk_show_powered, hgpk_set_powered, false); |
368 | 812 | ||
813 | static ssize_t attr_show_mode(struct psmouse *psmouse, void *data, char *buf) | ||
814 | { | ||
815 | struct hgpk_data *priv = psmouse->private; | ||
816 | |||
817 | return sprintf(buf, "%s\n", hgpk_mode_names[priv->mode]); | ||
818 | } | ||
819 | |||
820 | static ssize_t attr_set_mode(struct psmouse *psmouse, void *data, | ||
821 | const char *buf, size_t len) | ||
822 | { | ||
823 | struct hgpk_data *priv = psmouse->private; | ||
824 | enum hgpk_mode old_mode = priv->mode; | ||
825 | enum hgpk_mode new_mode = hgpk_mode_from_name(buf, len); | ||
826 | struct input_dev *old_dev = psmouse->dev; | ||
827 | struct input_dev *new_dev; | ||
828 | int err; | ||
829 | |||
830 | if (new_mode == HGPK_MODE_INVALID) | ||
831 | return -EINVAL; | ||
832 | |||
833 | if (old_mode == new_mode) | ||
834 | return len; | ||
835 | |||
836 | new_dev = input_allocate_device(); | ||
837 | if (!new_dev) | ||
838 | return -ENOMEM; | ||
839 | |||
840 | psmouse_set_state(psmouse, PSMOUSE_INITIALIZING); | ||
841 | |||
842 | /* Switch device into the new mode */ | ||
843 | priv->mode = new_mode; | ||
844 | err = hgpk_reset_device(psmouse, false); | ||
845 | if (err) | ||
846 | goto err_try_restore; | ||
847 | |||
848 | hgpk_setup_input_device(new_dev, old_dev, new_mode); | ||
849 | |||
850 | psmouse_set_state(psmouse, PSMOUSE_CMD_MODE); | ||
851 | |||
852 | err = input_register_device(new_dev); | ||
853 | if (err) | ||
854 | goto err_try_restore; | ||
855 | |||
856 | psmouse->dev = new_dev; | ||
857 | input_unregister_device(old_dev); | ||
858 | |||
859 | return len; | ||
860 | |||
861 | err_try_restore: | ||
862 | input_free_device(new_dev); | ||
863 | priv->mode = old_mode; | ||
864 | hgpk_reset_device(psmouse, false); | ||
865 | |||
866 | return err; | ||
867 | } | ||
868 | |||
869 | PSMOUSE_DEFINE_ATTR(hgpk_mode, S_IWUSR | S_IRUGO, NULL, | ||
870 | attr_show_mode, attr_set_mode); | ||
871 | |||
369 | static ssize_t hgpk_trigger_recal_show(struct psmouse *psmouse, | 872 | static ssize_t hgpk_trigger_recal_show(struct psmouse *psmouse, |
370 | void *data, char *buf) | 873 | void *data, char *buf) |
371 | { | 874 | { |
@@ -401,6 +904,8 @@ static void hgpk_disconnect(struct psmouse *psmouse) | |||
401 | 904 | ||
402 | device_remove_file(&psmouse->ps2dev.serio->dev, | 905 | device_remove_file(&psmouse->ps2dev.serio->dev, |
403 | &psmouse_attr_powered.dattr); | 906 | &psmouse_attr_powered.dattr); |
907 | device_remove_file(&psmouse->ps2dev.serio->dev, | ||
908 | &psmouse_attr_hgpk_mode.dattr); | ||
404 | 909 | ||
405 | if (psmouse->model >= HGPK_MODEL_C) | 910 | if (psmouse->model >= HGPK_MODEL_C) |
406 | device_remove_file(&psmouse->ps2dev.serio->dev, | 911 | device_remove_file(&psmouse->ps2dev.serio->dev, |
@@ -416,14 +921,13 @@ static void hgpk_recalib_work(struct work_struct *work) | |||
416 | struct hgpk_data *priv = container_of(w, struct hgpk_data, recalib_wq); | 921 | struct hgpk_data *priv = container_of(w, struct hgpk_data, recalib_wq); |
417 | struct psmouse *psmouse = priv->psmouse; | 922 | struct psmouse *psmouse = priv->psmouse; |
418 | 923 | ||
419 | hgpk_dbg(psmouse, "recalibrating touchpad..\n"); | ||
420 | |||
421 | if (hgpk_force_recalibrate(psmouse)) | 924 | if (hgpk_force_recalibrate(psmouse)) |
422 | hgpk_err(psmouse, "recalibration failed!\n"); | 925 | hgpk_err(psmouse, "recalibration failed!\n"); |
423 | } | 926 | } |
424 | 927 | ||
425 | static int hgpk_register(struct psmouse *psmouse) | 928 | static int hgpk_register(struct psmouse *psmouse) |
426 | { | 929 | { |
930 | struct hgpk_data *priv = psmouse->private; | ||
427 | int err; | 931 | int err; |
428 | 932 | ||
429 | /* register handlers */ | 933 | /* register handlers */ |
@@ -431,13 +935,14 @@ static int hgpk_register(struct psmouse *psmouse) | |||
431 | psmouse->poll = hgpk_poll; | 935 | psmouse->poll = hgpk_poll; |
432 | psmouse->disconnect = hgpk_disconnect; | 936 | psmouse->disconnect = hgpk_disconnect; |
433 | psmouse->reconnect = hgpk_reconnect; | 937 | psmouse->reconnect = hgpk_reconnect; |
434 | psmouse->pktsize = 3; | ||
435 | 938 | ||
436 | /* Disable the idle resync. */ | 939 | /* Disable the idle resync. */ |
437 | psmouse->resync_time = 0; | 940 | psmouse->resync_time = 0; |
438 | /* Reset after a lot of bad bytes. */ | 941 | /* Reset after a lot of bad bytes. */ |
439 | psmouse->resetafter = 1024; | 942 | psmouse->resetafter = 1024; |
440 | 943 | ||
944 | hgpk_setup_input_device(psmouse->dev, NULL, priv->mode); | ||
945 | |||
441 | err = device_create_file(&psmouse->ps2dev.serio->dev, | 946 | err = device_create_file(&psmouse->ps2dev.serio->dev, |
442 | &psmouse_attr_powered.dattr); | 947 | &psmouse_attr_powered.dattr); |
443 | if (err) { | 948 | if (err) { |
@@ -445,6 +950,13 @@ static int hgpk_register(struct psmouse *psmouse) | |||
445 | return err; | 950 | return err; |
446 | } | 951 | } |
447 | 952 | ||
953 | err = device_create_file(&psmouse->ps2dev.serio->dev, | ||
954 | &psmouse_attr_hgpk_mode.dattr); | ||
955 | if (err) { | ||
956 | hgpk_err(psmouse, "Failed creating 'hgpk_mode' sysfs node\n"); | ||
957 | goto err_remove_powered; | ||
958 | } | ||
959 | |||
448 | /* C-series touchpads added the recalibrate command */ | 960 | /* C-series touchpads added the recalibrate command */ |
449 | if (psmouse->model >= HGPK_MODEL_C) { | 961 | if (psmouse->model >= HGPK_MODEL_C) { |
450 | err = device_create_file(&psmouse->ps2dev.serio->dev, | 962 | err = device_create_file(&psmouse->ps2dev.serio->dev, |
@@ -452,30 +964,40 @@ static int hgpk_register(struct psmouse *psmouse) | |||
452 | if (err) { | 964 | if (err) { |
453 | hgpk_err(psmouse, | 965 | hgpk_err(psmouse, |
454 | "Failed creating 'recalibrate' sysfs node\n"); | 966 | "Failed creating 'recalibrate' sysfs node\n"); |
455 | device_remove_file(&psmouse->ps2dev.serio->dev, | 967 | goto err_remove_mode; |
456 | &psmouse_attr_powered.dattr); | ||
457 | return err; | ||
458 | } | 968 | } |
459 | } | 969 | } |
460 | 970 | ||
461 | return 0; | 971 | return 0; |
972 | |||
973 | err_remove_mode: | ||
974 | device_remove_file(&psmouse->ps2dev.serio->dev, | ||
975 | &psmouse_attr_hgpk_mode.dattr); | ||
976 | err_remove_powered: | ||
977 | device_remove_file(&psmouse->ps2dev.serio->dev, | ||
978 | &psmouse_attr_powered.dattr); | ||
979 | return err; | ||
462 | } | 980 | } |
463 | 981 | ||
464 | int hgpk_init(struct psmouse *psmouse) | 982 | int hgpk_init(struct psmouse *psmouse) |
465 | { | 983 | { |
466 | struct hgpk_data *priv; | 984 | struct hgpk_data *priv; |
467 | int err = -ENOMEM; | 985 | int err; |
468 | 986 | ||
469 | priv = kzalloc(sizeof(struct hgpk_data), GFP_KERNEL); | 987 | priv = kzalloc(sizeof(struct hgpk_data), GFP_KERNEL); |
470 | if (!priv) | 988 | if (!priv) { |
989 | err = -ENOMEM; | ||
471 | goto alloc_fail; | 990 | goto alloc_fail; |
991 | } | ||
472 | 992 | ||
473 | psmouse->private = priv; | 993 | psmouse->private = priv; |
994 | |||
474 | priv->psmouse = psmouse; | 995 | priv->psmouse = psmouse; |
475 | priv->powered = true; | 996 | priv->powered = true; |
997 | priv->mode = hgpk_default_mode; | ||
476 | INIT_DELAYED_WORK(&priv->recalib_wq, hgpk_recalib_work); | 998 | INIT_DELAYED_WORK(&priv->recalib_wq, hgpk_recalib_work); |
477 | 999 | ||
478 | err = psmouse_reset(psmouse); | 1000 | err = hgpk_reset_device(psmouse, false); |
479 | if (err) | 1001 | if (err) |
480 | goto init_fail; | 1002 | goto init_fail; |
481 | 1003 | ||
@@ -531,3 +1053,14 @@ int hgpk_detect(struct psmouse *psmouse, bool set_properties) | |||
531 | 1053 | ||
532 | return 0; | 1054 | return 0; |
533 | } | 1055 | } |
1056 | |||
1057 | void hgpk_module_init(void) | ||
1058 | { | ||
1059 | hgpk_default_mode = hgpk_mode_from_name(hgpk_mode_name, | ||
1060 | strlen(hgpk_mode_name)); | ||
1061 | if (hgpk_default_mode == HGPK_MODE_INVALID) { | ||
1062 | hgpk_default_mode = HGPK_MODE_MOUSE; | ||
1063 | strlcpy(hgpk_mode_name, hgpk_mode_names[HGPK_MODE_MOUSE], | ||
1064 | sizeof(hgpk_mode_name)); | ||
1065 | } | ||
1066 | } | ||
diff --git a/drivers/input/mouse/hgpk.h b/drivers/input/mouse/hgpk.h index d61cfd3ee9cb..311c0e87fcbf 100644 --- a/drivers/input/mouse/hgpk.h +++ b/drivers/input/mouse/hgpk.h | |||
@@ -5,6 +5,9 @@ | |||
5 | #ifndef _HGPK_H | 5 | #ifndef _HGPK_H |
6 | #define _HGPK_H | 6 | #define _HGPK_H |
7 | 7 | ||
8 | #define HGPK_GS 0xff /* The GlideSensor */ | ||
9 | #define HGPK_PT 0xcf /* The PenTablet */ | ||
10 | |||
8 | enum hgpk_model_t { | 11 | enum hgpk_model_t { |
9 | HGPK_MODEL_PREA = 0x0a, /* pre-B1s */ | 12 | HGPK_MODEL_PREA = 0x0a, /* pre-B1s */ |
10 | HGPK_MODEL_A = 0x14, /* found on B1s, PT disabled in hardware */ | 13 | HGPK_MODEL_A = 0x14, /* found on B1s, PT disabled in hardware */ |
@@ -13,12 +16,34 @@ enum hgpk_model_t { | |||
13 | HGPK_MODEL_D = 0x50, /* C1, mass production */ | 16 | HGPK_MODEL_D = 0x50, /* C1, mass production */ |
14 | }; | 17 | }; |
15 | 18 | ||
19 | enum hgpk_spew_flag { | ||
20 | NO_SPEW, | ||
21 | MAYBE_SPEWING, | ||
22 | SPEW_DETECTED, | ||
23 | RECALIBRATING, | ||
24 | }; | ||
25 | |||
26 | #define SPEW_WATCH_COUNT 42 /* at 12ms/packet, this is 1/2 second */ | ||
27 | |||
28 | enum hgpk_mode { | ||
29 | HGPK_MODE_MOUSE, | ||
30 | HGPK_MODE_GLIDESENSOR, | ||
31 | HGPK_MODE_PENTABLET, | ||
32 | HGPK_MODE_INVALID | ||
33 | }; | ||
34 | |||
16 | struct hgpk_data { | 35 | struct hgpk_data { |
17 | struct psmouse *psmouse; | 36 | struct psmouse *psmouse; |
37 | enum hgpk_mode mode; | ||
18 | bool powered; | 38 | bool powered; |
19 | int count, x_tally, y_tally; /* hardware workaround stuff */ | 39 | enum hgpk_spew_flag spew_flag; |
40 | int spew_count, x_tally, y_tally; /* spew detection */ | ||
20 | unsigned long recalib_window; | 41 | unsigned long recalib_window; |
21 | struct delayed_work recalib_wq; | 42 | struct delayed_work recalib_wq; |
43 | int abs_x, abs_y; | ||
44 | int dupe_count; | ||
45 | int xbigj, ybigj, xlast, ylast; /* jumpiness detection */ | ||
46 | int xsaw_secondary, ysaw_secondary; /* jumpiness detection */ | ||
22 | }; | 47 | }; |
23 | 48 | ||
24 | #define hgpk_dbg(psmouse, format, arg...) \ | 49 | #define hgpk_dbg(psmouse, format, arg...) \ |
@@ -33,9 +58,13 @@ struct hgpk_data { | |||
33 | dev_notice(&(psmouse)->ps2dev.serio->dev, format, ## arg) | 58 | dev_notice(&(psmouse)->ps2dev.serio->dev, format, ## arg) |
34 | 59 | ||
35 | #ifdef CONFIG_MOUSE_PS2_OLPC | 60 | #ifdef CONFIG_MOUSE_PS2_OLPC |
61 | void hgpk_module_init(void); | ||
36 | int hgpk_detect(struct psmouse *psmouse, bool set_properties); | 62 | int hgpk_detect(struct psmouse *psmouse, bool set_properties); |
37 | int hgpk_init(struct psmouse *psmouse); | 63 | int hgpk_init(struct psmouse *psmouse); |
38 | #else | 64 | #else |
65 | static inline void hgpk_module_init(void) | ||
66 | { | ||
67 | } | ||
39 | static inline int hgpk_detect(struct psmouse *psmouse, bool set_properties) | 68 | static inline int hgpk_detect(struct psmouse *psmouse, bool set_properties) |
40 | { | 69 | { |
41 | return -ENODEV; | 70 | return -ENODEV; |
diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c index cd9d0c97e429..3f74baee102b 100644 --- a/drivers/input/mouse/psmouse-base.c +++ b/drivers/input/mouse/psmouse-base.c | |||
@@ -1711,6 +1711,7 @@ static int __init psmouse_init(void) | |||
1711 | 1711 | ||
1712 | lifebook_module_init(); | 1712 | lifebook_module_init(); |
1713 | synaptics_module_init(); | 1713 | synaptics_module_init(); |
1714 | hgpk_module_init(); | ||
1714 | 1715 | ||
1715 | kpsmoused_wq = create_singlethread_workqueue("kpsmoused"); | 1716 | kpsmoused_wq = create_singlethread_workqueue("kpsmoused"); |
1716 | if (!kpsmoused_wq) { | 1717 | if (!kpsmoused_wq) { |
diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c index 2e300a460556..da392c22fc6c 100644 --- a/drivers/input/mouse/synaptics.c +++ b/drivers/input/mouse/synaptics.c | |||
@@ -25,7 +25,7 @@ | |||
25 | 25 | ||
26 | #include <linux/module.h> | 26 | #include <linux/module.h> |
27 | #include <linux/dmi.h> | 27 | #include <linux/dmi.h> |
28 | #include <linux/input.h> | 28 | #include <linux/input/mt.h> |
29 | #include <linux/serio.h> | 29 | #include <linux/serio.h> |
30 | #include <linux/libps2.h> | 30 | #include <linux/libps2.h> |
31 | #include <linux/slab.h> | 31 | #include <linux/slab.h> |
@@ -279,6 +279,25 @@ static void synaptics_set_rate(struct psmouse *psmouse, unsigned int rate) | |||
279 | synaptics_mode_cmd(psmouse, priv->mode); | 279 | synaptics_mode_cmd(psmouse, priv->mode); |
280 | } | 280 | } |
281 | 281 | ||
282 | static int synaptics_set_advanced_gesture_mode(struct psmouse *psmouse) | ||
283 | { | ||
284 | static unsigned char param = 0xc8; | ||
285 | struct synaptics_data *priv = psmouse->private; | ||
286 | |||
287 | if (!SYN_CAP_ADV_GESTURE(priv->ext_cap_0c)) | ||
288 | return 0; | ||
289 | |||
290 | if (psmouse_sliced_command(psmouse, SYN_QUE_MODEL)) | ||
291 | return -1; | ||
292 | if (ps2_command(&psmouse->ps2dev, ¶m, PSMOUSE_CMD_SETRATE)) | ||
293 | return -1; | ||
294 | |||
295 | /* Advanced gesture mode also sends multi finger data */ | ||
296 | priv->capabilities |= BIT(1); | ||
297 | |||
298 | return 0; | ||
299 | } | ||
300 | |||
282 | /***************************************************************************** | 301 | /***************************************************************************** |
283 | * Synaptics pass-through PS/2 port support | 302 | * Synaptics pass-through PS/2 port support |
284 | ****************************************************************************/ | 303 | ****************************************************************************/ |
@@ -380,7 +399,9 @@ static void synaptics_pt_create(struct psmouse *psmouse) | |||
380 | * Functions to interpret the absolute mode packets | 399 | * Functions to interpret the absolute mode packets |
381 | ****************************************************************************/ | 400 | ****************************************************************************/ |
382 | 401 | ||
383 | static void synaptics_parse_hw_state(unsigned char buf[], struct synaptics_data *priv, struct synaptics_hw_state *hw) | 402 | static int synaptics_parse_hw_state(const unsigned char buf[], |
403 | struct synaptics_data *priv, | ||
404 | struct synaptics_hw_state *hw) | ||
384 | { | 405 | { |
385 | memset(hw, 0, sizeof(struct synaptics_hw_state)); | 406 | memset(hw, 0, sizeof(struct synaptics_hw_state)); |
386 | 407 | ||
@@ -397,6 +418,14 @@ static void synaptics_parse_hw_state(unsigned char buf[], struct synaptics_data | |||
397 | ((buf[0] & 0x04) >> 1) | | 418 | ((buf[0] & 0x04) >> 1) | |
398 | ((buf[3] & 0x04) >> 2)); | 419 | ((buf[3] & 0x04) >> 2)); |
399 | 420 | ||
421 | if (SYN_CAP_ADV_GESTURE(priv->ext_cap_0c) && hw->w == 2) { | ||
422 | /* Gesture packet: (x, y, z) at half resolution */ | ||
423 | priv->mt.x = (((buf[4] & 0x0f) << 8) | buf[1]) << 1; | ||
424 | priv->mt.y = (((buf[4] & 0xf0) << 4) | buf[2]) << 1; | ||
425 | priv->mt.z = ((buf[3] & 0x30) | (buf[5] & 0x0f)) << 1; | ||
426 | return 1; | ||
427 | } | ||
428 | |||
400 | hw->left = (buf[0] & 0x01) ? 1 : 0; | 429 | hw->left = (buf[0] & 0x01) ? 1 : 0; |
401 | hw->right = (buf[0] & 0x02) ? 1 : 0; | 430 | hw->right = (buf[0] & 0x02) ? 1 : 0; |
402 | 431 | ||
@@ -452,6 +481,36 @@ static void synaptics_parse_hw_state(unsigned char buf[], struct synaptics_data | |||
452 | hw->left = (buf[0] & 0x01) ? 1 : 0; | 481 | hw->left = (buf[0] & 0x01) ? 1 : 0; |
453 | hw->right = (buf[0] & 0x02) ? 1 : 0; | 482 | hw->right = (buf[0] & 0x02) ? 1 : 0; |
454 | } | 483 | } |
484 | |||
485 | return 0; | ||
486 | } | ||
487 | |||
488 | static void set_slot(struct input_dev *dev, int slot, bool active, int x, int y) | ||
489 | { | ||
490 | input_mt_slot(dev, slot); | ||
491 | input_mt_report_slot_state(dev, MT_TOOL_FINGER, active); | ||
492 | if (active) { | ||
493 | input_report_abs(dev, ABS_MT_POSITION_X, x); | ||
494 | input_report_abs(dev, ABS_MT_POSITION_Y, | ||
495 | YMAX_NOMINAL + YMIN_NOMINAL - y); | ||
496 | } | ||
497 | } | ||
498 | |||
499 | static void synaptics_report_semi_mt_data(struct input_dev *dev, | ||
500 | const struct synaptics_hw_state *a, | ||
501 | const struct synaptics_hw_state *b, | ||
502 | int num_fingers) | ||
503 | { | ||
504 | if (num_fingers >= 2) { | ||
505 | set_slot(dev, 0, true, min(a->x, b->x), min(a->y, b->y)); | ||
506 | set_slot(dev, 1, true, max(a->x, b->x), max(a->y, b->y)); | ||
507 | } else if (num_fingers == 1) { | ||
508 | set_slot(dev, 0, true, a->x, a->y); | ||
509 | set_slot(dev, 1, false, 0, 0); | ||
510 | } else { | ||
511 | set_slot(dev, 0, false, 0, 0); | ||
512 | set_slot(dev, 1, false, 0, 0); | ||
513 | } | ||
455 | } | 514 | } |
456 | 515 | ||
457 | /* | 516 | /* |
@@ -466,7 +525,8 @@ static void synaptics_process_packet(struct psmouse *psmouse) | |||
466 | int finger_width; | 525 | int finger_width; |
467 | int i; | 526 | int i; |
468 | 527 | ||
469 | synaptics_parse_hw_state(psmouse->packet, priv, &hw); | 528 | if (synaptics_parse_hw_state(psmouse->packet, priv, &hw)) |
529 | return; | ||
470 | 530 | ||
471 | if (hw.scroll) { | 531 | if (hw.scroll) { |
472 | priv->scroll += hw.scroll; | 532 | priv->scroll += hw.scroll; |
@@ -488,7 +548,7 @@ static void synaptics_process_packet(struct psmouse *psmouse) | |||
488 | return; | 548 | return; |
489 | } | 549 | } |
490 | 550 | ||
491 | if (hw.z > 0) { | 551 | if (hw.z > 0 && hw.x > 1) { |
492 | num_fingers = 1; | 552 | num_fingers = 1; |
493 | finger_width = 5; | 553 | finger_width = 5; |
494 | if (SYN_CAP_EXTENDED(priv->capabilities)) { | 554 | if (SYN_CAP_EXTENDED(priv->capabilities)) { |
@@ -512,6 +572,9 @@ static void synaptics_process_packet(struct psmouse *psmouse) | |||
512 | finger_width = 0; | 572 | finger_width = 0; |
513 | } | 573 | } |
514 | 574 | ||
575 | if (SYN_CAP_ADV_GESTURE(priv->ext_cap_0c)) | ||
576 | synaptics_report_semi_mt_data(dev, &hw, &priv->mt, num_fingers); | ||
577 | |||
515 | /* Post events | 578 | /* Post events |
516 | * BTN_TOUCH has to be first as mousedev relies on it when doing | 579 | * BTN_TOUCH has to be first as mousedev relies on it when doing |
517 | * absolute -> relative conversion | 580 | * absolute -> relative conversion |
@@ -519,7 +582,7 @@ static void synaptics_process_packet(struct psmouse *psmouse) | |||
519 | if (hw.z > 30) input_report_key(dev, BTN_TOUCH, 1); | 582 | if (hw.z > 30) input_report_key(dev, BTN_TOUCH, 1); |
520 | if (hw.z < 25) input_report_key(dev, BTN_TOUCH, 0); | 583 | if (hw.z < 25) input_report_key(dev, BTN_TOUCH, 0); |
521 | 584 | ||
522 | if (hw.z > 0) { | 585 | if (num_fingers > 0) { |
523 | input_report_abs(dev, ABS_X, hw.x); | 586 | input_report_abs(dev, ABS_X, hw.x); |
524 | input_report_abs(dev, ABS_Y, YMAX_NOMINAL + YMIN_NOMINAL - hw.y); | 587 | input_report_abs(dev, ABS_Y, YMAX_NOMINAL + YMIN_NOMINAL - hw.y); |
525 | } | 588 | } |
@@ -622,6 +685,8 @@ static void set_input_params(struct input_dev *dev, struct synaptics_data *priv) | |||
622 | { | 685 | { |
623 | int i; | 686 | int i; |
624 | 687 | ||
688 | __set_bit(INPUT_PROP_POINTER, dev->propbit); | ||
689 | |||
625 | __set_bit(EV_ABS, dev->evbit); | 690 | __set_bit(EV_ABS, dev->evbit); |
626 | input_set_abs_params(dev, ABS_X, | 691 | input_set_abs_params(dev, ABS_X, |
627 | XMIN_NOMINAL, priv->x_max ?: XMAX_NOMINAL, 0, 0); | 692 | XMIN_NOMINAL, priv->x_max ?: XMAX_NOMINAL, 0, 0); |
@@ -629,6 +694,15 @@ static void set_input_params(struct input_dev *dev, struct synaptics_data *priv) | |||
629 | YMIN_NOMINAL, priv->y_max ?: YMAX_NOMINAL, 0, 0); | 694 | YMIN_NOMINAL, priv->y_max ?: YMAX_NOMINAL, 0, 0); |
630 | input_set_abs_params(dev, ABS_PRESSURE, 0, 255, 0, 0); | 695 | input_set_abs_params(dev, ABS_PRESSURE, 0, 255, 0, 0); |
631 | 696 | ||
697 | if (SYN_CAP_ADV_GESTURE(priv->ext_cap_0c)) { | ||
698 | __set_bit(INPUT_PROP_SEMI_MT, dev->propbit); | ||
699 | input_mt_init_slots(dev, 2); | ||
700 | input_set_abs_params(dev, ABS_MT_POSITION_X, XMIN_NOMINAL, | ||
701 | priv->x_max ?: XMAX_NOMINAL, 0, 0); | ||
702 | input_set_abs_params(dev, ABS_MT_POSITION_Y, YMIN_NOMINAL, | ||
703 | priv->y_max ?: YMAX_NOMINAL, 0, 0); | ||
704 | } | ||
705 | |||
632 | if (SYN_CAP_PALMDETECT(priv->capabilities)) | 706 | if (SYN_CAP_PALMDETECT(priv->capabilities)) |
633 | input_set_abs_params(dev, ABS_TOOL_WIDTH, 0, 15, 0, 0); | 707 | input_set_abs_params(dev, ABS_TOOL_WIDTH, 0, 15, 0, 0); |
634 | 708 | ||
@@ -663,6 +737,7 @@ static void set_input_params(struct input_dev *dev, struct synaptics_data *priv) | |||
663 | input_abs_set_res(dev, ABS_Y, priv->y_res); | 737 | input_abs_set_res(dev, ABS_Y, priv->y_res); |
664 | 738 | ||
665 | if (SYN_CAP_CLICKPAD(priv->ext_cap_0c)) { | 739 | if (SYN_CAP_CLICKPAD(priv->ext_cap_0c)) { |
740 | __set_bit(INPUT_PROP_BUTTONPAD, dev->propbit); | ||
666 | /* Clickpads report only left button */ | 741 | /* Clickpads report only left button */ |
667 | __clear_bit(BTN_RIGHT, dev->keybit); | 742 | __clear_bit(BTN_RIGHT, dev->keybit); |
668 | __clear_bit(BTN_MIDDLE, dev->keybit); | 743 | __clear_bit(BTN_MIDDLE, dev->keybit); |
@@ -702,6 +777,11 @@ static int synaptics_reconnect(struct psmouse *psmouse) | |||
702 | return -1; | 777 | return -1; |
703 | } | 778 | } |
704 | 779 | ||
780 | if (synaptics_set_advanced_gesture_mode(psmouse)) { | ||
781 | printk(KERN_ERR "Advanced gesture mode reconnect failed.\n"); | ||
782 | return -1; | ||
783 | } | ||
784 | |||
705 | return 0; | 785 | return 0; |
706 | } | 786 | } |
707 | 787 | ||
@@ -744,15 +824,45 @@ static const struct dmi_system_id __initconst toshiba_dmi_table[] = { | |||
744 | #endif | 824 | #endif |
745 | }; | 825 | }; |
746 | 826 | ||
827 | static bool broken_olpc_ec; | ||
828 | |||
829 | static const struct dmi_system_id __initconst olpc_dmi_table[] = { | ||
830 | #if defined(CONFIG_DMI) && defined(CONFIG_OLPC) | ||
831 | { | ||
832 | /* OLPC XO-1 or XO-1.5 */ | ||
833 | .matches = { | ||
834 | DMI_MATCH(DMI_SYS_VENDOR, "OLPC"), | ||
835 | DMI_MATCH(DMI_PRODUCT_NAME, "XO"), | ||
836 | }, | ||
837 | }, | ||
838 | { } | ||
839 | #endif | ||
840 | }; | ||
841 | |||
747 | void __init synaptics_module_init(void) | 842 | void __init synaptics_module_init(void) |
748 | { | 843 | { |
749 | impaired_toshiba_kbc = dmi_check_system(toshiba_dmi_table); | 844 | impaired_toshiba_kbc = dmi_check_system(toshiba_dmi_table); |
845 | broken_olpc_ec = dmi_check_system(olpc_dmi_table); | ||
750 | } | 846 | } |
751 | 847 | ||
752 | int synaptics_init(struct psmouse *psmouse) | 848 | int synaptics_init(struct psmouse *psmouse) |
753 | { | 849 | { |
754 | struct synaptics_data *priv; | 850 | struct synaptics_data *priv; |
755 | 851 | ||
852 | /* | ||
853 | * The OLPC XO has issues with Synaptics' absolute mode; similarly to | ||
854 | * the HGPK, it quickly degrades and the hardware becomes jumpy and | ||
855 | * overly sensitive. Not only that, but the constant packet spew | ||
856 | * (even at a lowered 40pps rate) overloads the EC such that key | ||
857 | * presses on the keyboard are missed. Given all of that, don't | ||
858 | * even attempt to use Synaptics mode. Relative mode seems to work | ||
859 | * just fine. | ||
860 | */ | ||
861 | if (broken_olpc_ec) { | ||
862 | printk(KERN_INFO "synaptics: OLPC XO detected, not enabling Synaptics protocol.\n"); | ||
863 | return -ENODEV; | ||
864 | } | ||
865 | |||
756 | psmouse->private = priv = kzalloc(sizeof(struct synaptics_data), GFP_KERNEL); | 866 | psmouse->private = priv = kzalloc(sizeof(struct synaptics_data), GFP_KERNEL); |
757 | if (!priv) | 867 | if (!priv) |
758 | return -ENOMEM; | 868 | return -ENOMEM; |
@@ -769,6 +879,11 @@ int synaptics_init(struct psmouse *psmouse) | |||
769 | goto init_fail; | 879 | goto init_fail; |
770 | } | 880 | } |
771 | 881 | ||
882 | if (synaptics_set_advanced_gesture_mode(psmouse)) { | ||
883 | printk(KERN_ERR "Advanced gesture mode init failed.\n"); | ||
884 | goto init_fail; | ||
885 | } | ||
886 | |||
772 | priv->pkt_type = SYN_MODEL_NEWABS(priv->model_id) ? SYN_NEWABS : SYN_OLDABS; | 887 | priv->pkt_type = SYN_MODEL_NEWABS(priv->model_id) ? SYN_NEWABS : SYN_OLDABS; |
773 | 888 | ||
774 | printk(KERN_INFO "Synaptics Touchpad, model: %ld, fw: %ld.%ld, id: %#lx, caps: %#lx/%#lx/%#lx\n", | 889 | printk(KERN_INFO "Synaptics Touchpad, model: %ld, fw: %ld.%ld, id: %#lx, caps: %#lx/%#lx/%#lx\n", |
@@ -802,8 +917,8 @@ int synaptics_init(struct psmouse *psmouse) | |||
802 | 917 | ||
803 | /* | 918 | /* |
804 | * Toshiba's KBC seems to have trouble handling data from | 919 | * Toshiba's KBC seems to have trouble handling data from |
805 | * Synaptics as full rate, switch to lower rate which is roughly | 920 | * Synaptics at full rate. Switch to a lower rate (roughly |
806 | * thye same as rate of standard PS/2 mouse. | 921 | * the same rate as a standard PS/2 mouse). |
807 | */ | 922 | */ |
808 | if (psmouse->rate >= 80 && impaired_toshiba_kbc) { | 923 | if (psmouse->rate >= 80 && impaired_toshiba_kbc) { |
809 | printk(KERN_INFO "synaptics: Toshiba %s detected, limiting rate to 40pps.\n", | 924 | printk(KERN_INFO "synaptics: Toshiba %s detected, limiting rate to 40pps.\n", |
diff --git a/drivers/input/mouse/synaptics.h b/drivers/input/mouse/synaptics.h index 0aefaa885871..25e5d042a72c 100644 --- a/drivers/input/mouse/synaptics.h +++ b/drivers/input/mouse/synaptics.h | |||
@@ -54,6 +54,7 @@ | |||
54 | #define SYN_CAP_CLICKPAD(ex0c) ((ex0c) & 0x100000) /* 1-button ClickPad */ | 54 | #define SYN_CAP_CLICKPAD(ex0c) ((ex0c) & 0x100000) /* 1-button ClickPad */ |
55 | #define SYN_CAP_CLICKPAD2BTN(ex0c) ((ex0c) & 0x000100) /* 2-button ClickPad */ | 55 | #define SYN_CAP_CLICKPAD2BTN(ex0c) ((ex0c) & 0x000100) /* 2-button ClickPad */ |
56 | #define SYN_CAP_MAX_DIMENSIONS(ex0c) ((ex0c) & 0x020000) | 56 | #define SYN_CAP_MAX_DIMENSIONS(ex0c) ((ex0c) & 0x020000) |
57 | #define SYN_CAP_ADV_GESTURE(ex0c) ((ex0c) & 0x080000) | ||
57 | 58 | ||
58 | /* synaptics modes query bits */ | 59 | /* synaptics modes query bits */ |
59 | #define SYN_MODE_ABSOLUTE(m) ((m) & (1 << 7)) | 60 | #define SYN_MODE_ABSOLUTE(m) ((m) & (1 << 7)) |
@@ -113,6 +114,8 @@ struct synaptics_data { | |||
113 | int scroll; | 114 | int scroll; |
114 | 115 | ||
115 | struct serio *pt_port; /* Pass-through serio port */ | 116 | struct serio *pt_port; /* Pass-through serio port */ |
117 | |||
118 | struct synaptics_hw_state mt; /* current gesture packet */ | ||
116 | }; | 119 | }; |
117 | 120 | ||
118 | void synaptics_module_init(void); | 121 | void synaptics_module_init(void); |