diff options
-rw-r--r-- | drivers/input/mouse/olpc.c | 28 | ||||
-rw-r--r-- | drivers/input/mouse/olpc.h | 2 |
2 files changed, 26 insertions, 4 deletions
diff --git a/drivers/input/mouse/olpc.c b/drivers/input/mouse/olpc.c index 3f981789f92b..1a046ee41d83 100644 --- a/drivers/input/mouse/olpc.c +++ b/drivers/input/mouse/olpc.c @@ -151,6 +151,12 @@ static void olpc_process_packet_gspt(struct psmouse *psmouse) input_sync(dev); input_sync(dev2); + if (priv->pending_mode == OLPC_GS && + psmouse->packet[0] == OLPC_PKT_PT && pt_down) { + priv->pending_mode = 0; + cancel_delayed_work(&priv->mode_switch); + } + if (priv->i->flags & (OLPC_PT|OLPC_GS)) { int pending = 0; if (psmouse->packet[0] == OLPC_PKT_PT && !pt_down) @@ -166,7 +172,7 @@ static void olpc_process_packet_gspt(struct psmouse *psmouse) priv->pending_mode = pending; printk(KERN_WARNING "Scheduling mode switch to %s.\n", pending == OLPC_GS ? "GS" : "PT"); - queue_work(kpsmoused_wq, &priv->mode_switch); + queue_delayed_work(kpsmoused_wq, &priv->mode_switch, 0); } } } @@ -353,8 +359,9 @@ static void olpc_disconnect(struct psmouse *psmouse) kfree(priv); } -static void olpc_mode_switch(struct work_struct *work) +static void olpc_mode_switch(struct work_struct *w) { + struct delayed_work *work = container_of(w, struct delayed_work, work); struct olpc_data *priv = container_of(work, struct olpc_data, mode_switch); struct psmouse *psmouse = priv->psmouse; struct ps2dev *ps2dev = &psmouse->ps2dev; @@ -386,8 +393,23 @@ static void olpc_mode_switch(struct work_struct *work) * hardware sends back its ACK, it has stopped sending bytes). */ pending_mode = priv->pending_mode; + if (olpc_new_mode(psmouse, priv->pending_mode)) goto bad; + + /* + * Deal with a potential race condition. + * + * If there is a brief tap of a stylus or a fingernail that + * triggers a mode switch to PT mode, and the stylus/fingernail is + * lifted after the DISABLE above, but before we reenable in the new mode, + * then we can get stuck in PT mode. + */ + if (pending_mode == OLPC_PT) { + priv->pending_mode = OLPC_GS; + queue_delayed_work(kpsmoused_wq, &priv->mode_switch, msecs_to_jiffies(50)); + } + return; bad: @@ -477,7 +499,7 @@ int olpc_init(struct psmouse *psmouse) /* Reset after a lot of bad bytes. */ psmouse->resetafter = 1024; - INIT_WORK(&priv->mode_switch, olpc_mode_switch); + INIT_DELAYED_WORK(&priv->mode_switch, olpc_mode_switch); return 0; diff --git a/drivers/input/mouse/olpc.h b/drivers/input/mouse/olpc.h index 6c88de4b12cf..74c2e4111ba6 100644 --- a/drivers/input/mouse/olpc.h +++ b/drivers/input/mouse/olpc.h @@ -32,7 +32,7 @@ struct olpc_data { int pending_mode; int current_mode; s64 late; - struct work_struct mode_switch; + struct delayed_work mode_switch; }; |