diff options
Diffstat (limited to 'drivers/input/mouse/hgpk.c')
-rw-r--r-- | drivers/input/mouse/hgpk.c | 695 |
1 files changed, 614 insertions, 81 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 | } | ||