From 97e487b666b787ce7a4aaca102273b90d0e97110 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Thu, 21 Jun 2012 03:35:31 +0000 Subject: [PATCH] input: Add Synaptics USB device driver (Closes: #678071) svn path=/dists/sid/linux/; revision=19178 --- debian/changelog | 1 + debian/config/config | 1 + debian/installer/modules/input-modules | 1 + ...nput-add-Synaptics-USB-device-driver.patch | 683 ++++++++++++++++++ debian/patches/series | 1 + 5 files changed, 687 insertions(+) create mode 100644 debian/patches/features/all/Input-add-Synaptics-USB-device-driver.patch diff --git a/debian/changelog b/debian/changelog index 9f4d70d6b..775187706 100644 --- a/debian/changelog +++ b/debian/changelog @@ -24,6 +24,7 @@ linux (3.2.21-1) UNRELEASED; urgency=low - cpufreq: Add support for x86 cpuinfo auto loading (Closes: #664813) * [x86] ACPI: Load acpi-cpufreq from processor driver automatically * Bump ABI to 3 + * input: Add Synaptics USB device driver (Closes: #678071) [ Aurelien Jarno ] * [mips,mipsel] udeb: Remove rivafb and nvidiafb. diff --git a/debian/config/config b/debian/config/config index 4ef3eef82..2e76052e3 100644 --- a/debian/config/config +++ b/debian/config/config @@ -738,6 +738,7 @@ CONFIG_MOUSE_PS2_SENTELIC=y # CONFIG_MOUSE_PS2_TOUCHKIT is not set # CONFIG_MOUSE_GPIO is not set CONFIG_MOUSE_SYNAPTICS_I2C=m +CONFIG_MOUSE_SYNAPTICS_USB=m ## ## file: drivers/input/serio/Kconfig diff --git a/debian/installer/modules/input-modules b/debian/installer/modules/input-modules index bf17a3011..8f7f9b373 100644 --- a/debian/installer/modules/input-modules +++ b/debian/installer/modules/input-modules @@ -7,4 +7,5 @@ hid-logitech ? hid-monterey ? hid-sunplus ? hid-cherry ? +synaptics_usb ? wistron_btns ? diff --git a/debian/patches/features/all/Input-add-Synaptics-USB-device-driver.patch b/debian/patches/features/all/Input-add-Synaptics-USB-device-driver.patch new file mode 100644 index 000000000..a333f3140 --- /dev/null +++ b/debian/patches/features/all/Input-add-Synaptics-USB-device-driver.patch @@ -0,0 +1,683 @@ +From: Jan Steinhoff +Date: Fri, 3 Feb 2012 00:21:31 -0800 +Subject: Input: add Synaptics USB device driver + +commit 8491ee1093c476ea3a9a19ab8593d8531cab40f7 upstream. + +This patch adds a driver for Synaptics USB touchpad or pointing stick +devices. These USB devices emulate an USB mouse by default, so one can +also use the usbhid driver. However, in combination with special user +space drivers this kernel driver allows one to customize the behaviour +of the device. + +An extended version of this driver with support for the cPad background +display can be found at +. + +Signed-off-by: Jan Steinhoff +Acked-by: Jiri Kosina +Signed-off-by: Dmitry Torokhov +--- + drivers/hid/hid-core.c | 10 + + drivers/hid/hid-ids.h | 11 + + drivers/input/mouse/Kconfig | 17 ++ + drivers/input/mouse/Makefile | 1 + + drivers/input/mouse/synaptics_usb.c | 568 +++++++++++++++++++++++++++++++++++ + 5 files changed, 607 insertions(+) + create mode 100644 drivers/input/mouse/synaptics_usb.c + +diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c +index 848a56c..b639855 100644 +--- a/drivers/hid/hid-core.c ++++ b/drivers/hid/hid-core.c +@@ -1892,6 +1892,16 @@ static const struct hid_device_id hid_ignore_list[] = { + { HID_USB_DEVICE(USB_VENDOR_ID_PANJIT, 0x0004) }, + { HID_USB_DEVICE(USB_VENDOR_ID_PHILIPS, USB_DEVICE_ID_PHILIPS_IEEE802154_DONGLE) }, + { HID_USB_DEVICE(USB_VENDOR_ID_POWERCOM, USB_DEVICE_ID_POWERCOM_UPS) }, ++#if defined(CONFIG_MOUSE_SYNAPTICS_USB) || defined(CONFIG_MOUSE_SYNAPTICS_USB_MODULE) ++ { HID_USB_DEVICE(USB_VENDOR_ID_SYNAPTICS, USB_DEVICE_ID_SYNAPTICS_TP) }, ++ { HID_USB_DEVICE(USB_VENDOR_ID_SYNAPTICS, USB_DEVICE_ID_SYNAPTICS_INT_TP) }, ++ { HID_USB_DEVICE(USB_VENDOR_ID_SYNAPTICS, USB_DEVICE_ID_SYNAPTICS_CPAD) }, ++ { HID_USB_DEVICE(USB_VENDOR_ID_SYNAPTICS, USB_DEVICE_ID_SYNAPTICS_STICK) }, ++ { HID_USB_DEVICE(USB_VENDOR_ID_SYNAPTICS, USB_DEVICE_ID_SYNAPTICS_WP) }, ++ { HID_USB_DEVICE(USB_VENDOR_ID_SYNAPTICS, USB_DEVICE_ID_SYNAPTICS_COMP_TP) }, ++ { HID_USB_DEVICE(USB_VENDOR_ID_SYNAPTICS, USB_DEVICE_ID_SYNAPTICS_WTP) }, ++ { HID_USB_DEVICE(USB_VENDOR_ID_SYNAPTICS, USB_DEVICE_ID_SYNAPTICS_DPAD) }, ++#endif + { HID_USB_DEVICE(USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_LABPRO) }, + { HID_USB_DEVICE(USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_GOTEMP) }, + { HID_USB_DEVICE(USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_SKIP) }, +diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h +index 06ce996..3b68343 100644 +--- a/drivers/hid/hid-ids.h ++++ b/drivers/hid/hid-ids.h +@@ -633,6 +633,17 @@ + #define USB_DEVICE_ID_SYMBOL_SCANNER_1 0x0800 + #define USB_DEVICE_ID_SYMBOL_SCANNER_2 0x1300 + ++#define USB_VENDOR_ID_SYNAPTICS 0x06cb ++#define USB_DEVICE_ID_SYNAPTICS_TP 0x0001 ++#define USB_DEVICE_ID_SYNAPTICS_INT_TP 0x0002 ++#define USB_DEVICE_ID_SYNAPTICS_CPAD 0x0003 ++#define USB_DEVICE_ID_SYNAPTICS_TS 0x0006 ++#define USB_DEVICE_ID_SYNAPTICS_STICK 0x0007 ++#define USB_DEVICE_ID_SYNAPTICS_WP 0x0008 ++#define USB_DEVICE_ID_SYNAPTICS_COMP_TP 0x0009 ++#define USB_DEVICE_ID_SYNAPTICS_WTP 0x0010 ++#define USB_DEVICE_ID_SYNAPTICS_DPAD 0x0013 ++ + #define USB_VENDOR_ID_THRUSTMASTER 0x044f + + #define USB_VENDOR_ID_TOPSEED 0x0766 +diff --git a/drivers/input/mouse/Kconfig b/drivers/input/mouse/Kconfig +index 9c1e6ee..9b8db82 100644 +--- a/drivers/input/mouse/Kconfig ++++ b/drivers/input/mouse/Kconfig +@@ -322,4 +322,21 @@ config MOUSE_SYNAPTICS_I2C + To compile this driver as a module, choose M here: the + module will be called synaptics_i2c. + ++config MOUSE_SYNAPTICS_USB ++ tristate "Synaptics USB device support" ++ depends on USB_ARCH_HAS_HCD ++ select USB ++ help ++ Say Y here if you want to use a Synaptics USB touchpad or pointing ++ stick. ++ ++ While these devices emulate an USB mouse by default and can be used ++ with standard usbhid driver, this driver, together with its X.Org ++ counterpart, allows you to fully utilize capabilities of the device. ++ More information can be found at: ++ ++ ++ To compile this driver as a module, choose M here: the ++ module will be called synaptics_usb. ++ + endif +diff --git a/drivers/input/mouse/Makefile b/drivers/input/mouse/Makefile +index 570c84a4..4718eff 100644 +--- a/drivers/input/mouse/Makefile ++++ b/drivers/input/mouse/Makefile +@@ -18,6 +18,7 @@ obj-$(CONFIG_MOUSE_PXA930_TRKBALL) += pxa930_trkball.o + obj-$(CONFIG_MOUSE_RISCPC) += rpcmouse.o + obj-$(CONFIG_MOUSE_SERIAL) += sermouse.o + obj-$(CONFIG_MOUSE_SYNAPTICS_I2C) += synaptics_i2c.o ++obj-$(CONFIG_MOUSE_SYNAPTICS_USB) += synaptics_usb.o + obj-$(CONFIG_MOUSE_VSXXXAA) += vsxxxaa.o + + psmouse-objs := psmouse-base.o synaptics.o +diff --git a/drivers/input/mouse/synaptics_usb.c b/drivers/input/mouse/synaptics_usb.c +new file mode 100644 +index 0000000..e559a94 +--- /dev/null ++++ b/drivers/input/mouse/synaptics_usb.c +@@ -0,0 +1,568 @@ ++/* ++ * USB Synaptics device driver ++ * ++ * Copyright (c) 2002 Rob Miller (rob@inpharmatica . co . uk) ++ * Copyright (c) 2003 Ron Lee (ron@debian.org) ++ * cPad driver for kernel 2.4 ++ * ++ * Copyright (c) 2004 Jan Steinhoff (cpad@jan-steinhoff . de) ++ * Copyright (c) 2004 Ron Lee (ron@debian.org) ++ * rewritten for kernel 2.6 ++ * ++ * cPad display character device part is not included. It can be found at ++ * http://jan-steinhoff.de/linux/synaptics-usb.html ++ * ++ * Bases on: usb_skeleton.c v2.2 by Greg Kroah-Hartman ++ * drivers/hid/usbhid/usbmouse.c by Vojtech Pavlik ++ * drivers/input/mouse/synaptics.c by Peter Osterlund ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License as published by the Free ++ * Software Foundation; either version 2 of the License, or (at your option) ++ * any later version. ++ * ++ * Trademarks are the property of their respective owners. ++ */ ++ ++/* ++ * There are three different types of Synaptics USB devices: Touchpads, ++ * touchsticks (or trackpoints), and touchscreens. Touchpads are well supported ++ * by this driver, touchstick support has not been tested much yet, and ++ * touchscreens have not been tested at all. ++ * ++ * Up to three alternate settings are possible: ++ * setting 0: one int endpoint for relative movement (used by usbhid.ko) ++ * setting 1: one int endpoint for absolute finger position ++ * setting 2 (cPad only): one int endpoint for absolute finger position and ++ * two bulk endpoints for the display (in/out) ++ * This driver uses setting 1. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define USB_VENDOR_ID_SYNAPTICS 0x06cb ++#define USB_DEVICE_ID_SYNAPTICS_TP 0x0001 /* Synaptics USB TouchPad */ ++#define USB_DEVICE_ID_SYNAPTICS_INT_TP 0x0002 /* Integrated USB TouchPad */ ++#define USB_DEVICE_ID_SYNAPTICS_CPAD 0x0003 /* Synaptics cPad */ ++#define USB_DEVICE_ID_SYNAPTICS_TS 0x0006 /* Synaptics TouchScreen */ ++#define USB_DEVICE_ID_SYNAPTICS_STICK 0x0007 /* Synaptics USB Styk */ ++#define USB_DEVICE_ID_SYNAPTICS_WP 0x0008 /* Synaptics USB WheelPad */ ++#define USB_DEVICE_ID_SYNAPTICS_COMP_TP 0x0009 /* Composite USB TouchPad */ ++#define USB_DEVICE_ID_SYNAPTICS_WTP 0x0010 /* Wireless TouchPad */ ++#define USB_DEVICE_ID_SYNAPTICS_DPAD 0x0013 /* DisplayPad */ ++ ++#define SYNUSB_TOUCHPAD (1 << 0) ++#define SYNUSB_STICK (1 << 1) ++#define SYNUSB_TOUCHSCREEN (1 << 2) ++#define SYNUSB_AUXDISPLAY (1 << 3) /* For cPad */ ++#define SYNUSB_COMBO (1 << 4) /* Composite device (TP + stick) */ ++#define SYNUSB_IO_ALWAYS (1 << 5) ++ ++#define USB_DEVICE_SYNAPTICS(prod, kind) \ ++ USB_DEVICE(USB_VENDOR_ID_SYNAPTICS, \ ++ USB_DEVICE_ID_SYNAPTICS_##prod), \ ++ .driver_info = (kind), ++ ++#define SYNUSB_RECV_SIZE 8 ++ ++#define XMIN_NOMINAL 1472 ++#define XMAX_NOMINAL 5472 ++#define YMIN_NOMINAL 1408 ++#define YMAX_NOMINAL 4448 ++ ++struct synusb { ++ struct usb_device *udev; ++ struct usb_interface *intf; ++ struct urb *urb; ++ unsigned char *data; ++ ++ /* input device related data structures */ ++ struct input_dev *input; ++ char name[128]; ++ char phys[64]; ++ ++ /* characteristics of the device */ ++ unsigned long flags; ++}; ++ ++static void synusb_report_buttons(struct synusb *synusb) ++{ ++ struct input_dev *input_dev = synusb->input; ++ ++ input_report_key(input_dev, BTN_LEFT, synusb->data[1] & 0x04); ++ input_report_key(input_dev, BTN_RIGHT, synusb->data[1] & 0x01); ++ input_report_key(input_dev, BTN_MIDDLE, synusb->data[1] & 0x02); ++} ++ ++static void synusb_report_stick(struct synusb *synusb) ++{ ++ struct input_dev *input_dev = synusb->input; ++ int x, y; ++ unsigned int pressure; ++ ++ pressure = synusb->data[6]; ++ x = (s16)(be16_to_cpup((__be16 *)&synusb->data[2]) << 3) >> 7; ++ y = (s16)(be16_to_cpup((__be16 *)&synusb->data[4]) << 3) >> 7; ++ ++ if (pressure > 0) { ++ input_report_rel(input_dev, REL_X, x); ++ input_report_rel(input_dev, REL_Y, -y); ++ } ++ ++ input_report_abs(input_dev, ABS_PRESSURE, pressure); ++ ++ synusb_report_buttons(synusb); ++ ++ input_sync(input_dev); ++} ++ ++static void synusb_report_touchpad(struct synusb *synusb) ++{ ++ struct input_dev *input_dev = synusb->input; ++ unsigned int num_fingers, tool_width; ++ unsigned int x, y; ++ unsigned int pressure, w; ++ ++ pressure = synusb->data[6]; ++ x = be16_to_cpup((__be16 *)&synusb->data[2]); ++ y = be16_to_cpup((__be16 *)&synusb->data[4]); ++ w = synusb->data[0] & 0x0f; ++ ++ if (pressure > 0) { ++ num_fingers = 1; ++ tool_width = 5; ++ switch (w) { ++ case 0 ... 1: ++ num_fingers = 2 + w; ++ break; ++ ++ case 2: /* pen, pretend its a finger */ ++ break; ++ ++ case 4 ... 15: ++ tool_width = w; ++ break; ++ } ++ } else { ++ num_fingers = 0; ++ tool_width = 0; ++ } ++ ++ /* ++ * Post events ++ * BTN_TOUCH has to be first as mousedev relies on it when doing ++ * absolute -> relative conversion ++ */ ++ ++ if (pressure > 30) ++ input_report_key(input_dev, BTN_TOUCH, 1); ++ if (pressure < 25) ++ input_report_key(input_dev, BTN_TOUCH, 0); ++ ++ if (num_fingers > 0) { ++ input_report_abs(input_dev, ABS_X, x); ++ input_report_abs(input_dev, ABS_Y, ++ YMAX_NOMINAL + YMIN_NOMINAL - y); ++ } ++ ++ input_report_abs(input_dev, ABS_PRESSURE, pressure); ++ input_report_abs(input_dev, ABS_TOOL_WIDTH, tool_width); ++ ++ input_report_key(input_dev, BTN_TOOL_FINGER, num_fingers == 1); ++ input_report_key(input_dev, BTN_TOOL_DOUBLETAP, num_fingers == 2); ++ input_report_key(input_dev, BTN_TOOL_TRIPLETAP, num_fingers == 3); ++ ++ synusb_report_buttons(synusb); ++ if (synusb->flags & SYNUSB_AUXDISPLAY) ++ input_report_key(input_dev, BTN_MIDDLE, synusb->data[1] & 0x08); ++ ++ input_sync(input_dev); ++} ++ ++static void synusb_irq(struct urb *urb) ++{ ++ struct synusb *synusb = urb->context; ++ int error; ++ ++ /* Check our status in case we need to bail out early. */ ++ switch (urb->status) { ++ case 0: ++ usb_mark_last_busy(synusb->udev); ++ break; ++ ++ /* Device went away so don't keep trying to read from it. */ ++ case -ECONNRESET: ++ case -ENOENT: ++ case -ESHUTDOWN: ++ return; ++ ++ default: ++ goto resubmit; ++ break; ++ } ++ ++ if (synusb->flags & SYNUSB_STICK) ++ synusb_report_stick(synusb); ++ else ++ synusb_report_touchpad(synusb); ++ ++resubmit: ++ error = usb_submit_urb(urb, GFP_ATOMIC); ++ if (error && error != -EPERM) ++ dev_err(&synusb->intf->dev, ++ "%s - usb_submit_urb failed with result: %d", ++ __func__, error); ++} ++ ++static struct usb_endpoint_descriptor * ++synusb_get_in_endpoint(struct usb_host_interface *iface) ++{ ++ ++ struct usb_endpoint_descriptor *endpoint; ++ int i; ++ ++ for (i = 0; i < iface->desc.bNumEndpoints; ++i) { ++ endpoint = &iface->endpoint[i].desc; ++ ++ if (usb_endpoint_is_int_in(endpoint)) { ++ /* we found our interrupt in endpoint */ ++ return endpoint; ++ } ++ } ++ ++ return NULL; ++} ++ ++static int synusb_open(struct input_dev *dev) ++{ ++ struct synusb *synusb = input_get_drvdata(dev); ++ int retval; ++ ++ retval = usb_autopm_get_interface(synusb->intf); ++ if (retval) { ++ dev_err(&synusb->intf->dev, ++ "%s - usb_autopm_get_interface failed, error: %d\n", ++ __func__, retval); ++ return retval; ++ } ++ ++ retval = usb_submit_urb(synusb->urb, GFP_KERNEL); ++ if (retval) { ++ dev_err(&synusb->intf->dev, ++ "%s - usb_submit_urb failed, error: %d\n", ++ __func__, retval); ++ retval = -EIO; ++ goto out; ++ } ++ ++ synusb->intf->needs_remote_wakeup = 1; ++ ++out: ++ usb_autopm_put_interface(synusb->intf); ++ return retval; ++} ++ ++static void synusb_close(struct input_dev *dev) ++{ ++ struct synusb *synusb = input_get_drvdata(dev); ++ int autopm_error; ++ ++ autopm_error = usb_autopm_get_interface(synusb->intf); ++ ++ usb_kill_urb(synusb->urb); ++ synusb->intf->needs_remote_wakeup = 0; ++ ++ if (!autopm_error) ++ usb_autopm_put_interface(synusb->intf); ++} ++ ++static int synusb_probe(struct usb_interface *intf, ++ const struct usb_device_id *id) ++{ ++ struct usb_device *udev = interface_to_usbdev(intf); ++ struct usb_endpoint_descriptor *ep; ++ struct synusb *synusb; ++ struct input_dev *input_dev; ++ unsigned int intf_num = intf->cur_altsetting->desc.bInterfaceNumber; ++ unsigned int altsetting = min(intf->num_altsetting, 1U); ++ int error; ++ ++ error = usb_set_interface(udev, intf_num, altsetting); ++ if (error) { ++ dev_err(&udev->dev, ++ "Can not set alternate setting to %i, error: %i", ++ altsetting, error); ++ return error; ++ } ++ ++ ep = synusb_get_in_endpoint(intf->cur_altsetting); ++ if (!ep) ++ return -ENODEV; ++ ++ synusb = kzalloc(sizeof(*synusb), GFP_KERNEL); ++ input_dev = input_allocate_device(); ++ if (!synusb || !input_dev) { ++ error = -ENOMEM; ++ goto err_free_mem; ++ } ++ ++ synusb->udev = udev; ++ synusb->intf = intf; ++ synusb->input = input_dev; ++ ++ synusb->flags = id->driver_info; ++ if (synusb->flags & SYNUSB_COMBO) { ++ /* ++ * This is a combo device, we need to set proper ++ * capability, depending on the interface. ++ */ ++ synusb->flags |= intf_num == 1 ? ++ SYNUSB_STICK : SYNUSB_TOUCHPAD; ++ } ++ ++ synusb->urb = usb_alloc_urb(0, GFP_KERNEL); ++ if (!synusb->urb) { ++ error = -ENOMEM; ++ goto err_free_mem; ++ } ++ ++ synusb->data = usb_alloc_coherent(udev, SYNUSB_RECV_SIZE, GFP_KERNEL, ++ &synusb->urb->transfer_dma); ++ if (!synusb->data) { ++ error = -ENOMEM; ++ goto err_free_urb; ++ } ++ ++ usb_fill_int_urb(synusb->urb, udev, ++ usb_rcvintpipe(udev, ep->bEndpointAddress), ++ synusb->data, SYNUSB_RECV_SIZE, ++ synusb_irq, synusb, ++ ep->bInterval); ++ synusb->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; ++ ++ if (udev->manufacturer) ++ strlcpy(synusb->name, udev->manufacturer, ++ sizeof(synusb->name)); ++ ++ if (udev->product) { ++ if (udev->manufacturer) ++ strlcat(synusb->name, " ", sizeof(synusb->name)); ++ strlcat(synusb->name, udev->product, sizeof(synusb->name)); ++ } ++ ++ if (!strlen(synusb->name)) ++ snprintf(synusb->name, sizeof(synusb->name), ++ "USB Synaptics Device %04x:%04x", ++ le16_to_cpu(udev->descriptor.idVendor), ++ le16_to_cpu(udev->descriptor.idProduct)); ++ ++ if (synusb->flags & SYNUSB_STICK) ++ strlcat(synusb->name, " (Stick) ", sizeof(synusb->name)); ++ ++ usb_make_path(udev, synusb->phys, sizeof(synusb->phys)); ++ strlcat(synusb->phys, "/input0", sizeof(synusb->phys)); ++ ++ input_dev->name = synusb->name; ++ input_dev->phys = synusb->phys; ++ usb_to_input_id(udev, &input_dev->id); ++ input_dev->dev.parent = &synusb->intf->dev; ++ ++ if (!(synusb->flags & SYNUSB_IO_ALWAYS)) { ++ input_dev->open = synusb_open; ++ input_dev->close = synusb_close; ++ } ++ ++ input_set_drvdata(input_dev, synusb); ++ ++ __set_bit(EV_ABS, input_dev->evbit); ++ __set_bit(EV_KEY, input_dev->evbit); ++ ++ if (synusb->flags & SYNUSB_STICK) { ++ __set_bit(EV_REL, input_dev->evbit); ++ __set_bit(REL_X, input_dev->relbit); ++ __set_bit(REL_Y, input_dev->relbit); ++ input_set_abs_params(input_dev, ABS_PRESSURE, 0, 127, 0, 0); ++ } else { ++ input_set_abs_params(input_dev, ABS_X, ++ XMIN_NOMINAL, XMAX_NOMINAL, 0, 0); ++ input_set_abs_params(input_dev, ABS_Y, ++ YMIN_NOMINAL, YMAX_NOMINAL, 0, 0); ++ input_set_abs_params(input_dev, ABS_PRESSURE, 0, 255, 0, 0); ++ input_set_abs_params(input_dev, ABS_TOOL_WIDTH, 0, 15, 0, 0); ++ __set_bit(BTN_TOUCH, input_dev->keybit); ++ __set_bit(BTN_TOOL_FINGER, input_dev->keybit); ++ __set_bit(BTN_TOOL_DOUBLETAP, input_dev->keybit); ++ __set_bit(BTN_TOOL_TRIPLETAP, input_dev->keybit); ++ } ++ ++ __set_bit(BTN_LEFT, input_dev->keybit); ++ __set_bit(BTN_RIGHT, input_dev->keybit); ++ __set_bit(BTN_MIDDLE, input_dev->keybit); ++ ++ usb_set_intfdata(intf, synusb); ++ ++ if (synusb->flags & SYNUSB_IO_ALWAYS) { ++ error = synusb_open(input_dev); ++ if (error) ++ goto err_free_dma; ++ } ++ ++ error = input_register_device(input_dev); ++ if (error) { ++ dev_err(&udev->dev, ++ "Failed to register input device, error %d\n", ++ error); ++ goto err_stop_io; ++ } ++ ++ return 0; ++ ++err_stop_io: ++ if (synusb->flags & SYNUSB_IO_ALWAYS) ++ synusb_close(synusb->input); ++err_free_dma: ++ usb_free_coherent(udev, SYNUSB_RECV_SIZE, synusb->data, ++ synusb->urb->transfer_dma); ++err_free_urb: ++ usb_free_urb(synusb->urb); ++err_free_mem: ++ input_free_device(input_dev); ++ kfree(synusb); ++ usb_set_intfdata(intf, NULL); ++ ++ return error; ++} ++ ++static void synusb_disconnect(struct usb_interface *intf) ++{ ++ struct synusb *synusb = usb_get_intfdata(intf); ++ struct usb_device *udev = interface_to_usbdev(intf); ++ ++ if (synusb->flags & SYNUSB_IO_ALWAYS) ++ synusb_close(synusb->input); ++ ++ input_unregister_device(synusb->input); ++ ++ usb_free_coherent(udev, SYNUSB_RECV_SIZE, synusb->data, ++ synusb->urb->transfer_dma); ++ usb_free_urb(synusb->urb); ++ kfree(synusb); ++ ++ usb_set_intfdata(intf, NULL); ++} ++ ++static int synusb_suspend(struct usb_interface *intf, pm_message_t message) ++{ ++ struct synusb *synusb = usb_get_intfdata(intf); ++ struct input_dev *input_dev = synusb->input; ++ ++ mutex_lock(&input_dev->mutex); ++ usb_kill_urb(synusb->urb); ++ mutex_unlock(&input_dev->mutex); ++ ++ return 0; ++} ++ ++static int synusb_resume(struct usb_interface *intf) ++{ ++ struct synusb *synusb = usb_get_intfdata(intf); ++ struct input_dev *input_dev = synusb->input; ++ int retval = 0; ++ ++ mutex_lock(&input_dev->mutex); ++ ++ if ((input_dev->users || (synusb->flags & SYNUSB_IO_ALWAYS)) && ++ usb_submit_urb(synusb->urb, GFP_NOIO) < 0) { ++ retval = -EIO; ++ } ++ ++ mutex_unlock(&input_dev->mutex); ++ ++ return retval; ++} ++ ++static int synusb_pre_reset(struct usb_interface *intf) ++{ ++ struct synusb *synusb = usb_get_intfdata(intf); ++ struct input_dev *input_dev = synusb->input; ++ ++ mutex_lock(&input_dev->mutex); ++ usb_kill_urb(synusb->urb); ++ ++ return 0; ++} ++ ++static int synusb_post_reset(struct usb_interface *intf) ++{ ++ struct synusb *synusb = usb_get_intfdata(intf); ++ struct input_dev *input_dev = synusb->input; ++ int retval = 0; ++ ++ if ((input_dev->users || (synusb->flags & SYNUSB_IO_ALWAYS)) && ++ usb_submit_urb(synusb->urb, GFP_NOIO) < 0) { ++ retval = -EIO; ++ } ++ ++ mutex_unlock(&input_dev->mutex); ++ ++ return retval; ++} ++ ++static int synusb_reset_resume(struct usb_interface *intf) ++{ ++ return synusb_resume(intf); ++} ++ ++static struct usb_device_id synusb_idtable[] = { ++ { USB_DEVICE_SYNAPTICS(TP, SYNUSB_TOUCHPAD) }, ++ { USB_DEVICE_SYNAPTICS(INT_TP, SYNUSB_TOUCHPAD) }, ++ { USB_DEVICE_SYNAPTICS(CPAD, ++ SYNUSB_TOUCHPAD | SYNUSB_AUXDISPLAY | SYNUSB_IO_ALWAYS) }, ++ { USB_DEVICE_SYNAPTICS(TS, SYNUSB_TOUCHSCREEN) }, ++ { USB_DEVICE_SYNAPTICS(STICK, SYNUSB_STICK) }, ++ { USB_DEVICE_SYNAPTICS(WP, SYNUSB_TOUCHPAD) }, ++ { USB_DEVICE_SYNAPTICS(COMP_TP, SYNUSB_COMBO) }, ++ { USB_DEVICE_SYNAPTICS(WTP, SYNUSB_TOUCHPAD) }, ++ { USB_DEVICE_SYNAPTICS(DPAD, SYNUSB_TOUCHPAD) }, ++ { } ++}; ++MODULE_DEVICE_TABLE(usb, synusb_idtable); ++ ++static struct usb_driver synusb_driver = { ++ .name = "synaptics_usb", ++ .probe = synusb_probe, ++ .disconnect = synusb_disconnect, ++ .id_table = synusb_idtable, ++ .suspend = synusb_suspend, ++ .resume = synusb_resume, ++ .pre_reset = synusb_pre_reset, ++ .post_reset = synusb_post_reset, ++ .reset_resume = synusb_reset_resume, ++ .supports_autosuspend = 1, ++}; ++ ++static int __init synusb_init(void) ++{ ++ return usb_register(&synusb_driver); ++} ++ ++static void __exit synusb_exit(void) ++{ ++ usb_deregister(&synusb_driver); ++} ++ ++module_init(synusb_init); ++module_exit(synusb_exit); ++ ++MODULE_AUTHOR("Rob Miller , " ++ "Ron Lee , " ++ "Jan Steinhoff "); ++MODULE_DESCRIPTION("Synaptics USB device driver"); ++MODULE_LICENSE("GPL"); diff --git a/debian/patches/series b/debian/patches/series index 240163323..740739006 100644 --- a/debian/patches/series +++ b/debian/patches/series @@ -355,3 +355,4 @@ features/arm/kirkwood-create-a-generic-function-for-gpio-led-blinking.patch features/arm/kirkwood-add-configuration-for-mpp12-as-gpio.patch features/arm/kirkwood-add-iconnect-support.patch +features/all/Input-add-Synaptics-USB-device-driver.patch