linux-input.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/2] appletouch updates for geyser 3/4
@ 2008-07-29 11:11 Johannes Berg
  2008-07-29 11:11 ` [PATCH 1/2] appletouch: prepare for geyser 3/4 handling Johannes Berg
                   ` (2 more replies)
  0 siblings, 3 replies; 5+ messages in thread
From: Johannes Berg @ 2008-07-29 11:11 UTC (permalink / raw)
  To: Dmitry Torokhov; +Cc: linux-input

Not much to say here, works fine on older models and Sven says
it works on new models.

johannes

^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH 1/2] appletouch: prepare for geyser 3/4 handling
  2008-07-29 11:11 [PATCH 0/2] appletouch updates for geyser 3/4 Johannes Berg
@ 2008-07-29 11:11 ` Johannes Berg
  2008-07-29 11:11 ` [PATCH 2/2] appletouch: handle geyser 3/4 status bits Johannes Berg
  2008-10-08  8:18 ` [PATCH 0/2] appletouch updates for geyser 3/4 Johannes Berg
  2 siblings, 0 replies; 5+ messages in thread
From: Johannes Berg @ 2008-07-29 11:11 UTC (permalink / raw)
  To: Dmitry Torokhov; +Cc: linux-input, Sven Anders

[-- Attachment #1: appletouch.c.2.6.27-step1.patch --]
[-- Type: text/plain, Size: 9504 bytes --]

From: Sven Anders <anders@anduras.de>

Split complete function into separate functions 
for GEYSER1/2 and GEYSER 3/4.

Signed-off-by: Sven Anders <anders@anduras.de>
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>

---
 drivers/input/mouse/appletouch.c |  265 ++++++++++++++++++++++++++++-----------
 1 file changed, 196 insertions(+), 69 deletions(-)

--- everything.orig/drivers/input/mouse/appletouch.c	2008-07-26 16:47:17.000000000 +0200
+++ everything/drivers/input/mouse/appletouch.c	2008-07-29 10:01:41.000000000 +0200
@@ -327,11 +327,14 @@ static inline void atp_report_fingers(st
 	input_report_key(input, BTN_TOOL_TRIPLETAP, fingers > 2);
 }
 
-static void atp_complete(struct urb *urb)
+/* Check URB status and for correct length of data package */
+
+#define ATP_URB_STATUS_SUCCESS		0
+#define ATP_URB_STATUS_ERROR		1
+#define ATP_URB_STATUS_ERROR_FATAL	2
+
+static int atp_status_check(struct urb *urb)
 {
-	int x, y, x_z, y_z, x_f, y_f;
-	int retval, i, j;
-	int key;
 	struct atp *dev = urb->context;
 
 	switch (urb->status) {
@@ -351,11 +354,12 @@ static void atp_complete(struct urb *urb
 		/* This urb is terminated, clean up */
 		dbg("atp_complete: urb shutting down with status: %d",
 		    urb->status);
-		return;
+		return ATP_URB_STATUS_ERROR_FATAL;
+
 	default:
 		dbg("atp_complete: nonzero urb status received: %d",
 		    urb->status);
-		goto exit;
+		return ATP_URB_STATUS_ERROR;
 	}
 
 	/* drop incomplete datasets */
@@ -363,30 +367,33 @@ static void atp_complete(struct urb *urb
 		dprintk("appletouch: incomplete data package"
 			" (first byte: %d, length: %d).\n",
 			dev->data[0], dev->urb->actual_length);
-		goto exit;
+		return ATP_URB_STATUS_ERROR;
 	}
 
-	/* reorder the sensors values */
-	if (dev->type == ATP_GEYSER3 || dev->type == ATP_GEYSER4) {
-		memset(dev->xy_cur, 0, sizeof(dev->xy_cur));
+	return ATP_URB_STATUS_SUCCESS;
+}
 
-		/*
-		 * The values are laid out like this:
-		 * -, Y1, Y2, -, Y3, Y4, -, ..., -, X1, X2, -, X3, X4, ...
-		 * '-' is an unused value.
-		 */
+/*
+ * USB interrupt callback functions
+ */
 
-		/* 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 (dev->type == ATP_GEYSER2) {
+/* Interrupt function for older touchpads: FOUNTAIN/GEYSER1/GEYSER2 */
+
+static void atp_complete_geyser_1_2(struct urb *urb)
+{
+	int x, y, x_z, y_z, x_f, y_f;
+	int retval, i, j;
+	int key;
+	struct atp *dev = urb->context;
+	int status = atp_status_check(urb);
+
+	if (status == ATP_URB_STATUS_ERROR_FATAL)
+		return;
+	else if (status == ATP_URB_STATUS_ERROR)
+		goto exit;
+
+	/* reorder the sensors values */
+	if (dev->type == ATP_GEYSER2) {
 		memset(dev->xy_cur, 0, sizeof(dev->xy_cur));
 
 		/*
@@ -427,33 +434,145 @@ static void atp_complete(struct urb *urb
 		/* first sample */
 		dev->valid = true;
 		dev->x_old = dev->y_old = -1;
+
+		/* Store first sample */
 		memcpy(dev->xy_old, dev->xy_cur, sizeof(dev->xy_old));
 
-		if (dev->size_detect_done ||
-		    dev->type == ATP_GEYSER3) /* No 17" Macbooks (yet) */
+		/* Perform size detection, if not done already */
+		if (!dev->size_detect_done) {
+
+			/* 17" Powerbooks have extra X sensors */
+			for (i = (dev->type == ATP_GEYSER2 ? 15 : 16);
+			     i < ATP_XSENSORS; i++) {
+				if (!dev->xy_cur[i])
+					continue;
+
+				printk(KERN_INFO "appletouch: 17\" model "
+				       "detected.\n");
+				if (dev->type == ATP_GEYSER2)
+					input_set_abs_params(dev->input, ABS_X,
+							     0,
+							     (20 - 1) *
+							     ATP_XFACT - 1,
+							     ATP_FUZZ, 0);
+				else
+					input_set_abs_params(dev->input, ABS_X,
+							     0,
+							     (26 - 1)*
+							     ATP_XFACT - 1,
+							     ATP_FUZZ, 0);
+				break;
+			}
+
+			dev->size_detect_done = 1;
 			goto exit;
+		}
+	}
 
-		/* 17" Powerbooks have extra X sensors */
-		for (i = (dev->type == ATP_GEYSER2 ? 15 : 16);
-		     i < ATP_XSENSORS; i++) {
-			if (!dev->xy_cur[i])
-				continue;
-
-			printk(KERN_INFO "appletouch: 17\" model detected.\n");
-			if (dev->type == ATP_GEYSER2)
-				input_set_abs_params(dev->input, ABS_X, 0,
-						     (20 - 1) *
-						     ATP_XFACT - 1,
-						     ATP_FUZZ, 0);
-			else
-				input_set_abs_params(dev->input, ABS_X, 0,
-						     (ATP_XSENSORS - 1) *
-						     ATP_XFACT - 1,
-						     ATP_FUZZ, 0);
-			break;
+	for (i = 0; i < ATP_XSENSORS + ATP_YSENSORS; i++) {
+		/* accumulate the change */
+		signed char change = dev->xy_old[i] - dev->xy_cur[i];
+		dev->xy_acc[i] -= change;
+
+		/* prevent down drifting */
+		if (dev->xy_acc[i] < 0)
+			dev->xy_acc[i] = 0;
+	}
+
+	memcpy(dev->xy_old, dev->xy_cur, sizeof(dev->xy_old));
+
+	dbg_dump("accumulator", dev->xy_acc);
+
+	x = atp_calculate_abs(dev->xy_acc, ATP_XSENSORS,
+			      ATP_XFACT, &x_z, &x_f);
+	y = atp_calculate_abs(dev->xy_acc + ATP_XSENSORS, ATP_YSENSORS,
+			      ATP_YFACT, &y_z, &y_f);
+	key = dev->data[dev->datalen - 1] & 1;
+
+	if (x && y) {
+		if (dev->x_old != -1) {
+			x = (dev->x_old * 3 + x) >> 2;
+			y = (dev->y_old * 3 + y) >> 2;
+			dev->x_old = x;
+			dev->y_old = y;
+
+			if (debug > 1)
+				printk(KERN_DEBUG "appletouch: X: %3d Y: %3d "
+				       "Xz: %3d Yz: %3d\n",
+				       x, y, x_z, y_z);
+
+			input_report_key(dev->input, BTN_TOUCH, 1);
+			input_report_abs(dev->input, ABS_X, x);
+			input_report_abs(dev->input, ABS_Y, y);
+			input_report_abs(dev->input, ABS_PRESSURE,
+					 min(ATP_PRESSURE, x_z + y_z));
+			atp_report_fingers(dev->input, max(x_f, y_f));
 		}
+		dev->x_old = x;
+		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);
+
+		/* reset the accumulator on release */
+		memset(dev->xy_acc, 0, sizeof(dev->xy_acc));
+	}
+
+	input_report_key(dev->input, BTN_LEFT, key);
+	input_sync(dev->input);
+
+ exit:
+	retval = usb_submit_urb(dev->urb, GFP_ATOMIC);
+	if (retval)
+		err("atp_complete: usb_submit_urb failed with result %d",
+		    retval);
+}
+
+/* Interrupt function for older touchpads: GEYSER3/GEYSER4 */
+
+static void atp_complete_geyser_3_4(struct urb *urb)
+{
+	int x, y, x_z, y_z, x_f, y_f;
+	int retval, i, j;
+	int key;
+	struct atp *dev = urb->context;
+	int status = atp_status_check(urb);
+
+	if (status == ATP_URB_STATUS_ERROR_FATAL)
+		return;
+	else if (status == ATP_URB_STATUS_ERROR)
+		goto exit;
+
+	/* Reorder the sensors values:
+	 *
+	 * 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];
+	}
+
+	dbg_dump("sample", dev->xy_cur);
+
+	if (!dev->valid) {
+		/* first sample */
+		dev->valid = true;
+		dev->x_old = dev->y_old = -1;
+		memcpy(dev->xy_old, dev->xy_cur, sizeof(dev->xy_old));
 
-		dev->size_detect_done = 1;
 		goto exit;
 	}
 
@@ -514,28 +633,26 @@ static void atp_complete(struct urb *urb
 	input_sync(dev->input);
 
 	/*
-	 * Many Geysers will continue to send packets continually after
+	 * Geysers 3/4 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. Re-initialization does not
-	 * work on Fountain touchpads.
+	 * several hundred times a second.
 	 */
-	if (dev->type != ATP_FOUNTAIN) {
-		/*
-		 * Button must not be pressed when entering suspend,
-		 * otherwise we will never release the button.
-		 */
-		if (!x && !y && !key) {
-			dev->idlecount++;
-			if (dev->idlecount == 10) {
-				dev->valid = false;
-				schedule_work(&dev->work);
-				/* Don't resubmit urb here, wait for reinit */
-				return;
-			}
-		} else
-			dev->idlecount = 0;
-	}
+
+	/*
+	 * Button must not be pressed when entering suspend,
+	 * otherwise we will never release the button.
+	 */
+	if (!x && !y && !key) {
+		dev->idlecount++;
+		if (dev->idlecount == 10) {
+			dev->valid = false;
+			schedule_work(&dev->work);
+			/* Don't resubmit urb here, wait for reinit */
+			return;
+		}
+	} else
+		dev->idlecount = 0;
 
  exit:
 	retval = usb_submit_urb(dev->urb, GFP_ATOMIC);
@@ -632,9 +749,19 @@ static int atp_probe(struct usb_interfac
 	if (!dev->data)
 		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);
+	/* Select the USB complete (callback) function */
+	if (dev->type == ATP_FOUNTAIN ||
+	    dev->type == ATP_GEYSER1 ||
+	    dev->type == ATP_GEYSER2)
+		usb_fill_int_urb(dev->urb, udev,
+				 usb_rcvintpipe(udev, int_in_endpointAddr),
+				 dev->data, dev->datalen,
+				 atp_complete_geyser_1_2, dev, 1);
+	else
+		usb_fill_int_urb(dev->urb, udev,
+				 usb_rcvintpipe(udev, int_in_endpointAddr),
+				 dev->data, dev->datalen,
+				 atp_complete_geyser_3_4, dev, 1);
 
 	error = atp_handle_geyser(dev);
 	if (error)

-- 


^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH 2/2] appletouch: handle geyser 3/4 status bits
  2008-07-29 11:11 [PATCH 0/2] appletouch updates for geyser 3/4 Johannes Berg
  2008-07-29 11:11 ` [PATCH 1/2] appletouch: prepare for geyser 3/4 handling Johannes Berg
