From: Peter Osterlund Some Synaptics touchpads have a middle mouse button that also works as a scroll wheel. Scroll data is reported as packets with w == 2 and the scroll amount in byte 1, treated as a signed character. For some reason, the smallest possible wheel movement is reported as a scroll amount of 4 units. This amount is typically spread out over more than one packet, so the driver has to accumulate scroll delta values to correctly deal with this. Signed-off-by: Peter Osterlund Signed-off-by: Andrew Morton --- 25-akpm/drivers/input/mouse/synaptics.c | 28 ++++++++++++++++++++++++++-- 25-akpm/drivers/input/mouse/synaptics.h | 2 ++ 2 files changed, 28 insertions(+), 2 deletions(-) diff -puN drivers/input/mouse/synaptics.c~input-add-support-for-synaptics-touchpad-scroll-wheels drivers/input/mouse/synaptics.c --- 25/drivers/input/mouse/synaptics.c~input-add-support-for-synaptics-touchpad-scroll-wheels 2005-02-02 15:08:16.618087840 -0800 +++ 25-akpm/drivers/input/mouse/synaptics.c 2005-02-02 15:08:16.624086928 -0800 @@ -322,8 +322,11 @@ static void synaptics_parse_hw_state(uns hw->left = (buf[0] & 0x01) ? 1 : 0; hw->right = (buf[0] & 0x02) ? 1 : 0; - if (SYN_CAP_MIDDLE_BUTTON(priv->capabilities)) + if (SYN_CAP_MIDDLE_BUTTON(priv->capabilities)) { hw->middle = ((buf[0] ^ buf[3]) & 0x01) ? 1 : 0; + if (hw->w == 2) + hw->scroll = (signed char)(buf[1]); + } if (SYN_CAP_FOUR_BUTTON(priv->capabilities)) { hw->up = ((buf[0] ^ buf[3]) & 0x01) ? 1 : 0; @@ -379,6 +382,26 @@ static void synaptics_process_packet(str synaptics_parse_hw_state(psmouse->packet, priv, &hw); + if (hw.scroll) { + priv->scroll += hw.scroll; + + while (priv->scroll >= 4) { + input_report_key(dev, BTN_BACK, !hw.down); + input_sync(dev); + input_report_key(dev, BTN_BACK, hw.down); + input_sync(dev); + priv->scroll -= 4; + } + while (priv->scroll <= -4) { + input_report_key(dev, BTN_FORWARD, !hw.up); + input_sync(dev); + input_report_key(dev, BTN_FORWARD, hw.up); + input_sync(dev); + priv->scroll += 4; + } + return; + } + if (hw.z > 0) { num_fingers = 1; finger_width = 5; @@ -528,7 +551,8 @@ static void set_input_params(struct inpu if (SYN_CAP_MIDDLE_BUTTON(priv->capabilities)) set_bit(BTN_MIDDLE, dev->keybit); - if (SYN_CAP_FOUR_BUTTON(priv->capabilities)) { + if (SYN_CAP_FOUR_BUTTON(priv->capabilities) || + SYN_CAP_MIDDLE_BUTTON(priv->capabilities)) { set_bit(BTN_FORWARD, dev->keybit); set_bit(BTN_BACK, dev->keybit); } diff -puN drivers/input/mouse/synaptics.h~input-add-support-for-synaptics-touchpad-scroll-wheels drivers/input/mouse/synaptics.h --- 25/drivers/input/mouse/synaptics.h~input-add-support-for-synaptics-touchpad-scroll-wheels 2005-02-02 15:08:16.620087536 -0800 +++ 25-akpm/drivers/input/mouse/synaptics.h 2005-02-02 15:08:16.624086928 -0800 @@ -92,6 +92,7 @@ struct synaptics_hw_state { unsigned int up:1; unsigned int down:1; unsigned char ext_buttons; + signed char scroll; }; struct synaptics_data { @@ -103,6 +104,7 @@ struct synaptics_data { unsigned char pkt_type; /* packet type - old, new, etc */ unsigned char mode; /* current mode byte */ + int scroll; }; #endif /* _SYNAPTICS_H */ _