aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorDaniel Drake <dsd@laptop.org>2010-11-12 01:19:57 -0500
committerDmitry Torokhov <dmitry.torokhov@gmail.com>2010-11-12 01:21:15 -0500
commitca94ec43540ce5d93fd30a3bf88321b6f11ed51a (patch)
treea371cc49adf0273e84040b1bf59e57c35a522c4c /drivers
parent10ee2ded629b1571cef1182728d6f65dbe4c7f79 (diff)
Input: hgpk - support GlideSensor and PenTablet modes
Add a "hgpk_mode" sysfs attribute that allows selection between 3 options: Mouse (the existing option), GlideSensor and PenTablet. GlideSensor is an enhanced protocol for the regular touchpad mode that additionally reports pressure and uses absolute coordinates. We suspect that it may be more reliable than mouse mode in some environments. PenTablet mode puts the touchpad into resistive mode, you must then use a stylus as an input. We suspect this is the most reliable way to drive the touchpad. The GlideSensor and PenTablet devices expose themselves with the intention of being combined with the synaptics X11 input driver. Based on earlier work by Paul Fox. Signed-off-by: Daniel Drake <dsd@laptop.org> Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/input/mouse/hgpk.c467
-rw-r--r--drivers/input/mouse/hgpk.h16
-rw-r--r--drivers/input/mouse/psmouse-base.c1
3 files changed, 441 insertions, 43 deletions
diff --git a/drivers/input/mouse/hgpk.c b/drivers/input/mouse/hgpk.c
index 1d2205b24800..3d33d958a122 100644
--- a/drivers/input/mouse/hgpk.c
+++ b/drivers/input/mouse/hgpk.c
@@ -69,6 +69,32 @@ module_param(post_interrupt_delay, int, 0644);
69MODULE_PARM_DESC(post_interrupt_delay, 69MODULE_PARM_DESC(post_interrupt_delay,
70 "delay (ms) before recal after recal interrupt detected"); 70 "delay (ms) before recal after recal interrupt detected");
71 71
72static char hgpk_mode_name[16];
73module_param_string(hgpk_mode, hgpk_mode_name, sizeof(hgpk_mode_name), 0644);
74MODULE_PARM_DESC(hgpk_mode,
75 "default hgpk mode: mouse, glidesensor or pentablet");
76
77static int hgpk_default_mode = HGPK_MODE_MOUSE;
78
79static const char * const hgpk_mode_names[] = {
80 [HGPK_MODE_MOUSE] = "Mouse",
81 [HGPK_MODE_GLIDESENSOR] = "GlideSensor",
82 [HGPK_MODE_PENTABLET] = "PenTablet",
83};
84
85static int hgpk_mode_from_name(const char *buf, int len)
86{
87 int i;
88
89 for (i = 0; i < ARRAY_SIZE(hgpk_mode_names); i++) {
90 const char *name = hgpk_mode_names[i];
91 if (strlen(name) == len && !strncasecmp(name, buf, len))
92 return i;
93 }
94
95 return HGPK_MODE_INVALID;
96}
97
72/* 98/*
73 * When the touchpad gets ultra-sensitive, one can keep their finger 1/2" 99 * When the touchpad gets ultra-sensitive, one can keep their finger 1/2"
74 * above the pad and still have it send packets. This causes a jump cursor 100 * above the pad and still have it send packets. This causes a jump cursor
@@ -143,23 +169,139 @@ static void hgpk_spewing_hack(struct psmouse *psmouse,
143 * swr/swl are the left/right buttons. 169 * swr/swl are the left/right buttons.
144 * x-neg/y-neg are the x and y delta negative bits 170 * x-neg/y-neg are the x and y delta negative bits
145 * x-over/y-over are the x and y overflow bits 171 * x-over/y-over are the x and y overflow bits
172 *
173 * ---
174 *
175 * HGPK Advanced Mode - single-mode format
176 *
177 * byte 0(PT): 1 1 0 0 1 1 1 1
178 * byte 0(GS): 1 1 1 1 1 1 1 1
179 * byte 1: 0 x6 x5 x4 x3 x2 x1 x0
180 * byte 2(PT): 0 0 x9 x8 x7 ? pt-dsw 0
181 * byte 2(GS): 0 x10 x9 x8 x7 ? gs-dsw pt-dsw
182 * byte 3: 0 y9 y8 y7 1 0 swr swl
183 * byte 4: 0 y6 y5 y4 y3 y2 y1 y0
184 * byte 5: 0 z6 z5 z4 z3 z2 z1 z0
185 *
186 * ?'s are not defined in the protocol spec, may vary between models.
187 *
188 * swr/swl are the left/right buttons.
189 *
190 * pt-dsw/gs-dsw indicate that the pt/gs sensor is detecting a
191 * pen/finger
146 */ 192 */
147static int hgpk_validate_byte(unsigned char *packet) 193static bool hgpk_is_byte_valid(struct psmouse *psmouse, unsigned char *packet)
148{ 194{
149 return (packet[0] & 0x0C) != 0x08; 195 struct hgpk_data *priv = psmouse->private;
196 int pktcnt = psmouse->pktcnt;
197 bool valid;
198
199 switch (priv->mode) {
200 case HGPK_MODE_MOUSE:
201 valid = (packet[0] & 0x0C) == 0x08;
202 break;
203
204 case HGPK_MODE_GLIDESENSOR:
205 valid = pktcnt == 1 ?
206 packet[0] == HGPK_GS : !(packet[pktcnt - 1] & 0x80);
207 break;
208
209 case HGPK_MODE_PENTABLET:
210 valid = pktcnt == 1 ?
211 packet[0] == HGPK_PT : !(packet[pktcnt - 1] & 0x80);
212 break;
213
214 default:
215 valid = false;
216 break;
217 }
218
219 if (!valid)
220 hgpk_dbg(psmouse,
221 "bad data, mode %d (%d) %02x %02x %02x %02x %02x %02x\n",
222 priv->mode, pktcnt,
223 psmouse->packet[0], psmouse->packet[1],
224 psmouse->packet[2], psmouse->packet[3],
225 psmouse->packet[4], psmouse->packet[5]);
226
227 return valid;
150} 228}
151 229
152static void hgpk_process_packet(struct psmouse *psmouse) 230static void hgpk_process_advanced_packet(struct psmouse *psmouse)
153{ 231{
154 struct input_dev *dev = psmouse->dev; 232 struct hgpk_data *priv = psmouse->private;
233 struct input_dev *idev = psmouse->dev;
155 unsigned char *packet = psmouse->packet; 234 unsigned char *packet = psmouse->packet;
156 int x, y, left, right; 235 int down = !!(packet[2] & 2);
236 int left = !!(packet[3] & 1);
237 int right = !!(packet[3] & 2);
238 int x = packet[1] | ((packet[2] & 0x78) << 4);
239 int y = packet[4] | ((packet[3] & 0x70) << 3);
240
241 if (priv->mode == HGPK_MODE_GLIDESENSOR) {
242 int pt_down = !!(packet[2] & 1);
243 int finger_down = !!(packet[2] & 2);
244 int z = packet[5];
245
246 input_report_abs(idev, ABS_PRESSURE, z);
247 if (tpdebug)
248 hgpk_dbg(psmouse, "pd=%d fd=%d z=%d",
249 pt_down, finger_down, z);
250 } else {
251 /*
252 * PenTablet mode does not report pressure, so we don't
253 * report it here
254 */
255 if (tpdebug)
256 hgpk_dbg(psmouse, "pd=%d ", down);
257 }
157 258
158 left = packet[0] & 1; 259 if (tpdebug)
159 right = (packet[0] >> 1) & 1; 260 hgpk_dbg(psmouse, "l=%d r=%d x=%d y=%d\n", left, right, x, y);
160 261
161 x = packet[1] - ((packet[0] << 4) & 0x100); 262 input_report_key(idev, BTN_TOUCH, down);
162 y = ((packet[0] << 3) & 0x100) - packet[2]; 263 input_report_key(idev, BTN_LEFT, left);
264 input_report_key(idev, BTN_RIGHT, right);
265
266 /*
267 * If this packet says that the finger was removed, reset our position
268 * tracking so that we don't erroneously detect a jump on next press.
269 */
270 if (!down)
271 priv->abs_x = priv->abs_y = -1;
272
273 /*
274 * Report position if finger/pen is down, but weed out duplicate
275 * packets (we get quite a few in this mode, and they mess up our
276 * jump detection.
277 */
278 if (down && (x != priv->abs_x || y != priv->abs_y)) {
279
280 /* Don't apply hacks in PT mode, it seems reliable */
281 if (priv->mode != HGPK_MODE_PENTABLET && priv->abs_x != -1) {
282 hgpk_jumpy_hack(psmouse,
283 priv->abs_x - x, priv->abs_y - y);
284 hgpk_spewing_hack(psmouse, left, right,
285 priv->abs_x - x, priv->abs_y - y);
286 }
287
288 input_report_abs(idev, ABS_X, x);
289 input_report_abs(idev, ABS_Y, y);
290 priv->abs_x = x;
291 priv->abs_y = y;
292 }
293
294 input_sync(idev);
295}
296
297static void hgpk_process_simple_packet(struct psmouse *psmouse)
298{
299 struct input_dev *dev = psmouse->dev;
300 unsigned char *packet = psmouse->packet;
301 int left = packet[0] & 1;
302 int right = (packet[0] >> 1) & 1;
303 int x = packet[1] - ((packet[0] << 4) & 0x100);
304 int y = ((packet[0] << 3) & 0x100) - packet[2];
163 305
164 hgpk_jumpy_hack(psmouse, x, y); 306 hgpk_jumpy_hack(psmouse, x, y);
165 hgpk_spewing_hack(psmouse, left, right, x, y); 307 hgpk_spewing_hack(psmouse, left, right, x, y);
@@ -180,15 +322,14 @@ static psmouse_ret_t hgpk_process_byte(struct psmouse *psmouse)
180{ 322{
181 struct hgpk_data *priv = psmouse->private; 323 struct hgpk_data *priv = psmouse->private;
182 324
183 if (hgpk_validate_byte(psmouse->packet)) { 325 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; 326 return PSMOUSE_BAD_DATA;
188 }
189 327
190 if (psmouse->pktcnt >= psmouse->pktsize) { 328 if (psmouse->pktcnt >= psmouse->pktsize) {
191 hgpk_process_packet(psmouse); 329 if (priv->mode == HGPK_MODE_MOUSE)
330 hgpk_process_simple_packet(psmouse);
331 else
332 hgpk_process_advanced_packet(psmouse);
192 return PSMOUSE_FULL_PACKET; 333 return PSMOUSE_FULL_PACKET;
193 } 334 }
194 335
@@ -210,10 +351,161 @@ static psmouse_ret_t hgpk_process_byte(struct psmouse *psmouse)
210 return PSMOUSE_GOOD_DATA; 351 return PSMOUSE_GOOD_DATA;
211} 352}
212 353
354static int hgpk_select_mode(struct psmouse *psmouse)
355{
356 struct ps2dev *ps2dev = &psmouse->ps2dev;
357 struct hgpk_data *priv = psmouse->private;
358 int i;
359 int cmd;
360
361 /*
362 * 4 disables to enable advanced mode
363 * then 3 0xf2 bytes as the preamble for GS/PT selection
364 */
365 const int advanced_init[] = {
366 PSMOUSE_CMD_DISABLE, PSMOUSE_CMD_DISABLE,
367 PSMOUSE_CMD_DISABLE, PSMOUSE_CMD_DISABLE,
368 0xf2, 0xf2, 0xf2,
369 };
370
371 switch (priv->mode) {
372 case HGPK_MODE_MOUSE:
373 psmouse->pktsize = 3;
374 break;
375
376 case HGPK_MODE_GLIDESENSOR:
377 case HGPK_MODE_PENTABLET:
378 psmouse->pktsize = 6;
379
380 /* Switch to 'Advanced mode.', four disables in a row. */
381 for (i = 0; i < ARRAY_SIZE(advanced_init); i++)
382 if (ps2_command(ps2dev, NULL, advanced_init[i]))
383 return -EIO;
384
385 /* select between GlideSensor (mouse) or PenTablet */
386 cmd = priv->mode == HGPK_MODE_GLIDESENSOR ?
387 PSMOUSE_CMD_SETSCALE11 : PSMOUSE_CMD_SETSCALE21;
388
389 if (ps2_command(ps2dev, NULL, cmd))
390 return -EIO;
391 break;
392
393 default:
394 return -EINVAL;
395 }
396
397 return 0;
398}
399
400static void hgpk_setup_input_device(struct input_dev *input,
401 struct input_dev *old_input,
402 enum hgpk_mode mode)
403{
404 if (old_input) {
405 input->name = old_input->name;
406 input->phys = old_input->phys;
407 input->id = old_input->id;
408 input->dev.parent = old_input->dev.parent;
409 }
410
411 memset(input->evbit, 0, sizeof(input->evbit));
412 memset(input->relbit, 0, sizeof(input->relbit));
413 memset(input->keybit, 0, sizeof(input->keybit));
414
415 /* All modes report left and right buttons */
416 __set_bit(EV_KEY, input->evbit);
417 __set_bit(BTN_LEFT, input->keybit);
418 __set_bit(BTN_RIGHT, input->keybit);
419
420 switch (mode) {
421 case HGPK_MODE_MOUSE:
422 __set_bit(EV_REL, input->evbit);
423 __set_bit(REL_X, input->relbit);
424 __set_bit(REL_Y, input->relbit);
425 break;
426
427 case HGPK_MODE_GLIDESENSOR:
428 __set_bit(BTN_TOUCH, input->keybit);
429 __set_bit(BTN_TOOL_FINGER, input->keybit);
430
431 __set_bit(EV_ABS, input->evbit);
432
433 /* GlideSensor has pressure sensor, PenTablet does not */
434 input_set_abs_params(input, ABS_PRESSURE, 0, 15, 0, 0);
435
436 /* From device specs */
437 input_set_abs_params(input, ABS_X, 0, 399, 0, 0);
438 input_set_abs_params(input, ABS_Y, 0, 290, 0, 0);
439
440 /* Calculated by hand based on usable size (52mm x 38mm) */
441 input_abs_set_res(input, ABS_X, 8);
442 input_abs_set_res(input, ABS_Y, 8);
443 break;
444
445 case HGPK_MODE_PENTABLET:
446 __set_bit(BTN_TOUCH, input->keybit);
447 __set_bit(BTN_TOOL_FINGER, input->keybit);
448
449 __set_bit(EV_ABS, input->evbit);
450
451 /* From device specs */
452 input_set_abs_params(input, ABS_X, 0, 999, 0, 0);
453 input_set_abs_params(input, ABS_Y, 5, 239, 0, 0);
454
455 /* Calculated by hand based on usable size (156mm x 38mm) */
456 input_abs_set_res(input, ABS_X, 6);
457 input_abs_set_res(input, ABS_Y, 8);
458 break;
459
460 default:
461 BUG();
462 }
463}
464
465static void hgpk_reset_hack_state(struct psmouse *psmouse)
466{
467 struct hgpk_data *priv = psmouse->private;
468
469 priv->abs_x = priv->abs_y = -1;
470}
471
472static int hgpk_reset_device(struct psmouse *psmouse, bool recalibrate)
473{
474 int err;
475
476 psmouse_reset(psmouse);
477
478 if (recalibrate) {
479 struct ps2dev *ps2dev = &psmouse->ps2dev;
480
481 /* send the recalibrate request */
482 if (ps2_command(ps2dev, NULL, 0xf5) ||
483 ps2_command(ps2dev, NULL, 0xf5) ||
484 ps2_command(ps2dev, NULL, 0xe6) ||
485 ps2_command(ps2dev, NULL, 0xf5)) {
486 return -1;
487 }
488
489 /* according to ALPS, 150mS is required for recalibration */
490 msleep(150);
491 }
492
493 err = hgpk_select_mode(psmouse);
494 if (err) {
495 hgpk_err(psmouse, "failed to select mode\n");
496 return err;
497 }
498
499 hgpk_reset_hack_state(psmouse);
500
501 return 0;
502}
503
213static int hgpk_force_recalibrate(struct psmouse *psmouse) 504static int hgpk_force_recalibrate(struct psmouse *psmouse)
214{ 505{
215 struct ps2dev *ps2dev = &psmouse->ps2dev; 506 struct ps2dev *ps2dev = &psmouse->ps2dev;
216 struct hgpk_data *priv = psmouse->private; 507 struct hgpk_data *priv = psmouse->private;
508 int err;
217 509
218 /* C-series touchpads added the recalibrate command */ 510 /* C-series touchpads added the recalibrate command */
219 if (psmouse->model < HGPK_MODEL_C) 511 if (psmouse->model < HGPK_MODEL_C)
@@ -223,20 +515,12 @@ static int hgpk_force_recalibrate(struct psmouse *psmouse)
223 psmouse_set_state(psmouse, PSMOUSE_INITIALIZING); 515 psmouse_set_state(psmouse, PSMOUSE_INITIALIZING);
224 516
225 /* start by resetting the device */ 517 /* start by resetting the device */
226 psmouse_reset(psmouse); 518 err = hgpk_reset_device(psmouse, true);
227 519 if (err)
228 /* send the recalibrate request */ 520 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 521
239 /* XXX: If a finger is down during this delay, recalibration will 522 /*
523 * XXX: If a finger is down during this delay, recalibration will
240 * detect capacitance incorrectly. This is a hardware bug, and 524 * 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 525 * we don't have a good way to deal with it. The 2s window stuff
242 * (below) is our best option for now. 526 * (below) is our best option for now.
@@ -247,12 +531,13 @@ static int hgpk_force_recalibrate(struct psmouse *psmouse)
247 531
248 psmouse_set_state(psmouse, PSMOUSE_ACTIVATED); 532 psmouse_set_state(psmouse, PSMOUSE_ACTIVATED);
249 533
250 /* After we recalibrate, we shouldn't get any packets for 2s. If 534 /*
535 * After we recalibrate, we shouldn't get any packets for 2s. If
251 * we do, it's likely that someone's finger was on the touchpad. 536 * we do, it's likely that someone's finger was on the touchpad.
252 * If someone's finger *was* on the touchpad, it's probably 537 * If someone's finger *was* on the touchpad, it's probably
253 * miscalibrated. So, we should schedule another recalibration 538 * miscalibrated. So, we should schedule another recalibration
254 */ 539 */
255 priv->recalib_window = jiffies + msecs_to_jiffies(recal_guard_time); 540 priv->recalib_window = jiffies + msecs_to_jiffies(recal_guard_time);
256 541
257 return 0; 542 return 0;
258} 543}
@@ -266,6 +551,7 @@ static int hgpk_toggle_power(struct psmouse *psmouse, int enable)
266{ 551{
267 struct ps2dev *ps2dev = &psmouse->ps2dev; 552 struct ps2dev *ps2dev = &psmouse->ps2dev;
268 int timeo; 553 int timeo;
554 int err;
269 555
270 /* Added on D-series touchpads */ 556 /* Added on D-series touchpads */
271 if (psmouse->model < HGPK_MODEL_D) 557 if (psmouse->model < HGPK_MODEL_D)
@@ -288,7 +574,11 @@ static int hgpk_toggle_power(struct psmouse *psmouse, int enable)
288 msleep(50); 574 msleep(50);
289 } 575 }
290 576
291 psmouse_reset(psmouse); 577 err = hgpk_reset_device(psmouse, false);
578 if (err) {
579 hgpk_err(psmouse, "Failed to reset device!\n");
580 return err;
581 }
292 582
293 /* should be all set, enable the touchpad */ 583 /* should be all set, enable the touchpad */
294 ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_ENABLE); 584 ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_ENABLE);
@@ -319,17 +609,17 @@ static int hgpk_poll(struct psmouse *psmouse)
319 609
320static int hgpk_reconnect(struct psmouse *psmouse) 610static int hgpk_reconnect(struct psmouse *psmouse)
321{ 611{
322 /* During suspend/resume the ps2 rails remain powered. We don't want 612 /*
613 * 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, 614 * to do a reset because it's flush data out of buffers; however,
324 * earlier prototypes (B1) had some brokenness that required a reset. */ 615 * earlier prototypes (B1) had some brokenness that required a reset.
616 */
325 if (olpc_board_at_least(olpc_board(0xb2))) 617 if (olpc_board_at_least(olpc_board(0xb2)))
326 if (psmouse->ps2dev.serio->dev.power.power_state.event != 618 if (psmouse->ps2dev.serio->dev.power.power_state.event !=
327 PM_EVENT_ON) 619 PM_EVENT_ON)
328 return 0; 620 return 0;
329 621
330 psmouse_reset(psmouse); 622 return hgpk_reset_device(psmouse, false);
331
332 return 0;
333} 623}
334 624
335static ssize_t hgpk_show_powered(struct psmouse *psmouse, void *data, char *buf) 625static ssize_t hgpk_show_powered(struct psmouse *psmouse, void *data, char *buf)
@@ -366,6 +656,65 @@ static ssize_t hgpk_set_powered(struct psmouse *psmouse, void *data,
366__PSMOUSE_DEFINE_ATTR(powered, S_IWUSR | S_IRUGO, NULL, 656__PSMOUSE_DEFINE_ATTR(powered, S_IWUSR | S_IRUGO, NULL,
367 hgpk_show_powered, hgpk_set_powered, false); 657 hgpk_show_powered, hgpk_set_powered, false);
368 658
659static ssize_t attr_show_mode(struct psmouse *psmouse, void *data, char *buf)
660{
661 struct hgpk_data *priv = psmouse->private;
662
663 return sprintf(buf, "%s\n", hgpk_mode_names[priv->mode]);
664}
665
666static ssize_t attr_set_mode(struct psmouse *psmouse, void *data,
667 const char *buf, size_t len)
668{
669 struct hgpk_data *priv = psmouse->private;
670 enum hgpk_mode old_mode = priv->mode;
671 enum hgpk_mode new_mode = hgpk_mode_from_name(buf, len);
672 struct input_dev *old_dev = psmouse->dev;
673 struct input_dev *new_dev;
674 int err;
675
676 if (new_mode == HGPK_MODE_INVALID)
677 return -EINVAL;
678
679 if (old_mode == new_mode)
680 return len;
681
682 new_dev = input_allocate_device();
683 if (!new_dev)
684 return -ENOMEM;
685
686 psmouse_set_state(psmouse, PSMOUSE_INITIALIZING);
687
688 /* Switch device into the new mode */
689 priv->mode = new_mode;
690 err = hgpk_reset_device(psmouse, false);
691 if (err)
692 goto err_try_restore;
693
694 hgpk_setup_input_device(new_dev, old_dev, new_mode);
695
696 psmouse_set_state(psmouse, PSMOUSE_CMD_MODE);
697
698 err = input_register_device(new_dev);
699 if (err)
700 goto err_try_restore;
701
702 psmouse->dev = new_dev;
703 input_unregister_device(old_dev);
704
705 return len;
706
707err_try_restore:
708 input_free_device(new_dev);
709 priv->mode = old_mode;
710 hgpk_reset_device(psmouse, false);
711
712 return err;
713}
714
715PSMOUSE_DEFINE_ATTR(hgpk_mode, S_IWUSR | S_IRUGO, NULL,
716 attr_show_mode, attr_set_mode);
717
369static ssize_t hgpk_trigger_recal_show(struct psmouse *psmouse, 718static ssize_t hgpk_trigger_recal_show(struct psmouse *psmouse,
370 void *data, char *buf) 719 void *data, char *buf)
371{ 720{
@@ -401,6 +750,8 @@ static void hgpk_disconnect(struct psmouse *psmouse)
401 750
402 device_remove_file(&psmouse->ps2dev.serio->dev, 751 device_remove_file(&psmouse->ps2dev.serio->dev,
403 &psmouse_attr_powered.dattr); 752 &psmouse_attr_powered.dattr);
753 device_remove_file(&psmouse->ps2dev.serio->dev,
754 &psmouse_attr_hgpk_mode.dattr);
404 755
405 if (psmouse->model >= HGPK_MODEL_C) 756 if (psmouse->model >= HGPK_MODEL_C)
406 device_remove_file(&psmouse->ps2dev.serio->dev, 757 device_remove_file(&psmouse->ps2dev.serio->dev,
@@ -424,6 +775,7 @@ static void hgpk_recalib_work(struct work_struct *work)
424 775
425static int hgpk_register(struct psmouse *psmouse) 776static int hgpk_register(struct psmouse *psmouse)
426{ 777{
778 struct hgpk_data *priv = psmouse->private;
427 int err; 779 int err;
428 780
429 /* register handlers */ 781 /* register handlers */
@@ -431,13 +783,14 @@ static int hgpk_register(struct psmouse *psmouse)
431 psmouse->poll = hgpk_poll; 783 psmouse->poll = hgpk_poll;
432 psmouse->disconnect = hgpk_disconnect; 784 psmouse->disconnect = hgpk_disconnect;
433 psmouse->reconnect = hgpk_reconnect; 785 psmouse->reconnect = hgpk_reconnect;
434 psmouse->pktsize = 3;
435 786
436 /* Disable the idle resync. */ 787 /* Disable the idle resync. */
437 psmouse->resync_time = 0; 788 psmouse->resync_time = 0;
438 /* Reset after a lot of bad bytes. */ 789 /* Reset after a lot of bad bytes. */
439 psmouse->resetafter = 1024; 790 psmouse->resetafter = 1024;
440 791
792 hgpk_setup_input_device(psmouse->dev, NULL, priv->mode);
793
441 err = device_create_file(&psmouse->ps2dev.serio->dev, 794 err = device_create_file(&psmouse->ps2dev.serio->dev,
442 &psmouse_attr_powered.dattr); 795 &psmouse_attr_powered.dattr);
443 if (err) { 796 if (err) {
@@ -445,6 +798,13 @@ static int hgpk_register(struct psmouse *psmouse)
445 return err; 798 return err;
446 } 799 }
447 800
801 err = device_create_file(&psmouse->ps2dev.serio->dev,
802 &psmouse_attr_hgpk_mode.dattr);
803 if (err) {
804 hgpk_err(psmouse, "Failed creating 'hgpk_mode' sysfs node\n");
805 goto err_remove_powered;
806 }
807
448 /* C-series touchpads added the recalibrate command */ 808 /* C-series touchpads added the recalibrate command */
449 if (psmouse->model >= HGPK_MODEL_C) { 809 if (psmouse->model >= HGPK_MODEL_C) {
450 err = device_create_file(&psmouse->ps2dev.serio->dev, 810 err = device_create_file(&psmouse->ps2dev.serio->dev,
@@ -452,30 +812,40 @@ static int hgpk_register(struct psmouse *psmouse)
452 if (err) { 812 if (err) {
453 hgpk_err(psmouse, 813 hgpk_err(psmouse,
454 "Failed creating 'recalibrate' sysfs node\n"); 814 "Failed creating 'recalibrate' sysfs node\n");
455 device_remove_file(&psmouse->ps2dev.serio->dev, 815 goto err_remove_mode;
456 &psmouse_attr_powered.dattr);
457 return err;
458 } 816 }
459 } 817 }
460 818
461 return 0; 819 return 0;
820
821err_remove_mode:
822 device_remove_file(&psmouse->ps2dev.serio->dev,
823 &psmouse_attr_hgpk_mode.dattr);
824err_remove_powered:
825 device_remove_file(&psmouse->ps2dev.serio->dev,
826 &psmouse_attr_powered.dattr);
827 return err;
462} 828}
463 829
464int hgpk_init(struct psmouse *psmouse) 830int hgpk_init(struct psmouse *psmouse)
465{ 831{
466 struct hgpk_data *priv; 832 struct hgpk_data *priv;
467 int err = -ENOMEM; 833 int err;
468 834
469 priv = kzalloc(sizeof(struct hgpk_data), GFP_KERNEL); 835 priv = kzalloc(sizeof(struct hgpk_data), GFP_KERNEL);
470 if (!priv) 836 if (!priv) {
837 err = -ENOMEM;
471 goto alloc_fail; 838 goto alloc_fail;
839 }
472 840
473 psmouse->private = priv; 841 psmouse->private = priv;
842
474 priv->psmouse = psmouse; 843 priv->psmouse = psmouse;
475 priv->powered = true; 844 priv->powered = true;
845 priv->mode = hgpk_default_mode;
476 INIT_DELAYED_WORK(&priv->recalib_wq, hgpk_recalib_work); 846 INIT_DELAYED_WORK(&priv->recalib_wq, hgpk_recalib_work);
477 847
478 err = psmouse_reset(psmouse); 848 err = hgpk_reset_device(psmouse, false);
479 if (err) 849 if (err)
480 goto init_fail; 850 goto init_fail;
481 851
@@ -531,3 +901,14 @@ int hgpk_detect(struct psmouse *psmouse, bool set_properties)
531 901
532 return 0; 902 return 0;
533} 903}
904
905void hgpk_module_init(void)
906{
907 hgpk_default_mode = hgpk_mode_from_name(hgpk_mode_name,
908 strlen(hgpk_mode_name));
909 if (hgpk_default_mode == HGPK_MODE_INVALID) {
910 hgpk_default_mode = HGPK_MODE_MOUSE;
911 strlcpy(hgpk_mode_name, hgpk_mode_names[HGPK_MODE_MOUSE],
912 sizeof(hgpk_mode_name));
913 }
914}
diff --git a/drivers/input/mouse/hgpk.h b/drivers/input/mouse/hgpk.h
index d61cfd3ee9cb..01c983bb8465 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
8enum hgpk_model_t { 11enum 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,21 @@ enum hgpk_model_t {
13 HGPK_MODEL_D = 0x50, /* C1, mass production */ 16 HGPK_MODEL_D = 0x50, /* C1, mass production */
14}; 17};
15 18
19enum hgpk_mode {
20 HGPK_MODE_MOUSE,
21 HGPK_MODE_GLIDESENSOR,
22 HGPK_MODE_PENTABLET,
23 HGPK_MODE_INVALID
24};
25
16struct hgpk_data { 26struct hgpk_data {
17 struct psmouse *psmouse; 27 struct psmouse *psmouse;
28 enum hgpk_mode mode;
18 bool powered; 29 bool powered;
19 int count, x_tally, y_tally; /* hardware workaround stuff */ 30 int count, x_tally, y_tally; /* hardware workaround stuff */
20 unsigned long recalib_window; 31 unsigned long recalib_window;
21 struct delayed_work recalib_wq; 32 struct delayed_work recalib_wq;
33 int abs_x, abs_y;
22}; 34};
23 35
24#define hgpk_dbg(psmouse, format, arg...) \ 36#define hgpk_dbg(psmouse, format, arg...) \
@@ -33,9 +45,13 @@ struct hgpk_data {
33 dev_notice(&(psmouse)->ps2dev.serio->dev, format, ## arg) 45 dev_notice(&(psmouse)->ps2dev.serio->dev, format, ## arg)
34 46
35#ifdef CONFIG_MOUSE_PS2_OLPC 47#ifdef CONFIG_MOUSE_PS2_OLPC
48void hgpk_module_init(void);
36int hgpk_detect(struct psmouse *psmouse, bool set_properties); 49int hgpk_detect(struct psmouse *psmouse, bool set_properties);
37int hgpk_init(struct psmouse *psmouse); 50int hgpk_init(struct psmouse *psmouse);
38#else 51#else
52static inline void hgpk_module_init(void)
53{
54}
39static inline int hgpk_detect(struct psmouse *psmouse, bool set_properties) 55static inline int hgpk_detect(struct psmouse *psmouse, bool set_properties)
40{ 56{
41 return -ENODEV; 57 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) {