@ 2008-07-29 11:11 ` Johannes Berg
  2008-10-08  8:18 ` [PATCH 0/2] appletouch updates for geyser 3/4 Johannes Berg
  2 siblings, 0 replies; 5+ messages in thread
From: Johannes Berg @ 2008-07-29 11:11 UTC (permalink / raw)
  To: Dmitry Torokhov; +Cc: linux-input, Sven Anders

[-- Attachment #1: appletouch.c.2.6.27-step2.patch --]
[-- Type: text/plain, Size: 4050 bytes --]

From: Sven Anders <anders@anduras.de>

Implement support for status bits on Geyser 3/4.

Signed-off-by: Sven Anders <anders@anduras.de>
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>

---
 drivers/input/mouse/appletouch.c |   54 ++++++++++++++++++++++++++-------------
 1 file changed, 36 insertions(+), 18 deletions(-)

--- everything.orig/drivers/input/mouse/appletouch.c	2008-07-29 09:57:56.000000000 +0200
+++ everything/drivers/input/mouse/appletouch.c	2008-07-29 09:58:01.000000000 +0200
@@ -136,12 +136,28 @@ MODULE_DEVICE_TABLE(usb, atp_table);
 #define ATP_GEYSER_MODE_REQUEST_INDEX		0
 #define ATP_GEYSER_MODE_VENDOR_VALUE		0x04
 
+/**
+ * enum atp_status_bits - status bit meanings
+ *
+ * These constants represent the meaning of the status bits.
+ * (only Geyser 3/4)
+ *
+ * @ATP_STATUS_BUTTON: The button was pressed
+ * @ATP_STATUS_BASE_UPDATE: Update of the base values (untouched pad)
+ * @ATP_STATUS_FROM_RESET: Reset previously performed
+ */
+enum atp_status_bits {
+	ATP_STATUS_BUTTON	= BIT(0),
+	ATP_STATUS_BASE_UPDATE	= BIT(2),
+	ATP_STATUS_FROM_RESET	= BIT(4),
+};
+
 /* Structure to hold all of our device specific stuff */
 struct atp {
 	char			phys[64];
 	struct usb_device	*udev;		/* usb device */
 	struct urb		*urb;		/* usb request block */
-	signed char		*data;		/* transferred data */
+	u8			*data;		/* transferred data */
 	struct input_dev	*input;		/* input dev */
 	enum atp_touchpad_type	type;		/* type of touchpad */
 	bool			open;
@@ -251,8 +267,6 @@ static void atp_reinit(struct work_struc
 	int retval;
 
 	dprintk("appletouch: putting appletouch to sleep (reinit)\n");
-	dev->idlecount = 0;
-
 	atp_geyser_init(udev);
 
 	retval = usb_submit_urb(dev->urb, GFP_ATOMIC);
@@ -487,7 +501,7 @@ static void atp_complete_geyser_1_2(stru
 			      ATP_XFACT, &x_z, &x_f);
 	y = atp_calculate_abs(dev->xy_acc + ATP_XSENSORS, ATP_YSENSORS,
 			      ATP_YFACT, &y_z, &y_f);
-	key = dev->data[dev->datalen - 1] & 1;
+	key = dev->data[dev->datalen - 1] & ATP_STATUS_BUTTON;
 
 	if (x && y) {
 		if (dev->x_old != -1) {
@@ -567,34 +581,39 @@ static void atp_complete_geyser_3_4(stru
 
 	dbg_dump("sample", dev->xy_cur);
 
-	if (!dev->valid) {
-		/* first sample */
-		dev->valid = true;
-		dev->x_old = dev->y_old = -1;
-		memcpy(dev->xy_old, dev->xy_cur, sizeof(dev->xy_old));
+	/* Just update the base values (i.e. touchpad in untouched state) */
+	if (dev->data[dev->datalen-1] & ATP_STATUS_BASE_UPDATE) {
+
+		if (debug)
+			printk(KERN_DEBUG "appletouch: updated base values\n");
 
+		memcpy(dev->xy_old, dev->xy_cur, sizeof(dev->xy_old));
 		goto exit;
 	}
 
 	for (i = 0; i < ATP_XSENSORS + ATP_YSENSORS; i++) {
-		/* accumulate the change */
-		signed char change = dev->xy_old[i] - dev->xy_cur[i];
-		dev->xy_acc[i] -= change;
+		/* calculate the change */
+		dev->xy_acc[i] = dev->xy_cur[i] - dev->xy_old[i];
+
+		/* this is a round-robin value, so couple with that */
+		if (dev->xy_acc[i] > 127)
+			dev->xy_acc[i] -= 256;
+
+		if (dev->xy_acc[i] < -127)
+			dev->xy_acc[i] += 256;
 
 		/* prevent down drifting */
 		if (dev->xy_acc[i] < 0)
 			dev->xy_acc[i] = 0;
 	}
 
-	memcpy(dev->xy_old, dev->xy_cur, sizeof(dev->xy_old));
-
 	dbg_dump("accumulator", dev->xy_acc);
 
 	x = atp_calculate_abs(dev->xy_acc, ATP_XSENSORS,
 			      ATP_XFACT, &x_z, &x_f);
 	y = atp_calculate_abs(dev->xy_acc + ATP_XSENSORS, ATP_YSENSORS,
 			      ATP_YFACT, &y_z, &y_f);
-	key = dev->data[dev->datalen - 1] & 1;
+	key = dev->data[dev->datalen - 1] & ATP_STATUS_BUTTON;
 
 	if (x && y) {
 		if (dev->x_old != -1) {
@@ -646,7 +665,8 @@ static void atp_complete_geyser_3_4(stru
 	if (!x && !y && !key) {
 		dev->idlecount++;
 		if (dev->idlecount == 10) {
-			dev->valid = false;
+			dev->x_old = dev->y_old = -1;
+			dev->idlecount = 0;
 			schedule_work(&dev->work);
 			/* Don't resubmit urb here, wait for reinit */
 			return;
@@ -878,8 +898,6 @@ static int atp_suspend(struct usb_interf
 	struct atp *dev = usb_get_intfdata(iface);
 
 	usb_kill_urb(dev->urb);
-	dev->valid = false;
-
 	return 0;
 }
 

-- 


^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH 0/2] appletouch updates for geyser 3/4
  2008-07-29 11:11 [PATCH 0/2] appletouch updates for geyser 3/4 Johannes Berg
  2008-07-29 11:11 ` [PATCH 1/2] appletouch: prepare for geyser 3/4 handling Johannes Berg
  2008-07-29 11:11 ` [PATCH 2/2] appletouch: handle geyser 3/4 status bits Johannes Berg
@ 2008-10-08  8:18 ` Johannes Berg
  2008-10-08 12:48   ` Dmitry Torokhov
  2 siblings, 1 reply; 5+ messages in thread
From: Johannes Berg @ 2008-10-08  8:18 UTC (permalink / raw)
  To: Dmitry Torokhov; +Cc: linux-input, Sven Anders

[-- Attachment #1: Type: text/plain, Size: 265 bytes --]

On Tue, 2008-07-29 at 13:18 +0200, Johannes Berg wrote:
> Not much to say here, works fine on older models and Sven says
> it works on new models.

Dmitry,

Sven says this patch series is nowhere to be found in git, any reason?
Did you miss it?

johannes

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH 0/2] appletouch updates for geyser 3/4
  2008-10-08  8:18 ` [PATCH 0/2] appletouch updates for geyser 3/4 Johannes Berg
@ 2008-10-08 12:48   ` Dmitry Torokhov
  0 siblings, 0 replies; 5+ messages in thread
From: Dmitry Torokhov @ 2008-10-08 12:48 UTC (permalink / raw)
  To: Johannes Berg; +Cc: linux-input, Sven Anders

On Wed, Oct 08, 2008 at 10:18:16AM +0200, Johannes Berg wrote:
> On Tue, 2008-07-29 at 13:18 +0200, Johannes Berg wrote:
> > Not much to say here, works fine on older models and Sven says
> > it works on new models.
> 
> Dmitry,
> 
> Sven says this patch series is nowhere to be found in git, any reason?
> Did you miss it?
> 

Johannes,

I believe it is in my 'next' branch of the input tree, commits:

d83d213d9fda671dfd84ea81182742f9e329a6b4
82a196f481661170b4982dc7e68a12e9253309d0

-- 
Dmitry

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2008-10-08 12:48 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2008-07-29 11:11 [PATCH 0/2] appletouch updates for geyser 3/4 Johannes Berg
2008-07-29 11:11 ` [PATCH 1/2] appletouch: prepare for geyser 3/4 handling Johannes Berg
2008-07-29 11:11 ` [PATCH 2/2] appletouch: handle geyser 3/4 status bits Johannes Berg
2008-10-08  8:18 ` [PATCH 0/2] appletouch updates for geyser 3/4 Johannes Berg
2008-10-08 12:48   ` Dmitry Torokhov

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).