diff mbox

input: handle bad parity PS/2 packets in mouse drivers better

Message ID 9e89675b1003271506x48aa445ta46cdf9029f82820@mail.gmail.com (mailing list archive)
State New, archived
Headers show

Commit Message

Damjan Jovanovic March 27, 2010, 10:06 p.m. UTC
None
diff mbox

Patch

diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c
index 7490f1d..82b34b6 100644
--- a/drivers/input/mouse/alps.c
+++ b/drivers/input/mouse/alps.c
@@ -378,10 +378,16 @@  static psmouse_ret_t alps_process_byte(struct psmouse *psmouse)
 	struct 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;
@@ -391,6 +397,8 @@  static psmouse_ret_t alps_process_byte(struct psmouse *psmouse)
 
 	if ((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);
 	}
 
@@ -409,7 +417,8 @@  static psmouse_ret_t alps_process_byte(struct psmouse *psmouse)
 	}
 
 	if (psmouse->pktcnt == 6) {
-		alps_process_packet(psmouse);
+		if (!psmouse->badparity)
+			alps_process_packet(psmouse);
 		return PSMOUSE_FULL_PACKET;
 	}
 
diff --git a/drivers/input/mouse/elantech.c b/drivers/input/mouse/elantech.c
index b27684f..813dde7 100644
--- a/drivers/input/mouse/elantech.c
+++ b/drivers/input/mouse/elantech.c
@@ -324,6 +324,9 @@  static psmouse_ret_t elantech_process_byte(struct psmouse *psmouse)
 	if (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);
 
diff --git a/drivers/input/mouse/hgpk.c b/drivers/input/mouse/hgpk.c
index 9169d15..c06439e 100644
--- a/drivers/input/mouse/hgpk.c
+++ b/drivers/input/mouse/hgpk.c
@@ -187,7 +187,8 @@  static psmouse_ret_t hgpk_process_byte(struct psmouse *psmouse)
 	}
 
 	if (psmouse->pktcnt >= psmouse->pktsize) {
-		hgpk_process_packet(psmouse);
+		if (!psmouse->badparity)
+			hgpk_process_packet(psmouse);
 		return PSMOUSE_FULL_PACKET;
 	}
 
diff --git a/drivers/input/mouse/lifebook.c b/drivers/input/mouse/lifebook.c
index 7c1d7d4..e4d1bac 100644
--- a/drivers/input/mouse/lifebook.c
+++ b/drivers/input/mouse/lifebook.c
@@ -138,6 +138,9 @@  static psmouse_ret_t lifebook_process_byte(struct psmouse *psmouse)
 	unsigned 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;
@@ -166,6 +169,9 @@  static psmouse_ret_t lifebook_process_byte(struct psmouse *psmouse)
 		}
 	}
 
+	if (psmouse->badparity)
+		return PSMOUSE_FULL_PACKET;
+
 	if (relative_packet) {
 		if (!dev2)
 			printk(KERN_WARNING "lifebook.c: got relative packet "
diff --git a/drivers/input/mouse/logips2pp.c b/drivers/input/mouse/logips2pp.c
index 543c240..7d41ddb 100644
--- a/drivers/input/mouse/logips2pp.c
+++ b/drivers/input/mouse/logips2pp.c
@@ -51,6 +51,9 @@  static psmouse_ret_t ps2pp_process_byte(struct psmouse *psmouse)
  * Full packet accumulated, process it
  */
 
+	if (psmouse->badparity)
+		return PSMOUSE_FULL_PACKET;
+
 	if ((packet[0] & 0x48) == 0x48 && (packet[1] & 0x02) == 0x02) {
 
 		/* Logitech extended packet */
diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c
index d8c0c8d..8aa033d 100644
--- a/drivers/input/mouse/psmouse-base.c
+++ b/drivers/input/mouse/psmouse-base.c
@@ -133,6 +133,9 @@  static psmouse_ret_t psmouse_process_byte(struct psmouse *psmouse)
  * Full packet accumulated, process it
  */
 
+	if (psmouse->badparity)
+		return PSMOUSE_FULL_PACKET;
+
 /*
  * Scroll wheel on IntelliMice, scroll buttons on NetMice
  */
@@ -217,6 +220,7 @@  void psmouse_queue_work(struct psmouse *psmouse, struct delayed_work *work,
 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;
@@ -257,10 +261,12 @@  static int psmouse_handle_byte(struct psmouse *psmouse)
 					return -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;
@@ -270,6 +276,7 @@  static int psmouse_handle_byte(struct psmouse *psmouse)
 			break;
 
 		case PSMOUSE_GOOD_DATA:
+			psmouse->badparity = 0;
 			break;
 	}
 	return 0;
@@ -293,8 +300,12 @@  static irqreturn_t psmouse_interrupt(struct serio *serio,
 			printk(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))
diff --git a/drivers/input/mouse/psmouse.h b/drivers/input/mouse/psmouse.h
index e053bdd..93ba9df 100644
--- a/drivers/input/mouse/psmouse.h
+++ b/drivers/input/mouse/psmouse.h
@@ -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;
diff --git a/drivers/input/mouse/sentelic.c b/drivers/input/mouse/sentelic.c
index 81a6b81..0778d84 100644
--- a/drivers/input/mouse/sentelic.c
+++ b/drivers/input/mouse/sentelic.c
@@ -637,6 +637,9 @@  static psmouse_ret_t fsp_process_byte(struct psmouse *psmouse)
 	 * 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,
diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c
index d3f5243..25ec71c 100644
--- a/drivers/input/mouse/synaptics.c
+++ b/drivers/input/mouse/synaptics.c
@@ -534,6 +534,9 @@  static psmouse_ret_t synaptics_process_byte(struct psmouse *psmouse)
 	struct 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);
 
diff --git a/drivers/input/mouse/touchkit_ps2.c b/drivers/input/mouse/touchkit_ps2.c
index 909431c..12a1e31 100644
--- a/drivers/input/mouse/touchkit_ps2.c
+++ b/drivers/input/mouse/touchkit_ps2.c
@@ -59,6 +59,9 @@  static psmouse_ret_t touchkit_ps2_process_byte(struct psmouse *psmouse)
 	if (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));