* Synaptics TouchPad PS/2 mouse driver
*
* 2003 Dmitry Torokhov <dtor@mail.ru>
- * Added support for pass-through port
+ * Added support for pass-through port. Special thanks to Peter Berg Larsen
+ * for explaining various Synaptics quirks.
*
* 2003 Peter Osterlund <petero2@telia.com>
* Ported to 2.5 input device infrastructure.
static void synaptics_parse_hw_state(unsigned char buf[], struct synaptics_data *priv, struct synaptics_hw_state *hw)
{
- hw->up = 0;
- hw->down = 0;
- hw->b0 = 0;
- hw->b1 = 0;
- hw->b2 = 0;
- hw->b3 = 0;
- hw->b4 = 0;
- hw->b5 = 0;
- hw->b6 = 0;
- hw->b7 = 0;
+ memset(hw, 0, sizeof(struct synaptics_hw_state));
if (SYN_MODEL_NEWABS(priv->model_id)) {
hw->x = (((buf[3] & 0x10) << 8) |
input_sync(dev);
}
+static int synaptics_validate_byte(struct psmouse *psmouse)
+{
+ static unsigned char newabs_mask[] = { 0xC8, 0x00, 0x00, 0xC8, 0x00 };
+ static unsigned char newabs_rslt[] = { 0x80, 0x00, 0x00, 0xC0, 0x00 };
+ static unsigned char oldabs_mask[] = { 0xC0, 0x60, 0x00, 0xC0, 0x60 };
+ static unsigned char oldabs_rslt[] = { 0xC0, 0x00, 0x00, 0x80, 0x00 };
+ struct synaptics_data *priv = psmouse->private;
+ int idx = psmouse->pktcnt - 1;
+
+ if (SYN_MODEL_NEWABS(priv->model_id))
+ return (psmouse->packet[idx] & newabs_mask[idx]) == newabs_rslt[idx];
+ else
+ return (psmouse->packet[idx] & oldabs_mask[idx]) == oldabs_rslt[idx];
+}
+
void synaptics_process_byte(struct psmouse *psmouse, struct pt_regs *regs)
{
struct input_dev *dev = &psmouse->dev;
struct synaptics_data *priv = psmouse->private;
- unsigned char data = psmouse->packet[psmouse->pktcnt - 1];
- int newabs = SYN_MODEL_NEWABS(priv->model_id);
input_regs(dev, regs);
- switch (psmouse->pktcnt) {
- case 1:
- if (newabs ? ((data & 0xC8) != 0x80) : ((data & 0xC0) != 0xC0)) {
- printk(KERN_WARNING "Synaptics driver lost sync at 1st byte\n");
- goto bad_sync;
- }
- break;
- case 2:
- if (!newabs && ((data & 0x60) != 0x00)) {
- printk(KERN_WARNING "Synaptics driver lost sync at 2nd byte\n");
- goto bad_sync;
- }
- break;
- case 4:
- if (newabs ? ((data & 0xC8) != 0xC0) : ((data & 0xC0) != 0x80)) {
- printk(KERN_WARNING "Synaptics driver lost sync at 4th byte\n");
- goto bad_sync;
- }
- break;
- case 5:
- if (!newabs && ((data & 0x60) != 0x00)) {
- printk(KERN_WARNING "Synaptics driver lost sync at 5th byte\n");
- goto bad_sync;
- }
- break;
- default:
- if (psmouse->pktcnt < 6)
- break; /* Wait for full packet */
-
+ if (psmouse->pktcnt >= 6) { /* Full packet received */
if (priv->out_of_sync) {
priv->out_of_sync = 0;
printk(KERN_NOTICE "Synaptics driver resynced.\n");
synaptics_pass_pt_packet(priv->ptport, psmouse->packet);
else
synaptics_process_packet(psmouse);
+ psmouse->pktcnt = 0;
+ } else if (psmouse->pktcnt && !synaptics_validate_byte(psmouse)) {
+ printk(KERN_WARNING "Synaptics driver lost sync at byte %d\n", psmouse->pktcnt);
psmouse->pktcnt = 0;
- break;
- }
- return;
-
- bad_sync:
- priv->out_of_sync++;
- psmouse->pktcnt = 0;
- if (psmouse_resetafter > 0 && priv->out_of_sync == psmouse_resetafter) {
- psmouse->state = PSMOUSE_IGNORE;
- serio_rescan(psmouse->serio);
+ if (++priv->out_of_sync == psmouse_resetafter) {
+ psmouse->state = PSMOUSE_IGNORE;
+ printk(KERN_NOTICE "synaptics: issuing rescan request\n");
+ serio_rescan(psmouse->serio);
+ }
}
}