25-akpm/drivers/input/mouse/synaptics.c |   90 ++++++++++++++++++++++++++++----
 25-akpm/drivers/input/mouse/synaptics.h |   12 ++++
 2 files changed, 92 insertions(+), 10 deletions(-)

diff -puN drivers/input/mouse/synaptics.c~p00003_synaptics-multi-button drivers/input/mouse/synaptics.c
--- 25/drivers/input/mouse/synaptics.c~p00003_synaptics-multi-button	Tue Jul 29 14:57:02 2003
+++ 25-akpm/drivers/input/mouse/synaptics.c	Tue Jul 29 14:57:02 2003
@@ -106,16 +106,25 @@ static int synaptics_model_id(struct psm
  * Read the capability-bits from the touchpad
  * see also the SYN_CAP_* macros
  */
-static int synaptics_capability(struct psmouse *psmouse, unsigned long int *capability)
+static int synaptics_capability(struct psmouse *psmouse, unsigned long int *capability, unsigned long int *ext_cap)
 {
 	unsigned char cap[3];
 
 	if (synaptics_send_cmd(psmouse, SYN_QUE_CAPABILITIES, cap))
 		return -1;
 	*capability = (cap[0]<<16) | (cap[1]<<8) | cap[2];
-	if (SYN_CAP_VALID(*capability))
-		return 0;
-	return -1;
+	*ext_cap = 0;
+	if (!SYN_CAP_VALID(*capability))
+		return -1;
+
+	if (SYN_EXT_CAP_REQUESTS(*capability)) {
+		if (synaptics_send_cmd(psmouse, SYN_QUE_EXT_CAPAB, cap)) {
+			printk(KERN_ERR "Synaptics claims to have extended capabilities,"
+			       " but I'm not able to read them.");
+		} else
+			*ext_cap = (cap[0]<<16) | (cap[1]<<8) | cap[2];
+	}
+	return 0;
 }
 
 /*
@@ -146,7 +155,6 @@ static void print_ident(struct synaptics
 	printk(KERN_INFO "Synaptics Touchpad, model: %ld\n", SYN_ID_MODEL(priv->identity));
 	printk(KERN_INFO " Firmware: %ld.%ld\n", SYN_ID_MAJOR(priv->identity),
 	       SYN_ID_MINOR(priv->identity));
-
 	if (SYN_MODEL_ROT180(priv->model_id))
 		printk(KERN_INFO " 180 degree mounted touchpad\n");
 	if (SYN_MODEL_PORTRAIT(priv->model_id))
@@ -159,7 +167,10 @@ static void print_ident(struct synaptics
 
 	if (SYN_CAP_EXTENDED(priv->capabilities)) {
 		printk(KERN_INFO " Touchpad has extended capability bits\n");
-		if (SYN_CAP_FOUR_BUTTON(priv->capabilities))
+		if (SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap))
+			printk(KERN_INFO " -> %d multi-buttons, i.e. besides standard buttons\n",
+			       (int)(SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap)));
+		else if (SYN_CAP_FOUR_BUTTON(priv->capabilities))
 			printk(KERN_INFO " -> four buttons\n");
 		if (SYN_CAP_MULTIFINGER(priv->capabilities))
 			printk(KERN_INFO " -> multifinger detection\n");
@@ -180,7 +191,7 @@ static int query_hardware(struct psmouse
 		return -1;
 	if (synaptics_model_id(psmouse, &priv->model_id))
 		return -1;
-	if (synaptics_capability(psmouse, &priv->capabilities))
+	if (synaptics_capability(psmouse, &priv->capabilities, &priv->ext_cap))
 		return -1;
 	if (synaptics_set_mode(psmouse, (SYN_BIT_ABSOLUTE_MODE |
 					 SYN_BIT_HIGH_RATE |
@@ -243,7 +254,24 @@ int synaptics_init(struct psmouse *psmou
 	set_bit(BTN_RIGHT, psmouse->dev.keybit);
 	set_bit(BTN_FORWARD, psmouse->dev.keybit);
 	set_bit(BTN_BACK, psmouse->dev.keybit);
-
+	if (SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap))
+		switch (SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap) & ~0x01) {
+		default:
+			printk(KERN_ERR "This touchpad reports more than 8 multi-buttons, don't know how to handle.\n");
+		case 8:
+			set_bit(BTN_7, psmouse->dev.keybit);
+			set_bit(BTN_6, psmouse->dev.keybit);
+		case 6:
+			set_bit(BTN_5, psmouse->dev.keybit);
+			set_bit(BTN_4, psmouse->dev.keybit);
+		case 4:
+			set_bit(BTN_3, psmouse->dev.keybit);
+			set_bit(BTN_2, psmouse->dev.keybit);
+		case 2:
+			set_bit(BTN_1, psmouse->dev.keybit);
+			set_bit(BTN_0, psmouse->dev.keybit);
+			break;
+		}
 	clear_bit(EV_REL, psmouse->dev.evbit);
 	clear_bit(REL_X, psmouse->dev.relbit);
 	clear_bit(REL_Y, psmouse->dev.relbit);
@@ -289,7 +317,14 @@ static void synaptics_parse_hw_state(str
 	hw->right = (buf[0] & 0x2) ? 1 : 0;
 	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;
 	if (SYN_CAP_EXTENDED(priv->capabilities) &&
 	    (SYN_CAP_FOUR_BUTTON(priv->capabilities))) {
 		hw->up = ((buf[3] & 0x01)) ? 1 : 0;
@@ -299,6 +334,24 @@ static void synaptics_parse_hw_state(str
 		if (hw->right)
 			hw->down = !hw->down;
 	}
+	if (buf[3] == 0xC2 && SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap)) {
+		switch (SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap) & ~0x01) {
+		default:
+			; /* we did comment while initialising... */
+		case 8:
+			hw->b7 = ((buf[5] & 0x08)) ? 1 : 0;
+			hw->b6 = ((buf[4] & 0x08)) ? 1 : 0;
+		case 6:
+			hw->b5 = ((buf[5] & 0x04)) ? 1 : 0;
+			hw->b4 = ((buf[4] & 0x04)) ? 1 : 0;
+		case 4:
+			hw->b3 = ((buf[5] & 0x02)) ? 1 : 0;
+			hw->b2 = ((buf[4] & 0x02)) ? 1 : 0;
+		case 2:
+			hw->b1 = ((buf[5] & 0x01)) ? 1 : 0;
+			hw->b0 = ((buf[4] & 0x01)) ? 1 : 0;
+		}
+	}
 }
 
 /*
@@ -350,7 +403,24 @@ static void synaptics_process_packet(str
 	input_report_key(dev, BTN_RIGHT,   hw.right);
 	input_report_key(dev, BTN_FORWARD, hw.up);
 	input_report_key(dev, BTN_BACK,    hw.down);
-
+	if (SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap))
+		switch(SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap) & ~0x01) {
+		default:
+			; /* we did comment while initialising... */
+		case 8:
+			input_report_key(dev, BTN_7,       hw.b7);
+			input_report_key(dev, BTN_6,       hw.b6);
+		case 6:
+			input_report_key(dev, BTN_5,       hw.b5);
+			input_report_key(dev, BTN_4,       hw.b4);
+		case 4:
+			input_report_key(dev, BTN_3,       hw.b3);
+			input_report_key(dev, BTN_2,       hw.b2);
+		case 2:
+			input_report_key(dev, BTN_1,       hw.b1);
+			input_report_key(dev, BTN_0,       hw.b0);
+			break;
+		}
 	input_sync(dev);
 }
 
