Input: appletouch - driver refactoring

The appletouch driver has grown up from supporting only a couple of
touchpads into supporting many touchpads, which can have different
number of sensors, different aspect ratios etc.

This patch cleans up the current driver code and makes it easy to
support the features of each different touchpad.

As a side effect, this patch also modifies the 'Y' multiplication factor
of the 'geyser3' and 'geyser4' touchpads (found on Core Duo and Core2
Duo MacBook and MacBook Pro laptops) in order to make the touchpad
output match the aspect ratio of the touchpad (Y factor changed from 43
to 64).

[dtor@mail.ru: make atp_info constant]
Signed-off-by: Stelian Pop <stelian@popies.net>
Acked-by: Johannes Berg <johannes@sipsolutions.net>
Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
This commit is contained in:
Stelian Pop 2008-10-28 23:20:46 -04:00 committed by Dmitry Torokhov
parent b67b4b1177
commit 09779678d1

View file

@ -3,7 +3,7 @@
* *
* Copyright (C) 2001-2004 Greg Kroah-Hartman (greg@kroah.com) * Copyright (C) 2001-2004 Greg Kroah-Hartman (greg@kroah.com)
* Copyright (C) 2005-2008 Johannes Berg (johannes@sipsolutions.net) * Copyright (C) 2005-2008 Johannes Berg (johannes@sipsolutions.net)
* Copyright (C) 2005 Stelian Pop (stelian@popies.net) * Copyright (C) 2005-2008 Stelian Pop (stelian@popies.net)
* Copyright (C) 2005 Frank Arnold (frank@scirocco-5v-turbo.de) * Copyright (C) 2005 Frank Arnold (frank@scirocco-5v-turbo.de)
* Copyright (C) 2005 Peter Osterlund (petero2@telia.com) * Copyright (C) 2005 Peter Osterlund (petero2@telia.com)
* Copyright (C) 2005 Michael Hanselmann (linux-kernel@hansmi.ch) * Copyright (C) 2005 Michael Hanselmann (linux-kernel@hansmi.ch)
@ -35,16 +35,74 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/usb/input.h> #include <linux/usb/input.h>
/* Type of touchpad */ /*
enum atp_touchpad_type { * Note: We try to keep the touchpad aspect ratio while still doing only
ATP_FOUNTAIN, * simple arithmetics:
ATP_GEYSER1, * 0 <= x <= (xsensors - 1) * xfact
ATP_GEYSER2, * 0 <= y <= (ysensors - 1) * yfact
ATP_GEYSER3, */
ATP_GEYSER4 struct atp_info {
int xsensors; /* number of X sensors */
int xsensors_17; /* 17" models have more sensors */
int ysensors; /* number of Y sensors */
int xfact; /* X multiplication factor */
int yfact; /* Y multiplication factor */
int datalen; /* size of USB transfers */
void (*callback)(struct urb *); /* callback function */
}; };
#define ATP_DEVICE(prod, type) \ static void atp_complete_geyser_1_2(struct urb *urb);
static void atp_complete_geyser_3_4(struct urb *urb);
static const struct atp_info fountain_info = {
.xsensors = 16,
.xsensors_17 = 26,
.ysensors = 16,
.xfact = 64,
.yfact = 43,
.datalen = 81,
.callback = atp_complete_geyser_1_2,
};
static const struct atp_info geyser1_info = {
.xsensors = 16,
.xsensors_17 = 26,
.ysensors = 16,
.xfact = 64,
.yfact = 43,
.datalen = 81,
.callback = atp_complete_geyser_1_2,
};
static const struct atp_info geyser2_info = {
.xsensors = 15,
.xsensors_17 = 20,
.ysensors = 9,
.xfact = 64,
.yfact = 43,
.datalen = 64,
.callback = atp_complete_geyser_1_2,
};
static const struct atp_info geyser3_info = {
.xsensors = 20,
.ysensors = 10,
.xfact = 64,
.yfact = 64,
.datalen = 64,
.callback = atp_complete_geyser_3_4,
};
static const struct atp_info geyser4_info = {
.xsensors = 20,
.ysensors = 10,
.xfact = 64,
.yfact = 64,
.datalen = 64,
.callback = atp_complete_geyser_3_4,
};
#define ATP_DEVICE(prod, info) \
{ \ { \
.match_flags = USB_DEVICE_ID_MATCH_DEVICE | \ .match_flags = USB_DEVICE_ID_MATCH_DEVICE | \
USB_DEVICE_ID_MATCH_INT_CLASS | \ USB_DEVICE_ID_MATCH_INT_CLASS | \
@ -53,7 +111,7 @@ enum atp_touchpad_type {
.idProduct = (prod), \ .idProduct = (prod), \
.bInterfaceClass = 0x03, \ .bInterfaceClass = 0x03, \
.bInterfaceProtocol = 0x02, \ .bInterfaceProtocol = 0x02, \
.driver_info = ATP_ ## type, \ .driver_info = (unsigned long) &info, \
} }
/* /*
@ -62,43 +120,39 @@ enum atp_touchpad_type {
* According to Info.plist Geyser IV is the same as Geyser III.) * According to Info.plist Geyser IV is the same as Geyser III.)
*/ */
static struct usb_device_id atp_table [] = { static struct usb_device_id atp_table[] = {
/* PowerBooks Feb 2005, iBooks G4 */ /* PowerBooks Feb 2005, iBooks G4 */
ATP_DEVICE(0x020e, FOUNTAIN), /* FOUNTAIN ANSI */ ATP_DEVICE(0x020e, fountain_info), /* FOUNTAIN ANSI */
ATP_DEVICE(0x020f, FOUNTAIN), /* FOUNTAIN ISO */ ATP_DEVICE(0x020f, fountain_info), /* FOUNTAIN ISO */
ATP_DEVICE(0x030a, FOUNTAIN), /* FOUNTAIN TP ONLY */ ATP_DEVICE(0x030a, fountain_info), /* FOUNTAIN TP ONLY */
ATP_DEVICE(0x030b, GEYSER1), /* GEYSER 1 TP ONLY */ ATP_DEVICE(0x030b, geyser1_info), /* GEYSER 1 TP ONLY */
/* PowerBooks Oct 2005 */ /* PowerBooks Oct 2005 */
ATP_DEVICE(0x0214, GEYSER2), /* GEYSER 2 ANSI */ ATP_DEVICE(0x0214, geyser2_info), /* GEYSER 2 ANSI */
ATP_DEVICE(0x0215, GEYSER2), /* GEYSER 2 ISO */ ATP_DEVICE(0x0215, geyser2_info), /* GEYSER 2 ISO */
ATP_DEVICE(0x0216, GEYSER2), /* GEYSER 2 JIS */ ATP_DEVICE(0x0216, geyser2_info), /* GEYSER 2 JIS */
/* Core Duo MacBook & MacBook Pro */ /* Core Duo MacBook & MacBook Pro */
ATP_DEVICE(0x0217, GEYSER3), /* GEYSER 3 ANSI */ ATP_DEVICE(0x0217, geyser3_info), /* GEYSER 3 ANSI */
ATP_DEVICE(0x0218, GEYSER3), /* GEYSER 3 ISO */ ATP_DEVICE(0x0218, geyser3_info), /* GEYSER 3 ISO */
ATP_DEVICE(0x0219, GEYSER3), /* GEYSER 3 JIS */ ATP_DEVICE(0x0219, geyser3_info), /* GEYSER 3 JIS */
/* Core2 Duo MacBook & MacBook Pro */ /* Core2 Duo MacBook & MacBook Pro */
ATP_DEVICE(0x021a, GEYSER4), /* GEYSER 4 ANSI */ ATP_DEVICE(0x021a, geyser4_info), /* GEYSER 4 ANSI */
ATP_DEVICE(0x021b, GEYSER4), /* GEYSER 4 ISO */ ATP_DEVICE(0x021b, geyser4_info), /* GEYSER 4 ISO */
ATP_DEVICE(0x021c, GEYSER4), /* GEYSER 4 JIS */ ATP_DEVICE(0x021c, geyser4_info), /* GEYSER 4 JIS */
/* Core2 Duo MacBook3,1 */ /* Core2 Duo MacBook3,1 */
ATP_DEVICE(0x0229, GEYSER4), /* GEYSER 4 HF ANSI */ ATP_DEVICE(0x0229, geyser4_info), /* GEYSER 4 HF ANSI */
ATP_DEVICE(0x022a, GEYSER4), /* GEYSER 4 HF ISO */ ATP_DEVICE(0x022a, geyser4_info), /* GEYSER 4 HF ISO */
ATP_DEVICE(0x022b, GEYSER4), /* GEYSER 4 HF JIS */ ATP_DEVICE(0x022b, geyser4_info), /* GEYSER 4 HF JIS */
/* Terminating entry */ /* Terminating entry */
{ } { }
}; };
MODULE_DEVICE_TABLE(usb, atp_table); MODULE_DEVICE_TABLE(usb, atp_table);
/* /* maximum number of sensors */
* number of sensors. Note that only 16 instead of 26 X (horizontal)
* sensors exist on 12" and 15" PowerBooks. All models have 16 Y
* (vertical) sensors.
*/
#define ATP_XSENSORS 26 #define ATP_XSENSORS 26
#define ATP_YSENSORS 16 #define ATP_YSENSORS 16
@ -107,21 +161,6 @@ MODULE_DEVICE_TABLE(usb, atp_table);
/* maximum pressure this driver will report */ /* maximum pressure this driver will report */
#define ATP_PRESSURE 300 #define ATP_PRESSURE 300
/*
* multiplication factor for the X and Y coordinates.
* We try to keep the touchpad aspect ratio while still doing only simple
* arithmetics.
* The factors below give coordinates like:
*
* 0 <= x < 960 on 12" and 15" Powerbooks
* 0 <= x < 1600 on 17" Powerbooks and 17" MacBook Pro
* 0 <= x < 1216 on MacBooks and 15" MacBook Pro
*
* 0 <= y < 646 on all Powerbooks
* 0 <= y < 774 on all MacBooks
*/
#define ATP_XFACT 64
#define ATP_YFACT 43
/* /*
* Threshold for the touchpad sensors. Any change less than ATP_THRESHOLD is * Threshold for the touchpad sensors. Any change less than ATP_THRESHOLD is
@ -159,7 +198,7 @@ struct atp {
struct urb *urb; /* usb request block */ struct urb *urb; /* usb request block */
u8 *data; /* transferred data */ u8 *data; /* transferred data */
struct input_dev *input; /* input dev */ struct input_dev *input; /* input dev */
enum atp_touchpad_type type; /* type of touchpad */ const struct atp_info *info; /* touchpad model */
bool open; bool open;
bool valid; /* are the samples valid? */ bool valid; /* are the samples valid? */
bool size_detect_done; bool size_detect_done;
@ -169,7 +208,6 @@ struct atp {
signed char xy_cur[ATP_XSENSORS + ATP_YSENSORS]; signed char xy_cur[ATP_XSENSORS + ATP_YSENSORS];
signed char xy_old[ATP_XSENSORS + ATP_YSENSORS]; signed char xy_old[ATP_XSENSORS + ATP_YSENSORS];
int xy_acc[ATP_XSENSORS + ATP_YSENSORS]; int xy_acc[ATP_XSENSORS + ATP_YSENSORS];
int datalen; /* size of USB transfer */
int idlecount; /* number of empty packets */ int idlecount; /* number of empty packets */
struct work_struct work; struct work_struct work;
}; };
@ -359,7 +397,7 @@ static int atp_status_check(struct urb *urb)
if (!dev->overflow_warned) { if (!dev->overflow_warned) {
printk(KERN_WARNING "appletouch: OVERFLOW with data " printk(KERN_WARNING "appletouch: OVERFLOW with data "
"length %d, actual length is %d\n", "length %d, actual length is %d\n",
dev->datalen, dev->urb->actual_length); dev->info->datalen, dev->urb->actual_length);
dev->overflow_warned = true; dev->overflow_warned = true;
} }
case -ECONNRESET: case -ECONNRESET:
@ -377,7 +415,7 @@ static int atp_status_check(struct urb *urb)
} }
/* drop incomplete datasets */ /* drop incomplete datasets */
if (dev->urb->actual_length != dev->datalen) { if (dev->urb->actual_length != dev->info->datalen) {
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);
@ -387,6 +425,25 @@ static int atp_status_check(struct urb *urb)
return ATP_URB_STATUS_SUCCESS; return ATP_URB_STATUS_SUCCESS;
} }
static void atp_detect_size(struct atp *dev)
{
int i;
/* 17" Powerbooks have extra X sensors */
for (i = dev->info->xsensors; i < ATP_XSENSORS; i++) {
if (dev->xy_cur[i]) {
printk(KERN_INFO "appletouch: 17\" model detected.\n");
input_set_abs_params(dev->input, ABS_X, 0,
(dev->info->xsensors_17 - 1) *
dev->info->xfact - 1,
ATP_FUZZ, 0);
break;
}
}
}
/* /*
* USB interrupt callback functions * USB interrupt callback functions
*/ */
@ -407,7 +464,7 @@ static void atp_complete_geyser_1_2(struct urb *urb)
goto exit; goto exit;
/* reorder the sensors values */ /* reorder the sensors values */
if (dev->type == ATP_GEYSER2) { if (dev->info == &geyser2_info) {
memset(dev->xy_cur, 0, sizeof(dev->xy_cur)); memset(dev->xy_cur, 0, sizeof(dev->xy_cur));
/* /*
@ -437,8 +494,8 @@ static void atp_complete_geyser_1_2(struct urb *urb)
dev->xy_cur[i + 24] = dev->data[5 * i + 44]; dev->xy_cur[i + 24] = dev->data[5 * i + 44];
/* Y values */ /* Y values */
dev->xy_cur[i + 26] = dev->data[5 * i + 1]; dev->xy_cur[ATP_XSENSORS + i] = dev->data[5 * i + 1];
dev->xy_cur[i + 34] = dev->data[5 * i + 3]; dev->xy_cur[ATP_XSENSORS + i + 8] = dev->data[5 * i + 3];
} }
} }
@ -453,32 +510,8 @@ static void atp_complete_geyser_1_2(struct urb *urb)
memcpy(dev->xy_old, dev->xy_cur, sizeof(dev->xy_old)); memcpy(dev->xy_old, dev->xy_cur, sizeof(dev->xy_old));
/* Perform size detection, if not done already */ /* Perform size detection, if not done already */
if (!dev->size_detect_done) { if (unlikely(!dev->size_detect_done)) {
atp_detect_size(dev);
/* 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; dev->size_detect_done = 1;
goto exit; goto exit;
} }
@ -499,10 +532,10 @@ static void atp_complete_geyser_1_2(struct urb *urb)
dbg_dump("accumulator", dev->xy_acc); dbg_dump("accumulator", dev->xy_acc);
x = atp_calculate_abs(dev->xy_acc, ATP_XSENSORS, x = atp_calculate_abs(dev->xy_acc, ATP_XSENSORS,
ATP_XFACT, &x_z, &x_f); dev->info->xfact, &x_z, &x_f);
y = atp_calculate_abs(dev->xy_acc + ATP_XSENSORS, ATP_YSENSORS, y = atp_calculate_abs(dev->xy_acc + ATP_XSENSORS, ATP_YSENSORS,
ATP_YFACT, &y_z, &y_f); dev->info->yfact, &y_z, &y_f);
key = dev->data[dev->datalen - 1] & ATP_STATUS_BUTTON; key = dev->data[dev->info->datalen - 1] & ATP_STATUS_BUTTON;
if (x && y) { if (x && y) {
if (dev->x_old != -1) { if (dev->x_old != -1) {
@ -583,7 +616,7 @@ static void atp_complete_geyser_3_4(struct urb *urb)
dbg_dump("sample", dev->xy_cur); dbg_dump("sample", dev->xy_cur);
/* Just update the base values (i.e. touchpad in untouched state) */ /* Just update the base values (i.e. touchpad in untouched state) */
if (dev->data[dev->datalen - 1] & ATP_STATUS_BASE_UPDATE) { if (dev->data[dev->info->datalen - 1] & ATP_STATUS_BASE_UPDATE) {
dprintk(KERN_DEBUG "appletouch: updated base values\n"); dprintk(KERN_DEBUG "appletouch: updated base values\n");
@ -610,10 +643,10 @@ static void atp_complete_geyser_3_4(struct urb *urb)
dbg_dump("accumulator", dev->xy_acc); dbg_dump("accumulator", dev->xy_acc);
x = atp_calculate_abs(dev->xy_acc, ATP_XSENSORS, x = atp_calculate_abs(dev->xy_acc, ATP_XSENSORS,
ATP_XFACT, &x_z, &x_f); dev->info->xfact, &x_z, &x_f);
y = atp_calculate_abs(dev->xy_acc + ATP_XSENSORS, ATP_YSENSORS, y = atp_calculate_abs(dev->xy_acc + ATP_XSENSORS, ATP_YSENSORS,
ATP_YFACT, &y_z, &y_f); dev->info->yfact, &y_z, &y_f);
key = dev->data[dev->datalen - 1] & ATP_STATUS_BUTTON; key = dev->data[dev->info->datalen - 1] & ATP_STATUS_BUTTON;
if (x && y) { if (x && y) {
if (dev->x_old != -1) { if (dev->x_old != -1) {
@ -705,7 +738,7 @@ static int atp_handle_geyser(struct atp *dev)
{ {
struct usb_device *udev = dev->udev; struct usb_device *udev = dev->udev;
if (dev->type != ATP_FOUNTAIN) { if (dev->info != &fountain_info) {
/* switch to raw sensor mode */ /* switch to raw sensor mode */
if (atp_geyser_init(udev)) if (atp_geyser_init(udev))
return -EIO; return -EIO;
@ -726,6 +759,7 @@ static int atp_probe(struct usb_interface *iface,
struct usb_endpoint_descriptor *endpoint; struct usb_endpoint_descriptor *endpoint;
int int_in_endpointAddr = 0; int int_in_endpointAddr = 0;
int i, error = -ENOMEM; int i, error = -ENOMEM;
const struct atp_info *info = (const struct atp_info *)id->driver_info;
/* set up the endpoint information */ /* set up the endpoint information */
/* use only the first interrupt-in endpoint */ /* use only the first interrupt-in endpoint */
@ -753,35 +787,22 @@ static int atp_probe(struct usb_interface *iface,
dev->udev = udev; dev->udev = udev;
dev->input = input_dev; dev->input = input_dev;
dev->type = id->driver_info; dev->info = info;
dev->overflow_warned = false; dev->overflow_warned = false;
if (dev->type == ATP_FOUNTAIN || dev->type == ATP_GEYSER1)
dev->datalen = 81;
else
dev->datalen = 64;
dev->urb = usb_alloc_urb(0, GFP_KERNEL); dev->urb = usb_alloc_urb(0, GFP_KERNEL);
if (!dev->urb) if (!dev->urb)
goto err_free_devs; goto err_free_devs;
dev->data = usb_buffer_alloc(dev->udev, dev->datalen, GFP_KERNEL, dev->data = usb_buffer_alloc(dev->udev, dev->info->datalen, GFP_KERNEL,
&dev->urb->transfer_dma); &dev->urb->transfer_dma);
if (!dev->data) if (!dev->data)
goto err_free_urb; goto err_free_urb;
/* Select the USB complete (callback) function */ usb_fill_int_urb(dev->urb, udev,
if (dev->type == ATP_FOUNTAIN || usb_rcvintpipe(udev, int_in_endpointAddr),
dev->type == ATP_GEYSER1 || dev->data, dev->info->datalen,
dev->type == ATP_GEYSER2) dev->info->callback, dev, 1);
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)
@ -802,35 +823,12 @@ static int atp_probe(struct usb_interface *iface,
set_bit(EV_ABS, input_dev->evbit); set_bit(EV_ABS, input_dev->evbit);
if (dev->type == ATP_GEYSER3 || dev->type == ATP_GEYSER4) { input_set_abs_params(input_dev, ABS_X, 0,
/* (dev->info->xsensors - 1) * dev->info->xfact - 1,
* MacBook have 20 X sensors, 10 Y sensors ATP_FUZZ, 0);
*/ input_set_abs_params(input_dev, ABS_Y, 0,
input_set_abs_params(input_dev, ABS_X, 0, (dev->info->ysensors - 1) * dev->info->yfact - 1,
((20 - 1) * ATP_XFACT) - 1, ATP_FUZZ, 0); ATP_FUZZ, 0);
input_set_abs_params(input_dev, ABS_Y, 0,
((10 - 1) * ATP_YFACT) - 1, ATP_FUZZ, 0);
} else if (dev->type == ATP_GEYSER2) {
/*
* Oct 2005 15" PowerBooks have 15 X sensors, 17" are detected
* later.
*/
input_set_abs_params(input_dev, ABS_X, 0,
((15 - 1) * ATP_XFACT) - 1, ATP_FUZZ, 0);
input_set_abs_params(input_dev, ABS_Y, 0,
((9 - 1) * ATP_YFACT) - 1, ATP_FUZZ, 0);
} else {
/*
* 12" and 15" Powerbooks only have 16 x sensors,
* 17" models are detected later.
*/
input_set_abs_params(input_dev, ABS_X, 0,
(16 - 1) * ATP_XFACT - 1,
ATP_FUZZ, 0);
input_set_abs_params(input_dev, ABS_Y, 0,
(ATP_YSENSORS - 1) * ATP_YFACT - 1,
ATP_FUZZ, 0);
}
input_set_abs_params(input_dev, ABS_PRESSURE, 0, ATP_PRESSURE, 0, 0); input_set_abs_params(input_dev, ABS_PRESSURE, 0, ATP_PRESSURE, 0, 0);
set_bit(EV_KEY, input_dev->evbit); set_bit(EV_KEY, input_dev->evbit);
@ -852,7 +850,7 @@ static int atp_probe(struct usb_interface *iface,
return 0; return 0;
err_free_buffer: err_free_buffer:
usb_buffer_free(dev->udev, dev->datalen, usb_buffer_free(dev->udev, dev->info->datalen,
dev->data, dev->urb->transfer_dma); dev->data, dev->urb->transfer_dma);
err_free_urb: err_free_urb:
usb_free_urb(dev->urb); usb_free_urb(dev->urb);
@ -871,7 +869,7 @@ static void atp_disconnect(struct usb_interface *iface)
if (dev) { if (dev) {
usb_kill_urb(dev->urb); usb_kill_urb(dev->urb);
input_unregister_device(dev->input); input_unregister_device(dev->input);
usb_buffer_free(dev->udev, dev->datalen, usb_buffer_free(dev->udev, dev->info->datalen,
dev->data, dev->urb->transfer_dma); dev->data, dev->urb->transfer_dma);
usb_free_urb(dev->urb); usb_free_urb(dev->urb);
kfree(dev); kfree(dev);