/* * Note: We try to keep the touchpad aspect ratio while still doing only * simple arithmetics: * 0 <= x <= (xsensors - 1) * xfact * 0 <= y <= (ysensors - 1) * yfact
*/ 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 */ int fuzz; /* fuzz touchpad generates */
};
/* * Table of devices (Product IDs) that work with this driver. * (The names come from Info.plist in AppleUSBTrackpad.kext, * According to Info.plist Geyser IV is the same as Geyser III.)
*/
staticconststruct usb_device_id atp_table[] = { /* PowerBooks Feb 2005, iBooks G4 */
ATP_DEVICE(0x020e, fountain_info), /* FOUNTAIN ANSI */
ATP_DEVICE(0x020f, fountain_info), /* FOUNTAIN ISO */
ATP_DEVICE(0x030a, fountain_info), /* FOUNTAIN TP ONLY */
ATP_DEVICE(0x030b, geyser1_info), /* GEYSER 1 TP ONLY */
/* PowerBooks Oct 2005 */
ATP_DEVICE(0x0214, geyser2_info), /* GEYSER 2 ANSI */
ATP_DEVICE(0x0215, geyser2_info), /* GEYSER 2 ISO */
ATP_DEVICE(0x0216, geyser2_info), /* GEYSER 2 JIS */
/* Core Duo MacBook & MacBook Pro */
ATP_DEVICE(0x0217, geyser3_info), /* GEYSER 3 ANSI */
ATP_DEVICE(0x0218, geyser3_info), /* GEYSER 3 ISO */
ATP_DEVICE(0x0219, geyser3_info), /* GEYSER 3 JIS */
/* Core2 Duo MacBook & MacBook Pro */
ATP_DEVICE(0x021a, geyser4_info), /* GEYSER 4 ANSI */
ATP_DEVICE(0x021b, geyser4_info), /* GEYSER 4 ISO */
ATP_DEVICE(0x021c, geyser4_info), /* GEYSER 4 JIS */
/* Core2 Duo MacBook3,1 */
ATP_DEVICE(0x0229, geyser4_info), /* GEYSER 4 HF ANSI */
ATP_DEVICE(0x022a, geyser4_info), /* GEYSER 4 HF ISO */
ATP_DEVICE(0x022b, geyser4_info), /* GEYSER 4 HF JIS */
/* maximum number of sensors */ #define ATP_XSENSORS 26 #define ATP_YSENSORS 16
/* * The largest possible bank of sensors with additional buffer of 4 extra values * on either side, for an array of smoothed sensor values.
*/ #define ATP_SMOOTHSIZE 34
/* maximum pressure this driver will report */ #define ATP_PRESSURE 300
/* * Threshold for the touchpad sensors. Any change less than ATP_THRESHOLD is * ignored.
*/ #define ATP_THRESHOLD 5
/* * How far we'll bitshift our sensor values before averaging them. Mitigates * rounding errors.
*/ #define ATP_SCALE 12
/** * 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 usb_interface *intf; /* usb interface */ struct urb *urb; /* usb request block */
u8 *data; /* transferred data */ struct input_dev *input; /* input dev */ conststruct atp_info *info; /* touchpad model */ bool open; bool valid; /* are the samples valid? */ bool size_detect_done; bool overflow_warned; int fingers_old; /* last reported finger count */ int x_old; /* last reported x/y, */ int y_old; /* used for smoothing */ signedchar xy_cur[ATP_XSENSORS + ATP_YSENSORS]; signedchar xy_old[ATP_XSENSORS + ATP_YSENSORS]; int xy_acc[ATP_XSENSORS + ATP_YSENSORS]; int smooth[ATP_SMOOTHSIZE]; int smooth_tmp[ATP_SMOOTHSIZE]; int idlecount; /* number of empty packets */ struct work_struct work;
};
#define dprintk(format, a...) \ do { \ if (debug) \
printk(KERN_DEBUG format, ##a); \
} while (0)
MODULE_AUTHOR("Johannes Berg");
MODULE_AUTHOR("Stelian Pop");
MODULE_AUTHOR("Frank Arnold");
MODULE_AUTHOR("Michael Hanselmann");
MODULE_AUTHOR("Sven Anders");
MODULE_DESCRIPTION("Apple PowerBook and MacBook USB touchpad driver");
MODULE_LICENSE("GPL");
/* * Make the threshold a module parameter
*/ staticint threshold = ATP_THRESHOLD;
module_param(threshold, int, 0644);
MODULE_PARM_DESC(threshold, "Discard any change in data from a sensor" " (the trackpad has many of these sensors)" " less than this value.");
/* * By default newer Geyser devices send standard USB HID mouse * packets (Report ID 2). This code changes device mode, so it * sends raw sensor reports (Report ID 5).
*/ staticint atp_geyser_init(struct atp *dev)
{ struct usb_device *udev = dev->udev; char *data; int size; int i; int ret;
data = kmalloc(8, GFP_KERNEL); if (!data) {
dev_err(&dev->intf->dev, "Out of memory\n"); return -ENOMEM;
}
if (size != 8) {
dprintk("atp_geyser_init: write error\n"); for (i = 0; i < 8; i++)
dprintk("appletouch[%d]: %d\n", i, data[i]);
dev_err(&dev->intf->dev, "Failed to request geyser raw mode\n");
ret = -EIO; goto out_free;
}
ret = 0;
out_free:
kfree(data); return ret;
}
/* * Reinitialise the device. This usually stops stream of empty packets * coming from it.
*/ staticvoid atp_reinit(struct work_struct *work)
{ struct atp *dev = container_of(work, struct atp, work); int retval;
dprintk("appletouch: putting appletouch to sleep (reinit)\n");
atp_geyser_init(dev);
retval = usb_submit_urb(dev->urb, GFP_ATOMIC); if (retval)
dev_err(&dev->intf->dev, "atp_reinit: usb_submit_urb failed with error %d\n",
retval);
}
staticint atp_calculate_abs(struct atp *dev, int offset, int nb_sensors, int fact, int *z, int *fingers)
{ int i, pass;
/* * Use offset to point xy_sensors at the first value in dev->xy_acc * for whichever dimension we're looking at this particular go-round.
*/ int *xy_sensors = dev->xy_acc + offset;
/* 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] < threshold) { if (is_increasing)
is_increasing = 0;
/* * 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 (*fingers < 1) /* No need to continue if no fingers are found. */ return 0;
/* * Use a smoothed version of sensor data for movement calculations, to * combat noise without needing to rely so heavily on a threshold. * This improves tracking. * * The smoothed array is bigger than the original so that the smoothing * doesn't result in edge values being truncated.
*/
memset(dev->smooth, 0, 4 * sizeof(dev->smooth[0])); /* Pull base values, scaled up to help avoid truncation errors. */ for (i = 0; i < nb_sensors; i++)
dev->smooth[i + 4] = xy_sensors[i] << ATP_SCALE;
memset(&dev->smooth[nb_sensors + 4], 0, 4 * sizeof(dev->smooth[0]));
for (i = 0; i < nb_sensors + 8; i++) { /* * Skip values if they're small enough to be truncated to 0 * by scale. Mostly noise.
*/ if ((dev->smooth[i] >> ATP_SCALE) > 0) {
pcum += dev->smooth[i] * i;
psum += dev->smooth[i];
}
}
switch (urb->status) { case 0: /* success */ break; case -EOVERFLOW: if (!dev->overflow_warned) {
dev_warn(&intf->dev, "appletouch: OVERFLOW with data length %d, actual length is %d\n",
dev->info->datalen, dev->urb->actual_length);
dev->overflow_warned = true;
}
fallthrough; case -ECONNRESET: case -ENOENT: case -ESHUTDOWN: /* This urb is terminated, clean up */
dev_dbg(&intf->dev, "atp_complete: urb shutting down with status: %d\n",
urb->status); return ATP_URB_STATUS_ERROR_FATAL;
/* Interrupt function for older touchpads: FOUNTAIN/GEYSER1/GEYSER2 */
staticvoid 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, fingers; struct atp *dev = urb->context; int status = atp_status_check(urb);
if (status == ATP_URB_STATUS_ERROR_FATAL) return; elseif (status == ATP_URB_STATUS_ERROR) gotoexit;
/* reorder the sensors values */ if (dev->info == &geyser2_info) {
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];
dev->xy_cur[i + 1] = dev->data[j + 1];
}
/* read Y values */ for (i = 0, j = 1; i < 9; i += 2, j += 3) {
dev->xy_cur[ATP_XSENSORS + i] = dev->data[j];
dev->xy_cur[ATP_XSENSORS + i + 1] = dev->data[j + 1];
}
} else { for (i = 0; i < 8; i++) { /* X values */
dev->xy_cur[i + 0] = dev->data[5 * i + 2];
dev->xy_cur[i + 8] = dev->data[5 * i + 4];
dev->xy_cur[i + 16] = dev->data[5 * i + 42]; if (i < 2)
dev->xy_cur[i + 24] = dev->data[5 * i + 44];
/* Y values */
dev->xy_cur[ATP_XSENSORS + i] = dev->data[5 * i + 1];
dev->xy_cur[ATP_XSENSORS + i + 8] = dev->data[5 * i + 3];
}
}
dbg_dump("sample", dev->xy_cur);
if (!dev->valid) { /* 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));
/* Perform size detection, if not done already */ if (unlikely(!dev->size_detect_done)) {
atp_detect_size(dev);
dev->size_detect_done = true; gotoexit;
}
}
for (i = 0; i < ATP_XSENSORS + ATP_YSENSORS; i++) { /* accumulate the change */ signedchar 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;
}
exit:
retval = usb_submit_urb(dev->urb, GFP_ATOMIC); if (retval)
dev_err(&dev->intf->dev, "atp_complete: usb_submit_urb failed with result %d\n",
retval);
}
/* Interrupt function for older touchpads: GEYSER3/GEYSER4 */
staticvoid 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, fingers; struct atp *dev = urb->context; int status = atp_status_check(urb);
if (status == ATP_URB_STATUS_ERROR_FATAL) return; elseif (status == ATP_URB_STATUS_ERROR) gotoexit;
/* 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);
/* Just update the base values (i.e. touchpad in untouched state) */ if (dev->data[dev->info->datalen - 1] & ATP_STATUS_BASE_UPDATE) {
/* * 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.
*/
/* * 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->x_old = dev->y_old = -1;
dev->idlecount = 0;
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); if (retval)
dev_err(&dev->intf->dev, "atp_complete: usb_submit_urb failed with result %d\n",
retval);
}
staticint atp_open(struct input_dev *input)
{ struct atp *dev = input_get_drvdata(input);
if (usb_submit_urb(dev->urb, GFP_KERNEL)) return -EIO;
dev->open = true; return 0;
}
staticvoid atp_close(struct input_dev *input)
{ struct atp *dev = input_get_drvdata(input);
staticint atp_handle_geyser(struct atp *dev)
{ if (dev->info != &fountain_info) { /* switch to raw sensor mode */ if (atp_geyser_init(dev)) return -EIO;
/* set up the endpoint information */ /* use only the first interrupt-in endpoint */
iface_desc = iface->cur_altsetting; for (i = 0; i < iface_desc->desc.bNumEndpoints; i++) {
endpoint = &iface_desc->endpoint[i].desc; if (!int_in_endpointAddr && usb_endpoint_is_int_in(endpoint)) { /* we found an interrupt in endpoint */
int_in_endpointAddr = endpoint->bEndpointAddress; break;
}
} if (!int_in_endpointAddr) {
dev_err(&iface->dev, "Could not find int-in endpoint\n"); return -EIO;
}
/* allocate memory for our device state and initialize it */
dev = kzalloc(sizeof(*dev), GFP_KERNEL);
input_dev = input_allocate_device(); if (!dev || !input_dev) {
dev_err(&iface->dev, "Out of memory\n"); goto err_free_devs;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.