--- linux-source-2.6.17-orig/drivers/usb/input/appletouch.c	2006-09-23 04:19:07.000000000 +0100
+++ linux-source-2.6.17/drivers/usb/input/appletouch.c	2007-04-09 18:31:17.000000000 +0100
@@ -47,6 +47,11 @@
 #define GEYSER_ISO_PRODUCT_ID	0x0215
 #define GEYSER_JIS_PRODUCT_ID	0x0216
 
+/* MacBook Devices */
+#define GEYSER3_ANSI_PRODUCT_ID	0x0217
+#define GEYSER3_ISO_PRODUCT_ID	0x0218
+#define GEYSER3_JIS_PRODUCT_ID	0x0219
+
 #define ATP_DEVICE(prod)					\
 	.match_flags = USB_DEVICE_ID_MATCH_DEVICE |		\
 		       USB_DEVICE_ID_MATCH_INT_CLASS |		\
@@ -68,6 +73,11 @@
 	{ ATP_DEVICE(GEYSER_ISO_PRODUCT_ID) },
 	{ ATP_DEVICE(GEYSER_JIS_PRODUCT_ID) },
 
+	{ ATP_DEVICE(GEYSER3_ANSI_PRODUCT_ID) },
+	{ ATP_DEVICE(GEYSER3_ISO_PRODUCT_ID) },
+	{ ATP_DEVICE(GEYSER3_JIS_PRODUCT_ID) },
+
+
 	/* Terminating entry */
 	{ }
 };
@@ -104,6 +114,20 @@
  * ignored.
  */
 #define ATP_THRESHOLD	 10
+/* Make the threshold a module parameter */
+static int tap_threshold = ATP_THRESHOLD;
+static int track_threshold = ATP_THRESHOLD;
+module_param(tap_threshold, int, 0644);
+module_param(track_threshold, int, 0644);
+MODULE_PARM_DESC(tap_threshold, "Discards any change in data from a sensor less than this value(taps)");
+MODULE_PARM_DESC(track_threshold, "Discards any change in data from a sensor less than this value(tracking)");
+
+/* MacBook Pro (Geyser 3) initialization constants */
+#define ATP_GEYSER3_MODE_READ_REQUEST_ID 1
+#define ATP_GEYSER3_MODE_WRITE_REQUEST_ID 9
+#define ATP_GEYSER3_MODE_REQUEST_VALUE 0x300
+#define ATP_GEYSER3_MODE_REQUEST_INDEX 0
+#define ATP_GEYSER3_MODE_VENDOR_VALUE 0x04
 
 /* Structure to hold all of our device specific stuff */
 struct atp {
@@ -158,6 +182,15 @@
 		(productId == GEYSER_JIS_PRODUCT_ID);
 }
 
