input: handle bad parity PS/2 packets in mouse drivers better
Subsystems (3)
PATCH 3/3 input: handle bad parity PS/2 packets in mouse drivers better
From: Damjan Jovanovic <[email protected]>
This fixes a regression introduced in Linux 2.6.2 where mice that sporadically produce bad parity go crazy and start jumping around and clicking randomly, which never happens in any version of Windows running on the same hardware. The bugzilla bug is
https://bugzilla.kernel.org/show_bug.cgi?id=6105
The patch works by always accumulating a full PS/2 packet, then ignoring the packet if any byte had a bad checksum. A month of testing it against an affected mouse has revealed it works perfectly in practice.
---
drivers/input/mouse/alps.c | 15 ++++++++++++--- drivers/input/mouse/elantech.c | 3 +++ drivers/input/mouse/hgpk.c | 3 ++- drivers/input/mouse/lifebook.c | 6 ++++++ drivers/input/mouse/logips2pp.c | 3 +++ drivers/input/mouse/psmouse-base.c | 15 +++++++++++++-- drivers/input/mouse/psmouse.h | 1 + drivers/input/mouse/sentelic.c | 3 +++ drivers/input/mouse/synaptics.c | 3 +++ drivers/input/mouse/touchkit_ps2.c | 3 +++ 10 files changed, 49 insertions(+), 6 deletions(-)
drivers/input/mouse/alps.c renamed from drivers/input/mouse/alps.c~input-handle-bad-parity-ps-2-packets-in-mouse-drivers-better +12 -3
@@ -379,10 +379,16 @@ static psmouse_ret_t alps_process_byte(sstruct alps_data *priv = psmouse->private;const struct alps_model_info *model = priv->i; +if (psmouse->pktcnt ==1 && psmouse->badparity) +return PSMOUSE_BAD_DATA ; +if ((psmouse->packet[0 ] &0xc8 ) ==0x08 ) {/* PS/2 packet */ if (psmouse->pktcnt ==3 ) { -alps_report_bare_ps2_packet (psmouse, psmouse->packet, - true); +if (psmouse->badparity) { +alps_report_bare_ps2_packet (psmouse, + psmouse->packet, + true); + }return PSMOUSE_FULL_PACKET ; }return PSMOUSE_GOOD_DATA ;
@@ -392,6 +398,8 @@ static psmouse_ret_t alps_process_byte(sif ((model->flags &ALPS_PS2_INTERLEAVED ) && psmouse->pktcnt >=4 && (psmouse->packet[3 ] &0x0f ) ==0x0f ) { +if (psmouse->badparity) +return PSMOUSE_BAD_DATA ;return alps_handle_interleaved_ps2 (psmouse); }
@@ -410,7 +418,8 @@ static psmouse_ret_t alps_process_byte(s }if (psmouse->pktcnt ==6 ) { -alps_process_packet (psmouse); +if (!psmouse->badparity) +alps_process_packet (psmouse);return PSMOUSE_FULL_PACKET ; }
drivers/input/mouse/elantech.c renamed from drivers/input/mouse/elantech.c~input-handle-bad-parity-ps-2-packets-in-mouse-drivers-better +3 -0
@@ -325,6 +325,9 @@ static psmouse_ret_t elantech_process_byif (psmouse->pktcnt < psmouse->pktsize)return PSMOUSE_GOOD_DATA ; +if (psmouse->pktcnt == psmouse->pktsize && psmouse->badparity) +return PSMOUSE_FULL_PACKET ; +if (etd->debug >1 )elantech_packet_dump (psmouse->packet, psmouse->pktsize);
drivers/input/mouse/hgpk.c renamed from drivers/input/mouse/hgpk.c~input-handle-bad-parity-ps-2-packets-in-mouse-drivers-better +2 -1
@@ -188,7 +188,8 @@ static psmouse_ret_t hgpk_process_byte(s }if (psmouse->pktcnt >= psmouse->pktsize) { -hgpk_process_packet (psmouse); +if (!psmouse->badparity) +hgpk_process_packet (psmouse);return PSMOUSE_FULL_PACKET ; }
drivers/input/mouse/lifebook.c renamed from drivers/input/mouse/lifebook.c~input-handle-bad-parity-ps-2-packets-in-mouse-drivers-better +6 -0
@@ -139,6 +139,9 @@ static psmouse_ret_t lifebook_process_byunsigned char *packet = psmouse->packet;bool relative_packet = packet[0 ] &0x08 ; +if (psmouse->pktcnt ==1 && psmouse->badparity) +return PSMOUSE_BAD_DATA ; +if (relative_packet || !lifebook_use_6byte_proto) {if (psmouse->pktcnt !=3 )return PSMOUSE_GOOD_DATA ;
@@ -167,6 +170,9 @@ static psmouse_ret_t lifebook_process_by } } +if (psmouse->badparity) +return PSMOUSE_FULL_PACKET ; +if (relative_packet) {if (!dev2) printk(KERN_WARNING "lifebook.c: got relative packet "
drivers/input/mouse/logips2pp.c renamed from drivers/input/mouse/logips2pp.c~input-handle-bad-parity-ps-2-packets-in-mouse-drivers-better +3 -0
@@ -51,6 +51,9 @@ static psmouse_ret_t ps2pp_process_byte(* Full packet accumulated, process it */ +if (psmouse->badparity) +return PSMOUSE_FULL_PACKET ; +if ((packet[0 ] &0x48 ) ==0x48 && (packet[1 ] &0x02 ) ==0x02 ) {/* Logitech extended packet */
drivers/input/mouse/psmouse-base.c renamed from drivers/input/mouse/psmouse-base.c~input-handle-bad-parity-ps-2-packets-in-mouse-drivers-better +13 -2
@@ -134,6 +134,9 @@ static psmouse_ret_t psmouse_process_byt* Full packet accumulated, process it */ +if (psmouse->badparity) +return PSMOUSE_FULL_PACKET ; +/* * Scroll wheel on IntelliMice, scroll buttons on NetMice */
@@ -218,6 +221,7 @@ void psmouse_queue_work(struct psmouse *static inline void __psmouse_set_state (struct psmouse *psmouse,enum psmouse_state new_state) { psmouse->state = new_state; + psmouse->badparity =0 ; psmouse->pktcnt = psmouse->out_of_sync_cnt =0 ; psmouse->ps2dev.flags =0 ; psmouse->last = jiffies;
@@ -258,10 +262,12 @@ static int psmouse_handle_byte(struct psreturn -1 ; } } + psmouse->badparity =0 ; psmouse->pktcnt =0 ;break ;case PSMOUSE_FULL_PACKET : + psmouse->badparity =0 ; psmouse->pktcnt =0 ;if (psmouse->out_of_sync_cnt) { psmouse->out_of_sync_cnt =0 ;
@@ -271,6 +277,7 @@ static int psmouse_handle_byte(struct psbreak ;case PSMOUSE_GOOD_DATA : + psmouse->badparity =0 ;break ; }return 0 ;
@@ -296,8 +303,12 @@ static irqreturn_t psmouse_interrupt(strprintk (KERN_WARNING "psmouse.c: bad data from KBC -%s%s\n" , flags &SERIO_TIMEOUT ?" timeout" :"" , flags &SERIO_PARITY ?" bad parity" :"" ); -ps2_cmd_aborted (&psmouse->ps2dev); - goto out; +if (flags &SERIO_TIMEOUT ) { +ps2_cmd_aborted (&psmouse->ps2dev); + goto out; + }else { + psmouse->badparity =1 ; + } }if (unlikely (psmouse->ps2dev.flags &PS2_FLAG_ACK ))
drivers/input/mouse/psmouse.h renamed from drivers/input/mouse/psmouse.h~input-handle-bad-parity-ps-2-packets-in-mouse-drivers-better +1 -0
@@ -43,6 +43,7 @@ struct psmouse {char *vendor;char *name;unsigned char packet[8 ]; +int badparity;unsigned char badbyte;unsigned char pktcnt;unsigned char pktsize;
drivers/input/mouse/sentelic.c renamed from drivers/input/mouse/sentelic.c~input-handle-bad-parity-ps-2-packets-in-mouse-drivers-better +3 -0
@@ -638,6 +638,9 @@ static psmouse_ret_t fsp_process_byte(st* Full packet accumulated, process it */ +if (psmouse->badparity) +return PSMOUSE_FULL_PACKET ; +switch (psmouse->packet[0 ] >>FSP_PKT_TYPE_SHIFT ) {case FSP_PKT_TYPE_ABS : dev_warn(&psmouse->ps2dev.serio->dev,
drivers/input/mouse/synaptics.c renamed from drivers/input/mouse/synaptics.c~input-handle-bad-parity-ps-2-packets-in-mouse-drivers-better +3 -0
@@ -554,6 +554,9 @@ static psmouse_ret_t synaptics_process_bstruct synaptics_data *priv = psmouse->private;if (psmouse->pktcnt >=6 ) {/* Full packet received */ +if (psmouse->badparity) +return PSMOUSE_FULL_PACKET ; +if (unlikely (priv->pkt_type ==SYN_NEWABS )) priv->pkt_type =synaptics_detect_pkt_type (psmouse);
drivers/input/mouse/touchkit_ps2.c renamed from drivers/input/mouse/touchkit_ps2.c~input-handle-bad-parity-ps-2-packets-in-mouse-drivers-better +3 -0
@@ -58,6 +58,9 @@ static psmouse_ret_t touchkit_ps2_procesif (psmouse->pktcnt !=5 )return PSMOUSE_GOOD_DATA ; +if (psmouse->badparity) +return PSMOUSE_FULL_PACKET ; +input_report_abs (dev,ABS_X ,TOUCHKIT_GET_X (packet));input_report_abs (dev,ABS_Y ,TOUCHKIT_GET_Y (packet));input_report_key (dev,BTN_TOUCH ,TOUCHKIT_GET_TOUCHED (packet));
_
Dmitry Torokhov
maintainerQuoted 8 lines · On Tue, Apr 27, 2010 at 02:12:39PM -0700, [email protected] wrote:
From: Damjan Jovanovic <[email protected]>
This fixes a regression introduced in Linux 2.6.2 where mice that sporadically produce bad parity go crazy and start jumping around and clicking randomly, which never happens in any version of Windows running on the same hardware. The bugzilla bug is
https://bugzilla.kernel.org/show_bug.cgi?id=6105
Quoted 8 lines
The patch works by always accumulating a full PS/2 packet, then ignoring the packet if any byte had a bad checksum. A month of testing it against an affected mouse has revealed it works perfectly in practice.
Signed-off-by Damjan Jovanovic <[email protected]>Cc Alessandro Rubini <[email protected]>Cc Dmitry Torokhov <[email protected]>Signed-off-by Andrew Morton <[email protected]>
Andrew, an alternative path has been merged, please drop this one.
Thanks.
Signature · 1 line
Dmitry