diff -puN drivers/input/mouse/synaptics.h~p00003_synaptics-multi-button drivers/input/mouse/synaptics.h
--- 25/drivers/input/mouse/synaptics.h~p00003_synaptics-multi-button	Tue Jul 29 14:57:02 2003
+++ 25-akpm/drivers/input/mouse/synaptics.h	Tue Jul 29 14:57:02 2003
@@ -22,6 +22,7 @@ extern void synaptics_disconnect(struct 
 #define SYN_QUE_SERIAL_NUMBER_PREFIX	0x06
 #define SYN_QUE_SERIAL_NUMBER_SUFFIX	0x07
 #define SYN_QUE_RESOLUTION		0x08
+#define SYN_QUE_EXT_CAPAB		0x09
 
 /* synatics modes */
 #define SYN_BIT_ABSOLUTE_MODE		(1 << 7)
@@ -47,6 +48,8 @@ extern void synaptics_disconnect(struct 
 #define SYN_CAP_MULTIFINGER(c)		((c) & (1 << 1))
 #define SYN_CAP_PALMDETECT(c)		((c) & (1 << 0))
 #define SYN_CAP_VALID(c)		((((c) & 0x00ff00) >> 8) == 0x47)
+#define SYN_EXT_CAP_REQUESTS(c)		((((c) & 0x700000) >> 20) == 1)
+#define SYN_CAP_MULTI_BUTTON_NO(ec)	(((ec) & 0x00f000) >> 12)
 
 /* synaptics modes query bits */
 #define SYN_MODE_ABSOLUTE(m)		((m) & (1 << 7))
@@ -75,12 +78,21 @@ struct synaptics_hw_state {
 	int right;
 	int up;
 	int down;
+	int b0;
+	int b1;
+	int b2;
+	int b3;
+	int b4;
+	int b5;
+	int b6;
+	int b7;
 };
 
 struct synaptics_data {
 	/* Data read from the touchpad */
 	unsigned long int model_id;		/* Model-ID */
 	unsigned long int capabilities; 	/* Capabilities */
+	unsigned long int ext_cap; 		/* Extended Capabilities */
 	unsigned long int identity;		/* Identification */
 
 	/* Data for normal processing */

_