From c46dd1eb9a4f1b8c1bb597a75199e3d34fb7b43b Mon Sep 17 00:00:00 2001 From: Paul Fox Date: Wed, 5 Aug 2009 00:30:31 -0700 Subject: 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 Acked-by: Andres Salomon Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/hgpk.c | 55 +++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 52 insertions(+), 3 deletions(-) (limited to 'drivers/input/mouse/hgpk.c') 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, __PSMOUSE_DEFINE_ATTR(powered, S_IWUSR | S_IRUGO, NULL, hgpk_show_powered, hgpk_set_powered, 0); +static ssize_t hgpk_trigger_recal_show(struct psmouse *psmouse, + void *data, char *buf) +{ + return -EINVAL; +} + +static ssize_t hgpk_trigger_recal(struct psmouse *psmouse, void *data, + const char *buf, size_t count) +{ + struct hgpk_data *priv = psmouse->private; + unsigned long value; + int err; + + err = strict_strtoul(buf, 10, &value); + if (err || value != 1) + return -EINVAL; + + /* + * We queue work instead of doing recalibration right here + * to avoid adding locking to to hgpk_force_recalibrate() + * since workqueue provides serialization. + */ + psmouse_queue_work(psmouse, &priv->recalib_wq, 0); + return count; +} + +__PSMOUSE_DEFINE_ATTR(recalibrate, S_IWUSR | S_IRUGO, NULL, + hgpk_trigger_recal_show, hgpk_trigger_recal, 0); + static void hgpk_disconnect(struct psmouse *psmouse) { struct hgpk_data *priv = psmouse->private; device_remove_file(&psmouse->ps2dev.serio->dev, &psmouse_attr_powered.dattr); + + if (psmouse->model >= HGPK_MODEL_C) + device_remove_file(&psmouse->ps2dev.serio->dev, + &psmouse_attr_recalibrate.dattr); + psmouse_reset(psmouse); kfree(priv); } @@ -423,10 +457,25 @@ static int hgpk_register(struct psmouse *psmouse) err = device_create_file(&psmouse->ps2dev.serio->dev, &psmouse_attr_powered.dattr); - if (err) - hgpk_err(psmouse, "Failed to create sysfs attribute\n"); + if (err) { + hgpk_err(psmouse, "Failed creating 'powered' sysfs node\n"); + return err; + } - return err; + /* C-series touchpads added the recalibrate command */ + if (psmouse->model >= HGPK_MODEL_C) { + err = device_create_file(&psmouse->ps2dev.serio->dev, + &psmouse_attr_recalibrate.dattr); + if (err) { + hgpk_err(psmouse, + "Failed creating 'recalibrate' sysfs node\n"); + device_remove_file(&psmouse->ps2dev.serio->dev, + &psmouse_attr_powered.dattr); + return err; + } + } + + return 0; } int hgpk_init(struct psmouse *psmouse) -- cgit From b7802c5c1ea9563f3746bea09c214ccedc8600f4 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Wed, 9 Sep 2009 19:13:20 -0700 Subject: Input: psmouse - use boolean type Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/hgpk.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/input/mouse/hgpk.c') diff --git a/drivers/input/mouse/hgpk.c b/drivers/input/mouse/hgpk.c index f5aa035774d9..de1e553028b7 100644 --- a/drivers/input/mouse/hgpk.c +++ b/drivers/input/mouse/hgpk.c @@ -367,7 +367,7 @@ static ssize_t hgpk_set_powered(struct psmouse *psmouse, void *data, } __PSMOUSE_DEFINE_ATTR(powered, S_IWUSR | S_IRUGO, NULL, - hgpk_show_powered, hgpk_set_powered, 0); + hgpk_show_powered, hgpk_set_powered, false); static ssize_t hgpk_trigger_recal_show(struct psmouse *psmouse, void *data, char *buf) @@ -396,7 +396,7 @@ static ssize_t hgpk_trigger_recal(struct psmouse *psmouse, void *data, } __PSMOUSE_DEFINE_ATTR(recalibrate, S_IWUSR | S_IRUGO, NULL, - hgpk_trigger_recal_show, hgpk_trigger_recal, 0); + hgpk_trigger_recal_show, hgpk_trigger_recal, false); static void hgpk_disconnect(struct psmouse *psmouse) { @@ -489,7 +489,7 @@ int hgpk_init(struct psmouse *psmouse) psmouse->private = priv; priv->psmouse = psmouse; - priv->powered = 1; + priv->powered = true; INIT_DELAYED_WORK(&priv->recalib_wq, hgpk_recalib_work); err = psmouse_reset(psmouse); @@ -532,7 +532,7 @@ static enum hgpk_model_t hgpk_get_model(struct psmouse *psmouse) return param[2]; } -int hgpk_detect(struct psmouse *psmouse, int set_properties) +int hgpk_detect(struct psmouse *psmouse, bool set_properties) { int version; -- cgit