Input: psmouse - add support for Intellimouse 4.0

Add support for the H-Wheel present on Microsoft Intellimouse 4.0
(AKA "tilt mouse")

Signed-off-by: Pozsar Balazs <pozsy@uhulinux.hu>
Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c
index 5f21532..8bc9f51 100644
--- a/drivers/input/mouse/psmouse-base.c
+++ b/drivers/input/mouse/psmouse-base.c
@@ -150,9 +150,20 @@
  */
 
 	if (psmouse->type == PSMOUSE_IMEX) {
-		input_report_rel(dev, REL_WHEEL, (int) (packet[3] & 8) - (int) (packet[3] & 7));
-		input_report_key(dev, BTN_SIDE, (packet[3] >> 4) & 1);
-		input_report_key(dev, BTN_EXTRA, (packet[3] >> 5) & 1);
+		switch (packet[3] & 0xC0) {
+			case 0x80: /* vertical scroll on IntelliMouse Explorer 4.0 */
+				input_report_rel(dev, REL_WHEEL, (int) (packet[3] & 32) - (int) (packet[3] & 31));
+				break;
+			case 0x40: /* horizontal scroll on IntelliMouse Explorer 4.0 */
+				input_report_rel(dev, REL_HWHEEL, (int) (packet[3] & 32) - (int) (packet[3] & 31));
+				break;
+			case 0x00:
+			case 0xC0:
+				input_report_rel(dev, REL_WHEEL, (int) (packet[3] & 8) - (int) (packet[3] & 7));
+				input_report_key(dev, BTN_SIDE, (packet[3] >> 4) & 1);
+				input_report_key(dev, BTN_EXTRA, (packet[3] >> 5) & 1);
+				break;
+		}
 	}
 
 /*
@@ -466,9 +477,25 @@
 	if (param[0] != 4)
 		return -1;
 
+/* Magic to enable horizontal scrolling on IntelliMouse 4.0 */
+	param[0] = 200;
+	ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE);
+	param[0] =  80;
+	ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE);
+	param[0] =  40;
+	ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE);
+
+	param[0] = 200;
+	ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE);
+	param[0] = 200;
+	ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE);
+	param[0] =  60;
+	ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE);
+
 	if (set_properties) {
 		set_bit(BTN_MIDDLE, psmouse->dev->keybit);
 		set_bit(REL_WHEEL, psmouse->dev->relbit);
+		set_bit(REL_HWHEEL, psmouse->dev->relbit);
 		set_bit(BTN_SIDE, psmouse->dev->keybit);
 		set_bit(BTN_EXTRA, psmouse->dev->keybit);