+static inline int atp_is_geyser_3(struct atp *dev)
+{
+	u16 productId = le16_to_cpu(dev->udev->descriptor.idProduct);
+
+	return (productId == GEYSER3_ANSI_PRODUCT_ID) ||
+		(productId == GEYSER3_ISO_PRODUCT_ID) ||
+		(productId == GEYSER3_JIS_PRODUCT_ID);
+}
+
 static int atp_calculate_abs(int *xy_sensors, int nb_sensors, int fact,
 			     int *z, int *fingers)
 {
@@ -165,15 +198,46 @@
 	/* values to calculate mean */
 	int pcum = 0, psum = 0;
 
+	int is_increasing = 0;
+
 	*fingers = 0;
 
 	for (i = 0; i < nb_sensors; i++) {
-		if (xy_sensors[i] < ATP_THRESHOLD)
+		if (xy_sensors[i] < tap_threshold) {
+			if (is_increasing)
+				is_increasing = 0;
 			continue;
-		if ((i - 1 < 0) || (xy_sensors[i - 1] < ATP_THRESHOLD))
+		}
+		/*
+  		 * Makes the finger detection more versatile.  For example,
+  		 * two fingers with no gap will be detected.  Also, my
+  		 * tests show it less likely to have intermittent loss
+  		 * of multiple finger readings while moving around (scrolling).
+  		 *
+  		 * Changes the multiple finger detection to counting humps on
+  		 * sensors (transitions from nonincreasing to increasing)
+  		 * instead of counting transitions from low sensors (no
+  		 * finger reading) to high sensors (finger above
+  		 * sensor)
+  		 * 
+  		 * - Jason Parekh <jasonparekh@gmail.com>
+  		 */
+		if ((i < 1) || (!is_increasing && (xy_sensors[i-1] < xy_sensors[i]))) {
 			(*fingers)++;
-		pcum += xy_sensors[i] * i;
-		psum += xy_sensors[i];
+			is_increasing = 1;
+		} else if ((i > 0) && (xy_sensors[i-1] >= xy_sensors[i])) {
+			is_increasing = 0;
+		}
+		
+	/* 
+	 * Subtracts threshold so a high sensor that just passes the threshold
+ 	 * won't skew the calculated absolute coordinate.  Fixes an issue
+ 	 * where slowly moving the mouse would occassionaly jump a number of
+ 	 * pixels (let me restate--slowly moving the mouse makes this issue
+ 	 * most apparent).
+ 	 */
+		pcum += (xy_sensors[i]-track_threshold) * i;
+		psum += (xy_sensors[i]-track_threshold);
 	}
 
 	if (psum > 0) {
@@ -223,12 +287,33 @@
 
 	/* drop incomplete datasets */
 	if (dev->urb->actual_length != dev->datalen) {
-		dprintk("appletouch: incomplete data package.\n");
+		dprintk("appletouch: incomplete data package"
+			" (first byte: %d, length: %d).\n",
+			dev->data[0], dev->urb->actual_length);
 		goto exit;
 	}
 
 	/* reorder the sensors values */
-	if (atp_is_geyser_2(dev)) {
+	if (atp_is_geyser_3(dev)) {
+		memset(dev->xy_cur, 0, sizeof(dev->xy_cur));
+
+		/*
+		 * The values are laid out like this:
+		 * -, Y1, Y2, -, Y3, Y4, -, ..., -, X1, X2, -, X3, X4, ...
+		 * '-' is an unused value.
+		 */
+
+		/* read X values */
+		for (i = 0, j = 19; i < 20; i += 2, j += 3) {
+			dev->xy_cur[i] = dev->data[j + 1];
+			dev->xy_cur[i + 1] = dev->data[j + 2];
+		}
+		/* read Y values */
+		for (i = 0, j = 1; i < 9; i += 2, j += 3) {
+			dev->xy_cur[ATP_XSENSORS + i] = dev->data[j + 1];
+			dev->xy_cur[ATP_XSENSORS + i + 1] = dev->data[j + 2];
+		}
+	} else if (atp_is_geyser_2(dev)) {
 		memset(dev->xy_cur, 0, sizeof(dev->xy_cur));
 
 		/*
@@ -271,6 +356,9 @@
 		dev->x_old = dev->y_old = -1;
 		memcpy(dev->xy_old, dev->xy_cur, sizeof(dev->xy_old));
 
+		if (atp_is_geyser_3(dev)) /* No 17" Macbooks (yet) */
+			goto exit;
+
 		/* 17" Powerbooks have extra X sensors */
 		for (i = (atp_is_geyser_2(dev)?15:16); i < ATP_XSENSORS; i++) {
 			if (!dev->xy_cur[i]) continue;
@@ -417,7 +505,51 @@
 	dev->udev = udev;
 	dev->input = input_dev;
 	dev->overflowwarn = 0;
-	dev->datalen = (atp_is_geyser_2(dev)?64:81);
+
+	if (atp_is_geyser_3(dev))
+		dev->datalen = 64;
+	else if (atp_is_geyser_2(dev))
+		dev->datalen = 64;
+	else
+		dev->datalen = 81;
+
+	if (atp_is_geyser_3(dev)) {
+		/*
+		 * By default Geyser 3 device sends standard USB HID mouse
+		 * packets (Report ID 2). This code changes device mode, so it
+		 * sends raw sensor reports (Report ID 5).
+		 */
+		char data[8];
+		int size;
+
+		size = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
+			ATP_GEYSER3_MODE_READ_REQUEST_ID,
+			USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+			ATP_GEYSER3_MODE_REQUEST_VALUE,
+			ATP_GEYSER3_MODE_REQUEST_INDEX, &data, 8, 5000);
+
+		if (size != 8) {
+			err("Could not do mode read request from device"
+							" (Geyser 3 mode)");
+			goto err_free_devs;
+		}
+
+		/* Apply the mode switch */
+		data[0] = ATP_GEYSER3_MODE_VENDOR_VALUE;
+
+		size = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+			ATP_GEYSER3_MODE_WRITE_REQUEST_ID,
+			USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+			ATP_GEYSER3_MODE_REQUEST_VALUE,
+			ATP_GEYSER3_MODE_REQUEST_INDEX, &data, 8, 5000);
+
+		if (size != 8) {
+			err("Could not do mode write request to device"
+							" (Geyser 3 mode)");
+			goto err_free_devs;
+		}
+		printk("appletouch Geyser 3 inited.\n");
+	}
 
 	dev->urb = usb_alloc_urb(0, GFP_KERNEL);
 	if (!dev->urb) {
@@ -450,7 +582,15 @@
 
 	set_bit(EV_ABS, input_dev->evbit);
 
-	if (atp_is_geyser_2(dev)) {
+	if (atp_is_geyser_3(dev)) {
+		/*
+		 * MacBook have 20 X sensors, 10 Y sensors
+		 */
+		input_set_abs_params(input_dev, ABS_X, 0,
+				     ((20 - 1) * ATP_XFACT) - 1, ATP_FUZZ, 0);
+		input_set_abs_params(input_dev, ABS_Y, 0,
+				     ((10 - 1) * ATP_YFACT) - 1, ATP_FUZZ, 0);
+	} else if (atp_is_geyser_2(dev)) {
 		/*
 		 * Oct 2005 15" PowerBooks have 15 X sensors, 17" are detected
 		 * later.

