| 1 | |
| 2 | |
| 3 | * USB Synaptics device driver
|
| 4 | *
|
| 5 | * Copyright (c) 2002 Rob Miller (rob@inpharmatica . co . uk)
|
| 6 | * Copyright (c) 2003 Ron Lee ([email protected])
|
| 7 | * cPad driver for kernel 2.4
|
| 8 | *
|
| 9 | * Copyright (c) 2004 Jan Steinhoff (cpad@jan-steinhoff . de)
|
| 10 | * Copyright (c) 2004 Ron Lee ([email protected])
|
| 11 | * rewritten for kernel 2.6
|
| 12 | *
|
| 13 | * cPad display character device part is not included. It can be found at
|
| 14 | * http://jan-steinhoff.de/linux/synaptics-usb.html
|
| 15 | *
|
| 16 | * Bases on: usb_skeleton.c v2.2 by Greg Kroah-Hartman
|
| 17 | * drivers/hid/usbhid/usbmouse.c by Vojtech Pavlik
|
| 18 | * drivers/input/mouse/synaptics.c by Peter Osterlund
|
| 19 | *
|
| 20 | * Trademarks are the property of their respective owners.
|
| 21 |
|
| 22 |
|
| 23 | |
| 24 | * There are three different types of Synaptics USB devices: Touchpads,
|
| 25 | * touchsticks (or trackpoints), and touchscreens. Touchpads are well supported
|
| 26 | * by this driver, touchstick support has not been tested much yet, and
|
| 27 | * touchscreens have not been tested at all.
|
| 28 | *
|
| 29 | * Up to three alternate settings are possible:
|
| 30 | * setting 0: one int endpoint for relative movement (used by usbhid.ko)
|
| 31 | * setting 1: one int endpoint for absolute finger position
|
| 32 | * setting 2 (cPad only): one int endpoint for absolute finger position and
|
| 33 | * two bulk endpoints for the display (in/out)
|
| 34 | * This driver uses setting 1.
|
| 35 |
|
| 36 |
|
| 37 | #include <linux/kernel.h>
|
| 38 | #include <linux/slab.h>
|
| 39 | #include <linux/module.h>
|
| 40 | #include <linux/moduleparam.h>
|
| 41 | #include <linux/usb.h>
|
| 42 | #include <linux/input.h>
|
| 43 | #include <linux/usb/input.h>
|
| 44 |
|
| 45 | #define USB_VENDOR_ID_SYNAPTICS 0x06cb
|
| 46 | #define USB_DEVICE_ID_SYNAPTICS_TP 0x0001
|
| 47 | #define USB_DEVICE_ID_SYNAPTICS_INT_TP 0x0002
|
| 48 | #define USB_DEVICE_ID_SYNAPTICS_CPAD 0x0003
|
| 49 | #define USB_DEVICE_ID_SYNAPTICS_TS 0x0006
|
| 50 | #define USB_DEVICE_ID_SYNAPTICS_STICK 0x0007
|
| 51 | #define USB_DEVICE_ID_SYNAPTICS_WP 0x0008
|
| 52 | #define USB_DEVICE_ID_SYNAPTICS_COMP_TP 0x0009
|
| 53 | #define USB_DEVICE_ID_SYNAPTICS_WTP 0x0010
|
| 54 | #define USB_DEVICE_ID_SYNAPTICS_DPAD 0x0013
|
| 55 |
|
| 56 | #define SYNUSB_TOUCHPAD (1 << 0)
|
| 57 | #define SYNUSB_STICK (1 << 1)
|
| 58 | #define SYNUSB_TOUCHSCREEN (1 << 2)
|
| 59 | #define SYNUSB_AUXDISPLAY (1 << 3)
|
| 60 | #define SYNUSB_COMBO (1 << 4)
|
| 61 | #define SYNUSB_IO_ALWAYS (1 << 5)
|
| 62 |
|
| 63 | #define USB_DEVICE_SYNAPTICS(prod, kind) \
|
| 64 | USB_DEVICE(USB_VENDOR_ID_SYNAPTICS, \
|
| 65 | USB_DEVICE_ID_SYNAPTICS_##prod), \
|
| 66 | .driver_info = (kind),
|
| 67 |
|
| 68 | #define SYNUSB_RECV_SIZE 8
|
| 69 |
|
| 70 | #define XMIN_NOMINAL 1472
|
| 71 | #define XMAX_NOMINAL 5472
|
| 72 | #define YMIN_NOMINAL 1408
|
| 73 | #define YMAX_NOMINAL 4448
|
| 74 |
|
| 75 | struct synusb {
|
| 76 | struct usb_device *udev;
|
| 77 | struct usb_interface *intf;
|
| 78 | struct urb *urb;
|
| 79 | unsigned char *data;
|
| 80 |
|
| 81 |
|
| 82 | struct mutex pm_mutex;
|
| 83 | bool is_open;
|
| 84 |
|
| 85 |
|
| 86 | struct input_dev *input;
|
| 87 | char name[128];
|
| 88 | char phys[64];
|
| 89 |
|
| 90 |
|
| 91 | unsigned long flags;
|
| 92 | };
|
| 93 |
|
| 94 | static void synusb_report_buttons(struct synusb *synusb)
|
| 95 | {
|
| 96 | struct input_dev *input_dev = synusb->input;
|
| 97 |
|
| 98 | input_report_key(input_dev, BTN_LEFT, synusb->data[1] & 0x04);
|
| 99 | input_report_key(input_dev, BTN_RIGHT, synusb->data[1] & 0x01);
|
| 100 | input_report_key(input_dev, BTN_MIDDLE, synusb->data[1] & 0x02);
|
| 101 | }
|
| 102 |
|
| 103 | static void synusb_report_stick(struct synusb *synusb)
|
| 104 | {
|
| 105 | struct input_dev *input_dev = synusb->input;
|
| 106 | int x, y;
|
| 107 | unsigned int pressure;
|
| 108 |
|
| 109 | pressure = synusb->data[6];
|
| 110 | x = (s16)(be16_to_cpup((__be16 *)&synusb->data[2]) << 3) >> 7;
|
| 111 | y = (s16)(be16_to_cpup((__be16 *)&synusb->data[4]) << 3) >> 7;
|
| 112 |
|
| 113 | if (pressure > 0) {
|
| 114 | input_report_rel(input_dev, REL_X, x);
|
| 115 | input_report_rel(input_dev, REL_Y, -y);
|
| 116 | }
|
| 117 |
|
| 118 | input_report_abs(input_dev, ABS_PRESSURE, pressure);
|
| 119 |
|
| 120 | synusb_report_buttons(synusb);
|
| 121 |
|
| 122 | input_sync(input_dev);
|
| 123 | }
|
| 124 |
|
| 125 | static void synusb_report_touchpad(struct synusb *synusb)
|
| 126 | {
|
| 127 | struct input_dev *input_dev = synusb->input;
|
| 128 | unsigned int num_fingers, tool_width;
|
| 129 | unsigned int x, y;
|
| 130 | unsigned int pressure, w;
|
| 131 |
|
| 132 | pressure = synusb->data[6];
|
| 133 | x = be16_to_cpup((__be16 *)&synusb->data[2]);
|
| 134 | y = be16_to_cpup((__be16 *)&synusb->data[4]);
|
| 135 | w = synusb->data[0] & 0x0f;
|
| 136 |
|
| 137 | if (pressure > 0) {
|
| 138 | num_fingers = 1;
|
| 139 | tool_width = 5;
|
| 140 | switch (w) {
|
| 141 | case 0 ... 1:
|
| 142 | num_fingers = 2 + w;
|
| 143 | break;
|
| 144 |
|
| 145 | case 2:
|
| 146 | break;
|
| 147 |
|
| 148 | case 4 ... 15:
|
| 149 | tool_width = w;
|
| 150 | break;
|
| 151 | }
|
| 152 | } else {
|
| 153 | num_fingers = 0;
|
| 154 | tool_width = 0;
|
| 155 | }
|
| 156 |
|
| 157 | |
| 158 | * Post events
|
| 159 | * BTN_TOUCH has to be first as mousedev relies on it when doing
|
| 160 | * absolute -> relative conversion
|
| 161 |
|
| 162 |
|
| 163 | if (pressure > 30)
|
| 164 | input_report_key(input_dev, BTN_TOUCH, 1);
|
| 165 | if (pressure < 25)
|
| 166 | input_report_key(input_dev, BTN_TOUCH, 0);
|
| 167 |
|
| 168 | if (num_fingers > 0) {
|
| 169 | input_report_abs(input_dev, ABS_X, x);
|
| 170 | input_report_abs(input_dev, ABS_Y,
|
| 171 | YMAX_NOMINAL + YMIN_NOMINAL - y);
|
| 172 | }
|
| 173 |
|
| 174 | input_report_abs(input_dev, ABS_PRESSURE, pressure);
|
| 175 | input_report_abs(input_dev, ABS_TOOL_WIDTH, tool_width);
|
| 176 |
|
| 177 | input_report_key(input_dev, BTN_TOOL_FINGER, num_fingers == 1);
|
| 178 | input_report_key(input_dev, BTN_TOOL_DOUBLETAP, num_fingers == 2);
|
| 179 | input_report_key(input_dev, BTN_TOOL_TRIPLETAP, num_fingers == 3);
|
| 180 |
|
| 181 | synusb_report_buttons(synusb);
|
| 182 | if (synusb->flags & SYNUSB_AUXDISPLAY)
|
| 183 | input_report_key(input_dev, BTN_MIDDLE, synusb->data[1] & 0x08);
|
| 184 |
|
| 185 | input_sync(input_dev);
|
| 186 | }
|
| 187 |
|
| 188 | static void synusb_irq(struct urb *urb)
|
| 189 | {
|
| 190 | struct synusb *synusb = urb->context;
|
| 191 | int error;
|
| 192 |
|
| 193 |
|
| 194 | switch (urb->status) {
|
| 195 | case 0:
|
| 196 | usb_mark_last_busy(synusb->udev);
|
| 197 | break;
|
| 198 |
|
| 199 |
|
| 200 | case -ECONNRESET:
|
| 201 | case -ENOENT:
|
| 202 | case -ESHUTDOWN:
|
| 203 | return;
|
| 204 |
|
| 205 | default:
|
| 206 | goto resubmit;
|
| 207 | break;
|
| 208 | }
|
| 209 |
|
| 210 | if (synusb->flags & SYNUSB_STICK)
|
| 211 | synusb_report_stick(synusb);
|
| 212 | else
|
| 213 | synusb_report_touchpad(synusb);
|
| 214 |
|
| 215 | resubmit:
|
| 216 | error = usb_submit_urb(urb, GFP_ATOMIC);
|
| 217 | if (error && error != -EPERM)
|
| 218 | dev_err(&synusb->intf->dev,
|
| 219 | "%s - usb_submit_urb failed with result: %d",
|
| 220 | __func__, error);
|
| 221 | }
|
| 222 |
|
| 223 | static int synusb_open(struct input_dev *dev)
|
| 224 | {
|
| 225 | struct synusb *synusb = input_get_drvdata(dev);
|
| 226 | int retval;
|
| 227 |
|
| 228 | retval = usb_autopm_get_interface(synusb->intf);
|
| 229 | if (retval) {
|
| 230 | dev_err(&synusb->intf->dev,
|
| 231 | "%s - usb_autopm_get_interface failed, error: %d\n",
|
| 232 | __func__, retval);
|
| 233 | return retval;
|
| 234 | }
|
| 235 |
|
| 236 | mutex_lock(&synusb->pm_mutex);
|
| 237 | retval = usb_submit_urb(synusb->urb, GFP_KERNEL);
|
| 238 | if (retval) {
|
| 239 | dev_err(&synusb->intf->dev,
|
| 240 | "%s - usb_submit_urb failed, error: %d\n",
|
| 241 | __func__, retval);
|
| 242 | retval = -EIO;
|
| 243 | goto out;
|
| 244 | }
|
| 245 |
|
| 246 | synusb->intf->needs_remote_wakeup = 1;
|
| 247 | synusb->is_open = true;
|
| 248 |
|
| 249 | out:
|
| 250 | mutex_unlock(&synusb->pm_mutex);
|
| 251 | usb_autopm_put_interface(synusb->intf);
|
| 252 | return retval;
|
| 253 | }
|
| 254 |
|
| 255 | static void synusb_close(struct input_dev *dev)
|
| 256 | {
|
| 257 | struct synusb *synusb = input_get_drvdata(dev);
|
| 258 | int autopm_error;
|
| 259 |
|
| 260 | autopm_error = usb_autopm_get_interface(synusb->intf);
|
| 261 |
|
| 262 | mutex_lock(&synusb->pm_mutex);
|
| 263 | usb_kill_urb(synusb->urb);
|
| 264 | synusb->intf->needs_remote_wakeup = 0;
|
| 265 | synusb->is_open = false;
|
| 266 | mutex_unlock(&synusb->pm_mutex);
|
| 267 |
|
| 268 | if (!autopm_error)
|
| 269 | usb_autopm_put_interface(synusb->intf);
|
| 270 | }
|
| 271 |
|
| 272 | static int synusb_probe(struct usb_interface *intf,
|
| 273 | const struct usb_device_id *id)
|
| 274 | {
|
| 275 | struct usb_device *udev = interface_to_usbdev(intf);
|
| 276 | struct usb_endpoint_descriptor *ep;
|
| 277 | struct synusb *synusb;
|
| 278 | struct input_dev *input_dev;
|
| 279 | unsigned int intf_num = intf->cur_altsetting->desc.bInterfaceNumber;
|
| 280 | unsigned int altsetting = min(intf->num_altsetting, 1U);
|
| 281 | int error;
|
| 282 |
|
| 283 | error = usb_set_interface(udev, intf_num, altsetting);
|
| 284 | if (error) {
|
| 285 | dev_err(&udev->dev,
|
| 286 | "Can not set alternate setting to %i, error: %i",
|
| 287 | altsetting, error);
|
| 288 | return error;
|
| 289 | }
|
| 290 |
|
| 291 | error = usb_find_int_in_endpoint(intf->cur_altsetting, &ep);
|
| 292 | if (error)
|
| 293 | return -ENODEV;
|
| 294 |
|
| 295 | synusb = kzalloc_obj(*synusb);
|
| 296 | input_dev = input_allocate_device();
|
| 297 | if (!synusb || !input_dev) {
|
| 298 | error = -ENOMEM;
|
| 299 | goto err_free_mem;
|
| 300 | }
|
| 301 |
|
| 302 | synusb->udev = udev;
|
| 303 | synusb->intf = intf;
|
| 304 | synusb->input = input_dev;
|
| 305 | mutex_init(&synusb->pm_mutex);
|
| 306 |
|
| 307 | synusb->flags = id->driver_info;
|
| 308 | if (synusb->flags & SYNUSB_COMBO) {
|
| 309 | |
| 310 | * This is a combo device, we need to set proper
|
| 311 | * capability, depending on the interface.
|
| 312 |
|
| 313 | synusb->flags |= intf_num == 1 ?
|
| 314 | SYNUSB_STICK : SYNUSB_TOUCHPAD;
|
| 315 | }
|
| 316 |
|
| 317 | synusb->urb = usb_alloc_urb(0, GFP_KERNEL);
|
| 318 | if (!synusb->urb) {
|
| 319 | error = -ENOMEM;
|
| 320 | goto err_free_mem;
|
| 321 | }
|
| 322 |
|
| 323 | synusb->data = usb_alloc_coherent(udev, SYNUSB_RECV_SIZE, GFP_KERNEL,
|
| 324 | &synusb->urb->transfer_dma);
|
| 325 | if (!synusb->data) {
|
| 326 | error = -ENOMEM;
|
| 327 | goto err_free_urb;
|
| 328 | }
|
| 329 |
|
| 330 | usb_fill_int_urb(synusb->urb, udev,
|
| 331 | usb_rcvintpipe(udev, ep->bEndpointAddress),
|
| 332 | synusb->data, SYNUSB_RECV_SIZE,
|
| 333 | synusb_irq, synusb,
|
| 334 | ep->bInterval);
|
| 335 | synusb->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
|
| 336 |
|
| 337 | if (udev->manufacturer)
|
| 338 | strscpy(synusb->name, udev->manufacturer,
|
| 339 | sizeof(synusb->name));
|
| 340 |
|
| 341 | if (udev->product) {
|
| 342 | if (udev->manufacturer)
|
| 343 | strlcat(synusb->name, " ", sizeof(synusb->name));
|
| 344 | strlcat(synusb->name, udev->product, sizeof(synusb->name));
|
| 345 | }
|
| 346 |
|
| 347 | if (!strlen(synusb->name))
|
| 348 | snprintf(synusb->name, sizeof(synusb->name),
|
| 349 | "USB Synaptics Device %04x:%04x",
|
| 350 | le16_to_cpu(udev->descriptor.idVendor),
|
| 351 | le16_to_cpu(udev->descriptor.idProduct));
|
| 352 |
|
| 353 | if (synusb->flags & SYNUSB_STICK)
|
| 354 | strlcat(synusb->name, " (Stick)", sizeof(synusb->name));
|
| 355 |
|
| 356 | usb_make_path(udev, synusb->phys, sizeof(synusb->phys));
|
| 357 | strlcat(synusb->phys, "/input0", sizeof(synusb->phys));
|
| 358 |
|
| 359 | input_dev->name = synusb->name;
|
| 360 | input_dev->phys = synusb->phys;
|
| 361 | usb_to_input_id(udev, &input_dev->id);
|
| 362 | input_dev->dev.parent = &synusb->intf->dev;
|
| 363 |
|
| 364 | if (!(synusb->flags & SYNUSB_IO_ALWAYS)) {
|
| 365 | input_dev->open = synusb_open;
|
| 366 | input_dev->close = synusb_close;
|
| 367 | }
|
| 368 |
|
| 369 | input_set_drvdata(input_dev, synusb);
|
| 370 |
|
| 371 | __set_bit(EV_ABS, input_dev->evbit);
|
| 372 | __set_bit(EV_KEY, input_dev->evbit);
|
| 373 |
|
| 374 | if (synusb->flags & SYNUSB_STICK) {
|
| 375 | __set_bit(EV_REL, input_dev->evbit);
|
| 376 | __set_bit(REL_X, input_dev->relbit);
|
| 377 | __set_bit(REL_Y, input_dev->relbit);
|
| 378 | __set_bit(INPUT_PROP_POINTING_STICK, input_dev->propbit);
|
| 379 | input_set_abs_params(input_dev, ABS_PRESSURE, 0, 127, 0, 0);
|
| 380 | } else {
|
| 381 | input_set_abs_params(input_dev, ABS_X,
|
| 382 | XMIN_NOMINAL, XMAX_NOMINAL, 0, 0);
|
| 383 | input_set_abs_params(input_dev, ABS_Y,
|
| 384 | YMIN_NOMINAL, YMAX_NOMINAL, 0, 0);
|
| 385 | input_set_abs_params(input_dev, ABS_PRESSURE, 0, 255, 0, 0);
|
| 386 | input_set_abs_params(input_dev, ABS_TOOL_WIDTH, 0, 15, 0, 0);
|
| 387 | __set_bit(BTN_TOUCH, input_dev->keybit);
|
| 388 | __set_bit(BTN_TOOL_FINGER, input_dev->keybit);
|
| 389 | __set_bit(BTN_TOOL_DOUBLETAP, input_dev->keybit);
|
| 390 | __set_bit(BTN_TOOL_TRIPLETAP, input_dev->keybit);
|
| 391 | }
|
| 392 |
|
| 393 | if (synusb->flags & SYNUSB_TOUCHSCREEN)
|
| 394 | __set_bit(INPUT_PROP_DIRECT, input_dev->propbit);
|
| 395 | else
|
| 396 | __set_bit(INPUT_PROP_POINTER, input_dev->propbit);
|
| 397 |
|
| 398 | __set_bit(BTN_LEFT, input_dev->keybit);
|
| 399 | __set_bit(BTN_RIGHT, input_dev->keybit);
|
| 400 | __set_bit(BTN_MIDDLE, input_dev->keybit);
|
| 401 |
|
| 402 | usb_set_intfdata(intf, synusb);
|
| 403 |
|
| 404 | if (synusb->flags & SYNUSB_IO_ALWAYS) {
|
| 405 | error = synusb_open(input_dev);
|
| 406 | if (error)
|
| 407 | goto err_free_dma;
|
| 408 | }
|
| 409 |
|
| 410 | error = input_register_device(input_dev);
|
| 411 | if (error) {
|
| 412 | dev_err(&udev->dev,
|
| 413 | "Failed to register input device, error %d\n",
|
| 414 | error);
|
| 415 | goto err_stop_io;
|
| 416 | }
|
| 417 |
|
| 418 | return 0;
|
| 419 |
|
| 420 | err_stop_io:
|
| 421 | if (synusb->flags & SYNUSB_IO_ALWAYS)
|
| 422 | synusb_close(synusb->input);
|
| 423 | err_free_dma:
|
| 424 | usb_free_coherent(udev, SYNUSB_RECV_SIZE, synusb->data,
|
| 425 | synusb->urb->transfer_dma);
|
| 426 | err_free_urb:
|
| 427 | usb_free_urb(synusb->urb);
|
| 428 | err_free_mem:
|
| 429 | input_free_device(input_dev);
|
| 430 | kfree(synusb);
|
| 431 | usb_set_intfdata(intf, NULL);
|
| 432 |
|
| 433 | return error;
|
| 434 | }
|
| 435 |
|
| 436 | static void synusb_disconnect(struct usb_interface *intf)
|
| 437 | {
|
| 438 | struct synusb *synusb = usb_get_intfdata(intf);
|
| 439 | struct usb_device *udev = interface_to_usbdev(intf);
|
| 440 |
|
| 441 | if (synusb->flags & SYNUSB_IO_ALWAYS)
|
| 442 | synusb_close(synusb->input);
|
| 443 |
|
| 444 | input_unregister_device(synusb->input);
|
| 445 |
|
| 446 | usb_free_coherent(udev, SYNUSB_RECV_SIZE, synusb->data,
|
| 447 | synusb->urb->transfer_dma);
|
| 448 | usb_free_urb(synusb->urb);
|
| 449 | kfree(synusb);
|
| 450 |
|
| 451 | usb_set_intfdata(intf, NULL);
|
| 452 | }
|
| 453 |
|
| 454 | static int synusb_suspend(struct usb_interface *intf, pm_message_t message)
|
| 455 | {
|
| 456 | struct synusb *synusb = usb_get_intfdata(intf);
|
| 457 |
|
| 458 | mutex_lock(&synusb->pm_mutex);
|
| 459 | usb_kill_urb(synusb->urb);
|
| 460 | mutex_unlock(&synusb->pm_mutex);
|
| 461 |
|
| 462 | return 0;
|
| 463 | }
|
| 464 |
|
| 465 | static int synusb_resume(struct usb_interface *intf)
|
| 466 | {
|
| 467 | struct synusb *synusb = usb_get_intfdata(intf);
|
| 468 | int retval = 0;
|
| 469 |
|
| 470 | mutex_lock(&synusb->pm_mutex);
|
| 471 |
|
| 472 | if ((synusb->is_open || (synusb->flags & SYNUSB_IO_ALWAYS)) &&
|
| 473 | usb_submit_urb(synusb->urb, GFP_NOIO) < 0) {
|
| 474 | retval = -EIO;
|
| 475 | }
|
| 476 |
|
| 477 | mutex_unlock(&synusb->pm_mutex);
|
| 478 |
|
| 479 | return retval;
|
| 480 | }
|
| 481 |
|
| 482 | static int synusb_pre_reset(struct usb_interface *intf)
|
| 483 | {
|
| 484 | struct synusb *synusb = usb_get_intfdata(intf);
|
| 485 |
|
| 486 | mutex_lock(&synusb->pm_mutex);
|
| 487 | usb_kill_urb(synusb->urb);
|
| 488 |
|
| 489 | return 0;
|
| 490 | }
|
| 491 |
|
| 492 | static int synusb_post_reset(struct usb_interface *intf)
|
| 493 | {
|
| 494 | struct synusb *synusb = usb_get_intfdata(intf);
|
| 495 | int retval = 0;
|
| 496 |
|
| 497 | if ((synusb->is_open || (synusb->flags & SYNUSB_IO_ALWAYS)) &&
|
| 498 | usb_submit_urb(synusb->urb, GFP_NOIO) < 0) {
|
| 499 | retval = -EIO;
|
| 500 | }
|
| 501 |
|
| 502 | mutex_unlock(&synusb->pm_mutex);
|
| 503 |
|
| 504 | return retval;
|
| 505 | }
|
| 506 |
|
| 507 | static int synusb_reset_resume(struct usb_interface *intf)
|
| 508 | {
|
| 509 | return synusb_resume(intf);
|
| 510 | }
|
| 511 |
|
| 512 | static const struct usb_device_id synusb_idtable[] = {
|
| 513 | { USB_DEVICE_SYNAPTICS(TP, SYNUSB_TOUCHPAD) },
|
| 514 | { USB_DEVICE_SYNAPTICS(INT_TP, SYNUSB_TOUCHPAD) },
|
| 515 | { USB_DEVICE_SYNAPTICS(CPAD,
|
| 516 | SYNUSB_TOUCHPAD | SYNUSB_AUXDISPLAY | SYNUSB_IO_ALWAYS) },
|
| 517 | { USB_DEVICE_SYNAPTICS(TS, SYNUSB_TOUCHSCREEN) },
|
| 518 | { USB_DEVICE_SYNAPTICS(STICK, SYNUSB_STICK) },
|
| 519 | { USB_DEVICE_SYNAPTICS(WP, SYNUSB_TOUCHPAD) },
|
| 520 | { USB_DEVICE_SYNAPTICS(COMP_TP, SYNUSB_COMBO) },
|
| 521 | { USB_DEVICE_SYNAPTICS(WTP, SYNUSB_TOUCHPAD) },
|
| 522 | { USB_DEVICE_SYNAPTICS(DPAD, SYNUSB_TOUCHPAD) },
|
| 523 | { }
|
| 524 | };
|
| 525 | MODULE_DEVICE_TABLE(usb, synusb_idtable);
|
| 526 |
|
| 527 | static struct usb_driver synusb_driver = {
|
| 528 | .name = "synaptics_usb",
|
| 529 | .probe = synusb_probe,
|
| 530 | .disconnect = synusb_disconnect,
|
| 531 | .id_table = synusb_idtable,
|
| 532 | .suspend = synusb_suspend,
|
| 533 | .resume = synusb_resume,
|
| 534 | .pre_reset = synusb_pre_reset,
|
| 535 | .post_reset = synusb_post_reset,
|
| 536 | .reset_resume = synusb_reset_resume,
|
| 537 | .supports_autosuspend = 1,
|
| 538 | };
|
| 539 |
|
| 540 | module_usb_driver(synusb_driver);
|
| 541 |
|
| 542 | MODULE_AUTHOR("Rob Miller <[email protected]>, "
|
| 543 | "Ron Lee <[email protected]>, "
|
| 544 | "Jan Steinhoff <[email protected]>");
|
| 545 | MODULE_DESCRIPTION("Synaptics USB device driver");
|
| 546 | MODULE_LICENSE("GPL");
|