Commit d8bf0bcd authored by Dmitry Torokhov's avatar Dmitry Torokhov

Input: Switch between strict/relaxed synaptics protocol checks based on

       data in the first full data packet. Having strict checks helps
       getting rid of bad data after losing sync, but not all harware
       implements strict protocol.
parent c99cb94a
...@@ -435,6 +435,8 @@ int synaptics_init(struct psmouse *psmouse) ...@@ -435,6 +435,8 @@ int synaptics_init(struct psmouse *psmouse)
goto init_fail; goto init_fail;
} }
priv->pkt_type = SYN_MODEL_NEWABS(priv->model_id) ? SYN_NEWABS : SYN_OLDABS;
if (SYN_CAP_EXTENDED(priv->capabilities) && SYN_CAP_PASS_THROUGH(priv->capabilities)) if (SYN_CAP_EXTENDED(priv->capabilities) && SYN_CAP_PASS_THROUGH(priv->capabilities))
synaptics_pt_create(psmouse); synaptics_pt_create(psmouse);
...@@ -602,19 +604,42 @@ static void synaptics_process_packet(struct psmouse *psmouse) ...@@ -602,19 +604,42 @@ static void synaptics_process_packet(struct psmouse *psmouse)
input_sync(dev); input_sync(dev);
} }
static int synaptics_validate_byte(struct psmouse *psmouse) static int synaptics_validate_byte(unsigned char packet[], int idx, unsigned char pkt_type)
{ {
static unsigned char newabs_mask[] = { 0xC0, 0x00, 0x00, 0xC0, 0x00 }; static unsigned char newabs_mask[] = { 0xC8, 0x00, 0x00, 0xC8, 0x00 };
static unsigned char newabs_rslt[] = { 0x80, 0x00, 0x00, 0xC0, 0x00 }; static unsigned char newabs_rel_mask[] = { 0xC0, 0x00, 0x00, 0xC0, 0x00 };
static unsigned char oldabs_mask[] = { 0xC0, 0x60, 0x00, 0xC0, 0x60 }; static unsigned char newabs_rslt[] = { 0x80, 0x00, 0x00, 0xC0, 0x00 };
static unsigned char oldabs_rslt[] = { 0xC0, 0x00, 0x00, 0x80, 0x00 }; static unsigned char oldabs_mask[] = { 0xC0, 0x60, 0x00, 0xC0, 0x60 };
struct synaptics_data *priv = psmouse->private; static unsigned char oldabs_rslt[] = { 0xC0, 0x00, 0x00, 0x80, 0x00 };
int idx = psmouse->pktcnt - 1;
if (SYN_MODEL_NEWABS(priv->model_id)) switch (pkt_type) {
return (psmouse->packet[idx] & newabs_mask[idx]) == newabs_rslt[idx]; case SYN_NEWABS:
else case SYN_NEWABS_RELAXED:
return (psmouse->packet[idx] & oldabs_mask[idx]) == oldabs_rslt[idx]; return (packet[idx] & newabs_rel_mask[idx]) == newabs_rslt[idx];
case SYN_NEWABS_STRICT:
return (packet[idx] & newabs_mask[idx]) == newabs_rslt[idx];
case SYN_OLDABS:
return (packet[idx] & oldabs_mask[idx]) == oldabs_rslt[idx];
default:
printk(KERN_ERR "synaptics: unknown packet type %d\n", pkt_type);
return 0;
}
}
static unsigned char synaptics_detect_pkt_type(struct psmouse *psmouse)
{
int i;
for (i = 0; i < 5; i++)
if (!synaptics_validate_byte(psmouse->packet, i, SYN_NEWABS_STRICT)) {
printk(KERN_INFO "synaptics: using relaxed packet validation\n");
return SYN_NEWABS_RELAXED;
}
return SYN_NEWABS_STRICT;
} }
void synaptics_process_byte(struct psmouse *psmouse, struct pt_regs *regs) void synaptics_process_byte(struct psmouse *psmouse, struct pt_regs *regs)
...@@ -630,13 +655,17 @@ void synaptics_process_byte(struct psmouse *psmouse, struct pt_regs *regs) ...@@ -630,13 +655,17 @@ void synaptics_process_byte(struct psmouse *psmouse, struct pt_regs *regs)
printk(KERN_NOTICE "Synaptics driver resynced.\n"); printk(KERN_NOTICE "Synaptics driver resynced.\n");
} }
if (unlikely(priv->pkt_type == SYN_NEWABS))
priv->pkt_type = synaptics_detect_pkt_type(psmouse);
if (psmouse->ptport && psmouse->ptport->serio.dev && synaptics_is_pt_packet(psmouse->packet)) if (psmouse->ptport && psmouse->ptport->serio.dev && synaptics_is_pt_packet(psmouse->packet))
synaptics_pass_pt_packet(&psmouse->ptport->serio, psmouse->packet); synaptics_pass_pt_packet(&psmouse->ptport->serio, psmouse->packet);
else else
synaptics_process_packet(psmouse); synaptics_process_packet(psmouse);
psmouse->pktcnt = 0; psmouse->pktcnt = 0;
} else if (psmouse->pktcnt && !synaptics_validate_byte(psmouse)) { } else if (psmouse->pktcnt &&
!synaptics_validate_byte(psmouse->packet, psmouse->pktcnt - 1, priv->pkt_type)) {
printk(KERN_WARNING "Synaptics driver lost sync at byte %d\n", psmouse->pktcnt); printk(KERN_WARNING "Synaptics driver lost sync at byte %d\n", psmouse->pktcnt);
psmouse->pktcnt = 0; psmouse->pktcnt = 0;
if (++priv->out_of_sync == psmouse_resetafter) { if (++priv->out_of_sync == psmouse_resetafter) {
......
...@@ -70,6 +70,12 @@ extern int synaptics_init(struct psmouse *psmouse); ...@@ -70,6 +70,12 @@ extern int synaptics_init(struct psmouse *psmouse);
#define SYN_PS_SET_MODE2 0x14 #define SYN_PS_SET_MODE2 0x14
#define SYN_PS_CLIENT_CMD 0x28 #define SYN_PS_CLIENT_CMD 0x28
/* synaptics packet types */
#define SYN_NEWABS 0
#define SYN_NEWABS_STRICT 1
#define SYN_NEWABS_RELAXED 2
#define SYN_OLDABS 3
/* /*
* A structure to describe the state of the touchpad hardware (buttons and pad) * A structure to describe the state of the touchpad hardware (buttons and pad)
*/ */
...@@ -103,6 +109,7 @@ struct synaptics_data { ...@@ -103,6 +109,7 @@ struct synaptics_data {
/* Data for normal processing */ /* Data for normal processing */
unsigned int out_of_sync; /* # of packets out of sync */ unsigned int out_of_sync; /* # of packets out of sync */
int old_w; /* Previous w value */ int old_w; /* Previous w value */
unsigned char pkt_type; /* packet type - old, new, etc */
}; };
#endif /* _SYNAPTICS_H */ #endif /* _SYNAPTICS_H */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment