diff options
| author | Dmitry Torokhov <dtor_core@ameritech.net> | 2006-01-14 00:27:37 -0500 |
|---|---|---|
| committer | Dmitry Torokhov <dtor_core@ameritech.net> | 2006-01-14 00:27:37 -0500 |
| commit | f0d5c6f419d3a10443f66d6835855837eae4ac4b (patch) | |
| tree | edbaf897d4618095a69865f198d26d2d017813d4 | |
| parent | b65d0d1bacfdbb4a134a7ebd16f280d5d42241cb (diff) | |
Input: psmouse - attempt to re-synchronize mouse every 5 seconds
This should help driver to deal vith KVMs that reset mice when
switching between boxes.
Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
| -rw-r--r-- | drivers/input/mouse/alps.c | 38 | ||||
| -rw-r--r-- | drivers/input/mouse/logips2pp.c | 2 | ||||
| -rw-r--r-- | drivers/input/mouse/psmouse-base.c | 316 | ||||
| -rw-r--r-- | drivers/input/mouse/psmouse.h | 9 | ||||
| -rw-r--r-- | drivers/input/mouse/synaptics.c | 2 |
5 files changed, 301 insertions, 66 deletions
diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c index 24474335dfd1..2141501e9f2e 100644 --- a/drivers/input/mouse/alps.c +++ b/drivers/input/mouse/alps.c | |||
| @@ -348,6 +348,40 @@ static int alps_tap_mode(struct psmouse *psmouse, int enable) | |||
| 348 | return 0; | 348 | return 0; |
| 349 | } | 349 | } |
| 350 | 350 | ||
| 351 | /* | ||
| 352 | * alps_poll() - poll the touchpad for current motion packet. | ||
| 353 | * Used in resync. | ||
| 354 | */ | ||
| 355 | static int alps_poll(struct psmouse *psmouse) | ||
| 356 | { | ||
| 357 | struct alps_data *priv = psmouse->private; | ||
| 358 | unsigned char buf[6]; | ||
| 359 | int poll_failed; | ||
| 360 | |||
| 361 | if (priv->i->flags & ALPS_PASS) | ||
| 362 | alps_passthrough_mode(psmouse, 1); | ||
| 363 | |||
| 364 | poll_failed = ps2_command(&psmouse->ps2dev, buf, | ||
| 365 | PSMOUSE_CMD_POLL | (psmouse->pktsize << 8)) < 0; | ||
| 366 | |||
| 367 | if (priv->i->flags & ALPS_PASS) | ||
| 368 | alps_passthrough_mode(psmouse, 0); | ||
| 369 | |||
| 370 | if (poll_failed || (buf[0] & priv->i->mask0) != priv->i->byte0) | ||
| 371 | return -1; | ||
| 372 | |||
| 373 | if ((psmouse->badbyte & 0xc8) == 0x08) { | ||
| 374 | /* | ||
| 375 | * Poll the track stick ... | ||
| 376 | */ | ||
| 377 | if (ps2_command(&psmouse->ps2dev, buf, PSMOUSE_CMD_POLL | (3 << 8))) | ||
| 378 | return -1; | ||
| 379 | } | ||
| 380 | |||
| 381 | memcpy(psmouse->packet, buf, sizeof(buf)); | ||
| 382 | return 0; | ||
| 383 | } | ||
| 384 | |||
| 351 | static int alps_reconnect(struct psmouse *psmouse) | 385 | static int alps_reconnect(struct psmouse *psmouse) |
| 352 | { | 386 | { |
| 353 | struct alps_data *priv = psmouse->private; | 387 | struct alps_data *priv = psmouse->private; |
| @@ -451,10 +485,14 @@ int alps_init(struct psmouse *psmouse) | |||
| 451 | input_register_device(priv->dev2); | 485 | input_register_device(priv->dev2); |
| 452 | 486 | ||
| 453 | psmouse->protocol_handler = alps_process_byte; | 487 | psmouse->protocol_handler = alps_process_byte; |
| 488 | psmouse->poll = alps_poll; | ||
| 454 | psmouse->disconnect = alps_disconnect; | 489 | psmouse->disconnect = alps_disconnect; |
| 455 | psmouse->reconnect = alps_reconnect; | 490 | psmouse->reconnect = alps_reconnect; |
| 456 | psmouse->pktsize = 6; | 491 | psmouse->pktsize = 6; |
| 457 | 492 | ||
| 493 | /* We are having trouble resyncing ALPS touchpads so disable it for now */ | ||
| 494 | psmouse->resync_time = 0; | ||
| 495 | |||
| 458 | return 0; | 496 | return 0; |
| 459 | 497 | ||
| 460 | init_fail: | 498 | init_fail: |
diff --git a/drivers/input/mouse/logips2pp.c b/drivers/input/mouse/logips2pp.c index 025a71de5404..c88520d3d13c 100644 --- a/drivers/input/mouse/logips2pp.c +++ b/drivers/input/mouse/logips2pp.c | |||
| @@ -117,7 +117,7 @@ static int ps2pp_cmd(struct psmouse *psmouse, unsigned char *param, unsigned cha | |||
| 117 | if (psmouse_sliced_command(psmouse, command)) | 117 | if (psmouse_sliced_command(psmouse, command)) |
| 118 | return -1; | 118 | return -1; |
| 119 | 119 | ||
| 120 | if (ps2_command(&psmouse->ps2dev, param, PSMOUSE_CMD_POLL)) | 120 | if (ps2_command(&psmouse->ps2dev, param, PSMOUSE_CMD_POLL | 0x0300)) |
| 121 | return -1; | 121 | return -1; |
| 122 | 122 | ||
| 123 | return 0; | 123 | return 0; |
diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c index 4d5ecc04c5b6..7665fd9ce559 100644 --- a/drivers/input/mouse/psmouse-base.c +++ b/drivers/input/mouse/psmouse-base.c | |||
| @@ -54,10 +54,14 @@ static unsigned int psmouse_smartscroll = 1; | |||
| 54 | module_param_named(smartscroll, psmouse_smartscroll, bool, 0644); | 54 | module_param_named(smartscroll, psmouse_smartscroll, bool, 0644); |
| 55 | MODULE_PARM_DESC(smartscroll, "Logitech Smartscroll autorepeat, 1 = enabled (default), 0 = disabled."); | 55 | MODULE_PARM_DESC(smartscroll, "Logitech Smartscroll autorepeat, 1 = enabled (default), 0 = disabled."); |
| 56 | 56 | ||
| 57 | static unsigned int psmouse_resetafter; | 57 | static unsigned int psmouse_resetafter = 5; |
| 58 | module_param_named(resetafter, psmouse_resetafter, uint, 0644); | 58 | module_param_named(resetafter, psmouse_resetafter, uint, 0644); |
| 59 | MODULE_PARM_DESC(resetafter, "Reset device after so many bad packets (0 = never)."); | 59 | MODULE_PARM_DESC(resetafter, "Reset device after so many bad packets (0 = never)."); |
| 60 | 60 | ||
| 61 | static unsigned int psmouse_resync_time = 5; | ||
| 62 | module_param_named(resync_time, psmouse_resync_time, uint, 0644); | ||
| 63 | MODULE_PARM_DESC(resync_time, "How long can mouse stay idle before forcing resync (in seconds, 0 = never)."); | ||
| 64 | |||
| 61 | PSMOUSE_DEFINE_ATTR(protocol, S_IWUSR | S_IRUGO, | 65 | PSMOUSE_DEFINE_ATTR(protocol, S_IWUSR | S_IRUGO, |
| 62 | NULL, | 66 | NULL, |
| 63 | psmouse_attr_show_protocol, psmouse_attr_set_protocol); | 67 | psmouse_attr_show_protocol, psmouse_attr_set_protocol); |
| @@ -70,12 +74,16 @@ PSMOUSE_DEFINE_ATTR(resolution, S_IWUSR | S_IRUGO, | |||
| 70 | PSMOUSE_DEFINE_ATTR(resetafter, S_IWUSR | S_IRUGO, | 74 | PSMOUSE_DEFINE_ATTR(resetafter, S_IWUSR | S_IRUGO, |
| 71 | (void *) offsetof(struct psmouse, resetafter), | 75 | (void *) offsetof(struct psmouse, resetafter), |
| 72 | psmouse_show_int_attr, psmouse_set_int_attr); | 76 | psmouse_show_int_attr, psmouse_set_int_attr); |
| 77 | PSMOUSE_DEFINE_ATTR(resync_time, S_IWUSR | S_IRUGO, | ||
| 78 | (void *) offsetof(struct psmouse, resync_time), | ||
| 79 | psmouse_show_int_attr, psmouse_set_int_attr); | ||
| 73 | 80 | ||
| 74 | static struct attribute *psmouse_attributes[] = { | 81 | static struct attribute *psmouse_attributes[] = { |
| 75 | &psmouse_attr_protocol.dattr.attr, | 82 | &psmouse_attr_protocol.dattr.attr, |
| 76 | &psmouse_attr_rate.dattr.attr, | 83 | &psmouse_attr_rate.dattr.attr, |
| 77 | &psmouse_attr_resolution.dattr.attr, | 84 | &psmouse_attr_resolution.dattr.attr, |
| 78 | &psmouse_attr_resetafter.dattr.attr, | 85 | &psmouse_attr_resetafter.dattr.attr, |
| 86 | &psmouse_attr_resync_time.dattr.attr, | ||
| 79 | NULL | 87 | NULL |
| 80 | }; | 88 | }; |
| 81 | 89 | ||
| @@ -98,6 +106,8 @@ __obsolete_setup("psmouse_rate="); | |||
| 98 | */ | 106 | */ |
| 99 | static DECLARE_MUTEX(psmouse_sem); | 107 | static DECLARE_MUTEX(psmouse_sem); |
| 100 | 108 | ||
| 109 | static struct workqueue_struct *kpsmoused_wq; | ||
| 110 | |||
| 101 | struct psmouse_protocol { | 111 | struct psmouse_protocol { |
| 102 | enum psmouse_type type; | 112 | enum psmouse_type type; |
| 103 | char *name; | 113 | char *name; |
| @@ -178,15 +188,79 @@ static psmouse_ret_t psmouse_process_byte(struct psmouse *psmouse, struct pt_reg | |||
| 178 | } | 188 | } |
| 179 | 189 | ||
| 180 | /* | 190 | /* |
| 181 | * psmouse_interrupt() handles incoming characters, either gathering them into | 191 | * __psmouse_set_state() sets new psmouse state and resets all flags. |
| 182 | * packets or passing them to the command routine as command output. | 192 | */ |
| 193 | |||
| 194 | static inline void __psmouse_set_state(struct psmouse *psmouse, enum psmouse_state new_state) | ||
| 195 | { | ||
| 196 | psmouse->state = new_state; | ||
| 197 | psmouse->pktcnt = psmouse->out_of_sync = 0; | ||
| 198 | psmouse->ps2dev.flags = 0; | ||
| 199 | psmouse->last = jiffies; | ||
| 200 | } | ||
| 201 | |||
| 202 | |||
| 203 | /* | ||
| 204 | * psmouse_set_state() sets new psmouse state and resets all flags and | ||
| 205 | * counters while holding serio lock so fighting with interrupt handler | ||
| 206 | * is not a concern. | ||
| 207 | */ | ||
| 208 | |||
| 209 | static void psmouse_set_state(struct psmouse *psmouse, enum psmouse_state new_state) | ||
| 210 | { | ||
| 211 | serio_pause_rx(psmouse->ps2dev.serio); | ||
| 212 | __psmouse_set_state(psmouse, new_state); | ||
| 213 | serio_continue_rx(psmouse->ps2dev.serio); | ||
| 214 | } | ||
| 215 | |||
| 216 | /* | ||
| 217 | * psmouse_handle_byte() processes one byte of the input data stream | ||
| 218 | * by calling corresponding protocol handler. | ||
| 219 | */ | ||
| 220 | |||
| 221 | static int psmouse_handle_byte(struct psmouse *psmouse, struct pt_regs *regs) | ||
| 222 | { | ||
| 223 | psmouse_ret_t rc = psmouse->protocol_handler(psmouse, regs); | ||
| 224 | |||
| 225 | switch (rc) { | ||
| 226 | case PSMOUSE_BAD_DATA: | ||
| 227 | if (psmouse->state == PSMOUSE_ACTIVATED) { | ||
| 228 | printk(KERN_WARNING "psmouse.c: %s at %s lost sync at byte %d\n", | ||
| 229 | psmouse->name, psmouse->phys, psmouse->pktcnt); | ||
| 230 | if (++psmouse->out_of_sync == psmouse->resetafter) { | ||
| 231 | __psmouse_set_state(psmouse, PSMOUSE_IGNORE); | ||
| 232 | printk(KERN_NOTICE "psmouse.c: issuing reconnect request\n"); | ||
| 233 | serio_reconnect(psmouse->ps2dev.serio); | ||
| 234 | return -1; | ||
| 235 | } | ||
| 236 | } | ||
| 237 | psmouse->pktcnt = 0; | ||
| 238 | break; | ||
| 239 | |||
| 240 | case PSMOUSE_FULL_PACKET: | ||
| 241 | psmouse->pktcnt = 0; | ||
| 242 | if (psmouse->out_of_sync) { | ||
| 243 | psmouse->out_of_sync = 0; | ||
| 244 | printk(KERN_NOTICE "psmouse.c: %s at %s - driver resynched.\n", | ||
| 245 | psmouse->name, psmouse->phys); | ||
| 246 | } | ||
| 247 | break; | ||
| 248 | |||
| 249 | case PSMOUSE_GOOD_DATA: | ||
| 250 | break; | ||
| 251 | } | ||
| 252 | return 0; | ||
| 253 | } | ||
| 254 | |||
| 255 | /* | ||
| 256 | * psmouse_interrupt() handles incoming characters, either passing them | ||
| 257 | * for normal processing or gathering them as command response. | ||
| 183 | */ | 258 | */ |
| 184 | 259 | ||
| 185 | static irqreturn_t psmouse_interrupt(struct serio *serio, | 260 | static irqreturn_t psmouse_interrupt(struct serio *serio, |
| 186 | unsigned char data, unsigned int flags, struct pt_regs *regs) | 261 | unsigned char data, unsigned int flags, struct pt_regs *regs) |
| 187 | { | 262 | { |
| 188 | struct psmouse *psmouse = serio_get_drvdata(serio); | 263 | struct psmouse *psmouse = serio_get_drvdata(serio); |
| 189 | psmouse_ret_t rc; | ||
| 190 | 264 | ||
| 191 | if (psmouse->state == PSMOUSE_IGNORE) | 265 | if (psmouse->state == PSMOUSE_IGNORE) |
| 192 | goto out; | 266 | goto out; |
| @@ -208,67 +282,58 @@ static irqreturn_t psmouse_interrupt(struct serio *serio, | |||
| 208 | if (ps2_handle_response(&psmouse->ps2dev, data)) | 282 | if (ps2_handle_response(&psmouse->ps2dev, data)) |
| 209 | goto out; | 283 | goto out; |
| 210 | 284 | ||
| 211 | if (psmouse->state == PSMOUSE_INITIALIZING) | 285 | if (psmouse->state <= PSMOUSE_RESYNCING) |
| 212 | goto out; | 286 | goto out; |
| 213 | 287 | ||
| 214 | if (psmouse->state == PSMOUSE_ACTIVATED && | 288 | if (psmouse->state == PSMOUSE_ACTIVATED && |
| 215 | psmouse->pktcnt && time_after(jiffies, psmouse->last + HZ/2)) { | 289 | psmouse->pktcnt && time_after(jiffies, psmouse->last + HZ/2)) { |
| 216 | printk(KERN_WARNING "psmouse.c: %s at %s lost synchronization, throwing %d bytes away.\n", | 290 | printk(KERN_INFO "psmouse.c: %s at %s lost synchronization, throwing %d bytes away.\n", |
| 217 | psmouse->name, psmouse->phys, psmouse->pktcnt); | 291 | psmouse->name, psmouse->phys, psmouse->pktcnt); |
| 218 | psmouse->pktcnt = 0; | 292 | psmouse->badbyte = psmouse->packet[0]; |
| 293 | __psmouse_set_state(psmouse, PSMOUSE_RESYNCING); | ||
| 294 | queue_work(kpsmoused_wq, &psmouse->resync_work); | ||
| 295 | goto out; | ||
| 219 | } | 296 | } |
| 220 | 297 | ||
| 221 | psmouse->last = jiffies; | ||
| 222 | psmouse->packet[psmouse->pktcnt++] = data; | 298 | psmouse->packet[psmouse->pktcnt++] = data; |
| 223 | 299 | /* | |
| 224 | if (psmouse->packet[0] == PSMOUSE_RET_BAT) { | 300 | * Check if this is a new device announcement (0xAA 0x00) |
| 301 | */ | ||
| 302 | if (unlikely(psmouse->packet[0] == PSMOUSE_RET_BAT && psmouse->pktcnt <= 2)) { | ||
| 225 | if (psmouse->pktcnt == 1) | 303 | if (psmouse->pktcnt == 1) |
| 226 | goto out; | 304 | goto out; |
| 227 | 305 | ||
| 228 | if (psmouse->pktcnt == 2) { | 306 | if (psmouse->packet[1] == PSMOUSE_RET_ID) { |
| 229 | if (psmouse->packet[1] == PSMOUSE_RET_ID) { | 307 | __psmouse_set_state(psmouse, PSMOUSE_IGNORE); |
| 230 | psmouse->state = PSMOUSE_IGNORE; | 308 | serio_reconnect(serio); |
| 231 | serio_reconnect(serio); | 309 | goto out; |
| 232 | goto out; | ||
| 233 | } | ||
| 234 | if (psmouse->type == PSMOUSE_SYNAPTICS) { | ||
| 235 | /* neither 0xAA nor 0x00 are valid first bytes | ||
| 236 | * for a packet in absolute mode | ||
| 237 | */ | ||
| 238 | psmouse->pktcnt = 0; | ||
| 239 | goto out; | ||
| 240 | } | ||
| 241 | } | 310 | } |
| 242 | } | 311 | /* |
| 243 | 312 | * Not a new device, try processing first byte normally | |
| 244 | rc = psmouse->protocol_handler(psmouse, regs); | 313 | */ |
| 314 | psmouse->pktcnt = 1; | ||
| 315 | if (psmouse_handle_byte(psmouse, regs)) | ||
| 316 | goto out; | ||
| 245 | 317 | ||
| 246 | switch (rc) { | 318 | psmouse->packet[psmouse->pktcnt++] = data; |
| 247 | case PSMOUSE_BAD_DATA: | 319 | } |
| 248 | printk(KERN_WARNING "psmouse.c: %s at %s lost sync at byte %d\n", | ||
| 249 | psmouse->name, psmouse->phys, psmouse->pktcnt); | ||
| 250 | psmouse->pktcnt = 0; | ||
| 251 | 320 | ||
| 252 | if (++psmouse->out_of_sync == psmouse->resetafter) { | 321 | /* |
| 253 | psmouse->state = PSMOUSE_IGNORE; | 322 | * See if we need to force resync because mouse was idle for too long |
| 254 | printk(KERN_NOTICE "psmouse.c: issuing reconnect request\n"); | 323 | */ |
| 255 | serio_reconnect(psmouse->ps2dev.serio); | 324 | if (psmouse->state == PSMOUSE_ACTIVATED && |
| 256 | } | 325 | psmouse->pktcnt == 1 && psmouse->resync_time && |
| 257 | break; | 326 | time_after(jiffies, psmouse->last + psmouse->resync_time * HZ)) { |
| 327 | psmouse->badbyte = psmouse->packet[0]; | ||
| 328 | __psmouse_set_state(psmouse, PSMOUSE_RESYNCING); | ||
| 329 | queue_work(kpsmoused_wq, &psmouse->resync_work); | ||
| 330 | goto out; | ||
| 331 | } | ||
| 258 | 332 | ||
| 259 | case PSMOUSE_FULL_PACKET: | 333 | psmouse->last = jiffies; |
| 260 | psmouse->pktcnt = 0; | 334 | psmouse_handle_byte(psmouse, regs); |
| 261 | if (psmouse->out_of_sync) { | ||
| 262 | psmouse->out_of_sync = 0; | ||
| 263 | printk(KERN_NOTICE "psmouse.c: %s at %s - driver resynched.\n", | ||
| 264 | psmouse->name, psmouse->phys); | ||
| 265 | } | ||
| 266 | break; | ||
| 267 | 335 | ||
| 268 | case PSMOUSE_GOOD_DATA: | 336 | out: |
| 269 | break; | ||
| 270 | } | ||
| 271 | out: | ||
| 272 | return IRQ_HANDLED; | 337 | return IRQ_HANDLED; |
| 273 | } | 338 | } |
| 274 | 339 | ||
| @@ -752,21 +817,6 @@ static void psmouse_initialize(struct psmouse *psmouse) | |||
| 752 | } | 817 | } |
| 753 | 818 | ||
| 754 | /* | 819 | /* |
| 755 | * psmouse_set_state() sets new psmouse state and resets all flags and | ||
| 756 | * counters while holding serio lock so fighting with interrupt handler | ||
| 757 | * is not a concern. | ||
| 758 | */ | ||
| 759 | |||
| 760 | static void psmouse_set_state(struct psmouse *psmouse, enum psmouse_state new_state) | ||
| 761 | { | ||
| 762 | serio_pause_rx(psmouse->ps2dev.serio); | ||
| 763 | psmouse->state = new_state; | ||
| 764 | psmouse->pktcnt = psmouse->out_of_sync = 0; | ||
| 765 | psmouse->ps2dev.flags = 0; | ||
| 766 | serio_continue_rx(psmouse->ps2dev.serio); | ||
| 767 | } | ||
| 768 | |||
| 769 | /* | ||
| 770 | * psmouse_activate() enables the mouse so that we get motion reports from it. | 820 | * psmouse_activate() enables the mouse so that we get motion reports from it. |
| 771 | */ | 821 | */ |
| 772 | 822 | ||
| @@ -794,6 +844,111 @@ static void psmouse_deactivate(struct psmouse *psmouse) | |||
| 794 | psmouse_set_state(psmouse, PSMOUSE_CMD_MODE); | 844 | psmouse_set_state(psmouse, PSMOUSE_CMD_MODE); |
| 795 | } | 845 | } |
| 796 | 846 | ||
| 847 | /* | ||
| 848 | * psmouse_poll() - default poll hanlder. Everyone except for ALPS uses it. | ||
| 849 | */ | ||
| 850 | |||
| 851 | static int psmouse_poll(struct psmouse *psmouse) | ||
| 852 | { | ||
| 853 | return ps2_command(&psmouse->ps2dev, psmouse->packet, | ||
| 854 | PSMOUSE_CMD_POLL | (psmouse->pktsize << 8)); | ||
| 855 | } | ||
| 856 | |||
| 857 | |||
| 858 | /* | ||
| 859 | * psmouse_resync() attempts to re-validate current protocol. | ||
| 860 | */ | ||
| 861 | |||
| 862 | static void psmouse_resync(void *p) | ||
| 863 | { | ||
| 864 | struct psmouse *psmouse = p, *parent = NULL; | ||
| 865 | struct serio *serio = psmouse->ps2dev.serio; | ||
| 866 | psmouse_ret_t rc = PSMOUSE_GOOD_DATA; | ||
| 867 | int failed = 0, enabled = 0; | ||
| 868 | int i; | ||
| 869 | |||
| 870 | down(&psmouse_sem); | ||
| 871 | |||
| 872 | if (psmouse->state != PSMOUSE_RESYNCING) | ||
| 873 | goto out; | ||
| 874 | |||
| 875 | if (serio->parent && serio->id.type == SERIO_PS_PSTHRU) { | ||
| 876 | parent = serio_get_drvdata(serio->parent); | ||
| 877 | psmouse_deactivate(parent); | ||
| 878 | } | ||
| 879 | |||
| 880 | /* | ||
| 881 | * Some mice don't ACK commands sent while they are in the middle of | ||
| 882 | * transmitting motion packet. To avoid delay we use ps2_sendbyte() | ||
| 883 | * instead of ps2_command() which would wait for 200ms for an ACK | ||
| 884 | * that may never come. | ||
| 885 | * As an additional quirk ALPS touchpads may not only forget to ACK | ||
| 886 | * disable command but will stop reporting taps, so if we see that | ||
| 887 | * mouse at least once ACKs disable we will do full reconnect if ACK | ||
| 888 | * is missing. | ||
| 889 | */ | ||
| 890 | psmouse->num_resyncs++; | ||
| 891 | |||
| 892 | if (ps2_sendbyte(&psmouse->ps2dev, PSMOUSE_CMD_DISABLE, 20)) { | ||
| 893 | if (psmouse->num_resyncs < 3 || psmouse->acks_disable_command) | ||
| 894 | failed = 1; | ||
| 895 | } else | ||
| 896 | psmouse->acks_disable_command = 1; | ||
| 897 | |||
| 898 | /* | ||
| 899 | * Poll the mouse. If it was reset the packet will be shorter than | ||
| 900 | * psmouse->pktsize and ps2_command will fail. We do not expect and | ||
| 901 | * do not handle scenario when mouse "upgrades" its protocol while | ||
| 902 | * disconnected since it would require additional delay. If we ever | ||
| 903 | * see a mouse that does it we'll adjust the code. | ||
| 904 | */ | ||
| 905 | if (!failed) { | ||
| 906 | if (psmouse->poll(psmouse)) | ||
| 907 | failed = 1; | ||
| 908 | else { | ||
| 909 | psmouse_set_state(psmouse, PSMOUSE_CMD_MODE); | ||
| 910 | for (i = 0; i < psmouse->pktsize; i++) { | ||
| 911 | psmouse->pktcnt++; | ||
| 912 | rc = psmouse->protocol_handler(psmouse, NULL); | ||
| 913 | if (rc != PSMOUSE_GOOD_DATA) | ||
| 914 | break; | ||
| 915 | } | ||
| 916 | if (rc != PSMOUSE_FULL_PACKET) | ||
| 917 | failed = 1; | ||
| 918 | psmouse_set_state(psmouse, PSMOUSE_RESYNCING); | ||
| 919 | } | ||
| 920 | } | ||
| 921 | /* | ||
| 922 | * Now try to enable mouse. We try to do that even if poll failed and also | ||
| 923 | * repeat our attempts 5 times, otherwise we may be left out with disabled | ||
| 924 | * mouse. | ||
| 925 | */ | ||
| 926 | for (i = 0; i < 5; i++) { | ||
| 927 | if (!ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_ENABLE)) { | ||
| 928 | enabled = 1; | ||
| 929 | break; | ||
| 930 | } | ||
| 931 | msleep(200); | ||
| 932 | } | ||
| 933 | |||
| 934 | if (!enabled) { | ||
| 935 | printk(KERN_WARNING "psmouse.c: failed to re-enable mouse on %s\n", | ||
| 936 | psmouse->ps2dev.serio->phys); | ||
| 937 | failed = 1; | ||
| 938 | } | ||
| 939 | |||
| 940 | if (failed) { | ||
| 941 | psmouse_set_state(psmouse, PSMOUSE_IGNORE); | ||
| 942 | printk(KERN_INFO "psmouse.c: resync failed, issuing reconnect request\n"); | ||
| 943 | serio_reconnect(serio); | ||
| 944 | } else | ||
| 945 | psmouse_set_state(psmouse, PSMOUSE_ACTIVATED); | ||
| 946 | |||
| 947 | if (parent) | ||
| 948 | psmouse_activate(parent); | ||
| 949 | out: | ||
| 950 | up(&psmouse_sem); | ||
| 951 | } | ||
| 797 | 952 | ||
| 798 | /* | 953 | /* |
| 799 | * psmouse_cleanup() resets the mouse into power-on state. | 954 | * psmouse_cleanup() resets the mouse into power-on state. |
| @@ -822,6 +977,11 @@ static void psmouse_disconnect(struct serio *serio) | |||
| 822 | 977 | ||
| 823 | psmouse_set_state(psmouse, PSMOUSE_CMD_MODE); | 978 | psmouse_set_state(psmouse, PSMOUSE_CMD_MODE); |
| 824 | 979 | ||
| 980 | /* make sure we don't have a resync in progress */ | ||
| 981 | up(&psmouse_sem); | ||
| 982 | flush_workqueue(kpsmoused_wq); | ||
| 983 | down(&psmouse_sem); | ||
| 984 | |||
| 825 | if (serio->parent && serio->id.type == SERIO_PS_PSTHRU) { | 985 | if (serio->parent && serio->id.type == SERIO_PS_PSTHRU) { |
| 826 | parent = serio_get_drvdata(serio->parent); | 986 | parent = serio_get_drvdata(serio->parent); |
| 827 | psmouse_deactivate(parent); | 987 | psmouse_deactivate(parent); |
| @@ -859,6 +1019,7 @@ static int psmouse_switch_protocol(struct psmouse *psmouse, struct psmouse_proto | |||
| 859 | 1019 | ||
| 860 | psmouse->set_rate = psmouse_set_rate; | 1020 | psmouse->set_rate = psmouse_set_rate; |
| 861 | psmouse->set_resolution = psmouse_set_resolution; | 1021 | psmouse->set_resolution = psmouse_set_resolution; |
| 1022 | psmouse->poll = psmouse_poll; | ||
| 862 | psmouse->protocol_handler = psmouse_process_byte; | 1023 | psmouse->protocol_handler = psmouse_process_byte; |
| 863 | psmouse->pktsize = 3; | 1024 | psmouse->pktsize = 3; |
| 864 | 1025 | ||
| @@ -874,6 +1035,23 @@ static int psmouse_switch_protocol(struct psmouse *psmouse, struct psmouse_proto | |||
| 874 | else | 1035 | else |
| 875 | psmouse->type = psmouse_extensions(psmouse, psmouse_max_proto, 1); | 1036 | psmouse->type = psmouse_extensions(psmouse, psmouse_max_proto, 1); |
| 876 | 1037 | ||
| 1038 | /* | ||
| 1039 | * If mouse's packet size is 3 there is no point in polling the | ||
| 1040 | * device in hopes to detect protocol reset - we won't get less | ||
| 1041 | * than 3 bytes response anyhow. | ||
| 1042 | */ | ||
| 1043 | if (psmouse->pktsize == 3) | ||
| 1044 | psmouse->resync_time = 0; | ||
| 1045 | |||
| 1046 | /* | ||
| 1047 | * Some smart KVMs fake response to POLL command returning just | ||
| 1048 | * 3 bytes and messing up our resync logic, so if initial poll | ||
| 1049 | * fails we won't try polling the device anymore. Hopefully | ||
| 1050 | * such KVM will maintain initially selected protocol. | ||
| 1051 | */ | ||
| 1052 | if (psmouse->resync_time && psmouse->poll(psmouse)) | ||
| 1053 | psmouse->resync_time = 0; | ||
| 1054 | |||
| 877 | sprintf(psmouse->devname, "%s %s %s", | 1055 | sprintf(psmouse->devname, "%s %s %s", |
| 878 | psmouse_protocol_by_type(psmouse->type)->name, psmouse->vendor, psmouse->name); | 1056 | psmouse_protocol_by_type(psmouse->type)->name, psmouse->vendor, psmouse->name); |
| 879 | 1057 | ||
| @@ -914,6 +1092,7 @@ static int psmouse_connect(struct serio *serio, struct serio_driver *drv) | |||
| 914 | goto out; | 1092 | goto out; |
| 915 | 1093 | ||
| 916 | ps2_init(&psmouse->ps2dev, serio); | 1094 | ps2_init(&psmouse->ps2dev, serio); |
| 1095 | INIT_WORK(&psmouse->resync_work, psmouse_resync, psmouse); | ||
| 917 | psmouse->dev = input_dev; | 1096 | psmouse->dev = input_dev; |
| 918 | sprintf(psmouse->phys, "%s/input0", serio->phys); | 1097 | sprintf(psmouse->phys, "%s/input0", serio->phys); |
| 919 | 1098 | ||
| @@ -934,6 +1113,7 @@ static int psmouse_connect(struct serio *serio, struct serio_driver *drv) | |||
| 934 | psmouse->rate = psmouse_rate; | 1113 | psmouse->rate = psmouse_rate; |
| 935 | psmouse->resolution = psmouse_resolution; | 1114 | psmouse->resolution = psmouse_resolution; |
| 936 | psmouse->resetafter = psmouse_resetafter; | 1115 | psmouse->resetafter = psmouse_resetafter; |
| 1116 | psmouse->resync_time = parent ? 0 : psmouse_resync_time; | ||
| 937 | psmouse->smartscroll = psmouse_smartscroll; | 1117 | psmouse->smartscroll = psmouse_smartscroll; |
| 938 | 1118 | ||
| 939 | psmouse_switch_protocol(psmouse, NULL); | 1119 | psmouse_switch_protocol(psmouse, NULL); |
| @@ -1278,13 +1458,21 @@ static int psmouse_get_maxproto(char *buffer, struct kernel_param *kp) | |||
| 1278 | 1458 | ||
| 1279 | static int __init psmouse_init(void) | 1459 | static int __init psmouse_init(void) |
| 1280 | { | 1460 | { |
| 1461 | kpsmoused_wq = create_singlethread_workqueue("kpsmoused"); | ||
| 1462 | if (!kpsmoused_wq) { | ||
| 1463 | printk(KERN_ERR "psmouse: failed to create kpsmoused workqueue\n"); | ||
| 1464 | return -ENOMEM; | ||
| 1465 | } | ||
| 1466 | |||
| 1281 | serio_register_driver(&psmouse_drv); | 1467 | serio_register_driver(&psmouse_drv); |
| 1468 | |||
| 1282 | return 0; | 1469 | return 0; |
| 1283 | } | 1470 | } |
| 1284 | 1471 | ||
| 1285 | static void __exit psmouse_exit(void) | 1472 | static void __exit psmouse_exit(void) |
| 1286 | { | 1473 | { |
| 1287 | serio_unregister_driver(&psmouse_drv); | 1474 | serio_unregister_driver(&psmouse_drv); |
| 1475 | destroy_workqueue(kpsmoused_wq); | ||
| 1288 | } | 1476 | } |
| 1289 | 1477 | ||
| 1290 | module_init(psmouse_init); | 1478 | module_init(psmouse_init); |
diff --git a/drivers/input/mouse/psmouse.h b/drivers/input/mouse/psmouse.h index 7c4192bd1279..4d9107fba6a1 100644 --- a/drivers/input/mouse/psmouse.h +++ b/drivers/input/mouse/psmouse.h | |||
| @@ -7,7 +7,7 @@ | |||
| 7 | #define PSMOUSE_CMD_GETINFO 0x03e9 | 7 | #define PSMOUSE_CMD_GETINFO 0x03e9 |
| 8 | #define PSMOUSE_CMD_SETSTREAM 0x00ea | 8 | #define PSMOUSE_CMD_SETSTREAM 0x00ea |
| 9 | #define PSMOUSE_CMD_SETPOLL 0x00f0 | 9 | #define PSMOUSE_CMD_SETPOLL 0x00f0 |
| 10 | #define PSMOUSE_CMD_POLL 0x03eb | 10 | #define PSMOUSE_CMD_POLL 0x00eb /* caller sets number of bytes to receive */ |
| 11 | #define PSMOUSE_CMD_GETID 0x02f2 | 11 | #define PSMOUSE_CMD_GETID 0x02f2 |
| 12 | #define PSMOUSE_CMD_SETRATE 0x10f3 | 12 | #define PSMOUSE_CMD_SETRATE 0x10f3 |
| 13 | #define PSMOUSE_CMD_ENABLE 0x00f4 | 13 | #define PSMOUSE_CMD_ENABLE 0x00f4 |
| @@ -23,6 +23,7 @@ | |||
| 23 | enum psmouse_state { | 23 | enum psmouse_state { |
| 24 | PSMOUSE_IGNORE, | 24 | PSMOUSE_IGNORE, |
| 25 | PSMOUSE_INITIALIZING, | 25 | PSMOUSE_INITIALIZING, |
| 26 | PSMOUSE_RESYNCING, | ||
| 26 | PSMOUSE_CMD_MODE, | 27 | PSMOUSE_CMD_MODE, |
| 27 | PSMOUSE_ACTIVATED, | 28 | PSMOUSE_ACTIVATED, |
| 28 | }; | 29 | }; |
| @@ -38,15 +39,19 @@ struct psmouse { | |||
| 38 | void *private; | 39 | void *private; |
| 39 | struct input_dev *dev; | 40 | struct input_dev *dev; |
| 40 | struct ps2dev ps2dev; | 41 | struct ps2dev ps2dev; |
| 42 | struct work_struct resync_work; | ||
| 41 | char *vendor; | 43 | char *vendor; |
| 42 | char *name; | 44 | char *name; |
| 43 | unsigned char packet[8]; | 45 | unsigned char packet[8]; |
| 46 | unsigned char badbyte; | ||
| 44 | unsigned char pktcnt; | 47 | unsigned char pktcnt; |
| 45 | unsigned char pktsize; | 48 | unsigned char pktsize; |
| 46 | unsigned char type; | 49 | unsigned char type; |
| 50 | unsigned char acks_disable_command; | ||
| 47 | unsigned int model; | 51 | unsigned int model; |
| 48 | unsigned long last; | 52 | unsigned long last; |
| 49 | unsigned long out_of_sync; | 53 | unsigned long out_of_sync; |
| 54 | unsigned long num_resyncs; | ||
| 50 | enum psmouse_state state; | 55 | enum psmouse_state state; |
| 51 | char devname[64]; | 56 | char devname[64]; |
| 52 | char phys[32]; | 57 | char phys[32]; |
| @@ -54,6 +59,7 @@ struct psmouse { | |||
| 54 | unsigned int rate; | 59 | unsigned int rate; |
| 55 | unsigned int resolution; | 60 | unsigned int resolution; |
| 56 | unsigned int resetafter; | 61 | unsigned int resetafter; |
| 62 | unsigned int resync_time; | ||
| 57 | unsigned int smartscroll; /* Logitech only */ | 63 | unsigned int smartscroll; /* Logitech only */ |
| 58 | 64 | ||
| 59 | psmouse_ret_t (*protocol_handler)(struct psmouse *psmouse, struct pt_regs *regs); | 65 | psmouse_ret_t (*protocol_handler)(struct psmouse *psmouse, struct pt_regs *regs); |
| @@ -62,6 +68,7 @@ struct psmouse { | |||
| 62 | 68 | ||
| 63 | int (*reconnect)(struct psmouse *psmouse); | 69 | int (*reconnect)(struct psmouse *psmouse); |
| 64 | void (*disconnect)(struct psmouse *psmouse); | 70 | void (*disconnect)(struct psmouse *psmouse); |
| 71 | int (*poll)(struct psmouse *psmouse); | ||
| 65 | 72 | ||
| 66 | void (*pt_activate)(struct psmouse *psmouse); | 73 | void (*pt_activate)(struct psmouse *psmouse); |
| 67 | void (*pt_deactivate)(struct psmouse *psmouse); | 74 | void (*pt_deactivate)(struct psmouse *psmouse); |
diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c index 97cdfd6acaca..2051bec2c394 100644 --- a/drivers/input/mouse/synaptics.c +++ b/drivers/input/mouse/synaptics.c | |||
| @@ -652,6 +652,8 @@ int synaptics_init(struct psmouse *psmouse) | |||
| 652 | psmouse->disconnect = synaptics_disconnect; | 652 | psmouse->disconnect = synaptics_disconnect; |
| 653 | psmouse->reconnect = synaptics_reconnect; | 653 | psmouse->reconnect = synaptics_reconnect; |
| 654 | psmouse->pktsize = 6; | 654 | psmouse->pktsize = 6; |
| 655 | /* Synaptics can usually stay in sync without extra help */ | ||
| 656 | psmouse->resync_time = 0; | ||
| 655 | 657 | ||
| 656 | if (SYN_CAP_PASS_THROUGH(priv->capabilities)) | 658 | if (SYN_CAP_PASS_THROUGH(priv->capabilities)) |
| 657 | synaptics_pt_create(psmouse); | 659 | synaptics_pt_create(psmouse); |
