On Sun, 2007-06-24 at 11:04 +0200, Nicolas Boichat wrote:
> Soeren Sonnenburg wrote:
> > The attached patch tries to resolve the 'appletouch runs amok' problem,
> > which accured *for me* after using the mbp for a couple of hours/days
> > with the power-saving [PATCH] Make appletouch shut up when it has
> > nothing to say from Matthew Garrett.
> > 
> > I am using it for 3 days now without ever running in trouble. So I think
> > it is ready for wider testing.
> 
> In SVN now, so it will get wider testing .-)

I've had the same problem to re-appear like a week ago. Since then I
have been investigating this issue further and am attaching a new patch
which survived for the last 5 days.

First of all the left mouse button is just bit one in the status byte
(the last byte in the package) as was discovered by sven anders.

Second, when appletouch after 10 idle packages does a mode reset, the
data should marked invalid (then on the next touch the driver re-gets
data once without moving mouse etc). This is important if the touchpad
conditions change (e.g. long time no touch + bigger temperature change).

However sven figured out that bit 3 of the status bit should actually be
used to re-get touchpad data.

So if you want a working minimally intrusive patch use this one.

I will in future only contribute to svens much more mature work.

Soeren
diff --git a/drivers/input/mouse/appletouch.c b/drivers/input/mouse/appletouch.c
index e321526..c434685 100644
--- a/drivers/input/mouse/appletouch.c
+++ b/drivers/input/mouse/appletouch.c
@@ -134,7 +134,7 @@ MODULE_DEVICE_TABLE (usb, atp_table);
 #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
+#define ATP_GEYSER3_MODE_VENDOR_VALUE 0x24
 
 /* Structure to hold all of our device specific stuff */
 struct atp {
@@ -155,6 +155,8 @@ struct atp {
 	int			xy_acc[ATP_XSENSORS + ATP_YSENSORS];
 	int			overflowwarn;	/* overflow warning printed? */
 	int			datalen;	/* size of an USB urb transfer */
+	int                     idlecount;      /* number of empty packets */
+	struct work_struct      work;
 };
 
 #define dbg_dump(msg, tab) \
@@ -208,6 +210,64 @@ static inline int atp_is_geyser_3(struct atp *dev)
 		(productId == GEYSER4_JIS_PRODUCT_ID);
 }
 
