Commit d83d213d authored by Sven Anders's avatar Sven Anders Committed by Dmitry Torokhov

Input: appletouch - prepare for geyser 3/4 handling

Split complete function into separate functions for GEYSER1/2 and GEYSER 3/4.
Signed-off-by: default avatarSven Anders <anders@anduras.de>
Signed-off-by: default avatarJohannes Berg <johannes@sipsolutions.net>
Signed-off-by: default avatarDmitry Torokhov <dtor@mail.ru>
parent ce25d7e9
...@@ -327,11 +327,14 @@ static inline void atp_report_fingers(struct input_dev *input, int fingers) ...@@ -327,11 +327,14 @@ static inline void atp_report_fingers(struct input_dev *input, int fingers)
input_report_key(input, BTN_TOOL_TRIPLETAP, fingers > 2); 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; struct atp *dev = urb->context;
switch (urb->status) { switch (urb->status) {
...@@ -351,11 +354,12 @@ static void atp_complete(struct urb *urb) ...@@ -351,11 +354,12 @@ static void atp_complete(struct urb *urb)
/* This urb is terminated, clean up */ /* This urb is terminated, clean up */
dbg("atp_complete: urb shutting down with status: %d", dbg("atp_complete: urb shutting down with status: %d",
urb->status); urb->status);
return; return ATP_URB_STATUS_ERROR_FATAL;
default: default:
dbg("atp_complete: nonzero urb status received: %d", dbg("atp_complete: nonzero urb status received: %d",
urb->status); urb->status);
goto exit; return ATP_URB_STATUS_ERROR;
} }
/* drop incomplete datasets */ /* drop incomplete datasets */
...@@ -363,30 +367,33 @@ static void atp_complete(struct urb *urb) ...@@ -363,30 +367,33 @@ static void atp_complete(struct urb *urb)
dprintk("appletouch: incomplete data package" dprintk("appletouch: incomplete data package"
" (first byte: %d, length: %d).\n", " (first byte: %d, length: %d).\n",
dev->data[0], dev->urb->actual_length); dev->data[0], dev->urb->actual_length);
goto exit; return ATP_URB_STATUS_ERROR;
} }
/* reorder the sensors values */ return ATP_URB_STATUS_SUCCESS;
if (dev->type == ATP_GEYSER3 || dev->type == ATP_GEYSER4) { }
memset(dev->xy_cur, 0, sizeof(dev->xy_cur));
/* /*
* The values are laid out like this: * USB interrupt callback functions
* -, Y1, Y2, -, Y3, Y4, -, ..., -, X1, X2, -, X3, X4, ... */
* '-' is an unused value.
*/
/* read X values */ /* Interrupt function for older touchpads: FOUNTAIN/GEYSER1/GEYSER2 */
for (i = 0, j = 19; i < 20; i += 2, j += 3) {
dev->xy_cur[i] = dev->data[j + 1]; static void atp_complete_geyser_1_2(struct urb *urb)
dev->xy_cur[i + 1] = dev->data[j + 2]; {
} int x, y, x_z, y_z, x_f, y_f;
/* read Y values */ int retval, i, j;
for (i = 0, j = 1; i < 9; i += 2, j += 3) { int key;
dev->xy_cur[ATP_XSENSORS + i] = dev->data[j + 1]; struct atp *dev = urb->context;
dev->xy_cur[ATP_XSENSORS + i + 1] = dev->data[j + 2]; int status = atp_status_check(urb);
}
} else if (dev->type == ATP_GEYSER2) { 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)); memset(dev->xy_cur, 0, sizeof(dev->xy_cur));
/* /*
...@@ -427,33 +434,146 @@ static void atp_complete(struct urb *urb) ...@@ -427,33 +434,146 @@ static void atp_complete(struct urb *urb)
/* first sample */ /* first sample */
dev->valid = true; dev->valid = true;
dev->x_old = dev->y_old = -1; dev->x_old = dev->y_old = -1;
/* Store first sample */
memcpy(dev->xy_old, dev->xy_cur, sizeof(dev->xy_old)); memcpy(dev->xy_old, dev->xy_cur, sizeof(dev->xy_old));
if (dev->size_detect_done || /* Perform size detection, if not done already */
dev->type == ATP_GEYSER3) /* No 17" Macbooks (yet) */ 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; goto exit;
}
}
/* 17" Powerbooks have extra X sensors */ for (i = 0; i < ATP_XSENSORS + ATP_YSENSORS; i++) {
for (i = (dev->type == ATP_GEYSER2 ? 15 : 16); /* accumulate the change */
i < ATP_XSENSORS; i++) { signed char change = dev->xy_old[i] - dev->xy_cur[i];
if (!dev->xy_cur[i]) dev->xy_acc[i] -= change;
continue;
/* prevent down drifting */
printk(KERN_INFO "appletouch: 17\" model detected.\n"); if (dev->xy_acc[i] < 0)
if (dev->type == ATP_GEYSER2) dev->xy_acc[i] = 0;
input_set_abs_params(dev->input, ABS_X, 0, }
(20 - 1) *
ATP_XFACT - 1, memcpy(dev->xy_old, dev->xy_cur, sizeof(dev->xy_old));
ATP_FUZZ, 0);
else dbg_dump("accumulator", dev->xy_acc);
input_set_abs_params(dev->input, ABS_X, 0,
(ATP_XSENSORS - 1) * x = atp_calculate_abs(dev->xy_acc, ATP_XSENSORS,
ATP_XFACT - 1, ATP_XFACT, &x_z, &x_f);
ATP_FUZZ, 0); y = atp_calculate_abs(dev->xy_acc + ATP_XSENSORS, ATP_YSENSORS,
break; 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; goto exit;
} }
...@@ -514,28 +634,26 @@ static void atp_complete(struct urb *urb) ...@@ -514,28 +634,26 @@ static void atp_complete(struct urb *urb)
input_sync(dev->input); 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 * the first touch unless reinitialised. Do so if it's been
* idle for a while in order to avoid waking the kernel up * idle for a while in order to avoid waking the kernel up
* several hundred times a second. Re-initialization does not * several hundred times a second.
* work on Fountain touchpads.
*/ */
if (dev->type != ATP_FOUNTAIN) {
/* /*
* Button must not be pressed when entering suspend, * Button must not be pressed when entering suspend,
* otherwise we will never release the button. * otherwise we will never release the button.
*/ */
if (!x && !y && !key) { if (!x && !y && !key) {
dev->idlecount++; dev->idlecount++;
if (dev->idlecount == 10) { if (dev->idlecount == 10) {
dev->valid = false; dev->valid = false;
schedule_work(&dev->work); schedule_work(&dev->work);
/* Don't resubmit urb here, wait for reinit */ /* Don't resubmit urb here, wait for reinit */
return; return;
} }
} else } else
dev->idlecount = 0; dev->idlecount = 0;
}
exit: exit:
retval = usb_submit_urb(dev->urb, GFP_ATOMIC); retval = usb_submit_urb(dev->urb, GFP_ATOMIC);
...@@ -632,9 +750,19 @@ static int atp_probe(struct usb_interface *iface, ...@@ -632,9 +750,19 @@ static int atp_probe(struct usb_interface *iface,
if (!dev->data) if (!dev->data)
goto err_free_urb; goto err_free_urb;
usb_fill_int_urb(dev->urb, udev, /* Select the USB complete (callback) function */
usb_rcvintpipe(udev, int_in_endpointAddr), if (dev->type == ATP_FOUNTAIN ||
dev->data, dev->datalen, atp_complete, dev, 1); 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); error = atp_handle_geyser(dev);
if (error) if (error)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment