diff options
Diffstat (limited to 'sys-kernel/mactel-linux-sources/files/mactel-patches-r140/appletouch-shut-up-when-it-has-nothing-to-say.patch')
-rw-r--r-- | sys-kernel/mactel-linux-sources/files/mactel-patches-r140/appletouch-shut-up-when-it-has-nothing-to-say.patch | 202 |
1 files changed, 202 insertions, 0 deletions
diff --git a/sys-kernel/mactel-linux-sources/files/mactel-patches-r140/appletouch-shut-up-when-it-has-nothing-to-say.patch b/sys-kernel/mactel-linux-sources/files/mactel-patches-r140/appletouch-shut-up-when-it-has-nothing-to-say.patch new file mode 100644 index 0000000..7faa546 --- /dev/null +++ b/sys-kernel/mactel-linux-sources/files/mactel-patches-r140/appletouch-shut-up-when-it-has-nothing-to-say.patch @@ -0,0 +1,202 @@ +The attached minimally intrusive patch is based on Matthew Garret's + +From: Soeren Sonnenburg <kernel@nn7.de> + +patch 'Make appletouch shut up when it has nothing to say' patches (e.g. +http://lkml.org/lkml/2007/5/13/117): Matthews description follows / +second paragraph lists my additional changes. + +The appletouch geyser3 devices found in the Intel Macs (and possibly some later +PPC ones?) send a constant stream of packets after the first touch. This +results in the kernel waking up around once every couple of milliseconds +to process them, making it almost impossible to spend any significant +period of time in C3 state on a dynamic HZ kernel. Sending the mode +initialization code makes the device shut up until it's touched again. +This patch does so after receiving 10 packets with no interesting +content. + +In addition it now empties the work queue via cancel_work_sync on module +exit, keeps all error checking and only reports BTN_LEFT presses if bit +1 in the status byte (last byte in packet) is set. This fixes the random +left clicks issue. Furthermore it invalidates touchpad data before the +mode switch, which fixes the touchpad runs amok issue. + +Credits: +Sven Anders found out that one should only check for bit 1 for BTN_LEFT. +Matthew Garrett did the initial 'Make appletouch shut up when it has +nothing to say' so I am adding him to the signed-off lines (hope that is +the correct way). + +Patch follows inline and attached. + +Soeren. + +Signed-off-by: Soeren Sonnenburg <kernel@nn7.de> +Signed-off-by: Matthew Garrett <mjg59@srcf.ucam.org> +--- + + drivers/input/mouse/appletouch.c | 112 ++++++++++++++++++++++++++------------ + 1 files changed, 77 insertions(+), 35 deletions(-) + +diff --git a/drivers/input/mouse/appletouch.c b/drivers/input/mouse/appletouch.c +index c26af96..22182a7 100644 +--- a/drivers/input/mouse/appletouch.c ++++ b/drivers/input/mouse/appletouch.c +@@ -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,63 @@ 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) + { +@@ -449,11 +508,21 @@ static void atp_complete(struct urb* urb) + + /* 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) { ++ dev->valid=0; ++ schedule_work (&dev->work); ++ } ++ } ++ } + ++ input_report_key(dev->input, BTN_LEFT, dev->data[dev->datalen-1] & 1); + input_sync(dev->input); + + exit: +@@ -480,6 +549,7 @@ static void atp_close(struct input_dev *input) + struct atp *dev = input_get_drvdata(input); + + usb_kill_urb(dev->urb); ++ cancel_work_sync(&dev->work); + dev->open = 0; + } + +@@ -528,40 +598,10 @@ 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"); + } + +@@ -636,6 +676,8 @@ static int atp_probe(struct usb_interface *iface, const struct usb_device_id *id + /* save our data pointer in this interface device */ + usb_set_intfdata(iface, dev); + ++ INIT_WORK(&dev->work, atp_reinit); ++ + return 0; + + err_free_buffer: |