diff options
author | Paul Fox <pgf@laptop.org> | 2009-08-05 03:30:31 -0400 |
---|---|---|
committer | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2009-08-05 03:34:32 -0400 |
commit | c46dd1eb9a4f1b8c1bb597a75199e3d34fb7b43b (patch) | |
tree | 62f03ed65d4e6cc309535e6cafb20290cce3698e /drivers/input | |
parent | cf5f439b48f82c230dcd81d0061e00664cbb6d39 (diff) |
Input: hgpk - forced recalibration for the OLPC touchpad
The OLPC XO laptop incorporates a combination touchpad/tablet device
which unfortunately requires frequent recalibration. The driver will
force this automatically when various suspicious behaviors are
observed, and the user can recalibrate manually (with a special
keyboard sequence). There's currently no way, however, for an external
program to cause recalibration. We can not use the reconnect
capability which is already available in /sys because full reset of
the touchpad takes 1.1 - 1.2 secons which is too long.
This patch creates a new node in /sys which, when written with '1',
will force a touchpad recalibration; no other writes (or reads)
of this node are supported.
Signed-off-by: Paul Fox <pgf@laptop.org>
Acked-by: Andres Salomon <dilinger@collabora.co.uk>
Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
Diffstat (limited to 'drivers/input')
-rw-r--r-- | drivers/input/mouse/hgpk.c | 55 |
1 files changed, 52 insertions, 3 deletions
diff --git a/drivers/input/mouse/hgpk.c b/drivers/input/mouse/hgpk.c index a1ad2f1a7bb3..f5aa035774d9 100644 --- a/drivers/input/mouse/hgpk.c +++ b/drivers/input/mouse/hgpk.c | |||
@@ -369,12 +369,46 @@ static ssize_t hgpk_set_powered(struct psmouse *psmouse, void *data, | |||
369 | __PSMOUSE_DEFINE_ATTR(powered, S_IWUSR | S_IRUGO, NULL, | 369 | __PSMOUSE_DEFINE_ATTR(powered, S_IWUSR | S_IRUGO, NULL, |
370 | hgpk_show_powered, hgpk_set_powered, 0); | 370 | hgpk_show_powered, hgpk_set_powered, 0); |
371 | 371 | ||
372 | static ssize_t hgpk_trigger_recal_show(struct psmouse *psmouse, | ||
373 | void *data, char *buf) | ||
374 | { | ||
375 | return -EINVAL; | ||
376 | } | ||
377 | |||
378 | static ssize_t hgpk_trigger_recal(struct psmouse *psmouse, void *data, | ||
379 | const char *buf, size_t count) | ||
380 | { | ||
381 | struct hgpk_data *priv = psmouse->private; | ||
382 | unsigned long value; | ||
383 | int err; | ||
384 | |||
385 | err = strict_strtoul(buf, 10, &value); | ||
386 | if (err || value != 1) | ||
387 | return -EINVAL; | ||
388 | |||
389 | /* | ||
390 | * We queue work instead of doing recalibration right here | ||
391 | * to avoid adding locking to to hgpk_force_recalibrate() | ||
392 | * since workqueue provides serialization. | ||
393 | */ | ||
394 | psmouse_queue_work(psmouse, &priv->recalib_wq, 0); | ||
395 | return count; | ||
396 | } | ||
397 | |||
398 | __PSMOUSE_DEFINE_ATTR(recalibrate, S_IWUSR | S_IRUGO, NULL, | ||
399 | hgpk_trigger_recal_show, hgpk_trigger_recal, 0); | ||
400 | |||
372 | static void hgpk_disconnect(struct psmouse *psmouse) | 401 | static void hgpk_disconnect(struct psmouse *psmouse) |
373 | { | 402 | { |
374 | struct hgpk_data *priv = psmouse->private; | 403 | struct hgpk_data *priv = psmouse->private; |
375 | 404 | ||
376 | device_remove_file(&psmouse->ps2dev.serio->dev, | 405 | device_remove_file(&psmouse->ps2dev.serio->dev, |
377 | &psmouse_attr_powered.dattr); | 406 | &psmouse_attr_powered.dattr); |
407 | |||
408 | if (psmouse->model >= HGPK_MODEL_C) | ||
409 | device_remove_file(&psmouse->ps2dev.serio->dev, | ||
410 | &psmouse_attr_recalibrate.dattr); | ||
411 | |||
378 | psmouse_reset(psmouse); | 412 | psmouse_reset(psmouse); |
379 | kfree(priv); | 413 | kfree(priv); |
380 | } | 414 | } |
@@ -423,10 +457,25 @@ static int hgpk_register(struct psmouse *psmouse) | |||
423 | 457 | ||
424 | err = device_create_file(&psmouse->ps2dev.serio->dev, | 458 | err = device_create_file(&psmouse->ps2dev.serio->dev, |
425 | &psmouse_attr_powered.dattr); | 459 | &psmouse_attr_powered.dattr); |
426 | if (err) | 460 | if (err) { |
427 | hgpk_err(psmouse, "Failed to create sysfs attribute\n"); | 461 | hgpk_err(psmouse, "Failed creating 'powered' sysfs node\n"); |
462 | return err; | ||
463 | } | ||
428 | 464 | ||
429 | return err; | 465 | /* C-series touchpads added the recalibrate command */ |
466 | if (psmouse->model >= HGPK_MODEL_C) { | ||
467 | err = device_create_file(&psmouse->ps2dev.serio->dev, | ||
468 | &psmouse_attr_recalibrate.dattr); | ||
469 | if (err) { | ||
470 | hgpk_err(psmouse, | ||
471 | "Failed creating 'recalibrate' sysfs node\n"); | ||
472 | device_remove_file(&psmouse->ps2dev.serio->dev, | ||
473 | &psmouse_attr_powered.dattr); | ||
474 | return err; | ||
475 | } | ||
476 | } | ||
477 | |||
478 | return 0; | ||
430 | } | 479 | } |
431 | 480 | ||
432 | int hgpk_init(struct psmouse *psmouse) | 481 | int hgpk_init(struct psmouse *psmouse) |