diff options
Diffstat (limited to 'usr')
| -rw-r--r-- | usr/src/dkms_main_tree/dkms_dbversion | 1 | ||||
| -rw-r--r-- | usr/src/dkms_source_tree/KERNEL_SOURCE_VERSION | 1 | ||||
| -rw-r--r-- | usr/src/dkms_source_tree/Makefile | 38 | ||||
| -rw-r--r-- | usr/src/dkms_source_tree/dkms.conf | 9 | ||||
| -rw-r--r-- | usr/src/dkms_source_tree/hid-core.c | 1145 | ||||
| -rw-r--r-- | usr/src/dkms_source_tree/hid-ff.c | 95 | ||||
| -rw-r--r-- | usr/src/dkms_source_tree/hid-lg2ff.c | 114 | ||||
| -rw-r--r-- | usr/src/dkms_source_tree/hid-lgff.c | 151 | ||||
| -rw-r--r-- | usr/src/dkms_source_tree/hid-pidff.c | 1332 | ||||
| -rw-r--r-- | usr/src/dkms_source_tree/hid-plff.c | 139 | ||||
| -rw-r--r-- | usr/src/dkms_source_tree/hid-quirks.c | 1224 | ||||
| -rw-r--r-- | usr/src/dkms_source_tree/hid-tmff.c | 225 | ||||
| -rw-r--r-- | usr/src/dkms_source_tree/hid-zpff.c | 107 | ||||
| -rw-r--r-- | usr/src/dkms_source_tree/hiddev.c | 893 | ||||
| -rw-r--r-- | usr/src/dkms_source_tree/patches/10-ignore-trackpad-on-unibody-macbooks.patch | 24 | ||||
| -rw-r--r-- | usr/src/dkms_source_tree/usbhid.h | 88 | ||||
| -rw-r--r-- | usr/src/dkms_source_tree/usbkbd.c | 365 | ||||
| -rw-r--r-- | usr/src/dkms_source_tree/usbmouse.c | 253 |
18 files changed, 6204 insertions, 0 deletions
diff --git a/usr/src/dkms_main_tree/dkms_dbversion b/usr/src/dkms_main_tree/dkms_dbversion new file mode 100644 index 0000000..227cea2 --- /dev/null +++ b/usr/src/dkms_main_tree/dkms_dbversion | |||
| @@ -0,0 +1 @@ | |||
| 2.0.0 | |||
diff --git a/usr/src/dkms_source_tree/KERNEL_SOURCE_VERSION b/usr/src/dkms_source_tree/KERNEL_SOURCE_VERSION new file mode 100644 index 0000000..9cd2822 --- /dev/null +++ b/usr/src/dkms_source_tree/KERNEL_SOURCE_VERSION | |||
| @@ -0,0 +1 @@ | |||
| 2.6.27-7-generic | |||
diff --git a/usr/src/dkms_source_tree/Makefile b/usr/src/dkms_source_tree/Makefile new file mode 100644 index 0000000..00a7b70 --- /dev/null +++ b/usr/src/dkms_source_tree/Makefile | |||
| @@ -0,0 +1,38 @@ | |||
| 1 | # | ||
| 2 | # Makefile for the USB input drivers | ||
| 3 | # | ||
| 4 | |||
| 5 | # Multipart objects. | ||
| 6 | usbhid-objs := hid-core.o hid-quirks.o | ||
| 7 | |||
| 8 | # Optional parts of multipart objects. | ||
| 9 | |||
| 10 | ifeq ($(CONFIG_USB_HIDDEV),y) | ||
| 11 | usbhid-objs += hiddev.o | ||
| 12 | endif | ||
| 13 | ifeq ($(CONFIG_HID_PID),y) | ||
| 14 | usbhid-objs += hid-pidff.o | ||
| 15 | endif | ||
| 16 | ifeq ($(CONFIG_LOGITECH_FF),y) | ||
| 17 | usbhid-objs += hid-lgff.o | ||
| 18 | endif | ||
| 19 | ifeq ($(CONFIG_LOGIRUMBLEPAD2_FF),y) | ||
| 20 | usbhid-objs += hid-lg2ff.o | ||
| 21 | endif | ||
| 22 | ifeq ($(CONFIG_PANTHERLORD_FF),y) | ||
| 23 | usbhid-objs += hid-plff.o | ||
| 24 | endif | ||
| 25 | ifeq ($(CONFIG_THRUSTMASTER_FF),y) | ||
| 26 | usbhid-objs += hid-tmff.o | ||
| 27 | endif | ||
| 28 | ifeq ($(CONFIG_ZEROPLUS_FF),y) | ||
| 29 | usbhid-objs += hid-zpff.o | ||
| 30 | endif | ||
| 31 | ifeq ($(CONFIG_HID_FF),y) | ||
| 32 | usbhid-objs += hid-ff.o | ||
| 33 | endif | ||
| 34 | |||
| 35 | obj-$(CONFIG_USB_HID) += usbhid.o | ||
| 36 | obj-$(CONFIG_USB_KBD) += usbkbd.o | ||
| 37 | obj-$(CONFIG_USB_MOUSE) += usbmouse.o | ||
| 38 | |||
diff --git a/usr/src/dkms_source_tree/dkms.conf b/usr/src/dkms_source_tree/dkms.conf new file mode 100644 index 0000000..34d0f25 --- /dev/null +++ b/usr/src/dkms_source_tree/dkms.conf | |||
| @@ -0,0 +1,9 @@ | |||
| 1 | NAME=usbhid | ||
| 2 | VERSION=0.10.2 | ||
| 3 | PACKAGE_NAME="$NAME" | ||
| 4 | PACKAGE_VERSION="$VERSION" | ||
| 5 | MAKE[0]="make -C ${kernel_source_dir} | ||
| 6 | SUBDIRS=${dkms_tree}/${NAME}/${VERSION}/build modules" | ||
| 7 | BUILT_MODULE_NAME[0]="usbhid" | ||
| 8 | DEST_MODULE_LOCATION[0]="/kernel/drivers/hid/usbhid" | ||
| 9 | REMAKE_INITRD=y | ||
diff --git a/usr/src/dkms_source_tree/hid-core.c b/usr/src/dkms_source_tree/hid-core.c new file mode 100644 index 0000000..27fe4d8 --- /dev/null +++ b/usr/src/dkms_source_tree/hid-core.c | |||
| @@ -0,0 +1,1145 @@ | |||
| 1 | /* | ||
| 2 | * USB HID support for Linux | ||
| 3 | * | ||
| 4 | * Copyright (c) 1999 Andreas Gal | ||
| 5 | * Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz> | ||
| 6 | * Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc | ||
| 7 | * Copyright (c) 2006-2007 Jiri Kosina | ||
| 8 | */ | ||
| 9 | |||
| 10 | /* | ||
| 11 | * This program is free software; you can redistribute it and/or modify it | ||
| 12 | * under the terms of the GNU General Public License as published by the Free | ||
| 13 | * Software Foundation; either version 2 of the License, or (at your option) | ||
| 14 | * any later version. | ||
| 15 | */ | ||
| 16 | |||
| 17 | #include <linux/module.h> | ||
| 18 | #include <linux/slab.h> | ||
| 19 | #include <linux/init.h> | ||
| 20 | #include <linux/kernel.h> | ||
| 21 | #include <linux/list.h> | ||
| 22 | #include <linux/mm.h> | ||
| 23 | #include <linux/smp_lock.h> | ||
| 24 | #include <linux/spinlock.h> | ||
| 25 | #include <asm/unaligned.h> | ||
| 26 | #include <asm/byteorder.h> | ||
| 27 | #include <linux/input.h> | ||
| 28 | #include <linux/wait.h> | ||
| 29 | |||
| 30 | #include <linux/usb.h> | ||
| 31 | |||
| 32 | #include <linux/hid.h> | ||
| 33 | #include <linux/hiddev.h> | ||
| 34 | #include <linux/hid-debug.h> | ||
| 35 | #include <linux/hidraw.h> | ||
| 36 | #include "usbhid.h" | ||
| 37 | |||
| 38 | /* | ||
| 39 | * Version Information | ||
| 40 | */ | ||
| 41 | |||
| 42 | #define DRIVER_VERSION "v2.6" | ||
| 43 | #define DRIVER_AUTHOR "Andreas Gal, Vojtech Pavlik, Jiri Kosina" | ||
| 44 | #define DRIVER_DESC "USB HID core driver" | ||
| 45 | #define DRIVER_LICENSE "GPL" | ||
| 46 | |||
| 47 | static char *hid_types[] = {"Device", "Pointer", "Mouse", "Device", "Joystick", | ||
| 48 | "Gamepad", "Keyboard", "Keypad", "Multi-Axis Controller"}; | ||
| 49 | /* | ||
| 50 | * Module parameters. | ||
| 51 | */ | ||
| 52 | |||
| 53 | static unsigned int hid_mousepoll_interval; | ||
| 54 | module_param_named(mousepoll, hid_mousepoll_interval, uint, 0644); | ||
| 55 | MODULE_PARM_DESC(mousepoll, "Polling interval of mice"); | ||
| 56 | |||
| 57 | /* Quirks specified at module load time */ | ||
| 58 | static char *quirks_param[MAX_USBHID_BOOT_QUIRKS] = { [ 0 ... (MAX_USBHID_BOOT_QUIRKS - 1) ] = NULL }; | ||
| 59 | module_param_array_named(quirks, quirks_param, charp, NULL, 0444); | ||
| 60 | MODULE_PARM_DESC(quirks, "Add/modify USB HID quirks by specifying " | ||
| 61 | " quirks=vendorID:productID:quirks" | ||
| 62 | " where vendorID, productID, and quirks are all in" | ||
| 63 | " 0x-prefixed hex"); | ||
| 64 | static char *rdesc_quirks_param[MAX_USBHID_BOOT_QUIRKS] = { [ 0 ... (MAX_USBHID_BOOT_QUIRKS - 1) ] = NULL }; | ||
| 65 | module_param_array_named(rdesc_quirks, rdesc_quirks_param, charp, NULL, 0444); | ||
| 66 | MODULE_PARM_DESC(rdesc_quirks, "Add/modify report descriptor quirks by specifying " | ||
| 67 | " rdesc_quirks=vendorID:productID:rdesc_quirks" | ||
| 68 | " where vendorID, productID, and rdesc_quirks are all in" | ||
| 69 | " 0x-prefixed hex"); | ||
| 70 | /* | ||
| 71 | * Input submission and I/O error handler. | ||
| 72 | */ | ||
| 73 | |||
| 74 | static void hid_io_error(struct hid_device *hid); | ||
| 75 | |||
| 76 | /* Start up the input URB */ | ||
| 77 | static int hid_start_in(struct hid_device *hid) | ||
| 78 | { | ||
| 79 | unsigned long flags; | ||
| 80 | int rc = 0; | ||
| 81 | struct usbhid_device *usbhid = hid->driver_data; | ||
| 82 | |||
| 83 | spin_lock_irqsave(&usbhid->inlock, flags); | ||
| 84 | if (hid->open > 0 && !test_bit(HID_SUSPENDED, &usbhid->iofl) && | ||
| 85 | !test_bit(HID_DISCONNECTED, &usbhid->iofl) && | ||
| 86 | !test_and_set_bit(HID_IN_RUNNING, &usbhid->iofl)) { | ||
| 87 | rc = usb_submit_urb(usbhid->urbin, GFP_ATOMIC); | ||
| 88 | if (rc != 0) | ||
| 89 | clear_bit(HID_IN_RUNNING, &usbhid->iofl); | ||
| 90 | } | ||
| 91 | spin_unlock_irqrestore(&usbhid->inlock, flags); | ||
| 92 | return rc; | ||
| 93 | } | ||
| 94 | |||
| 95 | /* I/O retry timer routine */ | ||
| 96 | static void hid_retry_timeout(unsigned long _hid) | ||
| 97 | { | ||
| 98 | struct hid_device *hid = (struct hid_device *) _hid; | ||
| 99 | struct usbhid_device *usbhid = hid->driver_data; | ||
| 100 | |||
| 101 | dev_dbg(&usbhid->intf->dev, "retrying intr urb\n"); | ||
| 102 | if (hid_start_in(hid)) | ||
| 103 | hid_io_error(hid); | ||
| 104 | } | ||
| 105 | |||
| 106 | /* Workqueue routine to reset the device or clear a halt */ | ||
| 107 | static void hid_reset(struct work_struct *work) | ||
| 108 | { | ||
| 109 | struct usbhid_device *usbhid = | ||
| 110 | container_of(work, struct usbhid_device, reset_work); | ||
| 111 | struct hid_device *hid = usbhid->hid; | ||
| 112 | int rc_lock, rc = 0; | ||
| 113 | |||
| 114 | if (test_bit(HID_CLEAR_HALT, &usbhid->iofl)) { | ||
| 115 | dev_dbg(&usbhid->intf->dev, "clear halt\n"); | ||
| 116 | rc = usb_clear_halt(hid_to_usb_dev(hid), usbhid->urbin->pipe); | ||
| 117 | clear_bit(HID_CLEAR_HALT, &usbhid->iofl); | ||
| 118 | hid_start_in(hid); | ||
| 119 | } | ||
| 120 | |||
| 121 | else if (test_bit(HID_RESET_PENDING, &usbhid->iofl)) { | ||
| 122 | dev_dbg(&usbhid->intf->dev, "resetting device\n"); | ||
| 123 | rc = rc_lock = usb_lock_device_for_reset(hid_to_usb_dev(hid), usbhid->intf); | ||
| 124 | if (rc_lock >= 0) { | ||
| 125 | rc = usb_reset_device(hid_to_usb_dev(hid)); | ||
| 126 | if (rc_lock) | ||
| 127 | usb_unlock_device(hid_to_usb_dev(hid)); | ||
| 128 | } | ||
| 129 | clear_bit(HID_RESET_PENDING, &usbhid->iofl); | ||
| 130 | } | ||
| 131 | |||
| 132 | switch (rc) { | ||
| 133 | case 0: | ||
| 134 | if (!test_bit(HID_IN_RUNNING, &usbhid->iofl)) | ||
| 135 | hid_io_error(hid); | ||
| 136 | break; | ||
| 137 | default: | ||
| 138 | err_hid("can't reset device, %s-%s/input%d, status %d", | ||
| 139 | hid_to_usb_dev(hid)->bus->bus_name, | ||
| 140 | hid_to_usb_dev(hid)->devpath, | ||
| 141 | usbhid->ifnum, rc); | ||
| 142 | /* FALLTHROUGH */ | ||
| 143 | case -EHOSTUNREACH: | ||
| 144 | case -ENODEV: | ||
| 145 | case -EINTR: | ||
| 146 | break; | ||
| 147 | } | ||
| 148 | } | ||
| 149 | |||
| 150 | /* Main I/O error handler */ | ||
| 151 | static void hid_io_error(struct hid_device *hid) | ||
| 152 | { | ||
| 153 | unsigned long flags; | ||
| 154 | struct usbhid_device *usbhid = hid->driver_data; | ||
| 155 | |||
| 156 | spin_lock_irqsave(&usbhid->inlock, flags); | ||
| 157 | |||
| 158 | /* Stop when disconnected */ | ||
| 159 | if (test_bit(HID_DISCONNECTED, &usbhid->iofl)) | ||
| 160 | goto done; | ||
| 161 | |||
| 162 | /* If it has been a while since the last error, we'll assume | ||
| 163 | * this a brand new error and reset the retry timeout. */ | ||
| 164 | if (time_after(jiffies, usbhid->stop_retry + HZ/2)) | ||
| 165 | usbhid->retry_delay = 0; | ||
| 166 | |||
| 167 | /* When an error occurs, retry at increasing intervals */ | ||
| 168 | if (usbhid->retry_delay == 0) { | ||
| 169 | usbhid->retry_delay = 13; /* Then 26, 52, 104, 104, ... */ | ||
| 170 | usbhid->stop_retry = jiffies + msecs_to_jiffies(1000); | ||
| 171 | } else if (usbhid->retry_delay < 100) | ||
| 172 | usbhid->retry_delay *= 2; | ||
| 173 | |||
| 174 | if (time_after(jiffies, usbhid->stop_retry)) { | ||
| 175 | |||
| 176 | /* Retries failed, so do a port reset */ | ||
| 177 | if (!test_and_set_bit(HID_RESET_PENDING, &usbhid->iofl)) { | ||
| 178 | schedule_work(&usbhid->reset_work); | ||
| 179 | goto done; | ||
| 180 | } | ||
| 181 | } | ||
| 182 | |||
| 183 | mod_timer(&usbhid->io_retry, | ||
| 184 | jiffies + msecs_to_jiffies(usbhid->retry_delay)); | ||
| 185 | done: | ||
| 186 | spin_unlock_irqrestore(&usbhid->inlock, flags); | ||
| 187 | } | ||
| 188 | |||
| 189 | /* | ||
| 190 | * Input interrupt completion handler. | ||
| 191 | */ | ||
| 192 | |||
| 193 | static void hid_irq_in(struct urb *urb) | ||
| 194 | { | ||
| 195 | struct hid_device *hid = urb->context; | ||
| 196 | struct usbhid_device *usbhid = hid->driver_data; | ||
| 197 | int status; | ||
| 198 | |||
| 199 | switch (urb->status) { | ||
| 200 | case 0: /* success */ | ||
| 201 | usbhid->retry_delay = 0; | ||
| 202 | hid_input_report(urb->context, HID_INPUT_REPORT, | ||
| 203 | urb->transfer_buffer, | ||
| 204 | urb->actual_length, 1); | ||
| 205 | break; | ||
| 206 | case -EPIPE: /* stall */ | ||
| 207 | clear_bit(HID_IN_RUNNING, &usbhid->iofl); | ||
| 208 | set_bit(HID_CLEAR_HALT, &usbhid->iofl); | ||
| 209 | schedule_work(&usbhid->reset_work); | ||
| 210 | return; | ||
| 211 | case -ECONNRESET: /* unlink */ | ||
| 212 | case -ENOENT: | ||
| 213 | case -ESHUTDOWN: /* unplug */ | ||
| 214 | clear_bit(HID_IN_RUNNING, &usbhid->iofl); | ||
| 215 | return; | ||
| 216 | case -EILSEQ: /* protocol error or unplug */ | ||
| 217 | case -EPROTO: /* protocol error or unplug */ | ||
| 218 | case -ETIME: /* protocol error or unplug */ | ||
| 219 | case -ETIMEDOUT: /* Should never happen, but... */ | ||
| 220 | clear_bit(HID_IN_RUNNING, &usbhid->iofl); | ||
| 221 | hid_io_error(hid); | ||
| 222 | return; | ||
| 223 | default: /* error */ | ||
| 224 | warn("input irq status %d received", urb->status); | ||
| 225 | } | ||
| 226 | |||
| 227 | status = usb_submit_urb(urb, GFP_ATOMIC); | ||
| 228 | if (status) { | ||
| 229 | clear_bit(HID_IN_RUNNING, &usbhid->iofl); | ||
| 230 | if (status != -EPERM) { | ||
| 231 | err_hid("can't resubmit intr, %s-%s/input%d, status %d", | ||
| 232 | hid_to_usb_dev(hid)->bus->bus_name, | ||
| 233 | hid_to_usb_dev(hid)->devpath, | ||
| 234 | usbhid->ifnum, status); | ||
| 235 | hid_io_error(hid); | ||
| 236 | } | ||
| 237 | } | ||
| 238 | } | ||
| 239 | |||
| 240 | static int hid_submit_out(struct hid_device *hid) | ||
| 241 | { | ||
| 242 | struct hid_report *report; | ||
| 243 | struct usbhid_device *usbhid = hid->driver_data; | ||
| 244 | |||
| 245 | report = usbhid->out[usbhid->outtail]; | ||
| 246 | |||
| 247 | hid_output_report(report, usbhid->outbuf); | ||
| 248 | usbhid->urbout->transfer_buffer_length = ((report->size - 1) >> 3) + 1 + (report->id > 0); | ||
| 249 | usbhid->urbout->dev = hid_to_usb_dev(hid); | ||
| 250 | |||
| 251 | dbg_hid("submitting out urb\n"); | ||
| 252 | |||
| 253 | if (usb_submit_urb(usbhid->urbout, GFP_ATOMIC)) { | ||
| 254 | err_hid("usb_submit_urb(out) failed"); | ||
| 255 | return -1; | ||
| 256 | } | ||
| 257 | |||
| 258 | return 0; | ||
| 259 | } | ||
| 260 | |||
| 261 | static int hid_submit_ctrl(struct hid_device *hid) | ||
| 262 | { | ||
| 263 | struct hid_report *report; | ||
| 264 | unsigned char dir; | ||
| 265 | int len; | ||
| 266 | struct usbhid_device *usbhid = hid->driver_data; | ||
| 267 | |||
| 268 | report = usbhid->ctrl[usbhid->ctrltail].report; | ||
| 269 | dir = usbhid->ctrl[usbhid->ctrltail].dir; | ||
| 270 | |||
| 271 | len = ((report->size - 1) >> 3) + 1 + (report->id > 0); | ||
| 272 | if (dir == USB_DIR_OUT) { | ||
| 273 | hid_output_report(report, usbhid->ctrlbuf); | ||
| 274 | usbhid->urbctrl->pipe = usb_sndctrlpipe(hid_to_usb_dev(hid), 0); | ||
| 275 | usbhid->urbctrl->transfer_buffer_length = len; | ||
| 276 | } else { | ||
| 277 | int maxpacket, padlen; | ||
| 278 | |||
| 279 | usbhid->urbctrl->pipe = usb_rcvctrlpipe(hid_to_usb_dev(hid), 0); | ||
| 280 | maxpacket = usb_maxpacket(hid_to_usb_dev(hid), usbhid->urbctrl->pipe, 0); | ||
| 281 | if (maxpacket > 0) { | ||
| 282 | padlen = DIV_ROUND_UP(len, maxpacket); | ||
| 283 | padlen *= maxpacket; | ||
| 284 | if (padlen > usbhid->bufsize) | ||
| 285 | padlen = usbhid->bufsize; | ||
| 286 | } else | ||
| 287 | padlen = 0; | ||
| 288 | usbhid->urbctrl->transfer_buffer_length = padlen; | ||
| 289 | } | ||
| 290 | usbhid->urbctrl->dev = hid_to_usb_dev(hid); | ||
| 291 | |||
| 292 | usbhid->cr->bRequestType = USB_TYPE_CLASS | USB_RECIP_INTERFACE | dir; | ||
| 293 | usbhid->cr->bRequest = (dir == USB_DIR_OUT) ? HID_REQ_SET_REPORT : HID_REQ_GET_REPORT; | ||
| 294 | usbhid->cr->wValue = cpu_to_le16(((report->type + 1) << 8) | report->id); | ||
| 295 | usbhid->cr->wIndex = cpu_to_le16(usbhid->ifnum); | ||
| 296 | usbhid->cr->wLength = cpu_to_le16(len); | ||
| 297 | |||
| 298 | dbg_hid("submitting ctrl urb: %s wValue=0x%04x wIndex=0x%04x wLength=%u\n", | ||
| 299 | usbhid->cr->bRequest == HID_REQ_SET_REPORT ? "Set_Report" : "Get_Report", | ||
| 300 | usbhid->cr->wValue, usbhid->cr->wIndex, usbhid->cr->wLength); | ||
| 301 | |||
| 302 | if (usb_submit_urb(usbhid->urbctrl, GFP_ATOMIC)) { | ||
| 303 | err_hid("usb_submit_urb(ctrl) failed"); | ||
| 304 | return -1; | ||
| 305 | } | ||
| 306 | |||
| 307 | return 0; | ||
| 308 | } | ||
| 309 | |||
| 310 | /* | ||
| 311 | * Output interrupt completion handler. | ||
| 312 | */ | ||
| 313 | |||
| 314 | static void hid_irq_out(struct urb *urb) | ||
| 315 | { | ||
| 316 | struct hid_device *hid = urb->context; | ||
| 317 | struct usbhid_device *usbhid = hid->driver_data; | ||
| 318 | unsigned long flags; | ||
| 319 | int unplug = 0; | ||
| 320 | |||
| 321 | switch (urb->status) { | ||
| 322 | case 0: /* success */ | ||
| 323 | break; | ||
| 324 | case -ESHUTDOWN: /* unplug */ | ||
| 325 | unplug = 1; | ||
| 326 | case -EILSEQ: /* protocol error or unplug */ | ||
| 327 | case -EPROTO: /* protocol error or unplug */ | ||
| 328 | case -ECONNRESET: /* unlink */ | ||
| 329 | case -ENOENT: | ||
| 330 | break; | ||
| 331 | default: /* error */ | ||
| 332 | warn("output irq status %d received", urb->status); | ||
| 333 | } | ||
| 334 | |||
| 335 | spin_lock_irqsave(&usbhid->outlock, flags); | ||
| 336 | |||
| 337 | if (unplug) | ||
| 338 | usbhid->outtail = usbhid->outhead; | ||
| 339 | else | ||
| 340 | usbhid->outtail = (usbhid->outtail + 1) & (HID_OUTPUT_FIFO_SIZE - 1); | ||
| 341 | |||
| 342 | if (usbhid->outhead != usbhid->outtail) { | ||
| 343 | if (hid_submit_out(hid)) { | ||
| 344 | clear_bit(HID_OUT_RUNNING, &usbhid->iofl); | ||
| 345 | wake_up(&usbhid->wait); | ||
| 346 | } | ||
| 347 | spin_unlock_irqrestore(&usbhid->outlock, flags); | ||
| 348 | return; | ||
| 349 | } | ||
| 350 | |||
| 351 | clear_bit(HID_OUT_RUNNING, &usbhid->iofl); | ||
| 352 | spin_unlock_irqrestore(&usbhid->outlock, flags); | ||
| 353 | wake_up(&usbhid->wait); | ||
| 354 | } | ||
| 355 | |||
| 356 | /* | ||
| 357 | * Control pipe completion handler. | ||
| 358 | */ | ||
| 359 | |||
| 360 | static void hid_ctrl(struct urb *urb) | ||
| 361 | { | ||
| 362 | struct hid_device *hid = urb->context; | ||
| 363 | struct usbhid_device *usbhid = hid->driver_data; | ||
| 364 | unsigned long flags; | ||
| 365 | int unplug = 0; | ||
| 366 | |||
| 367 | spin_lock_irqsave(&usbhid->ctrllock, flags); | ||
| 368 | |||
| 369 | switch (urb->status) { | ||
| 370 | case 0: /* success */ | ||
| 371 | if (usbhid->ctrl[usbhid->ctrltail].dir == USB_DIR_IN) | ||
| 372 | hid_input_report(urb->context, usbhid->ctrl[usbhid->ctrltail].report->type, | ||
| 373 | urb->transfer_buffer, urb->actual_length, 0); | ||
| 374 | break; | ||
| 375 | case -ESHUTDOWN: /* unplug */ | ||
| 376 | unplug = 1; | ||
| 377 | case -EILSEQ: /* protocol error or unplug */ | ||
| 378 | case -EPROTO: /* protocol error or unplug */ | ||
| 379 | case -ECONNRESET: /* unlink */ | ||
| 380 | case -ENOENT: | ||
| 381 | case -EPIPE: /* report not available */ | ||
| 382 | break; | ||
| 383 | default: /* error */ | ||
| 384 | warn("ctrl urb status %d received", urb->status); | ||
| 385 | } | ||
| 386 | |||
| 387 | if (unplug) | ||
| 388 | usbhid->ctrltail = usbhid->ctrlhead; | ||
| 389 | else | ||
| 390 | usbhid->ctrltail = (usbhid->ctrltail + 1) & (HID_CONTROL_FIFO_SIZE - 1); | ||
| 391 | |||
| 392 | if (usbhid->ctrlhead != usbhid->ctrltail) { | ||
| 393 | if (hid_submit_ctrl(hid)) { | ||
| 394 | clear_bit(HID_CTRL_RUNNING, &usbhid->iofl); | ||
| 395 | wake_up(&usbhid->wait); | ||
| 396 | } | ||
| 397 | spin_unlock_irqrestore(&usbhid->ctrllock, flags); | ||
| 398 | return; | ||
| 399 | } | ||
| 400 | |||
| 401 | clear_bit(HID_CTRL_RUNNING, &usbhid->iofl); | ||
| 402 | spin_unlock_irqrestore(&usbhid->ctrllock, flags); | ||
| 403 | wake_up(&usbhid->wait); | ||
| 404 | } | ||
| 405 | |||
| 406 | void usbhid_submit_report(struct hid_device *hid, struct hid_report *report, unsigned char dir) | ||
| 407 | { | ||
| 408 | int head; | ||
| 409 | unsigned long flags; | ||
| 410 | struct usbhid_device *usbhid = hid->driver_data; | ||
| 411 | |||
| 412 | if ((hid->quirks & HID_QUIRK_NOGET) && dir == USB_DIR_IN) | ||
| 413 | return; | ||
| 414 | |||
| 415 | if (usbhid->urbout && dir == USB_DIR_OUT && report->type == HID_OUTPUT_REPORT) { | ||
| 416 | |||
| 417 | spin_lock_irqsave(&usbhid->outlock, flags); | ||
| 418 | |||
| 419 | if ((head = (usbhid->outhead + 1) & (HID_OUTPUT_FIFO_SIZE - 1)) == usbhid->outtail) { | ||
| 420 | spin_unlock_irqrestore(&usbhid->outlock, flags); | ||
| 421 | warn("output queue full"); | ||
| 422 | return; | ||
| 423 | } | ||
| 424 | |||
| 425 | usbhid->out[usbhid->outhead] = report; | ||
| 426 | usbhid->outhead = head; | ||
| 427 | |||
| 428 | if (!test_and_set_bit(HID_OUT_RUNNING, &usbhid->iofl)) | ||
| 429 | if (hid_submit_out(hid)) | ||
| 430 | clear_bit(HID_OUT_RUNNING, &usbhid->iofl); | ||
| 431 | |||
| 432 | spin_unlock_irqrestore(&usbhid->outlock, flags); | ||
| 433 | return; | ||
| 434 | } | ||
| 435 | |||
| 436 | spin_lock_irqsave(&usbhid->ctrllock, flags); | ||
| 437 | |||
| 438 | if ((head = (usbhid->ctrlhead + 1) & (HID_CONTROL_FIFO_SIZE - 1)) == usbhid->ctrltail) { | ||
| 439 | spin_unlock_irqrestore(&usbhid->ctrllock, flags); | ||
| 440 | warn("control queue full"); | ||
| 441 | return; | ||
| 442 | } | ||
| 443 | |||
| 444 | usbhid->ctrl[usbhid->ctrlhead].report = report; | ||
| 445 | usbhid->ctrl[usbhid->ctrlhead].dir = dir; | ||
| 446 | usbhid->ctrlhead = head; | ||
| 447 | |||
| 448 | if (!test_and_set_bit(HID_CTRL_RUNNING, &usbhid->iofl)) | ||
| 449 | if (hid_submit_ctrl(hid)) | ||
| 450 | clear_bit(HID_CTRL_RUNNING, &usbhid->iofl); | ||
| 451 | |||
| 452 | spin_unlock_irqrestore(&usbhid->ctrllock, flags); | ||
| 453 | } | ||
| 454 | |||
| 455 | static int usb_hidinput_input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) | ||
| 456 | { | ||
| 457 | struct hid_device *hid = input_get_drvdata(dev); | ||
| 458 | struct hid_field *field; | ||
| 459 | int offset; | ||
| 460 | |||
| 461 | if (type == EV_FF) | ||
| 462 | return input_ff_event(dev, type, code, value); | ||
| 463 | |||
| 464 | if (type != EV_LED) | ||
| 465 | return -1; | ||
| 466 | |||
| 467 | if ((offset = hidinput_find_field(hid, type, code, &field)) == -1) { | ||
| 468 | warn("event field not found"); | ||
| 469 | return -1; | ||
| 470 | } | ||
| 471 | |||
| 472 | hid_set_field(field, offset, value); | ||
| 473 | usbhid_submit_report(hid, field->report, USB_DIR_OUT); | ||
| 474 | |||
| 475 | return 0; | ||
| 476 | } | ||
| 477 | |||
| 478 | int usbhid_wait_io(struct hid_device *hid) | ||
| 479 | { | ||
| 480 | struct usbhid_device *usbhid = hid->driver_data; | ||
| 481 | |||
| 482 | if (!wait_event_timeout(usbhid->wait, | ||
| 483 | (!test_bit(HID_CTRL_RUNNING, &usbhid->iofl) && | ||
| 484 | !test_bit(HID_OUT_RUNNING, &usbhid->iofl)), | ||
| 485 | 10*HZ)) { | ||
| 486 | dbg_hid("timeout waiting for ctrl or out queue to clear\n"); | ||
| 487 | return -1; | ||
| 488 | } | ||
| 489 | |||
| 490 | return 0; | ||
| 491 | } | ||
| 492 | |||
| 493 | static int hid_set_idle(struct usb_device *dev, int ifnum, int report, int idle) | ||
| 494 | { | ||
| 495 | return usb_control_msg(dev, usb_sndctrlpipe(dev, 0), | ||
| 496 | HID_REQ_SET_IDLE, USB_TYPE_CLASS | USB_RECIP_INTERFACE, (idle << 8) | report, | ||
| 497 | ifnum, NULL, 0, USB_CTRL_SET_TIMEOUT); | ||
| 498 | } | ||
| 499 | |||
| 500 | static int hid_get_class_descriptor(struct usb_device *dev, int ifnum, | ||
| 501 | unsigned char type, void *buf, int size) | ||
| 502 | { | ||
| 503 | int result, retries = 4; | ||
| 504 | |||
| 505 | memset(buf, 0, size); | ||
| 506 | |||
| 507 | do { | ||
| 508 | result = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), | ||
| 509 | USB_REQ_GET_DESCRIPTOR, USB_RECIP_INTERFACE | USB_DIR_IN, | ||
| 510 | (type << 8), ifnum, buf, size, USB_CTRL_GET_TIMEOUT); | ||
| 511 | retries--; | ||
| 512 | } while (result < size && retries); | ||
| 513 | return result; | ||
| 514 | } | ||
| 515 | |||
| 516 | int usbhid_open(struct hid_device *hid) | ||
| 517 | { | ||
| 518 | struct usbhid_device *usbhid = hid->driver_data; | ||
| 519 | int res; | ||
| 520 | |||
| 521 | if (!hid->open++) { | ||
| 522 | res = usb_autopm_get_interface(usbhid->intf); | ||
| 523 | if (res < 0) { | ||
| 524 | hid->open--; | ||
| 525 | return -EIO; | ||
| 526 | } | ||
| 527 | } | ||
| 528 | if (hid_start_in(hid)) | ||
| 529 | hid_io_error(hid); | ||
| 530 | return 0; | ||
| 531 | } | ||
| 532 | |||
| 533 | void usbhid_close(struct hid_device *hid) | ||
| 534 | { | ||
| 535 | struct usbhid_device *usbhid = hid->driver_data; | ||
| 536 | |||
| 537 | if (!--hid->open) { | ||
| 538 | usb_kill_urb(usbhid->urbin); | ||
| 539 | usb_autopm_put_interface(usbhid->intf); | ||
| 540 | } | ||
| 541 | } | ||
| 542 | |||
| 543 | /* | ||
| 544 | * Initialize all reports | ||
| 545 | */ | ||
| 546 | |||
| 547 | void usbhid_init_reports(struct hid_device *hid) | ||
| 548 | { | ||
| 549 | struct hid_report *report; | ||
| 550 | struct usbhid_device *usbhid = hid->driver_data; | ||
| 551 | int err, ret; | ||
| 552 | |||
| 553 | list_for_each_entry(report, &hid->report_enum[HID_INPUT_REPORT].report_list, list) | ||
| 554 | usbhid_submit_report(hid, report, USB_DIR_IN); | ||
| 555 | |||
| 556 | list_for_each_entry(report, &hid->report_enum[HID_FEATURE_REPORT].report_list, list) | ||
| 557 | usbhid_submit_report(hid, report, USB_DIR_IN); | ||
| 558 | |||
| 559 | err = 0; | ||
| 560 | ret = usbhid_wait_io(hid); | ||
| 561 | while (ret) { | ||
| 562 | err |= ret; | ||
| 563 | if (test_bit(HID_CTRL_RUNNING, &usbhid->iofl)) | ||
| 564 | usb_kill_urb(usbhid->urbctrl); | ||
| 565 | if (test_bit(HID_OUT_RUNNING, &usbhid->iofl)) | ||
| 566 | usb_kill_urb(usbhid->urbout); | ||
| 567 | ret = usbhid_wait_io(hid); | ||
| 568 | } | ||
| 569 | |||
| 570 | if (err) | ||
| 571 | warn("timeout initializing reports"); | ||
| 572 | } | ||
| 573 | |||
| 574 | /* | ||
| 575 | * Reset LEDs which BIOS might have left on. For now, just NumLock (0x01). | ||
| 576 | */ | ||
| 577 | static int hid_find_field_early(struct hid_device *hid, unsigned int page, | ||
| 578 | unsigned int hid_code, struct hid_field **pfield) | ||
| 579 | { | ||
| 580 | struct hid_report *report; | ||
| 581 | struct hid_field *field; | ||
| 582 | struct hid_usage *usage; | ||
| 583 | int i, j; | ||
| 584 | |||
| 585 | list_for_each_entry(report, &hid->report_enum[HID_OUTPUT_REPORT].report_list, list) { | ||
| 586 | for (i = 0; i < report->maxfield; i++) { | ||
| 587 | field = report->field[i]; | ||
| 588 | for (j = 0; j < field->maxusage; j++) { | ||
| 589 | usage = &field->usage[j]; | ||
| 590 | if ((usage->hid & HID_USAGE_PAGE) == page && | ||
| 591 | (usage->hid & 0xFFFF) == hid_code) { | ||
| 592 | *pfield = field; | ||
| 593 | return j; | ||
| 594 | } | ||
| 595 | } | ||
| 596 | } | ||
| 597 | } | ||
| 598 | return -1; | ||
| 599 | } | ||
| 600 | |||
| 601 | static void usbhid_set_leds(struct hid_device *hid) | ||
| 602 | { | ||
| 603 | struct hid_field *field; | ||
| 604 | int offset; | ||
| 605 | |||
| 606 | if ((offset = hid_find_field_early(hid, HID_UP_LED, 0x01, &field)) != -1) { | ||
| 607 | hid_set_field(field, offset, 0); | ||
| 608 | usbhid_submit_report(hid, field->report, USB_DIR_OUT); | ||
| 609 | } | ||
| 610 | } | ||
| 611 | |||
| 612 | /* | ||
| 613 | * Traverse the supplied list of reports and find the longest | ||
| 614 | */ | ||
| 615 | static void hid_find_max_report(struct hid_device *hid, unsigned int type, | ||
| 616 | unsigned int *max) | ||
| 617 | { | ||
| 618 | struct hid_report *report; | ||
| 619 | unsigned int size; | ||
| 620 | |||
| 621 | list_for_each_entry(report, &hid->report_enum[type].report_list, list) { | ||
| 622 | size = ((report->size - 1) >> 3) + 1; | ||
| 623 | if (type == HID_INPUT_REPORT && hid->report_enum[type].numbered) | ||
| 624 | size++; | ||
| 625 | if (*max < size) | ||
| 626 | *max = size; | ||
| 627 | } | ||
| 628 | } | ||
| 629 | |||
| 630 | static int hid_alloc_buffers(struct usb_device *dev, struct hid_device *hid) | ||
| 631 | { | ||
| 632 | struct usbhid_device *usbhid = hid->driver_data; | ||
| 633 | |||
| 634 | if (!(usbhid->inbuf = usb_buffer_alloc(dev, usbhid->bufsize, GFP_ATOMIC, &usbhid->inbuf_dma))) | ||
| 635 | return -1; | ||
| 636 | if (!(usbhid->outbuf = usb_buffer_alloc(dev, usbhid->bufsize, GFP_ATOMIC, &usbhid->outbuf_dma))) | ||
| 637 | return -1; | ||
| 638 | if (!(usbhid->cr = usb_buffer_alloc(dev, sizeof(*(usbhid->cr)), GFP_ATOMIC, &usbhid->cr_dma))) | ||
| 639 | return -1; | ||
| 640 | if (!(usbhid->ctrlbuf = usb_buffer_alloc(dev, usbhid->bufsize, GFP_ATOMIC, &usbhid->ctrlbuf_dma))) | ||
| 641 | return -1; | ||
| 642 | |||
| 643 | return 0; | ||
| 644 | } | ||
| 645 | |||
| 646 | static int usbhid_output_raw_report(struct hid_device *hid, __u8 *buf, size_t count) | ||
| 647 | { | ||
| 648 | struct usbhid_device *usbhid = hid->driver_data; | ||
| 649 | struct usb_device *dev = hid_to_usb_dev(hid); | ||
| 650 | struct usb_interface *intf = usbhid->intf; | ||
| 651 | struct usb_host_interface *interface = intf->cur_altsetting; | ||
| 652 | int ret; | ||
| 653 | |||
| 654 | ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), | ||
| 655 | HID_REQ_SET_REPORT, | ||
| 656 | USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE, | ||
| 657 | ((HID_OUTPUT_REPORT + 1) << 8) | *buf, | ||
| 658 | interface->desc.bInterfaceNumber, buf + 1, count - 1, | ||
| 659 | USB_CTRL_SET_TIMEOUT); | ||
| 660 | |||
| 661 | /* count also the report id */ | ||
| 662 | if (ret > 0) | ||
| 663 | ret++; | ||
| 664 | |||
| 665 | return ret; | ||
| 666 | } | ||
| 667 | |||
| 668 | static void hid_free_buffers(struct usb_device *dev, struct hid_device *hid) | ||
| 669 | { | ||
| 670 | struct usbhid_device *usbhid = hid->driver_data; | ||
| 671 | |||
| 672 | usb_buffer_free(dev, usbhid->bufsize, usbhid->inbuf, usbhid->inbuf_dma); | ||
| 673 | usb_buffer_free(dev, usbhid->bufsize, usbhid->outbuf, usbhid->outbuf_dma); | ||
| 674 | usb_buffer_free(dev, sizeof(*(usbhid->cr)), usbhid->cr, usbhid->cr_dma); | ||
| 675 | usb_buffer_free(dev, usbhid->bufsize, usbhid->ctrlbuf, usbhid->ctrlbuf_dma); | ||
| 676 | } | ||
| 677 | |||
| 678 | /* | ||
| 679 | * Sending HID_REQ_GET_REPORT changes the operation mode of the ps3 controller | ||
| 680 | * to "operational". Without this, the ps3 controller will not report any | ||
| 681 | * events. | ||
| 682 | */ | ||
| 683 | static void hid_fixup_sony_ps3_controller(struct usb_device *dev, int ifnum) | ||
| 684 | { | ||
| 685 | int result; | ||
| 686 | char *buf = kmalloc(18, GFP_KERNEL); | ||
| 687 | |||
| 688 | if (!buf) | ||
| 689 | return; | ||
| 690 | |||
| 691 | result = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), | ||
| 692 | HID_REQ_GET_REPORT, | ||
| 693 | USB_DIR_IN | USB_TYPE_CLASS | | ||
| 694 | USB_RECIP_INTERFACE, | ||
| 695 | (3 << 8) | 0xf2, ifnum, buf, 17, | ||
| 696 | USB_CTRL_GET_TIMEOUT); | ||
| 697 | |||
| 698 | if (result < 0) | ||
| 699 | err_hid("%s failed: %d\n", __func__, result); | ||
| 700 | |||
| 701 | kfree(buf); | ||
| 702 | } | ||
| 703 | |||
| 704 | static struct hid_device *usb_hid_configure(struct usb_interface *intf) | ||
| 705 | { | ||
| 706 | struct usb_host_interface *interface = intf->cur_altsetting; | ||
| 707 | struct usb_device *dev = interface_to_usbdev (intf); | ||
| 708 | struct hid_descriptor *hdesc; | ||
| 709 | struct hid_device *hid; | ||
| 710 | u32 quirks = 0; | ||
| 711 | unsigned int insize = 0, rsize = 0; | ||
| 712 | char *rdesc; | ||
| 713 | int n, len; | ||
| 714 | struct usbhid_device *usbhid; | ||
| 715 | |||
| 716 | quirks = usbhid_lookup_quirk(le16_to_cpu(dev->descriptor.idVendor), | ||
| 717 | le16_to_cpu(dev->descriptor.idProduct)); | ||
| 718 | |||
| 719 | /* Many keyboards and mice don't like to be polled for reports, | ||
| 720 | * so we will always set the HID_QUIRK_NOGET flag for them. */ | ||
| 721 | if (interface->desc.bInterfaceSubClass == USB_INTERFACE_SUBCLASS_BOOT) { | ||
| 722 | if (interface->desc.bInterfaceProtocol == USB_INTERFACE_PROTOCOL_KEYBOARD || | ||
| 723 | interface->desc.bInterfaceProtocol == USB_INTERFACE_PROTOCOL_MOUSE) | ||
| 724 | quirks |= HID_QUIRK_NOGET; | ||
| 725 | } | ||
| 726 | |||
| 727 | if (quirks & HID_QUIRK_IGNORE) | ||
| 728 | return NULL; | ||
| 729 | |||
| 730 | if ((quirks & HID_QUIRK_IGNORE_MOUSE) && | ||
| 731 | (interface->desc.bInterfaceProtocol == USB_INTERFACE_PROTOCOL_MOUSE)) | ||
| 732 | return NULL; | ||
| 733 | |||
| 734 | |||
| 735 | if (usb_get_extra_descriptor(interface, HID_DT_HID, &hdesc) && | ||
| 736 | (!interface->desc.bNumEndpoints || | ||
| 737 | usb_get_extra_descriptor(&interface->endpoint[0], HID_DT_HID, &hdesc))) { | ||
| 738 | dbg_hid("class descriptor not present\n"); | ||
| 739 | return NULL; | ||
| 740 | } | ||
| 741 | |||
| 742 | for (n = 0; n < hdesc->bNumDescriptors; n++) | ||
| 743 | if (hdesc->desc[n].bDescriptorType == HID_DT_REPORT) | ||
| 744 | rsize = le16_to_cpu(hdesc->desc[n].wDescriptorLength); | ||
| 745 | |||
| 746 | if (!rsize || rsize > HID_MAX_DESCRIPTOR_SIZE) { | ||
| 747 | dbg_hid("weird size of report descriptor (%u)\n", rsize); | ||
| 748 | return NULL; | ||
| 749 | } | ||
| 750 | |||
| 751 | if (!(rdesc = kmalloc(rsize, GFP_KERNEL))) { | ||
| 752 | dbg_hid("couldn't allocate rdesc memory\n"); | ||
| 753 | return NULL; | ||
| 754 | } | ||
| 755 | |||
| 756 | hid_set_idle(dev, interface->desc.bInterfaceNumber, 0, 0); | ||
| 757 | |||
| 758 | if ((n = hid_get_class_descriptor(dev, interface->desc.bInterfaceNumber, HID_DT_REPORT, rdesc, rsize)) < 0) { | ||
| 759 | dbg_hid("reading report descriptor failed\n"); | ||
| 760 | kfree(rdesc); | ||
| 761 | return NULL; | ||
| 762 | } | ||
| 763 | |||
| 764 | usbhid_fixup_report_descriptor(le16_to_cpu(dev->descriptor.idVendor), | ||
| 765 | le16_to_cpu(dev->descriptor.idProduct), rdesc, | ||
| 766 | rsize, rdesc_quirks_param); | ||
| 767 | |||
| 768 | dbg_hid("report descriptor (size %u, read %d) = ", rsize, n); | ||
| 769 | for (n = 0; n < rsize; n++) | ||
| 770 | dbg_hid_line(" %02x", (unsigned char) rdesc[n]); | ||
| 771 | dbg_hid_line("\n"); | ||
| 772 | |||
| 773 | if (!(hid = hid_parse_report(rdesc, n))) { | ||
| 774 | dbg_hid("parsing report descriptor failed\n"); | ||
| 775 | kfree(rdesc); | ||
| 776 | return NULL; | ||
| 777 | } | ||
| 778 | |||
| 779 | kfree(rdesc); | ||
| 780 | hid->quirks = quirks; | ||
| 781 | |||
| 782 | if (!(usbhid = kzalloc(sizeof(struct usbhid_device), GFP_KERNEL))) | ||
| 783 | goto fail_no_usbhid; | ||
| 784 | |||
| 785 | hid->driver_data = usbhid; | ||
| 786 | usbhid->hid = hid; | ||
| 787 | |||
| 788 | usbhid->bufsize = HID_MIN_BUFFER_SIZE; | ||
| 789 | hid_find_max_report(hid, HID_INPUT_REPORT, &usbhid->bufsize); | ||
| 790 | hid_find_max_report(hid, HID_OUTPUT_REPORT, &usbhid->bufsize); | ||
| 791 | hid_find_max_report(hid, HID_FEATURE_REPORT, &usbhid->bufsize); | ||
| 792 | |||
| 793 | if (usbhid->bufsize > HID_MAX_BUFFER_SIZE) | ||
| 794 | usbhid->bufsize = HID_MAX_BUFFER_SIZE; | ||
| 795 | |||
| 796 | hid_find_max_report(hid, HID_INPUT_REPORT, &insize); | ||
| 797 | |||
| 798 | if (insize > HID_MAX_BUFFER_SIZE) | ||
| 799 | insize = HID_MAX_BUFFER_SIZE; | ||
| 800 | |||
| 801 | if (hid_alloc_buffers(dev, hid)) { | ||
| 802 | hid_free_buffers(dev, hid); | ||
| 803 | goto fail; | ||
| 804 | } | ||
| 805 | |||
| 806 | hid->name[0] = 0; | ||
| 807 | |||
| 808 | if (dev->manufacturer) | ||
| 809 | strlcpy(hid->name, dev->manufacturer, sizeof(hid->name)); | ||
| 810 | |||
| 811 | if (dev->product) { | ||
| 812 | if (dev->manufacturer) | ||
| 813 | strlcat(hid->name, " ", sizeof(hid->name)); | ||
| 814 | strlcat(hid->name, dev->product, sizeof(hid->name)); | ||
| 815 | } | ||
| 816 | |||
| 817 | if (!strlen(hid->name)) | ||
| 818 | snprintf(hid->name, sizeof(hid->name), "HID %04x:%04x", | ||
| 819 | le16_to_cpu(dev->descriptor.idVendor), | ||
| 820 | le16_to_cpu(dev->descriptor.idProduct)); | ||
| 821 | |||
| 822 | for (n = 0; n < interface->desc.bNumEndpoints; n++) { | ||
| 823 | |||
| 824 | struct usb_endpoint_descriptor *endpoint; | ||
| 825 | int pipe; | ||
| 826 | int interval; | ||
| 827 | |||
| 828 | endpoint = &interface->endpoint[n].desc; | ||
| 829 | if ((endpoint->bmAttributes & 3) != 3) /* Not an interrupt endpoint */ | ||
| 830 | continue; | ||
| 831 | |||
| 832 | interval = endpoint->bInterval; | ||
| 833 | |||
| 834 | /* Some vendors give fullspeed interval on highspeed devides */ | ||
| 835 | if (quirks & HID_QUIRK_FULLSPEED_INTERVAL && | ||
| 836 | dev->speed == USB_SPEED_HIGH) { | ||
| 837 | interval = fls(endpoint->bInterval*8); | ||
| 838 | printk(KERN_INFO "%s: Fixing fullspeed to highspeed interval: %d -> %d\n", | ||
| 839 | hid->name, endpoint->bInterval, interval); | ||
| 840 | } | ||
| 841 | |||
| 842 | /* Change the polling interval of mice. */ | ||
| 843 | if (hid->collection->usage == HID_GD_MOUSE && hid_mousepoll_interval > 0) | ||
| 844 | interval = hid_mousepoll_interval; | ||
| 845 | |||
| 846 | if (usb_endpoint_dir_in(endpoint)) { | ||
| 847 | if (usbhid->urbin) | ||
| 848 | continue; | ||
| 849 | if (!(usbhid->urbin = usb_alloc_urb(0, GFP_KERNEL))) | ||
| 850 | goto fail; | ||
| 851 | pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress); | ||
| 852 | usb_fill_int_urb(usbhid->urbin, dev, pipe, usbhid->inbuf, insize, | ||
| 853 | hid_irq_in, hid, interval); | ||
| 854 | usbhid->urbin->transfer_dma = usbhid->inbuf_dma; | ||
| 855 | usbhid->urbin->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; | ||
| 856 | } else { | ||
| 857 | if (usbhid->urbout) | ||
| 858 | continue; | ||
| 859 | if (!(usbhid->urbout = usb_alloc_urb(0, GFP_KERNEL))) | ||
| 860 | goto fail; | ||
| 861 | pipe = usb_sndintpipe(dev, endpoint->bEndpointAddress); | ||
| 862 | usb_fill_int_urb(usbhid->urbout, dev, pipe, usbhid->outbuf, 0, | ||
| 863 | hid_irq_out, hid, interval); | ||
| 864 | usbhid->urbout->transfer_dma = usbhid->outbuf_dma; | ||
| 865 | usbhid->urbout->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; | ||
| 866 | } | ||
| 867 | } | ||
| 868 | |||
| 869 | if (!usbhid->urbin) { | ||
| 870 | err_hid("couldn't find an input interrupt endpoint"); | ||
| 871 | goto fail; | ||
| 872 | } | ||
| 873 | |||
| 874 | init_waitqueue_head(&usbhid->wait); | ||
| 875 | INIT_WORK(&usbhid->reset_work, hid_reset); | ||
| 876 | setup_timer(&usbhid->io_retry, hid_retry_timeout, (unsigned long) hid); | ||
| 877 | |||
| 878 | spin_lock_init(&usbhid->inlock); | ||
| 879 | spin_lock_init(&usbhid->outlock); | ||
| 880 | spin_lock_init(&usbhid->ctrllock); | ||
| 881 | |||
| 882 | hid->version = le16_to_cpu(hdesc->bcdHID); | ||
| 883 | hid->country = hdesc->bCountryCode; | ||
| 884 | hid->dev = &intf->dev; | ||
| 885 | usbhid->intf = intf; | ||
| 886 | usbhid->ifnum = interface->desc.bInterfaceNumber; | ||
| 887 | |||
| 888 | hid->bus = BUS_USB; | ||
| 889 | hid->vendor = le16_to_cpu(dev->descriptor.idVendor); | ||
| 890 | hid->product = le16_to_cpu(dev->descriptor.idProduct); | ||
| 891 | |||
| 892 | usb_make_path(dev, hid->phys, sizeof(hid->phys)); | ||
| 893 | strlcat(hid->phys, "/input", sizeof(hid->phys)); | ||
| 894 | len = strlen(hid->phys); | ||
| 895 | if (len < sizeof(hid->phys) - 1) | ||
| 896 | snprintf(hid->phys + len, sizeof(hid->phys) - len, | ||
| 897 | "%d", intf->altsetting[0].desc.bInterfaceNumber); | ||
| 898 | |||
| 899 | if (usb_string(dev, dev->descriptor.iSerialNumber, hid->uniq, 64) <= 0) | ||
| 900 | hid->uniq[0] = 0; | ||
| 901 | |||
| 902 | usbhid->urbctrl = usb_alloc_urb(0, GFP_KERNEL); | ||
| 903 | if (!usbhid->urbctrl) | ||
| 904 | goto fail; | ||
| 905 | |||
| 906 | usb_fill_control_urb(usbhid->urbctrl, dev, 0, (void *) usbhid->cr, | ||
| 907 | usbhid->ctrlbuf, 1, hid_ctrl, hid); | ||
| 908 | usbhid->urbctrl->setup_dma = usbhid->cr_dma; | ||
| 909 | usbhid->urbctrl->transfer_dma = usbhid->ctrlbuf_dma; | ||
| 910 | usbhid->urbctrl->transfer_flags |= (URB_NO_TRANSFER_DMA_MAP | URB_NO_SETUP_DMA_MAP); | ||
| 911 | hid->hidinput_input_event = usb_hidinput_input_event; | ||
| 912 | hid->hid_open = usbhid_open; | ||
| 913 | hid->hid_close = usbhid_close; | ||
| 914 | #ifdef CONFIG_USB_HIDDEV | ||
| 915 | hid->hiddev_hid_event = hiddev_hid_event; | ||
| 916 | hid->hiddev_report_event = hiddev_report_event; | ||
| 917 | #endif | ||
| 918 | hid->hid_output_raw_report = usbhid_output_raw_report; | ||
| 919 | return hid; | ||
| 920 | |||
| 921 | fail: | ||
| 922 | usb_free_urb(usbhid->urbin); | ||
| 923 | usb_free_urb(usbhid->urbout); | ||
| 924 | usb_free_urb(usbhid->urbctrl); | ||
| 925 | hid_free_buffers(dev, hid); | ||
| 926 | kfree(usbhid); | ||
| 927 | fail_no_usbhid: | ||
| 928 | hid_free_device(hid); | ||
| 929 | |||
| 930 | return NULL; | ||
| 931 | } | ||
| 932 | |||
| 933 | static void hid_disconnect(struct usb_interface *intf) | ||
| 934 | { | ||
| 935 | struct hid_device *hid = usb_get_intfdata (intf); | ||
| 936 | struct usbhid_device *usbhid; | ||
| 937 | |||
| 938 | if (!hid) | ||
| 939 | return; | ||
| 940 | |||
| 941 | usbhid = hid->driver_data; | ||
| 942 | |||
| 943 | spin_lock_irq(&usbhid->inlock); /* Sync with error handler */ | ||
| 944 | usb_set_intfdata(intf, NULL); | ||
| 945 | set_bit(HID_DISCONNECTED, &usbhid->iofl); | ||
| 946 | spin_unlock_irq(&usbhid->inlock); | ||
| 947 | usb_kill_urb(usbhid->urbin); | ||
| 948 | usb_kill_urb(usbhid->urbout); | ||
| 949 | usb_kill_urb(usbhid->urbctrl); | ||
| 950 | |||
| 951 | del_timer_sync(&usbhid->io_retry); | ||
| 952 | cancel_work_sync(&usbhid->reset_work); | ||
| 953 | |||
| 954 | if (hid->claimed & HID_CLAIMED_INPUT) | ||
| 955 | hidinput_disconnect(hid); | ||
| 956 | if (hid->claimed & HID_CLAIMED_HIDDEV) | ||
| 957 | hiddev_disconnect(hid); | ||
| 958 | if (hid->claimed & HID_CLAIMED_HIDRAW) | ||
| 959 | hidraw_disconnect(hid); | ||
| 960 | |||
| 961 | usb_free_urb(usbhid->urbin); | ||
| 962 | usb_free_urb(usbhid->urbctrl); | ||
| 963 | usb_free_urb(usbhid->urbout); | ||
| 964 | |||
| 965 | hid_free_buffers(hid_to_usb_dev(hid), hid); | ||
| 966 | kfree(usbhid); | ||
| 967 | hid_free_device(hid); | ||
| 968 | } | ||
| 969 | |||
| 970 | static int hid_probe(struct usb_interface *intf, const struct usb_device_id *id) | ||
| 971 | { | ||
| 972 | struct hid_device *hid; | ||
| 973 | char path[64]; | ||
| 974 | int i; | ||
| 975 | char *c; | ||
| 976 | |||
| 977 | dbg_hid("HID probe called for ifnum %d\n", | ||
| 978 | intf->altsetting->desc.bInterfaceNumber); | ||
| 979 | |||
| 980 | if (!(hid = usb_hid_configure(intf))) | ||
| 981 | return -ENODEV; | ||
| 982 | |||
| 983 | usbhid_init_reports(hid); | ||
| 984 | hid_dump_device(hid); | ||
| 985 | if (hid->quirks & HID_QUIRK_RESET_LEDS) | ||
| 986 | usbhid_set_leds(hid); | ||
| 987 | |||
| 988 | if (!hidinput_connect(hid)) | ||
| 989 | hid->claimed |= HID_CLAIMED_INPUT; | ||
| 990 | if (!hiddev_connect(hid)) | ||
| 991 | hid->claimed |= HID_CLAIMED_HIDDEV; | ||
| 992 | if (!hidraw_connect(hid)) | ||
| 993 | hid->claimed |= HID_CLAIMED_HIDRAW; | ||
| 994 | |||
| 995 | usb_set_intfdata(intf, hid); | ||
| 996 | |||
| 997 | if (!hid->claimed) { | ||
| 998 | printk ("HID device claimed by neither input, hiddev nor hidraw\n"); | ||
| 999 | hid_disconnect(intf); | ||
| 1000 | return -ENODEV; | ||
| 1001 | } | ||
| 1002 | |||
| 1003 | if ((hid->claimed & HID_CLAIMED_INPUT)) | ||
| 1004 | hid_ff_init(hid); | ||
| 1005 | |||
| 1006 | if (hid->quirks & HID_QUIRK_SONY_PS3_CONTROLLER) | ||
| 1007 | hid_fixup_sony_ps3_controller(interface_to_usbdev(intf), | ||
| 1008 | intf->cur_altsetting->desc.bInterfaceNumber); | ||
| 1009 | |||
| 1010 | printk(KERN_INFO); | ||
| 1011 | |||
| 1012 | if (hid->claimed & HID_CLAIMED_INPUT) | ||
| 1013 | printk("input"); | ||
| 1014 | if ((hid->claimed & HID_CLAIMED_INPUT) && ((hid->claimed & HID_CLAIMED_HIDDEV) || | ||
| 1015 | hid->claimed & HID_CLAIMED_HIDRAW)) | ||
| 1016 | printk(","); | ||
| 1017 | if (hid->claimed & HID_CLAIMED_HIDDEV) | ||
| 1018 | printk("hiddev%d", hid->minor); | ||
| 1019 | if ((hid->claimed & HID_CLAIMED_INPUT) && (hid->claimed & HID_CLAIMED_HIDDEV) && | ||
| 1020 | (hid->claimed & HID_CLAIMED_HIDRAW)) | ||
| 1021 | printk(","); | ||
| 1022 | if (hid->claimed & HID_CLAIMED_HIDRAW) | ||
| 1023 | printk("hidraw%d", ((struct hidraw*)hid->hidraw)->minor); | ||
| 1024 | |||
| 1025 | c = "Device"; | ||
| 1026 | for (i = 0; i < hid->maxcollection; i++) { | ||
| 1027 | if (hid->collection[i].type == HID_COLLECTION_APPLICATION && | ||
| 1028 | (hid->collection[i].usage & HID_USAGE_PAGE) == HID_UP_GENDESK && | ||
| 1029 | (hid->collection[i].usage & 0xffff) < ARRAY_SIZE(hid_types)) { | ||
| 1030 | c = hid_types[hid->collection[i].usage & 0xffff]; | ||
| 1031 | break; | ||
| 1032 | } | ||
| 1033 | } | ||
| 1034 | |||
| 1035 | usb_make_path(interface_to_usbdev(intf), path, 63); | ||
| 1036 | |||
| 1037 | printk(": USB HID v%x.%02x %s [%s] on %s\n", | ||
| 1038 | hid->version >> 8, hid->version & 0xff, c, hid->name, path); | ||
| 1039 | |||
| 1040 | return 0; | ||
| 1041 | } | ||
| 1042 | |||
| 1043 | static int hid_suspend(struct usb_interface *intf, pm_message_t message) | ||
| 1044 | { | ||
| 1045 | struct hid_device *hid = usb_get_intfdata (intf); | ||
| 1046 | struct usbhid_device *usbhid = hid->driver_data; | ||
| 1047 | |||
| 1048 | spin_lock_irq(&usbhid->inlock); /* Sync with error handler */ | ||
| 1049 | set_bit(HID_SUSPENDED, &usbhid->iofl); | ||
| 1050 | spin_unlock_irq(&usbhid->inlock); | ||
| 1051 | del_timer(&usbhid->io_retry); | ||
| 1052 | usb_kill_urb(usbhid->urbin); | ||
| 1053 | dev_dbg(&intf->dev, "suspend\n"); | ||
| 1054 | return 0; | ||
| 1055 | } | ||
| 1056 | |||
| 1057 | static int hid_resume(struct usb_interface *intf) | ||
| 1058 | { | ||
| 1059 | struct hid_device *hid = usb_get_intfdata (intf); | ||
| 1060 | struct usbhid_device *usbhid = hid->driver_data; | ||
| 1061 | int status; | ||
| 1062 | |||
| 1063 | clear_bit(HID_SUSPENDED, &usbhid->iofl); | ||
| 1064 | usbhid->retry_delay = 0; | ||
| 1065 | status = hid_start_in(hid); | ||
| 1066 | dev_dbg(&intf->dev, "resume status %d\n", status); | ||
| 1067 | return status; | ||
| 1068 | } | ||
| 1069 | |||
| 1070 | /* Treat USB reset pretty much the same as suspend/resume */ | ||
| 1071 | static int hid_pre_reset(struct usb_interface *intf) | ||
| 1072 | { | ||
| 1073 | /* FIXME: What if the interface is already suspended? */ | ||
| 1074 | hid_suspend(intf, PMSG_ON); | ||
| 1075 | return 0; | ||
| 1076 | } | ||
| 1077 | |||
| 1078 | /* Same routine used for post_reset and reset_resume */ | ||
| 1079 | static int hid_post_reset(struct usb_interface *intf) | ||
| 1080 | { | ||
| 1081 | struct usb_device *dev = interface_to_usbdev (intf); | ||
| 1082 | |||
| 1083 | hid_set_idle(dev, intf->cur_altsetting->desc.bInterfaceNumber, 0, 0); | ||
| 1084 | /* FIXME: Any more reinitialization needed? */ | ||
| 1085 | |||
| 1086 | return hid_resume(intf); | ||
| 1087 | } | ||
| 1088 | |||
| 1089 | static struct usb_device_id hid_usb_ids [] = { | ||
| 1090 | { .match_flags = USB_DEVICE_ID_MATCH_INT_CLASS, | ||
| 1091 | .bInterfaceClass = USB_INTERFACE_CLASS_HID }, | ||
| 1092 | { } /* Terminating entry */ | ||
| 1093 | }; | ||
| 1094 | |||
| 1095 | MODULE_DEVICE_TABLE (usb, hid_usb_ids); | ||
| 1096 | |||
| 1097 | static struct usb_driver hid_driver = { | ||
| 1098 | .name = "usbhid", | ||
| 1099 | .probe = hid_probe, | ||
| 1100 | .disconnect = hid_disconnect, | ||
| 1101 | .suspend = hid_suspend, | ||
| 1102 | .resume = hid_resume, | ||
| 1103 | .reset_resume = hid_post_reset, | ||
| 1104 | .pre_reset = hid_pre_reset, | ||
| 1105 | .post_reset = hid_post_reset, | ||
| 1106 | .id_table = hid_usb_ids, | ||
| 1107 | .supports_autosuspend = 1, | ||
| 1108 | }; | ||
| 1109 | |||
| 1110 | static int __init hid_init(void) | ||
| 1111 | { | ||
| 1112 | int retval; | ||
| 1113 | retval = usbhid_quirks_init(quirks_param); | ||
| 1114 | if (retval) | ||
| 1115 | goto usbhid_quirks_init_fail; | ||
| 1116 | retval = hiddev_init(); | ||
| 1117 | if (retval) | ||
| 1118 | goto hiddev_init_fail; | ||
| 1119 | retval = usb_register(&hid_driver); | ||
| 1120 | if (retval) | ||
| 1121 | goto usb_register_fail; | ||
| 1122 | info(DRIVER_VERSION ":" DRIVER_DESC); | ||
| 1123 | |||
| 1124 | return 0; | ||
| 1125 | usb_register_fail: | ||
| 1126 | hiddev_exit(); | ||
| 1127 | hiddev_init_fail: | ||
| 1128 | usbhid_quirks_exit(); | ||
| 1129 | usbhid_quirks_init_fail: | ||
| 1130 | return retval; | ||
| 1131 | } | ||
| 1132 | |||
| 1133 | static void __exit hid_exit(void) | ||
| 1134 | { | ||
| 1135 | usb_deregister(&hid_driver); | ||
| 1136 | hiddev_exit(); | ||
| 1137 | usbhid_quirks_exit(); | ||
| 1138 | } | ||
| 1139 | |||
| 1140 | module_init(hid_init); | ||
| 1141 | module_exit(hid_exit); | ||
| 1142 | |||
| 1143 | MODULE_AUTHOR(DRIVER_AUTHOR); | ||
| 1144 | MODULE_DESCRIPTION(DRIVER_DESC); | ||
| 1145 | MODULE_LICENSE(DRIVER_LICENSE); | ||
diff --git a/usr/src/dkms_source_tree/hid-ff.c b/usr/src/dkms_source_tree/hid-ff.c new file mode 100644 index 0000000..1d0dac5 --- /dev/null +++ b/usr/src/dkms_source_tree/hid-ff.c | |||
| @@ -0,0 +1,95 @@ | |||
| 1 | /* | ||
| 2 | * Force feedback support for hid devices. | ||
| 3 | * Not all hid devices use the same protocol. For example, some use PID, | ||
| 4 | * other use their own proprietary procotol. | ||
| 5 | * | ||
| 6 | * Copyright (c) 2002-2004 Johann Deneux | ||
| 7 | */ | ||
| 8 | |||
| 9 | /* | ||
| 10 | * This program is free software; you can redistribute it and/or modify | ||
| 11 | * it under the terms of the GNU General Public License as published by | ||
| 12 | * the Free Software Foundation; either version 2 of the License, or | ||
| 13 | * (at your option) any later version. | ||
| 14 | * | ||
| 15 | * This program is distributed in the hope that it will be useful, | ||
| 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 18 | * GNU General Public License for more details. | ||
| 19 | * | ||
| 20 | * You should have received a copy of the GNU General Public License | ||
| 21 | * along with this program; if not, write to the Free Software | ||
| 22 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 23 | * | ||
| 24 | * Should you need to contact me, the author, you can do so by | ||
| 25 | * e-mail - mail your message to <johann.deneux@it.uu.se> | ||
| 26 | */ | ||
| 27 | |||
| 28 | #include <linux/input.h> | ||
| 29 | |||
| 30 | #undef DEBUG | ||
| 31 | #include <linux/usb.h> | ||
| 32 | |||
| 33 | #include <linux/hid.h> | ||
| 34 | #include "usbhid.h" | ||
| 35 | |||
| 36 | /* | ||
| 37 | * This table contains pointers to initializers. To add support for new | ||
| 38 | * devices, you need to add the USB vendor and product ids here. | ||
| 39 | */ | ||
| 40 | struct hid_ff_initializer { | ||
| 41 | u16 idVendor; | ||
| 42 | u16 idProduct; | ||
| 43 | int (*init)(struct hid_device*); | ||
| 44 | }; | ||
| 45 | |||
| 46 | /* | ||
| 47 | * We try pidff when no other driver is found because PID is the | ||
| 48 | * standards compliant way of implementing force feedback in HID. | ||
| 49 | * pidff_init() will quickly abort if the device doesn't appear to | ||
| 50 | * be a PID device | ||
| 51 | */ | ||
| 52 | static struct hid_ff_initializer inits[] = { | ||
| 53 | #ifdef CONFIG_LOGITECH_FF | ||
| 54 | { 0x46d, 0xc211, hid_lgff_init }, /* Logitech Cordless rumble pad */ | ||
| 55 | { 0x46d, 0xc219, hid_lgff_init }, /* Logitech Cordless rumble pad 2 */ | ||
| 56 | { 0x46d, 0xc283, hid_lgff_init }, /* Logitech Wingman Force 3d */ | ||
| 57 | { 0x46d, 0xc286, hid_lgff_init }, /* Logitech Force 3D Pro Joystick */ | ||
| 58 | { 0x46d, 0xc294, hid_lgff_init }, /* Logitech Formula Force EX */ | ||
| 59 | { 0x46d, 0xc295, hid_lgff_init }, /* Logitech MOMO force wheel */ | ||
| 60 | { 0x46d, 0xca03, hid_lgff_init }, /* Logitech MOMO force wheel */ | ||
| 61 | #endif | ||
| 62 | #ifdef CONFIG_LOGIRUMBLEPAD2_FF | ||
| 63 | { 0x46d, 0xc218, hid_lg2ff_init }, /* Logitech Rumblepad 2 */ | ||
| 64 | #endif | ||
| 65 | #ifdef CONFIG_PANTHERLORD_FF | ||
| 66 | { 0x810, 0x0001, hid_plff_init }, /* "Twin USB Joystick" */ | ||
| 67 | { 0xe8f, 0x0003, hid_plff_init }, /* "GreenAsia Inc. USB Joystick " */ | ||
| 68 | #endif | ||
| 69 | #ifdef CONFIG_THRUSTMASTER_FF | ||
| 70 | { 0x44f, 0xb300, hid_tmff_init }, | ||
| 71 | { 0x44f, 0xb304, hid_tmff_init }, | ||
| 72 | { 0x44f, 0xb651, hid_tmff_init }, /* FGT Rumble Force Wheel */ | ||
| 73 | { 0x44f, 0xb654, hid_tmff_init }, /* FGT Force Feedback Wheel */ | ||
| 74 | #endif | ||
| 75 | #ifdef CONFIG_ZEROPLUS_FF | ||
| 76 | { 0xc12, 0x0005, hid_zpff_init }, | ||
| 77 | { 0xc12, 0x0030, hid_zpff_init }, | ||
| 78 | #endif | ||
| 79 | { 0, 0, hid_pidff_init} /* Matches anything */ | ||
| 80 | }; | ||
| 81 | |||
| 82 | int hid_ff_init(struct hid_device* hid) | ||
| 83 | { | ||
| 84 | struct hid_ff_initializer *init; | ||
| 85 | int vendor = le16_to_cpu(hid_to_usb_dev(hid)->descriptor.idVendor); | ||
| 86 | int product = le16_to_cpu(hid_to_usb_dev(hid)->descriptor.idProduct); | ||
| 87 | |||
| 88 | for (init = inits; init->idVendor; init++) | ||
| 89 | if (init->idVendor == vendor && init->idProduct == product) | ||
| 90 | break; | ||
| 91 | |||
| 92 | return init->init(hid); | ||
| 93 | } | ||
| 94 | EXPORT_SYMBOL_GPL(hid_ff_init); | ||
| 95 | |||
diff --git a/usr/src/dkms_source_tree/hid-lg2ff.c b/usr/src/dkms_source_tree/hid-lg2ff.c new file mode 100644 index 0000000..d469bd0 --- /dev/null +++ b/usr/src/dkms_source_tree/hid-lg2ff.c | |||
| @@ -0,0 +1,114 @@ | |||
| 1 | /* | ||
| 2 | * Force feedback support for Logitech Rumblepad 2 | ||
| 3 | * | ||
| 4 | * Copyright (c) 2008 Anssi Hannula <anssi.hannula@gmail.com> | ||
| 5 | */ | ||
| 6 | |||
| 7 | /* | ||
| 8 | * This program is free software; you can redistribute it and/or modify | ||
| 9 | * it under the terms of the GNU General Public License as published by | ||
| 10 | * the Free Software Foundation; either version 2 of the License, or | ||
| 11 | * (at your option) any later version. | ||
| 12 | * | ||
| 13 | * This program is distributed in the hope that it will be useful, | ||
| 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 16 | * GNU General Public License for more details. | ||
| 17 | * | ||
| 18 | * You should have received a copy of the GNU General Public License | ||
| 19 | * along with this program; if not, write to the Free Software | ||
| 20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 21 | */ | ||
| 22 | |||
| 23 | |||
| 24 | #include <linux/input.h> | ||
| 25 | #include <linux/usb.h> | ||
| 26 | #include <linux/hid.h> | ||
| 27 | #include "usbhid.h" | ||
| 28 | |||
| 29 | struct lg2ff_device { | ||
| 30 | struct hid_report *report; | ||
| 31 | }; | ||
| 32 | |||
| 33 | static int play_effect(struct input_dev *dev, void *data, | ||
| 34 | struct ff_effect *effect) | ||
| 35 | { | ||
| 36 | struct hid_device *hid = input_get_drvdata(dev); | ||
| 37 | struct lg2ff_device *lg2ff = data; | ||
| 38 | int weak, strong; | ||
| 39 | |||
| 40 | strong = effect->u.rumble.strong_magnitude; | ||
| 41 | weak = effect->u.rumble.weak_magnitude; | ||
| 42 | |||
| 43 | if (weak || strong) { | ||
| 44 | weak = weak * 0xff / 0xffff; | ||
| 45 | strong = strong * 0xff / 0xffff; | ||
| 46 | |||
| 47 | lg2ff->report->field[0]->value[0] = 0x51; | ||
| 48 | lg2ff->report->field[0]->value[2] = weak; | ||
| 49 | lg2ff->report->field[0]->value[4] = strong; | ||
| 50 | } else { | ||
| 51 | lg2ff->report->field[0]->value[0] = 0xf3; | ||
| 52 | lg2ff->report->field[0]->value[2] = 0x00; | ||
| 53 | lg2ff->report->field[0]->value[4] = 0x00; | ||
| 54 | } | ||
| 55 | |||
| 56 | usbhid_submit_report(hid, lg2ff->report, USB_DIR_OUT); | ||
| 57 | return 0; | ||
| 58 | } | ||
| 59 | |||
| 60 | int hid_lg2ff_init(struct hid_device *hid) | ||
| 61 | { | ||
| 62 | struct lg2ff_device *lg2ff; | ||
| 63 | struct hid_report *report; | ||
| 64 | struct hid_input *hidinput = list_entry(hid->inputs.next, | ||
| 65 | struct hid_input, list); | ||
| 66 | struct list_head *report_list = | ||
| 67 | &hid->report_enum[HID_OUTPUT_REPORT].report_list; | ||
| 68 | struct input_dev *dev = hidinput->input; | ||
| 69 | int error; | ||
| 70 | |||
| 71 | if (list_empty(report_list)) { | ||
| 72 | printk(KERN_ERR "hid-lg2ff: no output report found\n"); | ||
| 73 | return -ENODEV; | ||
| 74 | } | ||
| 75 | |||
| 76 | report = list_entry(report_list->next, struct hid_report, list); | ||
| 77 | |||
| 78 | if (report->maxfield < 1) { | ||
| 79 | printk(KERN_ERR "hid-lg2ff: output report is empty\n"); | ||
| 80 | return -ENODEV; | ||
| 81 | } | ||
| 82 | if (report->field[0]->report_count < 7) { | ||
| 83 | printk(KERN_ERR "hid-lg2ff: not enough values in the field\n"); | ||
| 84 | return -ENODEV; | ||
| 85 | } | ||
| 86 | |||
| 87 | lg2ff = kmalloc(sizeof(struct lg2ff_device), GFP_KERNEL); | ||
| 88 | if (!lg2ff) | ||
| 89 | return -ENOMEM; | ||
| 90 | |||
| 91 | set_bit(FF_RUMBLE, dev->ffbit); | ||
| 92 | |||
| 93 | error = input_ff_create_memless(dev, lg2ff, play_effect); | ||
| 94 | if (error) { | ||
| 95 | kfree(lg2ff); | ||
| 96 | return error; | ||
| 97 | } | ||
| 98 | |||
| 99 | lg2ff->report = report; | ||
| 100 | report->field[0]->value[0] = 0xf3; | ||
| 101 | report->field[0]->value[1] = 0x00; | ||
| 102 | report->field[0]->value[2] = 0x00; | ||
| 103 | report->field[0]->value[3] = 0x00; | ||
| 104 | report->field[0]->value[4] = 0x00; | ||
| 105 | report->field[0]->value[5] = 0x00; | ||
| 106 | report->field[0]->value[6] = 0x00; | ||
| 107 | |||
| 108 | usbhid_submit_report(hid, report, USB_DIR_OUT); | ||
| 109 | |||
| 110 | printk(KERN_INFO "Force feedback for Logitech Rumblepad 2 by " | ||
| 111 | "Anssi Hannula <anssi.hannula@gmail.com>\n"); | ||
| 112 | |||
| 113 | return 0; | ||
| 114 | } | ||
diff --git a/usr/src/dkms_source_tree/hid-lgff.c b/usr/src/dkms_source_tree/hid-lgff.c new file mode 100644 index 0000000..4b7ab6a --- /dev/null +++ b/usr/src/dkms_source_tree/hid-lgff.c | |||
| @@ -0,0 +1,151 @@ | |||
| 1 | /* | ||
| 2 | * Force feedback support for hid-compliant for some of the devices from | ||
| 3 | * Logitech, namely: | ||
| 4 | * - WingMan Cordless RumblePad | ||
| 5 | * - WingMan Force 3D | ||
| 6 | * | ||
| 7 | * Copyright (c) 2002-2004 Johann Deneux | ||
| 8 | * Copyright (c) 2006 Anssi Hannula <anssi.hannula@gmail.com> | ||
| 9 | */ | ||
| 10 | |||
| 11 | /* | ||
| 12 | * This program is free software; you can redistribute it and/or modify | ||
| 13 | * it under the terms of the GNU General Public License as published by | ||
| 14 | * the Free Software Foundation; either version 2 of the License, or | ||
| 15 | * (at your option) any later version. | ||
| 16 | * | ||
| 17 | * This program is distributed in the hope that it will be useful, | ||
| 18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 20 | * GNU General Public License for more details. | ||
| 21 | * | ||
| 22 | * You should have received a copy of the GNU General Public License | ||
| 23 | * along with this program; if not, write to the Free Software | ||
| 24 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 25 | * | ||
| 26 | * Should you need to contact me, the author, you can do so by | ||
| 27 | * e-mail - mail your message to <johann.deneux@it.uu.se> | ||
| 28 | */ | ||
| 29 | |||
| 30 | #include <linux/input.h> | ||
| 31 | #include <linux/usb.h> | ||
| 32 | #include <linux/hid.h> | ||
| 33 | #include "usbhid.h" | ||
| 34 | |||
| 35 | struct dev_type { | ||
| 36 | u16 idVendor; | ||
| 37 | u16 idProduct; | ||
| 38 | const signed short *ff; | ||
| 39 | }; | ||
| 40 | |||
| 41 | static const signed short ff_rumble[] = { | ||
| 42 | FF_RUMBLE, | ||
| 43 | -1 | ||
| 44 | }; | ||
| 45 | |||
| 46 | static const signed short ff_joystick[] = { | ||
| 47 | FF_CONSTANT, | ||
| 48 | -1 | ||
| 49 | }; | ||
| 50 | |||
| 51 | static const struct dev_type devices[] = { | ||
| 52 | { 0x046d, 0xc211, ff_rumble }, | ||
| 53 | { 0x046d, 0xc219, ff_rumble }, | ||
| 54 | { 0x046d, 0xc283, ff_joystick }, | ||
| 55 | { 0x046d, 0xc286, ff_joystick }, | ||
| 56 | { 0x046d, 0xc294, ff_joystick }, | ||
| 57 | { 0x046d, 0xc295, ff_joystick }, | ||
| 58 | { 0x046d, 0xca03, ff_joystick }, | ||
| 59 | }; | ||
| 60 | |||
| 61 | static int hid_lgff_play(struct input_dev *dev, void *data, struct ff_effect *effect) | ||
| 62 | { | ||
| 63 | struct hid_device *hid = input_get_drvdata(dev); | ||
| 64 | struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list; | ||
| 65 | struct hid_report *report = list_entry(report_list->next, struct hid_report, list); | ||
| 66 | int x, y; | ||
| 67 | unsigned int left, right; | ||
| 68 | |||
| 69 | #define CLAMP(x) if (x < 0) x = 0; if (x > 0xff) x = 0xff | ||
| 70 | |||
| 71 | switch (effect->type) { | ||
| 72 | case FF_CONSTANT: | ||
| 73 | x = effect->u.ramp.start_level + 0x7f; /* 0x7f is center */ | ||
| 74 | y = effect->u.ramp.end_level + 0x7f; | ||
| 75 | CLAMP(x); | ||
| 76 | CLAMP(y); | ||
| 77 | report->field[0]->value[0] = 0x51; | ||
| 78 | report->field[0]->value[1] = 0x08; | ||
| 79 | report->field[0]->value[2] = x; | ||
| 80 | report->field[0]->value[3] = y; | ||
| 81 | dbg_hid("(x, y)=(%04x, %04x)\n", x, y); | ||
| 82 | usbhid_submit_report(hid, report, USB_DIR_OUT); | ||
| 83 | break; | ||
| 84 | |||
| 85 | case FF_RUMBLE: | ||
| 86 | right = effect->u.rumble.strong_magnitude; | ||
| 87 | left = effect->u.rumble.weak_magnitude; | ||
| 88 | right = right * 0xff / 0xffff; | ||
| 89 | left = left * 0xff / 0xffff; | ||
| 90 | CLAMP(left); | ||
| 91 | CLAMP(right); | ||
| 92 | report->field[0]->value[0] = 0x42; | ||
| 93 | report->field[0]->value[1] = 0x00; | ||
| 94 | report->field[0]->value[2] = left; | ||
| 95 | report->field[0]->value[3] = right; | ||
| 96 | dbg_hid("(left, right)=(%04x, %04x)\n", left, right); | ||
| 97 | usbhid_submit_report(hid, report, USB_DIR_OUT); | ||
| 98 | break; | ||
| 99 | } | ||
| 100 | return 0; | ||
| 101 | } | ||
| 102 | |||
| 103 | int hid_lgff_init(struct hid_device* hid) | ||
| 104 | { | ||
| 105 | struct hid_input *hidinput = list_entry(hid->inputs.next, struct hid_input, list); | ||
| 106 | struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list; | ||
| 107 | struct input_dev *dev = hidinput->input; | ||
| 108 | struct hid_report *report; | ||
| 109 | struct hid_field *field; | ||
| 110 | const signed short *ff_bits = ff_joystick; | ||
| 111 | int error; | ||
| 112 | int i; | ||
| 113 | |||
| 114 | /* Find the report to use */ | ||
| 115 | if (list_empty(report_list)) { | ||
| 116 | err_hid("No output report found"); | ||
| 117 | return -1; | ||
| 118 | } | ||
| 119 | |||
| 120 | /* Check that the report looks ok */ | ||
| 121 | report = list_entry(report_list->next, struct hid_report, list); | ||
| 122 | if (!report) { | ||
| 123 | err_hid("NULL output report"); | ||
| 124 | return -1; | ||
| 125 | } | ||
| 126 | |||
| 127 | field = report->field[0]; | ||
| 128 | if (!field) { | ||
| 129 | err_hid("NULL field"); | ||
| 130 | return -1; | ||
| 131 | } | ||
| 132 | |||
| 133 | for (i = 0; i < ARRAY_SIZE(devices); i++) { | ||
| 134 | if (dev->id.vendor == devices[i].idVendor && | ||
| 135 | dev->id.product == devices[i].idProduct) { | ||
| 136 | ff_bits = devices[i].ff; | ||
| 137 | break; | ||
| 138 | } | ||
| 139 | } | ||
| 140 | |||
| 141 | for (i = 0; ff_bits[i] >= 0; i++) | ||
| 142 | set_bit(ff_bits[i], dev->ffbit); | ||
| 143 | |||
| 144 | error = input_ff_create_memless(dev, NULL, hid_lgff_play); | ||
| 145 | if (error) | ||
| 146 | return error; | ||
| 147 | |||
| 148 | printk(KERN_INFO "Force feedback for Logitech force feedback devices by Johann Deneux <johann.deneux@it.uu.se>\n"); | ||
| 149 | |||
| 150 | return 0; | ||
| 151 | } | ||
diff --git a/usr/src/dkms_source_tree/hid-pidff.c b/usr/src/dkms_source_tree/hid-pidff.c new file mode 100644 index 0000000..0113261 --- /dev/null +++ b/usr/src/dkms_source_tree/hid-pidff.c | |||
| @@ -0,0 +1,1332 @@ | |||
| 1 | /* | ||
| 2 | * Force feedback driver for USB HID PID compliant devices | ||
| 3 | * | ||
| 4 | * Copyright (c) 2005, 2006 Anssi Hannula <anssi.hannula@gmail.com> | ||
| 5 | */ | ||
| 6 | |||
| 7 | /* | ||
| 8 | * This program is free software; you can redistribute it and/or modify | ||
| 9 | * it under the terms of the GNU General Public License as published by | ||
| 10 | * the Free Software Foundation; either version 2 of the License, or | ||
| 11 | * (at your option) any later version. | ||
| 12 | * | ||
| 13 | * This program is distributed in the hope that it will be useful, | ||
| 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 16 | * GNU General Public License for more details. | ||
| 17 | * | ||
| 18 | * You should have received a copy of the GNU General Public License | ||
| 19 | * along with this program; if not, write to the Free Software | ||
| 20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 21 | */ | ||
| 22 | |||
| 23 | /* #define DEBUG */ | ||
| 24 | |||
| 25 | #define debug(format, arg...) pr_debug("hid-pidff: " format "\n" , ## arg) | ||
| 26 | |||
| 27 | #include <linux/input.h> | ||
| 28 | #include <linux/usb.h> | ||
| 29 | |||
| 30 | #include <linux/hid.h> | ||
| 31 | |||
| 32 | #include "usbhid.h" | ||
| 33 | |||
| 34 | #define PID_EFFECTS_MAX 64 | ||
| 35 | |||
| 36 | /* Report usage table used to put reports into an array */ | ||
| 37 | |||
| 38 | #define PID_SET_EFFECT 0 | ||
| 39 | #define PID_EFFECT_OPERATION 1 | ||
| 40 | #define PID_DEVICE_GAIN 2 | ||
| 41 | #define PID_POOL 3 | ||
| 42 | #define PID_BLOCK_LOAD 4 | ||
| 43 | #define PID_BLOCK_FREE 5 | ||
| 44 | #define PID_DEVICE_CONTROL 6 | ||
| 45 | #define PID_CREATE_NEW_EFFECT 7 | ||
| 46 | |||
| 47 | #define PID_REQUIRED_REPORTS 7 | ||
| 48 | |||
| 49 | #define PID_SET_ENVELOPE 8 | ||
| 50 | #define PID_SET_CONDITION 9 | ||
| 51 | #define PID_SET_PERIODIC 10 | ||
| 52 | #define PID_SET_CONSTANT 11 | ||
| 53 | #define PID_SET_RAMP 12 | ||
| 54 | static const u8 pidff_reports[] = { | ||
| 55 | 0x21, 0x77, 0x7d, 0x7f, 0x89, 0x90, 0x96, 0xab, | ||
| 56 | 0x5a, 0x5f, 0x6e, 0x73, 0x74 | ||
| 57 | }; | ||
| 58 | |||
| 59 | /* device_control is really 0x95, but 0x96 specified as it is the usage of | ||
| 60 | the only field in that report */ | ||
| 61 | |||
| 62 | /* Value usage tables used to put fields and values into arrays */ | ||
| 63 | |||
| 64 | #define PID_EFFECT_BLOCK_INDEX 0 | ||
| 65 | |||
| 66 | #define PID_DURATION 1 | ||
| 67 | #define PID_GAIN 2 | ||
| 68 | #define PID_TRIGGER_BUTTON 3 | ||
| 69 | #define PID_TRIGGER_REPEAT_INT 4 | ||
| 70 | #define PID_DIRECTION_ENABLE 5 | ||
| 71 | #define PID_START_DELAY 6 | ||
| 72 | static const u8 pidff_set_effect[] = { | ||
| 73 | 0x22, 0x50, 0x52, 0x53, 0x54, 0x56, 0xa7 | ||
| 74 | }; | ||
| 75 | |||
| 76 | #define PID_ATTACK_LEVEL 1 | ||
| 77 | #define PID_ATTACK_TIME 2 | ||
| 78 | #define PID_FADE_LEVEL 3 | ||
| 79 | #define PID_FADE_TIME 4 | ||
| 80 | static const u8 pidff_set_envelope[] = { 0x22, 0x5b, 0x5c, 0x5d, 0x5e }; | ||
| 81 | |||
| 82 | #define PID_PARAM_BLOCK_OFFSET 1 | ||
| 83 | #define PID_CP_OFFSET 2 | ||
| 84 | #define PID_POS_COEFFICIENT 3 | ||
| 85 | #define PID_NEG_COEFFICIENT 4 | ||
| 86 | #define PID_POS_SATURATION 5 | ||
| 87 | #define PID_NEG_SATURATION 6 | ||
| 88 | #define PID_DEAD_BAND 7 | ||
| 89 | static const u8 pidff_set_condition[] = { | ||
| 90 | 0x22, 0x23, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65 | ||
| 91 | }; | ||
| 92 | |||
| 93 | #define PID_MAGNITUDE 1 | ||
| 94 | #define PID_OFFSET 2 | ||
| 95 | #define PID_PHASE 3 | ||
| 96 | #define PID_PERIOD 4 | ||
| 97 | static const u8 pidff_set_periodic[] = { 0x22, 0x70, 0x6f, 0x71, 0x72 }; | ||
| 98 | static const u8 pidff_set_constant[] = { 0x22, 0x70 }; | ||
| 99 | |||
| 100 | #define PID_RAMP_START 1 | ||
| 101 | #define PID_RAMP_END 2 | ||
| 102 | static const u8 pidff_set_ramp[] = { 0x22, 0x75, 0x76 }; | ||
| 103 | |||
| 104 | #define PID_RAM_POOL_AVAILABLE 1 | ||
| 105 | static const u8 pidff_block_load[] = { 0x22, 0xac }; | ||
| 106 | |||
| 107 | #define PID_LOOP_COUNT 1 | ||
| 108 | static const u8 pidff_effect_operation[] = { 0x22, 0x7c }; | ||
| 109 | |||
| 110 | static const u8 pidff_block_free[] = { 0x22 }; | ||
| 111 | |||
| 112 | #define PID_DEVICE_GAIN_FIELD 0 | ||
| 113 | static const u8 pidff_device_gain[] = { 0x7e }; | ||
| 114 | |||
| 115 | #define PID_RAM_POOL_SIZE 0 | ||
| 116 | #define PID_SIMULTANEOUS_MAX 1 | ||
| 117 | #define PID_DEVICE_MANAGED_POOL 2 | ||
| 118 | static const u8 pidff_pool[] = { 0x80, 0x83, 0xa9 }; | ||
| 119 | |||
| 120 | /* Special field key tables used to put special field keys into arrays */ | ||
| 121 | |||
| 122 | #define PID_ENABLE_ACTUATORS 0 | ||
| 123 | #define PID_RESET 1 | ||
| 124 | static const u8 pidff_device_control[] = { 0x97, 0x9a }; | ||
| 125 | |||
| 126 | #define PID_CONSTANT 0 | ||
| 127 | #define PID_RAMP 1 | ||
| 128 | #define PID_SQUARE 2 | ||
| 129 | #define PID_SINE 3 | ||
| 130 | #define PID_TRIANGLE 4 | ||
| 131 | #define PID_SAW_UP 5 | ||
| 132 | #define PID_SAW_DOWN 6 | ||
| 133 | #define PID_SPRING 7 | ||
| 134 | #define PID_DAMPER 8 | ||
| 135 | #define PID_INERTIA 9 | ||
| 136 | #define PID_FRICTION 10 | ||
| 137 | static const u8 pidff_effect_types[] = { | ||
| 138 | 0x26, 0x27, 0x30, 0x31, 0x32, 0x33, 0x34, | ||
| 139 | 0x40, 0x41, 0x42, 0x43 | ||
| 140 | }; | ||
| 141 | |||
| 142 | #define PID_BLOCK_LOAD_SUCCESS 0 | ||
| 143 | #define PID_BLOCK_LOAD_FULL 1 | ||
| 144 | static const u8 pidff_block_load_status[] = { 0x8c, 0x8d }; | ||
| 145 | |||
| 146 | #define PID_EFFECT_START 0 | ||
| 147 | #define PID_EFFECT_STOP 1 | ||
| 148 | static const u8 pidff_effect_operation_status[] = { 0x79, 0x7b }; | ||
| 149 | |||
| 150 | struct pidff_usage { | ||
| 151 | struct hid_field *field; | ||
| 152 | s32 *value; | ||
| 153 | }; | ||
| 154 | |||
| 155 | struct pidff_device { | ||
| 156 | struct hid_device *hid; | ||
| 157 | |||
| 158 | struct hid_report *reports[sizeof(pidff_reports)]; | ||
| 159 | |||
| 160 | struct pidff_usage set_effect[sizeof(pidff_set_effect)]; | ||
| 161 | struct pidff_usage set_envelope[sizeof(pidff_set_envelope)]; | ||
| 162 | struct pidff_usage set_condition[sizeof(pidff_set_condition)]; | ||
| 163 | struct pidff_usage set_periodic[sizeof(pidff_set_periodic)]; | ||
| 164 | struct pidff_usage set_constant[sizeof(pidff_set_constant)]; | ||
| 165 | struct pidff_usage set_ramp[sizeof(pidff_set_ramp)]; | ||
| 166 | |||
| 167 | struct pidff_usage device_gain[sizeof(pidff_device_gain)]; | ||
| 168 | struct pidff_usage block_load[sizeof(pidff_block_load)]; | ||
| 169 | struct pidff_usage pool[sizeof(pidff_pool)]; | ||
| 170 | struct pidff_usage effect_operation[sizeof(pidff_effect_operation)]; | ||
| 171 | struct pidff_usage block_free[sizeof(pidff_block_free)]; | ||
| 172 | |||
| 173 | /* Special field is a field that is not composed of | ||
| 174 | usage<->value pairs that pidff_usage values are */ | ||
| 175 | |||
| 176 | /* Special field in create_new_effect */ | ||
| 177 | struct hid_field *create_new_effect_type; | ||
| 178 | |||
| 179 | /* Special fields in set_effect */ | ||
| 180 | struct hid_field *set_effect_type; | ||
| 181 | struct hid_field *effect_direction; | ||
| 182 | |||
| 183 | /* Special field in device_control */ | ||
| 184 | struct hid_field *device_control; | ||
| 185 | |||
| 186 | /* Special field in block_load */ | ||
| 187 | struct hid_field *block_load_status; | ||
| 188 | |||
| 189 | /* Special field in effect_operation */ | ||
| 190 | struct hid_field *effect_operation_status; | ||
| 191 | |||
| 192 | int control_id[sizeof(pidff_device_control)]; | ||
| 193 | int type_id[sizeof(pidff_effect_types)]; | ||
| 194 | int status_id[sizeof(pidff_block_load_status)]; | ||
| 195 | int operation_id[sizeof(pidff_effect_operation_status)]; | ||
| 196 | |||
| 197 | int pid_id[PID_EFFECTS_MAX]; | ||
| 198 | }; | ||
| 199 | |||
| 200 | /* | ||
| 201 | * Scale an unsigned value with range 0..max for the given field | ||
| 202 | */ | ||
| 203 | static int pidff_rescale(int i, int max, struct hid_field *field) | ||
| 204 | { | ||
| 205 | return i * (field->logical_maximum - field->logical_minimum) / max + | ||
| 206 | field->logical_minimum; | ||
| 207 | } | ||
| 208 | |||
| 209 | /* | ||
| 210 | * Scale a signed value in range -0x8000..0x7fff for the given field | ||
| 211 | */ | ||
| 212 | static int pidff_rescale_signed(int i, struct hid_field *field) | ||
| 213 | { | ||
| 214 | return i == 0 ? 0 : i > | ||
| 215 | 0 ? i * field->logical_maximum / 0x7fff : i * | ||
| 216 | field->logical_minimum / -0x8000; | ||
| 217 | } | ||
| 218 | |||
| 219 | static void pidff_set(struct pidff_usage *usage, u16 value) | ||
| 220 | { | ||
| 221 | usage->value[0] = pidff_rescale(value, 0xffff, usage->field); | ||
| 222 | debug("calculated from %d to %d", value, usage->value[0]); | ||
| 223 | } | ||
| 224 | |||
| 225 | static void pidff_set_signed(struct pidff_usage *usage, s16 value) | ||
| 226 | { | ||
| 227 | if (usage->field->logical_minimum < 0) | ||
| 228 | usage->value[0] = pidff_rescale_signed(value, usage->field); | ||
| 229 | else { | ||
| 230 | if (value < 0) | ||
| 231 | usage->value[0] = | ||
| 232 | pidff_rescale(-value, 0x8000, usage->field); | ||
| 233 | else | ||
| 234 | usage->value[0] = | ||
| 235 | pidff_rescale(value, 0x7fff, usage->field); | ||
| 236 | } | ||
| 237 | debug("calculated from %d to %d", value, usage->value[0]); | ||
| 238 | } | ||
| 239 | |||
| 240 | /* | ||
| 241 | * Send envelope report to the device | ||
| 242 | */ | ||
| 243 | static void pidff_set_envelope_report(struct pidff_device *pidff, | ||
| 244 | struct ff_envelope *envelope) | ||
| 245 | { | ||
| 246 | pidff->set_envelope[PID_EFFECT_BLOCK_INDEX].value[0] = | ||
| 247 | pidff->block_load[PID_EFFECT_BLOCK_INDEX].value[0]; | ||
| 248 | |||
| 249 | pidff->set_envelope[PID_ATTACK_LEVEL].value[0] = | ||
| 250 | pidff_rescale(envelope->attack_level > | ||
| 251 | 0x7fff ? 0x7fff : envelope->attack_level, 0x7fff, | ||
| 252 | pidff->set_envelope[PID_ATTACK_LEVEL].field); | ||
| 253 | pidff->set_envelope[PID_FADE_LEVEL].value[0] = | ||
| 254 | pidff_rescale(envelope->fade_level > | ||
| 255 | 0x7fff ? 0x7fff : envelope->fade_level, 0x7fff, | ||
| 256 | pidff->set_envelope[PID_FADE_LEVEL].field); | ||
| 257 | |||
| 258 | pidff->set_envelope[PID_ATTACK_TIME].value[0] = envelope->attack_length; | ||
| 259 | pidff->set_envelope[PID_FADE_TIME].value[0] = envelope->fade_length; | ||
| 260 | |||
| 261 | debug("attack %u => %d", envelope->attack_level, | ||
| 262 | pidff->set_envelope[PID_ATTACK_LEVEL].value[0]); | ||
| 263 | |||
| 264 | usbhid_submit_report(pidff->hid, pidff->reports[PID_SET_ENVELOPE], | ||
| 265 | USB_DIR_OUT); | ||
| 266 | } | ||
| 267 | |||
| 268 | /* | ||
| 269 | * Test if the new envelope differs from old one | ||
| 270 | */ | ||
| 271 | static int pidff_needs_set_envelope(struct ff_envelope *envelope, | ||
| 272 | struct ff_envelope *old) | ||
| 273 | { | ||
| 274 | return envelope->attack_level != old->attack_level || | ||
| 275 | envelope->fade_level != old->fade_level || | ||
| 276 | envelope->attack_length != old->attack_length || | ||
| 277 | envelope->fade_length != old->fade_length; | ||
| 278 | } | ||
| 279 | |||
| 280 | /* | ||
| 281 | * Send constant force report to the device | ||
| 282 | */ | ||
| 283 | static void pidff_set_constant_force_report(struct pidff_device *pidff, | ||
| 284 | struct ff_effect *effect) | ||
| 285 | { | ||
| 286 | pidff->set_constant[PID_EFFECT_BLOCK_INDEX].value[0] = | ||
| 287 | pidff->block_load[PID_EFFECT_BLOCK_INDEX].value[0]; | ||
| 288 | pidff_set_signed(&pidff->set_constant[PID_MAGNITUDE], | ||
| 289 | effect->u.constant.level); | ||
| 290 | |||
| 291 | usbhid_submit_report(pidff->hid, pidff->reports[PID_SET_CONSTANT], | ||
| 292 | USB_DIR_OUT); | ||
| 293 | } | ||
| 294 | |||
| 295 | /* | ||
| 296 | * Test if the constant parameters have changed between effects | ||
| 297 | */ | ||
| 298 | static int pidff_needs_set_constant(struct ff_effect *effect, | ||
| 299 | struct ff_effect *old) | ||
| 300 | { | ||
| 301 | return effect->u.constant.level != old->u.constant.level; | ||
| 302 | } | ||
| 303 | |||
| 304 | /* | ||
| 305 | * Send set effect report to the device | ||
| 306 | */ | ||
| 307 | static void pidff_set_effect_report(struct pidff_device *pidff, | ||
| 308 | struct ff_effect *effect) | ||
| 309 | { | ||
| 310 | pidff->set_effect[PID_EFFECT_BLOCK_INDEX].value[0] = | ||
| 311 | pidff->block_load[PID_EFFECT_BLOCK_INDEX].value[0]; | ||
| 312 | pidff->set_effect_type->value[0] = | ||
| 313 | pidff->create_new_effect_type->value[0]; | ||
| 314 | pidff->set_effect[PID_DURATION].value[0] = effect->replay.length; | ||
| 315 | pidff->set_effect[PID_TRIGGER_BUTTON].value[0] = effect->trigger.button; | ||
| 316 | pidff->set_effect[PID_TRIGGER_REPEAT_INT].value[0] = | ||
| 317 | effect->trigger.interval; | ||
| 318 | pidff->set_effect[PID_GAIN].value[0] = | ||
| 319 | pidff->set_effect[PID_GAIN].field->logical_maximum; | ||
| 320 | pidff->set_effect[PID_DIRECTION_ENABLE].value[0] = 1; | ||
| 321 | pidff->effect_direction->value[0] = | ||
| 322 | pidff_rescale(effect->direction, 0xffff, | ||
| 323 | pidff->effect_direction); | ||
| 324 | pidff->set_effect[PID_START_DELAY].value[0] = effect->replay.delay; | ||
| 325 | |||
| 326 | usbhid_submit_report(pidff->hid, pidff->reports[PID_SET_EFFECT], | ||
| 327 | USB_DIR_OUT); | ||
| 328 | } | ||
| 329 | |||
| 330 | /* | ||
| 331 | * Test if the values used in set_effect have changed | ||
| 332 | */ | ||
| 333 | static int pidff_needs_set_effect(struct ff_effect *effect, | ||
| 334 | struct ff_effect *old) | ||
| 335 | { | ||
| 336 | return effect->replay.length != old->replay.length || | ||
| 337 | effect->trigger.interval != old->trigger.interval || | ||
| 338 | effect->trigger.button != old->trigger.button || | ||
| 339 | effect->direction != old->direction || | ||
| 340 | effect->replay.delay != old->replay.delay; | ||
| 341 | } | ||
| 342 | |||
| 343 | /* | ||
| 344 | * Send periodic effect report to the device | ||
| 345 | */ | ||
| 346 | static void pidff_set_periodic_report(struct pidff_device *pidff, | ||
| 347 | struct ff_effect *effect) | ||
| 348 | { | ||
| 349 | pidff->set_periodic[PID_EFFECT_BLOCK_INDEX].value[0] = | ||
| 350 | pidff->block_load[PID_EFFECT_BLOCK_INDEX].value[0]; | ||
| 351 | pidff_set_signed(&pidff->set_periodic[PID_MAGNITUDE], | ||
| 352 | effect->u.periodic.magnitude); | ||
| 353 | pidff_set_signed(&pidff->set_periodic[PID_OFFSET], | ||
| 354 | effect->u.periodic.offset); | ||
| 355 | pidff_set(&pidff->set_periodic[PID_PHASE], effect->u.periodic.phase); | ||
| 356 | pidff->set_periodic[PID_PERIOD].value[0] = effect->u.periodic.period; | ||
| 357 | |||
| 358 | usbhid_submit_report(pidff->hid, pidff->reports[PID_SET_PERIODIC], | ||
| 359 | USB_DIR_OUT); | ||
| 360 | |||
| 361 | } | ||
| 362 | |||
| 363 | /* | ||
| 364 | * Test if periodic effect parameters have changed | ||
| 365 | */ | ||
| 366 | static int pidff_needs_set_periodic(struct ff_effect *effect, | ||
| 367 | struct ff_effect *old) | ||
| 368 | { | ||
| 369 | return effect->u.periodic.magnitude != old->u.periodic.magnitude || | ||
| 370 | effect->u.periodic.offset != old->u.periodic.offset || | ||
| 371 | effect->u.periodic.phase != old->u.periodic.phase || | ||
| 372 | effect->u.periodic.period != old->u.periodic.period; | ||
| 373 | } | ||
| 374 | |||
| 375 | /* | ||
| 376 | * Send condition effect reports to the device | ||
| 377 | */ | ||
| 378 | static void pidff_set_condition_report(struct pidff_device *pidff, | ||
| 379 | struct ff_effect *effect) | ||
| 380 | { | ||
| 381 | int i; | ||
| 382 | |||
| 383 | pidff->set_condition[PID_EFFECT_BLOCK_INDEX].value[0] = | ||
| 384 | pidff->block_load[PID_EFFECT_BLOCK_INDEX].value[0]; | ||
| 385 | |||
| 386 | for (i = 0; i < 2; i++) { | ||
| 387 | pidff->set_condition[PID_PARAM_BLOCK_OFFSET].value[0] = i; | ||
| 388 | pidff_set_signed(&pidff->set_condition[PID_CP_OFFSET], | ||
| 389 | effect->u.condition[i].center); | ||
| 390 | pidff_set_signed(&pidff->set_condition[PID_POS_COEFFICIENT], | ||
| 391 | effect->u.condition[i].right_coeff); | ||
| 392 | pidff_set_signed(&pidff->set_condition[PID_NEG_COEFFICIENT], | ||
| 393 | effect->u.condition[i].left_coeff); | ||
| 394 | pidff_set(&pidff->set_condition[PID_POS_SATURATION], | ||
| 395 | effect->u.condition[i].right_saturation); | ||
| 396 | pidff_set(&pidff->set_condition[PID_NEG_SATURATION], | ||
| 397 | effect->u.condition[i].left_saturation); | ||
| 398 | pidff_set(&pidff->set_condition[PID_DEAD_BAND], | ||
| 399 | effect->u.condition[i].deadband); | ||
| 400 | usbhid_wait_io(pidff->hid); | ||
| 401 | usbhid_submit_report(pidff->hid, pidff->reports[PID_SET_CONDITION], | ||
| 402 | USB_DIR_OUT); | ||
| 403 | } | ||
| 404 | } | ||
| 405 | |||
| 406 | /* | ||
| 407 | * Test if condition effect parameters have changed | ||
| 408 | */ | ||
| 409 | static int pidff_needs_set_condition(struct ff_effect *effect, | ||
| 410 | struct ff_effect *old) | ||
| 411 | { | ||
| 412 | int i; | ||
| 413 | int ret = 0; | ||
| 414 | |||
| 415 | for (i = 0; i < 2; i++) { | ||
| 416 | struct ff_condition_effect *cond = &effect->u.condition[i]; | ||
| 417 | struct ff_condition_effect *old_cond = &old->u.condition[i]; | ||
| 418 | |||
| 419 | ret |= cond->center != old_cond->center || | ||
| 420 | cond->right_coeff != old_cond->right_coeff || | ||
| 421 | cond->left_coeff != old_cond->left_coeff || | ||
| 422 | cond->right_saturation != old_cond->right_saturation || | ||
| 423 | cond->left_saturation != old_cond->left_saturation || | ||
| 424 | cond->deadband != old_cond->deadband; | ||
| 425 | } | ||
| 426 | |||
| 427 | return ret; | ||
| 428 | } | ||
| 429 | |||
| 430 | /* | ||
| 431 | * Send ramp force report to the device | ||
| 432 | */ | ||
| 433 | static void pidff_set_ramp_force_report(struct pidff_device *pidff, | ||
| 434 | struct ff_effect *effect) | ||
| 435 | { | ||
| 436 | pidff->set_ramp[PID_EFFECT_BLOCK_INDEX].value[0] = | ||
| 437 | pidff->block_load[PID_EFFECT_BLOCK_INDEX].value[0]; | ||
| 438 | pidff_set_signed(&pidff->set_ramp[PID_RAMP_START], | ||
| 439 | effect->u.ramp.start_level); | ||
| 440 | pidff_set_signed(&pidff->set_ramp[PID_RAMP_END], | ||
| 441 | effect->u.ramp.end_level); | ||
| 442 | usbhid_submit_report(pidff->hid, pidff->reports[PID_SET_RAMP], | ||
| 443 | USB_DIR_OUT); | ||
| 444 | } | ||
| 445 | |||
| 446 | /* | ||
| 447 | * Test if ramp force parameters have changed | ||
| 448 | */ | ||
| 449 | static int pidff_needs_set_ramp(struct ff_effect *effect, struct ff_effect *old) | ||
| 450 | { | ||
| 451 | return effect->u.ramp.start_level != old->u.ramp.start_level || | ||
| 452 | effect->u.ramp.end_level != old->u.ramp.end_level; | ||
| 453 | } | ||
| 454 | |||
| 455 | /* | ||
| 456 | * Send a request for effect upload to the device | ||
| 457 | * | ||
| 458 | * Returns 0 if device reported success, -ENOSPC if the device reported memory | ||
| 459 | * is full. Upon unknown response the function will retry for 60 times, if | ||
| 460 | * still unsuccessful -EIO is returned. | ||
| 461 | */ | ||
| 462 | static int pidff_request_effect_upload(struct pidff_device *pidff, int efnum) | ||
| 463 | { | ||
| 464 | int j; | ||
| 465 | |||
| 466 | pidff->create_new_effect_type->value[0] = efnum; | ||
| 467 | usbhid_submit_report(pidff->hid, pidff->reports[PID_CREATE_NEW_EFFECT], | ||
| 468 | USB_DIR_OUT); | ||
| 469 | debug("create_new_effect sent, type: %d", efnum); | ||
| 470 | |||
| 471 | pidff->block_load[PID_EFFECT_BLOCK_INDEX].value[0] = 0; | ||
| 472 | pidff->block_load_status->value[0] = 0; | ||
| 473 | usbhid_wait_io(pidff->hid); | ||
| 474 | |||
| 475 | for (j = 0; j < 60; j++) { | ||
| 476 | debug("pid_block_load requested"); | ||
| 477 | usbhid_submit_report(pidff->hid, pidff->reports[PID_BLOCK_LOAD], | ||
| 478 | USB_DIR_IN); | ||
| 479 | usbhid_wait_io(pidff->hid); | ||
| 480 | if (pidff->block_load_status->value[0] == | ||
| 481 | pidff->status_id[PID_BLOCK_LOAD_SUCCESS]) { | ||
| 482 | debug("device reported free memory: %d bytes", | ||
| 483 | pidff->block_load[PID_RAM_POOL_AVAILABLE].value ? | ||
| 484 | pidff->block_load[PID_RAM_POOL_AVAILABLE].value[0] : -1); | ||
| 485 | return 0; | ||
| 486 | } | ||
| 487 | if (pidff->block_load_status->value[0] == | ||
| 488 | pidff->status_id[PID_BLOCK_LOAD_FULL]) { | ||
| 489 | debug("not enough memory free: %d bytes", | ||
| 490 | pidff->block_load[PID_RAM_POOL_AVAILABLE].value ? | ||
| 491 | pidff->block_load[PID_RAM_POOL_AVAILABLE].value[0] : -1); | ||
| 492 | return -ENOSPC; | ||
| 493 | } | ||
| 494 | } | ||
| 495 | printk(KERN_ERR "hid-pidff: pid_block_load failed 60 times\n"); | ||
| 496 | return -EIO; | ||
| 497 | } | ||
| 498 | |||
| 499 | /* | ||
| 500 | * Play the effect with PID id n times | ||
| 501 | */ | ||
| 502 | static void pidff_playback_pid(struct pidff_device *pidff, int pid_id, int n) | ||
| 503 | { | ||
| 504 | pidff->effect_operation[PID_EFFECT_BLOCK_INDEX].value[0] = pid_id; | ||
| 505 | |||
| 506 | if (n == 0) { | ||
| 507 | pidff->effect_operation_status->value[0] = | ||
| 508 | pidff->operation_id[PID_EFFECT_STOP]; | ||
| 509 | } else { | ||
| 510 | pidff->effect_operation_status->value[0] = | ||
| 511 | pidff->operation_id[PID_EFFECT_START]; | ||
| 512 | pidff->effect_operation[PID_LOOP_COUNT].value[0] = n; | ||
| 513 | } | ||
| 514 | |||
| 515 | usbhid_wait_io(pidff->hid); | ||
| 516 | usbhid_submit_report(pidff->hid, pidff->reports[PID_EFFECT_OPERATION], | ||
| 517 | USB_DIR_OUT); | ||
| 518 | } | ||
| 519 | |||
| 520 | /** | ||
| 521 | * Play the effect with effect id @effect_id for @value times | ||
| 522 | */ | ||
| 523 | static int pidff_playback(struct input_dev *dev, int effect_id, int value) | ||
| 524 | { | ||
| 525 | struct pidff_device *pidff = dev->ff->private; | ||
| 526 | |||
| 527 | pidff_playback_pid(pidff, pidff->pid_id[effect_id], value); | ||
| 528 | |||
| 529 | return 0; | ||
| 530 | } | ||
| 531 | |||
| 532 | /* | ||
| 533 | * Erase effect with PID id | ||
| 534 | */ | ||
| 535 | static void pidff_erase_pid(struct pidff_device *pidff, int pid_id) | ||
| 536 | { | ||
| 537 | pidff->block_free[PID_EFFECT_BLOCK_INDEX].value[0] = pid_id; | ||
| 538 | usbhid_submit_report(pidff->hid, pidff->reports[PID_BLOCK_FREE], | ||
| 539 | USB_DIR_OUT); | ||
| 540 | } | ||
| 541 | |||
| 542 | /* | ||
| 543 | * Stop and erase effect with effect_id | ||
| 544 | */ | ||
| 545 | static int pidff_erase_effect(struct input_dev *dev, int effect_id) | ||
| 546 | { | ||
| 547 | struct pidff_device *pidff = dev->ff->private; | ||
| 548 | int pid_id = pidff->pid_id[effect_id]; | ||
| 549 | |||
| 550 | debug("starting to erase %d/%d", effect_id, pidff->pid_id[effect_id]); | ||
| 551 | pidff_playback_pid(pidff, pid_id, 0); | ||
| 552 | pidff_erase_pid(pidff, pid_id); | ||
| 553 | |||
| 554 | return 0; | ||
| 555 | } | ||
| 556 | |||
| 557 | /* | ||
| 558 | * Effect upload handler | ||
| 559 | */ | ||
| 560 | static int pidff_upload_effect(struct input_dev *dev, struct ff_effect *effect, | ||
| 561 | struct ff_effect *old) | ||
| 562 | { | ||
| 563 | struct pidff_device *pidff = dev->ff->private; | ||
| 564 | int type_id; | ||
| 565 | int error; | ||
| 566 | |||
| 567 | switch (effect->type) { | ||
| 568 | case FF_CONSTANT: | ||
| 569 | if (!old) { | ||
| 570 | error = pidff_request_effect_upload(pidff, | ||
| 571 | pidff->type_id[PID_CONSTANT]); | ||
| 572 | if (error) | ||
| 573 | return error; | ||
| 574 | } | ||
| 575 | if (!old || pidff_needs_set_effect(effect, old)) | ||
| 576 | pidff_set_effect_report(pidff, effect); | ||
| 577 | if (!old || pidff_needs_set_constant(effect, old)) | ||
| 578 | pidff_set_constant_force_report(pidff, effect); | ||
| 579 | if (!old || | ||
| 580 | pidff_needs_set_envelope(&effect->u.constant.envelope, | ||
| 581 | &old->u.constant.envelope)) | ||
| 582 | pidff_set_envelope_report(pidff, | ||
| 583 | &effect->u.constant.envelope); | ||
| 584 | break; | ||
| 585 | |||
| 586 | case FF_PERIODIC: | ||
| 587 | if (!old) { | ||
| 588 | switch (effect->u.periodic.waveform) { | ||
| 589 | case FF_SQUARE: | ||
| 590 | type_id = PID_SQUARE; | ||
| 591 | break; | ||
| 592 | case FF_TRIANGLE: | ||
| 593 | type_id = PID_TRIANGLE; | ||
| 594 | break; | ||
| 595 | case FF_SINE: | ||
| 596 | type_id = PID_SINE; | ||
| 597 | break; | ||
| 598 | case FF_SAW_UP: | ||
| 599 | type_id = PID_SAW_UP; | ||
| 600 | break; | ||
| 601 | case FF_SAW_DOWN: | ||
| 602 | type_id = PID_SAW_DOWN; | ||
| 603 | break; | ||
| 604 | default: | ||
| 605 | printk(KERN_ERR | ||
| 606 | "hid-pidff: invalid waveform\n"); | ||
| 607 | return -EINVAL; | ||
| 608 | } | ||
| 609 | |||
| 610 | error = pidff_request_effect_upload(pidff, | ||
| 611 | pidff->type_id[type_id]); | ||
| 612 | if (error) | ||
| 613 | return error; | ||
| 614 | } | ||
| 615 | if (!old || pidff_needs_set_effect(effect, old)) | ||
| 616 | pidff_set_effect_report(pidff, effect); | ||
| 617 | if (!old || pidff_needs_set_periodic(effect, old)) | ||
| 618 | pidff_set_periodic_report(pidff, effect); | ||
| 619 | if (!old || | ||
| 620 | pidff_needs_set_envelope(&effect->u.periodic.envelope, | ||
| 621 | &old->u.periodic.envelope)) | ||
| 622 | pidff_set_envelope_report(pidff, | ||
| 623 | &effect->u.periodic.envelope); | ||
| 624 | break; | ||
| 625 | |||
| 626 | case FF_RAMP: | ||
| 627 | if (!old) { | ||
| 628 | error = pidff_request_effect_upload(pidff, | ||
| 629 | pidff->type_id[PID_RAMP]); | ||
| 630 | if (error) | ||
| 631 | return error; | ||
| 632 | } | ||
| 633 | if (!old || pidff_needs_set_effect(effect, old)) | ||
| 634 | pidff_set_effect_report(pidff, effect); | ||
| 635 | if (!old || pidff_needs_set_ramp(effect, old)) | ||
| 636 | pidff_set_ramp_force_report(pidff, effect); | ||
| 637 | if (!old || | ||
| 638 | pidff_needs_set_envelope(&effect->u.ramp.envelope, | ||
| 639 | &old->u.ramp.envelope)) | ||
| 640 | pidff_set_envelope_report(pidff, | ||
| 641 | &effect->u.ramp.envelope); | ||
| 642 | break; | ||
| 643 | |||
| 644 | case FF_SPRING: | ||
| 645 | if (!old) { | ||
| 646 | error = pidff_request_effect_upload(pidff, | ||
| 647 | pidff->type_id[PID_SPRING]); | ||
| 648 | if (error) | ||
| 649 | return error; | ||
| 650 | } | ||
| 651 | if (!old || pidff_needs_set_effect(effect, old)) | ||
| 652 | pidff_set_effect_report(pidff, effect); | ||
| 653 | if (!old || pidff_needs_set_condition(effect, old)) | ||
| 654 | pidff_set_condition_report(pidff, effect); | ||
| 655 | break; | ||
| 656 | |||
| 657 | case FF_FRICTION: | ||
| 658 | if (!old) { | ||
| 659 | error = pidff_request_effect_upload(pidff, | ||
| 660 | pidff->type_id[PID_FRICTION]); | ||
| 661 | if (error) | ||
| 662 | return error; | ||
| 663 | } | ||
| 664 | if (!old || pidff_needs_set_effect(effect, old)) | ||
| 665 | pidff_set_effect_report(pidff, effect); | ||
| 666 | if (!old || pidff_needs_set_condition(effect, old)) | ||
| 667 | pidff_set_condition_report(pidff, effect); | ||
| 668 | break; | ||
| 669 | |||
| 670 | case FF_DAMPER: | ||
| 671 | if (!old) { | ||
| 672 | error = pidff_request_effect_upload(pidff, | ||
| 673 | pidff->type_id[PID_DAMPER]); | ||
| 674 | if (error) | ||
| 675 | return error; | ||
| 676 | } | ||
| 677 | if (!old || pidff_needs_set_effect(effect, old)) | ||
| 678 | pidff_set_effect_report(pidff, effect); | ||
| 679 | if (!old || pidff_needs_set_condition(effect, old)) | ||
| 680 | pidff_set_condition_report(pidff, effect); | ||
| 681 | break; | ||
| 682 | |||
| 683 | case FF_INERTIA: | ||
| 684 | if (!old) { | ||
| 685 | error = pidff_request_effect_upload(pidff, | ||
| 686 | pidff->type_id[PID_INERTIA]); | ||
| 687 | if (error) | ||
| 688 | return error; | ||
| 689 | } | ||
| 690 | if (!old || pidff_needs_set_effect(effect, old)) | ||
| 691 | pidff_set_effect_report(pidff, effect); | ||
| 692 | if (!old || pidff_needs_set_condition(effect, old)) | ||
| 693 | pidff_set_condition_report(pidff, effect); | ||
| 694 | break; | ||
| 695 | |||
| 696 | default: | ||
| 697 | printk(KERN_ERR "hid-pidff: invalid type\n"); | ||
| 698 | return -EINVAL; | ||
| 699 | } | ||
| 700 | |||
| 701 | if (!old) | ||
| 702 | pidff->pid_id[effect->id] = | ||
| 703 | pidff->block_load[PID_EFFECT_BLOCK_INDEX].value[0]; | ||
| 704 | |||
| 705 | debug("uploaded"); | ||
| 706 | |||
| 707 | return 0; | ||
| 708 | } | ||
| 709 | |||
| 710 | /* | ||
| 711 | * set_gain() handler | ||
| 712 | */ | ||
| 713 | static void pidff_set_gain(struct input_dev *dev, u16 gain) | ||
| 714 | { | ||
| 715 | struct pidff_device *pidff = dev->ff->private; | ||
| 716 | |||
| 717 | pidff_set(&pidff->device_gain[PID_DEVICE_GAIN_FIELD], gain); | ||
| 718 | usbhid_submit_report(pidff->hid, pidff->reports[PID_DEVICE_GAIN], | ||
| 719 | USB_DIR_OUT); | ||
| 720 | } | ||
| 721 | |||
| 722 | static void pidff_autocenter(struct pidff_device *pidff, u16 magnitude) | ||
| 723 | { | ||
| 724 | struct hid_field *field = | ||
| 725 | pidff->block_load[PID_EFFECT_BLOCK_INDEX].field; | ||
| 726 | |||
| 727 | if (!magnitude) { | ||
| 728 | pidff_playback_pid(pidff, field->logical_minimum, 0); | ||
| 729 | return; | ||
| 730 | } | ||
| 731 | |||
| 732 | pidff_playback_pid(pidff, field->logical_minimum, 1); | ||
| 733 | |||
| 734 | pidff->set_effect[PID_EFFECT_BLOCK_INDEX].value[0] = | ||
| 735 | pidff->block_load[PID_EFFECT_BLOCK_INDEX].field->logical_minimum; | ||
| 736 | pidff->set_effect_type->value[0] = pidff->type_id[PID_SPRING]; | ||
| 737 | pidff->set_effect[PID_DURATION].value[0] = 0; | ||
| 738 | pidff->set_effect[PID_TRIGGER_BUTTON].value[0] = 0; | ||
| 739 | pidff->set_effect[PID_TRIGGER_REPEAT_INT].value[0] = 0; | ||
| 740 | pidff_set(&pidff->set_effect[PID_GAIN], magnitude); | ||
| 741 | pidff->set_effect[PID_DIRECTION_ENABLE].value[0] = 1; | ||
| 742 | pidff->set_effect[PID_START_DELAY].value[0] = 0; | ||
| 743 | |||
| 744 | usbhid_submit_report(pidff->hid, pidff->reports[PID_SET_EFFECT], | ||
| 745 | USB_DIR_OUT); | ||
| 746 | } | ||
| 747 | |||
| 748 | /* | ||
| 749 | * pidff_set_autocenter() handler | ||
| 750 | */ | ||
| 751 | static void pidff_set_autocenter(struct input_dev *dev, u16 magnitude) | ||
| 752 | { | ||
| 753 | struct pidff_device *pidff = dev->ff->private; | ||
| 754 | |||
| 755 | pidff_autocenter(pidff, magnitude); | ||
| 756 | } | ||
| 757 | |||
| 758 | /* | ||
| 759 | * Find fields from a report and fill a pidff_usage | ||
| 760 | */ | ||
| 761 | static int pidff_find_fields(struct pidff_usage *usage, const u8 *table, | ||
| 762 | struct hid_report *report, int count, int strict) | ||
| 763 | { | ||
| 764 | int i, j, k, found; | ||
| 765 | |||
| 766 | for (k = 0; k < count; k++) { | ||
| 767 | found = 0; | ||
| 768 | for (i = 0; i < report->maxfield; i++) { | ||
| 769 | if (report->field[i]->maxusage != | ||
| 770 | report->field[i]->report_count) { | ||
| 771 | debug("maxusage and report_count do not match, " | ||
| 772 | "skipping"); | ||
| 773 | continue; | ||
| 774 | } | ||
| 775 | for (j = 0; j < report->field[i]->maxusage; j++) { | ||
| 776 | if (report->field[i]->usage[j].hid == | ||
| 777 | (HID_UP_PID | table[k])) { | ||
| 778 | debug("found %d at %d->%d", k, i, j); | ||
| 779 | usage[k].field = report->field[i]; | ||
| 780 | usage[k].value = | ||
| 781 | &report->field[i]->value[j]; | ||
| 782 | found = 1; | ||
| 783 | break; | ||
| 784 | } | ||
| 785 | } | ||
| 786 | if (found) | ||
| 787 | break; | ||
| 788 | } | ||
| 789 | if (!found && strict) { | ||
| 790 | debug("failed to locate %d", k); | ||
| 791 | return -1; | ||
| 792 | } | ||
| 793 | } | ||
| 794 | return 0; | ||
| 795 | } | ||
| 796 | |||
| 797 | /* | ||
| 798 | * Return index into pidff_reports for the given usage | ||
| 799 | */ | ||
| 800 | static int pidff_check_usage(int usage) | ||
| 801 | { | ||
| 802 | int i; | ||
| 803 | |||
| 804 | for (i = 0; i < sizeof(pidff_reports); i++) | ||
| 805 | if (usage == (HID_UP_PID | pidff_reports[i])) | ||
| 806 | return i; | ||
| 807 | |||
| 808 | return -1; | ||
| 809 | } | ||
| 810 | |||
| 811 | /* | ||
| 812 | * Find the reports and fill pidff->reports[] | ||
| 813 | * report_type specifies either OUTPUT or FEATURE reports | ||
| 814 | */ | ||
| 815 | static void pidff_find_reports(struct hid_device *hid, int report_type, | ||
| 816 | struct pidff_device *pidff) | ||
| 817 | { | ||
| 818 | struct hid_report *report; | ||
| 819 | int i, ret; | ||
| 820 | |||
| 821 | list_for_each_entry(report, | ||
| 822 | &hid->report_enum[report_type].report_list, list) { | ||
| 823 | if (report->maxfield < 1) | ||
| 824 | continue; | ||
| 825 | ret = pidff_check_usage(report->field[0]->logical); | ||
| 826 | if (ret != -1) { | ||
| 827 | debug("found usage 0x%02x from field->logical", | ||
| 828 | pidff_reports[ret]); | ||
| 829 | pidff->reports[ret] = report; | ||
| 830 | continue; | ||
| 831 | } | ||
| 832 | |||
| 833 | /* | ||
| 834 | * Sometimes logical collections are stacked to indicate | ||
| 835 | * different usages for the report and the field, in which | ||
| 836 | * case we want the usage of the parent. However, Linux HID | ||
| 837 | * implementation hides this fact, so we have to dig it up | ||
| 838 | * ourselves | ||
| 839 | */ | ||
| 840 | i = report->field[0]->usage[0].collection_index; | ||
| 841 | if (i <= 0 || | ||
| 842 | hid->collection[i - 1].type != HID_COLLECTION_LOGICAL) | ||
| 843 | continue; | ||
| 844 | ret = pidff_check_usage(hid->collection[i - 1].usage); | ||
| 845 | if (ret != -1 && !pidff->reports[ret]) { | ||
| 846 | debug("found usage 0x%02x from collection array", | ||
| 847 | pidff_reports[ret]); | ||
| 848 | pidff->reports[ret] = report; | ||
| 849 | } | ||
| 850 | } | ||
| 851 | } | ||
| 852 | |||
| 853 | /* | ||
| 854 | * Test if the required reports have been found | ||
| 855 | */ | ||
| 856 | static int pidff_reports_ok(struct pidff_device *pidff) | ||
| 857 | { | ||
| 858 | int i; | ||
| 859 | |||
| 860 | for (i = 0; i <= PID_REQUIRED_REPORTS; i++) { | ||
| 861 | if (!pidff->reports[i]) { | ||
| 862 | debug("%d missing", i); | ||
| 863 | return 0; | ||
| 864 | } | ||
| 865 | } | ||
| 866 | |||
| 867 | return 1; | ||
| 868 | } | ||
| 869 | |||
| 870 | /* | ||
| 871 | * Find a field with a specific usage within a report | ||
| 872 | */ | ||
| 873 | static struct hid_field *pidff_find_special_field(struct hid_report *report, | ||
| 874 | int usage, int enforce_min) | ||
| 875 | { | ||
| 876 | int i; | ||
| 877 | |||
| 878 | for (i = 0; i < report->maxfield; i++) { | ||
| 879 | if (report->field[i]->logical == (HID_UP_PID | usage) && | ||
| 880 | report->field[i]->report_count > 0) { | ||
| 881 | if (!enforce_min || | ||
| 882 | report->field[i]->logical_minimum == 1) | ||
| 883 | return report->field[i]; | ||
| 884 | else { | ||
| 885 | printk(KERN_ERR "hid-pidff: logical_minimum " | ||
| 886 | "is not 1 as it should be\n"); | ||
| 887 | return NULL; | ||
| 888 | } | ||
| 889 | } | ||
| 890 | } | ||
| 891 | return NULL; | ||
| 892 | } | ||
| 893 | |||
| 894 | /* | ||
| 895 | * Fill a pidff->*_id struct table | ||
| 896 | */ | ||
| 897 | static int pidff_find_special_keys(int *keys, struct hid_field *fld, | ||
| 898 | const u8 *usagetable, int count) | ||
| 899 | { | ||
| 900 | |||
| 901 | int i, j; | ||
| 902 | int found = 0; | ||
| 903 | |||
| 904 | for (i = 0; i < count; i++) { | ||
| 905 | for (j = 0; j < fld->maxusage; j++) { | ||
| 906 | if (fld->usage[j].hid == (HID_UP_PID | usagetable[i])) { | ||
| 907 | keys[i] = j + 1; | ||
| 908 | found++; | ||
| 909 | break; | ||
| 910 | } | ||
| 911 | } | ||
| 912 | } | ||
| 913 | return found; | ||
| 914 | } | ||
| 915 | |||
| 916 | #define PIDFF_FIND_SPECIAL_KEYS(keys, field, name) \ | ||
| 917 | pidff_find_special_keys(pidff->keys, pidff->field, pidff_ ## name, \ | ||
| 918 | sizeof(pidff_ ## name)) | ||
| 919 | |||
| 920 | /* | ||
| 921 | * Find and check the special fields | ||
| 922 | */ | ||
| 923 | static int pidff_find_special_fields(struct pidff_device *pidff) | ||
| 924 | { | ||
| 925 | debug("finding special fields"); | ||
| 926 | |||
| 927 | pidff->create_new_effect_type = | ||
| 928 | pidff_find_special_field(pidff->reports[PID_CREATE_NEW_EFFECT], | ||
| 929 | 0x25, 1); | ||
| 930 | pidff->set_effect_type = | ||
| 931 | pidff_find_special_field(pidff->reports[PID_SET_EFFECT], | ||
| 932 | 0x25, 1); | ||
| 933 | pidff->effect_direction = | ||
| 934 | pidff_find_special_field(pidff->reports[PID_SET_EFFECT], | ||
| 935 | 0x57, 0); | ||
| 936 | pidff->device_control = | ||
| 937 | pidff_find_special_field(pidff->reports[PID_DEVICE_CONTROL], | ||
| 938 | 0x96, 1); | ||
| 939 | pidff->block_load_status = | ||
| 940 | pidff_find_special_field(pidff->reports[PID_BLOCK_LOAD], | ||
| 941 | 0x8b, 1); | ||
| 942 | pidff->effect_operation_status = | ||
| 943 | pidff_find_special_field(pidff->reports[PID_EFFECT_OPERATION], | ||
| 944 | 0x78, 1); | ||
| 945 | |||
| 946 | debug("search done"); | ||
| 947 | |||
| 948 | if (!pidff->create_new_effect_type || !pidff->set_effect_type) { | ||
| 949 | printk(KERN_ERR "hid-pidff: effect lists not found\n"); | ||
| 950 | return -1; | ||
| 951 | } | ||
| 952 | |||
| 953 | if (!pidff->effect_direction) { | ||
| 954 | printk(KERN_ERR "hid-pidff: direction field not found\n"); | ||
| 955 | return -1; | ||
| 956 | } | ||
| 957 | |||
| 958 | if (!pidff->device_control) { | ||
| 959 | printk(KERN_ERR "hid-pidff: device control field not found\n"); | ||
| 960 | return -1; | ||
| 961 | } | ||
| 962 | |||
| 963 | if (!pidff->block_load_status) { | ||
| 964 | printk(KERN_ERR | ||
| 965 | "hid-pidff: block load status field not found\n"); | ||
| 966 | return -1; | ||
| 967 | } | ||
| 968 | |||
| 969 | if (!pidff->effect_operation_status) { | ||
| 970 | printk(KERN_ERR | ||
| 971 | "hid-pidff: effect operation field not found\n"); | ||
| 972 | return -1; | ||
| 973 | } | ||
| 974 | |||
| 975 | pidff_find_special_keys(pidff->control_id, pidff->device_control, | ||
| 976 | pidff_device_control, | ||
| 977 | sizeof(pidff_device_control)); | ||
| 978 | |||
| 979 | PIDFF_FIND_SPECIAL_KEYS(control_id, device_control, device_control); | ||
| 980 | |||
| 981 | if (!PIDFF_FIND_SPECIAL_KEYS(type_id, create_new_effect_type, | ||
| 982 | effect_types)) { | ||
| 983 | printk(KERN_ERR "hid-pidff: no effect types found\n"); | ||
| 984 | return -1; | ||
| 985 | } | ||
| 986 | |||
| 987 | if (PIDFF_FIND_SPECIAL_KEYS(status_id, block_load_status, | ||
| 988 | block_load_status) != | ||
| 989 | sizeof(pidff_block_load_status)) { | ||
| 990 | printk(KERN_ERR | ||
| 991 | "hidpidff: block load status identifiers not found\n"); | ||
| 992 | return -1; | ||
| 993 | } | ||
| 994 | |||
| 995 | if (PIDFF_FIND_SPECIAL_KEYS(operation_id, effect_operation_status, | ||
| 996 | effect_operation_status) != | ||
| 997 | sizeof(pidff_effect_operation_status)) { | ||
| 998 | printk(KERN_ERR | ||
| 999 | "hidpidff: effect operation identifiers not found\n"); | ||
| 1000 | return -1; | ||
| 1001 | } | ||
| 1002 | |||
| 1003 | return 0; | ||
| 1004 | } | ||
| 1005 | |||
| 1006 | /** | ||
| 1007 | * Find the implemented effect types | ||
| 1008 | */ | ||
| 1009 | static int pidff_find_effects(struct pidff_device *pidff, | ||
| 1010 | struct input_dev *dev) | ||
| 1011 | { | ||
| 1012 | int i; | ||
| 1013 | |||
| 1014 | for (i = 0; i < sizeof(pidff_effect_types); i++) { | ||
| 1015 | int pidff_type = pidff->type_id[i]; | ||
| 1016 | if (pidff->set_effect_type->usage[pidff_type].hid != | ||
| 1017 | pidff->create_new_effect_type->usage[pidff_type].hid) { | ||
| 1018 | printk(KERN_ERR "hid-pidff: " | ||
| 1019 | "effect type number %d is invalid\n", i); | ||
| 1020 | return -1; | ||
| 1021 | } | ||
| 1022 | } | ||
| 1023 | |||
| 1024 | if (pidff->type_id[PID_CONSTANT]) | ||
| 1025 | set_bit(FF_CONSTANT, dev->ffbit); | ||
| 1026 | if (pidff->type_id[PID_RAMP]) | ||
| 1027 | set_bit(FF_RAMP, dev->ffbit); | ||
| 1028 | if (pidff->type_id[PID_SQUARE]) { | ||
| 1029 | set_bit(FF_SQUARE, dev->ffbit); | ||
| 1030 | set_bit(FF_PERIODIC, dev->ffbit); | ||
| 1031 | } | ||
| 1032 | if (pidff->type_id[PID_SINE]) { | ||
| 1033 | set_bit(FF_SINE, dev->ffbit); | ||
| 1034 | set_bit(FF_PERIODIC, dev->ffbit); | ||
| 1035 | } | ||
| 1036 | if (pidff->type_id[PID_TRIANGLE]) { | ||
| 1037 | set_bit(FF_TRIANGLE, dev->ffbit); | ||
| 1038 | set_bit(FF_PERIODIC, dev->ffbit); | ||
| 1039 | } | ||
| 1040 | if (pidff->type_id[PID_SAW_UP]) { | ||
| 1041 | set_bit(FF_SAW_UP, dev->ffbit); | ||
| 1042 | set_bit(FF_PERIODIC, dev->ffbit); | ||
| 1043 | } | ||
| 1044 | if (pidff->type_id[PID_SAW_DOWN]) { | ||
| 1045 | set_bit(FF_SAW_DOWN, dev->ffbit); | ||
| 1046 | set_bit(FF_PERIODIC, dev->ffbit); | ||
| 1047 | } | ||
| 1048 | if (pidff->type_id[PID_SPRING]) | ||
| 1049 | set_bit(FF_SPRING, dev->ffbit); | ||
| 1050 | if (pidff->type_id[PID_DAMPER]) | ||
| 1051 | set_bit(FF_DAMPER, dev->ffbit); | ||
| 1052 | if (pidff->type_id[PID_INERTIA]) | ||
| 1053 | set_bit(FF_INERTIA, dev->ffbit); | ||
| 1054 | if (pidff->type_id[PID_FRICTION]) | ||
| 1055 | set_bit(FF_FRICTION, dev->ffbit); | ||
| 1056 | |||
| 1057 | return 0; | ||
| 1058 | |||
| 1059 | } | ||
| 1060 | |||
| 1061 | #define PIDFF_FIND_FIELDS(name, report, strict) \ | ||
| 1062 | pidff_find_fields(pidff->name, pidff_ ## name, \ | ||
| 1063 | pidff->reports[report], \ | ||
| 1064 | sizeof(pidff_ ## name), strict) | ||
| 1065 | |||
| 1066 | /* | ||
| 1067 | * Fill and check the pidff_usages | ||
| 1068 | */ | ||
| 1069 | static int pidff_init_fields(struct pidff_device *pidff, struct input_dev *dev) | ||
| 1070 | { | ||
| 1071 | int envelope_ok = 0; | ||
| 1072 | |||
| 1073 | if (PIDFF_FIND_FIELDS(set_effect, PID_SET_EFFECT, 1)) { | ||
| 1074 | printk(KERN_ERR | ||
| 1075 | "hid-pidff: unknown set_effect report layout\n"); | ||
| 1076 | return -ENODEV; | ||
| 1077 | } | ||
| 1078 | |||
| 1079 | PIDFF_FIND_FIELDS(block_load, PID_BLOCK_LOAD, 0); | ||
| 1080 | if (!pidff->block_load[PID_EFFECT_BLOCK_INDEX].value) { | ||
| 1081 | printk(KERN_ERR | ||
| 1082 | "hid-pidff: unknown pid_block_load report layout\n"); | ||
| 1083 | return -ENODEV; | ||
| 1084 | } | ||
| 1085 | |||
| 1086 | if (PIDFF_FIND_FIELDS(effect_operation, PID_EFFECT_OPERATION, 1)) { | ||
| 1087 | printk(KERN_ERR | ||
| 1088 | "hid-pidff: unknown effect_operation report layout\n"); | ||
| 1089 | return -ENODEV; | ||
| 1090 | } | ||
| 1091 | |||
| 1092 | if (PIDFF_FIND_FIELDS(block_free, PID_BLOCK_FREE, 1)) { | ||
| 1093 | printk(KERN_ERR | ||
| 1094 | "hid-pidff: unknown pid_block_free report layout\n"); | ||
| 1095 | return -ENODEV; | ||
| 1096 | } | ||
| 1097 | |||
| 1098 | if (!PIDFF_FIND_FIELDS(set_envelope, PID_SET_ENVELOPE, 1)) | ||
| 1099 | envelope_ok = 1; | ||
| 1100 | |||
| 1101 | if (pidff_find_special_fields(pidff) || pidff_find_effects(pidff, dev)) | ||
| 1102 | return -ENODEV; | ||
| 1103 | |||
| 1104 | if (!envelope_ok) { | ||
| 1105 | if (test_and_clear_bit(FF_CONSTANT, dev->ffbit)) | ||
| 1106 | printk(KERN_WARNING "hid-pidff: " | ||
| 1107 | "has constant effect but no envelope\n"); | ||
| 1108 | if (test_and_clear_bit(FF_RAMP, dev->ffbit)) | ||
| 1109 | printk(KERN_WARNING "hid-pidff: " | ||
| 1110 | "has ramp effect but no envelope\n"); | ||
| 1111 | |||
| 1112 | if (test_and_clear_bit(FF_PERIODIC, dev->ffbit)) | ||
| 1113 | printk(KERN_WARNING "hid-pidff: " | ||
| 1114 | "has periodic effect but no envelope\n"); | ||
| 1115 | } | ||
| 1116 | |||
| 1117 | if (test_bit(FF_CONSTANT, dev->ffbit) && | ||
| 1118 | PIDFF_FIND_FIELDS(set_constant, PID_SET_CONSTANT, 1)) { | ||
| 1119 | printk(KERN_WARNING | ||
| 1120 | "hid-pidff: unknown constant effect layout\n"); | ||
| 1121 | clear_bit(FF_CONSTANT, dev->ffbit); | ||
| 1122 | } | ||
| 1123 | |||
| 1124 | if (test_bit(FF_RAMP, dev->ffbit) && | ||
| 1125 | PIDFF_FIND_FIELDS(set_ramp, PID_SET_RAMP, 1)) { | ||
| 1126 | printk(KERN_WARNING "hid-pidff: unknown ramp effect layout\n"); | ||
| 1127 | clear_bit(FF_RAMP, dev->ffbit); | ||
| 1128 | } | ||
| 1129 | |||
| 1130 | if ((test_bit(FF_SPRING, dev->ffbit) || | ||
| 1131 | test_bit(FF_DAMPER, dev->ffbit) || | ||
| 1132 | test_bit(FF_FRICTION, dev->ffbit) || | ||
| 1133 | test_bit(FF_INERTIA, dev->ffbit)) && | ||
| 1134 | PIDFF_FIND_FIELDS(set_condition, PID_SET_CONDITION, 1)) { | ||
| 1135 | printk(KERN_WARNING | ||
| 1136 | "hid-pidff: unknown condition effect layout\n"); | ||
| 1137 | clear_bit(FF_SPRING, dev->ffbit); | ||
| 1138 | clear_bit(FF_DAMPER, dev->ffbit); | ||
| 1139 | clear_bit(FF_FRICTION, dev->ffbit); | ||
| 1140 | clear_bit(FF_INERTIA, dev->ffbit); | ||
| 1141 | } | ||
| 1142 | |||
| 1143 | if (test_bit(FF_PERIODIC, dev->ffbit) && | ||
| 1144 | PIDFF_FIND_FIELDS(set_periodic, PID_SET_PERIODIC, 1)) { | ||
| 1145 | printk(KERN_WARNING | ||
| 1146 | "hid-pidff: unknown periodic effect layout\n"); | ||
| 1147 | clear_bit(FF_PERIODIC, dev->ffbit); | ||
| 1148 | } | ||
| 1149 | |||
| 1150 | PIDFF_FIND_FIELDS(pool, PID_POOL, 0); | ||
| 1151 | |||
| 1152 | if (!PIDFF_FIND_FIELDS(device_gain, PID_DEVICE_GAIN, 1)) | ||
| 1153 | set_bit(FF_GAIN, dev->ffbit); | ||
| 1154 | |||
| 1155 | return 0; | ||
| 1156 | } | ||
| 1157 | |||
| 1158 | /* | ||
| 1159 | * Reset the device | ||
| 1160 | */ | ||
| 1161 | static void pidff_reset(struct pidff_device *pidff) | ||
| 1162 | { | ||
| 1163 | struct hid_device *hid = pidff->hid; | ||
| 1164 | int i = 0; | ||
| 1165 | |||
| 1166 | pidff->device_control->value[0] = pidff->control_id[PID_RESET]; | ||
| 1167 | /* We reset twice as sometimes hid_wait_io isn't waiting long enough */ | ||
| 1168 | usbhid_submit_report(hid, pidff->reports[PID_DEVICE_CONTROL], USB_DIR_OUT); | ||
| 1169 | usbhid_wait_io(hid); | ||
| 1170 | usbhid_submit_report(hid, pidff->reports[PID_DEVICE_CONTROL], USB_DIR_OUT); | ||
| 1171 | usbhid_wait_io(hid); | ||
| 1172 | |||
| 1173 | pidff->device_control->value[0] = | ||
| 1174 | pidff->control_id[PID_ENABLE_ACTUATORS]; | ||
| 1175 | usbhid_submit_report(hid, pidff->reports[PID_DEVICE_CONTROL], USB_DIR_OUT); | ||
| 1176 | usbhid_wait_io(hid); | ||
| 1177 | |||
| 1178 | /* pool report is sometimes messed up, refetch it */ | ||
| 1179 | usbhid_submit_report(hid, pidff->reports[PID_POOL], USB_DIR_IN); | ||
| 1180 | usbhid_wait_io(hid); | ||
| 1181 | |||
| 1182 | if (pidff->pool[PID_SIMULTANEOUS_MAX].value) { | ||
| 1183 | int sim_effects = pidff->pool[PID_SIMULTANEOUS_MAX].value[0]; | ||
| 1184 | while (sim_effects < 2) { | ||
| 1185 | if (i++ > 20) { | ||
| 1186 | printk(KERN_WARNING "hid-pidff: device reports " | ||
| 1187 | "%d simultaneous effects\n", | ||
| 1188 | sim_effects); | ||
| 1189 | break; | ||
| 1190 | } | ||
| 1191 | debug("pid_pool requested again"); | ||
| 1192 | usbhid_submit_report(hid, pidff->reports[PID_POOL], | ||
| 1193 | USB_DIR_IN); | ||
| 1194 | usbhid_wait_io(hid); | ||
| 1195 | } | ||
| 1196 | } | ||
| 1197 | } | ||
| 1198 | |||
| 1199 | /* | ||
| 1200 | * Test if autocenter modification is using the supported method | ||
| 1201 | */ | ||
| 1202 | static int pidff_check_autocenter(struct pidff_device *pidff, | ||
| 1203 | struct input_dev *dev) | ||
| 1204 | { | ||
| 1205 | int error; | ||
| 1206 | |||
| 1207 | /* | ||
| 1208 | * Let's find out if autocenter modification is supported | ||
| 1209 | * Specification doesn't specify anything, so we request an | ||
| 1210 | * effect upload and cancel it immediately. If the approved | ||
| 1211 | * effect id was one above the minimum, then we assume the first | ||
| 1212 | * effect id is a built-in spring type effect used for autocenter | ||
| 1213 | */ | ||
| 1214 | |||
| 1215 | error = pidff_request_effect_upload(pidff, 1); | ||
| 1216 | if (error) { | ||
| 1217 | printk(KERN_ERR "hid-pidff: upload request failed\n"); | ||
| 1218 | return error; | ||
| 1219 | } | ||
| 1220 | |||
| 1221 | if (pidff->block_load[PID_EFFECT_BLOCK_INDEX].value[0] == | ||
| 1222 | pidff->block_load[PID_EFFECT_BLOCK_INDEX].field->logical_minimum + 1) { | ||
| 1223 | pidff_autocenter(pidff, 0xffff); | ||
| 1224 | set_bit(FF_AUTOCENTER, dev->ffbit); | ||
| 1225 | } else { | ||
| 1226 | printk(KERN_NOTICE "hid-pidff: " | ||
| 1227 | "device has unknown autocenter control method\n"); | ||
| 1228 | } | ||
| 1229 | |||
| 1230 | pidff_erase_pid(pidff, | ||
| 1231 | pidff->block_load[PID_EFFECT_BLOCK_INDEX].value[0]); | ||
| 1232 | |||
| 1233 | return 0; | ||
| 1234 | |||
| 1235 | } | ||
| 1236 | |||
| 1237 | /* | ||
| 1238 | * Check if the device is PID and initialize it | ||
| 1239 | */ | ||
| 1240 | int hid_pidff_init(struct hid_device *hid) | ||
| 1241 | { | ||
| 1242 | struct pidff_device *pidff; | ||
| 1243 | struct hid_input *hidinput = list_entry(hid->inputs.next, | ||
| 1244 | struct hid_input, list); | ||
| 1245 | struct input_dev *dev = hidinput->input; | ||
| 1246 | struct ff_device *ff; | ||
| 1247 | int max_effects; | ||
| 1248 | int error; | ||
| 1249 | |||
| 1250 | debug("starting pid init"); | ||
| 1251 | |||
| 1252 | if (list_empty(&hid->report_enum[HID_OUTPUT_REPORT].report_list)) { | ||
| 1253 | debug("not a PID device, no output report"); | ||
| 1254 | return -ENODEV; | ||
| 1255 | } | ||
| 1256 | |||
| 1257 | pidff = kzalloc(sizeof(*pidff), GFP_KERNEL); | ||
| 1258 | if (!pidff) | ||
| 1259 | return -ENOMEM; | ||
| 1260 | |||
| 1261 | pidff->hid = hid; | ||
| 1262 | |||
| 1263 | pidff_find_reports(hid, HID_OUTPUT_REPORT, pidff); | ||
| 1264 | pidff_find_reports(hid, HID_FEATURE_REPORT, pidff); | ||
| 1265 | |||
| 1266 | if (!pidff_reports_ok(pidff)) { | ||
| 1267 | debug("reports not ok, aborting"); | ||
| 1268 | error = -ENODEV; | ||
| 1269 | goto fail; | ||
| 1270 | } | ||
| 1271 | |||
| 1272 | error = pidff_init_fields(pidff, dev); | ||
| 1273 | if (error) | ||
| 1274 | goto fail; | ||
| 1275 | |||
| 1276 | pidff_reset(pidff); | ||
| 1277 | |||
| 1278 | if (test_bit(FF_GAIN, dev->ffbit)) { | ||
| 1279 | pidff_set(&pidff->device_gain[PID_DEVICE_GAIN_FIELD], 0xffff); | ||
| 1280 | usbhid_submit_report(pidff->hid, pidff->reports[PID_DEVICE_GAIN], | ||
| 1281 | USB_DIR_OUT); | ||
| 1282 | } | ||
| 1283 | |||
| 1284 | error = pidff_check_autocenter(pidff, dev); | ||
| 1285 | if (error) | ||
| 1286 | goto fail; | ||
| 1287 | |||
| 1288 | max_effects = | ||
| 1289 | pidff->block_load[PID_EFFECT_BLOCK_INDEX].field->logical_maximum - | ||
| 1290 | pidff->block_load[PID_EFFECT_BLOCK_INDEX].field->logical_minimum + | ||
| 1291 | 1; | ||
| 1292 | debug("max effects is %d", max_effects); | ||
| 1293 | |||
| 1294 | if (max_effects > PID_EFFECTS_MAX) | ||
| 1295 | max_effects = PID_EFFECTS_MAX; | ||
| 1296 | |||
| 1297 | if (pidff->pool[PID_SIMULTANEOUS_MAX].value) | ||
| 1298 | debug("max simultaneous effects is %d", | ||
| 1299 | pidff->pool[PID_SIMULTANEOUS_MAX].value[0]); | ||
| 1300 | |||
| 1301 | if (pidff->pool[PID_RAM_POOL_SIZE].value) | ||
| 1302 | debug("device memory size is %d bytes", | ||
| 1303 | pidff->pool[PID_RAM_POOL_SIZE].value[0]); | ||
| 1304 | |||
| 1305 | if (pidff->pool[PID_DEVICE_MANAGED_POOL].value && | ||
| 1306 | pidff->pool[PID_DEVICE_MANAGED_POOL].value[0] == 0) { | ||
| 1307 | printk(KERN_NOTICE "hid-pidff: " | ||
| 1308 | "device does not support device managed pool\n"); | ||
| 1309 | goto fail; | ||
| 1310 | } | ||
| 1311 | |||
| 1312 | error = input_ff_create(dev, max_effects); | ||
| 1313 | if (error) | ||
| 1314 | goto fail; | ||
| 1315 | |||
| 1316 | ff = dev->ff; | ||
| 1317 | ff->private = pidff; | ||
| 1318 | ff->upload = pidff_upload_effect; | ||
| 1319 | ff->erase = pidff_erase_effect; | ||
| 1320 | ff->set_gain = pidff_set_gain; | ||
| 1321 | ff->set_autocenter = pidff_set_autocenter; | ||
| 1322 | ff->playback = pidff_playback; | ||
| 1323 | |||
| 1324 | printk(KERN_INFO "Force feedback for USB HID PID devices by " | ||
| 1325 | "Anssi Hannula <anssi.hannula@gmail.com>\n"); | ||
| 1326 | |||
| 1327 | return 0; | ||
| 1328 | |||
| 1329 | fail: | ||
| 1330 | kfree(pidff); | ||
| 1331 | return error; | ||
| 1332 | } | ||
diff --git a/usr/src/dkms_source_tree/hid-plff.c b/usr/src/dkms_source_tree/hid-plff.c new file mode 100644 index 0000000..9eb83cf --- /dev/null +++ b/usr/src/dkms_source_tree/hid-plff.c | |||
| @@ -0,0 +1,139 @@ | |||
| 1 | /* | ||
| 2 | * Force feedback support for PantherLord/GreenAsia based devices | ||
| 3 | * | ||
| 4 | * The devices are distributed under various names and the same USB device ID | ||
| 5 | * can be used in both adapters and actual game controllers. | ||
| 6 | * | ||
| 7 | * 0810:0001 "Twin USB Joystick" | ||
| 8 | * - tested with PantherLord USB/PS2 2in1 Adapter | ||
| 9 | * - contains two reports, one for each port (HID_QUIRK_MULTI_INPUT) | ||
| 10 | * | ||
| 11 | * 0e8f:0003 "GreenAsia Inc. USB Joystick " | ||
| 12 | * - tested with Köng Gaming gamepad | ||
| 13 | * | ||
| 14 | * Copyright (c) 2007 Anssi Hannula <anssi.hannula@gmail.com> | ||
| 15 | */ | ||
| 16 | |||
| 17 | /* | ||
| 18 | * This program is free software; you can redistribute it and/or modify | ||
| 19 | * it under the terms of the GNU General Public License as published by | ||
| 20 | * the Free Software Foundation; either version 2 of the License, or | ||
| 21 | * (at your option) any later version. | ||
| 22 | * | ||
| 23 | * This program is distributed in the hope that it will be useful, | ||
| 24 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 25 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 26 | * GNU General Public License for more details. | ||
| 27 | * | ||
| 28 | * You should have received a copy of the GNU General Public License | ||
| 29 | * along with this program; if not, write to the Free Software | ||
| 30 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 31 | */ | ||
| 32 | |||
| 33 | |||
| 34 | /* #define DEBUG */ | ||
| 35 | |||
| 36 | #define debug(format, arg...) pr_debug("hid-plff: " format "\n" , ## arg) | ||
| 37 | |||
| 38 | #include <linux/input.h> | ||
| 39 | #include <linux/usb.h> | ||
| 40 | #include <linux/hid.h> | ||
| 41 | #include "usbhid.h" | ||
| 42 | |||
| 43 | struct plff_device { | ||
| 44 | struct hid_report *report; | ||
| 45 | }; | ||
| 46 | |||
| 47 | static int hid_plff_play(struct input_dev *dev, void *data, | ||
| 48 | struct ff_effect *effect) | ||
| 49 | { | ||
| 50 | struct hid_device *hid = input_get_drvdata(dev); | ||
| 51 | struct plff_device *plff = data; | ||
| 52 | int left, right; | ||
| 53 | |||
| 54 | left = effect->u.rumble.strong_magnitude; | ||
| 55 | right = effect->u.rumble.weak_magnitude; | ||
| 56 | debug("called with 0x%04x 0x%04x", left, right); | ||
| 57 | |||
| 58 | left = left * 0x7f / 0xffff; | ||
| 59 | right = right * 0x7f / 0xffff; | ||
| 60 | |||
| 61 | plff->report->field[0]->value[2] = left; | ||
| 62 | plff->report->field[0]->value[3] = right; | ||
| 63 | debug("running with 0x%02x 0x%02x", left, right); | ||
| 64 | usbhid_submit_report(hid, plff->report, USB_DIR_OUT); | ||
| 65 | |||
| 66 | return 0; | ||
| 67 | } | ||
| 68 | |||
| 69 | int hid_plff_init(struct hid_device *hid) | ||
| 70 | { | ||
| 71 | struct plff_device *plff; | ||
| 72 | struct hid_report *report; | ||
| 73 | struct hid_input *hidinput; | ||
| 74 | struct list_head *report_list = | ||
| 75 | &hid->report_enum[HID_OUTPUT_REPORT].report_list; | ||
| 76 | struct list_head *report_ptr = report_list; | ||
| 77 | struct input_dev *dev; | ||
| 78 | int error; | ||
| 79 | |||
| 80 | /* The device contains one output report per physical device, all | ||
| 81 | containing 1 field, which contains 4 ff00.0002 usages and 4 16bit | ||
| 82 | absolute values. | ||
| 83 | |||
| 84 | The input reports also contain a field which contains | ||
| 85 | 8 ff00.0001 usages and 8 boolean values. Their meaning is | ||
| 86 | currently unknown. */ | ||
| 87 | |||
| 88 | if (list_empty(report_list)) { | ||
| 89 | printk(KERN_ERR "hid-plff: no output reports found\n"); | ||
| 90 | return -ENODEV; | ||
| 91 | } | ||
| 92 | |||
| 93 | list_for_each_entry(hidinput, &hid->inputs, list) { | ||
| 94 | |||
| 95 | report_ptr = report_ptr->next; | ||
| 96 | |||
| 97 | if (report_ptr == report_list) { | ||
| 98 | printk(KERN_ERR "hid-plff: required output report is missing\n"); | ||
| 99 | return -ENODEV; | ||
| 100 | } | ||
| 101 | |||
| 102 | report = list_entry(report_ptr, struct hid_report, list); | ||
| 103 | if (report->maxfield < 1) { | ||
| 104 | printk(KERN_ERR "hid-plff: no fields in the report\n"); | ||
| 105 | return -ENODEV; | ||
| 106 | } | ||
| 107 | |||
| 108 | if (report->field[0]->report_count < 4) { | ||
| 109 | printk(KERN_ERR "hid-plff: not enough values in the field\n"); | ||
| 110 | return -ENODEV; | ||
| 111 | } | ||
| 112 | |||
| 113 | plff = kzalloc(sizeof(struct plff_device), GFP_KERNEL); | ||
| 114 | if (!plff) | ||
| 115 | return -ENOMEM; | ||
| 116 | |||
| 117 | dev = hidinput->input; | ||
| 118 | |||
| 119 | set_bit(FF_RUMBLE, dev->ffbit); | ||
| 120 | |||
| 121 | error = input_ff_create_memless(dev, plff, hid_plff_play); | ||
| 122 | if (error) { | ||
| 123 | kfree(plff); | ||
| 124 | return error; | ||
| 125 | } | ||
| 126 | |||
| 127 | plff->report = report; | ||
| 128 | plff->report->field[0]->value[0] = 0x00; | ||
| 129 | plff->report->field[0]->value[1] = 0x00; | ||
| 130 | plff->report->field[0]->value[2] = 0x00; | ||
| 131 | plff->report->field[0]->value[3] = 0x00; | ||
| 132 | usbhid_submit_report(hid, plff->report, USB_DIR_OUT); | ||
| 133 | } | ||
| 134 | |||
| 135 | printk(KERN_INFO "hid-plff: Force feedback for PantherLord/GreenAsia " | ||
| 136 | "devices by Anssi Hannula <anssi.hannula@gmail.com>\n"); | ||
| 137 | |||
| 138 | return 0; | ||
| 139 | } | ||
diff --git a/usr/src/dkms_source_tree/hid-quirks.c b/usr/src/dkms_source_tree/hid-quirks.c new file mode 100644 index 0000000..870247d --- /dev/null +++ b/usr/src/dkms_source_tree/hid-quirks.c | |||
| @@ -0,0 +1,1224 @@ | |||
| 1 | /* | ||
| 2 | * USB HID quirks support for Linux | ||
| 3 | * | ||
| 4 | * Copyright (c) 1999 Andreas Gal | ||
| 5 | * Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz> | ||
| 6 | * Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc | ||
| 7 | * Copyright (c) 2006-2007 Jiri Kosina | ||
| 8 | * Copyright (c) 2007 Paul Walmsley | ||
| 9 | */ | ||
| 10 | |||
| 11 | /* | ||
| 12 | * This program is free software; you can redistribute it and/or modify it | ||
| 13 | * under the terms of the GNU General Public License as published by the Free | ||
| 14 | * Software Foundation; either version 2 of the License, or (at your option) | ||
| 15 | * any later version. | ||
| 16 | */ | ||
| 17 | |||
| 18 | #include <linux/hid.h> | ||
| 19 | |||
| 20 | #define USB_VENDOR_ID_A4TECH 0x09da | ||
| 21 | #define USB_DEVICE_ID_A4TECH_WCP32PU 0x0006 | ||
| 22 | #define USB_DEVICE_ID_A4TECH_X5_005D 0x000a | ||
| 23 | |||
| 24 | #define USB_VENDOR_ID_AASHIMA 0x06d6 | ||
| 25 | #define USB_DEVICE_ID_AASHIMA_GAMEPAD 0x0025 | ||
| 26 | #define USB_DEVICE_ID_AASHIMA_PREDATOR 0x0026 | ||
| 27 | |||
| 28 | #define USB_VENDOR_ID_ACECAD 0x0460 | ||
| 29 | #define USB_DEVICE_ID_ACECAD_FLAIR 0x0004 | ||
| 30 | #define USB_DEVICE_ID_ACECAD_302 0x0008 | ||
| 31 | |||
| 32 | #define USB_VENDOR_ID_ADS_TECH 0x06e1 | ||
| 33 | #define USB_DEVICE_ID_ADS_TECH_RADIO_SI470X 0xa155 | ||
| 34 | |||
| 35 | #define USB_VENDOR_ID_AFATECH 0x15a4 | ||
| 36 | #define USB_DEVICE_ID_AFATECH_AF9016 0x9016 | ||
| 37 | |||
| 38 | #define USB_VENDOR_ID_AIPTEK 0x08ca | ||
| 39 | #define USB_DEVICE_ID_AIPTEK_01 0x0001 | ||
| 40 | #define USB_DEVICE_ID_AIPTEK_10 0x0010 | ||
| 41 | #define USB_DEVICE_ID_AIPTEK_20 0x0020 | ||
| 42 | #define USB_DEVICE_ID_AIPTEK_21 0x0021 | ||
| 43 | #define USB_DEVICE_ID_AIPTEK_22 0x0022 | ||
| 44 | #define USB_DEVICE_ID_AIPTEK_23 0x0023 | ||
| 45 | #define USB_DEVICE_ID_AIPTEK_24 0x0024 | ||
| 46 | |||
| 47 | #define USB_VENDOR_ID_AIRCABLE 0x16CA | ||
| 48 | #define USB_DEVICE_ID_AIRCABLE1 0x1502 | ||
| 49 | |||
| 50 | #define USB_VENDOR_ID_ALCOR 0x058f | ||
| 51 | #define USB_DEVICE_ID_ALCOR_USBRS232 0x9720 | ||
| 52 | |||
| 53 | #define USB_VENDOR_ID_ALPS 0x0433 | ||
| 54 | #define USB_DEVICE_ID_IBM_GAMEPAD 0x1101 | ||
| 55 | |||
| 56 | #define USB_VENDOR_ID_APPLE 0x05ac | ||
| 57 | #define USB_DEVICE_ID_APPLE_MIGHTYMOUSE 0x0304 | ||
| 58 | #define USB_DEVICE_ID_APPLE_FOUNTAIN_ANSI 0x020e | ||
| 59 | #define USB_DEVICE_ID_APPLE_FOUNTAIN_ISO 0x020f | ||
| 60 | #define USB_DEVICE_ID_APPLE_GEYSER_ANSI 0x0214 | ||
| 61 | #define USB_DEVICE_ID_APPLE_GEYSER_ISO 0x0215 | ||
| 62 | #define USB_DEVICE_ID_APPLE_GEYSER_JIS 0x0216 | ||
| 63 | #define USB_DEVICE_ID_APPLE_GEYSER3_ANSI 0x0217 | ||
| 64 | #define USB_DEVICE_ID_APPLE_GEYSER3_ISO 0x0218 | ||
| 65 | #define USB_DEVICE_ID_APPLE_GEYSER3_JIS 0x0219 | ||
| 66 | #define USB_DEVICE_ID_APPLE_GEYSER4_ANSI 0x021a | ||
| 67 | #define USB_DEVICE_ID_APPLE_GEYSER4_ISO 0x021b | ||
| 68 | #define USB_DEVICE_ID_APPLE_GEYSER4_JIS 0x021c | ||
| 69 | #define USB_DEVICE_ID_APPLE_ALU_ANSI 0x0220 | ||
| 70 | #define USB_DEVICE_ID_APPLE_ALU_ISO 0x0221 | ||
| 71 | #define USB_DEVICE_ID_APPLE_ALU_JIS 0x0222 | ||
| 72 | #define USB_DEVICE_ID_APPLE_WELLSPRING_ANSI 0x0223 | ||
| 73 | #define USB_DEVICE_ID_APPLE_WELLSPRING_ISO 0x0224 | ||
| 74 | #define USB_DEVICE_ID_APPLE_WELLSPRING_JIS 0x0225 | ||
| 75 | #define USB_DEVICE_ID_APPLE_GEYSER4_HF_ANSI 0x0229 | ||
| 76 | #define USB_DEVICE_ID_APPLE_GEYSER4_HF_ISO 0x022a | ||
| 77 | #define USB_DEVICE_ID_APPLE_GEYSER4_HF_JIS 0x022b | ||
| 78 | #define USB_DEVICE_ID_APPLE_ALU_WIRELESS_ANSI 0x022c | ||
| 79 | #define USB_DEVICE_ID_APPLE_ALU_WIRELESS_ISO 0x022d | ||
| 80 | #define USB_DEVICE_ID_APPLE_ALU_WIRELESS_JIS 0x022e | ||
| 81 | #define USB_DEVICE_ID_APPLE_WELLSPRING2_ANSI 0x0230 | ||
| 82 | #define USB_DEVICE_ID_APPLE_WELLSPRING2_ISO 0x0231 | ||
| 83 | #define USB_DEVICE_ID_APPLE_WELLSPRING2_JIS 0x0232 | ||
| 84 | #define USB_DEVICE_ID_APPLE_WELLSPRING3_ANSI 0x0236 | ||
| 85 | #define USB_DEVICE_ID_APPLE_WELLSPRING3_ISO 0x0237 | ||
| 86 | #define USB_DEVICE_ID_APPLE_WELLSPRING3_JIS 0x0238 | ||
| 87 | #define USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY 0x030a | ||
| 88 | #define USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY 0x030b | ||
| 89 | #define USB_DEVICE_ID_APPLE_IRCONTROL4 0x8242 | ||
| 90 | |||
| 91 | #define USB_VENDOR_ID_ASUS 0x0b05 | ||
| 92 | #define USB_DEVICE_ID_ASUS_LCM 0x1726 | ||
| 93 | |||
| 94 | #define USB_VENDOR_ID_ATEN 0x0557 | ||
| 95 | #define USB_DEVICE_ID_ATEN_UC100KM 0x2004 | ||
| 96 | #define USB_DEVICE_ID_ATEN_CS124U 0x2202 | ||
| 97 | #define USB_DEVICE_ID_ATEN_2PORTKVM 0x2204 | ||
| 98 | #define USB_DEVICE_ID_ATEN_4PORTKVM 0x2205 | ||
| 99 | #define USB_DEVICE_ID_ATEN_4PORTKVMC 0x2208 | ||
| 100 | |||
| 101 | #define USB_VENDOR_ID_BELKIN 0x050d | ||
| 102 | #define USB_DEVICE_ID_FLIP_KVM 0x3201 | ||
| 103 | |||
| 104 | #define USB_VENDOR_ID_BERKSHIRE 0x0c98 | ||
| 105 | #define USB_DEVICE_ID_BERKSHIRE_PCWD 0x1140 | ||
| 106 | |||
| 107 | #define USB_VENDOR_ID_CHERRY 0x046a | ||
| 108 | #define USB_DEVICE_ID_CHERRY_CYMOTION 0x0023 | ||
| 109 | |||
| 110 | #define USB_VENDOR_ID_CHIC 0x05fe | ||
| 111 | #define USB_DEVICE_ID_CHIC_GAMEPAD 0x0014 | ||
| 112 | |||
| 113 | #define USB_VENDOR_ID_CIDC 0x1677 | ||
| 114 | |||
| 115 | #define USB_VENDOR_ID_CMEDIA 0x0d8c | ||
| 116 | #define USB_DEVICE_ID_CM109 0x000e | ||
| 117 | |||
| 118 | #define USB_VENDOR_ID_CODEMERCS 0x07c0 | ||
| 119 | #define USB_DEVICE_ID_CODEMERCS_IOW_FIRST 0x1500 | ||
| 120 | #define USB_DEVICE_ID_CODEMERCS_IOW_LAST 0x15ff | ||
| 121 | |||
| 122 | #define USB_VENDOR_ID_CYGNAL 0x10c4 | ||
| 123 | #define USB_DEVICE_ID_CYGNAL_RADIO_SI470X 0x818a | ||
| 124 | |||
| 125 | #define USB_VENDOR_ID_CYPRESS 0x04b4 | ||
| 126 | #define USB_DEVICE_ID_CYPRESS_MOUSE 0x0001 | ||
| 127 | #define USB_DEVICE_ID_CYPRESS_HIDCOM 0x5500 | ||
| 128 | #define USB_DEVICE_ID_CYPRESS_ULTRAMOUSE 0x7417 | ||
| 129 | #define USB_DEVICE_ID_CYPRESS_BARCODE_1 0xde61 | ||
| 130 | #define USB_DEVICE_ID_CYPRESS_BARCODE_2 0xde64 | ||
| 131 | |||
| 132 | #define USB_VENDOR_ID_DELL 0x413c | ||
| 133 | #define USB_DEVICE_ID_DELL_W7658 0x2005 | ||
| 134 | |||
| 135 | #define USB_VENDOR_ID_DELORME 0x1163 | ||
| 136 | #define USB_DEVICE_ID_DELORME_EARTHMATE 0x0100 | ||
| 137 | #define USB_DEVICE_ID_DELORME_EM_LT20 0x0200 | ||
| 138 | |||
| 139 | #define USB_VENDOR_ID_DMI 0x0c0b | ||
| 140 | #define USB_DEVICE_ID_DMI_ENC 0x5fab | ||
| 141 | |||
| 142 | #define USB_VENDOR_ID_ELO 0x04E7 | ||
| 143 | #define USB_DEVICE_ID_ELO_TS2700 0x0020 | ||
| 144 | |||
| 145 | #define USB_VENDOR_ID_ESSENTIAL_REALITY 0x0d7f | ||
| 146 | #define USB_DEVICE_ID_ESSENTIAL_REALITY_P5 0x0100 | ||
| 147 | |||
| 148 | #define USB_VENDOR_ID_EZKEY 0x0518 | ||
| 149 | #define USB_DEVICE_ID_BTC_8193 0x0002 | ||
| 150 | |||
| 151 | #define USB_VENDOR_ID_GAMERON 0x0810 | ||
| 152 | #define USB_DEVICE_ID_GAMERON_DUAL_PSX_ADAPTOR 0x0001 | ||
| 153 | |||
| 154 | #define USB_VENDOR_ID_GENERAL_TOUCH 0x0dfc | ||
| 155 | |||
| 156 | #define USB_VENDOR_ID_GLAB 0x06c2 | ||
| 157 | #define USB_DEVICE_ID_4_PHIDGETSERVO_30 0x0038 | ||
| 158 | #define USB_DEVICE_ID_1_PHIDGETSERVO_30 0x0039 | ||
| 159 | #define USB_DEVICE_ID_0_0_4_IF_KIT 0x0040 | ||
| 160 | #define USB_DEVICE_ID_0_16_16_IF_KIT 0x0044 | ||
| 161 | #define USB_DEVICE_ID_8_8_8_IF_KIT 0x0045 | ||
| 162 | #define USB_DEVICE_ID_0_8_7_IF_KIT 0x0051 | ||
| 163 | #define USB_DEVICE_ID_0_8_8_IF_KIT 0x0053 | ||
| 164 | #define USB_DEVICE_ID_PHIDGET_MOTORCONTROL 0x0058 | ||
| 165 | |||
| 166 | #define USB_VENDOR_ID_GOTOP 0x08f2 | ||
| 167 | #define USB_DEVICE_ID_SUPER_Q2 0x007f | ||
| 168 | #define USB_DEVICE_ID_GOGOPEN 0x00ce | ||
| 169 | #define USB_DEVICE_ID_PENPOWER 0x00f4 | ||
| 170 | |||
| 171 | #define USB_VENDOR_ID_GRETAGMACBETH 0x0971 | ||
| 172 | #define USB_DEVICE_ID_GRETAGMACBETH_HUEY 0x2005 | ||
| 173 | |||
| 174 | #define USB_VENDOR_ID_GRIFFIN 0x077d | ||
| 175 | #define USB_DEVICE_ID_POWERMATE 0x0410 | ||
| 176 | #define USB_DEVICE_ID_SOUNDKNOB 0x04AA | ||
| 177 | |||
| 178 | #define USB_VENDOR_ID_GTCO 0x078c | ||
| 179 | #define USB_DEVICE_ID_GTCO_90 0x0090 | ||
| 180 | #define USB_DEVICE_ID_GTCO_100 0x0100 | ||
| 181 | #define USB_DEVICE_ID_GTCO_101 0x0101 | ||
| 182 | #define USB_DEVICE_ID_GTCO_103 0x0103 | ||
| 183 | #define USB_DEVICE_ID_GTCO_104 0x0104 | ||
| 184 | #define USB_DEVICE_ID_GTCO_105 0x0105 | ||
| 185 | #define USB_DEVICE_ID_GTCO_106 0x0106 | ||
| 186 | #define USB_DEVICE_ID_GTCO_107 0x0107 | ||
| 187 | #define USB_DEVICE_ID_GTCO_108 0x0108 | ||
| 188 | #define USB_DEVICE_ID_GTCO_200 0x0200 | ||
| 189 | #define USB_DEVICE_ID_GTCO_201 0x0201 | ||
| 190 | #define USB_DEVICE_ID_GTCO_202 0x0202 | ||
| 191 | #define USB_DEVICE_ID_GTCO_203 0x0203 | ||
| 192 | #define USB_DEVICE_ID_GTCO_204 0x0204 | ||
| 193 | #define USB_DEVICE_ID_GTCO_205 0x0205 | ||
| 194 | #define USB_DEVICE_ID_GTCO_206 0x0206 | ||
| 195 | #define USB_DEVICE_ID_GTCO_207 0x0207 | ||
| 196 | #define USB_DEVICE_ID_GTCO_300 0x0300 | ||
| 197 | #define USB_DEVICE_ID_GTCO_301 0x0301 | ||
| 198 | #define USB_DEVICE_ID_GTCO_302 0x0302 | ||
| 199 | #define USB_DEVICE_ID_GTCO_303 0x0303 | ||
| 200 | #define USB_DEVICE_ID_GTCO_304 0x0304 | ||
| 201 | #define USB_DEVICE_ID_GTCO_305 0x0305 | ||
| 202 | #define USB_DEVICE_ID_GTCO_306 0x0306 | ||
| 203 | #define USB_DEVICE_ID_GTCO_307 0x0307 | ||
| 204 | #define USB_DEVICE_ID_GTCO_308 0x0308 | ||
| 205 | #define USB_DEVICE_ID_GTCO_309 0x0309 | ||
| 206 | #define USB_DEVICE_ID_GTCO_400 0x0400 | ||
| 207 | #define USB_DEVICE_ID_GTCO_401 0x0401 | ||
| 208 | #define USB_DEVICE_ID_GTCO_402 0x0402 | ||
| 209 | #define USB_DEVICE_ID_GTCO_403 0x0403 | ||
| 210 | #define USB_DEVICE_ID_GTCO_404 0x0404 | ||
| 211 | #define USB_DEVICE_ID_GTCO_405 0x0405 | ||
| 212 | #define USB_DEVICE_ID_GTCO_500 0x0500 | ||
| 213 | #define USB_DEVICE_ID_GTCO_501 0x0501 | ||
| 214 | #define USB_DEVICE_ID_GTCO_502 0x0502 | ||
| 215 | #define USB_DEVICE_ID_GTCO_503 0x0503 | ||
| 216 | #define USB_DEVICE_ID_GTCO_504 0x0504 | ||
| 217 | #define USB_DEVICE_ID_GTCO_1000 0x1000 | ||
| 218 | #define USB_DEVICE_ID_GTCO_1001 0x1001 | ||
| 219 | #define USB_DEVICE_ID_GTCO_1002 0x1002 | ||
| 220 | #define USB_DEVICE_ID_GTCO_1003 0x1003 | ||
| 221 | #define USB_DEVICE_ID_GTCO_1004 0x1004 | ||
| 222 | #define USB_DEVICE_ID_GTCO_1005 0x1005 | ||
| 223 | #define USB_DEVICE_ID_GTCO_1006 0x1006 | ||
| 224 | #define USB_DEVICE_ID_GTCO_1007 0x1007 | ||
| 225 | #define USB_VENDOR_ID_HAPP 0x078b | ||
| 226 | #define USB_DEVICE_ID_UGCI_DRIVING 0x0010 | ||
| 227 | #define USB_DEVICE_ID_UGCI_FLYING 0x0020 | ||
| 228 | #define USB_DEVICE_ID_UGCI_FIGHTING 0x0030 | ||
| 229 | |||
| 230 | #define USB_VENDOR_ID_IMATION 0x0718 | ||
| 231 | #define USB_DEVICE_ID_DISC_STAKKA 0xd000 | ||
| 232 | |||
| 233 | #define USB_VENDOR_ID_KBGEAR 0x084e | ||
| 234 | #define USB_DEVICE_ID_KBGEAR_JAMSTUDIO 0x1001 | ||
| 235 | |||
| 236 | #define USB_VENDOR_ID_LD 0x0f11 | ||
| 237 | #define USB_DEVICE_ID_LD_CASSY 0x1000 | ||
| 238 | #define USB_DEVICE_ID_LD_POCKETCASSY 0x1010 | ||
| 239 | #define USB_DEVICE_ID_LD_MOBILECASSY 0x1020 | ||
| 240 | #define USB_DEVICE_ID_LD_JWM 0x1080 | ||
| 241 | #define USB_DEVICE_ID_LD_DMMP 0x1081 | ||
| 242 | #define USB_DEVICE_ID_LD_UMIP 0x1090 | ||
| 243 | #define USB_DEVICE_ID_LD_XRAY1 0x1100 | ||
| 244 | #define USB_DEVICE_ID_LD_XRAY2 0x1101 | ||
| 245 | #define USB_DEVICE_ID_LD_VIDEOCOM 0x1200 | ||
| 246 | #define USB_DEVICE_ID_LD_COM3LAB 0x2000 | ||
| 247 | #define USB_DEVICE_ID_LD_TELEPORT 0x2010 | ||
| 248 | #define USB_DEVICE_ID_LD_NETWORKANALYSER 0x2020 | ||
| 249 | #define USB_DEVICE_ID_LD_POWERCONTROL 0x2030 | ||
| 250 | #define USB_DEVICE_ID_LD_MACHINETEST 0x2040 | ||
| 251 | |||
| 252 | #define USB_VENDOR_ID_LOGITECH 0x046d | ||
| 253 | #define USB_DEVICE_ID_LOGITECH_RECEIVER 0xc101 | ||
| 254 | #define USB_DEVICE_ID_LOGITECH_HARMONY 0xc110 | ||
| 255 | #define USB_DEVICE_ID_LOGITECH_HARMONY_2 0xc111 | ||
| 256 | #define USB_DEVICE_ID_LOGITECH_HARMONY_3 0xc112 | ||
| 257 | #define USB_DEVICE_ID_LOGITECH_HARMONY_4 0xc113 | ||
| 258 | #define USB_DEVICE_ID_LOGITECH_HARMONY_5 0xc114 | ||
| 259 | #define USB_DEVICE_ID_LOGITECH_HARMONY_6 0xc115 | ||
| 260 | #define USB_DEVICE_ID_LOGITECH_HARMONY_7 0xc116 | ||
| 261 | #define USB_DEVICE_ID_LOGITECH_HARMONY_8 0xc117 | ||
| 262 | #define USB_DEVICE_ID_LOGITECH_HARMONY_9 0xc118 | ||
| 263 | #define USB_DEVICE_ID_LOGITECH_HARMONY_10 0xc119 | ||
| 264 | #define USB_DEVICE_ID_LOGITECH_HARMONY_11 0xc11a | ||
| 265 | #define USB_DEVICE_ID_LOGITECH_HARMONY_12 0xc11b | ||
| 266 | #define USB_DEVICE_ID_LOGITECH_HARMONY_13 0xc11c | ||
| 267 | #define USB_DEVICE_ID_LOGITECH_HARMONY_14 0xc11d | ||
| 268 | #define USB_DEVICE_ID_LOGITECH_HARMONY_15 0xc11e | ||
| 269 | #define USB_DEVICE_ID_LOGITECH_HARMONY_16 0xc11f | ||
| 270 | #define USB_DEVICE_ID_LOGITECH_HARMONY_17 0xc120 | ||
| 271 | #define USB_DEVICE_ID_LOGITECH_HARMONY_18 0xc121 | ||
| 272 | #define USB_DEVICE_ID_LOGITECH_HARMONY_19 0xc122 | ||
| 273 | #define USB_DEVICE_ID_LOGITECH_HARMONY_20 0xc123 | ||
| 274 | #define USB_DEVICE_ID_LOGITECH_HARMONY_21 0xc124 | ||
| 275 | #define USB_DEVICE_ID_LOGITECH_HARMONY_22 0xc125 | ||
| 276 | #define USB_DEVICE_ID_LOGITECH_HARMONY_23 0xc126 | ||
| 277 | #define USB_DEVICE_ID_LOGITECH_HARMONY_24 0xc127 | ||
| 278 | #define USB_DEVICE_ID_LOGITECH_HARMONY_25 0xc128 | ||
| 279 | #define USB_DEVICE_ID_LOGITECH_HARMONY_26 0xc129 | ||
| 280 | #define USB_DEVICE_ID_LOGITECH_HARMONY_27 0xc12a | ||
| 281 | #define USB_DEVICE_ID_LOGITECH_HARMONY_28 0xc12b | ||
| 282 | #define USB_DEVICE_ID_LOGITECH_HARMONY_29 0xc12c | ||
| 283 | #define USB_DEVICE_ID_LOGITECH_HARMONY_30 0xc12d | ||
| 284 | #define USB_DEVICE_ID_LOGITECH_HARMONY_31 0xc12e | ||
| 285 | #define USB_DEVICE_ID_LOGITECH_HARMONY_32 0xc12f | ||
| 286 | #define USB_DEVICE_ID_LOGITECH_HARMONY_33 0xc130 | ||
| 287 | #define USB_DEVICE_ID_LOGITECH_HARMONY_34 0xc131 | ||
| 288 | #define USB_DEVICE_ID_LOGITECH_HARMONY_35 0xc132 | ||
| 289 | #define USB_DEVICE_ID_LOGITECH_HARMONY_36 0xc133 | ||
| 290 | #define USB_DEVICE_ID_LOGITECH_HARMONY_37 0xc134 | ||
| 291 | #define USB_DEVICE_ID_LOGITECH_HARMONY_38 0xc135 | ||
| 292 | #define USB_DEVICE_ID_LOGITECH_HARMONY_39 0xc136 | ||
| 293 | #define USB_DEVICE_ID_LOGITECH_HARMONY_40 0xc137 | ||
| 294 | #define USB_DEVICE_ID_LOGITECH_HARMONY_41 0xc138 | ||
| 295 | #define USB_DEVICE_ID_LOGITECH_HARMONY_42 0xc139 | ||
| 296 | #define USB_DEVICE_ID_LOGITECH_HARMONY_43 0xc13a | ||
| 297 | #define USB_DEVICE_ID_LOGITECH_HARMONY_44 0xc13b | ||
| 298 | #define USB_DEVICE_ID_LOGITECH_HARMONY_45 0xc13c | ||
| 299 | #define USB_DEVICE_ID_LOGITECH_HARMONY_46 0xc13d | ||
| 300 | #define USB_DEVICE_ID_LOGITECH_HARMONY_47 0xc13e | ||
| 301 | #define USB_DEVICE_ID_LOGITECH_HARMONY_48 0xc13f | ||
| 302 | #define USB_DEVICE_ID_LOGITECH_HARMONY_49 0xc140 | ||
| 303 | #define USB_DEVICE_ID_LOGITECH_HARMONY_50 0xc141 | ||
| 304 | #define USB_DEVICE_ID_LOGITECH_HARMONY_51 0xc142 | ||
| 305 | #define USB_DEVICE_ID_LOGITECH_HARMONY_52 0xc143 | ||
| 306 | #define USB_DEVICE_ID_LOGITECH_HARMONY_53 0xc144 | ||
| 307 | #define USB_DEVICE_ID_LOGITECH_HARMONY_54 0xc145 | ||
| 308 | #define USB_DEVICE_ID_LOGITECH_HARMONY_55 0xc146 | ||
| 309 | #define USB_DEVICE_ID_LOGITECH_HARMONY_56 0xc147 | ||
| 310 | #define USB_DEVICE_ID_LOGITECH_HARMONY_57 0xc148 | ||
| 311 | #define USB_DEVICE_ID_LOGITECH_HARMONY_58 0xc149 | ||
| 312 | #define USB_DEVICE_ID_LOGITECH_HARMONY_59 0xc14a | ||
| 313 | #define USB_DEVICE_ID_LOGITECH_HARMONY_60 0xc14b | ||
| 314 | #define USB_DEVICE_ID_LOGITECH_HARMONY_61 0xc14c | ||
| 315 | #define USB_DEVICE_ID_LOGITECH_HARMONY_62 0xc14d | ||
| 316 | #define USB_DEVICE_ID_LOGITECH_HARMONY_63 0xc14e | ||
| 317 | #define USB_DEVICE_ID_LOGITECH_HARMONY_64 0xc14f | ||
| 318 | #define USB_DEVICE_ID_LOGITECH_EXTREME_3D 0xc215 | ||
| 319 | #define USB_DEVICE_ID_LOGITECH_WHEEL 0xc294 | ||
| 320 | #define USB_DEVICE_ID_LOGITECH_ELITE_KBD 0xc30a | ||
| 321 | #define USB_DEVICE_ID_LOGITECH_KBD 0xc311 | ||
| 322 | #define USB_DEVICE_ID_S510_RECEIVER 0xc50c | ||
| 323 | #define USB_DEVICE_ID_S510_RECEIVER_2 0xc517 | ||
| 324 | #define USB_DEVICE_ID_LOGITECH_CORDLESS_DESKTOP_LX500 0xc512 | ||
| 325 | #define USB_DEVICE_ID_MX3000_RECEIVER 0xc513 | ||
| 326 | #define USB_DEVICE_ID_DINOVO_DESKTOP 0xc704 | ||
| 327 | #define USB_DEVICE_ID_DINOVO_EDGE 0xc714 | ||
| 328 | #define USB_DEVICE_ID_DINOVO_MINI 0xc71f | ||
| 329 | |||
| 330 | #define USB_VENDOR_ID_MCC 0x09db | ||
| 331 | #define USB_DEVICE_ID_MCC_PMD1024LS 0x0076 | ||
| 332 | #define USB_DEVICE_ID_MCC_PMD1208LS 0x007a | ||
| 333 | |||
| 334 | #define USB_VENDOR_ID_MGE 0x0463 | ||
| 335 | #define USB_DEVICE_ID_MGE_UPS 0xffff | ||
| 336 | #define USB_DEVICE_ID_MGE_UPS1 0x0001 | ||
| 337 | |||
| 338 | #define USB_VENDOR_ID_MICROCHIP 0x04d8 | ||
| 339 | #define USB_DEVICE_ID_PICKIT1 0x0032 | ||
| 340 | #define USB_DEVICE_ID_PICKIT2 0x0033 | ||
| 341 | |||
| 342 | #define USB_VENDOR_ID_MICROSOFT 0x045e | ||
| 343 | #define USB_DEVICE_ID_SIDEWINDER_GV 0x003b | ||
| 344 | #define USB_DEVICE_ID_WIRELESS_OPTICAL_DESKTOP_3_0 0x009d | ||
| 345 | #define USB_DEVICE_ID_DESKTOP_RECV_1028 0x00f9 | ||
| 346 | #define USB_DEVICE_ID_MS_NE4K 0x00db | ||
| 347 | #define USB_DEVICE_ID_MS_LK6K 0x00f9 | ||
| 348 | |||
| 349 | #define USB_VENDOR_ID_MONTEREY 0x0566 | ||
| 350 | #define USB_DEVICE_ID_GENIUS_KB29E 0x3004 | ||
| 351 | |||
| 352 | #define USB_VENDOR_ID_NCR 0x0404 | ||
| 353 | #define USB_DEVICE_ID_NCR_FIRST 0x0300 | ||
| 354 | #define USB_DEVICE_ID_NCR_LAST 0x03ff | ||
| 355 | |||
| 356 | #define USB_VENDOR_ID_NATIONAL_SEMICONDUCTOR 0x0400 | ||
| 357 | #define USB_DEVICE_ID_N_S_HARMONY 0xc359 | ||
| 358 | |||
| 359 | #define USB_VENDOR_ID_NATSU 0x08b7 | ||
| 360 | #define USB_DEVICE_ID_NATSU_GAMEPAD 0x0001 | ||
| 361 | |||
| 362 | #define USB_VENDOR_ID_NEC 0x073e | ||
| 363 | #define USB_DEVICE_ID_NEC_USB_GAME_PAD 0x0301 | ||
| 364 | |||
| 365 | #define USB_VENDOR_ID_ONTRAK 0x0a07 | ||
| 366 | #define USB_DEVICE_ID_ONTRAK_ADU100 0x0064 | ||
| 367 | |||
| 368 | #define USB_VENDOR_ID_PANJIT 0x134c | ||
| 369 | |||
| 370 | #define USB_VENDOR_ID_PANTHERLORD 0x0810 | ||
| 371 | #define USB_DEVICE_ID_PANTHERLORD_TWIN_USB_JOYSTICK 0x0001 | ||
| 372 | |||
| 373 | #define USB_VENDOR_ID_PETALYNX 0x18b1 | ||
| 374 | #define USB_DEVICE_ID_PETALYNX_MAXTER_REMOTE 0x0037 | ||
| 375 | |||
| 376 | #define USB_VENDOR_ID_PLAYDOTCOM 0x0b43 | ||
| 377 | #define USB_DEVICE_ID_PLAYDOTCOM_EMS_USBII 0x0003 | ||
| 378 | |||
| 379 | #define USB_VENDOR_ID_SAITEK 0x06a3 | ||
| 380 | #define USB_DEVICE_ID_SAITEK_RUMBLEPAD 0xff17 | ||
| 381 | |||
| 382 | #define USB_VENDOR_ID_SAMSUNG 0x0419 | ||
| 383 | #define USB_DEVICE_ID_SAMSUNG_IR_REMOTE 0x0001 | ||
| 384 | |||
| 385 | #define USB_VENDOR_ID_SONY 0x054c | ||
| 386 | #define USB_DEVICE_ID_SONY_PS3_CONTROLLER 0x0268 | ||
| 387 | |||
| 388 | #define USB_VENDOR_ID_SOUNDGRAPH 0x15c2 | ||
| 389 | #define USB_DEVICE_ID_SOUNDGRAPH_IMON_LCD 0x0038 | ||
| 390 | |||
| 391 | #define USB_VENDOR_ID_SUN 0x0430 | ||
| 392 | #define USB_DEVICE_ID_RARITAN_KVM_DONGLE 0xcdab | ||
| 393 | |||
| 394 | #define USB_VENDOR_ID_SUNPLUS 0x04fc | ||
| 395 | #define USB_DEVICE_ID_SUNPLUS_WDESKTOP 0x05d8 | ||
| 396 | |||
| 397 | #define USB_VENDOR_ID_TOPMAX 0x0663 | ||
| 398 | #define USB_DEVICE_ID_TOPMAX_COBRAPAD 0x0103 | ||
| 399 | |||
| 400 | #define USB_VENDOR_ID_TURBOX 0x062a | ||
| 401 | #define USB_DEVICE_ID_TURBOX_KEYBOARD 0x0201 | ||
| 402 | |||
| 403 | #define USB_VENDOR_ID_VERNIER 0x08f7 | ||
| 404 | #define USB_DEVICE_ID_VERNIER_LABPRO 0x0001 | ||
| 405 | #define USB_DEVICE_ID_VERNIER_GOTEMP 0x0002 | ||
| 406 | #define USB_DEVICE_ID_VERNIER_SKIP 0x0003 | ||
| 407 | #define USB_DEVICE_ID_VERNIER_CYCLOPS 0x0004 | ||
| 408 | #define USB_DEVICE_ID_VERNIER_LCSPEC 0x0006 | ||
| 409 | |||
| 410 | #define USB_VENDOR_ID_WACOM 0x056a | ||
| 411 | |||
| 412 | #define USB_VENDOR_ID_WISEGROUP 0x0925 | ||
| 413 | #define USB_DEVICE_ID_1_PHIDGETSERVO_20 0x8101 | ||
| 414 | #define USB_DEVICE_ID_4_PHIDGETSERVO_20 0x8104 | ||
| 415 | #define USB_DEVICE_ID_8_8_4_IF_KIT 0x8201 | ||
| 416 | #define USB_DEVICE_ID_QUAD_USB_JOYPAD 0x8800 | ||
| 417 | #define USB_DEVICE_ID_DUAL_USB_JOYPAD 0x8866 | ||
| 418 | |||
| 419 | #define USB_VENDOR_ID_WISEGROUP_LTD 0x6677 | ||
| 420 | #define USB_DEVICE_ID_SMARTJOY_DUAL_PLUS 0x8802 | ||
| 421 | |||
| 422 | #define USB_VENDOR_ID_YEALINK 0x6993 | ||
| 423 | #define USB_DEVICE_ID_YEALINK_P1K_P4K_B2K 0xb001 | ||
| 424 | |||
| 425 | #define USB_VENDOR_ID_KYE 0x0458 | ||
| 426 | #define USB_DEVICE_ID_KYE_GPEN_560 0x5003 | ||
| 427 | |||
| 428 | /* | ||
| 429 | * Alphabetically sorted blacklist by quirk type. | ||
| 430 | */ | ||
| 431 | |||
| 432 | static const struct hid_blacklist { | ||
| 433 | __u16 idVendor; | ||
| 434 | __u16 idProduct; | ||
| 435 | __u32 quirks; | ||
| 436 | } hid_blacklist[] = { | ||
| 437 | |||
| 438 | { USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_WCP32PU, HID_QUIRK_2WHEEL_MOUSE_HACK_7 }, | ||
| 439 | { USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_X5_005D, HID_QUIRK_2WHEEL_MOUSE_HACK_B8 }, | ||
| 440 | { USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_MOUSE, HID_QUIRK_2WHEEL_MOUSE_HACK_5 }, | ||
| 441 | |||
| 442 | { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RECEIVER, HID_QUIRK_BAD_RELATIVE_KEYS }, | ||
| 443 | |||
| 444 | { USB_VENDOR_ID_AASHIMA, USB_DEVICE_ID_AASHIMA_GAMEPAD, HID_QUIRK_BADPAD }, | ||
| 445 | { USB_VENDOR_ID_AASHIMA, USB_DEVICE_ID_AASHIMA_PREDATOR, HID_QUIRK_BADPAD }, | ||
| 446 | { USB_VENDOR_ID_ALPS, USB_DEVICE_ID_IBM_GAMEPAD, HID_QUIRK_BADPAD }, | ||
| 447 | { USB_VENDOR_ID_CHIC, USB_DEVICE_ID_CHIC_GAMEPAD, HID_QUIRK_BADPAD }, | ||
| 448 | { USB_VENDOR_ID_GAMERON, USB_DEVICE_ID_GAMERON_DUAL_PSX_ADAPTOR, HID_QUIRK_MULTI_INPUT }, | ||
| 449 | { USB_VENDOR_ID_HAPP, USB_DEVICE_ID_UGCI_DRIVING, HID_QUIRK_BADPAD | HID_QUIRK_MULTI_INPUT }, | ||
| 450 | { USB_VENDOR_ID_HAPP, USB_DEVICE_ID_UGCI_FLYING, HID_QUIRK_BADPAD | HID_QUIRK_MULTI_INPUT }, | ||
| 451 | { USB_VENDOR_ID_HAPP, USB_DEVICE_ID_UGCI_FIGHTING, HID_QUIRK_BADPAD | HID_QUIRK_MULTI_INPUT }, | ||
| 452 | { USB_VENDOR_ID_NATSU, USB_DEVICE_ID_NATSU_GAMEPAD, HID_QUIRK_BADPAD }, | ||
| 453 | { USB_VENDOR_ID_NEC, USB_DEVICE_ID_NEC_USB_GAME_PAD, HID_QUIRK_BADPAD }, | ||
| 454 | { USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_RUMBLEPAD, HID_QUIRK_BADPAD }, | ||
| 455 | { USB_VENDOR_ID_TOPMAX, USB_DEVICE_ID_TOPMAX_COBRAPAD, HID_QUIRK_BADPAD }, | ||
| 456 | |||
| 457 | { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_DESKTOP, HID_QUIRK_DUPLICATE_USAGES }, | ||
| 458 | { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_EDGE, HID_QUIRK_DUPLICATE_USAGES }, | ||
| 459 | { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_MINI, HID_QUIRK_DUPLICATE_USAGES }, | ||
| 460 | |||
| 461 | { USB_VENDOR_ID_AFATECH, USB_DEVICE_ID_AFATECH_AF9016, HID_QUIRK_FULLSPEED_INTERVAL }, | ||
| 462 | |||
| 463 | { USB_VENDOR_ID_BELKIN, USB_DEVICE_ID_FLIP_KVM, HID_QUIRK_HIDDEV }, | ||
| 464 | { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL4, HID_QUIRK_HIDDEV | HID_QUIRK_IGNORE_HIDINPUT }, | ||
| 465 | { USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_IR_REMOTE, HID_QUIRK_HIDDEV | HID_QUIRK_IGNORE_HIDINPUT }, | ||
| 466 | { USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_SIDEWINDER_GV, HID_QUIRK_HIDINPUT }, | ||
| 467 | |||
| 468 | { USB_VENDOR_ID_EZKEY, USB_DEVICE_ID_BTC_8193, HID_QUIRK_HWHEEL_WHEEL_INVERT }, | ||
| 469 | |||
| 470 | { USB_VENDOR_ID_ADS_TECH, USB_DEVICE_ID_ADS_TECH_RADIO_SI470X, HID_QUIRK_IGNORE }, | ||
| 471 | { USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_01, HID_QUIRK_IGNORE }, | ||
| 472 | { USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_10, HID_QUIRK_IGNORE }, | ||
| 473 | { USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_20, HID_QUIRK_IGNORE }, | ||
| 474 | { USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_21, HID_QUIRK_IGNORE }, | ||
| 475 | { USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_22, HID_QUIRK_IGNORE }, | ||
| 476 | { USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_23, HID_QUIRK_IGNORE }, | ||
| 477 | { USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_24, HID_QUIRK_IGNORE }, | ||
| 478 | { USB_VENDOR_ID_AIRCABLE, USB_DEVICE_ID_AIRCABLE1, HID_QUIRK_IGNORE }, | ||
| 479 | { USB_VENDOR_ID_ALCOR, USB_DEVICE_ID_ALCOR_USBRS232, HID_QUIRK_IGNORE }, | ||
| 480 | { USB_VENDOR_ID_ASUS, USB_DEVICE_ID_ASUS_LCM, HID_QUIRK_IGNORE}, | ||
| 481 | { USB_VENDOR_ID_BERKSHIRE, USB_DEVICE_ID_BERKSHIRE_PCWD, HID_QUIRK_IGNORE }, | ||
| 482 | { USB_VENDOR_ID_CIDC, 0x0103, HID_QUIRK_IGNORE }, | ||
| 483 | { USB_VENDOR_ID_CYGNAL, USB_DEVICE_ID_CYGNAL_RADIO_SI470X, HID_QUIRK_IGNORE }, | ||
| 484 | { USB_VENDOR_ID_CMEDIA, USB_DEVICE_ID_CM109, HID_QUIRK_IGNORE }, | ||
| 485 | { USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_HIDCOM, HID_QUIRK_IGNORE }, | ||
| 486 | { USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_ULTRAMOUSE, HID_QUIRK_IGNORE }, | ||
| 487 | { USB_VENDOR_ID_DELORME, USB_DEVICE_ID_DELORME_EARTHMATE, HID_QUIRK_IGNORE }, | ||
| 488 | { USB_VENDOR_ID_DELORME, USB_DEVICE_ID_DELORME_EM_LT20, HID_QUIRK_IGNORE }, | ||
| 489 | { USB_VENDOR_ID_ESSENTIAL_REALITY, USB_DEVICE_ID_ESSENTIAL_REALITY_P5, HID_QUIRK_IGNORE }, | ||
| 490 | { USB_VENDOR_ID_GENERAL_TOUCH, 0x0001, HID_QUIRK_IGNORE }, | ||
| 491 | { USB_VENDOR_ID_GENERAL_TOUCH, 0x0002, HID_QUIRK_IGNORE }, | ||
| 492 | { USB_VENDOR_ID_GENERAL_TOUCH, 0x0003, HID_QUIRK_IGNORE }, | ||
| 493 | { USB_VENDOR_ID_GENERAL_TOUCH, 0x0004, HID_QUIRK_IGNORE }, | ||
| 494 | { USB_VENDOR_ID_GLAB, USB_DEVICE_ID_4_PHIDGETSERVO_30, HID_QUIRK_IGNORE }, | ||
| 495 | { USB_VENDOR_ID_GLAB, USB_DEVICE_ID_1_PHIDGETSERVO_30, HID_QUIRK_IGNORE }, | ||
| 496 | { USB_VENDOR_ID_GLAB, USB_DEVICE_ID_0_0_4_IF_KIT, HID_QUIRK_IGNORE }, | ||
| 497 | { USB_VENDOR_ID_GLAB, USB_DEVICE_ID_0_16_16_IF_KIT, HID_QUIRK_IGNORE }, | ||
| 498 | { USB_VENDOR_ID_GLAB, USB_DEVICE_ID_8_8_8_IF_KIT, HID_QUIRK_IGNORE }, | ||
| 499 | { USB_VENDOR_ID_GLAB, USB_DEVICE_ID_0_8_7_IF_KIT, HID_QUIRK_IGNORE }, | ||
| 500 | { USB_VENDOR_ID_GLAB, USB_DEVICE_ID_0_8_8_IF_KIT, HID_QUIRK_IGNORE }, | ||
| 501 | { USB_VENDOR_ID_GLAB, USB_DEVICE_ID_PHIDGET_MOTORCONTROL, HID_QUIRK_IGNORE }, | ||
| 502 | { USB_VENDOR_ID_GOTOP, USB_DEVICE_ID_SUPER_Q2, HID_QUIRK_IGNORE }, | ||
| 503 | { USB_VENDOR_ID_GOTOP, USB_DEVICE_ID_GOGOPEN, HID_QUIRK_IGNORE }, | ||
| 504 | { USB_VENDOR_ID_GOTOP, USB_DEVICE_ID_PENPOWER, HID_QUIRK_IGNORE }, | ||
| 505 | { USB_VENDOR_ID_GRETAGMACBETH, USB_DEVICE_ID_GRETAGMACBETH_HUEY, HID_QUIRK_IGNORE }, | ||
| 506 | { USB_VENDOR_ID_GRIFFIN, USB_DEVICE_ID_POWERMATE, HID_QUIRK_IGNORE }, | ||
| 507 | { USB_VENDOR_ID_GRIFFIN, USB_DEVICE_ID_SOUNDKNOB, HID_QUIRK_IGNORE }, | ||
| 508 | { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_90, HID_QUIRK_IGNORE }, | ||
| 509 | { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_100, HID_QUIRK_IGNORE }, | ||
| 510 | { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_101, HID_QUIRK_IGNORE }, | ||
| 511 | { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_103, HID_QUIRK_IGNORE }, | ||
| 512 | { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_104, HID_QUIRK_IGNORE }, | ||
| 513 | { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_105, HID_QUIRK_IGNORE }, | ||
| 514 | { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_106, HID_QUIRK_IGNORE }, | ||
| 515 | { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_107, HID_QUIRK_IGNORE }, | ||
| 516 | { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_108, HID_QUIRK_IGNORE }, | ||
| 517 | { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_200, HID_QUIRK_IGNORE }, | ||
| 518 | { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_201, HID_QUIRK_IGNORE }, | ||
| 519 | { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_202, HID_QUIRK_IGNORE }, | ||
| 520 | { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_203, HID_QUIRK_IGNORE }, | ||
| 521 | { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_204, HID_QUIRK_IGNORE }, | ||
| 522 | { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_205, HID_QUIRK_IGNORE }, | ||
| 523 | { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_206, HID_QUIRK_IGNORE }, | ||
| 524 | { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_207, HID_QUIRK_IGNORE }, | ||
| 525 | { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_300, HID_QUIRK_IGNORE }, | ||
| 526 | { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_301, HID_QUIRK_IGNORE }, | ||
| 527 | { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_302, HID_QUIRK_IGNORE }, | ||
| 528 | { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_303, HID_QUIRK_IGNORE }, | ||
| 529 | { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_304, HID_QUIRK_IGNORE }, | ||
| 530 | { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_305, HID_QUIRK_IGNORE }, | ||
| 531 | { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_306, HID_QUIRK_IGNORE }, | ||
| 532 | { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_307, HID_QUIRK_IGNORE }, | ||
| 533 | { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_308, HID_QUIRK_IGNORE }, | ||
| 534 | { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_309, HID_QUIRK_IGNORE }, | ||
| 535 | { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_400, HID_QUIRK_IGNORE }, | ||
| 536 | { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_401, HID_QUIRK_IGNORE }, | ||
| 537 | { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_402, HID_QUIRK_IGNORE }, | ||
| 538 | { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_403, HID_QUIRK_IGNORE }, | ||
| 539 | { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_404, HID_QUIRK_IGNORE }, | ||
| 540 | { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_405, HID_QUIRK_IGNORE }, | ||
| 541 | { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_500, HID_QUIRK_IGNORE }, | ||
| 542 | { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_501, HID_QUIRK_IGNORE }, | ||
| 543 | { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_502, HID_QUIRK_IGNORE }, | ||
| 544 | { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_503, HID_QUIRK_IGNORE }, | ||
| 545 | { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_504, HID_QUIRK_IGNORE }, | ||
| 546 | { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1000, HID_QUIRK_IGNORE }, | ||
| 547 | { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1001, HID_QUIRK_IGNORE }, | ||
| 548 | { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1002, HID_QUIRK_IGNORE }, | ||
| 549 | { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1003, HID_QUIRK_IGNORE }, | ||
| 550 | { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1004, HID_QUIRK_IGNORE }, | ||
| 551 | { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1005, HID_QUIRK_IGNORE }, | ||
| 552 | { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1006, HID_QUIRK_IGNORE }, | ||
| 553 | { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1007, HID_QUIRK_IGNORE }, | ||
| 554 | { USB_VENDOR_ID_IMATION, USB_DEVICE_ID_DISC_STAKKA, HID_QUIRK_IGNORE }, | ||
| 555 | { USB_VENDOR_ID_KBGEAR, USB_DEVICE_ID_KBGEAR_JAMSTUDIO, HID_QUIRK_IGNORE }, | ||
| 556 | { USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_CASSY, HID_QUIRK_IGNORE }, | ||
| 557 | { USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_POCKETCASSY, HID_QUIRK_IGNORE }, | ||
| 558 | { USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MOBILECASSY, HID_QUIRK_IGNORE }, | ||
| 559 | { USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_JWM, HID_QUIRK_IGNORE }, | ||
| 560 | { USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_DMMP, HID_QUIRK_IGNORE }, | ||
| 561 | { USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_UMIP, HID_QUIRK_IGNORE }, | ||
| 562 | { USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_XRAY1, HID_QUIRK_IGNORE }, | ||
| 563 | { USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_XRAY2, HID_QUIRK_IGNORE }, | ||
| 564 | { USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_VIDEOCOM, HID_QUIRK_IGNORE }, | ||
| 565 | { USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_COM3LAB, HID_QUIRK_IGNORE }, | ||
| 566 | { USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_TELEPORT, HID_QUIRK_IGNORE }, | ||
| 567 | { USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_NETWORKANALYSER, HID_QUIRK_IGNORE }, | ||
| 568 | { USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_POWERCONTROL, HID_QUIRK_IGNORE }, | ||
| 569 | { USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MACHINETEST, HID_QUIRK_IGNORE }, | ||
| 570 | { USB_VENDOR_ID_MCC, USB_DEVICE_ID_MCC_PMD1024LS, HID_QUIRK_IGNORE }, | ||
| 571 | { USB_VENDOR_ID_MCC, USB_DEVICE_ID_MCC_PMD1208LS, HID_QUIRK_IGNORE }, | ||
| 572 | { USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS, HID_QUIRK_IGNORE }, | ||
| 573 | { USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS1, HID_QUIRK_IGNORE }, | ||
| 574 | { USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100, HID_QUIRK_IGNORE }, | ||
| 575 | { USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 20, HID_QUIRK_IGNORE }, | ||
| 576 | { USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 30, HID_QUIRK_IGNORE }, | ||
| 577 | { USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 100, HID_QUIRK_IGNORE }, | ||
| 578 | { USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 108, HID_QUIRK_IGNORE }, | ||
| 579 | { USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 118, HID_QUIRK_IGNORE }, | ||
| 580 | { USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 200, HID_QUIRK_IGNORE }, | ||
| 581 | { USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 300, HID_QUIRK_IGNORE }, | ||
| 582 | { USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 400, HID_QUIRK_IGNORE }, | ||
| 583 | { USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 500, HID_QUIRK_IGNORE }, | ||
| 584 | { USB_VENDOR_ID_PANJIT, 0x0001, HID_QUIRK_IGNORE }, | ||
| 585 | { USB_VENDOR_ID_PANJIT, 0x0002, HID_QUIRK_IGNORE }, | ||
| 586 | { USB_VENDOR_ID_PANJIT, 0x0003, HID_QUIRK_IGNORE }, | ||
| 587 | { USB_VENDOR_ID_PANJIT, 0x0004, HID_QUIRK_IGNORE }, | ||
| 588 | { USB_VENDOR_ID_SOUNDGRAPH, USB_DEVICE_ID_SOUNDGRAPH_IMON_LCD, HID_QUIRK_IGNORE }, | ||
| 589 | { USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_LABPRO, HID_QUIRK_IGNORE }, | ||
| 590 | { USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_GOTEMP, HID_QUIRK_IGNORE }, | ||
| 591 | { USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_SKIP, HID_QUIRK_IGNORE }, | ||
| 592 | { USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_CYCLOPS, HID_QUIRK_IGNORE }, | ||
| 593 | { USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_LCSPEC, HID_QUIRK_IGNORE }, | ||
| 594 | { USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_4_PHIDGETSERVO_20, HID_QUIRK_IGNORE }, | ||
| 595 | { USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_1_PHIDGETSERVO_20, HID_QUIRK_IGNORE }, | ||
| 596 | { USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_8_8_4_IF_KIT, HID_QUIRK_IGNORE }, | ||
| 597 | { USB_VENDOR_ID_YEALINK, USB_DEVICE_ID_YEALINK_P1K_P4K_B2K, HID_QUIRK_IGNORE }, | ||
| 598 | |||
| 599 | { USB_VENDOR_ID_ACECAD, USB_DEVICE_ID_ACECAD_FLAIR, HID_QUIRK_IGNORE }, | ||
| 600 | { USB_VENDOR_ID_ACECAD, USB_DEVICE_ID_ACECAD_302, HID_QUIRK_IGNORE }, | ||
| 601 | |||
| 602 | { USB_VENDOR_ID_MICROCHIP, USB_DEVICE_ID_PICKIT1, HID_QUIRK_IGNORE }, | ||
| 603 | { USB_VENDOR_ID_MICROCHIP, USB_DEVICE_ID_PICKIT2, HID_QUIRK_IGNORE }, | ||
| 604 | |||
| 605 | { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_ELITE_KBD, HID_QUIRK_LOGITECH_IGNORE_DOUBLED_WHEEL | HID_QUIRK_LOGITECH_EXPANDED_KEYMAP }, | ||
| 606 | { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_CORDLESS_DESKTOP_LX500, HID_QUIRK_LOGITECH_IGNORE_DOUBLED_WHEEL | HID_QUIRK_LOGITECH_EXPANDED_KEYMAP }, | ||
| 607 | |||
| 608 | { USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_NE4K, HID_QUIRK_MICROSOFT_KEYS }, | ||
| 609 | { USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_LK6K, HID_QUIRK_MICROSOFT_KEYS }, | ||
| 610 | |||
| 611 | { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MIGHTYMOUSE, HID_QUIRK_MIGHTYMOUSE | HID_QUIRK_INVERT_HWHEEL }, | ||
| 612 | |||
| 613 | { USB_VENDOR_ID_PANTHERLORD, USB_DEVICE_ID_PANTHERLORD_TWIN_USB_JOYSTICK, HID_QUIRK_MULTI_INPUT | HID_QUIRK_SKIP_OUTPUT_REPORTS }, | ||
| 614 | { USB_VENDOR_ID_PLAYDOTCOM, USB_DEVICE_ID_PLAYDOTCOM_EMS_USBII, HID_QUIRK_MULTI_INPUT }, | ||
| 615 | |||
| 616 | { USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER, HID_QUIRK_SONY_PS3_CONTROLLER | HID_QUIRK_HIDDEV }, | ||
| 617 | |||
| 618 | { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_UC100KM, HID_QUIRK_NOGET }, | ||
| 619 | { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_CS124U, HID_QUIRK_NOGET }, | ||
| 620 | { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_2PORTKVM, HID_QUIRK_NOGET }, | ||
| 621 | { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_4PORTKVM, HID_QUIRK_NOGET }, | ||
| 622 | { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_4PORTKVMC, HID_QUIRK_NOGET }, | ||
| 623 | { USB_VENDOR_ID_DMI, USB_DEVICE_ID_DMI_ENC, HID_QUIRK_NOGET }, | ||
| 624 | { USB_VENDOR_ID_ELO, USB_DEVICE_ID_ELO_TS2700, HID_QUIRK_NOGET }, | ||
| 625 | { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_EXTREME_3D, HID_QUIRK_NOGET }, | ||
| 626 | { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WHEEL, HID_QUIRK_NOGET }, | ||
| 627 | { USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_WIRELESS_OPTICAL_DESKTOP_3_0, HID_QUIRK_NOGET }, | ||
| 628 | { USB_VENDOR_ID_PETALYNX, USB_DEVICE_ID_PETALYNX_MAXTER_REMOTE, HID_QUIRK_NOGET }, | ||
| 629 | { USB_VENDOR_ID_SUN, USB_DEVICE_ID_RARITAN_KVM_DONGLE, HID_QUIRK_NOGET }, | ||
| 630 | { USB_VENDOR_ID_TURBOX, USB_DEVICE_ID_TURBOX_KEYBOARD, HID_QUIRK_NOGET }, | ||
| 631 | { USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_DUAL_USB_JOYPAD, HID_QUIRK_NOGET | HID_QUIRK_MULTI_INPUT | HID_QUIRK_SKIP_OUTPUT_REPORTS }, | ||
| 632 | { USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_QUAD_USB_JOYPAD, HID_QUIRK_NOGET | HID_QUIRK_MULTI_INPUT }, | ||
| 633 | |||
| 634 | { USB_VENDOR_ID_WISEGROUP_LTD, USB_DEVICE_ID_SMARTJOY_DUAL_PLUS, HID_QUIRK_NOGET | HID_QUIRK_MULTI_INPUT }, | ||
| 635 | |||
| 636 | { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_ANSI, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE }, | ||
| 637 | { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_ISO, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE }, | ||
| 638 | { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_ANSI, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE }, | ||
| 639 | { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_ISO, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE | HID_QUIRK_APPLE_ISO_KEYBOARD}, | ||
| 640 | { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_JIS, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE }, | ||
| 641 | { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_ANSI, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE }, | ||
| 642 | { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_ISO, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE | HID_QUIRK_APPLE_ISO_KEYBOARD}, | ||
| 643 | { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_JIS, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE }, | ||
| 644 | { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_ANSI, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE }, | ||
| 645 | { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_ISO, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE | HID_QUIRK_APPLE_ISO_KEYBOARD}, | ||
| 646 | { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_JIS, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE }, | ||
| 647 | { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_ANSI, HID_QUIRK_APPLE_HAS_FN }, | ||
| 648 | { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_ISO, HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_APPLE_ISO_KEYBOARD }, | ||
| 649 | { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_JIS, HID_QUIRK_APPLE_HAS_FN }, | ||
| 650 | { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_HF_ANSI, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE }, | ||
| 651 | { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_HF_ISO, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE }, | ||
| 652 | { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_HF_JIS, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE }, | ||
| 653 | { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_ANSI, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN }, | ||
| 654 | { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_ISO, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_APPLE_ISO_KEYBOARD }, | ||
| 655 | { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_JIS, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN }, | ||
| 656 | { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING_ANSI, HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE }, | ||
| 657 | { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING_ISO, HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_APPLE_ISO_KEYBOARD | HID_QUIRK_IGNORE_MOUSE}, | ||
| 658 | { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING_JIS, HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE}, | ||
| 659 | { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING2_ANSI, HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE}, | ||
| 660 | { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING2_ISO, HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_APPLE_ISO_KEYBOARD | HID_QUIRK_IGNORE_MOUSE }, | ||
| 661 | { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING2_JIS, HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE }, | ||
| 662 | { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING3_ANSI, HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE}, | ||
| 663 | { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING3_ISO, HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_APPLE_ISO_KEYBOARD | HID_QUIRK_IGNORE_MOUSE }, | ||
| 664 | { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING3_JIS, HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE }, | ||
| 665 | { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE }, | ||
| 666 | { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE }, | ||
| 667 | |||
| 668 | { USB_VENDOR_ID_DELL, USB_DEVICE_ID_DELL_W7658, HID_QUIRK_RESET_LEDS }, | ||
| 669 | { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_KBD, HID_QUIRK_RESET_LEDS }, | ||
| 670 | { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY, HID_QUIRK_IGNORE }, | ||
| 671 | { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_2, HID_QUIRK_IGNORE }, | ||
| 672 | { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_3, HID_QUIRK_IGNORE }, | ||
| 673 | { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_4, HID_QUIRK_IGNORE }, | ||
| 674 | { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_5, HID_QUIRK_IGNORE }, | ||
| 675 | { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_6, HID_QUIRK_IGNORE }, | ||
| 676 | { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_7, HID_QUIRK_IGNORE }, | ||
| 677 | { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_8, HID_QUIRK_IGNORE }, | ||
| 678 | { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_9, HID_QUIRK_IGNORE }, | ||
| 679 | { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_10, HID_QUIRK_IGNORE }, | ||
| 680 | { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_11, HID_QUIRK_IGNORE }, | ||
| 681 | { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_12, HID_QUIRK_IGNORE }, | ||
| 682 | { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_13, HID_QUIRK_IGNORE }, | ||
| 683 | { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_14, HID_QUIRK_IGNORE }, | ||
| 684 | { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_15, HID_QUIRK_IGNORE }, | ||
| 685 | { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_16, HID_QUIRK_IGNORE }, | ||
| 686 | { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_17, HID_QUIRK_IGNORE }, | ||
| 687 | { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_18, HID_QUIRK_IGNORE }, | ||
| 688 | { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_19, HID_QUIRK_IGNORE }, | ||
| 689 | { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_20, HID_QUIRK_IGNORE }, | ||
| 690 | { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_21, HID_QUIRK_IGNORE }, | ||
| 691 | { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_22, HID_QUIRK_IGNORE }, | ||
| 692 | { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_23, HID_QUIRK_IGNORE }, | ||
| 693 | { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_24, HID_QUIRK_IGNORE }, | ||
| 694 | { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_25, HID_QUIRK_IGNORE }, | ||
| 695 | { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_26, HID_QUIRK_IGNORE }, | ||
| 696 | { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_27, HID_QUIRK_IGNORE }, | ||
| 697 | { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_28, HID_QUIRK_IGNORE }, | ||
| 698 | { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_29, HID_QUIRK_IGNORE }, | ||
| 699 | { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_30, HID_QUIRK_IGNORE }, | ||
| 700 | { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_31, HID_QUIRK_IGNORE }, | ||
| 701 | { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_32, HID_QUIRK_IGNORE }, | ||
| 702 | { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_33, HID_QUIRK_IGNORE }, | ||
| 703 | { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_34, HID_QUIRK_IGNORE }, | ||
| 704 | { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_35, HID_QUIRK_IGNORE }, | ||
| 705 | { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_36, HID_QUIRK_IGNORE }, | ||
| 706 | { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_37, HID_QUIRK_IGNORE }, | ||
| 707 | { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_38, HID_QUIRK_IGNORE }, | ||
| 708 | { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_39, HID_QUIRK_IGNORE }, | ||
| 709 | { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_40, HID_QUIRK_IGNORE }, | ||
| 710 | { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_41, HID_QUIRK_IGNORE }, | ||
| 711 | { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_42, HID_QUIRK_IGNORE }, | ||
| 712 | { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_43, HID_QUIRK_IGNORE }, | ||
| 713 | { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_44, HID_QUIRK_IGNORE }, | ||
| 714 | { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_45, HID_QUIRK_IGNORE }, | ||
| 715 | { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_46, HID_QUIRK_IGNORE }, | ||
| 716 | { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_47, HID_QUIRK_IGNORE }, | ||
| 717 | { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_48, HID_QUIRK_IGNORE }, | ||
| 718 | { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_49, HID_QUIRK_IGNORE }, | ||
| 719 | { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_50, HID_QUIRK_IGNORE }, | ||
| 720 | { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_51, HID_QUIRK_IGNORE }, | ||
| 721 | { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_52, HID_QUIRK_IGNORE }, | ||
| 722 | { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_53, HID_QUIRK_IGNORE }, | ||
| 723 | { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_54, HID_QUIRK_IGNORE }, | ||
| 724 | { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_55, HID_QUIRK_IGNORE }, | ||
| 725 | { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_56, HID_QUIRK_IGNORE }, | ||
| 726 | { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_57, HID_QUIRK_IGNORE }, | ||
| 727 | { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_58, HID_QUIRK_IGNORE }, | ||
| 728 | { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_59, HID_QUIRK_IGNORE }, | ||
| 729 | { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_60, HID_QUIRK_IGNORE }, | ||
| 730 | { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_61, HID_QUIRK_IGNORE }, | ||
| 731 | { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_62, HID_QUIRK_IGNORE }, | ||
| 732 | { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_63, HID_QUIRK_IGNORE }, | ||
| 733 | { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_64, HID_QUIRK_IGNORE }, | ||
| 734 | { USB_VENDOR_ID_NATIONAL_SEMICONDUCTOR, USB_DEVICE_ID_N_S_HARMONY, HID_QUIRK_IGNORE }, | ||
| 735 | { USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_GPEN_560, HID_QUIRK_IGNORE }, | ||
| 736 | |||
| 737 | { 0, 0 } | ||
| 738 | }; | ||
| 739 | |||
| 740 | /* Quirks for devices which require report descriptor fixup go here */ | ||
| 741 | static const struct hid_rdesc_blacklist { | ||
| 742 | __u16 idVendor; | ||
| 743 | __u16 idProduct; | ||
| 744 | __u32 quirks; | ||
| 745 | } hid_rdesc_blacklist[] = { | ||
| 746 | |||
| 747 | { USB_VENDOR_ID_CHERRY, USB_DEVICE_ID_CHERRY_CYMOTION, HID_QUIRK_RDESC_CYMOTION }, | ||
| 748 | |||
| 749 | { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_MX3000_RECEIVER, HID_QUIRK_RDESC_LOGITECH }, | ||
| 750 | { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER, HID_QUIRK_RDESC_LOGITECH }, | ||
| 751 | { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER_2, HID_QUIRK_RDESC_LOGITECH }, | ||
| 752 | { USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_DESKTOP_RECV_1028, HID_QUIRK_RDESC_MICROSOFT_RECV_1028 }, | ||
| 753 | |||
| 754 | { USB_VENDOR_ID_MONTEREY, USB_DEVICE_ID_GENIUS_KB29E, HID_QUIRK_RDESC_BUTTON_CONSUMER }, | ||
| 755 | |||
| 756 | { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_JIS, HID_QUIRK_RDESC_MACBOOK_JIS }, | ||
| 757 | |||
| 758 | { USB_VENDOR_ID_PETALYNX, USB_DEVICE_ID_PETALYNX_MAXTER_REMOTE, HID_QUIRK_RDESC_PETALYNX }, | ||
| 759 | |||
| 760 | { USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_IR_REMOTE, HID_QUIRK_RDESC_SAMSUNG_REMOTE }, | ||
| 761 | |||
| 762 | { USB_VENDOR_ID_SUNPLUS, USB_DEVICE_ID_SUNPLUS_WDESKTOP, HID_QUIRK_RDESC_SUNPLUS_WDESKTOP }, | ||
| 763 | |||
| 764 | { USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_1, HID_QUIRK_RDESC_SWAPPED_MIN_MAX }, | ||
| 765 | { USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_2, HID_QUIRK_RDESC_SWAPPED_MIN_MAX }, | ||
| 766 | |||
| 767 | { 0, 0 } | ||
| 768 | }; | ||
| 769 | |||
| 770 | /* Dynamic HID quirks list - specified at runtime */ | ||
| 771 | struct quirks_list_struct { | ||
| 772 | struct hid_blacklist hid_bl_item; | ||
| 773 | struct list_head node; | ||
| 774 | }; | ||
| 775 | |||
| 776 | static LIST_HEAD(dquirks_list); | ||
| 777 | static DECLARE_RWSEM(dquirks_rwsem); | ||
| 778 | |||
| 779 | /* Runtime ("dynamic") quirks manipulation functions */ | ||
| 780 | |||
| 781 | /** | ||
| 782 | * usbhid_exists_dquirk: find any dynamic quirks for a USB HID device | ||
| 783 | * @idVendor: the 16-bit USB vendor ID, in native byteorder | ||
| 784 | * @idProduct: the 16-bit USB product ID, in native byteorder | ||
| 785 | * | ||
| 786 | * Description: | ||
| 787 | * Scans dquirks_list for a matching dynamic quirk and returns | ||
| 788 | * the pointer to the relevant struct hid_blacklist if found. | ||
| 789 | * Must be called with a read lock held on dquirks_rwsem. | ||
| 790 | * | ||
| 791 | * Returns: NULL if no quirk found, struct hid_blacklist * if found. | ||
| 792 | */ | ||
| 793 | static struct hid_blacklist *usbhid_exists_dquirk(const u16 idVendor, | ||
| 794 | const u16 idProduct) | ||
| 795 | { | ||
| 796 | struct quirks_list_struct *q; | ||
| 797 | struct hid_blacklist *bl_entry = NULL; | ||
| 798 | |||
| 799 | list_for_each_entry(q, &dquirks_list, node) { | ||
| 800 | if (q->hid_bl_item.idVendor == idVendor && | ||
| 801 | q->hid_bl_item.idProduct == idProduct) { | ||
| 802 | bl_entry = &q->hid_bl_item; | ||
| 803 | break; | ||
| 804 | } | ||
| 805 | } | ||
| 806 | |||
| 807 | if (bl_entry != NULL) | ||
| 808 | dbg_hid("Found dynamic quirk 0x%x for USB HID vendor 0x%hx prod 0x%hx\n", | ||
| 809 | bl_entry->quirks, bl_entry->idVendor, | ||
| 810 | bl_entry->idProduct); | ||
| 811 | |||
| 812 | return bl_entry; | ||
| 813 | } | ||
| 814 | |||
| 815 | |||
| 816 | /** | ||
| 817 | * usbhid_modify_dquirk: add/replace a HID quirk | ||
| 818 | * @idVendor: the 16-bit USB vendor ID, in native byteorder | ||
| 819 | * @idProduct: the 16-bit USB product ID, in native byteorder | ||
| 820 | * @quirks: the u32 quirks value to add/replace | ||
| 821 | * | ||
| 822 | * Description: | ||
| 823 | * If an dynamic quirk exists in memory for this (idVendor, | ||
| 824 | * idProduct) pair, replace its quirks value with what was | ||
| 825 | * provided. Otherwise, add the quirk to the dynamic quirks list. | ||
| 826 | * | ||
| 827 | * Returns: 0 OK, -error on failure. | ||
| 828 | */ | ||
| 829 | static int usbhid_modify_dquirk(const u16 idVendor, const u16 idProduct, | ||
| 830 | const u32 quirks) | ||
| 831 | { | ||
| 832 | struct quirks_list_struct *q_new, *q; | ||
| 833 | int list_edited = 0; | ||
| 834 | |||
| 835 | if (!idVendor) { | ||
| 836 | dbg_hid("Cannot add a quirk with idVendor = 0\n"); | ||
| 837 | return -EINVAL; | ||
| 838 | } | ||
| 839 | |||
| 840 | q_new = kmalloc(sizeof(struct quirks_list_struct), GFP_KERNEL); | ||
| 841 | if (!q_new) { | ||
| 842 | dbg_hid("Could not allocate quirks_list_struct\n"); | ||
| 843 | return -ENOMEM; | ||
| 844 | } | ||
| 845 | |||
| 846 | q_new->hid_bl_item.idVendor = idVendor; | ||
| 847 | q_new->hid_bl_item.idProduct = idProduct; | ||
| 848 | q_new->hid_bl_item.quirks = quirks; | ||
| 849 | |||
| 850 | down_write(&dquirks_rwsem); | ||
| 851 | |||
| 852 | list_for_each_entry(q, &dquirks_list, node) { | ||
| 853 | |||
| 854 | if (q->hid_bl_item.idVendor == idVendor && | ||
| 855 | q->hid_bl_item.idProduct == idProduct) { | ||
| 856 | |||
| 857 | list_replace(&q->node, &q_new->node); | ||
| 858 | kfree(q); | ||
| 859 | list_edited = 1; | ||
| 860 | break; | ||
| 861 | |||
| 862 | } | ||
| 863 | |||
| 864 | } | ||
| 865 | |||
| 866 | if (!list_edited) | ||
| 867 | list_add_tail(&q_new->node, &dquirks_list); | ||
| 868 | |||
| 869 | up_write(&dquirks_rwsem); | ||
| 870 | |||
| 871 | return 0; | ||
| 872 | } | ||
| 873 | |||
| 874 | /** | ||
| 875 | * usbhid_remove_all_dquirks: remove all runtime HID quirks from memory | ||
| 876 | * | ||
| 877 | * Description: | ||
| 878 | * Free all memory associated with dynamic quirks - called before | ||
| 879 | * module unload. | ||
| 880 | * | ||
| 881 | */ | ||
| 882 | static void usbhid_remove_all_dquirks(void) | ||
| 883 | { | ||
| 884 | struct quirks_list_struct *q, *temp; | ||
| 885 | |||
| 886 | down_write(&dquirks_rwsem); | ||
| 887 | list_for_each_entry_safe(q, temp, &dquirks_list, node) { | ||
| 888 | list_del(&q->node); | ||
| 889 | kfree(q); | ||
| 890 | } | ||
| 891 | up_write(&dquirks_rwsem); | ||
| 892 | |||
| 893 | } | ||
| 894 | |||
| 895 | /** | ||
| 896 | * usbhid_quirks_init: apply USB HID quirks specified at module load time | ||
| 897 | */ | ||
| 898 | int usbhid_quirks_init(char **quirks_param) | ||
| 899 | { | ||
| 900 | u16 idVendor, idProduct; | ||
| 901 | u32 quirks; | ||
| 902 | int n = 0, m; | ||
| 903 | |||
| 904 | for (; quirks_param[n] && n < MAX_USBHID_BOOT_QUIRKS; n++) { | ||
| 905 | |||
| 906 | m = sscanf(quirks_param[n], "0x%hx:0x%hx:0x%x", | ||
| 907 | &idVendor, &idProduct, &quirks); | ||
| 908 | |||
| 909 | if (m != 3 || | ||
| 910 | usbhid_modify_dquirk(idVendor, idProduct, quirks) != 0) { | ||
| 911 | printk(KERN_WARNING | ||
| 912 | "Could not parse HID quirk module param %s\n", | ||
| 913 | quirks_param[n]); | ||
| 914 | } | ||
| 915 | } | ||
| 916 | |||
| 917 | return 0; | ||
| 918 | } | ||
| 919 | |||
| 920 | /** | ||
| 921 | * usbhid_quirks_exit: release memory associated with dynamic_quirks | ||
| 922 | * | ||
| 923 | * Description: | ||
| 924 | * Release all memory associated with dynamic quirks. Called upon | ||
| 925 | * module unload. | ||
| 926 | * | ||
| 927 | * Returns: nothing | ||
| 928 | */ | ||
| 929 | void usbhid_quirks_exit(void) | ||
| 930 | { | ||
| 931 | usbhid_remove_all_dquirks(); | ||
| 932 | } | ||
| 933 | |||
| 934 | /** | ||
| 935 | * usbhid_exists_squirk: return any static quirks for a USB HID device | ||
| 936 | * @idVendor: the 16-bit USB vendor ID, in native byteorder | ||
| 937 | * @idProduct: the 16-bit USB product ID, in native byteorder | ||
| 938 | * | ||
| 939 | * Description: | ||
| 940 | * Given a USB vendor ID and product ID, return a pointer to | ||
| 941 | * the hid_blacklist entry associated with that device. | ||
| 942 | * | ||
| 943 | * Returns: pointer if quirk found, or NULL if no quirks found. | ||
| 944 | */ | ||
| 945 | static const struct hid_blacklist *usbhid_exists_squirk(const u16 idVendor, | ||
| 946 | const u16 idProduct) | ||
| 947 | { | ||
| 948 | const struct hid_blacklist *bl_entry = NULL; | ||
| 949 | int n = 0; | ||
| 950 | |||
| 951 | for (; hid_blacklist[n].idVendor; n++) | ||
| 952 | if (hid_blacklist[n].idVendor == idVendor && | ||
| 953 | hid_blacklist[n].idProduct == idProduct) | ||
| 954 | bl_entry = &hid_blacklist[n]; | ||
| 955 | |||
| 956 | if (bl_entry != NULL) | ||
| 957 | dbg_hid("Found squirk 0x%x for USB HID vendor 0x%hx prod 0x%hx\n", | ||
| 958 | bl_entry->quirks, bl_entry->idVendor, | ||
| 959 | bl_entry->idProduct); | ||
| 960 | return bl_entry; | ||
| 961 | } | ||
| 962 | |||
| 963 | /** | ||
| 964 | * usbhid_lookup_quirk: return any quirks associated with a USB HID device | ||
| 965 | * @idVendor: the 16-bit USB vendor ID, in native byteorder | ||
| 966 | * @idProduct: the 16-bit USB product ID, in native byteorder | ||
| 967 | * | ||
| 968 | * Description: | ||
| 969 | * Given a USB vendor ID and product ID, return any quirks associated | ||
| 970 | * with that device. | ||
| 971 | * | ||
| 972 | * Returns: a u32 quirks value. | ||
| 973 | */ | ||
| 974 | u32 usbhid_lookup_quirk(const u16 idVendor, const u16 idProduct) | ||
| 975 | { | ||
| 976 | u32 quirks = 0; | ||
| 977 | const struct hid_blacklist *bl_entry = NULL; | ||
| 978 | |||
| 979 | /* Ignore all Wacom devices */ | ||
| 980 | if (idVendor == USB_VENDOR_ID_WACOM) | ||
| 981 | return HID_QUIRK_IGNORE; | ||
| 982 | |||
| 983 | /* ignore all Code Mercenaries IOWarrior devices */ | ||
| 984 | if (idVendor == USB_VENDOR_ID_CODEMERCS) | ||
| 985 | if (idProduct >= USB_DEVICE_ID_CODEMERCS_IOW_FIRST && | ||
| 986 | idProduct <= USB_DEVICE_ID_CODEMERCS_IOW_LAST) | ||
| 987 | return HID_QUIRK_IGNORE; | ||
| 988 | |||
| 989 | /* NCR devices must not be queried for reports */ | ||
| 990 | if (idVendor == USB_VENDOR_ID_NCR && | ||
| 991 | idProduct >= USB_DEVICE_ID_NCR_FIRST && | ||
| 992 | idProduct <= USB_DEVICE_ID_NCR_LAST) | ||
| 993 | return HID_QUIRK_NOGET; | ||
| 994 | |||
| 995 | down_read(&dquirks_rwsem); | ||
| 996 | bl_entry = usbhid_exists_dquirk(idVendor, idProduct); | ||
| 997 | if (!bl_entry) | ||
| 998 | bl_entry = usbhid_exists_squirk(idVendor, idProduct); | ||
| 999 | if (bl_entry) | ||
| 1000 | quirks = bl_entry->quirks; | ||
| 1001 | up_read(&dquirks_rwsem); | ||
| 1002 | |||
| 1003 | return quirks; | ||
| 1004 | } | ||
| 1005 | |||
| 1006 | EXPORT_SYMBOL_GPL(usbhid_lookup_quirk); | ||
| 1007 | |||
| 1008 | /* | ||
| 1009 | * Cherry Cymotion keyboard have an invalid HID report descriptor, | ||
| 1010 | * that needs fixing before we can parse it. | ||
| 1011 | */ | ||
| 1012 | static void usbhid_fixup_cymotion_descriptor(char *rdesc, int rsize) | ||
| 1013 | { | ||
| 1014 | if (rsize >= 17 && rdesc[11] == 0x3c && rdesc[12] == 0x02) { | ||
| 1015 | printk(KERN_INFO "Fixing up Cherry Cymotion report descriptor\n"); | ||
| 1016 | rdesc[11] = rdesc[16] = 0xff; | ||
| 1017 | rdesc[12] = rdesc[17] = 0x03; | ||
| 1018 | } | ||
| 1019 | } | ||
| 1020 | |||
| 1021 | |||
| 1022 | /* | ||
| 1023 | * Certain Logitech keyboards send in report #3 keys which are far | ||
| 1024 | * above the logical maximum described in descriptor. This extends | ||
| 1025 | * the original value of 0x28c of logical maximum to 0x104d | ||
| 1026 | */ | ||
| 1027 | static void usbhid_fixup_logitech_descriptor(unsigned char *rdesc, int rsize) | ||
| 1028 | { | ||
| 1029 | if (rsize >= 90 && rdesc[83] == 0x26 | ||
| 1030 | && rdesc[84] == 0x8c | ||
| 1031 | && rdesc[85] == 0x02) { | ||
| 1032 | printk(KERN_INFO "Fixing up Logitech keyboard report descriptor\n"); | ||
| 1033 | rdesc[84] = rdesc[89] = 0x4d; | ||
| 1034 | rdesc[85] = rdesc[90] = 0x10; | ||
| 1035 | } | ||
| 1036 | } | ||
| 1037 | |||
| 1038 | static void usbhid_fixup_sunplus_wdesktop(unsigned char *rdesc, int rsize) | ||
| 1039 | { | ||
| 1040 | if (rsize >= 107 && rdesc[104] == 0x26 | ||
| 1041 | && rdesc[105] == 0x80 | ||
| 1042 | && rdesc[106] == 0x03) { | ||
| 1043 | printk(KERN_INFO "Fixing up Sunplus Wireless Desktop report descriptor\n"); | ||
| 1044 | rdesc[105] = rdesc[110] = 0x03; | ||
| 1045 | rdesc[106] = rdesc[111] = 0x21; | ||
| 1046 | } | ||
| 1047 | } | ||
| 1048 | |||
| 1049 | /* | ||
| 1050 | * Samsung IrDA remote controller (reports as Cypress USB Mouse). | ||
| 1051 | * | ||
| 1052 | * Vendor specific report #4 has a size of 48 bit, | ||
| 1053 | * and therefore is not accepted when inspecting the descriptors. | ||
| 1054 | * As a workaround we reinterpret the report as: | ||
| 1055 | * Variable type, count 6, size 8 bit, log. maximum 255 | ||
| 1056 | * The burden to reconstruct the data is moved into user space. | ||
| 1057 | */ | ||
| 1058 | static void usbhid_fixup_samsung_irda_descriptor(unsigned char *rdesc, | ||
| 1059 | int rsize) | ||
| 1060 | { | ||
| 1061 | if (rsize >= 182 && rdesc[175] == 0x25 | ||
| 1062 | && rdesc[176] == 0x40 | ||
| 1063 | && rdesc[177] == 0x75 | ||
| 1064 | && rdesc[178] == 0x30 | ||
| 1065 | && rdesc[179] == 0x95 | ||
| 1066 | && rdesc[180] == 0x01 | ||
| 1067 | && rdesc[182] == 0x40) { | ||
| 1068 | printk(KERN_INFO "Fixing up Samsung IrDA report descriptor\n"); | ||
| 1069 | rdesc[176] = 0xff; | ||
| 1070 | rdesc[178] = 0x08; | ||
| 1071 | rdesc[180] = 0x06; | ||
| 1072 | rdesc[182] = 0x42; | ||
| 1073 | } | ||
| 1074 | } | ||
| 1075 | |||
| 1076 | /* Petalynx Maxter Remote has maximum for consumer page set too low */ | ||
| 1077 | static void usbhid_fixup_petalynx_descriptor(unsigned char *rdesc, int rsize) | ||
| 1078 | { | ||
| 1079 | if (rsize >= 60 && rdesc[39] == 0x2a | ||
| 1080 | && rdesc[40] == 0xf5 | ||
| 1081 | && rdesc[41] == 0x00 | ||
| 1082 | && rdesc[59] == 0x26 | ||
| 1083 | && rdesc[60] == 0xf9 | ||
| 1084 | && rdesc[61] == 0x00) { | ||
| 1085 | printk(KERN_INFO "Fixing up Petalynx Maxter Remote report descriptor\n"); | ||
| 1086 | rdesc[60] = 0xfa; | ||
| 1087 | rdesc[40] = 0xfa; | ||
| 1088 | } | ||
| 1089 | } | ||
| 1090 | |||
| 1091 | /* | ||
| 1092 | * Some USB barcode readers from cypress have usage min and usage max in | ||
| 1093 | * the wrong order | ||
| 1094 | */ | ||
| 1095 | static void usbhid_fixup_cypress_descriptor(unsigned char *rdesc, int rsize) | ||
| 1096 | { | ||
| 1097 | short fixed = 0; | ||
| 1098 | int i; | ||
| 1099 | |||
| 1100 | for (i = 0; i < rsize - 4; i++) { | ||
| 1101 | if (rdesc[i] == 0x29 && rdesc [i+2] == 0x19) { | ||
| 1102 | unsigned char tmp; | ||
| 1103 | |||
| 1104 | rdesc[i] = 0x19; rdesc[i+2] = 0x29; | ||
| 1105 | tmp = rdesc[i+3]; | ||
| 1106 | rdesc[i+3] = rdesc[i+1]; | ||
| 1107 | rdesc[i+1] = tmp; | ||
| 1108 | } | ||
| 1109 | } | ||
| 1110 | |||
| 1111 | if (fixed) | ||
| 1112 | printk(KERN_INFO "Fixing up Cypress report descriptor\n"); | ||
| 1113 | } | ||
| 1114 | |||
| 1115 | /* | ||
| 1116 | * MacBook JIS keyboard has wrong logical maximum | ||
| 1117 | */ | ||
| 1118 | static void usbhid_fixup_macbook_descriptor(unsigned char *rdesc, int rsize) | ||
| 1119 | { | ||
| 1120 | if (rsize >= 60 && rdesc[53] == 0x65 | ||
| 1121 | && rdesc[59] == 0x65) { | ||
| 1122 | printk(KERN_INFO "Fixing up MacBook JIS keyboard report descriptor\n"); | ||
| 1123 | rdesc[53] = rdesc[59] = 0xe7; | ||
| 1124 | } | ||
| 1125 | } | ||
| 1126 | |||
| 1127 | static void usbhid_fixup_button_consumer_descriptor(unsigned char *rdesc, int rsize) | ||
| 1128 | { | ||
| 1129 | if (rsize >= 30 && rdesc[29] == 0x05 | ||
| 1130 | && rdesc[30] == 0x09) { | ||
| 1131 | printk(KERN_INFO "Fixing up button/consumer in HID report descriptor\n"); | ||
| 1132 | rdesc[30] = 0x0c; | ||
| 1133 | } | ||
| 1134 | } | ||
| 1135 | |||
| 1136 | /* | ||
| 1137 | * Microsoft Wireless Desktop Receiver (Model 1028) has several | ||
| 1138 | * 'Usage Min/Max' where it ought to have 'Physical Min/Max' | ||
| 1139 | */ | ||
| 1140 | static void usbhid_fixup_microsoft_descriptor(unsigned char *rdesc, int rsize) | ||
| 1141 | { | ||
| 1142 | if (rsize == 571 && rdesc[284] == 0x19 | ||
| 1143 | && rdesc[286] == 0x2a | ||
| 1144 | && rdesc[304] == 0x19 | ||
| 1145 | && rdesc[306] == 0x29 | ||
| 1146 | && rdesc[352] == 0x1a | ||
| 1147 | && rdesc[355] == 0x2a | ||
| 1148 | && rdesc[557] == 0x19 | ||
| 1149 | && rdesc[559] == 0x29) { | ||
| 1150 | printk(KERN_INFO "Fixing up Microsoft Wireless Receiver Model 1028 report descriptor\n"); | ||
| 1151 | rdesc[284] = rdesc[304] = rdesc[557] = 0x35; | ||
| 1152 | rdesc[352] = 0x36; | ||
| 1153 | rdesc[286] = rdesc[355] = 0x46; | ||
| 1154 | rdesc[306] = rdesc[559] = 0x45; | ||
| 1155 | } | ||
| 1156 | } | ||
| 1157 | |||
| 1158 | static void __usbhid_fixup_report_descriptor(__u32 quirks, char *rdesc, unsigned rsize) | ||
| 1159 | { | ||
| 1160 | if ((quirks & HID_QUIRK_RDESC_CYMOTION)) | ||
| 1161 | usbhid_fixup_cymotion_descriptor(rdesc, rsize); | ||
| 1162 | |||
| 1163 | if (quirks & HID_QUIRK_RDESC_LOGITECH) | ||
| 1164 | usbhid_fixup_logitech_descriptor(rdesc, rsize); | ||
| 1165 | |||
| 1166 | if (quirks & HID_QUIRK_RDESC_SWAPPED_MIN_MAX) | ||
| 1167 | usbhid_fixup_cypress_descriptor(rdesc, rsize); | ||
| 1168 | |||
| 1169 | if (quirks & HID_QUIRK_RDESC_PETALYNX) | ||
| 1170 | usbhid_fixup_petalynx_descriptor(rdesc, rsize); | ||
| 1171 | |||
| 1172 | if (quirks & HID_QUIRK_RDESC_MACBOOK_JIS) | ||
| 1173 | usbhid_fixup_macbook_descriptor(rdesc, rsize); | ||
| 1174 | |||
| 1175 | if (quirks & HID_QUIRK_RDESC_BUTTON_CONSUMER) | ||
| 1176 | usbhid_fixup_button_consumer_descriptor(rdesc, rsize); | ||
| 1177 | |||
| 1178 | if (quirks & HID_QUIRK_RDESC_SAMSUNG_REMOTE) | ||
| 1179 | usbhid_fixup_samsung_irda_descriptor(rdesc, rsize); | ||
| 1180 | |||
| 1181 | if (quirks & HID_QUIRK_RDESC_MICROSOFT_RECV_1028) | ||
| 1182 | usbhid_fixup_microsoft_descriptor(rdesc, rsize); | ||
| 1183 | |||
| 1184 | if (quirks & HID_QUIRK_RDESC_SUNPLUS_WDESKTOP) | ||
| 1185 | usbhid_fixup_sunplus_wdesktop(rdesc, rsize); | ||
| 1186 | } | ||
| 1187 | |||
| 1188 | /** | ||
| 1189 | * usbhid_fixup_report_descriptor: check if report descriptor needs fixup | ||
| 1190 | * | ||
| 1191 | * Description: | ||
| 1192 | * Walks the hid_rdesc_blacklist[] array and checks whether the device | ||
| 1193 | * is known to have broken report descriptor that needs to be fixed up | ||
| 1194 | * prior to entering the HID parser | ||
| 1195 | * | ||
| 1196 | * Returns: nothing | ||
| 1197 | */ | ||
| 1198 | void usbhid_fixup_report_descriptor(const u16 idVendor, const u16 idProduct, | ||
| 1199 | char *rdesc, unsigned rsize, char **quirks_param) | ||
| 1200 | { | ||
| 1201 | int n, m; | ||
| 1202 | u16 paramVendor, paramProduct; | ||
| 1203 | u32 quirks; | ||
| 1204 | |||
| 1205 | /* static rdesc quirk entries */ | ||
| 1206 | for (n = 0; hid_rdesc_blacklist[n].idVendor; n++) | ||
| 1207 | if (hid_rdesc_blacklist[n].idVendor == idVendor && | ||
| 1208 | hid_rdesc_blacklist[n].idProduct == idProduct) | ||
| 1209 | __usbhid_fixup_report_descriptor(hid_rdesc_blacklist[n].quirks, | ||
| 1210 | rdesc, rsize); | ||
| 1211 | |||
| 1212 | /* runtime rdesc quirk entries handling */ | ||
| 1213 | for (n = 0; quirks_param[n] && n < MAX_USBHID_BOOT_QUIRKS; n++) { | ||
| 1214 | m = sscanf(quirks_param[n], "0x%hx:0x%hx:0x%x", | ||
| 1215 | ¶mVendor, ¶mProduct, &quirks); | ||
| 1216 | |||
| 1217 | if (m != 3) | ||
| 1218 | printk(KERN_WARNING | ||
| 1219 | "Could not parse HID quirk module param %s\n", | ||
| 1220 | quirks_param[n]); | ||
| 1221 | else if (paramVendor == idVendor && paramProduct == idProduct) | ||
| 1222 | __usbhid_fixup_report_descriptor(quirks, rdesc, rsize); | ||
| 1223 | } | ||
| 1224 | } | ||
diff --git a/usr/src/dkms_source_tree/hid-tmff.c b/usr/src/dkms_source_tree/hid-tmff.c new file mode 100644 index 0000000..144578b --- /dev/null +++ b/usr/src/dkms_source_tree/hid-tmff.c | |||
| @@ -0,0 +1,225 @@ | |||
| 1 | /* | ||
| 2 | * Force feedback support for various HID compliant devices by ThrustMaster: | ||
| 3 | * ThrustMaster FireStorm Dual Power 2 | ||
| 4 | * and possibly others whose device ids haven't been added. | ||
| 5 | * | ||
| 6 | * Modified to support ThrustMaster devices by Zinx Verituse | ||
| 7 | * on 2003-01-25 from the Logitech force feedback driver, | ||
| 8 | * which is by Johann Deneux. | ||
| 9 | * | ||
| 10 | * Copyright (c) 2003 Zinx Verituse <zinx@epicsol.org> | ||
| 11 | * Copyright (c) 2002 Johann Deneux | ||
| 12 | */ | ||
| 13 | |||
| 14 | /* | ||
| 15 | * This program is free software; you can redistribute it and/or modify | ||
| 16 | * it under the terms of the GNU General Public License as published by | ||
| 17 | * the Free Software Foundation; either version 2 of the License, or | ||
| 18 | * (at your option) any later version. | ||
| 19 | * | ||
| 20 | * This program is distributed in the hope that it will be useful, | ||
| 21 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 22 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 23 | * GNU General Public License for more details. | ||
| 24 | * | ||
| 25 | * You should have received a copy of the GNU General Public License | ||
| 26 | * along with this program; if not, write to the Free Software | ||
| 27 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 28 | */ | ||
| 29 | |||
| 30 | #include <linux/input.h> | ||
| 31 | |||
| 32 | #undef DEBUG | ||
| 33 | #include <linux/usb.h> | ||
| 34 | |||
| 35 | #include <linux/hid.h> | ||
| 36 | #include "usbhid.h" | ||
| 37 | |||
| 38 | /* Usages for thrustmaster devices I know about */ | ||
| 39 | #define THRUSTMASTER_USAGE_FF (HID_UP_GENDESK | 0xbb) | ||
| 40 | |||
| 41 | struct dev_type { | ||
| 42 | u16 idVendor; | ||
| 43 | u16 idProduct; | ||
| 44 | const signed short *ff; | ||
| 45 | }; | ||
| 46 | |||
| 47 | static const signed short ff_rumble[] = { | ||
| 48 | FF_RUMBLE, | ||
| 49 | -1 | ||
| 50 | }; | ||
| 51 | |||
| 52 | static const signed short ff_joystick[] = { | ||
| 53 | FF_CONSTANT, | ||
| 54 | -1 | ||
| 55 | }; | ||
| 56 | |||
| 57 | static const struct dev_type devices[] = { | ||
| 58 | { 0x44f, 0xb300, ff_rumble }, | ||
| 59 | { 0x44f, 0xb304, ff_rumble }, | ||
| 60 | { 0x44f, 0xb651, ff_rumble }, /* FGT Rumble Force Wheel */ | ||
| 61 | { 0x44f, 0xb654, ff_joystick }, /* FGT Force Feedback Wheel */ | ||
| 62 | }; | ||
| 63 | |||
| 64 | struct tmff_device { | ||
| 65 | struct hid_report *report; | ||
| 66 | struct hid_field *ff_field; | ||
| 67 | }; | ||
| 68 | |||
| 69 | /* Changes values from 0 to 0xffff into values from minimum to maximum */ | ||
| 70 | static inline int hid_tmff_scale_u16(unsigned int in, | ||
| 71 | int minimum, int maximum) | ||
| 72 | { | ||
| 73 | int ret; | ||
| 74 | |||
| 75 | ret = (in * (maximum - minimum) / 0xffff) + minimum; | ||
| 76 | if (ret < minimum) | ||
| 77 | return minimum; | ||
| 78 | if (ret > maximum) | ||
| 79 | return maximum; | ||
| 80 | return ret; | ||
| 81 | } | ||
| 82 | |||
| 83 | /* Changes values from -0x80 to 0x7f into values from minimum to maximum */ | ||
| 84 | static inline int hid_tmff_scale_s8(int in, | ||
| 85 | int minimum, int maximum) | ||
| 86 | { | ||
| 87 | int ret; | ||
| 88 | |||
| 89 | ret = (((in + 0x80) * (maximum - minimum)) / 0xff) + minimum; | ||
| 90 | if (ret < minimum) | ||
| 91 | return minimum; | ||
| 92 | if (ret > maximum) | ||
| 93 | return maximum; | ||
| 94 | return ret; | ||
| 95 | } | ||
| 96 | |||
| 97 | static int hid_tmff_play(struct input_dev *dev, void *data, struct ff_effect *effect) | ||
| 98 | { | ||
| 99 | struct hid_device *hid = input_get_drvdata(dev); | ||
| 100 | struct tmff_device *tmff = data; | ||
| 101 | struct hid_field *ff_field = tmff->ff_field; | ||
| 102 | int x, y; | ||
| 103 | int left, right; /* Rumbling */ | ||
| 104 | |||
| 105 | switch (effect->type) { | ||
| 106 | case FF_CONSTANT: | ||
| 107 | x = hid_tmff_scale_s8(effect->u.ramp.start_level, | ||
| 108 | ff_field->logical_minimum, | ||
| 109 | ff_field->logical_maximum); | ||
| 110 | y = hid_tmff_scale_s8(effect->u.ramp.end_level, | ||
| 111 | ff_field->logical_minimum, | ||
| 112 | ff_field->logical_maximum); | ||
| 113 | |||
| 114 | dbg_hid("(x, y)=(%04x, %04x)\n", x, y); | ||
| 115 | ff_field->value[0] = x; | ||
| 116 | ff_field->value[1] = y; | ||
| 117 | usbhid_submit_report(hid, tmff->report, USB_DIR_OUT); | ||
| 118 | break; | ||
| 119 | |||
| 120 | case FF_RUMBLE: | ||
| 121 | left = hid_tmff_scale_u16(effect->u.rumble.weak_magnitude, | ||
| 122 | ff_field->logical_minimum, | ||
| 123 | ff_field->logical_maximum); | ||
| 124 | right = hid_tmff_scale_u16(effect->u.rumble.strong_magnitude, | ||
| 125 | ff_field->logical_minimum, | ||
| 126 | ff_field->logical_maximum); | ||
| 127 | |||
| 128 | dbg_hid("(left,right)=(%08x, %08x)\n", left, right); | ||
| 129 | ff_field->value[0] = left; | ||
| 130 | ff_field->value[1] = right; | ||
| 131 | usbhid_submit_report(hid, tmff->report, USB_DIR_OUT); | ||
| 132 | break; | ||
| 133 | } | ||
| 134 | return 0; | ||
| 135 | } | ||
| 136 | |||
| 137 | int hid_tmff_init(struct hid_device *hid) | ||
| 138 | { | ||
| 139 | struct tmff_device *tmff; | ||
| 140 | struct hid_report *report; | ||
| 141 | struct list_head *report_list; | ||
| 142 | struct hid_input *hidinput = list_entry(hid->inputs.next, struct hid_input, list); | ||
| 143 | struct input_dev *input_dev = hidinput->input; | ||
| 144 | const signed short *ff_bits = ff_joystick; | ||
| 145 | int error; | ||
| 146 | int i; | ||
| 147 | |||
| 148 | tmff = kzalloc(sizeof(struct tmff_device), GFP_KERNEL); | ||
| 149 | if (!tmff) | ||
| 150 | return -ENOMEM; | ||
| 151 | |||
| 152 | /* Find the report to use */ | ||
| 153 | report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list; | ||
| 154 | list_for_each_entry(report, report_list, list) { | ||
| 155 | int fieldnum; | ||
| 156 | |||
| 157 | for (fieldnum = 0; fieldnum < report->maxfield; ++fieldnum) { | ||
| 158 | struct hid_field *field = report->field[fieldnum]; | ||
| 159 | |||
| 160 | if (field->maxusage <= 0) | ||
| 161 | continue; | ||
| 162 | |||
| 163 | switch (field->usage[0].hid) { | ||
| 164 | case THRUSTMASTER_USAGE_FF: | ||
| 165 | if (field->report_count < 2) { | ||
| 166 | warn("ignoring FF field with report_count < 2"); | ||
| 167 | continue; | ||
| 168 | } | ||
| 169 | |||
| 170 | if (field->logical_maximum == field->logical_minimum) { | ||
| 171 | warn("ignoring FF field with logical_maximum == logical_minimum"); | ||
| 172 | continue; | ||
| 173 | } | ||
| 174 | |||
| 175 | if (tmff->report && tmff->report != report) { | ||
| 176 | warn("ignoring FF field in other report"); | ||
| 177 | continue; | ||
| 178 | } | ||
| 179 | |||
| 180 | if (tmff->ff_field && tmff->ff_field != field) { | ||
| 181 | warn("ignoring duplicate FF field"); | ||
| 182 | continue; | ||
| 183 | } | ||
| 184 | |||
| 185 | tmff->report = report; | ||
| 186 | tmff->ff_field = field; | ||
| 187 | |||
| 188 | for (i = 0; i < ARRAY_SIZE(devices); i++) { | ||
| 189 | if (input_dev->id.vendor == devices[i].idVendor && | ||
| 190 | input_dev->id.product == devices[i].idProduct) { | ||
| 191 | ff_bits = devices[i].ff; | ||
| 192 | break; | ||
| 193 | } | ||
| 194 | } | ||
| 195 | |||
| 196 | for (i = 0; ff_bits[i] >= 0; i++) | ||
| 197 | set_bit(ff_bits[i], input_dev->ffbit); | ||
| 198 | |||
| 199 | break; | ||
| 200 | |||
| 201 | default: | ||
| 202 | warn("ignoring unknown output usage %08x", field->usage[0].hid); | ||
| 203 | continue; | ||
| 204 | } | ||
| 205 | } | ||
| 206 | } | ||
| 207 | |||
| 208 | if (!tmff->report) { | ||
| 209 | err("cant find FF field in output reports\n"); | ||
| 210 | error = -ENODEV; | ||
| 211 | goto fail; | ||
| 212 | } | ||
| 213 | |||
| 214 | error = input_ff_create_memless(input_dev, tmff, hid_tmff_play); | ||
| 215 | if (error) | ||
| 216 | goto fail; | ||
| 217 | |||
| 218 | info("Force feedback for ThrustMaster devices by Zinx Verituse <zinx@epicsol.org>"); | ||
| 219 | return 0; | ||
| 220 | |||
| 221 | fail: | ||
| 222 | kfree(tmff); | ||
| 223 | return error; | ||
| 224 | } | ||
| 225 | |||
diff --git a/usr/src/dkms_source_tree/hid-zpff.c b/usr/src/dkms_source_tree/hid-zpff.c new file mode 100644 index 0000000..5a68827 --- /dev/null +++ b/usr/src/dkms_source_tree/hid-zpff.c | |||
| @@ -0,0 +1,107 @@ | |||
| 1 | /* | ||
| 2 | * Force feedback support for Zeroplus based devices | ||
| 3 | * | ||
| 4 | * Copyright (c) 2005, 2006 Anssi Hannula <anssi.hannula@gmail.com> | ||
| 5 | */ | ||
| 6 | |||
| 7 | /* | ||
| 8 | * This program is free software; you can redistribute it and/or modify | ||
| 9 | * it under the terms of the GNU General Public License as published by | ||
| 10 | * the Free Software Foundation; either version 2 of the License, or | ||
| 11 | * (at your option) any later version. | ||
| 12 | * | ||
| 13 | * This program is distributed in the hope that it will be useful, | ||
| 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 16 | * GNU General Public License for more details. | ||
| 17 | * | ||
| 18 | * You should have received a copy of the GNU General Public License | ||
| 19 | * along with this program; if not, write to the Free Software | ||
| 20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 21 | */ | ||
| 22 | |||
| 23 | |||
| 24 | #include <linux/input.h> | ||
| 25 | #include <linux/usb.h> | ||
| 26 | #include <linux/hid.h> | ||
| 27 | #include "usbhid.h" | ||
| 28 | |||
| 29 | struct zpff_device { | ||
| 30 | struct hid_report *report; | ||
| 31 | }; | ||
| 32 | |||
| 33 | static int hid_zpff_play(struct input_dev *dev, void *data, | ||
| 34 | struct ff_effect *effect) | ||
| 35 | { | ||
| 36 | struct hid_device *hid = input_get_drvdata(dev); | ||
| 37 | struct zpff_device *zpff = data; | ||
| 38 | int left, right; | ||
| 39 | |||
| 40 | /* | ||
| 41 | * The following is specified the other way around in the Zeroplus | ||
| 42 | * datasheet but the order below is correct for the XFX Executioner; | ||
| 43 | * however it is possible that the XFX Executioner is an exception | ||
| 44 | */ | ||
| 45 | |||
| 46 | left = effect->u.rumble.strong_magnitude; | ||
| 47 | right = effect->u.rumble.weak_magnitude; | ||
| 48 | dbg_hid("called with 0x%04x 0x%04x\n", left, right); | ||
| 49 | |||
| 50 | left = left * 0x7f / 0xffff; | ||
| 51 | right = right * 0x7f / 0xffff; | ||
| 52 | |||
| 53 | zpff->report->field[2]->value[0] = left; | ||
| 54 | zpff->report->field[3]->value[0] = right; | ||
| 55 | dbg_hid("running with 0x%02x 0x%02x\n", left, right); | ||
| 56 | usbhid_submit_report(hid, zpff->report, USB_DIR_OUT); | ||
| 57 | |||
| 58 | return 0; | ||
| 59 | } | ||
| 60 | |||
| 61 | int hid_zpff_init(struct hid_device *hid) | ||
| 62 | { | ||
| 63 | struct zpff_device *zpff; | ||
| 64 | struct hid_report *report; | ||
| 65 | struct hid_input *hidinput = list_entry(hid->inputs.next, | ||
| 66 | struct hid_input, list); | ||
| 67 | struct list_head *report_list = | ||
| 68 | &hid->report_enum[HID_OUTPUT_REPORT].report_list; | ||
| 69 | struct input_dev *dev = hidinput->input; | ||
| 70 | int error; | ||
| 71 | |||
| 72 | if (list_empty(report_list)) { | ||
| 73 | printk(KERN_ERR "hid-zpff: no output report found\n"); | ||
| 74 | return -ENODEV; | ||
| 75 | } | ||
| 76 | |||
| 77 | report = list_entry(report_list->next, struct hid_report, list); | ||
| 78 | |||
| 79 | if (report->maxfield < 4) { | ||
| 80 | printk(KERN_ERR "hid-zpff: not enough fields in report\n"); | ||
| 81 | return -ENODEV; | ||
| 82 | } | ||
| 83 | |||
| 84 | zpff = kzalloc(sizeof(struct zpff_device), GFP_KERNEL); | ||
| 85 | if (!zpff) | ||
| 86 | return -ENOMEM; | ||
| 87 | |||
| 88 | set_bit(FF_RUMBLE, dev->ffbit); | ||
| 89 | |||
| 90 | error = input_ff_create_memless(dev, zpff, hid_zpff_play); | ||
| 91 | if (error) { | ||
| 92 | kfree(zpff); | ||
| 93 | return error; | ||
| 94 | } | ||
| 95 | |||
| 96 | zpff->report = report; | ||
| 97 | zpff->report->field[0]->value[0] = 0x00; | ||
| 98 | zpff->report->field[1]->value[0] = 0x02; | ||
| 99 | zpff->report->field[2]->value[0] = 0x00; | ||
| 100 | zpff->report->field[3]->value[0] = 0x00; | ||
| 101 | usbhid_submit_report(hid, zpff->report, USB_DIR_OUT); | ||
| 102 | |||
| 103 | printk(KERN_INFO "Force feedback for Zeroplus based devices by " | ||
| 104 | "Anssi Hannula <anssi.hannula@gmail.com>\n"); | ||
| 105 | |||
| 106 | return 0; | ||
| 107 | } | ||
diff --git a/usr/src/dkms_source_tree/hiddev.c b/usr/src/dkms_source_tree/hiddev.c new file mode 100644 index 0000000..842e9ed --- /dev/null +++ b/usr/src/dkms_source_tree/hiddev.c | |||
| @@ -0,0 +1,893 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 2001 Paul Stewart | ||
| 3 | * Copyright (c) 2001 Vojtech Pavlik | ||
| 4 | * | ||
| 5 | * HID char devices, giving access to raw HID device events. | ||
| 6 | * | ||
| 7 | */ | ||
| 8 | |||
| 9 | /* | ||
| 10 | * This program is free software; you can redistribute it and/or modify | ||
| 11 | * it under the terms of the GNU General Public License as published by | ||
| 12 | * the Free Software Foundation; either version 2 of the License, or | ||
| 13 | * (at your option) any later version. | ||
| 14 | * | ||
| 15 | * This program is distributed in the hope that it will be useful, | ||
| 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 18 | * GNU General Public License for more details. | ||
| 19 | * | ||
| 20 | * You should have received a copy of the GNU General Public License | ||
| 21 | * along with this program; if not, write to the Free Software | ||
| 22 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 23 | * | ||
| 24 | * Should you need to contact me, the author, you can do so either by | ||
| 25 | * e-mail - mail your message to Paul Stewart <stewart@wetlogic.net> | ||
| 26 | */ | ||
| 27 | |||
| 28 | #include <linux/poll.h> | ||
| 29 | #include <linux/slab.h> | ||
| 30 | #include <linux/module.h> | ||
| 31 | #include <linux/init.h> | ||
| 32 | #include <linux/smp_lock.h> | ||
| 33 | #include <linux/input.h> | ||
| 34 | #include <linux/usb.h> | ||
| 35 | #include <linux/hid.h> | ||
| 36 | #include <linux/hiddev.h> | ||
| 37 | #include <linux/compat.h> | ||
| 38 | #include "usbhid.h" | ||
| 39 | |||
| 40 | #ifdef CONFIG_USB_DYNAMIC_MINORS | ||
| 41 | #define HIDDEV_MINOR_BASE 0 | ||
| 42 | #define HIDDEV_MINORS 256 | ||
| 43 | #else | ||
| 44 | #define HIDDEV_MINOR_BASE 96 | ||
| 45 | #define HIDDEV_MINORS 16 | ||
| 46 | #endif | ||
| 47 | #define HIDDEV_BUFFER_SIZE 64 | ||
| 48 | |||
| 49 | struct hiddev { | ||
| 50 | int exist; | ||
| 51 | int open; | ||
| 52 | wait_queue_head_t wait; | ||
| 53 | struct hid_device *hid; | ||
| 54 | struct list_head list; | ||
| 55 | spinlock_t list_lock; | ||
| 56 | }; | ||
| 57 | |||
| 58 | struct hiddev_list { | ||
| 59 | struct hiddev_usage_ref buffer[HIDDEV_BUFFER_SIZE]; | ||
| 60 | int head; | ||
| 61 | int tail; | ||
| 62 | unsigned flags; | ||
| 63 | struct fasync_struct *fasync; | ||
| 64 | struct hiddev *hiddev; | ||
| 65 | struct list_head node; | ||
| 66 | }; | ||
| 67 | |||
| 68 | static struct hiddev *hiddev_table[HIDDEV_MINORS]; | ||
| 69 | |||
| 70 | /* | ||
| 71 | * Find a report, given the report's type and ID. The ID can be specified | ||
| 72 | * indirectly by REPORT_ID_FIRST (which returns the first report of the given | ||
| 73 | * type) or by (REPORT_ID_NEXT | old_id), which returns the next report of the | ||
| 74 | * given type which follows old_id. | ||
| 75 | */ | ||
| 76 | static struct hid_report * | ||
| 77 | hiddev_lookup_report(struct hid_device *hid, struct hiddev_report_info *rinfo) | ||
| 78 | { | ||
| 79 | unsigned int flags = rinfo->report_id & ~HID_REPORT_ID_MASK; | ||
| 80 | unsigned int rid = rinfo->report_id & HID_REPORT_ID_MASK; | ||
| 81 | struct hid_report_enum *report_enum; | ||
| 82 | struct hid_report *report; | ||
| 83 | struct list_head *list; | ||
| 84 | |||
| 85 | if (rinfo->report_type < HID_REPORT_TYPE_MIN || | ||
| 86 | rinfo->report_type > HID_REPORT_TYPE_MAX) | ||
| 87 | return NULL; | ||
| 88 | |||
| 89 | report_enum = hid->report_enum + | ||
| 90 | (rinfo->report_type - HID_REPORT_TYPE_MIN); | ||
| 91 | |||
| 92 | switch (flags) { | ||
| 93 | case 0: /* Nothing to do -- report_id is already set correctly */ | ||
| 94 | break; | ||
| 95 | |||
| 96 | case HID_REPORT_ID_FIRST: | ||
| 97 | if (list_empty(&report_enum->report_list)) | ||
| 98 | return NULL; | ||
| 99 | |||
| 100 | list = report_enum->report_list.next; | ||
| 101 | report = list_entry(list, struct hid_report, list); | ||
| 102 | rinfo->report_id = report->id; | ||
| 103 | break; | ||
| 104 | |||
| 105 | case HID_REPORT_ID_NEXT: | ||
| 106 | report = report_enum->report_id_hash[rid]; | ||
| 107 | if (!report) | ||
| 108 | return NULL; | ||
| 109 | |||
| 110 | list = report->list.next; | ||
| 111 | if (list == &report_enum->report_list) | ||
| 112 | return NULL; | ||
| 113 | |||
| 114 | report = list_entry(list, struct hid_report, list); | ||
| 115 | rinfo->report_id = report->id; | ||
| 116 | break; | ||
| 117 | |||
| 118 | default: | ||
| 119 | return NULL; | ||
| 120 | } | ||
| 121 | |||
| 122 | return report_enum->report_id_hash[rinfo->report_id]; | ||
| 123 | } | ||
| 124 | |||
| 125 | /* | ||
| 126 | * Perform an exhaustive search of the report table for a usage, given its | ||
| 127 | * type and usage id. | ||
| 128 | */ | ||
| 129 | static struct hid_field * | ||
| 130 | hiddev_lookup_usage(struct hid_device *hid, struct hiddev_usage_ref *uref) | ||
| 131 | { | ||
| 132 | int i, j; | ||
| 133 | struct hid_report *report; | ||
| 134 | struct hid_report_enum *report_enum; | ||
| 135 | struct hid_field *field; | ||
| 136 | |||
| 137 | if (uref->report_type < HID_REPORT_TYPE_MIN || | ||
| 138 | uref->report_type > HID_REPORT_TYPE_MAX) | ||
| 139 | return NULL; | ||
| 140 | |||
| 141 | report_enum = hid->report_enum + | ||
| 142 | (uref->report_type - HID_REPORT_TYPE_MIN); | ||
| 143 | |||
| 144 | list_for_each_entry(report, &report_enum->report_list, list) { | ||
| 145 | for (i = 0; i < report->maxfield; i++) { | ||
| 146 | field = report->field[i]; | ||
| 147 | for (j = 0; j < field->maxusage; j++) { | ||
| 148 | if (field->usage[j].hid == uref->usage_code) { | ||
| 149 | uref->report_id = report->id; | ||
| 150 | uref->field_index = i; | ||
| 151 | uref->usage_index = j; | ||
| 152 | return field; | ||
| 153 | } | ||
| 154 | } | ||
| 155 | } | ||
| 156 | } | ||
| 157 | |||
| 158 | return NULL; | ||
| 159 | } | ||
| 160 | |||
| 161 | static void hiddev_send_event(struct hid_device *hid, | ||
| 162 | struct hiddev_usage_ref *uref) | ||
| 163 | { | ||
| 164 | struct hiddev *hiddev = hid->hiddev; | ||
| 165 | struct hiddev_list *list; | ||
| 166 | unsigned long flags; | ||
| 167 | |||
| 168 | spin_lock_irqsave(&hiddev->list_lock, flags); | ||
| 169 | list_for_each_entry(list, &hiddev->list, node) { | ||
| 170 | if (uref->field_index != HID_FIELD_INDEX_NONE || | ||
| 171 | (list->flags & HIDDEV_FLAG_REPORT) != 0) { | ||
| 172 | list->buffer[list->head] = *uref; | ||
| 173 | list->head = (list->head + 1) & | ||
| 174 | (HIDDEV_BUFFER_SIZE - 1); | ||
| 175 | kill_fasync(&list->fasync, SIGIO, POLL_IN); | ||
| 176 | } | ||
| 177 | } | ||
| 178 | spin_unlock_irqrestore(&hiddev->list_lock, flags); | ||
| 179 | |||
| 180 | wake_up_interruptible(&hiddev->wait); | ||
| 181 | } | ||
| 182 | |||
| 183 | /* | ||
| 184 | * This is where hid.c calls into hiddev to pass an event that occurred over | ||
| 185 | * the interrupt pipe | ||
| 186 | */ | ||
| 187 | void hiddev_hid_event(struct hid_device *hid, struct hid_field *field, | ||
| 188 | struct hid_usage *usage, __s32 value) | ||
| 189 | { | ||
| 190 | unsigned type = field->report_type; | ||
| 191 | struct hiddev_usage_ref uref; | ||
| 192 | |||
| 193 | uref.report_type = | ||
| 194 | (type == HID_INPUT_REPORT) ? HID_REPORT_TYPE_INPUT : | ||
| 195 | ((type == HID_OUTPUT_REPORT) ? HID_REPORT_TYPE_OUTPUT : | ||
| 196 | ((type == HID_FEATURE_REPORT) ? HID_REPORT_TYPE_FEATURE : 0)); | ||
| 197 | uref.report_id = field->report->id; | ||
| 198 | uref.field_index = field->index; | ||
| 199 | uref.usage_index = (usage - field->usage); | ||
| 200 | uref.usage_code = usage->hid; | ||
| 201 | uref.value = value; | ||
| 202 | |||
| 203 | hiddev_send_event(hid, &uref); | ||
| 204 | } | ||
| 205 | EXPORT_SYMBOL_GPL(hiddev_hid_event); | ||
| 206 | |||
| 207 | void hiddev_report_event(struct hid_device *hid, struct hid_report *report) | ||
| 208 | { | ||
| 209 | unsigned type = report->type; | ||
| 210 | struct hiddev_usage_ref uref; | ||
| 211 | |||
| 212 | memset(&uref, 0, sizeof(uref)); | ||
| 213 | uref.report_type = | ||
| 214 | (type == HID_INPUT_REPORT) ? HID_REPORT_TYPE_INPUT : | ||
| 215 | ((type == HID_OUTPUT_REPORT) ? HID_REPORT_TYPE_OUTPUT : | ||
| 216 | ((type == HID_FEATURE_REPORT) ? HID_REPORT_TYPE_FEATURE : 0)); | ||
| 217 | uref.report_id = report->id; | ||
| 218 | uref.field_index = HID_FIELD_INDEX_NONE; | ||
| 219 | |||
| 220 | hiddev_send_event(hid, &uref); | ||
| 221 | } | ||
| 222 | |||
| 223 | /* | ||
| 224 | * fasync file op | ||
| 225 | */ | ||
| 226 | static int hiddev_fasync(int fd, struct file *file, int on) | ||
| 227 | { | ||
| 228 | int retval; | ||
| 229 | struct hiddev_list *list = file->private_data; | ||
| 230 | |||
| 231 | retval = fasync_helper(fd, file, on, &list->fasync); | ||
| 232 | |||
| 233 | return retval < 0 ? retval : 0; | ||
| 234 | } | ||
| 235 | |||
| 236 | |||
| 237 | /* | ||
| 238 | * release file op | ||
| 239 | */ | ||
| 240 | static int hiddev_release(struct inode * inode, struct file * file) | ||
| 241 | { | ||
| 242 | struct hiddev_list *list = file->private_data; | ||
| 243 | unsigned long flags; | ||
| 244 | |||
| 245 | hiddev_fasync(-1, file, 0); | ||
| 246 | |||
| 247 | spin_lock_irqsave(&list->hiddev->list_lock, flags); | ||
| 248 | list_del(&list->node); | ||
| 249 | spin_unlock_irqrestore(&list->hiddev->list_lock, flags); | ||
| 250 | |||
| 251 | if (!--list->hiddev->open) { | ||
| 252 | if (list->hiddev->exist) | ||
| 253 | usbhid_close(list->hiddev->hid); | ||
| 254 | else | ||
| 255 | kfree(list->hiddev); | ||
| 256 | } | ||
| 257 | |||
| 258 | kfree(list); | ||
| 259 | |||
| 260 | return 0; | ||
| 261 | } | ||
| 262 | |||
| 263 | /* | ||
| 264 | * open file op | ||
| 265 | */ | ||
| 266 | static int hiddev_open(struct inode *inode, struct file *file) | ||
| 267 | { | ||
| 268 | struct hiddev_list *list; | ||
| 269 | unsigned long flags; | ||
| 270 | |||
| 271 | int i = iminor(inode) - HIDDEV_MINOR_BASE; | ||
| 272 | |||
| 273 | if (i >= HIDDEV_MINORS || !hiddev_table[i]) | ||
| 274 | return -ENODEV; | ||
| 275 | |||
| 276 | if (!(list = kzalloc(sizeof(struct hiddev_list), GFP_KERNEL))) | ||
| 277 | return -ENOMEM; | ||
| 278 | |||
| 279 | list->hiddev = hiddev_table[i]; | ||
| 280 | |||
| 281 | spin_lock_irqsave(&list->hiddev->list_lock, flags); | ||
| 282 | list_add_tail(&list->node, &hiddev_table[i]->list); | ||
| 283 | spin_unlock_irqrestore(&list->hiddev->list_lock, flags); | ||
| 284 | |||
| 285 | file->private_data = list; | ||
| 286 | |||
| 287 | if (!list->hiddev->open++) | ||
| 288 | if (list->hiddev->exist) | ||
| 289 | usbhid_open(hiddev_table[i]->hid); | ||
| 290 | |||
| 291 | return 0; | ||
| 292 | } | ||
| 293 | |||
| 294 | /* | ||
| 295 | * "write" file op | ||
| 296 | */ | ||
| 297 | static ssize_t hiddev_write(struct file * file, const char __user * buffer, size_t count, loff_t *ppos) | ||
| 298 | { | ||
| 299 | return -EINVAL; | ||
| 300 | } | ||
| 301 | |||
| 302 | /* | ||
| 303 | * "read" file op | ||
| 304 | */ | ||
| 305 | static ssize_t hiddev_read(struct file * file, char __user * buffer, size_t count, loff_t *ppos) | ||
| 306 | { | ||
| 307 | DECLARE_WAITQUEUE(wait, current); | ||
| 308 | struct hiddev_list *list = file->private_data; | ||
| 309 | int event_size; | ||
| 310 | int retval = 0; | ||
| 311 | |||
| 312 | event_size = ((list->flags & HIDDEV_FLAG_UREF) != 0) ? | ||
| 313 | sizeof(struct hiddev_usage_ref) : sizeof(struct hiddev_event); | ||
| 314 | |||
| 315 | if (count < event_size) | ||
| 316 | return 0; | ||
| 317 | |||
| 318 | while (retval == 0) { | ||
| 319 | if (list->head == list->tail) { | ||
| 320 | add_wait_queue(&list->hiddev->wait, &wait); | ||
| 321 | set_current_state(TASK_INTERRUPTIBLE); | ||
| 322 | |||
| 323 | while (list->head == list->tail) { | ||
| 324 | if (file->f_flags & O_NONBLOCK) { | ||
| 325 | retval = -EAGAIN; | ||
| 326 | break; | ||
| 327 | } | ||
| 328 | if (signal_pending(current)) { | ||
| 329 | retval = -ERESTARTSYS; | ||
| 330 | break; | ||
| 331 | } | ||
| 332 | if (!list->hiddev->exist) { | ||
| 333 | retval = -EIO; | ||
| 334 | break; | ||
| 335 | } | ||
| 336 | |||
| 337 | schedule(); | ||
| 338 | set_current_state(TASK_INTERRUPTIBLE); | ||
| 339 | } | ||
| 340 | |||
| 341 | set_current_state(TASK_RUNNING); | ||
| 342 | remove_wait_queue(&list->hiddev->wait, &wait); | ||
| 343 | } | ||
| 344 | |||
| 345 | if (retval) | ||
| 346 | return retval; | ||
| 347 | |||
| 348 | |||
| 349 | while (list->head != list->tail && | ||
| 350 | retval + event_size <= count) { | ||
| 351 | if ((list->flags & HIDDEV_FLAG_UREF) == 0) { | ||
| 352 | if (list->buffer[list->tail].field_index != | ||
| 353 | HID_FIELD_INDEX_NONE) { | ||
| 354 | struct hiddev_event event; | ||
| 355 | event.hid = list->buffer[list->tail].usage_code; | ||
| 356 | event.value = list->buffer[list->tail].value; | ||
| 357 | if (copy_to_user(buffer + retval, &event, sizeof(struct hiddev_event))) | ||
| 358 | return -EFAULT; | ||
| 359 | retval += sizeof(struct hiddev_event); | ||
| 360 | } | ||
| 361 | } else { | ||
| 362 | if (list->buffer[list->tail].field_index != HID_FIELD_INDEX_NONE || | ||
| 363 | (list->flags & HIDDEV_FLAG_REPORT) != 0) { | ||
| 364 | if (copy_to_user(buffer + retval, list->buffer + list->tail, sizeof(struct hiddev_usage_ref))) | ||
| 365 | return -EFAULT; | ||
| 366 | retval += sizeof(struct hiddev_usage_ref); | ||
| 367 | } | ||
| 368 | } | ||
| 369 | list->tail = (list->tail + 1) & (HIDDEV_BUFFER_SIZE - 1); | ||
| 370 | } | ||
| 371 | |||
| 372 | } | ||
| 373 | |||
| 374 | return retval; | ||
| 375 | } | ||
| 376 | |||
| 377 | /* | ||
| 378 | * "poll" file op | ||
| 379 | * No kernel lock - fine | ||
| 380 | */ | ||
| 381 | static unsigned int hiddev_poll(struct file *file, poll_table *wait) | ||
| 382 | { | ||
| 383 | struct hiddev_list *list = file->private_data; | ||
| 384 | |||
| 385 | poll_wait(file, &list->hiddev->wait, wait); | ||
| 386 | if (list->head != list->tail) | ||
| 387 | return POLLIN | POLLRDNORM; | ||
| 388 | if (!list->hiddev->exist) | ||
| 389 | return POLLERR | POLLHUP; | ||
| 390 | return 0; | ||
| 391 | } | ||
| 392 | |||
| 393 | /* | ||
| 394 | * "ioctl" file op | ||
| 395 | */ | ||
| 396 | static noinline int hiddev_ioctl_usage(struct hiddev *hiddev, unsigned int cmd, void __user *user_arg) | ||
| 397 | { | ||
| 398 | struct hid_device *hid = hiddev->hid; | ||
| 399 | struct hiddev_report_info rinfo; | ||
| 400 | struct hiddev_usage_ref_multi *uref_multi = NULL; | ||
| 401 | struct hiddev_usage_ref *uref; | ||
| 402 | struct hid_report *report; | ||
| 403 | struct hid_field *field; | ||
| 404 | int i; | ||
| 405 | |||
| 406 | uref_multi = kmalloc(sizeof(struct hiddev_usage_ref_multi), GFP_KERNEL); | ||
| 407 | if (!uref_multi) | ||
| 408 | return -ENOMEM; | ||
| 409 | lock_kernel(); | ||
| 410 | uref = &uref_multi->uref; | ||
| 411 | if (cmd == HIDIOCGUSAGES || cmd == HIDIOCSUSAGES) { | ||
| 412 | if (copy_from_user(uref_multi, user_arg, | ||
| 413 | sizeof(*uref_multi))) | ||
| 414 | goto fault; | ||
| 415 | } else { | ||
| 416 | if (copy_from_user(uref, user_arg, sizeof(*uref))) | ||
| 417 | goto fault; | ||
| 418 | } | ||
| 419 | |||
| 420 | switch (cmd) { | ||
| 421 | case HIDIOCGUCODE: | ||
| 422 | rinfo.report_type = uref->report_type; | ||
| 423 | rinfo.report_id = uref->report_id; | ||
| 424 | if ((report = hiddev_lookup_report(hid, &rinfo)) == NULL) | ||
| 425 | goto inval; | ||
| 426 | |||
| 427 | if (uref->field_index >= report->maxfield) | ||
| 428 | goto inval; | ||
| 429 | |||
| 430 | field = report->field[uref->field_index]; | ||
| 431 | if (uref->usage_index >= field->maxusage) | ||
| 432 | goto inval; | ||
| 433 | |||
| 434 | uref->usage_code = field->usage[uref->usage_index].hid; | ||
| 435 | |||
| 436 | if (copy_to_user(user_arg, uref, sizeof(*uref))) | ||
| 437 | goto fault; | ||
| 438 | |||
| 439 | kfree(uref_multi); | ||
| 440 | return 0; | ||
| 441 | |||
| 442 | default: | ||
| 443 | if (cmd != HIDIOCGUSAGE && | ||
| 444 | cmd != HIDIOCGUSAGES && | ||
| 445 | uref->report_type == HID_REPORT_TYPE_INPUT) | ||
| 446 | goto inval; | ||
| 447 | |||
| 448 | if (uref->report_id == HID_REPORT_ID_UNKNOWN) { | ||
| 449 | field = hiddev_lookup_usage(hid, uref); | ||
| 450 | if (field == NULL) | ||
| 451 | goto inval; | ||
| 452 | } else { | ||
| 453 | rinfo.report_type = uref->report_type; | ||
| 454 | rinfo.report_id = uref->report_id; | ||
| 455 | if ((report = hiddev_lookup_report(hid, &rinfo)) == NULL) | ||
| 456 | goto inval; | ||
| 457 | |||
| 458 | if (uref->field_index >= report->maxfield) | ||
| 459 | goto inval; | ||
| 460 | |||
| 461 | field = report->field[uref->field_index]; | ||
| 462 | |||
| 463 | if (cmd == HIDIOCGCOLLECTIONINDEX) { | ||
| 464 | if (uref->usage_index >= field->maxusage) | ||
| 465 | goto inval; | ||
| 466 | } else if (uref->usage_index >= field->report_count) | ||
| 467 | goto inval; | ||
| 468 | |||
| 469 | else if ((cmd == HIDIOCGUSAGES || cmd == HIDIOCSUSAGES) && | ||
| 470 | (uref_multi->num_values > HID_MAX_MULTI_USAGES || | ||
| 471 | uref->usage_index + uref_multi->num_values > field->report_count)) | ||
| 472 | goto inval; | ||
| 473 | } | ||
| 474 | |||
| 475 | switch (cmd) { | ||
| 476 | case HIDIOCGUSAGE: | ||
| 477 | uref->value = field->value[uref->usage_index]; | ||
| 478 | if (copy_to_user(user_arg, uref, sizeof(*uref))) | ||
| 479 | goto fault; | ||
| 480 | goto goodreturn; | ||
| 481 | |||
| 482 | case HIDIOCSUSAGE: | ||
| 483 | field->value[uref->usage_index] = uref->value; | ||
| 484 | goto goodreturn; | ||
| 485 | |||
| 486 | case HIDIOCGCOLLECTIONINDEX: | ||
| 487 | kfree(uref_multi); | ||
| 488 | return field->usage[uref->usage_index].collection_index; | ||
| 489 | case HIDIOCGUSAGES: | ||
| 490 | for (i = 0; i < uref_multi->num_values; i++) | ||
| 491 | uref_multi->values[i] = | ||
| 492 | field->value[uref->usage_index + i]; | ||
| 493 | if (copy_to_user(user_arg, uref_multi, | ||
| 494 | sizeof(*uref_multi))) | ||
| 495 | goto fault; | ||
| 496 | goto goodreturn; | ||
| 497 | case HIDIOCSUSAGES: | ||
| 498 | for (i = 0; i < uref_multi->num_values; i++) | ||
| 499 | field->value[uref->usage_index + i] = | ||
| 500 | uref_multi->values[i]; | ||
| 501 | goto goodreturn; | ||
| 502 | } | ||
| 503 | |||
| 504 | goodreturn: | ||
| 505 | unlock_kernel(); | ||
| 506 | kfree(uref_multi); | ||
| 507 | return 0; | ||
| 508 | fault: | ||
| 509 | unlock_kernel(); | ||
| 510 | kfree(uref_multi); | ||
| 511 | return -EFAULT; | ||
| 512 | inval: | ||
| 513 | unlock_kernel(); | ||
| 514 | kfree(uref_multi); | ||
| 515 | return -EINVAL; | ||
| 516 | } | ||
| 517 | } | ||
| 518 | |||
| 519 | static noinline int hiddev_ioctl_string(struct hiddev *hiddev, unsigned int cmd, void __user *user_arg) | ||
| 520 | { | ||
| 521 | struct hid_device *hid = hiddev->hid; | ||
| 522 | struct usb_device *dev = hid_to_usb_dev(hid); | ||
| 523 | int idx, len; | ||
| 524 | char *buf; | ||
| 525 | |||
| 526 | if (get_user(idx, (int __user *)user_arg)) | ||
| 527 | return -EFAULT; | ||
| 528 | |||
| 529 | if ((buf = kmalloc(HID_STRING_SIZE, GFP_KERNEL)) == NULL) | ||
| 530 | return -ENOMEM; | ||
| 531 | |||
| 532 | if ((len = usb_string(dev, idx, buf, HID_STRING_SIZE-1)) < 0) { | ||
| 533 | kfree(buf); | ||
| 534 | return -EINVAL; | ||
| 535 | } | ||
| 536 | |||
| 537 | if (copy_to_user(user_arg+sizeof(int), buf, len+1)) { | ||
| 538 | kfree(buf); | ||
| 539 | return -EFAULT; | ||
| 540 | } | ||
| 541 | |||
| 542 | kfree(buf); | ||
| 543 | |||
| 544 | return len; | ||
| 545 | } | ||
| 546 | |||
| 547 | static long hiddev_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | ||
| 548 | { | ||
| 549 | struct hiddev_list *list = file->private_data; | ||
| 550 | struct hiddev *hiddev = list->hiddev; | ||
| 551 | struct hid_device *hid = hiddev->hid; | ||
| 552 | struct usb_device *dev = hid_to_usb_dev(hid); | ||
| 553 | struct hiddev_collection_info cinfo; | ||
| 554 | struct hiddev_report_info rinfo; | ||
| 555 | struct hiddev_field_info finfo; | ||
| 556 | struct hiddev_devinfo dinfo; | ||
| 557 | struct hid_report *report; | ||
| 558 | struct hid_field *field; | ||
| 559 | struct usbhid_device *usbhid = hid->driver_data; | ||
| 560 | void __user *user_arg = (void __user *)arg; | ||
| 561 | int i; | ||
| 562 | |||
| 563 | /* Called without BKL by compat methods so no BKL taken */ | ||
| 564 | |||
| 565 | /* FIXME: Who or what stop this racing with a disconnect ?? */ | ||
| 566 | if (!hiddev->exist) | ||
| 567 | return -EIO; | ||
| 568 | |||
| 569 | switch (cmd) { | ||
| 570 | |||
| 571 | case HIDIOCGVERSION: | ||
| 572 | return put_user(HID_VERSION, (int __user *)arg); | ||
| 573 | |||
| 574 | case HIDIOCAPPLICATION: | ||
| 575 | if (arg < 0 || arg >= hid->maxapplication) | ||
| 576 | return -EINVAL; | ||
| 577 | |||
| 578 | for (i = 0; i < hid->maxcollection; i++) | ||
| 579 | if (hid->collection[i].type == | ||
| 580 | HID_COLLECTION_APPLICATION && arg-- == 0) | ||
| 581 | break; | ||
| 582 | |||
| 583 | if (i == hid->maxcollection) | ||
| 584 | return -EINVAL; | ||
| 585 | |||
| 586 | return hid->collection[i].usage; | ||
| 587 | |||
| 588 | case HIDIOCGDEVINFO: | ||
| 589 | dinfo.bustype = BUS_USB; | ||
| 590 | dinfo.busnum = dev->bus->busnum; | ||
| 591 | dinfo.devnum = dev->devnum; | ||
| 592 | dinfo.ifnum = usbhid->ifnum; | ||
| 593 | dinfo.vendor = le16_to_cpu(dev->descriptor.idVendor); | ||
| 594 | dinfo.product = le16_to_cpu(dev->descriptor.idProduct); | ||
| 595 | dinfo.version = le16_to_cpu(dev->descriptor.bcdDevice); | ||
| 596 | dinfo.num_applications = hid->maxapplication; | ||
| 597 | if (copy_to_user(user_arg, &dinfo, sizeof(dinfo))) | ||
| 598 | return -EFAULT; | ||
| 599 | |||
| 600 | return 0; | ||
| 601 | |||
| 602 | case HIDIOCGFLAG: | ||
| 603 | if (put_user(list->flags, (int __user *)arg)) | ||
| 604 | return -EFAULT; | ||
| 605 | |||
| 606 | return 0; | ||
| 607 | |||
| 608 | case HIDIOCSFLAG: | ||
| 609 | { | ||
| 610 | int newflags; | ||
| 611 | if (get_user(newflags, (int __user *)arg)) | ||
| 612 | return -EFAULT; | ||
| 613 | |||
| 614 | if ((newflags & ~HIDDEV_FLAGS) != 0 || | ||
| 615 | ((newflags & HIDDEV_FLAG_REPORT) != 0 && | ||
| 616 | (newflags & HIDDEV_FLAG_UREF) == 0)) | ||
| 617 | return -EINVAL; | ||
| 618 | |||
| 619 | list->flags = newflags; | ||
| 620 | |||
| 621 | return 0; | ||
| 622 | } | ||
| 623 | |||
| 624 | case HIDIOCGSTRING: | ||
| 625 | return hiddev_ioctl_string(hiddev, cmd, user_arg); | ||
| 626 | |||
| 627 | case HIDIOCINITREPORT: | ||
| 628 | usbhid_init_reports(hid); | ||
| 629 | |||
| 630 | return 0; | ||
| 631 | |||
| 632 | case HIDIOCGREPORT: | ||
| 633 | if (copy_from_user(&rinfo, user_arg, sizeof(rinfo))) | ||
| 634 | return -EFAULT; | ||
| 635 | |||
| 636 | if (rinfo.report_type == HID_REPORT_TYPE_OUTPUT) | ||
| 637 | return -EINVAL; | ||
| 638 | |||
| 639 | if ((report = hiddev_lookup_report(hid, &rinfo)) == NULL) | ||
| 640 | return -EINVAL; | ||
| 641 | |||
| 642 | usbhid_submit_report(hid, report, USB_DIR_IN); | ||
| 643 | usbhid_wait_io(hid); | ||
| 644 | |||
| 645 | return 0; | ||
| 646 | |||
| 647 | case HIDIOCSREPORT: | ||
| 648 | if (copy_from_user(&rinfo, user_arg, sizeof(rinfo))) | ||
| 649 | return -EFAULT; | ||
| 650 | |||
| 651 | if (rinfo.report_type == HID_REPORT_TYPE_INPUT) | ||
| 652 | return -EINVAL; | ||
| 653 | |||
| 654 | if ((report = hiddev_lookup_report(hid, &rinfo)) == NULL) | ||
| 655 | return -EINVAL; | ||
| 656 | |||
| 657 | usbhid_submit_report(hid, report, USB_DIR_OUT); | ||
| 658 | usbhid_wait_io(hid); | ||
| 659 | |||
| 660 | return 0; | ||
| 661 | |||
| 662 | case HIDIOCGREPORTINFO: | ||
| 663 | if (copy_from_user(&rinfo, user_arg, sizeof(rinfo))) | ||
| 664 | return -EFAULT; | ||
| 665 | |||
| 666 | if ((report = hiddev_lookup_report(hid, &rinfo)) == NULL) | ||
| 667 | return -EINVAL; | ||
| 668 | |||
| 669 | rinfo.num_fields = report->maxfield; | ||
| 670 | |||
| 671 | if (copy_to_user(user_arg, &rinfo, sizeof(rinfo))) | ||
| 672 | return -EFAULT; | ||
| 673 | |||
| 674 | return 0; | ||
| 675 | |||
| 676 | case HIDIOCGFIELDINFO: | ||
| 677 | if (copy_from_user(&finfo, user_arg, sizeof(finfo))) | ||
| 678 | return -EFAULT; | ||
| 679 | rinfo.report_type = finfo.report_type; | ||
| 680 | rinfo.report_id = finfo.report_id; | ||
| 681 | if ((report = hiddev_lookup_report(hid, &rinfo)) == NULL) | ||
| 682 | return -EINVAL; | ||
| 683 | |||
| 684 | if (finfo.field_index >= report->maxfield) | ||
| 685 | return -EINVAL; | ||
| 686 | |||
| 687 | field = report->field[finfo.field_index]; | ||
| 688 | memset(&finfo, 0, sizeof(finfo)); | ||
| 689 | finfo.report_type = rinfo.report_type; | ||
| 690 | finfo.report_id = rinfo.report_id; | ||
| 691 | finfo.field_index = field->report_count - 1; | ||
| 692 | finfo.maxusage = field->maxusage; | ||
| 693 | finfo.flags = field->flags; | ||
| 694 | finfo.physical = field->physical; | ||
| 695 | finfo.logical = field->logical; | ||
| 696 | finfo.application = field->application; | ||
| 697 | finfo.logical_minimum = field->logical_minimum; | ||
| 698 | finfo.logical_maximum = field->logical_maximum; | ||
| 699 | finfo.physical_minimum = field->physical_minimum; | ||
| 700 | finfo.physical_maximum = field->physical_maximum; | ||
| 701 | finfo.unit_exponent = field->unit_exponent; | ||
| 702 | finfo.unit = field->unit; | ||
| 703 | |||
| 704 | if (copy_to_user(user_arg, &finfo, sizeof(finfo))) | ||
| 705 | return -EFAULT; | ||
| 706 | |||
| 707 | return 0; | ||
| 708 | |||
| 709 | case HIDIOCGUCODE: | ||
| 710 | /* fall through */ | ||
| 711 | case HIDIOCGUSAGE: | ||
| 712 | case HIDIOCSUSAGE: | ||
| 713 | case HIDIOCGUSAGES: | ||
| 714 | case HIDIOCSUSAGES: | ||
| 715 | case HIDIOCGCOLLECTIONINDEX: | ||
| 716 | return hiddev_ioctl_usage(hiddev, cmd, user_arg); | ||
| 717 | |||
| 718 | case HIDIOCGCOLLECTIONINFO: | ||
| 719 | if (copy_from_user(&cinfo, user_arg, sizeof(cinfo))) | ||
| 720 | return -EFAULT; | ||
| 721 | |||
| 722 | if (cinfo.index >= hid->maxcollection) | ||
| 723 | return -EINVAL; | ||
| 724 | |||
| 725 | cinfo.type = hid->collection[cinfo.index].type; | ||
| 726 | cinfo.usage = hid->collection[cinfo.index].usage; | ||
| 727 | cinfo.level = hid->collection[cinfo.index].level; | ||
| 728 | |||
| 729 | if (copy_to_user(user_arg, &cinfo, sizeof(cinfo))) | ||
| 730 | return -EFAULT; | ||
| 731 | return 0; | ||
| 732 | |||
| 733 | default: | ||
| 734 | |||
| 735 | if (_IOC_TYPE(cmd) != 'H' || _IOC_DIR(cmd) != _IOC_READ) | ||
| 736 | return -EINVAL; | ||
| 737 | |||
| 738 | if (_IOC_NR(cmd) == _IOC_NR(HIDIOCGNAME(0))) { | ||
| 739 | int len; | ||
| 740 | if (!hid->name) | ||
| 741 | return 0; | ||
| 742 | len = strlen(hid->name) + 1; | ||
| 743 | if (len > _IOC_SIZE(cmd)) | ||
| 744 | len = _IOC_SIZE(cmd); | ||
| 745 | return copy_to_user(user_arg, hid->name, len) ? | ||
| 746 | -EFAULT : len; | ||
| 747 | } | ||
| 748 | |||
| 749 | if (_IOC_NR(cmd) == _IOC_NR(HIDIOCGPHYS(0))) { | ||
| 750 | int len; | ||
| 751 | if (!hid->phys) | ||
| 752 | return 0; | ||
| 753 | len = strlen(hid->phys) + 1; | ||
| 754 | if (len > _IOC_SIZE(cmd)) | ||
| 755 | len = _IOC_SIZE(cmd); | ||
| 756 | return copy_to_user(user_arg, hid->phys, len) ? | ||
| 757 | -EFAULT : len; | ||
| 758 | } | ||
| 759 | } | ||
| 760 | return -EINVAL; | ||
| 761 | } | ||
| 762 | |||
| 763 | #ifdef CONFIG_COMPAT | ||
| 764 | static long hiddev_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | ||
| 765 | { | ||
| 766 | return hiddev_ioctl(file, cmd, (unsigned long)compat_ptr(arg)); | ||
| 767 | } | ||
| 768 | #endif | ||
| 769 | |||
| 770 | static const struct file_operations hiddev_fops = { | ||
| 771 | .owner = THIS_MODULE, | ||
| 772 | .read = hiddev_read, | ||
| 773 | .write = hiddev_write, | ||
| 774 | .poll = hiddev_poll, | ||
| 775 | .open = hiddev_open, | ||
| 776 | .release = hiddev_release, | ||
| 777 | .unlocked_ioctl = hiddev_ioctl, | ||
| 778 | .fasync = hiddev_fasync, | ||
| 779 | #ifdef CONFIG_COMPAT | ||
| 780 | .compat_ioctl = hiddev_compat_ioctl, | ||
| 781 | #endif | ||
| 782 | }; | ||
| 783 | |||
| 784 | static struct usb_class_driver hiddev_class = { | ||
| 785 | .name = "hiddev%d", | ||
| 786 | .fops = &hiddev_fops, | ||
| 787 | .minor_base = HIDDEV_MINOR_BASE, | ||
| 788 | }; | ||
| 789 | |||
| 790 | /* | ||
| 791 | * This is where hid.c calls us to connect a hid device to the hiddev driver | ||
| 792 | */ | ||
| 793 | int hiddev_connect(struct hid_device *hid) | ||
| 794 | { | ||
| 795 | struct hiddev *hiddev; | ||
| 796 | struct usbhid_device *usbhid = hid->driver_data; | ||
| 797 | int i; | ||
| 798 | int retval; | ||
| 799 | |||
| 800 | for (i = 0; i < hid->maxcollection; i++) | ||
| 801 | if (hid->collection[i].type == | ||
| 802 | HID_COLLECTION_APPLICATION && | ||
| 803 | !IS_INPUT_APPLICATION(hid->collection[i].usage)) | ||
| 804 | break; | ||
| 805 | |||
| 806 | if (i == hid->maxcollection && (hid->quirks & HID_QUIRK_HIDDEV) == 0) | ||
| 807 | return -1; | ||
| 808 | |||
| 809 | if (!(hiddev = kzalloc(sizeof(struct hiddev), GFP_KERNEL))) | ||
| 810 | return -1; | ||
| 811 | |||
| 812 | retval = usb_register_dev(usbhid->intf, &hiddev_class); | ||
| 813 | if (retval) { | ||
| 814 | err_hid("Not able to get a minor for this device."); | ||
| 815 | kfree(hiddev); | ||
| 816 | return -1; | ||
| 817 | } | ||
| 818 | |||
| 819 | init_waitqueue_head(&hiddev->wait); | ||
| 820 | INIT_LIST_HEAD(&hiddev->list); | ||
| 821 | spin_lock_init(&hiddev->list_lock); | ||
| 822 | hiddev->hid = hid; | ||
| 823 | hiddev->exist = 1; | ||
| 824 | |||
| 825 | hid->minor = usbhid->intf->minor; | ||
| 826 | hid->hiddev = hiddev; | ||
| 827 | |||
| 828 | hiddev_table[usbhid->intf->minor - HIDDEV_MINOR_BASE] = hiddev; | ||
| 829 | |||
| 830 | return 0; | ||
| 831 | } | ||
| 832 | |||
| 833 | /* | ||
| 834 | * This is where hid.c calls us to disconnect a hiddev device from the | ||
| 835 | * corresponding hid device (usually because the usb device has disconnected) | ||
| 836 | */ | ||
| 837 | static struct usb_class_driver hiddev_class; | ||
| 838 | void hiddev_disconnect(struct hid_device *hid) | ||
| 839 | { | ||
| 840 | struct hiddev *hiddev = hid->hiddev; | ||
| 841 | struct usbhid_device *usbhid = hid->driver_data; | ||
| 842 | |||
| 843 | hiddev->exist = 0; | ||
| 844 | |||
| 845 | hiddev_table[hiddev->hid->minor - HIDDEV_MINOR_BASE] = NULL; | ||
| 846 | usb_deregister_dev(usbhid->intf, &hiddev_class); | ||
| 847 | |||
| 848 | if (hiddev->open) { | ||
| 849 | usbhid_close(hiddev->hid); | ||
| 850 | wake_up_interruptible(&hiddev->wait); | ||
| 851 | } else { | ||
| 852 | kfree(hiddev); | ||
| 853 | } | ||
| 854 | } | ||
| 855 | |||
| 856 | /* Currently this driver is a USB driver. It's not a conventional one in | ||
| 857 | * the sense that it doesn't probe at the USB level. Instead it waits to | ||
| 858 | * be connected by HID through the hiddev_connect / hiddev_disconnect | ||
| 859 | * routines. The reason to register as a USB device is to gain part of the | ||
| 860 | * minor number space from the USB major. | ||
| 861 | * | ||
| 862 | * In theory, should the HID code be generalized to more than one physical | ||
| 863 | * medium (say, IEEE 1384), this driver will probably need to register its | ||
| 864 | * own major number, and in doing so, no longer need to register with USB. | ||
| 865 | * At that point the probe routine and hiddev_driver struct below will no | ||
| 866 | * longer be useful. | ||
| 867 | */ | ||
| 868 | |||
| 869 | |||
| 870 | /* We never attach in this manner, and rely on HID to connect us. This | ||
| 871 | * is why there is no disconnect routine defined in the usb_driver either. | ||
| 872 | */ | ||
| 873 | static int hiddev_usbd_probe(struct usb_interface *intf, | ||
| 874 | const struct usb_device_id *hiddev_info) | ||
| 875 | { | ||
| 876 | return -ENODEV; | ||
| 877 | } | ||
| 878 | |||
| 879 | |||
| 880 | static /* const */ struct usb_driver hiddev_driver = { | ||
| 881 | .name = "hiddev", | ||
| 882 | .probe = hiddev_usbd_probe, | ||
| 883 | }; | ||
| 884 | |||
| 885 | int __init hiddev_init(void) | ||
| 886 | { | ||
| 887 | return usb_register(&hiddev_driver); | ||
| 888 | } | ||
| 889 | |||
| 890 | void hiddev_exit(void) | ||
| 891 | { | ||
| 892 | usb_deregister(&hiddev_driver); | ||
| 893 | } | ||
diff --git a/usr/src/dkms_source_tree/patches/10-ignore-trackpad-on-unibody-macbooks.patch b/usr/src/dkms_source_tree/patches/10-ignore-trackpad-on-unibody-macbooks.patch new file mode 100644 index 0000000..a527d1b --- /dev/null +++ b/usr/src/dkms_source_tree/patches/10-ignore-trackpad-on-unibody-macbooks.patch | |||
| @@ -0,0 +1,24 @@ | |||
| 1 | diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c | ||
| 2 | index b15f882..1c07576 100644 | ||
| 3 | --- a/drivers/hid/usbhid/hid-quirks.c | ||
| 4 | +++ b/drivers/hid/usbhid/hid-quirks.c | ||
| 5 | @@ -81,6 +81,9 @@ | ||
| 6 | #define USB_DEVICE_ID_APPLE_WELLSPRING2_ANSI 0x0230 | ||
| 7 | #define USB_DEVICE_ID_APPLE_WELLSPRING2_ISO 0x0231 | ||
| 8 | #define USB_DEVICE_ID_APPLE_WELLSPRING2_JIS 0x0232 | ||
| 9 | +#define USB_DEVICE_ID_APPLE_WELLSPRING3_ANSI 0x0236 | ||
| 10 | +#define USB_DEVICE_ID_APPLE_WELLSPRING3_ISO 0x0237 | ||
| 11 | +#define USB_DEVICE_ID_APPLE_WELLSPRING3_JIS 0x0238 | ||
| 12 | #define USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY 0x030a | ||
| 13 | #define USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY 0x030b | ||
| 14 | #define USB_DEVICE_ID_APPLE_IRCONTROL4 0x8242 | ||
| 15 | @@ -660,6 +663,9 @@ static const struct hid_blacklist { | ||
| 16 | { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING2_ANSI, HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE}, | ||
| 17 | { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING2_ISO, HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_APPLE_ISO_KEYBOARD | HID_QUIRK_IGNORE_MOUSE }, | ||
| 18 | { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING2_JIS, HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE }, | ||
| 19 | + { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING3_ANSI, HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE}, | ||
| 20 | + { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING3_ISO, HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_APPLE_ISO_KEYBOARD | HID_QUIRK_IGNORE_MOUSE }, | ||
| 21 | + { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING3_JIS, HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE }, | ||
| 22 | { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE }, | ||
| 23 | { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE }, | ||
| 24 | |||
diff --git a/usr/src/dkms_source_tree/usbhid.h b/usr/src/dkms_source_tree/usbhid.h new file mode 100644 index 0000000..62d2d7c --- /dev/null +++ b/usr/src/dkms_source_tree/usbhid.h | |||
| @@ -0,0 +1,88 @@ | |||
| 1 | #ifndef __USBHID_H | ||
| 2 | #define __USBHID_H | ||
| 3 | |||
| 4 | /* | ||
| 5 | * Copyright (c) 1999 Andreas Gal | ||
| 6 | * Copyright (c) 2000-2001 Vojtech Pavlik | ||
| 7 | * Copyright (c) 2006 Jiri Kosina | ||
| 8 | */ | ||
| 9 | |||
| 10 | /* | ||
| 11 | * This program is free software; you can redistribute it and/or modify | ||
| 12 | * it under the terms of the GNU General Public License as published by | ||
| 13 | * the Free Software Foundation; either version 2 of the License, or | ||
| 14 | * (at your option) any later version. | ||
| 15 | * | ||
| 16 | * This program is distributed in the hope that it will be useful, | ||
| 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 19 | * GNU General Public License for more details. | ||
| 20 | * | ||
| 21 | * You should have received a copy of the GNU General Public License | ||
| 22 | * along with this program; if not, write to the Free Software | ||
| 23 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 24 | * | ||
| 25 | */ | ||
| 26 | |||
| 27 | #include <linux/types.h> | ||
| 28 | #include <linux/slab.h> | ||
| 29 | #include <linux/list.h> | ||
| 30 | #include <linux/timer.h> | ||
| 31 | #include <linux/wait.h> | ||
| 32 | #include <linux/workqueue.h> | ||
| 33 | #include <linux/input.h> | ||
| 34 | |||
| 35 | /* API provided by hid-core.c for USB HID drivers */ | ||
| 36 | int usbhid_wait_io(struct hid_device* hid); | ||
| 37 | void usbhid_close(struct hid_device *hid); | ||
| 38 | int usbhid_open(struct hid_device *hid); | ||
| 39 | void usbhid_init_reports(struct hid_device *hid); | ||
| 40 | void usbhid_submit_report(struct hid_device *hid, struct hid_report *report, unsigned char dir); | ||
| 41 | |||
| 42 | /* | ||
| 43 | * USB-specific HID struct, to be pointed to | ||
| 44 | * from struct hid_device->driver_data | ||
| 45 | */ | ||
| 46 | |||
| 47 | struct usbhid_device { | ||
| 48 | struct hid_device *hid; /* pointer to corresponding HID dev */ | ||
| 49 | |||
| 50 | struct usb_interface *intf; /* USB interface */ | ||
| 51 | int ifnum; /* USB interface number */ | ||
| 52 | |||
| 53 | unsigned int bufsize; /* URB buffer size */ | ||
| 54 | |||
| 55 | struct urb *urbin; /* Input URB */ | ||
| 56 | char *inbuf; /* Input buffer */ | ||
| 57 | dma_addr_t inbuf_dma; /* Input buffer dma */ | ||
| 58 | spinlock_t inlock; /* Input fifo spinlock */ | ||
| 59 | |||
| 60 | struct urb *urbctrl; /* Control URB */ | ||
| 61 | struct usb_ctrlrequest *cr; /* Control request struct */ | ||
| 62 | dma_addr_t cr_dma; /* Control request struct dma */ | ||
| 63 | struct hid_control_fifo ctrl[HID_CONTROL_FIFO_SIZE]; /* Control fifo */ | ||
| 64 | unsigned char ctrlhead, ctrltail; /* Control fifo head & tail */ | ||
| 65 | char *ctrlbuf; /* Control buffer */ | ||
| 66 | dma_addr_t ctrlbuf_dma; /* Control buffer dma */ | ||
| 67 | spinlock_t ctrllock; /* Control fifo spinlock */ | ||
| 68 | |||
| 69 | struct urb *urbout; /* Output URB */ | ||
| 70 | struct hid_report *out[HID_CONTROL_FIFO_SIZE]; /* Output pipe fifo */ | ||
| 71 | unsigned char outhead, outtail; /* Output pipe fifo head & tail */ | ||
| 72 | char *outbuf; /* Output buffer */ | ||
| 73 | dma_addr_t outbuf_dma; /* Output buffer dma */ | ||
| 74 | spinlock_t outlock; /* Output fifo spinlock */ | ||
| 75 | |||
| 76 | unsigned long iofl; /* I/O flags (CTRL_RUNNING, OUT_RUNNING) */ | ||
| 77 | struct timer_list io_retry; /* Retry timer */ | ||
| 78 | unsigned long stop_retry; /* Time to give up, in jiffies */ | ||
| 79 | unsigned int retry_delay; /* Delay length in ms */ | ||
| 80 | struct work_struct reset_work; /* Task context for resets */ | ||
| 81 | wait_queue_head_t wait; /* For sleeping */ | ||
| 82 | }; | ||
| 83 | |||
| 84 | #define hid_to_usb_dev(hid_dev) \ | ||
| 85 | container_of(hid_dev->dev->parent, struct usb_device, dev) | ||
| 86 | |||
| 87 | #endif | ||
| 88 | |||
diff --git a/usr/src/dkms_source_tree/usbkbd.c b/usr/src/dkms_source_tree/usbkbd.c new file mode 100644 index 0000000..0caaafe --- /dev/null +++ b/usr/src/dkms_source_tree/usbkbd.c | |||
| @@ -0,0 +1,365 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 1999-2001 Vojtech Pavlik | ||
| 3 | * | ||
| 4 | * USB HIDBP Keyboard support | ||
| 5 | */ | ||
| 6 | |||
| 7 | /* | ||
| 8 | * This program is free software; you can redistribute it and/or modify | ||
| 9 | * it under the terms of the GNU General Public License as published by | ||
| 10 | * the Free Software Foundation; either version 2 of the License, or | ||
| 11 | * (at your option) any later version. | ||
| 12 | * | ||
| 13 | * This program is distributed in the hope that it will be useful, | ||
| 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 16 | * GNU General Public License for more details. | ||
| 17 | * | ||
| 18 | * You should have received a copy of the GNU General Public License | ||
| 19 | * along with this program; if not, write to the Free Software | ||
| 20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 21 | * | ||
| 22 | * Should you need to contact me, the author, you can do so either by | ||
| 23 | * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail: | ||
| 24 | * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic | ||
| 25 | */ | ||
| 26 | |||
| 27 | #include <linux/kernel.h> | ||
| 28 | #include <linux/slab.h> | ||
| 29 | #include <linux/module.h> | ||
| 30 | #include <linux/init.h> | ||
| 31 | #include <linux/usb/input.h> | ||
| 32 | #include <linux/hid.h> | ||
| 33 | |||
| 34 | /* | ||
| 35 | * Version Information | ||
| 36 | */ | ||
| 37 | #define DRIVER_VERSION "" | ||
| 38 | #define DRIVER_AUTHOR "Vojtech Pavlik <vojtech@ucw.cz>" | ||
| 39 | #define DRIVER_DESC "USB HID Boot Protocol keyboard driver" | ||
| 40 | #define DRIVER_LICENSE "GPL" | ||
| 41 | |||
| 42 | MODULE_AUTHOR(DRIVER_AUTHOR); | ||
| 43 | MODULE_DESCRIPTION(DRIVER_DESC); | ||
| 44 | MODULE_LICENSE(DRIVER_LICENSE); | ||
| 45 | |||
| 46 | static const unsigned char usb_kbd_keycode[256] = { | ||
| 47 | 0, 0, 0, 0, 30, 48, 46, 32, 18, 33, 34, 35, 23, 36, 37, 38, | ||
| 48 | 50, 49, 24, 25, 16, 19, 31, 20, 22, 47, 17, 45, 21, 44, 2, 3, | ||
| 49 | 4, 5, 6, 7, 8, 9, 10, 11, 28, 1, 14, 15, 57, 12, 13, 26, | ||
| 50 | 27, 43, 43, 39, 40, 41, 51, 52, 53, 58, 59, 60, 61, 62, 63, 64, | ||
| 51 | 65, 66, 67, 68, 87, 88, 99, 70,119,110,102,104,111,107,109,106, | ||
| 52 | 105,108,103, 69, 98, 55, 74, 78, 96, 79, 80, 81, 75, 76, 77, 71, | ||
| 53 | 72, 73, 82, 83, 86,127,116,117,183,184,185,186,187,188,189,190, | ||
| 54 | 191,192,193,194,134,138,130,132,128,129,131,137,133,135,136,113, | ||
| 55 | 115,114, 0, 0, 0,121, 0, 89, 93,124, 92, 94, 95, 0, 0, 0, | ||
| 56 | 122,123, 90, 91, 85, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | ||
| 57 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | ||
| 58 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | ||
| 59 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | ||
| 60 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | ||
| 61 | 29, 42, 56,125, 97, 54,100,126,164,166,165,163,161,115,114,113, | ||
| 62 | 150,158,159,128,136,177,178,176,142,152,173,140 | ||
| 63 | }; | ||
| 64 | |||
| 65 | struct usb_kbd { | ||
| 66 | struct input_dev *dev; | ||
| 67 | struct usb_device *usbdev; | ||
| 68 | unsigned char old[8]; | ||
| 69 | struct urb *irq, *led; | ||
| 70 | unsigned char newleds; | ||
| 71 | char name[128]; | ||
| 72 | char phys[64]; | ||
| 73 | |||
| 74 | unsigned char *new; | ||
| 75 | struct usb_ctrlrequest *cr; | ||
| 76 | unsigned char *leds; | ||
| 77 | dma_addr_t cr_dma; | ||
| 78 | dma_addr_t new_dma; | ||
| 79 | dma_addr_t leds_dma; | ||
| 80 | }; | ||
| 81 | |||
| 82 | static void usb_kbd_irq(struct urb *urb) | ||
| 83 | { | ||
| 84 | struct usb_kbd *kbd = urb->context; | ||
| 85 | int i; | ||
| 86 | |||
| 87 | switch (urb->status) { | ||
| 88 | case 0: /* success */ | ||
| 89 | break; | ||
| 90 | case -ECONNRESET: /* unlink */ | ||
| 91 | case -ENOENT: | ||
| 92 | case -ESHUTDOWN: | ||
| 93 | return; | ||
| 94 | /* -EPIPE: should clear the halt */ | ||
| 95 | default: /* error */ | ||
| 96 | goto resubmit; | ||
| 97 | } | ||
| 98 | |||
| 99 | for (i = 0; i < 8; i++) | ||
| 100 | input_report_key(kbd->dev, usb_kbd_keycode[i + 224], (kbd->new[0] >> i) & 1); | ||
| 101 | |||
| 102 | for (i = 2; i < 8; i++) { | ||
| 103 | |||
| 104 | if (kbd->old[i] > 3 && memscan(kbd->new + 2, kbd->old[i], 6) == kbd->new + 8) { | ||
| 105 | if (usb_kbd_keycode[kbd->old[i]]) | ||
| 106 | input_report_key(kbd->dev, usb_kbd_keycode[kbd->old[i]], 0); | ||
| 107 | else | ||
| 108 | info("Unknown key (scancode %#x) released.", kbd->old[i]); | ||
| 109 | } | ||
| 110 | |||
| 111 | if (kbd->new[i] > 3 && memscan(kbd->old + 2, kbd->new[i], 6) == kbd->old + 8) { | ||
| 112 | if (usb_kbd_keycode[kbd->new[i]]) | ||
| 113 | input_report_key(kbd->dev, usb_kbd_keycode[kbd->new[i]], 1); | ||
| 114 | else | ||
| 115 | info("Unknown key (scancode %#x) pressed.", kbd->new[i]); | ||
| 116 | } | ||
| 117 | } | ||
| 118 | |||
| 119 | input_sync(kbd->dev); | ||
| 120 | |||
| 121 | memcpy(kbd->old, kbd->new, 8); | ||
| 122 | |||
| 123 | resubmit: | ||
| 124 | i = usb_submit_urb (urb, GFP_ATOMIC); | ||
| 125 | if (i) | ||
| 126 | err_hid ("can't resubmit intr, %s-%s/input0, status %d", | ||
| 127 | kbd->usbdev->bus->bus_name, | ||
| 128 | kbd->usbdev->devpath, i); | ||
| 129 | } | ||
| 130 | |||
| 131 | static int usb_kbd_event(struct input_dev *dev, unsigned int type, | ||
| 132 | unsigned int code, int value) | ||
| 133 | { | ||
| 134 | struct usb_kbd *kbd = input_get_drvdata(dev); | ||
| 135 | |||
| 136 | if (type != EV_LED) | ||
| 137 | return -1; | ||
| 138 | |||
| 139 | kbd->newleds = (!!test_bit(LED_KANA, dev->led) << 3) | (!!test_bit(LED_COMPOSE, dev->led) << 3) | | ||
| 140 | (!!test_bit(LED_SCROLLL, dev->led) << 2) | (!!test_bit(LED_CAPSL, dev->led) << 1) | | ||
| 141 | (!!test_bit(LED_NUML, dev->led)); | ||
| 142 | |||
| 143 | if (kbd->led->status == -EINPROGRESS) | ||
| 144 | return 0; | ||
| 145 | |||
| 146 | if (*(kbd->leds) == kbd->newleds) | ||
| 147 | return 0; | ||
| 148 | |||
| 149 | *(kbd->leds) = kbd->newleds; | ||
| 150 | kbd->led->dev = kbd->usbdev; | ||
| 151 | if (usb_submit_urb(kbd->led, GFP_ATOMIC)) | ||
| 152 | err_hid("usb_submit_urb(leds) failed"); | ||
| 153 | |||
| 154 | return 0; | ||
| 155 | } | ||
| 156 | |||
| 157 | static void usb_kbd_led(struct urb *urb) | ||
| 158 | { | ||
| 159 | struct usb_kbd *kbd = urb->context; | ||
| 160 | |||
| 161 | if (urb->status) | ||
| 162 | warn("led urb status %d received", urb->status); | ||
| 163 | |||
| 164 | if (*(kbd->leds) == kbd->newleds) | ||
| 165 | return; | ||
| 166 | |||
| 167 | *(kbd->leds) = kbd->newleds; | ||
| 168 | kbd->led->dev = kbd->usbdev; | ||
| 169 | if (usb_submit_urb(kbd->led, GFP_ATOMIC)) | ||
| 170 | err_hid("usb_submit_urb(leds) failed"); | ||
| 171 | } | ||
| 172 | |||
| 173 | static int usb_kbd_open(struct input_dev *dev) | ||
| 174 | { | ||
| 175 | struct usb_kbd *kbd = input_get_drvdata(dev); | ||
| 176 | |||
| 177 | kbd->irq->dev = kbd->usbdev; | ||
| 178 | if (usb_submit_urb(kbd->irq, GFP_KERNEL)) | ||
| 179 | return -EIO; | ||
| 180 | |||
| 181 | return 0; | ||
| 182 | } | ||
| 183 | |||
| 184 | static void usb_kbd_close(struct input_dev *dev) | ||
| 185 | { | ||
| 186 | struct usb_kbd *kbd = input_get_drvdata(dev); | ||
| 187 | |||
| 188 | usb_kill_urb(kbd->irq); | ||
| 189 | } | ||
| 190 | |||
| 191 | static int usb_kbd_alloc_mem(struct usb_device *dev, struct usb_kbd *kbd) | ||
| 192 | { | ||
| 193 | if (!(kbd->irq = usb_alloc_urb(0, GFP_KERNEL))) | ||
| 194 | return -1; | ||
| 195 | if (!(kbd->led = usb_alloc_urb(0, GFP_KERNEL))) | ||
| 196 | return -1; | ||
| 197 | if (!(kbd->new = usb_buffer_alloc(dev, 8, GFP_ATOMIC, &kbd->new_dma))) | ||
| 198 | return -1; | ||
| 199 | if (!(kbd->cr = usb_buffer_alloc(dev, sizeof(struct usb_ctrlrequest), GFP_ATOMIC, &kbd->cr_dma))) | ||
| 200 | return -1; | ||
| 201 | if (!(kbd->leds = usb_buffer_alloc(dev, 1, GFP_ATOMIC, &kbd->leds_dma))) | ||
| 202 | return -1; | ||
| 203 | |||
| 204 | return 0; | ||
| 205 | } | ||
| 206 | |||
| 207 | static void usb_kbd_free_mem(struct usb_device *dev, struct usb_kbd *kbd) | ||
| 208 | { | ||
| 209 | usb_free_urb(kbd->irq); | ||
| 210 | usb_free_urb(kbd->led); | ||
| 211 | usb_buffer_free(dev, 8, kbd->new, kbd->new_dma); | ||
| 212 | usb_buffer_free(dev, sizeof(struct usb_ctrlrequest), kbd->cr, kbd->cr_dma); | ||
| 213 | usb_buffer_free(dev, 1, kbd->leds, kbd->leds_dma); | ||
| 214 | } | ||
| 215 | |||
| 216 | static int usb_kbd_probe(struct usb_interface *iface, | ||
| 217 | const struct usb_device_id *id) | ||
| 218 | { | ||
| 219 | struct usb_device *dev = interface_to_usbdev(iface); | ||
| 220 | struct usb_host_interface *interface; | ||
| 221 | struct usb_endpoint_descriptor *endpoint; | ||
| 222 | struct usb_kbd *kbd; | ||
| 223 | struct input_dev *input_dev; | ||
| 224 | int i, pipe, maxp; | ||
| 225 | int error = -ENOMEM; | ||
| 226 | |||
| 227 | interface = iface->cur_altsetting; | ||
| 228 | |||
| 229 | if (interface->desc.bNumEndpoints != 1) | ||
| 230 | return -ENODEV; | ||
| 231 | |||
| 232 | endpoint = &interface->endpoint[0].desc; | ||
| 233 | if (!usb_endpoint_is_int_in(endpoint)) | ||
| 234 | return -ENODEV; | ||
| 235 | |||
| 236 | pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress); | ||
| 237 | maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe)); | ||
| 238 | |||
| 239 | kbd = kzalloc(sizeof(struct usb_kbd), GFP_KERNEL); | ||
| 240 | input_dev = input_allocate_device(); | ||
| 241 | if (!kbd || !input_dev) | ||
| 242 | goto fail1; | ||
| 243 | |||
| 244 | if (usb_kbd_alloc_mem(dev, kbd)) | ||
| 245 | goto fail2; | ||
| 246 | |||
| 247 | kbd->usbdev = dev; | ||
| 248 | kbd->dev = input_dev; | ||
| 249 | |||
| 250 | if (dev->manufacturer) | ||
| 251 | strlcpy(kbd->name, dev->manufacturer, sizeof(kbd->name)); | ||
| 252 | |||
| 253 | if (dev->product) { | ||
| 254 | if (dev->manufacturer) | ||
| 255 | strlcat(kbd->name, " ", sizeof(kbd->name)); | ||
| 256 | strlcat(kbd->name, dev->product, sizeof(kbd->name)); | ||
| 257 | } | ||
| 258 | |||
| 259 | if (!strlen(kbd->name)) | ||
| 260 | snprintf(kbd->name, sizeof(kbd->name), | ||
| 261 | "USB HIDBP Keyboard %04x:%04x", | ||
| 262 | le16_to_cpu(dev->descriptor.idVendor), | ||
| 263 | le16_to_cpu(dev->descriptor.idProduct)); | ||
| 264 | |||
| 265 | usb_make_path(dev, kbd->phys, sizeof(kbd->phys)); | ||
| 266 | strlcpy(kbd->phys, "/input0", sizeof(kbd->phys)); | ||
| 267 | |||
| 268 | input_dev->name = kbd->name; | ||
| 269 | input_dev->phys = kbd->phys; | ||
| 270 | usb_to_input_id(dev, &input_dev->id); | ||
| 271 | input_dev->dev.parent = &iface->dev; | ||
| 272 | |||
| 273 | input_set_drvdata(input_dev, kbd); | ||
| 274 | |||
| 275 | input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_LED) | | ||
| 276 | BIT_MASK(EV_REP); | ||
| 277 | input_dev->ledbit[0] = BIT_MASK(LED_NUML) | BIT_MASK(LED_CAPSL) | | ||
| 278 | BIT_MASK(LED_SCROLLL) | BIT_MASK(LED_COMPOSE) | | ||
| 279 | BIT_MASK(LED_KANA); | ||
| 280 | |||
| 281 | for (i = 0; i < 255; i++) | ||
| 282 | set_bit(usb_kbd_keycode[i], input_dev->keybit); | ||
| 283 | clear_bit(0, input_dev->keybit); | ||
| 284 | |||
| 285 | input_dev->event = usb_kbd_event; | ||
| 286 | input_dev->open = usb_kbd_open; | ||
| 287 | input_dev->close = usb_kbd_close; | ||
| 288 | |||
| 289 | usb_fill_int_urb(kbd->irq, dev, pipe, | ||
| 290 | kbd->new, (maxp > 8 ? 8 : maxp), | ||
| 291 | usb_kbd_irq, kbd, endpoint->bInterval); | ||
| 292 | kbd->irq->transfer_dma = kbd->new_dma; | ||
| 293 | kbd->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; | ||
| 294 | |||
| 295 | kbd->cr->bRequestType = USB_TYPE_CLASS | USB_RECIP_INTERFACE; | ||
| 296 | kbd->cr->bRequest = 0x09; | ||
| 297 | kbd->cr->wValue = cpu_to_le16(0x200); | ||
| 298 | kbd->cr->wIndex = cpu_to_le16(interface->desc.bInterfaceNumber); | ||
| 299 | kbd->cr->wLength = cpu_to_le16(1); | ||
| 300 | |||
| 301 | usb_fill_control_urb(kbd->led, dev, usb_sndctrlpipe(dev, 0), | ||
| 302 | (void *) kbd->cr, kbd->leds, 1, | ||
| 303 | usb_kbd_led, kbd); | ||
| 304 | kbd->led->setup_dma = kbd->cr_dma; | ||
| 305 | kbd->led->transfer_dma = kbd->leds_dma; | ||
| 306 | kbd->led->transfer_flags |= (URB_NO_TRANSFER_DMA_MAP | URB_NO_SETUP_DMA_MAP); | ||
| 307 | |||
| 308 | error = input_register_device(kbd->dev); | ||
| 309 | if (error) | ||
| 310 | goto fail2; | ||
| 311 | |||
| 312 | usb_set_intfdata(iface, kbd); | ||
| 313 | return 0; | ||
| 314 | |||
| 315 | fail2: | ||
| 316 | usb_kbd_free_mem(dev, kbd); | ||
| 317 | fail1: | ||
| 318 | input_free_device(input_dev); | ||
| 319 | kfree(kbd); | ||
| 320 | return error; | ||
| 321 | } | ||
| 322 | |||
| 323 | static void usb_kbd_disconnect(struct usb_interface *intf) | ||
| 324 | { | ||
| 325 | struct usb_kbd *kbd = usb_get_intfdata (intf); | ||
| 326 | |||
| 327 | usb_set_intfdata(intf, NULL); | ||
| 328 | if (kbd) { | ||
| 329 | usb_kill_urb(kbd->irq); | ||
| 330 | input_unregister_device(kbd->dev); | ||
| 331 | usb_kbd_free_mem(interface_to_usbdev(intf), kbd); | ||
| 332 | kfree(kbd); | ||
| 333 | } | ||
| 334 | } | ||
| 335 | |||
| 336 | static struct usb_device_id usb_kbd_id_table [] = { | ||
| 337 | { USB_INTERFACE_INFO(USB_INTERFACE_CLASS_HID, USB_INTERFACE_SUBCLASS_BOOT, | ||
| 338 | USB_INTERFACE_PROTOCOL_KEYBOARD) }, | ||
| 339 | { } /* Terminating entry */ | ||
| 340 | }; | ||
| 341 | |||
| 342 | MODULE_DEVICE_TABLE (usb, usb_kbd_id_table); | ||
| 343 | |||
| 344 | static struct usb_driver usb_kbd_driver = { | ||
| 345 | .name = "usbkbd", | ||
| 346 | .probe = usb_kbd_probe, | ||
| 347 | .disconnect = usb_kbd_disconnect, | ||
| 348 | .id_table = usb_kbd_id_table, | ||
| 349 | }; | ||
| 350 | |||
| 351 | static int __init usb_kbd_init(void) | ||
| 352 | { | ||
| 353 | int result = usb_register(&usb_kbd_driver); | ||
| 354 | if (result == 0) | ||
| 355 | info(DRIVER_VERSION ":" DRIVER_DESC); | ||
| 356 | return result; | ||
| 357 | } | ||
| 358 | |||
| 359 | static void __exit usb_kbd_exit(void) | ||
| 360 | { | ||
| 361 | usb_deregister(&usb_kbd_driver); | ||
| 362 | } | ||
| 363 | |||
| 364 | module_init(usb_kbd_init); | ||
| 365 | module_exit(usb_kbd_exit); | ||
diff --git a/usr/src/dkms_source_tree/usbmouse.c b/usr/src/dkms_source_tree/usbmouse.c new file mode 100644 index 0000000..35689ef --- /dev/null +++ b/usr/src/dkms_source_tree/usbmouse.c | |||
| @@ -0,0 +1,253 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 1999-2001 Vojtech Pavlik | ||
| 3 | * | ||
| 4 | * USB HIDBP Mouse support | ||
| 5 | */ | ||
| 6 | |||
| 7 | /* | ||
| 8 | * This program is free software; you can redistribute it and/or modify | ||
| 9 | * it under the terms of the GNU General Public License as published by | ||
| 10 | * the Free Software Foundation; either version 2 of the License, or | ||
| 11 | * (at your option) any later version. | ||
| 12 | * | ||
| 13 | * This program is distributed in the hope that it will be useful, | ||
| 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 16 | * GNU General Public License for more details. | ||
| 17 | * | ||
| 18 | * You should have received a copy of the GNU General Public License | ||
| 19 | * along with this program; if not, write to the Free Software | ||
| 20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 21 | * | ||
| 22 | * Should you need to contact me, the author, you can do so either by | ||
| 23 | * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail: | ||
| 24 | * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic | ||
| 25 | */ | ||
| 26 | |||
| 27 | #include <linux/kernel.h> | ||
| 28 | #include <linux/slab.h> | ||
| 29 | #include <linux/module.h> | ||
| 30 | #include <linux/init.h> | ||
| 31 | #include <linux/usb/input.h> | ||
| 32 | #include <linux/hid.h> | ||
| 33 | |||
| 34 | /* | ||
| 35 | * Version Information | ||
| 36 | */ | ||
| 37 | #define DRIVER_VERSION "v1.6" | ||
| 38 | #define DRIVER_AUTHOR "Vojtech Pavlik <vojtech@ucw.cz>" | ||
| 39 | #define DRIVER_DESC "USB HID Boot Protocol mouse driver" | ||
| 40 | #define DRIVER_LICENSE "GPL" | ||
| 41 | |||
| 42 | MODULE_AUTHOR(DRIVER_AUTHOR); | ||
| 43 | MODULE_DESCRIPTION(DRIVER_DESC); | ||
| 44 | MODULE_LICENSE(DRIVER_LICENSE); | ||
| 45 | |||
| 46 | struct usb_mouse { | ||
| 47 | char name[128]; | ||
| 48 | char phys[64]; | ||
| 49 | struct usb_device *usbdev; | ||
| 50 | struct input_dev *dev; | ||
| 51 | struct urb *irq; | ||
| 52 | |||
| 53 | signed char *data; | ||
| 54 | dma_addr_t data_dma; | ||
| 55 | }; | ||
| 56 | |||
| 57 | static void usb_mouse_irq(struct urb *urb) | ||
| 58 | { | ||
| 59 | struct usb_mouse *mouse = urb->context; | ||
| 60 | signed char *data = mouse->data; | ||
| 61 | struct input_dev *dev = mouse->dev; | ||
| 62 | int status; | ||
| 63 | |||
| 64 | switch (urb->status) { | ||
| 65 | case 0: /* success */ | ||
| 66 | break; | ||
| 67 | case -ECONNRESET: /* unlink */ | ||
| 68 | case -ENOENT: | ||
| 69 | case -ESHUTDOWN: | ||
| 70 | return; | ||
| 71 | /* -EPIPE: should clear the halt */ | ||
| 72 | default: /* error */ | ||
| 73 | goto resubmit; | ||
| 74 | } | ||
| 75 | |||
| 76 | input_report_key(dev, BTN_LEFT, data[0] & 0x01); | ||
| 77 | input_report_key(dev, BTN_RIGHT, data[0] & 0x02); | ||
| 78 | input_report_key(dev, BTN_MIDDLE, data[0] & 0x04); | ||
| 79 | input_report_key(dev, BTN_SIDE, data[0] & 0x08); | ||
| 80 | input_report_key(dev, BTN_EXTRA, data[0] & 0x10); | ||
| 81 | |||
| 82 | input_report_rel(dev, REL_X, data[1]); | ||
| 83 | input_report_rel(dev, REL_Y, data[2]); | ||
| 84 | input_report_rel(dev, REL_WHEEL, data[3]); | ||
| 85 | |||
| 86 | input_sync(dev); | ||
| 87 | resubmit: | ||
| 88 | status = usb_submit_urb (urb, GFP_ATOMIC); | ||
| 89 | if (status) | ||
| 90 | err ("can't resubmit intr, %s-%s/input0, status %d", | ||
| 91 | mouse->usbdev->bus->bus_name, | ||
| 92 | mouse->usbdev->devpath, status); | ||
| 93 | } | ||
| 94 | |||
| 95 | static int usb_mouse_open(struct input_dev *dev) | ||
| 96 | { | ||
| 97 | struct usb_mouse *mouse = input_get_drvdata(dev); | ||
| 98 | |||
| 99 | mouse->irq->dev = mouse->usbdev; | ||
| 100 | if (usb_submit_urb(mouse->irq, GFP_KERNEL)) | ||
| 101 | return -EIO; | ||
| 102 | |||
| 103 | return 0; | ||
| 104 | } | ||
| 105 | |||
| 106 | static void usb_mouse_close(struct input_dev *dev) | ||
| 107 | { | ||
| 108 | struct usb_mouse *mouse = input_get_drvdata(dev); | ||
| 109 | |||
| 110 | usb_kill_urb(mouse->irq); | ||
| 111 | } | ||
| 112 | |||
| 113 | static int usb_mouse_probe(struct usb_interface *intf, const struct usb_device_id *id) | ||
| 114 | { | ||
| 115 | struct usb_device *dev = interface_to_usbdev(intf); | ||
| 116 | struct usb_host_interface *interface; | ||
| 117 | struct usb_endpoint_descriptor *endpoint; | ||
| 118 | struct usb_mouse *mouse; | ||
| 119 | struct input_dev *input_dev; | ||
| 120 | int pipe, maxp; | ||
| 121 | int error = -ENOMEM; | ||
| 122 | |||
| 123 | interface = intf->cur_altsetting; | ||
| 124 | |||
| 125 | if (interface->desc.bNumEndpoints != 1) | ||
| 126 | return -ENODEV; | ||
| 127 | |||
| 128 | endpoint = &interface->endpoint[0].desc; | ||
| 129 | if (!usb_endpoint_is_int_in(endpoint)) | ||
| 130 | return -ENODEV; | ||
| 131 | |||
| 132 | pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress); | ||
| 133 | maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe)); | ||
| 134 | |||
| 135 | mouse = kzalloc(sizeof(struct usb_mouse), GFP_KERNEL); | ||
| 136 | input_dev = input_allocate_device(); | ||
| 137 | if (!mouse || !input_dev) | ||
| 138 | goto fail1; | ||
| 139 | |||
| 140 | mouse->data = usb_buffer_alloc(dev, 8, GFP_ATOMIC, &mouse->data_dma); | ||
| 141 | if (!mouse->data) | ||
| 142 | goto fail1; | ||
| 143 | |||
| 144 | mouse->irq = usb_alloc_urb(0, GFP_KERNEL); | ||
| 145 | if (!mouse->irq) | ||
| 146 | goto fail2; | ||
| 147 | |||
| 148 | mouse->usbdev = dev; | ||
| 149 | mouse->dev = input_dev; | ||
| 150 | |||
| 151 | if (dev->manufacturer) | ||
| 152 | strlcpy(mouse->name, dev->manufacturer, sizeof(mouse->name)); | ||
| 153 | |||
| 154 | if (dev->product) { | ||
| 155 | if (dev->manufacturer) | ||
| 156 | strlcat(mouse->name, " ", sizeof(mouse->name)); | ||
| 157 | strlcat(mouse->name, dev->product, sizeof(mouse->name)); | ||
| 158 | } | ||
| 159 | |||
| 160 | if (!strlen(mouse->name)) | ||
| 161 | snprintf(mouse->name, sizeof(mouse->name), | ||
| 162 | "USB HIDBP Mouse %04x:%04x", | ||
| 163 | le16_to_cpu(dev->descriptor.idVendor), | ||
| 164 | le16_to_cpu(dev->descriptor.idProduct)); | ||
| 165 | |||
| 166 | usb_make_path(dev, mouse->phys, sizeof(mouse->phys)); | ||
| 167 | strlcat(mouse->phys, "/input0", sizeof(mouse->phys)); | ||
| 168 | |||
| 169 | input_dev->name = mouse->name; | ||
| 170 | input_dev->phys = mouse->phys; | ||
| 171 | usb_to_input_id(dev, &input_dev->id); | ||
| 172 | input_dev->dev.parent = &intf->dev; | ||
| 173 | |||
| 174 | input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL); | ||
| 175 | input_dev->keybit[BIT_WORD(BTN_MOUSE)] = BIT_MASK(BTN_LEFT) | | ||
| 176 | BIT_MASK(BTN_RIGHT) | BIT_MASK(BTN_MIDDLE); | ||
| 177 | input_dev->relbit[0] = BIT_MASK(REL_X) | BIT_MASK(REL_Y); | ||
| 178 | input_dev->keybit[BIT_WORD(BTN_MOUSE)] |= BIT_MASK(BTN_SIDE) | | ||
| 179 | BIT_MASK(BTN_EXTRA); | ||
| 180 | input_dev->relbit[0] |= BIT_MASK(REL_WHEEL); | ||
| 181 | |||
| 182 | input_set_drvdata(input_dev, mouse); | ||
| 183 | |||
| 184 | input_dev->open = usb_mouse_open; | ||
| 185 | input_dev->close = usb_mouse_close; | ||
| 186 | |||
| 187 | usb_fill_int_urb(mouse->irq, dev, pipe, mouse->data, | ||
| 188 | (maxp > 8 ? 8 : maxp), | ||
| 189 | usb_mouse_irq, mouse, endpoint->bInterval); | ||
| 190 | mouse->irq->transfer_dma = mouse->data_dma; | ||
| 191 | mouse->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; | ||
| 192 | |||
| 193 | error = input_register_device(mouse->dev); | ||
| 194 | if (error) | ||
| 195 | goto fail3; | ||
| 196 | |||
| 197 | usb_set_intfdata(intf, mouse); | ||
| 198 | return 0; | ||
| 199 | |||
| 200 | fail3: | ||
| 201 | usb_free_urb(mouse->irq); | ||
| 202 | fail2: | ||
| 203 | usb_buffer_free(dev, 8, mouse->data, mouse->data_dma); | ||
| 204 | fail1: | ||
| 205 | input_free_device(input_dev); | ||
| 206 | kfree(mouse); | ||
| 207 | return error; | ||
| 208 | } | ||
| 209 | |||
| 210 | static void usb_mouse_disconnect(struct usb_interface *intf) | ||
| 211 | { | ||
| 212 | struct usb_mouse *mouse = usb_get_intfdata (intf); | ||
| 213 | |||
| 214 | usb_set_intfdata(intf, NULL); | ||
| 215 | if (mouse) { | ||
| 216 | usb_kill_urb(mouse->irq); | ||
| 217 | input_unregister_device(mouse->dev); | ||
| 218 | usb_free_urb(mouse->irq); | ||
| 219 | usb_buffer_free(interface_to_usbdev(intf), 8, mouse->data, mouse->data_dma); | ||
| 220 | kfree(mouse); | ||
| 221 | } | ||
| 222 | } | ||
| 223 | |||
| 224 | static struct usb_device_id usb_mouse_id_table [] = { | ||
| 225 | { USB_INTERFACE_INFO(USB_INTERFACE_CLASS_HID, USB_INTERFACE_SUBCLASS_BOOT, | ||
| 226 | USB_INTERFACE_PROTOCOL_MOUSE) }, | ||
| 227 | { } /* Terminating entry */ | ||
| 228 | }; | ||
| 229 | |||
| 230 | MODULE_DEVICE_TABLE (usb, usb_mouse_id_table); | ||
| 231 | |||
| 232 | static struct usb_driver usb_mouse_driver = { | ||
| 233 | .name = "usbmouse", | ||
| 234 | .probe = usb_mouse_probe, | ||
| 235 | .disconnect = usb_mouse_disconnect, | ||
| 236 | .id_table = usb_mouse_id_table, | ||
| 237 | }; | ||
| 238 | |||
| 239 | static int __init usb_mouse_init(void) | ||
| 240 | { | ||
| 241 | int retval = usb_register(&usb_mouse_driver); | ||
| 242 | if (retval == 0) | ||
| 243 | info(DRIVER_VERSION ":" DRIVER_DESC); | ||
| 244 | return retval; | ||
| 245 | } | ||
| 246 | |||
| 247 | static void __exit usb_mouse_exit(void) | ||
| 248 | { | ||
| 249 | usb_deregister(&usb_mouse_driver); | ||
| 250 | } | ||
| 251 | |||
| 252 | module_init(usb_mouse_init); | ||
| 253 | module_exit(usb_mouse_exit); | ||