+/*
+ * 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).
+ */
+static int atp_geyser3_init(struct usb_device *udev)
+{
+	char data[8];
+	int size;
+	int i;
+
+	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) {
+		printk("appletouch atp_geyser3_init READ error\n");
+		for (i=0; i<8; i++)
+			printk("appletouch[%d]: %d\n", i, (int) data[i]);
+
+		err("Could not do mode read request from device"
+		    " (Geyser 3 mode)");
+		return -EIO;
+	}
+
+	/* 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) {
+		printk("appletouch atp_geyser3_init WRITE error\n");
+		for (i=0; i<8; i++)
+			printk("appletouch[%d]: %d\n", i, (int) data[i]);
+		err("Could not do mode write request to device"
+		    " (Geyser 3 mode)");
+		return -EIO;
+	}
+	return 0;
+}
+
+/* Reinitialise the device if it's a geyser 3 */
+static void atp_reinit(struct work_struct *work)
+{
+	struct atp *dev = container_of(work, struct atp, work);
+	struct usb_device *udev = dev->udev;
+
+	dev->idlecount = 0;
+	atp_geyser3_init(udev);
+}
+
 static int atp_calculate_abs(int *xy_sensors, int nb_sensors, int fact,
 			     int *z, int *fingers)
 {
@@ -418,6 +478,8 @@ static void atp_complete(struct urb* urb)
 	y = atp_calculate_abs(dev->xy_acc + ATP_XSENSORS, ATP_YSENSORS,
 			      ATP_YFACT, &y_z, &y_f);
 
+	input_report_key(dev->input, BTN_LEFT, dev->data[dev->datalen-1] & 1);
+
 	if (x && y) {
 		if (dev->x_old != -1) {
 			x = (dev->x_old * 3 + x) >> 2;
@@ -441,18 +503,33 @@ static void atp_complete(struct urb* urb)
 		dev->y_old = y;
 	}
 	else if (!x && !y) {
-
 		dev->x_old = dev->y_old = -1;
-		input_report_key(dev->input, BTN_TOUCH, 0);
 		input_report_abs(dev->input, ABS_PRESSURE, 0);
-		atp_report_fingers(dev->input, 0);
+
+		input_report_key(dev->input, BTN_TOUCH, 0);
+		input_report_key(dev->input, BTN_TOOL_FINGER, 0);
+		input_report_key(dev->input, BTN_TOOL_DOUBLETAP, 0);
+		input_report_key(dev->input, BTN_TOOL_TRIPLETAP, 0);
 
 		/* reset the accumulator on release */
 		memset(dev->xy_acc, 0, sizeof(dev->xy_acc));
-	}
 
-	input_report_key(dev->input, BTN_LEFT,
-			 !!dev->data[dev->datalen - 1]);
+		/* Geyser 3 will continue to send packets continually after
+		   the first touch unless reinitialised. Do so if it's been
+		   idle for a while in order to avoid waking the kernel up
+		   several hundred times a second */
+		if (atp_is_geyser_3(dev)) {
+			dev->idlecount++;
+			if (dev->idlecount == 10) {
+				memset(dev->data, 0, dev->datalen);
+				memset(dev->xy_old, 0, sizeof(dev->xy_old));
+				memset(dev->xy_cur, 0, sizeof(dev->xy_cur));
+				dev->valid=0;
+
+				schedule_work (&dev->work);
+			}
+		}
+	}
 
 	input_sync(dev->input);
 
@@ -466,7 +543,7 @@ exit:
 
 static int atp_open(struct input_dev *input)
 {
-	struct atp *dev = input_get_drvdata(input);
+	struct atp *dev = input->private;
 
 	if (usb_submit_urb(dev->urb, GFP_ATOMIC))
 		return -EIO;
@@ -477,7 +554,7 @@ static int atp_open(struct input_dev *input)
 
 static void atp_close(struct input_dev *input)
 {
-	struct atp *dev = input_get_drvdata(input);
+	struct atp *dev = input->private;
 
 	usb_kill_urb(dev->urb);
 	dev->open = 0;
@@ -491,7 +568,8 @@ static int atp_probe(struct usb_interface *iface, const struct usb_device_id *id
 	struct usb_host_interface *iface_desc;
 	struct usb_endpoint_descriptor *endpoint;
 	int int_in_endpointAddr = 0;
-	int i, error = -ENOMEM;
+	int i, retval = -ENOMEM;
+
 
 	/* set up the endpoint information */
 	/* use only the first interrupt-in endpoint */
@@ -528,55 +606,29 @@ static int atp_probe(struct usb_interface *iface, const struct usb_device_id *id
 		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)");
+		/* switch to raw sensor mode */
+		if (atp_geyser3_init(udev))
 			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)
+	if (!dev->urb) {
+		retval = -ENOMEM;
 		goto err_free_devs;
+	}
 
 	dev->data = usb_buffer_alloc(dev->udev, dev->datalen, GFP_KERNEL,
 				     &dev->urb->transfer_dma);
-	if (!dev->data)
+	if (!dev->data) {
+		retval = -ENOMEM;
 		goto err_free_urb;
+	}
 
 	usb_fill_int_urb(dev->urb, udev,
 			 usb_rcvintpipe(udev, int_in_endpointAddr),
-			 dev->data, dev->datalen, atp_complete, dev, 1);
+			 dev->data, dev->datalen, atp_complete, dev, 2);
 
 	usb_make_path(udev, dev->phys, sizeof(dev->phys));
 	strlcat(dev->phys, "/input0", sizeof(dev->phys));
@@ -584,10 +636,9 @@ static int atp_probe(struct usb_interface *iface, const struct usb_device_id *id
 	input_dev->name = "appletouch";
 	input_dev->phys = dev->phys;
 	usb_to_input_id(dev->udev, &input_dev->id);
-	input_dev->dev.parent = &iface->dev;
-
-	input_set_drvdata(input_dev, dev);
+	input_dev->cdev.dev = &iface->dev;
 
+	input_dev->private = dev;
 	input_dev->open = atp_open;
 	input_dev->close = atp_close;
 
@@ -629,25 +680,22 @@ static int atp_probe(struct usb_interface *iface, const struct usb_device_id *id
 	set_bit(BTN_TOOL_TRIPLETAP, input_dev->keybit);
 	set_bit(BTN_LEFT, input_dev->keybit);
 
-	error = input_register_device(dev->input);
-	if (error)
-		goto err_free_buffer;
+	input_register_device(dev->input);
 
 	/* save our data pointer in this interface device */
 	usb_set_intfdata(iface, dev);
 
+	INIT_WORK(&dev->work, atp_reinit);
+
 	return 0;
 
- err_free_buffer:
-	usb_buffer_free(dev->udev, dev->datalen,
-			dev->data, dev->urb->transfer_dma);
  err_free_urb:
 	usb_free_urb(dev->urb);
  err_free_devs:
 	usb_set_intfdata(iface, NULL);
 	kfree(dev);
 	input_free_device(input_dev);
-	return error;
+	return retval;
 }
 
 static void atp_disconnect(struct usb_interface *iface)
@@ -656,6 +704,7 @@ static void atp_disconnect(struct usb_interface *iface)
 
 	usb_set_intfdata(iface, NULL);
 	if (dev) {
+		cancel_work_sync(&dev->work);
 		usb_kill_urb(dev->urb);
 		input_unregister_device(dev->input);
 		usb_buffer_free(dev->udev, dev->datalen,
-------------------------------------------------------------------------
This SF.net email is sponsored by DB2 Express
Download DB2 Express C - the FREE version of DB2 express and take
control of your XML. No limits. Just data. Click to get it now.
http://sourceforge.net/powerbar/db2/
_______________________________________________
Mactel-linux-devel mailing list
Mactel-linux-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/mactel-linux-devel

Reply via email to