diff options
| author | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2011-01-07 01:34:59 -0500 |
|---|---|---|
| committer | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2011-01-07 01:34:59 -0500 |
| commit | 554738da71004d96e06fb75f4772dfc3b0f47810 (patch) | |
| tree | 149a96ce3727025d3b9260961ec94ba8306db278 /drivers/input/mouse | |
| parent | 7b4b30689d688d9ca2e5c3859db6bbe1c35e6014 (diff) | |
| parent | a6d38f889750ed6290728a19d9dad577b147c6d0 (diff) | |
Merge branch 'next' into for-linus
Conflicts:
include/linux/input.h
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); |
