USB HID: move usbhid code from drivers/usb/input to drivers/hid/usbhid
authorJiri Kosina <jkosina@suse.cz>
Thu, 8 Mar 2007 15:47:49 +0000 (16:47 +0100)
committerJiri Kosina <jkosina@suse.cz>
Wed, 11 Apr 2007 08:36:02 +0000 (10:36 +0200)
Separate usbhid code into dedicated drivers/hid/usbhid directory as
discussed previously with Greg, so that it eases maintaineance process.

Signed-off-by: Jiri Kosina <jkosina@suse.cz>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
29 files changed:
drivers/hid/Kconfig
drivers/hid/Makefile
drivers/hid/usbhid/Kconfig [new file with mode: 0644]
drivers/hid/usbhid/Makefile [new file with mode: 0644]
drivers/hid/usbhid/hid-core.c [new file with mode: 0644]
drivers/hid/usbhid/hid-ff.c [new file with mode: 0644]
drivers/hid/usbhid/hid-lgff.c [new file with mode: 0644]
drivers/hid/usbhid/hid-pidff.c [new file with mode: 0644]
drivers/hid/usbhid/hid-plff.c [new file with mode: 0644]
drivers/hid/usbhid/hid-tmff.c [new file with mode: 0644]
drivers/hid/usbhid/hid-zpff.c [new file with mode: 0644]
drivers/hid/usbhid/hiddev.c [new file with mode: 0644]
drivers/hid/usbhid/usbhid.h [new file with mode: 0644]
drivers/hid/usbhid/usbkbd.c [new file with mode: 0644]
drivers/hid/usbhid/usbmouse.c [new file with mode: 0644]
drivers/usb/Makefile
drivers/usb/input/Kconfig
drivers/usb/input/Makefile
drivers/usb/input/hid-core.c [deleted file]
drivers/usb/input/hid-ff.c [deleted file]
drivers/usb/input/hid-lgff.c [deleted file]
drivers/usb/input/hid-pidff.c [deleted file]
drivers/usb/input/hid-plff.c [deleted file]
drivers/usb/input/hid-tmff.c [deleted file]
drivers/usb/input/hid-zpff.c [deleted file]
drivers/usb/input/hiddev.c [deleted file]
drivers/usb/input/usbhid.h [deleted file]
drivers/usb/input/usbkbd.c [deleted file]
drivers/usb/input/usbmouse.c [deleted file]

index 850788f4dd2ee789d3cdd5cd9e08313d6620773d..8fbe9fdac128ea232099499729f80693b3aa0acf 100644 (file)
@@ -36,5 +36,7 @@ config HID_DEBUG
 
        If unsure, say N
 
+source "drivers/hid/usbhid/Kconfig"
+
 endmenu
 
index 52e97d8f3c95770427a7475c4efa64661bf38fc6..68d1376a53fbe3b80da6cde1f0089c4e664261db 100644 (file)
@@ -6,3 +6,7 @@ hid-objs                        := hid-core.o hid-input.o
 obj-$(CONFIG_HID)              += hid.o
 hid-$(CONFIG_HID_DEBUG)                += hid-debug.o
 
+obj-$(CONFIG_USB_HID)          += usbhid/
+obj-$(CONFIG_USB_MOUSE)                += usbhid/
+obj-$(CONFIG_USB_KBD)          += usbhid/
+
diff --git a/drivers/hid/usbhid/Kconfig b/drivers/hid/usbhid/Kconfig
new file mode 100644 (file)
index 0000000..7c87bdc
--- /dev/null
@@ -0,0 +1,149 @@
+comment "USB Input Devices"
+       depends on USB
+
+config USB_HID
+       tristate "USB Human Interface Device (full HID) support"
+       default y
+       depends on USB && INPUT
+       select HID
+       ---help---
+         Say Y here if you want full HID support to connect USB keyboards,
+         mice, joysticks, graphic tablets, or any other HID based devices
+         to your computer via USB, as well as Uninterruptible Power Supply
+         (UPS) and monitor control devices.
+
+         You can't use this driver and the HIDBP (Boot Protocol) keyboard
+         and mouse drivers at the same time. More information is available:
+         <file:Documentation/input/input.txt>.
+
+         If unsure, say Y.
+
+         To compile this driver as a module, choose M here: the
+         module will be called usbhid.
+
+comment "Input core support is needed for USB HID input layer or HIDBP support"
+       depends on USB_HID && INPUT=n
+
+config USB_HIDINPUT_POWERBOOK
+       bool "Enable support for iBook/PowerBook special keys"
+       default n
+       depends on USB_HID
+       help
+         Say Y here if you want support for the special keys (Fn, Numlock) on
+         Apple iBooks and PowerBooks.
+
+         If unsure, say N.
+
+config HID_FF
+       bool "Force feedback support (EXPERIMENTAL)"
+       depends on USB_HID && EXPERIMENTAL
+       help
+         Say Y here is you want force feedback support for a few HID devices.
+         See below for a list of supported devices.
+
+         See <file:Documentation/input/ff.txt> for a description of the force
+         feedback API.
+
+         If unsure, say N.
+
+config HID_PID
+       bool "PID device support"
+       depends on HID_FF
+       help
+         Say Y here if you have a PID-compliant device and wish to enable force
+         feedback for it. Microsoft Sidewinder Force Feedback 2 is one of such
+         devices.
+
+config LOGITECH_FF
+       bool "Logitech devices support"
+       depends on HID_FF
+       select INPUT_FF_MEMLESS if USB_HID
+       help
+         Say Y here if you have one of these devices:
+         - Logitech WingMan Cordless RumblePad
+         - Logitech WingMan Cordless RumblePad 2
+         - Logitech WingMan Force 3D
+         - Logitech Formula Force EX
+         - Logitech MOMO Force wheel
+
+         and if you want to enable force feedback for them.
+         Note: if you say N here, this device will still be supported, but without
+         force feedback.
+
+config PANTHERLORD_FF
+       bool "PantherLord USB/PS2 2in1 Adapter support"
+       depends on HID_FF
+       select INPUT_FF_MEMLESS if USB_HID
+       help
+         Say Y here if you have a PantherLord USB/PS2 2in1 Adapter and want
+         to enable force feedback support for it.
+
+config THRUSTMASTER_FF
+       bool "ThrustMaster FireStorm Dual Power 2 support (EXPERIMENTAL)"
+       depends on HID_FF && EXPERIMENTAL
+       select INPUT_FF_MEMLESS if USB_HID
+       help
+         Say Y here if you have a THRUSTMASTER FireStore Dual Power 2,
+         and want to enable force feedback support for it.
+         Note: if you say N here, this device will still be supported, but without
+         force feedback.
+
+config ZEROPLUS_FF
+       bool "Zeroplus based game controller support"
+       depends on HID_FF
+       select INPUT_FF_MEMLESS if USB_HID
+       help
+         Say Y here if you have a Zeroplus based game controller and want to
+         enable force feedback for it.
+
+config USB_HIDDEV
+       bool "/dev/hiddev raw HID device support"
+       depends on USB_HID
+       help
+         Say Y here if you want to support HID devices (from the USB
+         specification standpoint) that aren't strictly user interface
+         devices, like monitor controls and Uninterruptable Power Supplies.
+
+         This module supports these devices separately using a separate
+         event interface on /dev/usb/hiddevX (char 180:96 to 180:111).
+
+         If unsure, say Y.
+
+menu "USB HID Boot Protocol drivers"
+       depends on USB!=n && USB_HID!=y
+
+config USB_KBD
+       tristate "USB HIDBP Keyboard (simple Boot) support"
+       depends on USB && INPUT
+       ---help---
+         Say Y here only if you are absolutely sure that you don't want
+         to use the generic HID driver for your USB keyboard and prefer
+         to use the keyboard in its limited Boot Protocol mode instead.
+
+         This is almost certainly not what you want.  This is mostly
+         useful for embedded applications or simple keyboards.
+
+         To compile this driver as a module, choose M here: the
+         module will be called usbkbd.
+
+         If even remotely unsure, say N.
+
+config USB_MOUSE
+       tristate "USB HIDBP Mouse (simple Boot) support"
+       depends on USB && INPUT
+       ---help---
+         Say Y here only if you are absolutely sure that you don't want
+         to use the generic HID driver for your USB mouse and prefer
+         to use the mouse in its limited Boot Protocol mode instead.
+
+         This is almost certainly not what you want.  This is mostly
+         useful for embedded applications or simple mice.
+
+         To compile this driver as a module, choose M here: the
+         module will be called usbmouse.
+
+         If even remotely unsure, say N.
+
+endmenu
+
+
diff --git a/drivers/hid/usbhid/Makefile b/drivers/hid/usbhid/Makefile
new file mode 100644 (file)
index 0000000..de9bc1f
--- /dev/null
@@ -0,0 +1,35 @@
+#
+# Makefile for the USB input drivers
+#
+
+# Multipart objects.
+usbhid-objs    := hid-core.o
+
+# Optional parts of multipart objects.
+
+ifeq ($(CONFIG_USB_HIDDEV),y)
+       usbhid-objs     += hiddev.o
+endif
+ifeq ($(CONFIG_HID_PID),y)
+       usbhid-objs     += hid-pidff.o
+endif
+ifeq ($(CONFIG_LOGITECH_FF),y)
+       usbhid-objs     += hid-lgff.o
+endif
+ifeq ($(CONFIG_PANTHERLORD_FF),y)
+       usbhid-objs     += hid-plff.o
+endif
+ifeq ($(CONFIG_THRUSTMASTER_FF),y)
+       usbhid-objs     += hid-tmff.o
+endif
+ifeq ($(CONFIG_ZEROPLUS_FF),y)
+       usbhid-objs     += hid-zpff.o
+endif
+ifeq ($(CONFIG_HID_FF),y)
+       usbhid-objs     += hid-ff.o
+endif
+
+obj-$(CONFIG_USB_HID)          += usbhid.o
+obj-$(CONFIG_USB_KBD)          += usbkbd.o
+obj-$(CONFIG_USB_MOUSE)                += usbmouse.o
+
diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c
new file mode 100644 (file)
index 0000000..827a75a
--- /dev/null
@@ -0,0 +1,1477 @@
+/*
+ *  USB HID support for Linux
+ *
+ *  Copyright (c) 1999 Andreas Gal
+ *  Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz>
+ *  Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc
+ *  Copyright (c) 2006-2007 Jiri Kosina
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/mm.h>
+#include <linux/smp_lock.h>
+#include <linux/spinlock.h>
+#include <asm/unaligned.h>
+#include <asm/byteorder.h>
+#include <linux/input.h>
+#include <linux/wait.h>
+
+#include <linux/usb.h>
+
+#include <linux/hid.h>
+#include <linux/hiddev.h>
+#include <linux/hid-debug.h>
+#include "usbhid.h"
+
+/*
+ * Version Information
+ */
+
+#define DRIVER_VERSION "v2.6"
+#define DRIVER_AUTHOR "Andreas Gal, Vojtech Pavlik"
+#define DRIVER_DESC "USB HID core driver"
+#define DRIVER_LICENSE "GPL"
+
+static char *hid_types[] = {"Device", "Pointer", "Mouse", "Device", "Joystick",
+                               "Gamepad", "Keyboard", "Keypad", "Multi-Axis Controller"};
+/*
+ * Module parameters.
+ */
+
+static unsigned int hid_mousepoll_interval;
+module_param_named(mousepoll, hid_mousepoll_interval, uint, 0644);
+MODULE_PARM_DESC(mousepoll, "Polling interval of mice");
+
+/*
+ * Input submission and I/O error handler.
+ */
+
+static void hid_io_error(struct hid_device *hid);
+
+/* Start up the input URB */
+static int hid_start_in(struct hid_device *hid)
+{
+       unsigned long flags;
+       int rc = 0;
+       struct usbhid_device *usbhid = hid->driver_data;
+
+       spin_lock_irqsave(&usbhid->inlock, flags);
+       if (hid->open > 0 && !test_bit(HID_SUSPENDED, &usbhid->iofl) &&
+                       !test_and_set_bit(HID_IN_RUNNING, &usbhid->iofl)) {
+               rc = usb_submit_urb(usbhid->urbin, GFP_ATOMIC);
+               if (rc != 0)
+                       clear_bit(HID_IN_RUNNING, &usbhid->iofl);
+       }
+       spin_unlock_irqrestore(&usbhid->inlock, flags);
+       return rc;
+}
+
+/* I/O retry timer routine */
+static void hid_retry_timeout(unsigned long _hid)
+{
+       struct hid_device *hid = (struct hid_device *) _hid;
+       struct usbhid_device *usbhid = hid->driver_data;
+
+       dev_dbg(&usbhid->intf->dev, "retrying intr urb\n");
+       if (hid_start_in(hid))
+               hid_io_error(hid);
+}
+
+/* Workqueue routine to reset the device or clear a halt */
+static void hid_reset(struct work_struct *work)
+{
+       struct usbhid_device *usbhid =
+               container_of(work, struct usbhid_device, reset_work);
+       struct hid_device *hid = usbhid->hid;
+       int rc_lock, rc = 0;
+
+       if (test_bit(HID_CLEAR_HALT, &usbhid->iofl)) {
+               dev_dbg(&usbhid->intf->dev, "clear halt\n");
+               rc = usb_clear_halt(hid_to_usb_dev(hid), usbhid->urbin->pipe);
+               clear_bit(HID_CLEAR_HALT, &usbhid->iofl);
+               hid_start_in(hid);
+       }
+
+       else if (test_bit(HID_RESET_PENDING, &usbhid->iofl)) {
+               dev_dbg(&usbhid->intf->dev, "resetting device\n");
+               rc = rc_lock = usb_lock_device_for_reset(hid_to_usb_dev(hid), usbhid->intf);
+               if (rc_lock >= 0) {
+                       rc = usb_reset_composite_device(hid_to_usb_dev(hid), usbhid->intf);
+                       if (rc_lock)
+                               usb_unlock_device(hid_to_usb_dev(hid));
+               }
+               clear_bit(HID_RESET_PENDING, &usbhid->iofl);
+       }
+
+       switch (rc) {
+       case 0:
+               if (!test_bit(HID_IN_RUNNING, &usbhid->iofl))
+                       hid_io_error(hid);
+               break;
+       default:
+               err("can't reset device, %s-%s/input%d, status %d",
+                               hid_to_usb_dev(hid)->bus->bus_name,
+                               hid_to_usb_dev(hid)->devpath,
+                               usbhid->ifnum, rc);
+               /* FALLTHROUGH */
+       case -EHOSTUNREACH:
+       case -ENODEV:
+       case -EINTR:
+               break;
+       }
+}
+
+/* Main I/O error handler */
+static void hid_io_error(struct hid_device *hid)
+{
+       unsigned long flags;
+       struct usbhid_device *usbhid = hid->driver_data;
+
+       spin_lock_irqsave(&usbhid->inlock, flags);
+
+       /* Stop when disconnected */
+       if (usb_get_intfdata(usbhid->intf) == NULL)
+               goto done;
+
+       /* When an error occurs, retry at increasing intervals */
+       if (usbhid->retry_delay == 0) {
+               usbhid->retry_delay = 13;       /* Then 26, 52, 104, 104, ... */
+               usbhid->stop_retry = jiffies + msecs_to_jiffies(1000);
+       } else if (usbhid->retry_delay < 100)
+               usbhid->retry_delay *= 2;
+
+       if (time_after(jiffies, usbhid->stop_retry)) {
+
+               /* Retries failed, so do a port reset */
+               if (!test_and_set_bit(HID_RESET_PENDING, &usbhid->iofl)) {
+                       schedule_work(&usbhid->reset_work);
+                       goto done;
+               }
+       }
+
+       mod_timer(&usbhid->io_retry,
+                       jiffies + msecs_to_jiffies(usbhid->retry_delay));
+done:
+       spin_unlock_irqrestore(&usbhid->inlock, flags);
+}
+
+/*
+ * Input interrupt completion handler.
+ */
+
+static void hid_irq_in(struct urb *urb)
+{
+       struct hid_device       *hid = urb->context;
+       struct usbhid_device    *usbhid = hid->driver_data;
+       int                     status;
+
+       switch (urb->status) {
+               case 0:                 /* success */
+                       usbhid->retry_delay = 0;
+                       hid_input_report(urb->context, HID_INPUT_REPORT,
+                                        urb->transfer_buffer,
+                                        urb->actual_length, 1);
+                       break;
+               case -EPIPE:            /* stall */
+                       clear_bit(HID_IN_RUNNING, &usbhid->iofl);
+                       set_bit(HID_CLEAR_HALT, &usbhid->iofl);
+                       schedule_work(&usbhid->reset_work);
+                       return;
+               case -ECONNRESET:       /* unlink */
+               case -ENOENT:
+               case -ESHUTDOWN:        /* unplug */
+                       clear_bit(HID_IN_RUNNING, &usbhid->iofl);
+                       return;
+               case -EILSEQ:           /* protocol error or unplug */
+               case -EPROTO:           /* protocol error or unplug */
+               case -ETIME:            /* protocol error or unplug */
+               case -ETIMEDOUT:        /* Should never happen, but... */
+                       clear_bit(HID_IN_RUNNING, &usbhid->iofl);
+                       hid_io_error(hid);
+                       return;
+               default:                /* error */
+                       warn("input irq status %d received", urb->status);
+       }
+
+       status = usb_submit_urb(urb, GFP_ATOMIC);
+       if (status) {
+               clear_bit(HID_IN_RUNNING, &usbhid->iofl);
+               if (status != -EPERM) {
+                       err("can't resubmit intr, %s-%s/input%d, status %d",
+                                       hid_to_usb_dev(hid)->bus->bus_name,
+                                       hid_to_usb_dev(hid)->devpath,
+                                       usbhid->ifnum, status);
+                       hid_io_error(hid);
+               }
+       }
+}
+
+static int hid_submit_out(struct hid_device *hid)
+{
+       struct hid_report *report;
+       struct usbhid_device *usbhid = hid->driver_data;
+
+       report = usbhid->out[usbhid->outtail];
+
+       hid_output_report(report, usbhid->outbuf);
+       usbhid->urbout->transfer_buffer_length = ((report->size - 1) >> 3) + 1 + (report->id > 0);
+       usbhid->urbout->dev = hid_to_usb_dev(hid);
+
+       dbg("submitting out urb");
+
+       if (usb_submit_urb(usbhid->urbout, GFP_ATOMIC)) {
+               err("usb_submit_urb(out) failed");
+               return -1;
+       }
+
+       return 0;
+}
+
+static int hid_submit_ctrl(struct hid_device *hid)
+{
+       struct hid_report *report;
+       unsigned char dir;
+       int len;
+       struct usbhid_device *usbhid = hid->driver_data;
+
+       report = usbhid->ctrl[usbhid->ctrltail].report;
+       dir = usbhid->ctrl[usbhid->ctrltail].dir;
+
+       len = ((report->size - 1) >> 3) + 1 + (report->id > 0);
+       if (dir == USB_DIR_OUT) {
+               hid_output_report(report, usbhid->ctrlbuf);
+               usbhid->urbctrl->pipe = usb_sndctrlpipe(hid_to_usb_dev(hid), 0);
+               usbhid->urbctrl->transfer_buffer_length = len;
+       } else {
+               int maxpacket, padlen;
+
+               usbhid->urbctrl->pipe = usb_rcvctrlpipe(hid_to_usb_dev(hid), 0);
+               maxpacket = usb_maxpacket(hid_to_usb_dev(hid), usbhid->urbctrl->pipe, 0);
+               if (maxpacket > 0) {
+                       padlen = (len + maxpacket - 1) / maxpacket;
+                       padlen *= maxpacket;
+                       if (padlen > usbhid->bufsize)
+                               padlen = usbhid->bufsize;
+               } else
+                       padlen = 0;
+               usbhid->urbctrl->transfer_buffer_length = padlen;
+       }
+       usbhid->urbctrl->dev = hid_to_usb_dev(hid);
+
+       usbhid->cr->bRequestType = USB_TYPE_CLASS | USB_RECIP_INTERFACE | dir;
+       usbhid->cr->bRequest = (dir == USB_DIR_OUT) ? HID_REQ_SET_REPORT : HID_REQ_GET_REPORT;
+       usbhid->cr->wValue = cpu_to_le16(((report->type + 1) << 8) | report->id);
+       usbhid->cr->wIndex = cpu_to_le16(usbhid->ifnum);
+       usbhid->cr->wLength = cpu_to_le16(len);
+
+       dbg("submitting ctrl urb: %s wValue=0x%04x wIndex=0x%04x wLength=%u",
+               usbhid->cr->bRequest == HID_REQ_SET_REPORT ? "Set_Report" : "Get_Report",
+               usbhid->cr->wValue, usbhid->cr->wIndex, usbhid->cr->wLength);
+
+       if (usb_submit_urb(usbhid->urbctrl, GFP_ATOMIC)) {
+               err("usb_submit_urb(ctrl) failed");
+               return -1;
+       }
+
+       return 0;
+}
+
+/*
+ * Output interrupt completion handler.
+ */
+
+static void hid_irq_out(struct urb *urb)
+{
+       struct hid_device *hid = urb->context;
+       struct usbhid_device *usbhid = hid->driver_data;
+       unsigned long flags;
+       int unplug = 0;
+
+       switch (urb->status) {
+               case 0:                 /* success */
+                       break;
+               case -ESHUTDOWN:        /* unplug */
+                       unplug = 1;
+               case -EILSEQ:           /* protocol error or unplug */
+               case -EPROTO:           /* protocol error or unplug */
+               case -ECONNRESET:       /* unlink */
+               case -ENOENT:
+                       break;
+               default:                /* error */
+                       warn("output irq status %d received", urb->status);
+       }
+
+       spin_lock_irqsave(&usbhid->outlock, flags);
+
+       if (unplug)
+               usbhid->outtail = usbhid->outhead;
+       else
+               usbhid->outtail = (usbhid->outtail + 1) & (HID_OUTPUT_FIFO_SIZE - 1);
+
+       if (usbhid->outhead != usbhid->outtail) {
+               if (hid_submit_out(hid)) {
+                       clear_bit(HID_OUT_RUNNING, &usbhid->iofl);
+                       wake_up(&hid->wait);
+               }
+               spin_unlock_irqrestore(&usbhid->outlock, flags);
+               return;
+       }
+
+       clear_bit(HID_OUT_RUNNING, &usbhid->iofl);
+       spin_unlock_irqrestore(&usbhid->outlock, flags);
+       wake_up(&hid->wait);
+}
+
+/*
+ * Control pipe completion handler.
+ */
+
+static void hid_ctrl(struct urb *urb)
+{
+       struct hid_device *hid = urb->context;
+       struct usbhid_device *usbhid = hid->driver_data;
+       unsigned long flags;
+       int unplug = 0;
+
+       spin_lock_irqsave(&usbhid->ctrllock, flags);
+
+       switch (urb->status) {
+               case 0:                 /* success */
+                       if (usbhid->ctrl[usbhid->ctrltail].dir == USB_DIR_IN)
+                               hid_input_report(urb->context, usbhid->ctrl[usbhid->ctrltail].report->type,
+                                               urb->transfer_buffer, urb->actual_length, 0);
+                       break;
+               case -ESHUTDOWN:        /* unplug */
+                       unplug = 1;
+               case -EILSEQ:           /* protocol error or unplug */
+               case -EPROTO:           /* protocol error or unplug */
+               case -ECONNRESET:       /* unlink */
+               case -ENOENT:
+               case -EPIPE:            /* report not available */
+                       break;
+               default:                /* error */
+                       warn("ctrl urb status %d received", urb->status);
+       }
+
+       if (unplug)
+               usbhid->ctrltail = usbhid->ctrlhead;
+       else
+               usbhid->ctrltail = (usbhid->ctrltail + 1) & (HID_CONTROL_FIFO_SIZE - 1);
+
+       if (usbhid->ctrlhead != usbhid->ctrltail) {
+               if (hid_submit_ctrl(hid)) {
+                       clear_bit(HID_CTRL_RUNNING, &usbhid->iofl);
+                       wake_up(&hid->wait);
+               }
+               spin_unlock_irqrestore(&usbhid->ctrllock, flags);
+               return;
+       }
+
+       clear_bit(HID_CTRL_RUNNING, &usbhid->iofl);
+       spin_unlock_irqrestore(&usbhid->ctrllock, flags);
+       wake_up(&hid->wait);
+}
+
+void usbhid_submit_report(struct hid_device *hid, struct hid_report *report, unsigned char dir)
+{
+       int head;
+       unsigned long flags;
+       struct usbhid_device *usbhid = hid->driver_data;
+
+       if ((hid->quirks & HID_QUIRK_NOGET) && dir == USB_DIR_IN)
+               return;
+
+       if (usbhid->urbout && dir == USB_DIR_OUT && report->type == HID_OUTPUT_REPORT) {
+
+               spin_lock_irqsave(&usbhid->outlock, flags);
+
+               if ((head = (usbhid->outhead + 1) & (HID_OUTPUT_FIFO_SIZE - 1)) == usbhid->outtail) {
+                       spin_unlock_irqrestore(&usbhid->outlock, flags);
+                       warn("output queue full");
+                       return;
+               }
+
+               usbhid->out[usbhid->outhead] = report;
+               usbhid->outhead = head;
+
+               if (!test_and_set_bit(HID_OUT_RUNNING, &usbhid->iofl))
+                       if (hid_submit_out(hid))
+                               clear_bit(HID_OUT_RUNNING, &usbhid->iofl);
+
+               spin_unlock_irqrestore(&usbhid->outlock, flags);
+               return;
+       }
+
+       spin_lock_irqsave(&usbhid->ctrllock, flags);
+
+       if ((head = (usbhid->ctrlhead + 1) & (HID_CONTROL_FIFO_SIZE - 1)) == usbhid->ctrltail) {
+               spin_unlock_irqrestore(&usbhid->ctrllock, flags);
+               warn("control queue full");
+               return;
+       }
+
+       usbhid->ctrl[usbhid->ctrlhead].report = report;
+       usbhid->ctrl[usbhid->ctrlhead].dir = dir;
+       usbhid->ctrlhead = head;
+
+       if (!test_and_set_bit(HID_CTRL_RUNNING, &usbhid->iofl))
+               if (hid_submit_ctrl(hid))
+                       clear_bit(HID_CTRL_RUNNING, &usbhid->iofl);
+
+       spin_unlock_irqrestore(&usbhid->ctrllock, flags);
+}
+
+static int usb_hidinput_input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
+{
+       struct hid_device *hid = dev->private;
+       struct hid_field *field;
+       int offset;
+
+       if (type == EV_FF)
+               return input_ff_event(dev, type, code, value);
+
+       if (type != EV_LED)
+               return -1;
+
+       if ((offset = hidinput_find_field(hid, type, code, &field)) == -1) {
+               warn("event field not found");
+               return -1;
+       }
+
+       hid_set_field(field, offset, value);
+       usbhid_submit_report(hid, field->report, USB_DIR_OUT);
+
+       return 0;
+}
+
+int usbhid_wait_io(struct hid_device *hid)
+{
+       struct usbhid_device *usbhid = hid->driver_data;
+
+       if (!wait_event_timeout(hid->wait, (!test_bit(HID_CTRL_RUNNING, &usbhid->iofl) &&
+                                       !test_bit(HID_OUT_RUNNING, &usbhid->iofl)),
+                                       10*HZ)) {
+               dbg("timeout waiting for ctrl or out queue to clear");
+               return -1;
+       }
+
+       return 0;
+}
+
+static int hid_set_idle(struct usb_device *dev, int ifnum, int report, int idle)
+{
+       return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+               HID_REQ_SET_IDLE, USB_TYPE_CLASS | USB_RECIP_INTERFACE, (idle << 8) | report,
+               ifnum, NULL, 0, USB_CTRL_SET_TIMEOUT);
+}
+
+static int hid_get_class_descriptor(struct usb_device *dev, int ifnum,
+               unsigned char type, void *buf, int size)
+{
+       int result, retries = 4;
+
+       memset(buf, 0, size);
+
+       do {
+               result = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
+                               USB_REQ_GET_DESCRIPTOR, USB_RECIP_INTERFACE | USB_DIR_IN,
+                               (type << 8), ifnum, buf, size, USB_CTRL_GET_TIMEOUT);
+               retries--;
+       } while (result < size && retries);
+       return result;
+}
+
+int usbhid_open(struct hid_device *hid)
+{
+       ++hid->open;
+       if (hid_start_in(hid))
+               hid_io_error(hid);
+       return 0;
+}
+
+void usbhid_close(struct hid_device *hid)
+{
+       struct usbhid_device *usbhid = hid->driver_data;
+
+       if (!--hid->open)
+               usb_kill_urb(usbhid->urbin);
+}
+
+#define USB_VENDOR_ID_PANJIT           0x134c
+
+#define USB_VENDOR_ID_TURBOX           0x062a
+#define USB_DEVICE_ID_TURBOX_KEYBOARD  0x0201
+#define USB_VENDOR_ID_CIDC             0x1677
+
+/*
+ * Initialize all reports
+ */
+
+void usbhid_init_reports(struct hid_device *hid)
+{
+       struct hid_report *report;
+       struct usbhid_device *usbhid = hid->driver_data;
+       int err, ret;
+
+       list_for_each_entry(report, &hid->report_enum[HID_INPUT_REPORT].report_list, list)
+               usbhid_submit_report(hid, report, USB_DIR_IN);
+
+       list_for_each_entry(report, &hid->report_enum[HID_FEATURE_REPORT].report_list, list)
+               usbhid_submit_report(hid, report, USB_DIR_IN);
+
+       err = 0;
+       ret = usbhid_wait_io(hid);
+       while (ret) {
+               err |= ret;
+               if (test_bit(HID_CTRL_RUNNING, &usbhid->iofl))
+                       usb_kill_urb(usbhid->urbctrl);
+               if (test_bit(HID_OUT_RUNNING, &usbhid->iofl))
+                       usb_kill_urb(usbhid->urbout);
+               ret = usbhid_wait_io(hid);
+       }
+
+       if (err)
+               warn("timeout initializing reports");
+}
+
+#define USB_VENDOR_ID_GTCO             0x078c
+#define USB_DEVICE_ID_GTCO_90          0x0090
+#define USB_DEVICE_ID_GTCO_100         0x0100
+#define USB_DEVICE_ID_GTCO_101         0x0101
+#define USB_DEVICE_ID_GTCO_103         0x0103
+#define USB_DEVICE_ID_GTCO_104         0x0104
+#define USB_DEVICE_ID_GTCO_105         0x0105
+#define USB_DEVICE_ID_GTCO_106         0x0106
+#define USB_DEVICE_ID_GTCO_107         0x0107
+#define USB_DEVICE_ID_GTCO_108         0x0108
+#define USB_DEVICE_ID_GTCO_200         0x0200
+#define USB_DEVICE_ID_GTCO_201         0x0201
+#define USB_DEVICE_ID_GTCO_202         0x0202
+#define USB_DEVICE_ID_GTCO_203         0x0203
+#define USB_DEVICE_ID_GTCO_204         0x0204
+#define USB_DEVICE_ID_GTCO_205         0x0205
+#define USB_DEVICE_ID_GTCO_206         0x0206
+#define USB_DEVICE_ID_GTCO_207         0x0207
+#define USB_DEVICE_ID_GTCO_300         0x0300
+#define USB_DEVICE_ID_GTCO_301         0x0301
+#define USB_DEVICE_ID_GTCO_302         0x0302
+#define USB_DEVICE_ID_GTCO_303         0x0303
+#define USB_DEVICE_ID_GTCO_304         0x0304
+#define USB_DEVICE_ID_GTCO_305         0x0305
+#define USB_DEVICE_ID_GTCO_306         0x0306
+#define USB_DEVICE_ID_GTCO_307         0x0307
+#define USB_DEVICE_ID_GTCO_308         0x0308
+#define USB_DEVICE_ID_GTCO_309         0x0309
+#define USB_DEVICE_ID_GTCO_400         0x0400
+#define USB_DEVICE_ID_GTCO_401         0x0401
+#define USB_DEVICE_ID_GTCO_402         0x0402
+#define USB_DEVICE_ID_GTCO_403         0x0403
+#define USB_DEVICE_ID_GTCO_404         0x0404
+#define USB_DEVICE_ID_GTCO_405         0x0405
+#define USB_DEVICE_ID_GTCO_500         0x0500
+#define USB_DEVICE_ID_GTCO_501         0x0501
+#define USB_DEVICE_ID_GTCO_502         0x0502
+#define USB_DEVICE_ID_GTCO_503         0x0503
+#define USB_DEVICE_ID_GTCO_504         0x0504
+#define USB_DEVICE_ID_GTCO_1000                0x1000
+#define USB_DEVICE_ID_GTCO_1001                0x1001
+#define USB_DEVICE_ID_GTCO_1002                0x1002
+#define USB_DEVICE_ID_GTCO_1003                0x1003
+#define USB_DEVICE_ID_GTCO_1004                0x1004
+#define USB_DEVICE_ID_GTCO_1005                0x1005
+#define USB_DEVICE_ID_GTCO_1006                0x1006
+
+#define USB_VENDOR_ID_WACOM            0x056a
+
+#define USB_VENDOR_ID_ACECAD           0x0460
+#define USB_DEVICE_ID_ACECAD_FLAIR     0x0004
+#define USB_DEVICE_ID_ACECAD_302       0x0008
+
+#define USB_VENDOR_ID_KBGEAR           0x084e
+#define USB_DEVICE_ID_KBGEAR_JAMSTUDIO 0x1001
+
+#define USB_VENDOR_ID_AIPTEK           0x08ca
+#define USB_DEVICE_ID_AIPTEK_01                0x0001
+#define USB_DEVICE_ID_AIPTEK_10                0x0010
+#define USB_DEVICE_ID_AIPTEK_20                0x0020
+#define USB_DEVICE_ID_AIPTEK_21                0x0021
+#define USB_DEVICE_ID_AIPTEK_22                0x0022
+#define USB_DEVICE_ID_AIPTEK_23                0x0023
+#define USB_DEVICE_ID_AIPTEK_24                0x0024
+
+#define USB_VENDOR_ID_GRIFFIN          0x077d
+#define USB_DEVICE_ID_POWERMATE                0x0410
+#define USB_DEVICE_ID_SOUNDKNOB                0x04AA
+
+#define USB_VENDOR_ID_ATEN             0x0557
+#define USB_DEVICE_ID_ATEN_UC100KM     0x2004
+#define USB_DEVICE_ID_ATEN_CS124U      0x2202
+#define USB_DEVICE_ID_ATEN_2PORTKVM    0x2204
+#define USB_DEVICE_ID_ATEN_4PORTKVM    0x2205
+#define USB_DEVICE_ID_ATEN_4PORTKVMC   0x2208
+
+#define USB_VENDOR_ID_TOPMAX           0x0663
+#define USB_DEVICE_ID_TOPMAX_COBRAPAD  0x0103
+
+#define USB_VENDOR_ID_HAPP             0x078b
+#define USB_DEVICE_ID_UGCI_DRIVING     0x0010
+#define USB_DEVICE_ID_UGCI_FLYING      0x0020
+#define USB_DEVICE_ID_UGCI_FIGHTING    0x0030
+
+#define USB_VENDOR_ID_MGE              0x0463
+#define USB_DEVICE_ID_MGE_UPS          0xffff
+#define USB_DEVICE_ID_MGE_UPS1         0x0001
+
+#define USB_VENDOR_ID_ONTRAK           0x0a07
+#define USB_DEVICE_ID_ONTRAK_ADU100    0x0064
+
+#define USB_VENDOR_ID_ESSENTIAL_REALITY        0x0d7f
+#define USB_DEVICE_ID_ESSENTIAL_REALITY_P5 0x0100
+
+#define USB_VENDOR_ID_A4TECH           0x09da
+#define USB_DEVICE_ID_A4TECH_WCP32PU   0x0006
+
+#define USB_VENDOR_ID_AASHIMA          0x06d6
+#define USB_DEVICE_ID_AASHIMA_GAMEPAD  0x0025
+#define USB_DEVICE_ID_AASHIMA_PREDATOR 0x0026
+
+#define USB_VENDOR_ID_CYPRESS          0x04b4
+#define USB_DEVICE_ID_CYPRESS_MOUSE    0x0001
+#define USB_DEVICE_ID_CYPRESS_HIDCOM   0x5500
+#define USB_DEVICE_ID_CYPRESS_ULTRAMOUSE       0x7417
+
+#define USB_VENDOR_ID_BERKSHIRE                0x0c98
+#define USB_DEVICE_ID_BERKSHIRE_PCWD   0x1140
+
+#define USB_VENDOR_ID_ALPS             0x0433
+#define USB_DEVICE_ID_IBM_GAMEPAD      0x1101
+
+#define USB_VENDOR_ID_SAITEK           0x06a3
+#define USB_DEVICE_ID_SAITEK_RUMBLEPAD 0xff17
+
+#define USB_VENDOR_ID_NEC              0x073e
+#define USB_DEVICE_ID_NEC_USB_GAME_PAD 0x0301
+
+#define USB_VENDOR_ID_CHIC             0x05fe
+#define USB_DEVICE_ID_CHIC_GAMEPAD     0x0014
+
+#define USB_VENDOR_ID_GLAB             0x06c2
+#define USB_DEVICE_ID_4_PHIDGETSERVO_30        0x0038
+#define USB_DEVICE_ID_1_PHIDGETSERVO_30        0x0039
+#define USB_DEVICE_ID_0_0_4_IF_KIT     0x0040
+#define USB_DEVICE_ID_0_16_16_IF_KIT   0x0044
+#define USB_DEVICE_ID_8_8_8_IF_KIT     0x0045
+#define USB_DEVICE_ID_0_8_7_IF_KIT     0x0051
+#define USB_DEVICE_ID_0_8_8_IF_KIT     0x0053
+#define USB_DEVICE_ID_PHIDGET_MOTORCONTROL     0x0058
+
+#define USB_VENDOR_ID_WISEGROUP                0x0925
+#define USB_DEVICE_ID_1_PHIDGETSERVO_20        0x8101
+#define USB_DEVICE_ID_4_PHIDGETSERVO_20        0x8104
+#define USB_DEVICE_ID_8_8_4_IF_KIT     0x8201
+#define USB_DEVICE_ID_DUAL_USB_JOYPAD   0x8866
+
+#define USB_VENDOR_ID_WISEGROUP_LTD    0x6677
+#define USB_DEVICE_ID_SMARTJOY_DUAL_PLUS 0x8802
+
+#define USB_VENDOR_ID_CODEMERCS                0x07c0
+#define USB_DEVICE_ID_CODEMERCS_IOW_FIRST      0x1500
+#define USB_DEVICE_ID_CODEMERCS_IOW_LAST       0x15ff
+
+#define USB_VENDOR_ID_DELORME          0x1163
+#define USB_DEVICE_ID_DELORME_EARTHMATE 0x0100
+#define USB_DEVICE_ID_DELORME_EM_LT20  0x0200
+
+#define USB_VENDOR_ID_MCC              0x09db
+#define USB_DEVICE_ID_MCC_PMD1024LS    0x0076
+#define USB_DEVICE_ID_MCC_PMD1208LS    0x007a
+
+#define USB_VENDOR_ID_VERNIER          0x08f7
+#define USB_DEVICE_ID_VERNIER_LABPRO   0x0001
+#define USB_DEVICE_ID_VERNIER_GOTEMP   0x0002
+#define USB_DEVICE_ID_VERNIER_SKIP     0x0003
+#define USB_DEVICE_ID_VERNIER_CYCLOPS  0x0004
+
+#define USB_VENDOR_ID_LD               0x0f11
+#define USB_DEVICE_ID_LD_CASSY         0x1000
+#define USB_DEVICE_ID_LD_POCKETCASSY   0x1010
+#define USB_DEVICE_ID_LD_MOBILECASSY   0x1020
+#define USB_DEVICE_ID_LD_JWM           0x1080
+#define USB_DEVICE_ID_LD_DMMP          0x1081
+#define USB_DEVICE_ID_LD_UMIP          0x1090
+#define USB_DEVICE_ID_LD_XRAY1         0x1100
+#define USB_DEVICE_ID_LD_XRAY2         0x1101
+#define USB_DEVICE_ID_LD_VIDEOCOM      0x1200
+#define USB_DEVICE_ID_LD_COM3LAB       0x2000
+#define USB_DEVICE_ID_LD_TELEPORT      0x2010
+#define USB_DEVICE_ID_LD_NETWORKANALYSER 0x2020
+#define USB_DEVICE_ID_LD_POWERCONTROL  0x2030
+#define USB_DEVICE_ID_LD_MACHINETEST   0x2040
+
+#define USB_VENDOR_ID_APPLE            0x05ac
+#define USB_DEVICE_ID_APPLE_MIGHTYMOUSE        0x0304
+#define USB_DEVICE_ID_APPLE_FOUNTAIN_ANSI      0x020e
+#define USB_DEVICE_ID_APPLE_FOUNTAIN_ISO       0x020f
+#define USB_DEVICE_ID_APPLE_GEYSER_ANSI        0x0214
+#define USB_DEVICE_ID_APPLE_GEYSER_ISO 0x0215
+#define USB_DEVICE_ID_APPLE_GEYSER_JIS 0x0216
+#define USB_DEVICE_ID_APPLE_GEYSER3_ANSI       0x0217
+#define USB_DEVICE_ID_APPLE_GEYSER3_ISO        0x0218
+#define USB_DEVICE_ID_APPLE_GEYSER3_JIS        0x0219
+#define USB_DEVICE_ID_APPLE_GEYSER4_ANSI       0x021a
+#define USB_DEVICE_ID_APPLE_GEYSER4_ISO        0x021b
+#define USB_DEVICE_ID_APPLE_GEYSER4_JIS        0x021c
+#define USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY   0x030a
+#define USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY    0x030b
+#define USB_DEVICE_ID_APPLE_IR         0x8240
+
+#define USB_VENDOR_ID_CHERRY           0x046a
+#define USB_DEVICE_ID_CHERRY_CYMOTION  0x0023
+
+#define USB_VENDOR_ID_YEALINK          0x6993
+#define USB_DEVICE_ID_YEALINK_P1K_P4K_B2K      0xb001
+
+#define USB_VENDOR_ID_ALCOR            0x058f
+#define USB_DEVICE_ID_ALCOR_USBRS232   0x9720
+
+#define USB_VENDOR_ID_SUN              0x0430
+#define USB_DEVICE_ID_RARITAN_KVM_DONGLE       0xcdab
+
+#define USB_VENDOR_ID_AIRCABLE         0x16CA
+#define USB_DEVICE_ID_AIRCABLE1                0x1502
+
+#define USB_VENDOR_ID_LOGITECH         0x046d
+#define USB_DEVICE_ID_LOGITECH_USB_RECEIVER    0xc101
+#define USB_DEVICE_ID_LOGITECH_USB_RECEIVER_2  0xc517
+#define USB_DEVICE_ID_DINOVO_EDGE      0xc714
+
+#define USB_VENDOR_ID_IMATION          0x0718
+#define USB_DEVICE_ID_DISC_STAKKA      0xd000
+
+#define USB_VENDOR_ID_PANTHERLORD      0x0810
+#define USB_DEVICE_ID_PANTHERLORD_TWIN_USB_JOYSTICK    0x0001
+
+#define USB_VENDOR_ID_SONY                     0x054c
+#define USB_DEVICE_ID_SONY_PS3_CONTROLLER      0x0268
+
+/*
+ * Alphabetically sorted blacklist by quirk type.
+ */
+
+static const struct hid_blacklist {
+       __u16 idVendor;
+       __u16 idProduct;
+       unsigned quirks;
+} hid_blacklist[] = {
+
+       { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_EDGE, HID_QUIRK_DUPLICATE_USAGES },
+
+       { USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_01, HID_QUIRK_IGNORE },
+       { USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_10, HID_QUIRK_IGNORE },
+       { USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_20, HID_QUIRK_IGNORE },
+       { USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_21, HID_QUIRK_IGNORE },
+       { USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_22, HID_QUIRK_IGNORE },
+       { USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_23, HID_QUIRK_IGNORE },
+       { USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_24, HID_QUIRK_IGNORE },
+       { USB_VENDOR_ID_AIRCABLE, USB_DEVICE_ID_AIRCABLE1, HID_QUIRK_IGNORE },
+       { USB_VENDOR_ID_ALCOR, USB_DEVICE_ID_ALCOR_USBRS232, HID_QUIRK_IGNORE },
+       { USB_VENDOR_ID_BERKSHIRE, USB_DEVICE_ID_BERKSHIRE_PCWD, HID_QUIRK_IGNORE },
+       { USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_HIDCOM, HID_QUIRK_IGNORE },
+       { USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_ULTRAMOUSE, HID_QUIRK_IGNORE },
+       { USB_VENDOR_ID_DELORME, USB_DEVICE_ID_DELORME_EARTHMATE, HID_QUIRK_IGNORE },
+       { USB_VENDOR_ID_DELORME, USB_DEVICE_ID_DELORME_EM_LT20, HID_QUIRK_IGNORE },
+       { USB_VENDOR_ID_ESSENTIAL_REALITY, USB_DEVICE_ID_ESSENTIAL_REALITY_P5, HID_QUIRK_IGNORE },
+       { USB_VENDOR_ID_GLAB, USB_DEVICE_ID_4_PHIDGETSERVO_30, HID_QUIRK_IGNORE },
+       { USB_VENDOR_ID_GLAB, USB_DEVICE_ID_1_PHIDGETSERVO_30, HID_QUIRK_IGNORE },
+       { USB_VENDOR_ID_GLAB, USB_DEVICE_ID_0_0_4_IF_KIT, HID_QUIRK_IGNORE },
+       { USB_VENDOR_ID_GLAB, USB_DEVICE_ID_0_16_16_IF_KIT, HID_QUIRK_IGNORE },
+       { USB_VENDOR_ID_GLAB, USB_DEVICE_ID_8_8_8_IF_KIT, HID_QUIRK_IGNORE },
+       { USB_VENDOR_ID_GLAB, USB_DEVICE_ID_0_8_7_IF_KIT, HID_QUIRK_IGNORE },
+       { USB_VENDOR_ID_GLAB, USB_DEVICE_ID_0_8_8_IF_KIT, HID_QUIRK_IGNORE },
+       { USB_VENDOR_ID_GLAB, USB_DEVICE_ID_PHIDGET_MOTORCONTROL, HID_QUIRK_IGNORE },
+       { USB_VENDOR_ID_GRIFFIN, USB_DEVICE_ID_POWERMATE, HID_QUIRK_IGNORE },
+       { USB_VENDOR_ID_GRIFFIN, USB_DEVICE_ID_SOUNDKNOB, HID_QUIRK_IGNORE },
+       { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_90, HID_QUIRK_IGNORE },
+       { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_100, HID_QUIRK_IGNORE },
+       { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_101, HID_QUIRK_IGNORE },
+       { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_103, HID_QUIRK_IGNORE },
+       { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_104, HID_QUIRK_IGNORE },
+       { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_105, HID_QUIRK_IGNORE },
+       { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_106, HID_QUIRK_IGNORE },
+       { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_107, HID_QUIRK_IGNORE },
+       { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_108, HID_QUIRK_IGNORE },
+       { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_200, HID_QUIRK_IGNORE },
+       { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_201, HID_QUIRK_IGNORE },
+       { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_202, HID_QUIRK_IGNORE },
+       { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_203, HID_QUIRK_IGNORE },
+       { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_204, HID_QUIRK_IGNORE },
+       { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_205, HID_QUIRK_IGNORE },
+       { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_206, HID_QUIRK_IGNORE },
+       { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_207, HID_QUIRK_IGNORE },
+       { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_300, HID_QUIRK_IGNORE },
+       { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_301, HID_QUIRK_IGNORE },
+       { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_302, HID_QUIRK_IGNORE },
+       { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_303, HID_QUIRK_IGNORE },
+       { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_304, HID_QUIRK_IGNORE },
+       { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_305, HID_QUIRK_IGNORE },
+       { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_306, HID_QUIRK_IGNORE },
+       { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_307, HID_QUIRK_IGNORE },
+       { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_308, HID_QUIRK_IGNORE },
+       { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_309, HID_QUIRK_IGNORE },
+       { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_400, HID_QUIRK_IGNORE },
+       { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_401, HID_QUIRK_IGNORE },
+       { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_402, HID_QUIRK_IGNORE },
+       { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_403, HID_QUIRK_IGNORE },
+       { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_404, HID_QUIRK_IGNORE },
+       { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_405, HID_QUIRK_IGNORE },
+       { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_500, HID_QUIRK_IGNORE },
+       { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_501, HID_QUIRK_IGNORE },
+       { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_502, HID_QUIRK_IGNORE },
+       { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_503, HID_QUIRK_IGNORE },
+       { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_504, HID_QUIRK_IGNORE },
+       { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1000, HID_QUIRK_IGNORE },
+       { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1001, HID_QUIRK_IGNORE },
+       { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1002, HID_QUIRK_IGNORE },
+       { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1003, HID_QUIRK_IGNORE },
+       { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1004, HID_QUIRK_IGNORE },
+       { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1005, HID_QUIRK_IGNORE },
+       { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1006, HID_QUIRK_IGNORE },
+       { USB_VENDOR_ID_IMATION, USB_DEVICE_ID_DISC_STAKKA, HID_QUIRK_IGNORE },
+       { USB_VENDOR_ID_KBGEAR, USB_DEVICE_ID_KBGEAR_JAMSTUDIO, HID_QUIRK_IGNORE },
+       { USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_CASSY, HID_QUIRK_IGNORE },
+       { USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_POCKETCASSY, HID_QUIRK_IGNORE },
+       { USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MOBILECASSY, HID_QUIRK_IGNORE },
+       { USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_JWM, HID_QUIRK_IGNORE },
+       { USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_DMMP, HID_QUIRK_IGNORE },
+       { USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_UMIP, HID_QUIRK_IGNORE },
+       { USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_XRAY1, HID_QUIRK_IGNORE },
+       { USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_XRAY2, HID_QUIRK_IGNORE },
+       { USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_VIDEOCOM, HID_QUIRK_IGNORE },
+       { USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_COM3LAB, HID_QUIRK_IGNORE },
+       { USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_TELEPORT, HID_QUIRK_IGNORE },
+       { USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_NETWORKANALYSER, HID_QUIRK_IGNORE },
+       { USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_POWERCONTROL, HID_QUIRK_IGNORE },
+       { USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MACHINETEST, HID_QUIRK_IGNORE },
+       { USB_VENDOR_ID_MCC, USB_DEVICE_ID_MCC_PMD1024LS, HID_QUIRK_IGNORE },
+       { USB_VENDOR_ID_MCC, USB_DEVICE_ID_MCC_PMD1208LS, HID_QUIRK_IGNORE },
+       { USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS, HID_QUIRK_IGNORE },
+       { USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS1, HID_QUIRK_IGNORE },
+       { USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100, HID_QUIRK_IGNORE },
+       { USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 20, HID_QUIRK_IGNORE },
+       { USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 30, HID_QUIRK_IGNORE },
+       { USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 100, HID_QUIRK_IGNORE },
+       { USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 108, HID_QUIRK_IGNORE },
+       { USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 118, HID_QUIRK_IGNORE },
+       { USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 200, HID_QUIRK_IGNORE },
+       { USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 300, HID_QUIRK_IGNORE },
+       { USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 400, HID_QUIRK_IGNORE },
+       { USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 500, HID_QUIRK_IGNORE },
+       { USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_LABPRO, HID_QUIRK_IGNORE },
+       { USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_GOTEMP, HID_QUIRK_IGNORE },
+       { USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_SKIP, HID_QUIRK_IGNORE },
+       { USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_CYCLOPS, HID_QUIRK_IGNORE },
+       { USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_4_PHIDGETSERVO_20, HID_QUIRK_IGNORE },
+       { USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_1_PHIDGETSERVO_20, HID_QUIRK_IGNORE },
+       { USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_8_8_4_IF_KIT, HID_QUIRK_IGNORE },
+       { USB_VENDOR_ID_YEALINK, USB_DEVICE_ID_YEALINK_P1K_P4K_B2K, HID_QUIRK_IGNORE },
+
+       { USB_VENDOR_ID_ACECAD, USB_DEVICE_ID_ACECAD_FLAIR, HID_QUIRK_IGNORE },
+       { USB_VENDOR_ID_ACECAD, USB_DEVICE_ID_ACECAD_302, HID_QUIRK_IGNORE },
+
+       { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_UC100KM, HID_QUIRK_NOGET },
+       { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_CS124U, HID_QUIRK_NOGET },
+       { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_2PORTKVM, HID_QUIRK_NOGET },
+       { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_4PORTKVM, HID_QUIRK_NOGET },
+       { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_4PORTKVMC, HID_QUIRK_NOGET },
+       { USB_VENDOR_ID_SUN, USB_DEVICE_ID_RARITAN_KVM_DONGLE, HID_QUIRK_NOGET },
+       { USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_DUAL_USB_JOYPAD, HID_QUIRK_NOGET | HID_QUIRK_MULTI_INPUT },
+       { USB_VENDOR_ID_WISEGROUP_LTD, USB_DEVICE_ID_SMARTJOY_DUAL_PLUS, HID_QUIRK_NOGET | HID_QUIRK_MULTI_INPUT },
+
+       { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MIGHTYMOUSE, HID_QUIRK_MIGHTYMOUSE | HID_QUIRK_INVERT_HWHEEL },
+       { USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_WCP32PU, HID_QUIRK_2WHEEL_MOUSE_HACK_7 },
+       { USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_MOUSE, HID_QUIRK_2WHEEL_MOUSE_HACK_5 },
+
+       { USB_VENDOR_ID_AASHIMA, USB_DEVICE_ID_AASHIMA_GAMEPAD, HID_QUIRK_BADPAD },
+       { USB_VENDOR_ID_AASHIMA, USB_DEVICE_ID_AASHIMA_PREDATOR, HID_QUIRK_BADPAD },
+       { USB_VENDOR_ID_ALPS, USB_DEVICE_ID_IBM_GAMEPAD, HID_QUIRK_BADPAD },
+       { USB_VENDOR_ID_CHIC, USB_DEVICE_ID_CHIC_GAMEPAD, HID_QUIRK_BADPAD },
+       { USB_VENDOR_ID_HAPP, USB_DEVICE_ID_UGCI_DRIVING, HID_QUIRK_BADPAD | HID_QUIRK_MULTI_INPUT },
+       { USB_VENDOR_ID_HAPP, USB_DEVICE_ID_UGCI_FLYING, HID_QUIRK_BADPAD | HID_QUIRK_MULTI_INPUT },
+       { USB_VENDOR_ID_HAPP, USB_DEVICE_ID_UGCI_FIGHTING, HID_QUIRK_BADPAD | HID_QUIRK_MULTI_INPUT },
+       { USB_VENDOR_ID_NEC, USB_DEVICE_ID_NEC_USB_GAME_PAD, HID_QUIRK_BADPAD },
+       { USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_RUMBLEPAD, HID_QUIRK_BADPAD },
+       { USB_VENDOR_ID_TOPMAX, USB_DEVICE_ID_TOPMAX_COBRAPAD, HID_QUIRK_BADPAD },
+
+       { USB_VENDOR_ID_CHERRY, USB_DEVICE_ID_CHERRY_CYMOTION, HID_QUIRK_CYMOTION },
+
+       { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_ANSI, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
+       { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_ISO, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
+       { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_ANSI, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
+       { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_ISO, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE | HID_QUIRK_POWERBOOK_ISO_KEYBOARD},
+       { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_JIS, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
+       { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_ANSI, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
+       { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_ISO, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE | HID_QUIRK_POWERBOOK_ISO_KEYBOARD},
+       { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_JIS, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
+       { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_ANSI, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
+       { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_ISO, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE | HID_QUIRK_POWERBOOK_ISO_KEYBOARD},
+       { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_JIS, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
+       { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
+       { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
+
+       { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IR, HID_QUIRK_IGNORE },
+
+       { USB_VENDOR_ID_PANJIT, 0x0001, HID_QUIRK_IGNORE },
+       { USB_VENDOR_ID_PANJIT, 0x0002, HID_QUIRK_IGNORE },
+       { USB_VENDOR_ID_PANJIT, 0x0003, HID_QUIRK_IGNORE },
+       { USB_VENDOR_ID_PANJIT, 0x0004, HID_QUIRK_IGNORE },
+
+       { USB_VENDOR_ID_TURBOX, USB_DEVICE_ID_TURBOX_KEYBOARD, HID_QUIRK_NOGET },
+
+       { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_USB_RECEIVER, HID_QUIRK_BAD_RELATIVE_KEYS },
+       { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_USB_RECEIVER_2, HID_QUIRK_LOGITECH_S510_DESCRIPTOR },
+
+       { USB_VENDOR_ID_PANTHERLORD, USB_DEVICE_ID_PANTHERLORD_TWIN_USB_JOYSTICK, HID_QUIRK_MULTI_INPUT | HID_QUIRK_SKIP_OUTPUT_REPORTS },
+
+       { USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER, HID_QUIRK_SONY_PS3_CONTROLLER },
+
+       { USB_VENDOR_ID_CIDC, 0x0103, HID_QUIRK_IGNORE },
+
+       { 0, 0 }
+};
+
+/*
+ * Traverse the supplied list of reports and find the longest
+ */
+static void hid_find_max_report(struct hid_device *hid, unsigned int type, int *max)
+{
+       struct hid_report *report;
+       int size;
+
+       list_for_each_entry(report, &hid->report_enum[type].report_list, list) {
+               size = ((report->size - 1) >> 3) + 1;
+               if (type == HID_INPUT_REPORT && hid->report_enum[type].numbered)
+                       size++;
+               if (*max < size)
+                       *max = size;
+       }
+}
+
+static int hid_alloc_buffers(struct usb_device *dev, struct hid_device *hid)
+{
+       struct usbhid_device *usbhid = hid->driver_data;
+
+       if (!(usbhid->inbuf = usb_buffer_alloc(dev, usbhid->bufsize, GFP_ATOMIC, &usbhid->inbuf_dma)))
+               return -1;
+       if (!(usbhid->outbuf = usb_buffer_alloc(dev, usbhid->bufsize, GFP_ATOMIC, &usbhid->outbuf_dma)))
+               return -1;
+       if (!(usbhid->cr = usb_buffer_alloc(dev, sizeof(*(usbhid->cr)), GFP_ATOMIC, &usbhid->cr_dma)))
+               return -1;
+       if (!(usbhid->ctrlbuf = usb_buffer_alloc(dev, usbhid->bufsize, GFP_ATOMIC, &usbhid->ctrlbuf_dma)))
+               return -1;
+
+       return 0;
+}
+
+static void hid_free_buffers(struct usb_device *dev, struct hid_device *hid)
+{
+       struct usbhid_device *usbhid = hid->driver_data;
+
+       if (usbhid->inbuf)
+               usb_buffer_free(dev, usbhid->bufsize, usbhid->inbuf, usbhid->inbuf_dma);
+       if (usbhid->outbuf)
+               usb_buffer_free(dev, usbhid->bufsize, usbhid->outbuf, usbhid->outbuf_dma);
+       if (usbhid->cr)
+               usb_buffer_free(dev, sizeof(*(usbhid->cr)), usbhid->cr, usbhid->cr_dma);
+       if (usbhid->ctrlbuf)
+               usb_buffer_free(dev, usbhid->bufsize, usbhid->ctrlbuf, usbhid->ctrlbuf_dma);
+}
+
+/*
+ * Cherry Cymotion keyboard have an invalid HID report descriptor,
+ * that needs fixing before we can parse it.
+ */
+
+static void hid_fixup_cymotion_descriptor(char *rdesc, int rsize)
+{
+       if (rsize >= 17 && rdesc[11] == 0x3c && rdesc[12] == 0x02) {
+               info("Fixing up Cherry Cymotion report descriptor");
+               rdesc[11] = rdesc[16] = 0xff;
+               rdesc[12] = rdesc[17] = 0x03;
+       }
+}
+
+/*
+ * Sending HID_REQ_GET_REPORT changes the operation mode of the ps3 controller
+ * to "operational".  Without this, the ps3 controller will not report any
+ * events.
+ */
+static void hid_fixup_sony_ps3_controller(struct usb_device *dev, int ifnum)
+{
+       int result;
+       char *buf = kmalloc(18, GFP_KERNEL);
+
+       if (!buf)
+               return;
+
+       result = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
+                                HID_REQ_GET_REPORT,
+                                USB_DIR_IN | USB_TYPE_CLASS |
+                                USB_RECIP_INTERFACE,
+                                (3 << 8) | 0xf2, ifnum, buf, 17,
+                                USB_CTRL_GET_TIMEOUT);
+
+       if (result < 0)
+               err("%s failed: %d\n", __func__, result);
+
+       kfree(buf);
+}
+
+/*
+ * Logitech S510 keyboard sends in report #3 keys which are far
+ * above the logical maximum described in descriptor. This extends
+ * the original value of 0x28c of logical maximum to 0x104d
+ */
+static void hid_fixup_s510_descriptor(unsigned char *rdesc, int rsize)
+{
+       if (rsize >= 90 && rdesc[83] == 0x26
+                       && rdesc[84] == 0x8c
+                       && rdesc[85] == 0x02) {
+               info("Fixing up Logitech S510 report descriptor");
+               rdesc[84] = rdesc[89] = 0x4d;
+               rdesc[85] = rdesc[90] = 0x10;
+       }
+}
+
+static struct hid_device *usb_hid_configure(struct usb_interface *intf)
+{
+       struct usb_host_interface *interface = intf->cur_altsetting;
+       struct usb_device *dev = interface_to_usbdev (intf);
+       struct hid_descriptor *hdesc;
+       struct hid_device *hid;
+       unsigned quirks = 0, rsize = 0;
+       char *rdesc;
+       int n, len, insize = 0;
+       struct usbhid_device *usbhid;
+
+       /* Ignore all Wacom devices */
+       if (le16_to_cpu(dev->descriptor.idVendor) == USB_VENDOR_ID_WACOM)
+               return NULL;
+       /* ignore all Code Mercenaries IOWarrior devices */
+       if (le16_to_cpu(dev->descriptor.idVendor) == USB_VENDOR_ID_CODEMERCS)
+               if (le16_to_cpu(dev->descriptor.idProduct) >= USB_DEVICE_ID_CODEMERCS_IOW_FIRST &&
+                   le16_to_cpu(dev->descriptor.idProduct) <= USB_DEVICE_ID_CODEMERCS_IOW_LAST)
+                       return NULL;
+
+       for (n = 0; hid_blacklist[n].idVendor; n++)
+               if ((hid_blacklist[n].idVendor == le16_to_cpu(dev->descriptor.idVendor)) &&
+                       (hid_blacklist[n].idProduct == le16_to_cpu(dev->descriptor.idProduct)))
+                               quirks = hid_blacklist[n].quirks;
+
+       /* Many keyboards and mice don't like to be polled for reports,
+        * so we will always set the HID_QUIRK_NOGET flag for them. */
+       if (interface->desc.bInterfaceSubClass == USB_INTERFACE_SUBCLASS_BOOT) {
+               if (interface->desc.bInterfaceProtocol == USB_INTERFACE_PROTOCOL_KEYBOARD ||
+                       interface->desc.bInterfaceProtocol == USB_INTERFACE_PROTOCOL_MOUSE)
+                               quirks |= HID_QUIRK_NOGET;
+       }
+
+       if (quirks & HID_QUIRK_IGNORE)
+               return NULL;
+
+       if ((quirks & HID_QUIRK_IGNORE_MOUSE) &&
+               (interface->desc.bInterfaceProtocol == USB_INTERFACE_PROTOCOL_MOUSE))
+                       return NULL;
+
+
+       if (usb_get_extra_descriptor(interface, HID_DT_HID, &hdesc) &&
+           (!interface->desc.bNumEndpoints ||
+            usb_get_extra_descriptor(&interface->endpoint[0], HID_DT_HID, &hdesc))) {
+               dbg("class descriptor not present\n");
+               return NULL;
+       }
+
+       for (n = 0; n < hdesc->bNumDescriptors; n++)
+               if (hdesc->desc[n].bDescriptorType == HID_DT_REPORT)
+                       rsize = le16_to_cpu(hdesc->desc[n].wDescriptorLength);
+
+       if (!rsize || rsize > HID_MAX_DESCRIPTOR_SIZE) {
+               dbg("weird size of report descriptor (%u)", rsize);
+               return NULL;
+       }
+
+       if (!(rdesc = kmalloc(rsize, GFP_KERNEL))) {
+               dbg("couldn't allocate rdesc memory");
+               return NULL;
+       }
+
+       hid_set_idle(dev, interface->desc.bInterfaceNumber, 0, 0);
+
+       if ((n = hid_get_class_descriptor(dev, interface->desc.bInterfaceNumber, HID_DT_REPORT, rdesc, rsize)) < 0) {
+               dbg("reading report descriptor failed");
+               kfree(rdesc);
+               return NULL;
+       }
+
+       if ((quirks & HID_QUIRK_CYMOTION))
+               hid_fixup_cymotion_descriptor(rdesc, rsize);
+
+       if (quirks & HID_QUIRK_LOGITECH_S510_DESCRIPTOR)
+               hid_fixup_s510_descriptor(rdesc, rsize);
+
+#ifdef CONFIG_HID_DEBUG
+       printk(KERN_DEBUG __FILE__ ": report descriptor (size %u, read %d) = ", rsize, n);
+       for (n = 0; n < rsize; n++)
+               printk(" %02x", (unsigned char) rdesc[n]);
+       printk("\n");
+#endif
+
+       if (!(hid = hid_parse_report(rdesc, n))) {
+               dbg("parsing report descriptor failed");
+               kfree(rdesc);
+               return NULL;
+       }
+
+       kfree(rdesc);
+       hid->quirks = quirks;
+
+       if (!(usbhid = kzalloc(sizeof(struct usbhid_device), GFP_KERNEL)))
+               goto fail;
+
+       hid->driver_data = usbhid;
+       usbhid->hid = hid;
+
+       usbhid->bufsize = HID_MIN_BUFFER_SIZE;
+       hid_find_max_report(hid, HID_INPUT_REPORT, &usbhid->bufsize);
+       hid_find_max_report(hid, HID_OUTPUT_REPORT, &usbhid->bufsize);
+       hid_find_max_report(hid, HID_FEATURE_REPORT, &usbhid->bufsize);
+
+       if (usbhid->bufsize > HID_MAX_BUFFER_SIZE)
+               usbhid->bufsize = HID_MAX_BUFFER_SIZE;
+
+       hid_find_max_report(hid, HID_INPUT_REPORT, &insize);
+
+       if (insize > HID_MAX_BUFFER_SIZE)
+               insize = HID_MAX_BUFFER_SIZE;
+
+       if (hid_alloc_buffers(dev, hid)) {
+               hid_free_buffers(dev, hid);
+               goto fail;
+       }
+
+       for (n = 0; n < interface->desc.bNumEndpoints; n++) {
+
+               struct usb_endpoint_descriptor *endpoint;
+               int pipe;
+               int interval;
+
+               endpoint = &interface->endpoint[n].desc;
+               if ((endpoint->bmAttributes & 3) != 3)          /* Not an interrupt endpoint */
+                       continue;
+
+               interval = endpoint->bInterval;
+
+               /* Change the polling interval of mice. */
+               if (hid->collection->usage == HID_GD_MOUSE && hid_mousepoll_interval > 0)
+                       interval = hid_mousepoll_interval;
+
+               if (usb_endpoint_dir_in(endpoint)) {
+                       if (usbhid->urbin)
+                               continue;
+                       if (!(usbhid->urbin = usb_alloc_urb(0, GFP_KERNEL)))
+                               goto fail;
+                       pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);
+                       usb_fill_int_urb(usbhid->urbin, dev, pipe, usbhid->inbuf, insize,
+                                        hid_irq_in, hid, interval);
+                       usbhid->urbin->transfer_dma = usbhid->inbuf_dma;
+                       usbhid->urbin->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+               } else {
+                       if (usbhid->urbout)
+                               continue;
+                       if (!(usbhid->urbout = usb_alloc_urb(0, GFP_KERNEL)))
+                               goto fail;
+                       pipe = usb_sndintpipe(dev, endpoint->bEndpointAddress);
+                       usb_fill_int_urb(usbhid->urbout, dev, pipe, usbhid->outbuf, 0,
+                                        hid_irq_out, hid, interval);
+                       usbhid->urbout->transfer_dma = usbhid->outbuf_dma;
+                       usbhid->urbout->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+               }
+       }
+
+       if (!usbhid->urbin) {
+               err("couldn't find an input interrupt endpoint");
+               goto fail;
+       }
+
+       init_waitqueue_head(&hid->wait);
+
+       INIT_WORK(&usbhid->reset_work, hid_reset);
+       setup_timer(&usbhid->io_retry, hid_retry_timeout, (unsigned long) hid);
+
+       spin_lock_init(&usbhid->inlock);
+       spin_lock_init(&usbhid->outlock);
+       spin_lock_init(&usbhid->ctrllock);
+
+       hid->version = le16_to_cpu(hdesc->bcdHID);
+       hid->country = hdesc->bCountryCode;
+       hid->dev = &intf->dev;
+       usbhid->intf = intf;
+       usbhid->ifnum = interface->desc.bInterfaceNumber;
+
+       hid->name[0] = 0;
+
+       if (dev->manufacturer)
+               strlcpy(hid->name, dev->manufacturer, sizeof(hid->name));
+
+       if (dev->product) {
+               if (dev->manufacturer)
+                       strlcat(hid->name, " ", sizeof(hid->name));
+               strlcat(hid->name, dev->product, sizeof(hid->name));
+       }
+
+       if (!strlen(hid->name))
+               snprintf(hid->name, sizeof(hid->name), "HID %04x:%04x",
+                        le16_to_cpu(dev->descriptor.idVendor),
+                        le16_to_cpu(dev->descriptor.idProduct));
+
+       hid->bus = BUS_USB;
+       hid->vendor = le16_to_cpu(dev->descriptor.idVendor);
+       hid->product = le16_to_cpu(dev->descriptor.idProduct);
+
+       usb_make_path(dev, hid->phys, sizeof(hid->phys));
+       strlcat(hid->phys, "/input", sizeof(hid->phys));
+       len = strlen(hid->phys);
+       if (len < sizeof(hid->phys) - 1)
+               snprintf(hid->phys + len, sizeof(hid->phys) - len,
+                        "%d", intf->altsetting[0].desc.bInterfaceNumber);
+
+       if (usb_string(dev, dev->descriptor.iSerialNumber, hid->uniq, 64) <= 0)
+               hid->uniq[0] = 0;
+
+       usbhid->urbctrl = usb_alloc_urb(0, GFP_KERNEL);
+       if (!usbhid->urbctrl)
+               goto fail;
+
+       usb_fill_control_urb(usbhid->urbctrl, dev, 0, (void *) usbhid->cr,
+                            usbhid->ctrlbuf, 1, hid_ctrl, hid);
+       usbhid->urbctrl->setup_dma = usbhid->cr_dma;
+       usbhid->urbctrl->transfer_dma = usbhid->ctrlbuf_dma;
+       usbhid->urbctrl->transfer_flags |= (URB_NO_TRANSFER_DMA_MAP | URB_NO_SETUP_DMA_MAP);
+       hid->hidinput_input_event = usb_hidinput_input_event;
+       hid->hid_open = usbhid_open;
+       hid->hid_close = usbhid_close;
+#ifdef CONFIG_USB_HIDDEV
+       hid->hiddev_hid_event = hiddev_hid_event;
+       hid->hiddev_report_event = hiddev_report_event;
+#endif
+       return hid;
+
+fail:
+       usb_free_urb(usbhid->urbin);
+       usb_free_urb(usbhid->urbout);
+       usb_free_urb(usbhid->urbctrl);
+       hid_free_buffers(dev, hid);
+       hid_free_device(hid);
+
+       return NULL;
+}
+
+static void hid_disconnect(struct usb_interface *intf)
+{
+       struct hid_device *hid = usb_get_intfdata (intf);
+       struct usbhid_device *usbhid;
+
+       if (!hid)
+               return;
+
+       usbhid = hid->driver_data;
+
+       spin_lock_irq(&usbhid->inlock); /* Sync with error handler */
+       usb_set_intfdata(intf, NULL);
+       spin_unlock_irq(&usbhid->inlock);
+       usb_kill_urb(usbhid->urbin);
+       usb_kill_urb(usbhid->urbout);
+       usb_kill_urb(usbhid->urbctrl);
+
+       del_timer_sync(&usbhid->io_retry);
+       flush_scheduled_work();
+
+       if (hid->claimed & HID_CLAIMED_INPUT)
+               hidinput_disconnect(hid);
+       if (hid->claimed & HID_CLAIMED_HIDDEV)
+               hiddev_disconnect(hid);
+
+       usb_free_urb(usbhid->urbin);
+       usb_free_urb(usbhid->urbctrl);
+       usb_free_urb(usbhid->urbout);
+
+       hid_free_buffers(hid_to_usb_dev(hid), hid);
+       hid_free_device(hid);
+}
+
+static int hid_probe(struct usb_interface *intf, const struct usb_device_id *id)
+{
+       struct hid_device *hid;
+       char path[64];
+       int i;
+       char *c;
+
+       dbg("HID probe called for ifnum %d",
+                       intf->altsetting->desc.bInterfaceNumber);
+
+       if (!(hid = usb_hid_configure(intf)))
+               return -ENODEV;
+
+       usbhid_init_reports(hid);
+       hid_dump_device(hid);
+
+       if (!hidinput_connect(hid))
+               hid->claimed |= HID_CLAIMED_INPUT;
+       if (!hiddev_connect(hid))
+               hid->claimed |= HID_CLAIMED_HIDDEV;
+
+       usb_set_intfdata(intf, hid);
+
+       if (!hid->claimed) {
+               printk ("HID device not claimed by input or hiddev\n");
+               hid_disconnect(intf);
+               return -ENODEV;
+       }
+
+       if ((hid->claimed & HID_CLAIMED_INPUT))
+               hid_ff_init(hid);
+
+       if (hid->quirks & HID_QUIRK_SONY_PS3_CONTROLLER)
+               hid_fixup_sony_ps3_controller(interface_to_usbdev(intf),
+                       intf->cur_altsetting->desc.bInterfaceNumber);
+
+       printk(KERN_INFO);
+
+       if (hid->claimed & HID_CLAIMED_INPUT)
+               printk("input");
+       if (hid->claimed == (HID_CLAIMED_INPUT | HID_CLAIMED_HIDDEV))
+               printk(",");
+       if (hid->claimed & HID_CLAIMED_HIDDEV)
+               printk("hiddev%d", hid->minor);
+
+       c = "Device";
+       for (i = 0; i < hid->maxcollection; i++) {
+               if (hid->collection[i].type == HID_COLLECTION_APPLICATION &&
+                   (hid->collection[i].usage & HID_USAGE_PAGE) == HID_UP_GENDESK &&
+                   (hid->collection[i].usage & 0xffff) < ARRAY_SIZE(hid_types)) {
+                       c = hid_types[hid->collection[i].usage & 0xffff];
+                       break;
+               }
+       }
+
+       usb_make_path(interface_to_usbdev(intf), path, 63);
+
+       printk(": USB HID v%x.%02x %s [%s] on %s\n",
+               hid->version >> 8, hid->version & 0xff, c, hid->name, path);
+
+       return 0;
+}
+
+static int hid_suspend(struct usb_interface *intf, pm_message_t message)
+{
+       struct hid_device *hid = usb_get_intfdata (intf);
+       struct usbhid_device *usbhid = hid->driver_data;
+
+       spin_lock_irq(&usbhid->inlock); /* Sync with error handler */
+       set_bit(HID_SUSPENDED, &usbhid->iofl);
+       spin_unlock_irq(&usbhid->inlock);
+       del_timer(&usbhid->io_retry);
+       usb_kill_urb(usbhid->urbin);
+       dev_dbg(&intf->dev, "suspend\n");
+       return 0;
+}
+
+static int hid_resume(struct usb_interface *intf)
+{
+       struct hid_device *hid = usb_get_intfdata (intf);
+       struct usbhid_device *usbhid = hid->driver_data;
+       int status;
+
+       clear_bit(HID_SUSPENDED, &usbhid->iofl);
+       usbhid->retry_delay = 0;
+       status = hid_start_in(hid);
+       dev_dbg(&intf->dev, "resume status %d\n", status);
+       return status;
+}
+
+/* Treat USB reset pretty much the same as suspend/resume */
+static void hid_pre_reset(struct usb_interface *intf)
+{
+       /* FIXME: What if the interface is already suspended? */
+       hid_suspend(intf, PMSG_ON);
+}
+
+static void hid_post_reset(struct usb_interface *intf)
+{
+       struct usb_device *dev = interface_to_usbdev (intf);
+
+       hid_set_idle(dev, intf->cur_altsetting->desc.bInterfaceNumber, 0, 0);
+       /* FIXME: Any more reinitialization needed? */
+
+       hid_resume(intf);
+}
+
+static struct usb_device_id hid_usb_ids [] = {
+       { .match_flags = USB_DEVICE_ID_MATCH_INT_CLASS,
+               .bInterfaceClass = USB_INTERFACE_CLASS_HID },
+       { }                                             /* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE (usb, hid_usb_ids);
+
+static struct usb_driver hid_driver = {
+       .name =         "usbhid",
+       .probe =        hid_probe,
+       .disconnect =   hid_disconnect,
+       .suspend =      hid_suspend,
+       .resume =       hid_resume,
+       .pre_reset =    hid_pre_reset,
+       .post_reset =   hid_post_reset,
+       .id_table =     hid_usb_ids,
+};
+
+static int __init hid_init(void)
+{
+       int retval;
+       retval = hiddev_init();
+       if (retval)
+               goto hiddev_init_fail;
+       retval = usb_register(&hid_driver);
+       if (retval)
+               goto usb_register_fail;
+       info(DRIVER_VERSION ":" DRIVER_DESC);
+
+       return 0;
+usb_register_fail:
+       hiddev_exit();
+hiddev_init_fail:
+       return retval;
+}
+
+static void __exit hid_exit(void)
+{
+       usb_deregister(&hid_driver);
+       hiddev_exit();
+}
+
+module_init(hid_init);
+module_exit(hid_exit);
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE(DRIVER_LICENSE);
diff --git a/drivers/hid/usbhid/hid-ff.c b/drivers/hid/usbhid/hid-ff.c
new file mode 100644 (file)
index 0000000..e431faa
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ * $Id: hid-ff.c,v 1.2 2002/04/18 22:02:47 jdeneux Exp $
+ *
+ *  Force feedback support for hid devices.
+ *  Not all hid devices use the same protocol. For example, some use PID,
+ *  other use their own proprietary procotol.
+ *
+ *  Copyright (c) 2002-2004 Johann Deneux
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Should you need to contact me, the author, you can do so by
+ * e-mail - mail your message to <johann.deneux@it.uu.se>
+ */
+
+#include <linux/input.h>
+
+#undef DEBUG
+#include <linux/usb.h>
+
+#include <linux/hid.h>
+#include "usbhid.h"
+
+/*
+ * This table contains pointers to initializers. To add support for new
+ * devices, you need to add the USB vendor and product ids here.
+ */
+struct hid_ff_initializer {
+       u16 idVendor;
+       u16 idProduct;
+       int (*init)(struct hid_device*);
+};
+
+/*
+ * We try pidff when no other driver is found because PID is the
+ * standards compliant way of implementing force feedback in HID.
+ * pidff_init() will quickly abort if the device doesn't appear to
+ * be a PID device
+ */
+static struct hid_ff_initializer inits[] = {
+#ifdef CONFIG_LOGITECH_FF
+       { 0x46d, 0xc211, hid_lgff_init }, /* Logitech Cordless rumble pad */
+       { 0x46d, 0xc219, hid_lgff_init }, /* Logitech Cordless rumble pad 2 */
+       { 0x46d, 0xc283, hid_lgff_init }, /* Logitech Wingman Force 3d */
+       { 0x46d, 0xc294, hid_lgff_init }, /* Logitech Formula Force EX */
+       { 0x46d, 0xc295, hid_lgff_init }, /* Logitech MOMO force wheel */
+       { 0x46d, 0xca03, hid_lgff_init }, /* Logitech MOMO force wheel */
+#endif
+#ifdef CONFIG_PANTHERLORD_FF
+       { 0x810, 0x0001, hid_plff_init },
+#endif
+#ifdef CONFIG_THRUSTMASTER_FF
+       { 0x44f, 0xb304, hid_tmff_init },
+#endif
+#ifdef CONFIG_ZEROPLUS_FF
+       { 0xc12, 0x0005, hid_zpff_init },
+       { 0xc12, 0x0030, hid_zpff_init },
+#endif
+       { 0,     0,      hid_pidff_init}  /* Matches anything */
+};
+
+int hid_ff_init(struct hid_device* hid)
+{
+       struct hid_ff_initializer *init;
+       int vendor = le16_to_cpu(hid_to_usb_dev(hid)->descriptor.idVendor);
+       int product = le16_to_cpu(hid_to_usb_dev(hid)->descriptor.idProduct);
+
+       for (init = inits; init->idVendor; init++)
+               if (init->idVendor == vendor && init->idProduct == product)
+                       break;
+
+       return init->init(hid);
+}
+EXPORT_SYMBOL_GPL(hid_ff_init);
+
diff --git a/drivers/hid/usbhid/hid-lgff.c b/drivers/hid/usbhid/hid-lgff.c
new file mode 100644 (file)
index 0000000..e6f3af3
--- /dev/null
@@ -0,0 +1,150 @@
+/*
+ * Force feedback support for hid-compliant for some of the devices from
+ * Logitech, namely:
+ * - WingMan Cordless RumblePad
+ * - WingMan Force 3D
+ *
+ *  Copyright (c) 2002-2004 Johann Deneux
+ *  Copyright (c) 2006 Anssi Hannula <anssi.hannula@gmail.com>
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Should you need to contact me, the author, you can do so by
+ * e-mail - mail your message to <johann.deneux@it.uu.se>
+ */
+
+#include <linux/input.h>
+#include <linux/usb.h>
+#include <linux/hid.h>
+#include "usbhid.h"
+
+struct dev_type {
+       u16 idVendor;
+       u16 idProduct;
+       const signed short *ff;
+};
+
+static const signed short ff_rumble[] = {
+       FF_RUMBLE,
+       -1
+};
+
+static const signed short ff_joystick[] = {
+       FF_CONSTANT,
+       -1
+};
+
+static const struct dev_type devices[] = {
+       { 0x046d, 0xc211, ff_rumble },
+       { 0x046d, 0xc219, ff_rumble },
+       { 0x046d, 0xc283, ff_joystick },
+       { 0x046d, 0xc294, ff_joystick },
+       { 0x046d, 0xc295, ff_joystick },
+       { 0x046d, 0xca03, ff_joystick },
+};
+
+static int hid_lgff_play(struct input_dev *dev, void *data, struct ff_effect *effect)
+{
+       struct hid_device *hid = dev->private;
+       struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list;
+       struct hid_report *report = list_entry(report_list->next, struct hid_report, list);
+       int x, y;
+       unsigned int left, right;
+
+#define CLAMP(x) if (x < 0) x = 0; if (x > 0xff) x = 0xff
+
+       switch (effect->type) {
+       case FF_CONSTANT:
+               x = effect->u.ramp.start_level + 0x7f;  /* 0x7f is center */
+               y = effect->u.ramp.end_level + 0x7f;
+               CLAMP(x);
+               CLAMP(y);
+               report->field[0]->value[0] = 0x51;
+               report->field[0]->value[1] = 0x08;
+               report->field[0]->value[2] = x;
+               report->field[0]->value[3] = y;
+               dbg("(x, y)=(%04x, %04x)", x, y);
+               usbhid_submit_report(hid, report, USB_DIR_OUT);
+               break;
+
+       case FF_RUMBLE:
+               right = effect->u.rumble.strong_magnitude;
+               left = effect->u.rumble.weak_magnitude;
+               right = right * 0xff / 0xffff;
+               left = left * 0xff / 0xffff;
+               CLAMP(left);
+               CLAMP(right);
+               report->field[0]->value[0] = 0x42;
+               report->field[0]->value[1] = 0x00;
+               report->field[0]->value[2] = left;
+               report->field[0]->value[3] = right;
+               dbg("(left, right)=(%04x, %04x)", left, right);
+               usbhid_submit_report(hid, report, USB_DIR_OUT);
+               break;
+       }
+       return 0;
+}
+
+int hid_lgff_init(struct hid_device* hid)
+{
+       struct hid_input *hidinput = list_entry(hid->inputs.next, struct hid_input, list);
+       struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list;
+       struct input_dev *dev = hidinput->input;
+       struct hid_report *report;
+       struct hid_field *field;
+       const signed short *ff_bits = ff_joystick;
+       int error;
+       int i;
+
+       /* Find the report to use */
+       if (list_empty(report_list)) {
+               err("No output report found");
+               return -1;
+       }
+
+       /* Check that the report looks ok */
+       report = list_entry(report_list->next, struct hid_report, list);
+       if (!report) {
+               err("NULL output report");
+               return -1;
+       }
+
+       field = report->field[0];
+       if (!field) {
+               err("NULL field");
+               return -1;
+       }
+
+       for (i = 0; i < ARRAY_SIZE(devices); i++) {
+               if (dev->id.vendor == devices[i].idVendor &&
+                   dev->id.product == devices[i].idProduct) {
+                       ff_bits = devices[i].ff;
+                       break;
+               }
+       }
+
+       for (i = 0; ff_bits[i] >= 0; i++)
+               set_bit(ff_bits[i], dev->ffbit);
+
+       error = input_ff_create_memless(dev, NULL, hid_lgff_play);
+       if (error)
+               return error;
+
+       printk(KERN_INFO "Force feedback for Logitech force feedback devices by Johann Deneux <johann.deneux@it.uu.se>\n");
+
+       return 0;
+}
diff --git a/drivers/hid/usbhid/hid-pidff.c b/drivers/hid/usbhid/hid-pidff.c
new file mode 100644 (file)
index 0000000..f5a90e9
--- /dev/null
@@ -0,0 +1,1331 @@
+/*
+ *  Force feedback driver for USB HID PID compliant devices
+ *
+ *  Copyright (c) 2005, 2006 Anssi Hannula <anssi.hannula@gmail.com>
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/* #define DEBUG */
+
+#define debug(format, arg...) pr_debug("hid-pidff: " format "\n" , ## arg)
+
+#include <linux/input.h>
+#include <linux/usb.h>
+
+#include <linux/hid.h>
+
+#include "usbhid.h"
+
+#define        PID_EFFECTS_MAX         64
+
+/* Report usage table used to put reports into an array */
+
+#define PID_SET_EFFECT         0
+#define PID_EFFECT_OPERATION   1
+#define PID_DEVICE_GAIN                2
+#define PID_POOL               3
+#define PID_BLOCK_LOAD         4
+#define PID_BLOCK_FREE         5
+#define PID_DEVICE_CONTROL     6
+#define PID_CREATE_NEW_EFFECT  7
+
+#define PID_REQUIRED_REPORTS   7
+
+#define PID_SET_ENVELOPE       8
+#define PID_SET_CONDITION      9
+#define PID_SET_PERIODIC       10
+#define PID_SET_CONSTANT       11
+#define PID_SET_RAMP           12
+static const u8 pidff_reports[] = {
+       0x21, 0x77, 0x7d, 0x7f, 0x89, 0x90, 0x96, 0xab,
+       0x5a, 0x5f, 0x6e, 0x73, 0x74
+};
+
+/* device_control is really 0x95, but 0x96 specified as it is the usage of
+the only field in that report */
+
+/* Value usage tables used to put fields and values into arrays */
+
+#define PID_EFFECT_BLOCK_INDEX 0
+
+#define PID_DURATION           1
+#define PID_GAIN               2
+#define PID_TRIGGER_BUTTON     3
+#define PID_TRIGGER_REPEAT_INT 4
+#define PID_DIRECTION_ENABLE   5
+#define PID_START_DELAY                6
+static const u8 pidff_set_effect[] = {
+       0x22, 0x50, 0x52, 0x53, 0x54, 0x56, 0xa7
+};
+
+#define PID_ATTACK_LEVEL       1
+#define PID_ATTACK_TIME                2
+#define PID_FADE_LEVEL         3
+#define PID_FADE_TIME          4
+static const u8 pidff_set_envelope[] = { 0x22, 0x5b, 0x5c, 0x5d, 0x5e };
+
+#define PID_PARAM_BLOCK_OFFSET 1
+#define PID_CP_OFFSET          2
+#define PID_POS_COEFFICIENT    3
+#define PID_NEG_COEFFICIENT    4
+#define PID_POS_SATURATION     5
+#define PID_NEG_SATURATION     6
+#define PID_DEAD_BAND          7
+static const u8 pidff_set_condition[] = {
+       0x22, 0x23, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65
+};
+
+#define PID_MAGNITUDE          1
+#define PID_OFFSET             2
+#define PID_PHASE              3
+#define PID_PERIOD             4
+static const u8 pidff_set_periodic[] = { 0x22, 0x70, 0x6f, 0x71, 0x72 };
+static const u8 pidff_set_constant[] = { 0x22, 0x70 };
+
+#define PID_RAMP_START         1
+#define PID_RAMP_END           2
+static const u8 pidff_set_ramp[] = { 0x22, 0x75, 0x76 };
+
+#define PID_RAM_POOL_AVAILABLE 1
+static const u8 pidff_block_load[] = { 0x22, 0xac };
+
+#define PID_LOOP_COUNT         1
+static const u8 pidff_effect_operation[] = { 0x22, 0x7c };
+
+static const u8 pidff_block_free[] = { 0x22 };
+
+#define PID_DEVICE_GAIN_FIELD  0
+static const u8 pidff_device_gain[] = { 0x7e };
+
+#define PID_RAM_POOL_SIZE      0
+#define PID_SIMULTANEOUS_MAX   1
+#define PID_DEVICE_MANAGED_POOL        2
+static const u8 pidff_pool[] = { 0x80, 0x83, 0xa9 };
+
+/* Special field key tables used to put special field keys into arrays */
+
+#define PID_ENABLE_ACTUATORS   0
+#define PID_RESET              1
+static const u8 pidff_device_control[] = { 0x97, 0x9a };
+
+#define PID_CONSTANT   0
+#define PID_RAMP       1
+#define PID_SQUARE     2
+#define PID_SINE       3
+#define PID_TRIANGLE   4
+#define PID_SAW_UP     5
+#define PID_SAW_DOWN   6
+#define PID_SPRING     7
+#define PID_DAMPER     8
+#define PID_INERTIA    9
+#define PID_FRICTION   10
+static const u8 pidff_effect_types[] = {
+       0x26, 0x27, 0x30, 0x31, 0x32, 0x33, 0x34,
+       0x40, 0x41, 0x42, 0x43
+};
+
+#define PID_BLOCK_LOAD_SUCCESS 0
+#define PID_BLOCK_LOAD_FULL    1
+static const u8 pidff_block_load_status[] = { 0x8c, 0x8d };
+
+#define PID_EFFECT_START       0
+#define PID_EFFECT_STOP                1
+static const u8 pidff_effect_operation_status[] = { 0x79, 0x7b };
+
+struct pidff_usage {
+       struct hid_field *field;
+       s32 *value;
+};
+
+struct pidff_device {
+       struct hid_device *hid;
+
+       struct hid_report *reports[sizeof(pidff_reports)];
+
+       struct pidff_usage set_effect[sizeof(pidff_set_effect)];
+       struct pidff_usage set_envelope[sizeof(pidff_set_envelope)];
+       struct pidff_usage set_condition[sizeof(pidff_set_condition)];
+       struct pidff_usage set_periodic[sizeof(pidff_set_periodic)];
+       struct pidff_usage set_constant[sizeof(pidff_set_constant)];
+       struct pidff_usage set_ramp[sizeof(pidff_set_ramp)];
+
+       struct pidff_usage device_gain[sizeof(pidff_device_gain)];
+       struct pidff_usage block_load[sizeof(pidff_block_load)];
+       struct pidff_usage pool[sizeof(pidff_pool)];
+       struct pidff_usage effect_operation[sizeof(pidff_effect_operation)];
+       struct pidff_usage block_free[sizeof(pidff_block_free)];
+
+       /* Special field is a field that is not composed of
+          usage<->value pairs that pidff_usage values are */
+
+       /* Special field in create_new_effect */
+       struct hid_field *create_new_effect_type;
+
+       /* Special fields in set_effect */
+       struct hid_field *set_effect_type;
+       struct hid_field *effect_direction;
+
+       /* Special field in device_control */
+       struct hid_field *device_control;
+
+       /* Special field in block_load */
+       struct hid_field *block_load_status;
+
+       /* Special field in effect_operation */
+       struct hid_field *effect_operation_status;
+
+       int control_id[sizeof(pidff_device_control)];
+       int type_id[sizeof(pidff_effect_types)];
+       int status_id[sizeof(pidff_block_load_status)];
+       int operation_id[sizeof(pidff_effect_operation_status)];
+
+       int pid_id[PID_EFFECTS_MAX];
+};
+
+/*
+ * Scale an unsigned value with range 0..max for the given field
+ */
+static int pidff_rescale(int i, int max, struct hid_field *field)
+{
+       return i * (field->logical_maximum - field->logical_minimum) / max +
+           field->logical_minimum;
+}
+
+/*
+ * Scale a signed value in range -0x8000..0x7fff for the given field
+ */
+static int pidff_rescale_signed(int i, struct hid_field *field)
+{
+       return i == 0 ? 0 : i >
+           0 ? i * field->logical_maximum / 0x7fff : i *
+           field->logical_minimum / -0x8000;
+}
+
+static void pidff_set(struct pidff_usage *usage, u16 value)
+{
+       usage->value[0] = pidff_rescale(value, 0xffff, usage->field);
+       debug("calculated from %d to %d", value, usage->value[0]);
+}
+
+static void pidff_set_signed(struct pidff_usage *usage, s16 value)
+{
+       if (usage->field->logical_minimum < 0)
+               usage->value[0] = pidff_rescale_signed(value, usage->field);
+       else {
+               if (value < 0)
+                       usage->value[0] =
+                           pidff_rescale(-value, 0x8000, usage->field);
+               else
+                       usage->value[0] =
+                           pidff_rescale(value, 0x7fff, usage->field);
+       }
+       debug("calculated from %d to %d", value, usage->value[0]);
+}
+
+/*
+ * Send envelope report to the device
+ */
+static void pidff_set_envelope_report(struct pidff_device *pidff,
+                                     struct ff_envelope *envelope)
+{
+       pidff->set_envelope[PID_EFFECT_BLOCK_INDEX].value[0] =
+           pidff->block_load[PID_EFFECT_BLOCK_INDEX].value[0];
+
+       pidff->set_envelope[PID_ATTACK_LEVEL].value[0] =
+           pidff_rescale(envelope->attack_level >
+                         0x7fff ? 0x7fff : envelope->attack_level, 0x7fff,
+                         pidff->set_envelope[PID_ATTACK_LEVEL].field);
+       pidff->set_envelope[PID_FADE_LEVEL].value[0] =
+           pidff_rescale(envelope->fade_level >
+                         0x7fff ? 0x7fff : envelope->fade_level, 0x7fff,
+                         pidff->set_envelope[PID_FADE_LEVEL].field);
+
+       pidff->set_envelope[PID_ATTACK_TIME].value[0] = envelope->attack_length;
+       pidff->set_envelope[PID_FADE_TIME].value[0] = envelope->fade_length;
+
+       debug("attack %u => %d", envelope->attack_level,
+             pidff->set_envelope[PID_ATTACK_LEVEL].value[0]);
+
+       usbhid_submit_report(pidff->hid, pidff->reports[PID_SET_ENVELOPE],
+                         USB_DIR_OUT);
+}
+
+/*
+ * Test if the new envelope differs from old one
+ */
+static int pidff_needs_set_envelope(struct ff_envelope *envelope,
+                                   struct ff_envelope *old)
+{
+       return envelope->attack_level != old->attack_level ||
+              envelope->fade_level != old->fade_level ||
+              envelope->attack_length != old->attack_length ||
+              envelope->fade_length != old->fade_length;
+}
+
+/*
+ * Send constant force report to the device
+ */
+static void pidff_set_constant_force_report(struct pidff_device *pidff,
+                                           struct ff_effect *effect)
+{
+       pidff->set_constant[PID_EFFECT_BLOCK_INDEX].value[0] =
+               pidff->block_load[PID_EFFECT_BLOCK_INDEX].value[0];
+       pidff_set_signed(&pidff->set_constant[PID_MAGNITUDE],
+                        effect->u.constant.level);
+
+       usbhid_submit_report(pidff->hid, pidff->reports[PID_SET_CONSTANT],
+                         USB_DIR_OUT);
+}
+
+/*
+ * Test if the constant parameters have changed between effects
+ */
+static int pidff_needs_set_constant(struct ff_effect *effect,
+                                   struct ff_effect *old)
+{
+       return effect->u.constant.level != old->u.constant.level;
+}
+
+/*
+ * Send set effect report to the device
+ */
+static void pidff_set_effect_report(struct pidff_device *pidff,
+                                   struct ff_effect *effect)
+{
+       pidff->set_effect[PID_EFFECT_BLOCK_INDEX].value[0] =
+               pidff->block_load[PID_EFFECT_BLOCK_INDEX].value[0];
+       pidff->set_effect_type->value[0] =
+               pidff->create_new_effect_type->value[0];
+       pidff->set_effect[PID_DURATION].value[0] = effect->replay.length;
+       pidff->set_effect[PID_TRIGGER_BUTTON].value[0] = effect->trigger.button;
+       pidff->set_effect[PID_TRIGGER_REPEAT_INT].value[0] =
+               effect->trigger.interval;
+       pidff->set_effect[PID_GAIN].value[0] =
+               pidff->set_effect[PID_GAIN].field->logical_maximum;
+       pidff->set_effect[PID_DIRECTION_ENABLE].value[0] = 1;
+       pidff->effect_direction->value[0] =
+               pidff_rescale(effect->direction, 0xffff,
+                               pidff->effect_direction);
+       pidff->set_effect[PID_START_DELAY].value[0] = effect->replay.delay;
+
+       usbhid_submit_report(pidff->hid, pidff->reports[PID_SET_EFFECT],
+                         USB_DIR_OUT);
+}
+
+/*
+ * Test if the values used in set_effect have changed
+ */
+static int pidff_needs_set_effect(struct ff_effect *effect,
+                                 struct ff_effect *old)
+{
+       return effect->replay.length != old->replay.length ||
+              effect->trigger.interval != old->trigger.interval ||
+              effect->trigger.button != old->trigger.button ||
+              effect->direction != old->direction ||
+              effect->replay.delay != old->replay.delay;
+}
+
+/*
+ * Send periodic effect report to the device
+ */
+static void pidff_set_periodic_report(struct pidff_device *pidff,
+                                     struct ff_effect *effect)
+{
+       pidff->set_periodic[PID_EFFECT_BLOCK_INDEX].value[0] =
+               pidff->block_load[PID_EFFECT_BLOCK_INDEX].value[0];
+       pidff_set_signed(&pidff->set_periodic[PID_MAGNITUDE],
+                        effect->u.periodic.magnitude);
+       pidff_set_signed(&pidff->set_periodic[PID_OFFSET],
+                        effect->u.periodic.offset);
+       pidff_set(&pidff->set_periodic[PID_PHASE], effect->u.periodic.phase);
+       pidff->set_periodic[PID_PERIOD].value[0] = effect->u.periodic.period;
+
+       usbhid_submit_report(pidff->hid, pidff->reports[PID_SET_PERIODIC],
+                         USB_DIR_OUT);
+
+}
+
+/*
+ * Test if periodic effect parameters have changed
+ */
+static int pidff_needs_set_periodic(struct ff_effect *effect,
+                                   struct ff_effect *old)
+{
+       return effect->u.periodic.magnitude != old->u.periodic.magnitude ||
+              effect->u.periodic.offset != old->u.periodic.offset ||
+              effect->u.periodic.phase != old->u.periodic.phase ||
+              effect->u.periodic.period != old->u.periodic.period;
+}
+
+/*
+ * Send condition effect reports to the device
+ */
+static void pidff_set_condition_report(struct pidff_device *pidff,
+                                      struct ff_effect *effect)
+{
+       int i;
+
+       pidff->set_condition[PID_EFFECT_BLOCK_INDEX].value[0] =
+               pidff->block_load[PID_EFFECT_BLOCK_INDEX].value[0];
+
+       for (i = 0; i < 2; i++) {
+               pidff->set_condition[PID_PARAM_BLOCK_OFFSET].value[0] = i;
+               pidff_set_signed(&pidff->set_condition[PID_CP_OFFSET],
+                                effect->u.condition[i].center);
+               pidff_set_signed(&pidff->set_condition[PID_POS_COEFFICIENT],
+                                effect->u.condition[i].right_coeff);
+               pidff_set_signed(&pidff->set_condition[PID_NEG_COEFFICIENT],
+                                effect->u.condition[i].left_coeff);
+               pidff_set(&pidff->set_condition[PID_POS_SATURATION],
+                         effect->u.condition[i].right_saturation);
+               pidff_set(&pidff->set_condition[PID_NEG_SATURATION],
+                         effect->u.condition[i].left_saturation);
+               pidff_set(&pidff->set_condition[PID_DEAD_BAND],
+                         effect->u.condition[i].deadband);
+               usbhid_wait_io(pidff->hid);
+               usbhid_submit_report(pidff->hid, pidff->reports[PID_SET_CONDITION],
+                                 USB_DIR_OUT);
+       }
+}
+
+/*
+ * Test if condition effect parameters have changed
+ */
+static int pidff_needs_set_condition(struct ff_effect *effect,
+                                    struct ff_effect *old)
+{
+       int i;
+       int ret = 0;
+
+       for (i = 0; i < 2; i++) {
+               struct ff_condition_effect *cond = &effect->u.condition[i];
+               struct ff_condition_effect *old_cond = &old->u.condition[i];
+
+               ret |= cond->center != old_cond->center ||
+                      cond->right_coeff != old_cond->right_coeff ||
+                      cond->left_coeff != old_cond->left_coeff ||
+                      cond->right_saturation != old_cond->right_saturation ||
+                      cond->left_saturation != old_cond->left_saturation ||
+                      cond->deadband != old_cond->deadband;
+       }
+
+       return ret;
+}
+
+/*
+ * Send ramp force report to the device
+ */
+static void pidff_set_ramp_force_report(struct pidff_device *pidff,
+                                       struct ff_effect *effect)
+{
+       pidff->set_ramp[PID_EFFECT_BLOCK_INDEX].value[0] =
+               pidff->block_load[PID_EFFECT_BLOCK_INDEX].value[0];
+       pidff_set_signed(&pidff->set_ramp[PID_RAMP_START],
+                        effect->u.ramp.start_level);
+       pidff_set_signed(&pidff->set_ramp[PID_RAMP_END],
+                        effect->u.ramp.end_level);
+       usbhid_submit_report(pidff->hid, pidff->reports[PID_SET_RAMP],
+                         USB_DIR_OUT);
+}
+
+/*
+ * Test if ramp force parameters have changed
+ */
+static int pidff_needs_set_ramp(struct ff_effect *effect, struct ff_effect *old)
+{
+       return effect->u.ramp.start_level != old->u.ramp.start_level ||
+              effect->u.ramp.end_level != old->u.ramp.end_level;
+}
+
+/*
+ * Send a request for effect upload to the device
+ *
+ * Returns 0 if device reported success, -ENOSPC if the device reported memory
+ * is full. Upon unknown response the function will retry for 60 times, if
+ * still unsuccessful -EIO is returned.
+ */
+static int pidff_request_effect_upload(struct pidff_device *pidff, int efnum)
+{
+       int j;
+
+       pidff->create_new_effect_type->value[0] = efnum;
+       usbhid_submit_report(pidff->hid, pidff->reports[PID_CREATE_NEW_EFFECT],
+                         USB_DIR_OUT);
+       debug("create_new_effect sent, type: %d", efnum);
+
+       pidff->block_load[PID_EFFECT_BLOCK_INDEX].value[0] = 0;
+       pidff->block_load_status->value[0] = 0;
+       usbhid_wait_io(pidff->hid);
+
+       for (j = 0; j < 60; j++) {
+               debug("pid_block_load requested");
+               usbhid_submit_report(pidff->hid, pidff->reports[PID_BLOCK_LOAD],
+                                 USB_DIR_IN);
+               usbhid_wait_io(pidff->hid);
+               if (pidff->block_load_status->value[0] ==
+                   pidff->status_id[PID_BLOCK_LOAD_SUCCESS]) {
+                       debug("device reported free memory: %d bytes",
+                             pidff->block_load[PID_RAM_POOL_AVAILABLE].value ?
+                               pidff->block_load[PID_RAM_POOL_AVAILABLE].value[0] : -1);
+                       return 0;
+               }
+               if (pidff->block_load_status->value[0] ==
+                   pidff->status_id[PID_BLOCK_LOAD_FULL]) {
+                       debug("not enough memory free: %d bytes",
+                             pidff->block_load[PID_RAM_POOL_AVAILABLE].value ?
+                               pidff->block_load[PID_RAM_POOL_AVAILABLE].value[0] : -1);
+                       return -ENOSPC;
+               }
+       }
+       printk(KERN_ERR "hid-pidff: pid_block_load failed 60 times\n");
+       return -EIO;
+}
+
+/*
+ * Play the effect with PID id n times
+ */
+static void pidff_playback_pid(struct pidff_device *pidff, int pid_id, int n)
+{
+       pidff->effect_operation[PID_EFFECT_BLOCK_INDEX].value[0] = pid_id;
+
+       if (n == 0) {
+               pidff->effect_operation_status->value[0] =
+                       pidff->operation_id[PID_EFFECT_STOP];
+       } else {
+               pidff->effect_operation_status->value[0] =
+                       pidff->operation_id[PID_EFFECT_START];
+               pidff->effect_operation[PID_LOOP_COUNT].value[0] = n;
+       }
+
+       usbhid_wait_io(pidff->hid);
+       usbhid_submit_report(pidff->hid, pidff->reports[PID_EFFECT_OPERATION],
+                         USB_DIR_OUT);
+}
+
+/**
+ * Play the effect with effect id @effect_id for @value times
+ */
+static int pidff_playback(struct input_dev *dev, int effect_id, int value)
+{
+       struct pidff_device *pidff = dev->ff->private;
+
+       pidff_playback_pid(pidff, pidff->pid_id[effect_id], value);
+
+       return 0;
+}
+
+/*
+ * Erase effect with PID id
+ */
+static void pidff_erase_pid(struct pidff_device *pidff, int pid_id)
+{
+       pidff->block_free[PID_EFFECT_BLOCK_INDEX].value[0] = pid_id;
+       usbhid_submit_report(pidff->hid, pidff->reports[PID_BLOCK_FREE],
+                         USB_DIR_OUT);
+}
+
+/*
+ * Stop and erase effect with effect_id
+ */
+static int pidff_erase_effect(struct input_dev *dev, int effect_id)
+{
+       struct pidff_device *pidff = dev->ff->private;
+       int pid_id = pidff->pid_id[effect_id];
+
+       debug("starting to erase %d/%d", effect_id, pidff->pid_id[effect_id]);
+       pidff_playback_pid(pidff, pid_id, 0);
+       pidff_erase_pid(pidff, pid_id);
+
+       return 0;
+}
+
+/*
+ * Effect upload handler
+ */
+static int pidff_upload_effect(struct input_dev *dev, struct ff_effect *effect,
+                              struct ff_effect *old)
+{
+       struct pidff_device *pidff = dev->ff->private;
+       int type_id;
+       int error;
+
+       switch (effect->type) {
+       case FF_CONSTANT:
+               if (!old) {
+                       error = pidff_request_effect_upload(pidff,
+                                       pidff->type_id[PID_CONSTANT]);
+                       if (error)
+                               return error;
+               }
+               if (!old || pidff_needs_set_effect(effect, old))
+                       pidff_set_effect_report(pidff, effect);
+               if (!old || pidff_needs_set_constant(effect, old))
+                       pidff_set_constant_force_report(pidff, effect);
+               if (!old ||
+                   pidff_needs_set_envelope(&effect->u.constant.envelope,
+                                       &old->u.constant.envelope))
+                       pidff_set_envelope_report(pidff,
+                                       &effect->u.constant.envelope);
+               break;
+
+       case FF_PERIODIC:
+               if (!old) {
+                       switch (effect->u.periodic.waveform) {
+                       case FF_SQUARE:
+                               type_id = PID_SQUARE;
+                               break;
+                       case FF_TRIANGLE:
+                               type_id = PID_TRIANGLE;
+                               break;
+                       case FF_SINE:
+                               type_id = PID_SINE;
+                               break;
+                       case FF_SAW_UP:
+                               type_id = PID_SAW_UP;
+                               break;
+                       case FF_SAW_DOWN:
+                               type_id = PID_SAW_DOWN;
+                               break;
+                       default:
+                               printk(KERN_ERR
+                                      "hid-pidff: invalid waveform\n");
+                               return -EINVAL;
+                       }
+
+                       error = pidff_request_effect_upload(pidff,
+                                       pidff->type_id[type_id]);
+                       if (error)
+                               return error;
+               }
+               if (!old || pidff_needs_set_effect(effect, old))
+                       pidff_set_effect_report(pidff, effect);
+               if (!old || pidff_needs_set_periodic(effect, old))
+                       pidff_set_periodic_report(pidff, effect);
+               if (!old ||
+                   pidff_needs_set_envelope(&effect->u.periodic.envelope,
+                                       &old->u.periodic.envelope))
+                       pidff_set_envelope_report(pidff,
+                                       &effect->u.periodic.envelope);
+               break;
+
+       case FF_RAMP:
+               if (!old) {
+                       error = pidff_request_effect_upload(pidff,
+                                       pidff->type_id[PID_RAMP]);
+                       if (error)
+                               return error;
+               }
+               if (!old || pidff_needs_set_effect(effect, old))
+                       pidff_set_effect_report(pidff, effect);
+               if (!old || pidff_needs_set_ramp(effect, old))
+                       pidff_set_ramp_force_report(pidff, effect);
+               if (!old ||
+                   pidff_needs_set_envelope(&effect->u.ramp.envelope,
+                                       &old->u.ramp.envelope))
+                       pidff_set_envelope_report(pidff,
+                                       &effect->u.ramp.envelope);
+               break;
+
+       case FF_SPRING:
+               if (!old) {
+                       error = pidff_request_effect_upload(pidff,
+                                       pidff->type_id[PID_SPRING]);
+                       if (error)
+                               return error;
+               }
+               if (!old || pidff_needs_set_effect(effect, old))
+                       pidff_set_effect_report(pidff, effect);
+               if (!old || pidff_needs_set_condition(effect, old))
+                       pidff_set_condition_report(pidff, effect);
+               break;
+
+       case FF_FRICTION:
+               if (!old) {
+                       error = pidff_request_effect_upload(pidff,
+                                       pidff->type_id[PID_FRICTION]);
+                       if (error)
+                               return error;
+               }
+               if (!old || pidff_needs_set_effect(effect, old))
+                       pidff_set_effect_report(pidff, effect);
+               if (!old || pidff_needs_set_condition(effect, old))
+                       pidff_set_condition_report(pidff, effect);
+               break;
+
+       case FF_DAMPER:
+               if (!old) {
+                       error = pidff_request_effect_upload(pidff,
+                                       pidff->type_id[PID_DAMPER]);
+                       if (error)
+                               return error;
+               }
+               if (!old || pidff_needs_set_effect(effect, old))
+                       pidff_set_effect_report(pidff, effect);
+               if (!old || pidff_needs_set_condition(effect, old))
+                       pidff_set_condition_report(pidff, effect);
+               break;
+
+       case FF_INERTIA:
+               if (!old) {
+                       error = pidff_request_effect_upload(pidff,
+                                       pidff->type_id[PID_INERTIA]);
+                       if (error)
+                               return error;
+               }
+               if (!old || pidff_needs_set_effect(effect, old))
+                       pidff_set_effect_report(pidff, effect);
+               if (!old || pidff_needs_set_condition(effect, old))
+                       pidff_set_condition_report(pidff, effect);
+               break;
+
+       default:
+               printk(KERN_ERR "hid-pidff: invalid type\n");
+               return -EINVAL;
+       }
+
+       if (!old)
+               pidff->pid_id[effect->id] =
+                   pidff->block_load[PID_EFFECT_BLOCK_INDEX].value[0];
+
+       debug("uploaded");
+
+       return 0;
+}
+
+/*
+ * set_gain() handler
+ */
+static void pidff_set_gain(struct input_dev *dev, u16 gain)
+{
+       struct pidff_device *pidff = dev->ff->private;
+
+       pidff_set(&pidff->device_gain[PID_DEVICE_GAIN_FIELD], gain);
+       usbhid_submit_report(pidff->hid, pidff->reports[PID_DEVICE_GAIN],
+                         USB_DIR_OUT);
+}
+
+static void pidff_autocenter(struct pidff_device *pidff, u16 magnitude)
+{
+       struct hid_field *field =
+               pidff->block_load[PID_EFFECT_BLOCK_INDEX].field;
+
+       if (!magnitude) {
+               pidff_playback_pid(pidff, field->logical_minimum, 0);
+               return;
+       }
+
+       pidff_playback_pid(pidff, field->logical_minimum, 1);
+
+       pidff->set_effect[PID_EFFECT_BLOCK_INDEX].value[0] =
+               pidff->block_load[PID_EFFECT_BLOCK_INDEX].field->logical_minimum;
+       pidff->set_effect_type->value[0] = pidff->type_id[PID_SPRING];
+       pidff->set_effect[PID_DURATION].value[0] = 0;
+       pidff->set_effect[PID_TRIGGER_BUTTON].value[0] = 0;
+       pidff->set_effect[PID_TRIGGER_REPEAT_INT].value[0] = 0;
+       pidff_set(&pidff->set_effect[PID_GAIN], magnitude);
+       pidff->set_effect[PID_START_DELAY].value[0] = 0;
+
+       usbhid_submit_report(pidff->hid, pidff->reports[PID_SET_EFFECT],
+                         USB_DIR_OUT);
+}
+
+/*
+ * pidff_set_autocenter() handler
+ */
+static void pidff_set_autocenter(struct input_dev *dev, u16 magnitude)
+{
+       struct pidff_device *pidff = dev->ff->private;
+
+       pidff_autocenter(pidff, magnitude);
+}
+
+/*
+ * Find fields from a report and fill a pidff_usage
+ */
+static int pidff_find_fields(struct pidff_usage *usage, const u8 *table,
+                            struct hid_report *report, int count, int strict)
+{
+       int i, j, k, found;
+
+       for (k = 0; k < count; k++) {
+               found = 0;
+               for (i = 0; i < report->maxfield; i++) {
+                       if (report->field[i]->maxusage !=
+                           report->field[i]->report_count) {
+                               debug("maxusage and report_count do not match, "
+                                     "skipping");
+                               continue;
+                       }
+                       for (j = 0; j < report->field[i]->maxusage; j++) {
+                               if (report->field[i]->usage[j].hid ==
+                                   (HID_UP_PID | table[k])) {
+                                       debug("found %d at %d->%d", k, i, j);
+                                       usage[k].field = report->field[i];
+                                       usage[k].value =
+                                               &report->field[i]->value[j];
+                                       found = 1;
+                                       break;
+                               }
+                       }
+                       if (found)
+                               break;
+               }
+               if (!found && strict) {
+                       debug("failed to locate %d", k);
+                       return -1;
+               }
+       }
+       return 0;
+}
+
+/*
+ * Return index into pidff_reports for the given usage
+ */
+static int pidff_check_usage(int usage)
+{
+       int i;
+
+       for (i = 0; i < sizeof(pidff_reports); i++)
+               if (usage == (HID_UP_PID | pidff_reports[i]))
+                       return i;
+
+       return -1;
+}
+
+/*
+ * Find the reports and fill pidff->reports[]
+ * report_type specifies either OUTPUT or FEATURE reports
+ */
+static void pidff_find_reports(struct hid_device *hid, int report_type,
+                              struct pidff_device *pidff)
+{
+       struct hid_report *report;
+       int i, ret;
+
+       list_for_each_entry(report,
+                           &hid->report_enum[report_type].report_list, list) {
+               if (report->maxfield < 1)
+                       continue;
+               ret = pidff_check_usage(report->field[0]->logical);
+               if (ret != -1) {
+                       debug("found usage 0x%02x from field->logical",
+                             pidff_reports[ret]);
+                       pidff->reports[ret] = report;
+                       continue;
+               }
+
+               /*
+                * Sometimes logical collections are stacked to indicate
+                * different usages for the report and the field, in which
+                * case we want the usage of the parent. However, Linux HID
+                * implementation hides this fact, so we have to dig it up
+                * ourselves
+                */
+               i = report->field[0]->usage[0].collection_index;
+               if (i <= 0 ||
+                   hid->collection[i - 1].type != HID_COLLECTION_LOGICAL)
+                       continue;
+               ret = pidff_check_usage(hid->collection[i - 1].usage);
+               if (ret != -1 && !pidff->reports[ret]) {
+                       debug("found usage 0x%02x from collection array",
+                             pidff_reports[ret]);
+                       pidff->reports[ret] = report;
+               }
+       }
+}
+
+/*
+ * Test if the required reports have been found
+ */
+static int pidff_reports_ok(struct pidff_device *pidff)
+{
+       int i;
+
+       for (i = 0; i <= PID_REQUIRED_REPORTS; i++) {
+               if (!pidff->reports[i]) {
+                       debug("%d missing", i);
+                       return 0;
+               }
+       }
+
+       return 1;
+}
+
+/*
+ * Find a field with a specific usage within a report
+ */
+static struct hid_field *pidff_find_special_field(struct hid_report *report,
+                                                 int usage, int enforce_min)
+{
+       int i;
+
+       for (i = 0; i < report->maxfield; i++) {
+               if (report->field[i]->logical == (HID_UP_PID | usage) &&
+                   report->field[i]->report_count > 0) {
+                       if (!enforce_min ||
+                           report->field[i]->logical_minimum == 1)
+                               return report->field[i];
+                       else {
+                               printk(KERN_ERR "hid-pidff: logical_minimum "
+                                       "is not 1 as it should be\n");
+                               return NULL;
+                       }
+               }
+       }
+       return NULL;
+}
+
+/*
+ * Fill a pidff->*_id struct table
+ */
+static int pidff_find_special_keys(int *keys, struct hid_field *fld,
+                                  const u8 *usagetable, int count)
+{
+
+       int i, j;
+       int found = 0;
+
+       for (i = 0; i < count; i++) {
+               for (j = 0; j < fld->maxusage; j++) {
+                       if (fld->usage[j].hid == (HID_UP_PID | usagetable[i])) {
+                               keys[i] = j + 1;
+                               found++;
+                               break;
+                       }
+               }
+       }
+       return found;
+}
+
+#define PIDFF_FIND_SPECIAL_KEYS(keys, field, name) \
+       pidff_find_special_keys(pidff->keys, pidff->field, pidff_ ## name, \
+               sizeof(pidff_ ## name))
+
+/*
+ * Find and check the special fields
+ */
+static int pidff_find_special_fields(struct pidff_device *pidff)
+{
+       debug("finding special fields");
+
+       pidff->create_new_effect_type =
+               pidff_find_special_field(pidff->reports[PID_CREATE_NEW_EFFECT],
+                                        0x25, 1);
+       pidff->set_effect_type =
+               pidff_find_special_field(pidff->reports[PID_SET_EFFECT],
+                                        0x25, 1);
+       pidff->effect_direction =
+               pidff_find_special_field(pidff->reports[PID_SET_EFFECT],
+                                        0x57, 0);
+       pidff->device_control =
+               pidff_find_special_field(pidff->reports[PID_DEVICE_CONTROL],
+                                        0x96, 1);
+       pidff->block_load_status =
+               pidff_find_special_field(pidff->reports[PID_BLOCK_LOAD],
+                                        0x8b, 1);
+       pidff->effect_operation_status =
+               pidff_find_special_field(pidff->reports[PID_EFFECT_OPERATION],
+                                        0x78, 1);
+
+       debug("search done");
+
+       if (!pidff->create_new_effect_type || !pidff->set_effect_type) {
+               printk(KERN_ERR "hid-pidff: effect lists not found\n");
+               return -1;
+       }
+
+       if (!pidff->effect_direction) {
+               printk(KERN_ERR "hid-pidff: direction field not found\n");
+               return -1;
+       }
+
+       if (!pidff->device_control) {
+               printk(KERN_ERR "hid-pidff: device control field not found\n");
+               return -1;
+       }
+
+       if (!pidff->block_load_status) {
+               printk(KERN_ERR
+                      "hid-pidff: block load status field not found\n");
+               return -1;
+       }
+
+       if (!pidff->effect_operation_status) {
+               printk(KERN_ERR
+                      "hid-pidff: effect operation field not found\n");
+               return -1;
+       }
+
+       pidff_find_special_keys(pidff->control_id, pidff->device_control,
+                               pidff_device_control,
+                               sizeof(pidff_device_control));
+
+       PIDFF_FIND_SPECIAL_KEYS(control_id, device_control, device_control);
+
+       if (!PIDFF_FIND_SPECIAL_KEYS(type_id, create_new_effect_type,
+                                    effect_types)) {
+               printk(KERN_ERR "hid-pidff: no effect types found\n");
+               return -1;
+       }
+
+       if (PIDFF_FIND_SPECIAL_KEYS(status_id, block_load_status,
+                                   block_load_status) !=
+                       sizeof(pidff_block_load_status)) {
+               printk(KERN_ERR
+                      "hidpidff: block load status identifiers not found\n");
+               return -1;
+       }
+
+       if (PIDFF_FIND_SPECIAL_KEYS(operation_id, effect_operation_status,
+                                   effect_operation_status) !=
+                       sizeof(pidff_effect_operation_status)) {
+               printk(KERN_ERR
+                      "hidpidff: effect operation identifiers not found\n");
+               return -1;
+       }
+
+       return 0;
+}
+
+/**
+ * Find the implemented effect types
+ */
+static int pidff_find_effects(struct pidff_device *pidff,
+                             struct input_dev *dev)
+{
+       int i;
+
+       for (i = 0; i < sizeof(pidff_effect_types); i++) {
+               int pidff_type = pidff->type_id[i];
+               if (pidff->set_effect_type->usage[pidff_type].hid !=
+                   pidff->create_new_effect_type->usage[pidff_type].hid) {
+                       printk(KERN_ERR "hid-pidff: "
+                              "effect type number %d is invalid\n", i);
+                       return -1;
+               }
+       }
+
+       if (pidff->type_id[PID_CONSTANT])
+               set_bit(FF_CONSTANT, dev->ffbit);
+       if (pidff->type_id[PID_RAMP])
+               set_bit(FF_RAMP, dev->ffbit);
+       if (pidff->type_id[PID_SQUARE]) {
+               set_bit(FF_SQUARE, dev->ffbit);
+               set_bit(FF_PERIODIC, dev->ffbit);
+       }
+       if (pidff->type_id[PID_SINE]) {
+               set_bit(FF_SINE, dev->ffbit);
+               set_bit(FF_PERIODIC, dev->ffbit);
+       }
+       if (pidff->type_id[PID_TRIANGLE]) {
+               set_bit(FF_TRIANGLE, dev->ffbit);
+               set_bit(FF_PERIODIC, dev->ffbit);
+       }
+       if (pidff->type_id[PID_SAW_UP]) {
+               set_bit(FF_SAW_UP, dev->ffbit);
+               set_bit(FF_PERIODIC, dev->ffbit);
+       }
+       if (pidff->type_id[PID_SAW_DOWN]) {
+               set_bit(FF_SAW_DOWN, dev->ffbit);
+               set_bit(FF_PERIODIC, dev->ffbit);
+       }
+       if (pidff->type_id[PID_SPRING])
+               set_bit(FF_SPRING, dev->ffbit);
+       if (pidff->type_id[PID_DAMPER])
+               set_bit(FF_DAMPER, dev->ffbit);
+       if (pidff->type_id[PID_INERTIA])
+               set_bit(FF_INERTIA, dev->ffbit);
+       if (pidff->type_id[PID_FRICTION])
+               set_bit(FF_FRICTION, dev->ffbit);
+
+       return 0;
+
+}
+
+#define PIDFF_FIND_FIELDS(name, report, strict) \
+       pidff_find_fields(pidff->name, pidff_ ## name, \
+               pidff->reports[report], \
+               sizeof(pidff_ ## name), strict)
+
+/*
+ * Fill and check the pidff_usages
+ */
+static int pidff_init_fields(struct pidff_device *pidff, struct input_dev *dev)
+{
+       int envelope_ok = 0;
+
+       if (PIDFF_FIND_FIELDS(set_effect, PID_SET_EFFECT, 1)) {
+               printk(KERN_ERR
+                      "hid-pidff: unknown set_effect report layout\n");
+               return -ENODEV;
+       }
+
+       PIDFF_FIND_FIELDS(block_load, PID_BLOCK_LOAD, 0);
+       if (!pidff->block_load[PID_EFFECT_BLOCK_INDEX].value) {
+               printk(KERN_ERR
+                      "hid-pidff: unknown pid_block_load report layout\n");
+               return -ENODEV;
+       }
+
+       if (PIDFF_FIND_FIELDS(effect_operation, PID_EFFECT_OPERATION, 1)) {
+               printk(KERN_ERR
+                      "hid-pidff: unknown effect_operation report layout\n");
+               return -ENODEV;
+       }
+
+       if (PIDFF_FIND_FIELDS(block_free, PID_BLOCK_FREE, 1)) {
+               printk(KERN_ERR
+                      "hid-pidff: unknown pid_block_free report layout\n");
+               return -ENODEV;
+       }
+
+       if (!PIDFF_FIND_FIELDS(set_envelope, PID_SET_ENVELOPE, 1))
+               envelope_ok = 1;
+
+       if (pidff_find_special_fields(pidff) || pidff_find_effects(pidff, dev))
+               return -ENODEV;
+
+       if (!envelope_ok) {
+               if (test_and_clear_bit(FF_CONSTANT, dev->ffbit))
+                       printk(KERN_WARNING "hid-pidff: "
+                              "has constant effect but no envelope\n");
+               if (test_and_clear_bit(FF_RAMP, dev->ffbit))
+                       printk(KERN_WARNING "hid-pidff: "
+                               "has ramp effect but no envelope\n");
+
+               if (test_and_clear_bit(FF_PERIODIC, dev->ffbit))
+                       printk(KERN_WARNING "hid-pidff: "
+                               "has periodic effect but no envelope\n");
+       }
+
+       if (test_bit(FF_CONSTANT, dev->ffbit) &&
+           PIDFF_FIND_FIELDS(set_constant, PID_SET_CONSTANT, 1)) {
+               printk(KERN_WARNING
+                      "hid-pidff: unknown constant effect layout\n");
+               clear_bit(FF_CONSTANT, dev->ffbit);
+       }
+
+       if (test_bit(FF_RAMP, dev->ffbit) &&
+           PIDFF_FIND_FIELDS(set_ramp, PID_SET_RAMP, 1)) {
+               printk(KERN_WARNING "hid-pidff: unknown ramp effect layout\n");
+               clear_bit(FF_RAMP, dev->ffbit);
+       }
+
+       if ((test_bit(FF_SPRING, dev->ffbit) ||
+            test_bit(FF_DAMPER, dev->ffbit) ||
+            test_bit(FF_FRICTION, dev->ffbit) ||
+            test_bit(FF_INERTIA, dev->ffbit)) &&
+           PIDFF_FIND_FIELDS(set_condition, PID_SET_CONDITION, 1)) {
+               printk(KERN_WARNING
+                      "hid-pidff: unknown condition effect layout\n");
+               clear_bit(FF_SPRING, dev->ffbit);
+               clear_bit(FF_DAMPER, dev->ffbit);
+               clear_bit(FF_FRICTION, dev->ffbit);
+               clear_bit(FF_INERTIA, dev->ffbit);
+       }
+
+       if (test_bit(FF_PERIODIC, dev->ffbit) &&
+           PIDFF_FIND_FIELDS(set_periodic, PID_SET_PERIODIC, 1)) {
+               printk(KERN_WARNING
+                      "hid-pidff: unknown periodic effect layout\n");
+               clear_bit(FF_PERIODIC, dev->ffbit);
+       }
+
+       PIDFF_FIND_FIELDS(pool, PID_POOL, 0);
+
+       if (!PIDFF_FIND_FIELDS(device_gain, PID_DEVICE_GAIN, 1))
+               set_bit(FF_GAIN, dev->ffbit);
+
+       return 0;
+}
+
+/*
+ * Reset the device
+ */
+static void pidff_reset(struct pidff_device *pidff)
+{
+       struct hid_device *hid = pidff->hid;
+       int i = 0;
+
+       pidff->device_control->value[0] = pidff->control_id[PID_RESET];
+       /* We reset twice as sometimes hid_wait_io isn't waiting long enough */
+       usbhid_submit_report(hid, pidff->reports[PID_DEVICE_CONTROL], USB_DIR_OUT);
+       usbhid_wait_io(hid);
+       usbhid_submit_report(hid, pidff->reports[PID_DEVICE_CONTROL], USB_DIR_OUT);
+       usbhid_wait_io(hid);
+
+       pidff->device_control->value[0] =
+               pidff->control_id[PID_ENABLE_ACTUATORS];
+       usbhid_submit_report(hid, pidff->reports[PID_DEVICE_CONTROL], USB_DIR_OUT);
+       usbhid_wait_io(hid);
+
+       /* pool report is sometimes messed up, refetch it */
+       usbhid_submit_report(hid, pidff->reports[PID_POOL], USB_DIR_IN);
+       usbhid_wait_io(hid);
+
+       if (pidff->pool[PID_SIMULTANEOUS_MAX].value) {
+               int sim_effects = pidff->pool[PID_SIMULTANEOUS_MAX].value[0];
+               while (sim_effects < 2) {
+                       if (i++ > 20) {
+                               printk(KERN_WARNING "hid-pidff: device reports "
+                                      "%d simultaneous effects\n",
+                                      sim_effects);
+                               break;
+                       }
+                       debug("pid_pool requested again");
+                       usbhid_submit_report(hid, pidff->reports[PID_POOL],
+                                         USB_DIR_IN);
+                       usbhid_wait_io(hid);
+               }
+       }
+}
+
+/*
+ * Test if autocenter modification is using the supported method
+ */
+static int pidff_check_autocenter(struct pidff_device *pidff,
+                                 struct input_dev *dev)
+{
+       int error;
+
+       /*
+        * Let's find out if autocenter modification is supported
+        * Specification doesn't specify anything, so we request an
+        * effect upload and cancel it immediately. If the approved
+        * effect id was one above the minimum, then we assume the first
+        * effect id is a built-in spring type effect used for autocenter
+        */
+
+       error = pidff_request_effect_upload(pidff, 1);
+       if (error) {
+               printk(KERN_ERR "hid-pidff: upload request failed\n");
+               return error;
+       }
+
+       if (pidff->block_load[PID_EFFECT_BLOCK_INDEX].value[0] ==
+           pidff->block_load[PID_EFFECT_BLOCK_INDEX].field->logical_minimum + 1) {
+               pidff_autocenter(pidff, 0xffff);
+               set_bit(FF_AUTOCENTER, dev->ffbit);
+       } else {
+               printk(KERN_NOTICE "hid-pidff: "
+                      "device has unknown autocenter control method\n");
+       }
+
+       pidff_erase_pid(pidff,
+                       pidff->block_load[PID_EFFECT_BLOCK_INDEX].value[0]);
+
+       return 0;
+
+}
+
+/*
+ * Check if the device is PID and initialize it
+ */
+int hid_pidff_init(struct hid_device *hid)
+{
+       struct pidff_device *pidff;
+       struct hid_input *hidinput = list_entry(hid->inputs.next,
+                                               struct hid_input, list);
+       struct input_dev *dev = hidinput->input;
+       struct ff_device *ff;
+       int max_effects;
+       int error;
+
+       debug("starting pid init");
+
+       if (list_empty(&hid->report_enum[HID_OUTPUT_REPORT].report_list)) {
+               debug("not a PID device, no output report");
+               return -ENODEV;
+       }
+
+       pidff = kzalloc(sizeof(*pidff), GFP_KERNEL);
+       if (!pidff)
+               return -ENOMEM;
+
+       pidff->hid = hid;
+
+       pidff_find_reports(hid, HID_OUTPUT_REPORT, pidff);
+       pidff_find_reports(hid, HID_FEATURE_REPORT, pidff);
+
+       if (!pidff_reports_ok(pidff)) {
+               debug("reports not ok, aborting");
+               error = -ENODEV;
+               goto fail;
+       }
+
+       error = pidff_init_fields(pidff, dev);
+       if (error)
+               goto fail;
+
+       pidff_reset(pidff);
+
+       if (test_bit(FF_GAIN, dev->ffbit)) {
+               pidff_set(&pidff->device_gain[PID_DEVICE_GAIN_FIELD], 0xffff);
+               usbhid_submit_report(pidff->hid, pidff->reports[PID_DEVICE_GAIN],
+                                 USB_DIR_OUT);
+       }
+
+       error = pidff_check_autocenter(pidff, dev);
+       if (error)
+               goto fail;
+
+       max_effects =
+           pidff->block_load[PID_EFFECT_BLOCK_INDEX].field->logical_maximum -
+           pidff->block_load[PID_EFFECT_BLOCK_INDEX].field->logical_minimum +
+           1;
+       debug("max effects is %d", max_effects);
+
+       if (max_effects > PID_EFFECTS_MAX)
+               max_effects = PID_EFFECTS_MAX;
+
+       if (pidff->pool[PID_SIMULTANEOUS_MAX].value)
+               debug("max simultaneous effects is %d",
+                     pidff->pool[PID_SIMULTANEOUS_MAX].value[0]);
+
+       if (pidff->pool[PID_RAM_POOL_SIZE].value)
+               debug("device memory size is %d bytes",
+                     pidff->pool[PID_RAM_POOL_SIZE].value[0]);
+
+       if (pidff->pool[PID_DEVICE_MANAGED_POOL].value &&
+           pidff->pool[PID_DEVICE_MANAGED_POOL].value[0] == 0) {
+               printk(KERN_NOTICE "hid-pidff: "
+                      "device does not support device managed pool\n");
+               goto fail;
+       }
+
+       error = input_ff_create(dev, max_effects);
+       if (error)
+               goto fail;
+
+       ff = dev->ff;
+       ff->private = pidff;
+       ff->upload = pidff_upload_effect;
+       ff->erase = pidff_erase_effect;
+       ff->set_gain = pidff_set_gain;
+       ff->set_autocenter = pidff_set_autocenter;
+       ff->playback = pidff_playback;
+
+       printk(KERN_INFO "Force feedback for USB HID PID devices by "
+              "Anssi Hannula <anssi.hannula@gmail.com>\n");
+
+       return 0;
+
+ fail:
+       kfree(pidff);
+       return error;
+}
diff --git a/drivers/hid/usbhid/hid-plff.c b/drivers/hid/usbhid/hid-plff.c
new file mode 100644 (file)
index 0000000..76d2e6e
--- /dev/null
@@ -0,0 +1,129 @@
+/*
+ *  Force feedback support for PantherLord USB/PS2 2in1 Adapter devices
+ *
+ *  Copyright (c) 2007 Anssi Hannula <anssi.hannula@gmail.com>
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+/* #define DEBUG */
+
+#define debug(format, arg...) pr_debug("hid-plff: " format "\n" , ## arg)
+
+#include <linux/input.h>
+#include <linux/usb.h>
+#include <linux/hid.h>
+#include "usbhid.h"
+
+struct plff_device {
+       struct hid_report *report;
+};
+
+static int hid_plff_play(struct input_dev *dev, void *data,
+                        struct ff_effect *effect)
+{
+       struct hid_device *hid = dev->private;
+       struct plff_device *plff = data;
+       int left, right;
+
+       left = effect->u.rumble.strong_magnitude;
+       right = effect->u.rumble.weak_magnitude;
+       debug("called with 0x%04x 0x%04x", left, right);
+
+       left = left * 0x7f / 0xffff;
+       right = right * 0x7f / 0xffff;
+
+       plff->report->field[0]->value[2] = left;
+       plff->report->field[0]->value[3] = right;
+       debug("running with 0x%02x 0x%02x", left, right);
+       usbhid_submit_report(hid, plff->report, USB_DIR_OUT);
+
+       return 0;
+}
+
+int hid_plff_init(struct hid_device *hid)
+{
+       struct plff_device *plff;
+       struct hid_report *report;
+       struct hid_input *hidinput;
+       struct list_head *report_list =
+                       &hid->report_enum[HID_OUTPUT_REPORT].report_list;
+       struct list_head *report_ptr = report_list;
+       struct input_dev *dev;
+       int error;
+
+       /* The device contains 2 output reports (one for each
+          HID_QUIRK_MULTI_INPUT device), both containing 1 field, which
+          contains 4 ff00.0002 usages and 4 16bit absolute values.
+
+          The 2 input reports also contain a field which contains
+          8 ff00.0001 usages and 8 boolean values. Their meaning is
+          currently unknown. */
+
+       if (list_empty(report_list)) {
+               printk(KERN_ERR "hid-plff: no output reports found\n");
+               return -ENODEV;
+       }
+
+       list_for_each_entry(hidinput, &hid->inputs, list) {
+
+               report_ptr = report_ptr->next;
+
+               if (report_ptr == report_list) {
+                       printk(KERN_ERR "hid-plff: required output report is missing\n");
+                       return -ENODEV;
+               }
+
+               report = list_entry(report_ptr, struct hid_report, list);
+               if (report->maxfield < 1) {
+                       printk(KERN_ERR "hid-plff: no fields in the report\n");
+                       return -ENODEV;
+               }
+
+               if (report->field[0]->report_count < 4) {
+                       printk(KERN_ERR "hid-plff: not enough values in the field\n");
+                       return -ENODEV;
+               }
+
+               plff = kzalloc(sizeof(struct plff_device), GFP_KERNEL);
+               if (!plff)
+                       return -ENOMEM;
+
+               dev = hidinput->input;
+
+               set_bit(FF_RUMBLE, dev->ffbit);
+
+               error = input_ff_create_memless(dev, plff, hid_plff_play);
+               if (error) {
+                       kfree(plff);
+                       return error;
+               }
+
+               plff->report = report;
+               plff->report->field[0]->value[0] = 0x00;
+               plff->report->field[0]->value[1] = 0x00;
+               plff->report->field[0]->value[2] = 0x00;
+               plff->report->field[0]->value[3] = 0x00;
+               usbhid_submit_report(hid, plff->report, USB_DIR_OUT);
+       }
+
+       printk(KERN_INFO "hid-plff: Force feedback for PantherLord USB/PS2 "
+              "2in1 Adapters by Anssi Hannula <anssi.hannula@gmail.com>\n");
+
+       return 0;
+}
diff --git a/drivers/hid/usbhid/hid-tmff.c b/drivers/hid/usbhid/hid-tmff.c
new file mode 100644 (file)
index 0000000..ab67331
--- /dev/null
@@ -0,0 +1,147 @@
+/*
+ * Force feedback support for various HID compliant devices by ThrustMaster:
+ *    ThrustMaster FireStorm Dual Power 2
+ * and possibly others whose device ids haven't been added.
+ *
+ *  Modified to support ThrustMaster devices by Zinx Verituse
+ *  on 2003-01-25 from the Logitech force feedback driver,
+ *  which is by Johann Deneux.
+ *
+ *  Copyright (c) 2003 Zinx Verituse <zinx@epicsol.org>
+ *  Copyright (c) 2002 Johann Deneux
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/input.h>
+
+#undef DEBUG
+#include <linux/usb.h>
+
+#include <linux/hid.h>
+#include "usbhid.h"
+
+/* Usages for thrustmaster devices I know about */
+#define THRUSTMASTER_USAGE_RUMBLE_LR   (HID_UP_GENDESK | 0xbb)
+
+
+struct tmff_device {
+       struct hid_report *report;
+       struct hid_field *rumble;
+};
+
+/* Changes values from 0 to 0xffff into values from minimum to maximum */
+static inline int hid_tmff_scale(unsigned int in, int minimum, int maximum)
+{
+       int ret;
+
+       ret = (in * (maximum - minimum) / 0xffff) + minimum;
+       if (ret < minimum)
+               return minimum;
+       if (ret > maximum)
+               return maximum;
+       return ret;
+}
+
+static int hid_tmff_play(struct input_dev *dev, void *data, struct ff_effect *effect)
+{
+       struct hid_device *hid = dev->private;
+       struct tmff_device *tmff = data;
+       int left, right;        /* Rumbling */
+
+       left = hid_tmff_scale(effect->u.rumble.weak_magnitude,
+               tmff->rumble->logical_minimum, tmff->rumble->logical_maximum);
+       right = hid_tmff_scale(effect->u.rumble.strong_magnitude,
+               tmff->rumble->logical_minimum, tmff->rumble->logical_maximum);
+
+       tmff->rumble->value[0] = left;
+       tmff->rumble->value[1] = right;
+       dbg("(left,right)=(%08x, %08x)", left, right);
+       usbhid_submit_report(hid, tmff->report, USB_DIR_OUT);
+
+       return 0;
+}
+
+int hid_tmff_init(struct hid_device *hid)
+{
+       struct tmff_device *tmff;
+       struct list_head *pos;
+       struct hid_input *hidinput = list_entry(hid->inputs.next, struct hid_input, list);
+       struct input_dev *input_dev = hidinput->input;
+       int error;
+
+       tmff = kzalloc(sizeof(struct tmff_device), GFP_KERNEL);
+       if (!tmff)
+               return -ENOMEM;
+
+       /* Find the report to use */
+       __list_for_each(pos, &hid->report_enum[HID_OUTPUT_REPORT].report_list) {
+               struct hid_report *report = (struct hid_report *)pos;
+               int fieldnum;
+
+               for (fieldnum = 0; fieldnum < report->maxfield; ++fieldnum) {
+                       struct hid_field *field = report->field[fieldnum];
+
+                       if (field->maxusage <= 0)
+                               continue;
+
+                       switch (field->usage[0].hid) {
+                               case THRUSTMASTER_USAGE_RUMBLE_LR:
+                                       if (field->report_count < 2) {
+                                               warn("ignoring THRUSTMASTER_USAGE_RUMBLE_LR with report_count < 2");
+                                               continue;
+                                       }
+
+                                       if (field->logical_maximum == field->logical_minimum) {
+                                               warn("ignoring THRUSTMASTER_USAGE_RUMBLE_LR with logical_maximum == logical_minimum");
+                                               continue;
+                                       }
+
+                                       if (tmff->report && tmff->report != report) {
+                                               warn("ignoring THRUSTMASTER_USAGE_RUMBLE_LR in other report");
+                                               continue;
+                                       }
+
+                                       if (tmff->rumble && tmff->rumble != field) {
+                                               warn("ignoring duplicate THRUSTMASTER_USAGE_RUMBLE_LR");
+                                               continue;
+                                       }
+
+                                       tmff->report = report;
+                                       tmff->rumble = field;
+
+                                       set_bit(FF_RUMBLE, input_dev->ffbit);
+                                       break;
+
+                               default:
+                                       warn("ignoring unknown output usage %08x", field->usage[0].hid);
+                                       continue;
+                       }
+               }
+       }
+
+       error = input_ff_create_memless(input_dev, tmff, hid_tmff_play);
+       if (error) {
+               kfree(tmff);
+               return error;
+       }
+
+       info("Force feedback for ThrustMaster rumble pad devices by Zinx Verituse <zinx@epicsol.org>");
+
+       return 0;
+}
+
diff --git a/drivers/hid/usbhid/hid-zpff.c b/drivers/hid/usbhid/hid-zpff.c
new file mode 100644 (file)
index 0000000..7bd8238
--- /dev/null
@@ -0,0 +1,111 @@
+/*
+ *  Force feedback support for Zeroplus based devices
+ *
+ *  Copyright (c) 2005, 2006 Anssi Hannula <anssi.hannula@gmail.com>
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+/* #define DEBUG */
+
+#define debug(format, arg...) pr_debug("hid-zpff: " format "\n" , ## arg)
+
+#include <linux/input.h>
+#include <linux/usb.h>
+#include <linux/hid.h>
+#include "usbhid.h"
+
+struct zpff_device {
+       struct hid_report *report;
+};
+
+static int hid_zpff_play(struct input_dev *dev, void *data,
+                        struct ff_effect *effect)
+{
+       struct hid_device *hid = dev->private;
+       struct zpff_device *zpff = data;
+       int left, right;
+
+       /*
+        * The following is specified the other way around in the Zeroplus
+        * datasheet but the order below is correct for the XFX Executioner;
+        * however it is possible that the XFX Executioner is an exception
+        */
+
+       left = effect->u.rumble.strong_magnitude;
+       right = effect->u.rumble.weak_magnitude;
+       debug("called with 0x%04x 0x%04x", left, right);
+
+       left = left * 0x7f / 0xffff;
+       right = right * 0x7f / 0xffff;
+
+       zpff->report->field[2]->value[0] = left;
+       zpff->report->field[3]->value[0] = right;
+       debug("running with 0x%02x 0x%02x", left, right);
+       usbhid_submit_report(hid, zpff->report, USB_DIR_OUT);
+
+       return 0;
+}
+
+int hid_zpff_init(struct hid_device *hid)
+{
+       struct zpff_device *zpff;
+       struct hid_report *report;
+       struct hid_input *hidinput = list_entry(hid->inputs.next,
+                                               struct hid_input, list);
+       struct list_head *report_list =
+                       &hid->report_enum[HID_OUTPUT_REPORT].report_list;
+       struct input_dev *dev = hidinput->input;
+       int error;
+
+       if (list_empty(report_list)) {
+               printk(KERN_ERR "hid-zpff: no output report found\n");
+               return -ENODEV;
+       }
+
+       report = list_entry(report_list->next, struct hid_report, list);
+
+       if (report->maxfield < 4) {
+               printk(KERN_ERR "hid-zpff: not enough fields in report\n");
+               return -ENODEV;
+       }
+
+       zpff = kzalloc(sizeof(struct zpff_device), GFP_KERNEL);
+       if (!zpff)
+               return -ENOMEM;
+
+       set_bit(FF_RUMBLE, dev->ffbit);
+
+       error = input_ff_create_memless(dev, zpff, hid_zpff_play);
+       if (error) {
+               kfree(zpff);
+               return error;
+       }
+
+       zpff->report = report;
+       zpff->report->field[0]->value[0] = 0x00;
+       zpff->report->field[1]->value[0] = 0x02;
+       zpff->report->field[2]->value[0] = 0x00;
+       zpff->report->field[3]->value[0] = 0x00;
+       usbhid_submit_report(hid, zpff->report, USB_DIR_OUT);
+
+       printk(KERN_INFO "Force feedback for Zeroplus based devices by "
+              "Anssi Hannula <anssi.hannula@gmail.com>\n");
+
+       return 0;
+}
diff --git a/drivers/hid/usbhid/hiddev.c b/drivers/hid/usbhid/hiddev.c
new file mode 100644 (file)
index 0000000..a8b3d66
--- /dev/null
@@ -0,0 +1,847 @@
+/*
+ *  Copyright (c) 2001 Paul Stewart
+ *  Copyright (c) 2001 Vojtech Pavlik
+ *
+ *  HID char devices, giving access to raw HID device events.
+ *
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Should you need to contact me, the author, you can do so either by
+ * e-mail - mail your message to Paul Stewart <stewart@wetlogic.net>
+ */
+
+#include <linux/poll.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/smp_lock.h>
+#include <linux/input.h>
+#include <linux/usb.h>
+#include <linux/hid.h>
+#include <linux/hiddev.h>
+#include "usbhid.h"
+
+#ifdef CONFIG_USB_DYNAMIC_MINORS
+#define HIDDEV_MINOR_BASE      0
+#define HIDDEV_MINORS          256
+#else
+#define HIDDEV_MINOR_BASE      96
+#define HIDDEV_MINORS          16
+#endif
+#define HIDDEV_BUFFER_SIZE     64
+
+struct hiddev {
+       int exist;
+       int open;
+       wait_queue_head_t wait;
+       struct hid_device *hid;
+       struct list_head list;
+};
+
+struct hiddev_list {
+       struct hiddev_usage_ref buffer[HIDDEV_BUFFER_SIZE];
+       int head;
+       int tail;
+       unsigned flags;
+       struct fasync_struct *fasync;
+       struct hiddev *hiddev;
+       struct list_head node;
+};
+
+static struct hiddev *hiddev_table[HIDDEV_MINORS];
+
+/*
+ * Find a report, given the report's type and ID.  The ID can be specified
+ * indirectly by REPORT_ID_FIRST (which returns the first report of the given
+ * type) or by (REPORT_ID_NEXT | old_id), which returns the next report of the
+ * given type which follows old_id.
+ */
+static struct hid_report *
+hiddev_lookup_report(struct hid_device *hid, struct hiddev_report_info *rinfo)
+{
+       unsigned int flags = rinfo->report_id & ~HID_REPORT_ID_MASK;
+       unsigned int rid = rinfo->report_id & HID_REPORT_ID_MASK;
+       struct hid_report_enum *report_enum;
+       struct hid_report *report;
+       struct list_head *list;
+
+       if (rinfo->report_type < HID_REPORT_TYPE_MIN ||
+           rinfo->report_type > HID_REPORT_TYPE_MAX)
+               return NULL;
+
+       report_enum = hid->report_enum +
+               (rinfo->report_type - HID_REPORT_TYPE_MIN);
+
+       switch (flags) {
+       case 0: /* Nothing to do -- report_id is already set correctly */
+               break;
+
+       case HID_REPORT_ID_FIRST:
+               if (list_empty(&report_enum->report_list))
+                       return NULL;
+
+               list = report_enum->report_list.next;
+               report = list_entry(list, struct hid_report, list);
+               rinfo->report_id = report->id;
+               break;
+
+       case HID_REPORT_ID_NEXT:
+               report = report_enum->report_id_hash[rid];
+               if (!report)
+                       return NULL;
+
+               list = report->list.next;
+               if (list == &report_enum->report_list)
+                       return NULL;
+
+               report = list_entry(list, struct hid_report, list);
+               rinfo->report_id = report->id;
+               break;
+
+       default:
+               return NULL;
+       }
+
+       return report_enum->report_id_hash[rinfo->report_id];
+}
+
+/*
+ * Perform an exhaustive search of the report table for a usage, given its
+ * type and usage id.
+ */
+static struct hid_field *
+hiddev_lookup_usage(struct hid_device *hid, struct hiddev_usage_ref *uref)
+{
+       int i, j;
+       struct hid_report *report;
+       struct hid_report_enum *report_enum;
+       struct hid_field *field;
+
+       if (uref->report_type < HID_REPORT_TYPE_MIN ||
+           uref->report_type > HID_REPORT_TYPE_MAX)
+               return NULL;
+
+       report_enum = hid->report_enum +
+               (uref->report_type - HID_REPORT_TYPE_MIN);
+
+       list_for_each_entry(report, &report_enum->report_list, list) {
+               for (i = 0; i < report->maxfield; i++) {
+                       field = report->field[i];
+                       for (j = 0; j < field->maxusage; j++) {
+                               if (field->usage[j].hid == uref->usage_code) {
+                                       uref->report_id = report->id;
+                                       uref->field_index = i;
+                                       uref->usage_index = j;
+                                       return field;
+                               }
+                       }
+               }
+       }
+
+       return NULL;
+}
+
+static void hiddev_send_event(struct hid_device *hid,
+                             struct hiddev_usage_ref *uref)
+{
+       struct hiddev *hiddev = hid->hiddev;
+       struct hiddev_list *list;
+
+       list_for_each_entry(list, &hiddev->list, node) {
+               if (uref->field_index != HID_FIELD_INDEX_NONE ||
+                   (list->flags & HIDDEV_FLAG_REPORT) != 0) {
+                       list->buffer[list->head] = *uref;
+                       list->head = (list->head + 1) &
+                               (HIDDEV_BUFFER_SIZE - 1);
+                       kill_fasync(&list->fasync, SIGIO, POLL_IN);
+               }
+       }
+
+       wake_up_interruptible(&hiddev->wait);
+}
+
+/*
+ * This is where hid.c calls into hiddev to pass an event that occurred over
+ * the interrupt pipe
+ */
+void hiddev_hid_event(struct hid_device *hid, struct hid_field *field,
+                     struct hid_usage *usage, __s32 value)
+{
+       unsigned type = field->report_type;
+       struct hiddev_usage_ref uref;
+
+       uref.report_type =
+         (type == HID_INPUT_REPORT) ? HID_REPORT_TYPE_INPUT :
+         ((type == HID_OUTPUT_REPORT) ? HID_REPORT_TYPE_OUTPUT :
+          ((type == HID_FEATURE_REPORT) ? HID_REPORT_TYPE_FEATURE : 0));
+       uref.report_id = field->report->id;
+       uref.field_index = field->index;
+       uref.usage_index = (usage - field->usage);
+       uref.usage_code = usage->hid;
+       uref.value = value;
+
+       hiddev_send_event(hid, &uref);
+}
+EXPORT_SYMBOL_GPL(hiddev_hid_event);
+
+void hiddev_report_event(struct hid_device *hid, struct hid_report *report)
+{
+       unsigned type = report->type;
+       struct hiddev_usage_ref uref;
+
+       memset(&uref, 0, sizeof(uref));
+       uref.report_type =
+         (type == HID_INPUT_REPORT) ? HID_REPORT_TYPE_INPUT :
+         ((type == HID_OUTPUT_REPORT) ? HID_REPORT_TYPE_OUTPUT :
+          ((type == HID_FEATURE_REPORT) ? HID_REPORT_TYPE_FEATURE : 0));
+       uref.report_id = report->id;
+       uref.field_index = HID_FIELD_INDEX_NONE;
+
+       hiddev_send_event(hid, &uref);
+}
+
+/*
+ * fasync file op
+ */
+static int hiddev_fasync(int fd, struct file *file, int on)
+{
+       int retval;
+       struct hiddev_list *list = file->private_data;
+
+       retval = fasync_helper(fd, file, on, &list->fasync);
+
+       return retval < 0 ? retval : 0;
+}
+
+
+/*
+ * release file op
+ */
+static int hiddev_release(struct inode * inode, struct file * file)
+{
+       struct hiddev_list *list = file->private_data;
+
+       hiddev_fasync(-1, file, 0);
+       list_del(&list->node);
+
+       if (!--list->hiddev->open) {
+               if (list->hiddev->exist)
+                       usbhid_close(list->hiddev->hid);
+               else
+                       kfree(list->hiddev);
+       }
+
+       kfree(list);
+
+       return 0;
+}
+
+/*
+ * open file op
+ */
+static int hiddev_open(struct inode *inode, struct file *file)
+{
+       struct hiddev_list *list;
+
+       int i = iminor(inode) - HIDDEV_MINOR_BASE;
+
+       if (i >= HIDDEV_MINORS || !hiddev_table[i])
+               return -ENODEV;
+
+       if (!(list = kzalloc(sizeof(struct hiddev_list), GFP_KERNEL)))
+               return -ENOMEM;
+
+       list->hiddev = hiddev_table[i];
+       list_add_tail(&list->node, &hiddev_table[i]->list);
+       file->private_data = list;
+
+       if (!list->hiddev->open++)
+               if (list->hiddev->exist)
+                       usbhid_open(hiddev_table[i]->hid);
+
+       return 0;
+}
+
+/*
+ * "write" file op
+ */
+static ssize_t hiddev_write(struct file * file, const char __user * buffer, size_t count, loff_t *ppos)
+{
+       return -EINVAL;
+}
+
+/*
+ * "read" file op
+ */
+static ssize_t hiddev_read(struct file * file, char __user * buffer, size_t count, loff_t *ppos)
+{
+       DECLARE_WAITQUEUE(wait, current);
+       struct hiddev_list *list = file->private_data;
+       int event_size;
+       int retval = 0;
+
+       event_size = ((list->flags & HIDDEV_FLAG_UREF) != 0) ?
+               sizeof(struct hiddev_usage_ref) : sizeof(struct hiddev_event);
+
+       if (count < event_size)
+               return 0;
+
+       while (retval == 0) {
+               if (list->head == list->tail) {
+                       add_wait_queue(&list->hiddev->wait, &wait);
+                       set_current_state(TASK_INTERRUPTIBLE);
+
+                       while (list->head == list->tail) {
+                               if (file->f_flags & O_NONBLOCK) {
+                                       retval = -EAGAIN;
+                                       break;
+                               }
+                               if (signal_pending(current)) {
+                                       retval = -ERESTARTSYS;
+                                       break;
+                               }
+                               if (!list->hiddev->exist) {
+                                       retval = -EIO;
+                                       break;
+                               }
+
+                               schedule();
+                               set_current_state(TASK_INTERRUPTIBLE);
+                       }
+
+                       set_current_state(TASK_RUNNING);
+                       remove_wait_queue(&list->hiddev->wait, &wait);
+               }
+
+               if (retval)
+                       return retval;
+
+
+               while (list->head != list->tail &&
+                      retval + event_size <= count) {
+                       if ((list->flags & HIDDEV_FLAG_UREF) == 0) {
+                               if (list->buffer[list->tail].field_index !=
+                                   HID_FIELD_INDEX_NONE) {
+                                       struct hiddev_event event;
+                                       event.hid = list->buffer[list->tail].usage_code;
+                                       event.value = list->buffer[list->tail].value;
+                                       if (copy_to_user(buffer + retval, &event, sizeof(struct hiddev_event)))
+                                               return -EFAULT;
+                                       retval += sizeof(struct hiddev_event);
+                               }
+                       } else {
+                               if (list->buffer[list->tail].field_index != HID_FIELD_INDEX_NONE ||
+                                   (list->flags & HIDDEV_FLAG_REPORT) != 0) {
+                                       if (copy_to_user(buffer + retval, list->buffer + list->tail, sizeof(struct hiddev_usage_ref)))
+                                               return -EFAULT;
+                                       retval += sizeof(struct hiddev_usage_ref);
+                               }
+                       }
+                       list->tail = (list->tail + 1) & (HIDDEV_BUFFER_SIZE - 1);
+               }
+
+       }
+
+       return retval;
+}
+
+/*
+ * "poll" file op
+ * No kernel lock - fine
+ */
+static unsigned int hiddev_poll(struct file *file, poll_table *wait)
+{
+       struct hiddev_list *list = file->private_data;
+
+       poll_wait(file, &list->hiddev->wait, wait);
+       if (list->head != list->tail)
+               return POLLIN | POLLRDNORM;
+       if (!list->hiddev->exist)
+               return POLLERR | POLLHUP;
+       return 0;
+}
+
+/*
+ * "ioctl" file op
+ */
+static int hiddev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+{
+       struct hiddev_list *list = file->private_data;
+       struct hiddev *hiddev = list->hiddev;
+       struct hid_device *hid = hiddev->hid;
+       struct usb_device *dev = hid_to_usb_dev(hid);
+       struct hiddev_collection_info cinfo;
+       struct hiddev_report_info rinfo;
+       struct hiddev_field_info finfo;
+       struct hiddev_usage_ref_multi *uref_multi = NULL;
+       struct hiddev_usage_ref *uref;
+       struct hiddev_devinfo dinfo;
+       struct hid_report *report;
+       struct hid_field *field;
+       struct usbhid_device *usbhid = hid->driver_data;
+       void __user *user_arg = (void __user *)arg;
+       int i;
+
+       if (!hiddev->exist)
+               return -EIO;
+
+       switch (cmd) {
+
+       case HIDIOCGVERSION:
+               return put_user(HID_VERSION, (int __user *)arg);
+
+       case HIDIOCAPPLICATION:
+               if (arg < 0 || arg >= hid->maxapplication)
+                       return -EINVAL;
+
+               for (i = 0; i < hid->maxcollection; i++)
+                       if (hid->collection[i].type ==
+                           HID_COLLECTION_APPLICATION && arg-- == 0)
+                               break;
+
+               if (i == hid->maxcollection)
+                       return -EINVAL;
+
+               return hid->collection[i].usage;
+
+       case HIDIOCGDEVINFO:
+               dinfo.bustype = BUS_USB;
+               dinfo.busnum = dev->bus->busnum;
+               dinfo.devnum = dev->devnum;
+               dinfo.ifnum = usbhid->ifnum;
+               dinfo.vendor = le16_to_cpu(dev->descriptor.idVendor);
+               dinfo.product = le16_to_cpu(dev->descriptor.idProduct);
+               dinfo.version = le16_to_cpu(dev->descriptor.bcdDevice);
+               dinfo.num_applications = hid->maxapplication;
+               if (copy_to_user(user_arg, &dinfo, sizeof(dinfo)))
+                       return -EFAULT;
+
+               return 0;
+
+       case HIDIOCGFLAG:
+               if (put_user(list->flags, (int __user *)arg))
+                       return -EFAULT;
+
+               return 0;
+
+       case HIDIOCSFLAG:
+               {
+                       int newflags;
+                       if (get_user(newflags, (int __user *)arg))
+                               return -EFAULT;
+
+                       if ((newflags & ~HIDDEV_FLAGS) != 0 ||
+                           ((newflags & HIDDEV_FLAG_REPORT) != 0 &&
+                            (newflags & HIDDEV_FLAG_UREF) == 0))
+                               return -EINVAL;
+
+                       list->flags = newflags;
+
+                       return 0;
+               }
+
+       case HIDIOCGSTRING:
+               {
+                       int idx, len;
+                       char *buf;
+
+                       if (get_user(idx, (int __user *)arg))
+                               return -EFAULT;
+
+                       if ((buf = kmalloc(HID_STRING_SIZE, GFP_KERNEL)) == NULL)
+                               return -ENOMEM;
+
+                       if ((len = usb_string(dev, idx, buf, HID_STRING_SIZE-1)) < 0) {
+                               kfree(buf);
+                               return -EINVAL;
+                       }
+
+                       if (copy_to_user(user_arg+sizeof(int), buf, len+1)) {
+                               kfree(buf);
+                               return -EFAULT;
+                       }
+
+                       kfree(buf);
+
+                       return len;
+               }
+
+       case HIDIOCINITREPORT:
+               usbhid_init_reports(hid);
+
+               return 0;
+
+       case HIDIOCGREPORT:
+               if (copy_from_user(&rinfo, user_arg, sizeof(rinfo)))
+                       return -EFAULT;
+
+               if (rinfo.report_type == HID_REPORT_TYPE_OUTPUT)
+                       return -EINVAL;
+
+               if ((report = hiddev_lookup_report(hid, &rinfo)) == NULL)
+                       return -EINVAL;
+
+               usbhid_submit_report(hid, report, USB_DIR_IN);
+               usbhid_wait_io(hid);
+
+               return 0;
+
+       case HIDIOCSREPORT:
+               if (copy_from_user(&rinfo, user_arg, sizeof(rinfo)))
+                       return -EFAULT;
+
+               if (rinfo.report_type == HID_REPORT_TYPE_INPUT)
+                       return -EINVAL;
+
+               if ((report = hiddev_lookup_report(hid, &rinfo)) == NULL)
+                       return -EINVAL;
+
+               usbhid_submit_report(hid, report, USB_DIR_OUT);
+               usbhid_wait_io(hid);
+
+               return 0;
+
+       case HIDIOCGREPORTINFO:
+               if (copy_from_user(&rinfo, user_arg, sizeof(rinfo)))
+                       return -EFAULT;
+
+               if ((report = hiddev_lookup_report(hid, &rinfo)) == NULL)
+                       return -EINVAL;
+
+               rinfo.num_fields = report->maxfield;
+
+               if (copy_to_user(user_arg, &rinfo, sizeof(rinfo)))
+                       return -EFAULT;
+
+               return 0;
+
+       case HIDIOCGFIELDINFO:
+               if (copy_from_user(&finfo, user_arg, sizeof(finfo)))
+                       return -EFAULT;
+               rinfo.report_type = finfo.report_type;
+               rinfo.report_id = finfo.report_id;
+               if ((report = hiddev_lookup_report(hid, &rinfo)) == NULL)
+                       return -EINVAL;
+
+               if (finfo.field_index >= report->maxfield)
+                       return -EINVAL;
+
+               field = report->field[finfo.field_index];
+               memset(&finfo, 0, sizeof(finfo));
+               finfo.report_type = rinfo.report_type;
+               finfo.report_id = rinfo.report_id;
+               finfo.field_index = field->report_count - 1;
+               finfo.maxusage = field->maxusage;
+               finfo.flags = field->flags;
+               finfo.physical = field->physical;
+               finfo.logical = field->logical;
+               finfo.application = field->application;
+               finfo.logical_minimum = field->logical_minimum;
+               finfo.logical_maximum = field->logical_maximum;
+               finfo.physical_minimum = field->physical_minimum;
+               finfo.physical_maximum = field->physical_maximum;
+               finfo.unit_exponent = field->unit_exponent;
+               finfo.unit = field->unit;
+
+               if (copy_to_user(user_arg, &finfo, sizeof(finfo)))
+                       return -EFAULT;
+
+               return 0;
+
+       case HIDIOCGUCODE:
+               uref_multi = kmalloc(sizeof(struct hiddev_usage_ref_multi), GFP_KERNEL);
+               if (!uref_multi)
+                       return -ENOMEM;
+               uref = &uref_multi->uref;
+               if (copy_from_user(uref, user_arg, sizeof(*uref)))
+                       goto fault;
+
+               rinfo.report_type = uref->report_type;
+               rinfo.report_id = uref->report_id;
+               if ((report = hiddev_lookup_report(hid, &rinfo)) == NULL)
+                       goto inval;
+
+               if (uref->field_index >= report->maxfield)
+                       goto inval;
+
+               field = report->field[uref->field_index];
+               if (uref->usage_index >= field->maxusage)
+                       goto inval;
+
+               uref->usage_code = field->usage[uref->usage_index].hid;
+
+               if (copy_to_user(user_arg, uref, sizeof(*uref)))
+                       goto fault;
+
+               kfree(uref_multi);
+               return 0;
+
+       case HIDIOCGUSAGE:
+       case HIDIOCSUSAGE:
+       case HIDIOCGUSAGES:
+       case HIDIOCSUSAGES:
+       case HIDIOCGCOLLECTIONINDEX:
+               uref_multi = kmalloc(sizeof(struct hiddev_usage_ref_multi), GFP_KERNEL);
+               if (!uref_multi)
+                       return -ENOMEM;
+               uref = &uref_multi->uref;
+               if (cmd == HIDIOCGUSAGES || cmd == HIDIOCSUSAGES) {
+                       if (copy_from_user(uref_multi, user_arg,
+                                          sizeof(*uref_multi)))
+                               goto fault;
+               } else {
+                       if (copy_from_user(uref, user_arg, sizeof(*uref)))
+                               goto fault;
+               }
+
+               if (cmd != HIDIOCGUSAGE &&
+                   cmd != HIDIOCGUSAGES &&
+                   uref->report_type == HID_REPORT_TYPE_INPUT)
+                       goto inval;
+
+               if (uref->report_id == HID_REPORT_ID_UNKNOWN) {
+                       field = hiddev_lookup_usage(hid, uref);
+                       if (field == NULL)
+                               goto inval;
+               } else {
+                       rinfo.report_type = uref->report_type;
+                       rinfo.report_id = uref->report_id;
+                       if ((report = hiddev_lookup_report(hid, &rinfo)) == NULL)
+                               goto inval;
+
+                       if (uref->field_index >= report->maxfield)
+                               goto inval;
+
+                       field = report->field[uref->field_index];
+
+                       if (cmd == HIDIOCGCOLLECTIONINDEX) {
+                               if (uref->usage_index >= field->maxusage)
+                                       goto inval;
+                       } else if (uref->usage_index >= field->report_count)
+                               goto inval;
+
+                       else if ((cmd == HIDIOCGUSAGES || cmd == HIDIOCSUSAGES) &&
+                                (uref_multi->num_values > HID_MAX_MULTI_USAGES ||
+                                 uref->usage_index + uref_multi->num_values > field->report_count))
+                               goto inval;
+                       }
+
+               switch (cmd) {
+                       case HIDIOCGUSAGE:
+                               uref->value = field->value[uref->usage_index];
+                               if (copy_to_user(user_arg, uref, sizeof(*uref)))
+                                       goto fault;
+                               goto goodreturn;
+
+                       case HIDIOCSUSAGE:
+                               field->value[uref->usage_index] = uref->value;
+                               goto goodreturn;
+
+                       case HIDIOCGCOLLECTIONINDEX:
+                               kfree(uref_multi);
+                               return field->usage[uref->usage_index].collection_index;
+                       case HIDIOCGUSAGES:
+                               for (i = 0; i < uref_multi->num_values; i++)
+                                       uref_multi->values[i] =
+                                           field->value[uref->usage_index + i];
+                               if (copy_to_user(user_arg, uref_multi,
+                                                sizeof(*uref_multi)))
+                                       goto fault;
+                               goto goodreturn;
+                       case HIDIOCSUSAGES:
+                               for (i = 0; i < uref_multi->num_values; i++)
+                                       field->value[uref->usage_index + i] =
+                                           uref_multi->values[i];
+                               goto goodreturn;
+               }
+
+goodreturn:
+               kfree(uref_multi);
+               return 0;
+fault:
+               kfree(uref_multi);
+               return -EFAULT;
+inval:
+               kfree(uref_multi);
+               return -EINVAL;
+
+       case HIDIOCGCOLLECTIONINFO:
+               if (copy_from_user(&cinfo, user_arg, sizeof(cinfo)))
+                       return -EFAULT;
+
+               if (cinfo.index >= hid->maxcollection)
+                       return -EINVAL;
+
+               cinfo.type = hid->collection[cinfo.index].type;
+               cinfo.usage = hid->collection[cinfo.index].usage;
+               cinfo.level = hid->collection[cinfo.index].level;
+
+               if (copy_to_user(user_arg, &cinfo, sizeof(cinfo)))
+                       return -EFAULT;
+               return 0;
+
+       default:
+
+               if (_IOC_TYPE(cmd) != 'H' || _IOC_DIR(cmd) != _IOC_READ)
+                       return -EINVAL;
+
+               if (_IOC_NR(cmd) == _IOC_NR(HIDIOCGNAME(0))) {
+                       int len;
+                       if (!hid->name)
+                               return 0;
+                       len = strlen(hid->name) + 1;
+                       if (len > _IOC_SIZE(cmd))
+                                len = _IOC_SIZE(cmd);
+                       return copy_to_user(user_arg, hid->name, len) ?
+                               -EFAULT : len;
+               }
+
+               if (_IOC_NR(cmd) == _IOC_NR(HIDIOCGPHYS(0))) {
+                       int len;
+                       if (!hid->phys)
+                               return 0;
+                       len = strlen(hid->phys) + 1;
+                       if (len > _IOC_SIZE(cmd))
+                               len = _IOC_SIZE(cmd);
+                       return copy_to_user(user_arg, hid->phys, len) ?
+                               -EFAULT : len;
+               }
+       }
+       return -EINVAL;
+}
+
+static const struct file_operations hiddev_fops = {
+       .owner =        THIS_MODULE,
+       .read =         hiddev_read,
+       .write =        hiddev_write,
+       .poll =         hiddev_poll,
+       .open =         hiddev_open,
+       .release =      hiddev_release,
+       .ioctl =        hiddev_ioctl,
+       .fasync =       hiddev_fasync,
+};
+
+static struct usb_class_driver hiddev_class = {
+       .name =         "hiddev%d",
+       .fops =         &hiddev_fops,
+       .minor_base =   HIDDEV_MINOR_BASE,
+};
+
+/*
+ * This is where hid.c calls us to connect a hid device to the hiddev driver
+ */
+int hiddev_connect(struct hid_device *hid)
+{
+       struct hiddev *hiddev;
+       struct usbhid_device *usbhid = hid->driver_data;
+       int i;
+       int retval;
+
+       for (i = 0; i < hid->maxcollection; i++)
+               if (hid->collection[i].type ==
+                   HID_COLLECTION_APPLICATION &&
+                   !IS_INPUT_APPLICATION(hid->collection[i].usage))
+                       break;
+
+       if (i == hid->maxcollection && (hid->quirks & HID_QUIRK_HIDDEV) == 0)
+               return -1;
+
+       if (!(hiddev = kzalloc(sizeof(struct hiddev), GFP_KERNEL)))
+               return -1;
+
+       retval = usb_register_dev(usbhid->intf, &hiddev_class);
+       if (retval) {
+               err("Not able to get a minor for this device.");
+               kfree(hiddev);
+               return -1;
+       }
+
+       init_waitqueue_head(&hiddev->wait);
+       INIT_LIST_HEAD(&hiddev->list);
+       hiddev->hid = hid;
+       hiddev->exist = 1;
+
+       hid->minor = usbhid->intf->minor;
+       hid->hiddev = hiddev;
+
+       hiddev_table[usbhid->intf->minor - HIDDEV_MINOR_BASE] = hiddev;
+
+       return 0;
+}
+
+/*
+ * This is where hid.c calls us to disconnect a hiddev device from the
+ * corresponding hid device (usually because the usb device has disconnected)
+ */
+static struct usb_class_driver hiddev_class;
+void hiddev_disconnect(struct hid_device *hid)
+{
+       struct hiddev *hiddev = hid->hiddev;
+       struct usbhid_device *usbhid = hid->driver_data;
+
+       hiddev->exist = 0;
+
+       hiddev_table[hiddev->hid->minor - HIDDEV_MINOR_BASE] = NULL;
+       usb_deregister_dev(usbhid->intf, &hiddev_class);
+
+       if (hiddev->open) {
+               usbhid_close(hiddev->hid);
+               wake_up_interruptible(&hiddev->wait);
+       } else {
+               kfree(hiddev);
+       }
+}
+
+/* Currently this driver is a USB driver.  It's not a conventional one in
+ * the sense that it doesn't probe at the USB level.  Instead it waits to
+ * be connected by HID through the hiddev_connect / hiddev_disconnect
+ * routines.  The reason to register as a USB device is to gain part of the
+ * minor number space from the USB major.
+ *
+ * In theory, should the HID code be generalized to more than one physical
+ * medium (say, IEEE 1384), this driver will probably need to register its
+ * own major number, and in doing so, no longer need to register with USB.
+ * At that point the probe routine and hiddev_driver struct below will no
+ * longer be useful.
+ */
+
+
+/* We never attach in this manner, and rely on HID to connect us.  This
+ * is why there is no disconnect routine defined in the usb_driver either.
+ */
+static int hiddev_usbd_probe(struct usb_interface *intf,
+                            const struct usb_device_id *hiddev_info)
+{
+       return -ENODEV;
+}
+
+
+static /* const */ struct usb_driver hiddev_driver = {
+       .name =         "hiddev",
+       .probe =        hiddev_usbd_probe,
+};
+
+int __init hiddev_init(void)
+{
+       return usb_register(&hiddev_driver);
+}
+
+void hiddev_exit(void)
+{
+       usb_deregister(&hiddev_driver);
+}
diff --git a/drivers/hid/usbhid/usbhid.h b/drivers/hid/usbhid/usbhid.h
new file mode 100644 (file)
index 0000000..0023f96
--- /dev/null
@@ -0,0 +1,87 @@
+#ifndef __USBHID_H
+#define __USBHID_H
+
+/*
+ *  Copyright (c) 1999 Andreas Gal
+ *  Copyright (c) 2000-2001 Vojtech Pavlik
+ *  Copyright (c) 2006 Jiri Kosina
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/list.h>
+#include <linux/timer.h>
+#include <linux/workqueue.h>
+#include <linux/input.h>
+
+/*  API provided by hid-core.c for USB HID drivers */
+int usbhid_wait_io(struct hid_device* hid);
+void usbhid_close(struct hid_device *hid);
+int usbhid_open(struct hid_device *hid);
+void usbhid_init_reports(struct hid_device *hid);
+void usbhid_submit_report(struct hid_device *hid, struct hid_report *report, unsigned char dir);
+
+/*
+ * USB-specific HID struct, to be pointed to
+ * from struct hid_device->driver_data
+ */
+
+struct usbhid_device {
+       struct hid_device *hid;                                         /* pointer to corresponding HID dev */
+
+       struct usb_interface *intf;                                     /* USB interface */
+       int ifnum;                                                      /* USB interface number */
+
+       unsigned int bufsize;                                           /* URB buffer size */
+
+       struct urb *urbin;                                              /* Input URB */
+       char *inbuf;                                                    /* Input buffer */
+       dma_addr_t inbuf_dma;                                           /* Input buffer dma */
+       spinlock_t inlock;                                              /* Input fifo spinlock */
+
+       struct urb *urbctrl;                                            /* Control URB */
+       struct usb_ctrlrequest *cr;                                     /* Control request struct */
+       dma_addr_t cr_dma;                                              /* Control request struct dma */
+       struct hid_control_fifo ctrl[HID_CONTROL_FIFO_SIZE];            /* Control fifo */
+       unsigned char ctrlhead, ctrltail;                               /* Control fifo head & tail */
+       char *ctrlbuf;                                                  /* Control buffer */
+       dma_addr_t ctrlbuf_dma;                                         /* Control buffer dma */
+       spinlock_t ctrllock;                                            /* Control fifo spinlock */
+
+       struct urb *urbout;                                             /* Output URB */
+       struct hid_report *out[HID_CONTROL_FIFO_SIZE];                  /* Output pipe fifo */
+       unsigned char outhead, outtail;                                 /* Output pipe fifo head & tail */
+       char *outbuf;                                                   /* Output buffer */
+       dma_addr_t outbuf_dma;                                          /* Output buffer dma */
+       spinlock_t outlock;                                             /* Output fifo spinlock */
+
+       unsigned long iofl;                                             /* I/O flags (CTRL_RUNNING, OUT_RUNNING) */
+       struct timer_list io_retry;                                     /* Retry timer */
+       unsigned long stop_retry;                                       /* Time to give up, in jiffies */
+       unsigned int retry_delay;                                       /* Delay length in ms */
+       struct work_struct reset_work;                                  /* Task context for resets */
+
+};
+
+#define        hid_to_usb_dev(hid_dev) \
+       container_of(hid_dev->dev->parent, struct usb_device, dev)
+
+#endif
+
diff --git a/drivers/hid/usbhid/usbkbd.c b/drivers/hid/usbhid/usbkbd.c
new file mode 100644 (file)
index 0000000..3749f4a
--- /dev/null
@@ -0,0 +1,362 @@
+/*
+ * $Id: usbkbd.c,v 1.27 2001/12/27 10:37:41 vojtech Exp $
+ *
+ *  Copyright (c) 1999-2001 Vojtech Pavlik
+ *
+ *  USB HIDBP Keyboard support
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Should you need to contact me, the author, you can do so either by
+ * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
+ * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
+ */
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/usb/input.h>
+#include <linux/hid.h>
+
+/*
+ * Version Information
+ */
+#define DRIVER_VERSION ""
+#define DRIVER_AUTHOR "Vojtech Pavlik <vojtech@ucw.cz>"
+#define DRIVER_DESC "USB HID Boot Protocol keyboard driver"
+#define DRIVER_LICENSE "GPL"
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE(DRIVER_LICENSE);
+
+static unsigned char usb_kbd_keycode[256] = {
+         0,  0,  0,  0, 30, 48, 46, 32, 18, 33, 34, 35, 23, 36, 37, 38,
+        50, 49, 24, 25, 16, 19, 31, 20, 22, 47, 17, 45, 21, 44,  2,  3,
+         4,  5,  6,  7,  8,  9, 10, 11, 28,  1, 14, 15, 57, 12, 13, 26,
+        27, 43, 43, 39, 40, 41, 51, 52, 53, 58, 59, 60, 61, 62, 63, 64,
+        65, 66, 67, 68, 87, 88, 99, 70,119,110,102,104,111,107,109,106,
+       105,108,103, 69, 98, 55, 74, 78, 96, 79, 80, 81, 75, 76, 77, 71,
+        72, 73, 82, 83, 86,127,116,117,183,184,185,186,187,188,189,190,
+       191,192,193,194,134,138,130,132,128,129,131,137,133,135,136,113,
+       115,114,  0,  0,  0,121,  0, 89, 93,124, 92, 94, 95,  0,  0,  0,
+       122,123, 90, 91, 85,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+         0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+         0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+         0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+         0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+        29, 42, 56,125, 97, 54,100,126,164,166,165,163,161,115,114,113,
+       150,158,159,128,136,177,178,176,142,152,173,140
+};
+
+struct usb_kbd {
+       struct input_dev *dev;
+       struct usb_device *usbdev;
+       unsigned char old[8];
+       struct urb *irq, *led;
+       unsigned char newleds;
+       char name[128];
+       char phys[64];
+
+       unsigned char *new;
+       struct usb_ctrlrequest *cr;
+       unsigned char *leds;
+       dma_addr_t cr_dma;
+       dma_addr_t new_dma;
+       dma_addr_t leds_dma;
+};
+
+static void usb_kbd_irq(struct urb *urb)
+{
+       struct usb_kbd *kbd = urb->context;
+       int i;
+
+       switch (urb->status) {
+       case 0:                 /* success */
+               break;
+       case -ECONNRESET:       /* unlink */
+       case -ENOENT:
+       case -ESHUTDOWN:
+               return;
+       /* -EPIPE:  should clear the halt */
+       default:                /* error */
+               goto resubmit;
+       }
+
+       for (i = 0; i < 8; i++)
+               input_report_key(kbd->dev, usb_kbd_keycode[i + 224], (kbd->new[0] >> i) & 1);
+
+       for (i = 2; i < 8; i++) {
+
+               if (kbd->old[i] > 3 && memscan(kbd->new + 2, kbd->old[i], 6) == kbd->new + 8) {
+                       if (usb_kbd_keycode[kbd->old[i]])
+                               input_report_key(kbd->dev, usb_kbd_keycode[kbd->old[i]], 0);
+                       else
+                               info("Unknown key (scancode %#x) released.", kbd->old[i]);
+               }
+
+               if (kbd->new[i] > 3 && memscan(kbd->old + 2, kbd->new[i], 6) == kbd->old + 8) {
+                       if (usb_kbd_keycode[kbd->new[i]])
+                               input_report_key(kbd->dev, usb_kbd_keycode[kbd->new[i]], 1);
+                       else
+                               info("Unknown key (scancode %#x) pressed.", kbd->new[i]);
+               }
+       }
+
+       input_sync(kbd->dev);
+
+       memcpy(kbd->old, kbd->new, 8);
+
+resubmit:
+       i = usb_submit_urb (urb, GFP_ATOMIC);
+       if (i)
+               err ("can't resubmit intr, %s-%s/input0, status %d",
+                               kbd->usbdev->bus->bus_name,
+                               kbd->usbdev->devpath, i);
+}
+
+static int usb_kbd_event(struct input_dev *dev, unsigned int type,
+                        unsigned int code, int value)
+{
+       struct usb_kbd *kbd = dev->private;
+
+       if (type != EV_LED)
+               return -1;
+
+
+       kbd->newleds = (!!test_bit(LED_KANA,    dev->led) << 3) | (!!test_bit(LED_COMPOSE, dev->led) << 3) |
+                      (!!test_bit(LED_SCROLLL, dev->led) << 2) | (!!test_bit(LED_CAPSL,   dev->led) << 1) |
+                      (!!test_bit(LED_NUML,    dev->led));
+
+       if (kbd->led->status == -EINPROGRESS)
+               return 0;
+
+       if (*(kbd->leds) == kbd->newleds)
+               return 0;
+
+       *(kbd->leds) = kbd->newleds;
+       kbd->led->dev = kbd->usbdev;
+       if (usb_submit_urb(kbd->led, GFP_ATOMIC))
+               err("usb_submit_urb(leds) failed");
+
+       return 0;
+}
+
+static void usb_kbd_led(struct urb *urb)
+{
+       struct usb_kbd *kbd = urb->context;
+
+       if (urb->status)
+               warn("led urb status %d received", urb->status);
+
+       if (*(kbd->leds) == kbd->newleds)
+               return;
+
+       *(kbd->leds) = kbd->newleds;
+       kbd->led->dev = kbd->usbdev;
+       if (usb_submit_urb(kbd->led, GFP_ATOMIC))
+               err("usb_submit_urb(leds) failed");
+}
+
+static int usb_kbd_open(struct input_dev *dev)
+{
+       struct usb_kbd *kbd = dev->private;
+
+       kbd->irq->dev = kbd->usbdev;
+       if (usb_submit_urb(kbd->irq, GFP_KERNEL))
+               return -EIO;
+
+       return 0;
+}
+
+static void usb_kbd_close(struct input_dev *dev)
+{
+       struct usb_kbd *kbd = dev->private;
+
+       usb_kill_urb(kbd->irq);
+}
+
+static int usb_kbd_alloc_mem(struct usb_device *dev, struct usb_kbd *kbd)
+{
+       if (!(kbd->irq = usb_alloc_urb(0, GFP_KERNEL)))
+               return -1;
+       if (!(kbd->led = usb_alloc_urb(0, GFP_KERNEL)))
+               return -1;
+       if (!(kbd->new = usb_buffer_alloc(dev, 8, GFP_ATOMIC, &kbd->new_dma)))
+               return -1;
+       if (!(kbd->cr = usb_buffer_alloc(dev, sizeof(struct usb_ctrlrequest), GFP_ATOMIC, &kbd->cr_dma)))
+               return -1;
+       if (!(kbd->leds = usb_buffer_alloc(dev, 1, GFP_ATOMIC, &kbd->leds_dma)))
+               return -1;
+
+       return 0;
+}
+
+static void usb_kbd_free_mem(struct usb_device *dev, struct usb_kbd *kbd)
+{
+       usb_free_urb(kbd->irq);
+       usb_free_urb(kbd->led);
+       if (kbd->new)
+               usb_buffer_free(dev, 8, kbd->new, kbd->new_dma);
+       if (kbd->cr)
+               usb_buffer_free(dev, sizeof(struct usb_ctrlrequest), kbd->cr, kbd->cr_dma);
+       if (kbd->leds)
+               usb_buffer_free(dev, 1, kbd->leds, kbd->leds_dma);
+}
+
+static int usb_kbd_probe(struct usb_interface *iface,
+                        const struct usb_device_id *id)
+{
+       struct usb_device *dev = interface_to_usbdev(iface);
+       struct usb_host_interface *interface;
+       struct usb_endpoint_descriptor *endpoint;
+       struct usb_kbd *kbd;
+       struct input_dev *input_dev;
+       int i, pipe, maxp;
+
+       interface = iface->cur_altsetting;
+
+       if (interface->desc.bNumEndpoints != 1)
+               return -ENODEV;
+
+       endpoint = &interface->endpoint[0].desc;
+       if (!usb_endpoint_is_int_in(endpoint))
+               return -ENODEV;
+
+       pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);
+       maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe));
+
+       kbd = kzalloc(sizeof(struct usb_kbd), GFP_KERNEL);
+       input_dev = input_allocate_device();
+       if (!kbd || !input_dev)
+               goto fail1;
+
+       if (usb_kbd_alloc_mem(dev, kbd))
+               goto fail2;
+
+       kbd->usbdev = dev;
+       kbd->dev = input_dev;
+
+       if (dev->manufacturer)
+               strlcpy(kbd->name, dev->manufacturer, sizeof(kbd->name));
+
+       if (dev->product) {
+               if (dev->manufacturer)
+                       strlcat(kbd->name, " ", sizeof(kbd->name));
+               strlcat(kbd->name, dev->product, sizeof(kbd->name));
+       }
+
+       if (!strlen(kbd->name))
+               snprintf(kbd->name, sizeof(kbd->name),
+                        "USB HIDBP Keyboard %04x:%04x",
+                        le16_to_cpu(dev->descriptor.idVendor),
+                        le16_to_cpu(dev->descriptor.idProduct));
+
+       usb_make_path(dev, kbd->phys, sizeof(kbd->phys));
+       strlcpy(kbd->phys, "/input0", sizeof(kbd->phys));
+
+       input_dev->name = kbd->name;
+       input_dev->phys = kbd->phys;
+       usb_to_input_id(dev, &input_dev->id);
+       input_dev->cdev.dev = &iface->dev;
+       input_dev->private = kbd;
+
+       input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_LED) | BIT(EV_REP);
+       input_dev->ledbit[0] = BIT(LED_NUML) | BIT(LED_CAPSL) | BIT(LED_SCROLLL) | BIT(LED_COMPOSE) | BIT(LED_KANA);
+
+       for (i = 0; i < 255; i++)
+               set_bit(usb_kbd_keycode[i], input_dev->keybit);
+       clear_bit(0, input_dev->keybit);
+
+       input_dev->event = usb_kbd_event;
+       input_dev->open = usb_kbd_open;
+       input_dev->close = usb_kbd_close;
+
+       usb_fill_int_urb(kbd->irq, dev, pipe,
+                        kbd->new, (maxp > 8 ? 8 : maxp),
+                        usb_kbd_irq, kbd, endpoint->bInterval);
+       kbd->irq->transfer_dma = kbd->new_dma;
+       kbd->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+
+       kbd->cr->bRequestType = USB_TYPE_CLASS | USB_RECIP_INTERFACE;
+       kbd->cr->bRequest = 0x09;
+       kbd->cr->wValue = cpu_to_le16(0x200);
+       kbd->cr->wIndex = cpu_to_le16(interface->desc.bInterfaceNumber);
+       kbd->cr->wLength = cpu_to_le16(1);
+
+       usb_fill_control_urb(kbd->led, dev, usb_sndctrlpipe(dev, 0),
+                            (void *) kbd->cr, kbd->leds, 1,
+                            usb_kbd_led, kbd);
+       kbd->led->setup_dma = kbd->cr_dma;
+       kbd->led->transfer_dma = kbd->leds_dma;
+       kbd->led->transfer_flags |= (URB_NO_TRANSFER_DMA_MAP | URB_NO_SETUP_DMA_MAP);
+
+       input_register_device(kbd->dev);
+
+       usb_set_intfdata(iface, kbd);
+       return 0;
+
+fail2: usb_kbd_free_mem(dev, kbd);
+fail1: input_free_device(input_dev);
+       kfree(kbd);
+       return -ENOMEM;
+}
+
+static void usb_kbd_disconnect(struct usb_interface *intf)
+{
+       struct usb_kbd *kbd = usb_get_intfdata (intf);
+
+       usb_set_intfdata(intf, NULL);
+       if (kbd) {
+               usb_kill_urb(kbd->irq);
+               input_unregister_device(kbd->dev);
+               usb_kbd_free_mem(interface_to_usbdev(intf), kbd);
+               kfree(kbd);
+       }
+}
+
+static struct usb_device_id usb_kbd_id_table [] = {
+       { USB_INTERFACE_INFO(USB_INTERFACE_CLASS_HID, USB_INTERFACE_SUBCLASS_BOOT,
+               USB_INTERFACE_PROTOCOL_KEYBOARD) },
+       { }                                             /* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE (usb, usb_kbd_id_table);
+
+static struct usb_driver usb_kbd_driver = {
+       .name =         "usbkbd",
+       .probe =        usb_kbd_probe,
+       .disconnect =   usb_kbd_disconnect,
+       .id_table =     usb_kbd_id_table,
+};
+
+static int __init usb_kbd_init(void)
+{
+       int result = usb_register(&usb_kbd_driver);
+       if (result == 0)
+               info(DRIVER_VERSION ":" DRIVER_DESC);
+       return result;
+}
+
+static void __exit usb_kbd_exit(void)
+{
+       usb_deregister(&usb_kbd_driver);
+}
+
+module_init(usb_kbd_init);
+module_exit(usb_kbd_exit);
diff --git a/drivers/hid/usbhid/usbmouse.c b/drivers/hid/usbhid/usbmouse.c
new file mode 100644 (file)
index 0000000..692fd60
--- /dev/null
@@ -0,0 +1,245 @@
+/*
+ * $Id: usbmouse.c,v 1.15 2001/12/27 10:37:41 vojtech Exp $
+ *
+ *  Copyright (c) 1999-2001 Vojtech Pavlik
+ *
+ *  USB HIDBP Mouse support
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Should you need to contact me, the author, you can do so either by
+ * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
+ * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
+ */
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/usb/input.h>
+#include <linux/hid.h>
+
+/*
+ * Version Information
+ */
+#define DRIVER_VERSION "v1.6"
+#define DRIVER_AUTHOR "Vojtech Pavlik <vojtech@ucw.cz>"
+#define DRIVER_DESC "USB HID Boot Protocol mouse driver"
+#define DRIVER_LICENSE "GPL"
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE(DRIVER_LICENSE);
+
+struct usb_mouse {
+       char name[128];
+       char phys[64];
+       struct usb_device *usbdev;
+       struct input_dev *dev;
+       struct urb *irq;
+
+       signed char *data;
+       dma_addr_t data_dma;
+};
+
+static void usb_mouse_irq(struct urb *urb)
+{
+       struct usb_mouse *mouse = urb->context;
+       signed char *data = mouse->data;
+       struct input_dev *dev = mouse->dev;
+       int status;
+
+       switch (urb->status) {
+       case 0:                 /* success */
+               break;
+       case -ECONNRESET:       /* unlink */
+       case -ENOENT:
+       case -ESHUTDOWN:
+               return;
+       /* -EPIPE:  should clear the halt */
+       default:                /* error */
+               goto resubmit;
+       }
+
+       input_report_key(dev, BTN_LEFT,   data[0] & 0x01);
+       input_report_key(dev, BTN_RIGHT,  data[0] & 0x02);
+       input_report_key(dev, BTN_MIDDLE, data[0] & 0x04);
+       input_report_key(dev, BTN_SIDE,   data[0] & 0x08);
+       input_report_key(dev, BTN_EXTRA,  data[0] & 0x10);
+
+       input_report_rel(dev, REL_X,     data[1]);
+       input_report_rel(dev, REL_Y,     data[2]);
+       input_report_rel(dev, REL_WHEEL, data[3]);
+
+       input_sync(dev);
+resubmit:
+       status = usb_submit_urb (urb, GFP_ATOMIC);
+       if (status)
+               err ("can't resubmit intr, %s-%s/input0, status %d",
+                               mouse->usbdev->bus->bus_name,
+                               mouse->usbdev->devpath, status);
+}
+
+static int usb_mouse_open(struct input_dev *dev)
+{
+       struct usb_mouse *mouse = dev->private;
+
+       mouse->irq->dev = mouse->usbdev;
+       if (usb_submit_urb(mouse->irq, GFP_KERNEL))
+               return -EIO;
+
+       return 0;
+}
+
+static void usb_mouse_close(struct input_dev *dev)
+{
+       struct usb_mouse *mouse = dev->private;
+
+       usb_kill_urb(mouse->irq);
+}
+
+static int usb_mouse_probe(struct usb_interface *intf, const struct usb_device_id *id)
+{
+       struct usb_device *dev = interface_to_usbdev(intf);
+       struct usb_host_interface *interface;
+       struct usb_endpoint_descriptor *endpoint;
+       struct usb_mouse *mouse;
+       struct input_dev *input_dev;
+       int pipe, maxp;
+
+       interface = intf->cur_altsetting;
+
+       if (interface->desc.bNumEndpoints != 1)
+               return -ENODEV;
+
+       endpoint = &interface->endpoint[0].desc;
+       if (!usb_endpoint_is_int_in(endpoint))
+               return -ENODEV;
+
+       pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);
+       maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe));
+
+       mouse = kzalloc(sizeof(struct usb_mouse), GFP_KERNEL);
+       input_dev = input_allocate_device();
+       if (!mouse || !input_dev)
+               goto fail1;
+
+       mouse->data = usb_buffer_alloc(dev, 8, GFP_ATOMIC, &mouse->data_dma);
+       if (!mouse->data)
+               goto fail1;
+
+       mouse->irq = usb_alloc_urb(0, GFP_KERNEL);
+       if (!mouse->irq)
+               goto fail2;
+
+       mouse->usbdev = dev;
+       mouse->dev = input_dev;
+
+       if (dev->manufacturer)
+               strlcpy(mouse->name, dev->manufacturer, sizeof(mouse->name));
+
+       if (dev->product) {
+               if (dev->manufacturer)
+                       strlcat(mouse->name, " ", sizeof(mouse->name));
+               strlcat(mouse->name, dev->product, sizeof(mouse->name));
+       }
+
+       if (!strlen(mouse->name))
+               snprintf(mouse->name, sizeof(mouse->name),
+                        "USB HIDBP Mouse %04x:%04x",
+                        le16_to_cpu(dev->descriptor.idVendor),
+                        le16_to_cpu(dev->descriptor.idProduct));
+
+       usb_make_path(dev, mouse->phys, sizeof(mouse->phys));
+       strlcat(mouse->phys, "/input0", sizeof(mouse->phys));
+
+       input_dev->name = mouse->name;
+       input_dev->phys = mouse->phys;
+       usb_to_input_id(dev, &input_dev->id);
+       input_dev->cdev.dev = &intf->dev;
+
+       input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REL);
+       input_dev->keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_RIGHT) | BIT(BTN_MIDDLE);
+       input_dev->relbit[0] = BIT(REL_X) | BIT(REL_Y);
+       input_dev->keybit[LONG(BTN_MOUSE)] |= BIT(BTN_SIDE) | BIT(BTN_EXTRA);
+       input_dev->relbit[0] |= BIT(REL_WHEEL);
+
+       input_dev->private = mouse;
+       input_dev->open = usb_mouse_open;
+       input_dev->close = usb_mouse_close;
+
+       usb_fill_int_urb(mouse->irq, dev, pipe, mouse->data,
+                        (maxp > 8 ? 8 : maxp),
+                        usb_mouse_irq, mouse, endpoint->bInterval);
+       mouse->irq->transfer_dma = mouse->data_dma;
+       mouse->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+
+       input_register_device(mouse->dev);
+
+       usb_set_intfdata(intf, mouse);
+       return 0;
+
+fail2: usb_buffer_free(dev, 8, mouse->data, mouse->data_dma);
+fail1: input_free_device(input_dev);
+       kfree(mouse);
+       return -ENOMEM;
+}
+
+static void usb_mouse_disconnect(struct usb_interface *intf)
+{
+       struct usb_mouse *mouse = usb_get_intfdata (intf);
+
+       usb_set_intfdata(intf, NULL);
+       if (mouse) {
+               usb_kill_urb(mouse->irq);
+               input_unregister_device(mouse->dev);
+               usb_free_urb(mouse->irq);
+               usb_buffer_free(interface_to_usbdev(intf), 8, mouse->data, mouse->data_dma);
+               kfree(mouse);
+       }
+}
+
+static struct usb_device_id usb_mouse_id_table [] = {
+       { USB_INTERFACE_INFO(USB_INTERFACE_CLASS_HID, USB_INTERFACE_SUBCLASS_BOOT,
+               USB_INTERFACE_PROTOCOL_MOUSE) },
+       { }     /* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE (usb, usb_mouse_id_table);
+
+static struct usb_driver usb_mouse_driver = {
+       .name           = "usbmouse",
+       .probe          = usb_mouse_probe,
+       .disconnect     = usb_mouse_disconnect,
+       .id_table       = usb_mouse_id_table,
+};
+
+static int __init usb_mouse_init(void)
+{
+       int retval = usb_register(&usb_mouse_driver);
+       if (retval == 0)
+               info(DRIVER_VERSION ":" DRIVER_DESC);
+       return retval;
+}
+
+static void __exit usb_mouse_exit(void)
+{
+       usb_deregister(&usb_mouse_driver);
+}
+
+module_init(usb_mouse_init);
+module_exit(usb_mouse_exit);
index 8b7ff467d26242a2b08a55a4055e25d26bf17d49..f972fcc798b69e82fd31dfa7f10ae1bbabb16e90 100644 (file)
@@ -27,10 +27,7 @@ obj-$(CONFIG_USB)            += storage/
 obj-$(CONFIG_USB_ACECAD)       += input/
 obj-$(CONFIG_USB_AIPTEK)       += input/
 obj-$(CONFIG_USB_ATI_REMOTE)   += input/
-obj-$(CONFIG_USB_HID)          += input/
-obj-$(CONFIG_USB_KBD)          += input/
 obj-$(CONFIG_USB_KBTAB)                += input/
-obj-$(CONFIG_USB_MOUSE)                += input/
 obj-$(CONFIG_USB_MTOUCH)       += input/
 obj-$(CONFIG_USB_POWERMATE)    += input/
 obj-$(CONFIG_USB_WACOM)                += input/
index 69a9f3b6d0a9eaedb2d6c63078c02cc57ab0f4e3..a792e42f58afbe4baf53c34c56f59f79fd97ea48 100644 (file)
@@ -4,151 +4,6 @@
 comment "USB Input Devices"
        depends on USB
 
-config USB_HID
-       tristate "USB Human Interface Device (full HID) support"
-       default y
-       depends on USB && INPUT
-       select HID
-       ---help---
-         Say Y here if you want full HID support to connect USB keyboards,
-         mice, joysticks, graphic tablets, or any other HID based devices
-         to your computer via USB, as well as Uninterruptible Power Supply
-         (UPS) and monitor control devices.
-
-         You can't use this driver and the HIDBP (Boot Protocol) keyboard
-         and mouse drivers at the same time. More information is available:
-         <file:Documentation/input/input.txt>.
-
-         If unsure, say Y.
-
-         To compile this driver as a module, choose M here: the
-         module will be called usbhid.
-
-comment "Input core support is needed for USB HID input layer or HIDBP support"
-       depends on USB_HID && INPUT=n
-
-config USB_HIDINPUT_POWERBOOK
-       bool "Enable support for iBook/PowerBook special keys"
-       default n
-       depends on USB_HID
-       help
-         Say Y here if you want support for the special keys (Fn, Numlock) on
-         Apple iBooks and PowerBooks.
-
-         If unsure, say N.
-
-config HID_FF
-       bool "Force feedback support (EXPERIMENTAL)"
-       depends on USB_HID && EXPERIMENTAL
-       help
-         Say Y here is you want force feedback support for a few HID devices.
-         See below for a list of supported devices.
-
-         See <file:Documentation/input/ff.txt> for a description of the force
-         feedback API.
-
-         If unsure, say N.
-
-config HID_PID
-       bool "PID device support"
-       depends on HID_FF
-       help
-         Say Y here if you have a PID-compliant device and wish to enable force
-         feedback for it. Microsoft Sidewinder Force Feedback 2 is one of such
-         devices.
-
-config LOGITECH_FF
-       bool "Logitech devices support"
-       depends on HID_FF
-       select INPUT_FF_MEMLESS if USB_HID
-       help
-         Say Y here if you have one of these devices:
-         - Logitech WingMan Cordless RumblePad
-         - Logitech WingMan Cordless RumblePad 2
-         - Logitech WingMan Force 3D
-         - Logitech Formula Force EX
-         - Logitech MOMO Force wheel
-
-         and if you want to enable force feedback for them.
-         Note: if you say N here, this device will still be supported, but without
-         force feedback.
-
-config PANTHERLORD_FF
-       bool "PantherLord USB/PS2 2in1 Adapter support"
-       depends on HID_FF
-       select INPUT_FF_MEMLESS if USB_HID
-       help
-         Say Y here if you have a PantherLord USB/PS2 2in1 Adapter and want
-         to enable force feedback support for it.
-
-config THRUSTMASTER_FF
-       bool "ThrustMaster FireStorm Dual Power 2 support (EXPERIMENTAL)"
-       depends on HID_FF && EXPERIMENTAL
-       select INPUT_FF_MEMLESS if USB_HID
-       help
-         Say Y here if you have a THRUSTMASTER FireStore Dual Power 2,
-         and want to enable force feedback support for it.
-         Note: if you say N here, this device will still be supported, but without
-         force feedback.
-
-config ZEROPLUS_FF
-       bool "Zeroplus based game controller support"
-       depends on HID_FF
-       select INPUT_FF_MEMLESS if USB_HID
-       help
-         Say Y here if you have a Zeroplus based game controller and want to
-         enable force feedback for it.
-
-config USB_HIDDEV
-       bool "/dev/hiddev raw HID device support"
-       depends on USB_HID
-       help
-         Say Y here if you want to support HID devices (from the USB
-         specification standpoint) that aren't strictly user interface
-         devices, like monitor controls and Uninterruptable Power Supplies.
-
-         This module supports these devices separately using a separate
-         event interface on /dev/usb/hiddevX (char 180:96 to 180:111).
-
-         If unsure, say Y.
-
-menu "USB HID Boot Protocol drivers"
-       depends on USB!=n && USB_HID!=y
-
-config USB_KBD
-       tristate "USB HIDBP Keyboard (simple Boot) support"
-       depends on USB && INPUT
-       ---help---
-         Say Y here only if you are absolutely sure that you don't want
-         to use the generic HID driver for your USB keyboard and prefer
-         to use the keyboard in its limited Boot Protocol mode instead.
-
-         This is almost certainly not what you want.  This is mostly
-         useful for embedded applications or simple keyboards.
-
-         To compile this driver as a module, choose M here: the
-         module will be called usbkbd.
-
-         If even remotely unsure, say N.
-
-config USB_MOUSE
-       tristate "USB HIDBP Mouse (simple Boot) support"
-       depends on USB && INPUT
-       ---help---
-         Say Y here only if you are absolutely sure that you don't want
-         to use the generic HID driver for your USB mouse and prefer
-         to use the mouse in its limited Boot Protocol mode instead.
-
-         This is almost certainly not what you want.  This is mostly
-         useful for embedded applications or simple mice.
-
-         To compile this driver as a module, choose M here: the
-         module will be called usbmouse.
-
-         If even remotely unsure, say N.
-
-endmenu
-
 config USB_AIPTEK
        tristate "Aiptek 6000U/8000U tablet support"
        depends on USB && INPUT
index a9d206c945e99eb30b40edae16b175d90b851c1a..9bf420eef77fb6c5b10b878dca4ca14ae1b7837d 100644 (file)
@@ -4,40 +4,12 @@
 
 # Multipart objects.
 wacom-objs     := wacom_wac.o wacom_sys.o
-usbhid-objs    := hid-core.o
-
-# Optional parts of multipart objects.
-
-ifeq ($(CONFIG_USB_HIDDEV),y)
-       usbhid-objs     += hiddev.o
-endif
-ifeq ($(CONFIG_HID_PID),y)
-       usbhid-objs     += hid-pidff.o
-endif
-ifeq ($(CONFIG_LOGITECH_FF),y)
-       usbhid-objs     += hid-lgff.o
-endif
-ifeq ($(CONFIG_PANTHERLORD_FF),y)
-       usbhid-objs     += hid-plff.o
-endif
-ifeq ($(CONFIG_THRUSTMASTER_FF),y)
-       usbhid-objs     += hid-tmff.o
-endif
-ifeq ($(CONFIG_ZEROPLUS_FF),y)
-       usbhid-objs     += hid-zpff.o
-endif
-ifeq ($(CONFIG_HID_FF),y)
-       usbhid-objs     += hid-ff.o
-endif
 
 obj-$(CONFIG_USB_AIPTEK)       += aiptek.o
 obj-$(CONFIG_USB_ATI_REMOTE)   += ati_remote.o
 obj-$(CONFIG_USB_ATI_REMOTE2)  += ati_remote2.o
-obj-$(CONFIG_USB_HID)          += usbhid.o
-obj-$(CONFIG_USB_KBD)          += usbkbd.o
 obj-$(CONFIG_USB_KBTAB)                += kbtab.o
 obj-$(CONFIG_USB_KEYSPAN_REMOTE)       += keyspan_remote.o
-obj-$(CONFIG_USB_MOUSE)                += usbmouse.o
 obj-$(CONFIG_USB_MTOUCH)       += mtouchusb.o
 obj-$(CONFIG_USB_ITMTOUCH)     += itmtouch.o
 obj-$(CONFIG_USB_EGALAX)       += touchkitusb.o
diff --git a/drivers/usb/input/hid-core.c b/drivers/usb/input/hid-core.c
deleted file mode 100644 (file)
index 827a75a..0000000
+++ /dev/null
@@ -1,1477 +0,0 @@
-/*
- *  USB HID support for Linux
- *
- *  Copyright (c) 1999 Andreas Gal
- *  Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz>
- *  Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc
- *  Copyright (c) 2006-2007 Jiri Kosina
- */
-
-/*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the Free
- * Software Foundation; either version 2 of the License, or (at your option)
- * any later version.
- */
-
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/list.h>
-#include <linux/mm.h>
-#include <linux/smp_lock.h>
-#include <linux/spinlock.h>
-#include <asm/unaligned.h>
-#include <asm/byteorder.h>
-#include <linux/input.h>
-#include <linux/wait.h>
-
-#include <linux/usb.h>
-
-#include <linux/hid.h>
-#include <linux/hiddev.h>
-#include <linux/hid-debug.h>
-#include "usbhid.h"
-
-/*
- * Version Information
- */
-
-#define DRIVER_VERSION "v2.6"
-#define DRIVER_AUTHOR "Andreas Gal, Vojtech Pavlik"
-#define DRIVER_DESC "USB HID core driver"
-#define DRIVER_LICENSE "GPL"
-
-static char *hid_types[] = {"Device", "Pointer", "Mouse", "Device", "Joystick",
-                               "Gamepad", "Keyboard", "Keypad", "Multi-Axis Controller"};
-/*
- * Module parameters.
- */
-
-static unsigned int hid_mousepoll_interval;
-module_param_named(mousepoll, hid_mousepoll_interval, uint, 0644);
-MODULE_PARM_DESC(mousepoll, "Polling interval of mice");
-
-/*
- * Input submission and I/O error handler.
- */
-
-static void hid_io_error(struct hid_device *hid);
-
-/* Start up the input URB */
-static int hid_start_in(struct hid_device *hid)
-{
-       unsigned long flags;
-       int rc = 0;
-       struct usbhid_device *usbhid = hid->driver_data;
-
-       spin_lock_irqsave(&usbhid->inlock, flags);
-       if (hid->open > 0 && !test_bit(HID_SUSPENDED, &usbhid->iofl) &&
-                       !test_and_set_bit(HID_IN_RUNNING, &usbhid->iofl)) {
-               rc = usb_submit_urb(usbhid->urbin, GFP_ATOMIC);
-               if (rc != 0)
-                       clear_bit(HID_IN_RUNNING, &usbhid->iofl);
-       }
-       spin_unlock_irqrestore(&usbhid->inlock, flags);
-       return rc;
-}
-
-/* I/O retry timer routine */
-static void hid_retry_timeout(unsigned long _hid)
-{
-       struct hid_device *hid = (struct hid_device *) _hid;
-       struct usbhid_device *usbhid = hid->driver_data;
-
-       dev_dbg(&usbhid->intf->dev, "retrying intr urb\n");
-       if (hid_start_in(hid))
-               hid_io_error(hid);
-}
-
-/* Workqueue routine to reset the device or clear a halt */
-static void hid_reset(struct work_struct *work)
-{
-       struct usbhid_device *usbhid =
-               container_of(work, struct usbhid_device, reset_work);
-       struct hid_device *hid = usbhid->hid;
-       int rc_lock, rc = 0;
-
-       if (test_bit(HID_CLEAR_HALT, &usbhid->iofl)) {
-               dev_dbg(&usbhid->intf->dev, "clear halt\n");
-               rc = usb_clear_halt(hid_to_usb_dev(hid), usbhid->urbin->pipe);
-               clear_bit(HID_CLEAR_HALT, &usbhid->iofl);
-               hid_start_in(hid);
-       }
-
-       else if (test_bit(HID_RESET_PENDING, &usbhid->iofl)) {
-               dev_dbg(&usbhid->intf->dev, "resetting device\n");
-               rc = rc_lock = usb_lock_device_for_reset(hid_to_usb_dev(hid), usbhid->intf);
-               if (rc_lock >= 0) {
-                       rc = usb_reset_composite_device(hid_to_usb_dev(hid), usbhid->intf);
-                       if (rc_lock)
-                               usb_unlock_device(hid_to_usb_dev(hid));
-               }
-               clear_bit(HID_RESET_PENDING, &usbhid->iofl);
-       }
-
-       switch (rc) {
-       case 0:
-               if (!test_bit(HID_IN_RUNNING, &usbhid->iofl))
-                       hid_io_error(hid);
-               break;
-       default:
-               err("can't reset device, %s-%s/input%d, status %d",
-                               hid_to_usb_dev(hid)->bus->bus_name,
-                               hid_to_usb_dev(hid)->devpath,
-                               usbhid->ifnum, rc);
-               /* FALLTHROUGH */
-       case -EHOSTUNREACH:
-       case -ENODEV:
-       case -EINTR:
-               break;
-       }
-}
-
-/* Main I/O error handler */
-static void hid_io_error(struct hid_device *hid)
-{
-       unsigned long flags;
-       struct usbhid_device *usbhid = hid->driver_data;
-
-       spin_lock_irqsave(&usbhid->inlock, flags);
-
-       /* Stop when disconnected */
-       if (usb_get_intfdata(usbhid->intf) == NULL)
-               goto done;
-
-       /* When an error occurs, retry at increasing intervals */
-       if (usbhid->retry_delay == 0) {
-               usbhid->retry_delay = 13;       /* Then 26, 52, 104, 104, ... */
-               usbhid->stop_retry = jiffies + msecs_to_jiffies(1000);
-       } else if (usbhid->retry_delay < 100)
-               usbhid->retry_delay *= 2;
-
-       if (time_after(jiffies, usbhid->stop_retry)) {
-
-               /* Retries failed, so do a port reset */
-               if (!test_and_set_bit(HID_RESET_PENDING, &usbhid->iofl)) {
-                       schedule_work(&usbhid->reset_work);
-                       goto done;
-               }
-       }
-
-       mod_timer(&usbhid->io_retry,
-                       jiffies + msecs_to_jiffies(usbhid->retry_delay));
-done:
-       spin_unlock_irqrestore(&usbhid->inlock, flags);
-}
-
-/*
- * Input interrupt completion handler.
- */
-
-static void hid_irq_in(struct urb *urb)
-{
-       struct hid_device       *hid = urb->context;
-       struct usbhid_device    *usbhid = hid->driver_data;
-       int                     status;
-
-       switch (urb->status) {
-               case 0:                 /* success */
-                       usbhid->retry_delay = 0;
-                       hid_input_report(urb->context, HID_INPUT_REPORT,
-                                        urb->transfer_buffer,
-                                        urb->actual_length, 1);
-                       break;
-               case -EPIPE:            /* stall */
-                       clear_bit(HID_IN_RUNNING, &usbhid->iofl);
-                       set_bit(HID_CLEAR_HALT, &usbhid->iofl);
-                       schedule_work(&usbhid->reset_work);
-                       return;
-               case -ECONNRESET:       /* unlink */
-               case -ENOENT:
-               case -ESHUTDOWN:        /* unplug */
-                       clear_bit(HID_IN_RUNNING, &usbhid->iofl);
-                       return;
-               case -EILSEQ:           /* protocol error or unplug */
-               case -EPROTO:           /* protocol error or unplug */
-               case -ETIME:            /* protocol error or unplug */
-               case -ETIMEDOUT:        /* Should never happen, but... */
-                       clear_bit(HID_IN_RUNNING, &usbhid->iofl);
-                       hid_io_error(hid);
-                       return;
-               default:                /* error */
-                       warn("input irq status %d received", urb->status);
-       }
-
-       status = usb_submit_urb(urb, GFP_ATOMIC);
-       if (status) {
-               clear_bit(HID_IN_RUNNING, &usbhid->iofl);
-               if (status != -EPERM) {
-                       err("can't resubmit intr, %s-%s/input%d, status %d",
-                                       hid_to_usb_dev(hid)->bus->bus_name,
-                                       hid_to_usb_dev(hid)->devpath,
-                                       usbhid->ifnum, status);
-                       hid_io_error(hid);
-               }
-       }
-}
-
-static int hid_submit_out(struct hid_device *hid)
-{
-       struct hid_report *report;
-       struct usbhid_device *usbhid = hid->driver_data;
-
-       report = usbhid->out[usbhid->outtail];
-
-       hid_output_report(report, usbhid->outbuf);
-       usbhid->urbout->transfer_buffer_length = ((report->size - 1) >> 3) + 1 + (report->id > 0);
-       usbhid->urbout->dev = hid_to_usb_dev(hid);
-
-       dbg("submitting out urb");
-
-       if (usb_submit_urb(usbhid->urbout, GFP_ATOMIC)) {
-               err("usb_submit_urb(out) failed");
-               return -1;
-       }
-
-       return 0;
-}
-
-static int hid_submit_ctrl(struct hid_device *hid)
-{
-       struct hid_report *report;
-       unsigned char dir;
-       int len;
-       struct usbhid_device *usbhid = hid->driver_data;
-
-       report = usbhid->ctrl[usbhid->ctrltail].report;
-       dir = usbhid->ctrl[usbhid->ctrltail].dir;
-
-       len = ((report->size - 1) >> 3) + 1 + (report->id > 0);
-       if (dir == USB_DIR_OUT) {
-               hid_output_report(report, usbhid->ctrlbuf);
-               usbhid->urbctrl->pipe = usb_sndctrlpipe(hid_to_usb_dev(hid), 0);
-               usbhid->urbctrl->transfer_buffer_length = len;
-       } else {
-               int maxpacket, padlen;
-
-               usbhid->urbctrl->pipe = usb_rcvctrlpipe(hid_to_usb_dev(hid), 0);
-               maxpacket = usb_maxpacket(hid_to_usb_dev(hid), usbhid->urbctrl->pipe, 0);
-               if (maxpacket > 0) {
-                       padlen = (len + maxpacket - 1) / maxpacket;
-                       padlen *= maxpacket;
-                       if (padlen > usbhid->bufsize)
-                               padlen = usbhid->bufsize;
-               } else
-                       padlen = 0;
-               usbhid->urbctrl->transfer_buffer_length = padlen;
-       }
-       usbhid->urbctrl->dev = hid_to_usb_dev(hid);
-
-       usbhid->cr->bRequestType = USB_TYPE_CLASS | USB_RECIP_INTERFACE | dir;
-       usbhid->cr->bRequest = (dir == USB_DIR_OUT) ? HID_REQ_SET_REPORT : HID_REQ_GET_REPORT;
-       usbhid->cr->wValue = cpu_to_le16(((report->type + 1) << 8) | report->id);
-       usbhid->cr->wIndex = cpu_to_le16(usbhid->ifnum);
-       usbhid->cr->wLength = cpu_to_le16(len);
-
-       dbg("submitting ctrl urb: %s wValue=0x%04x wIndex=0x%04x wLength=%u",
-               usbhid->cr->bRequest == HID_REQ_SET_REPORT ? "Set_Report" : "Get_Report",
-               usbhid->cr->wValue, usbhid->cr->wIndex, usbhid->cr->wLength);
-
-       if (usb_submit_urb(usbhid->urbctrl, GFP_ATOMIC)) {
-               err("usb_submit_urb(ctrl) failed");
-               return -1;
-       }
-
-       return 0;
-}
-
-/*
- * Output interrupt completion handler.
- */
-
-static void hid_irq_out(struct urb *urb)
-{
-       struct hid_device *hid = urb->context;
-       struct usbhid_device *usbhid = hid->driver_data;
-       unsigned long flags;
-       int unplug = 0;
-
-       switch (urb->status) {
-               case 0:                 /* success */
-                       break;
-               case -ESHUTDOWN:        /* unplug */
-                       unplug = 1;
-               case -EILSEQ:           /* protocol error or unplug */
-               case -EPROTO:           /* protocol error or unplug */
-               case -ECONNRESET:       /* unlink */
-               case -ENOENT:
-                       break;
-               default:                /* error */
-                       warn("output irq status %d received", urb->status);
-       }
-
-       spin_lock_irqsave(&usbhid->outlock, flags);
-
-       if (unplug)
-               usbhid->outtail = usbhid->outhead;
-       else
-               usbhid->outtail = (usbhid->outtail + 1) & (HID_OUTPUT_FIFO_SIZE - 1);
-
-       if (usbhid->outhead != usbhid->outtail) {
-               if (hid_submit_out(hid)) {
-                       clear_bit(HID_OUT_RUNNING, &usbhid->iofl);
-                       wake_up(&hid->wait);
-               }
-               spin_unlock_irqrestore(&usbhid->outlock, flags);
-               return;
-       }
-
-       clear_bit(HID_OUT_RUNNING, &usbhid->iofl);
-       spin_unlock_irqrestore(&usbhid->outlock, flags);
-       wake_up(&hid->wait);
-}
-
-/*
- * Control pipe completion handler.
- */
-
-static void hid_ctrl(struct urb *urb)
-{
-       struct hid_device *hid = urb->context;
-       struct usbhid_device *usbhid = hid->driver_data;
-       unsigned long flags;
-       int unplug = 0;
-
-       spin_lock_irqsave(&usbhid->ctrllock, flags);
-
-       switch (urb->status) {
-               case 0:                 /* success */
-                       if (usbhid->ctrl[usbhid->ctrltail].dir == USB_DIR_IN)
-                               hid_input_report(urb->context, usbhid->ctrl[usbhid->ctrltail].report->type,
-                                               urb->transfer_buffer, urb->actual_length, 0);
-                       break;
-               case -ESHUTDOWN:        /* unplug */
-                       unplug = 1;
-               case -EILSEQ:           /* protocol error or unplug */
-               case -EPROTO:           /* protocol error or unplug */
-               case -ECONNRESET:       /* unlink */
-               case -ENOENT:
-               case -EPIPE:            /* report not available */
-                       break;
-               default:                /* error */
-                       warn("ctrl urb status %d received", urb->status);
-       }
-
-       if (unplug)
-               usbhid->ctrltail = usbhid->ctrlhead;
-       else
-               usbhid->ctrltail = (usbhid->ctrltail + 1) & (HID_CONTROL_FIFO_SIZE - 1);
-
-       if (usbhid->ctrlhead != usbhid->ctrltail) {
-               if (hid_submit_ctrl(hid)) {
-                       clear_bit(HID_CTRL_RUNNING, &usbhid->iofl);
-                       wake_up(&hid->wait);
-               }
-               spin_unlock_irqrestore(&usbhid->ctrllock, flags);
-               return;
-       }
-
-       clear_bit(HID_CTRL_RUNNING, &usbhid->iofl);
-       spin_unlock_irqrestore(&usbhid->ctrllock, flags);
-       wake_up(&hid->wait);
-}
-
-void usbhid_submit_report(struct hid_device *hid, struct hid_report *report, unsigned char dir)
-{
-       int head;
-       unsigned long flags;
-       struct usbhid_device *usbhid = hid->driver_data;
-
-       if ((hid->quirks & HID_QUIRK_NOGET) && dir == USB_DIR_IN)
-               return;
-
-       if (usbhid->urbout && dir == USB_DIR_OUT && report->type == HID_OUTPUT_REPORT) {
-
-               spin_lock_irqsave(&usbhid->outlock, flags);
-
-               if ((head = (usbhid->outhead + 1) & (HID_OUTPUT_FIFO_SIZE - 1)) == usbhid->outtail) {
-                       spin_unlock_irqrestore(&usbhid->outlock, flags);
-                       warn("output queue full");
-                       return;
-               }
-
-               usbhid->out[usbhid->outhead] = report;
-               usbhid->outhead = head;
-
-               if (!test_and_set_bit(HID_OUT_RUNNING, &usbhid->iofl))
-                       if (hid_submit_out(hid))
-                               clear_bit(HID_OUT_RUNNING, &usbhid->iofl);
-
-               spin_unlock_irqrestore(&usbhid->outlock, flags);
-               return;
-       }
-
-       spin_lock_irqsave(&usbhid->ctrllock, flags);
-
-       if ((head = (usbhid->ctrlhead + 1) & (HID_CONTROL_FIFO_SIZE - 1)) == usbhid->ctrltail) {
-               spin_unlock_irqrestore(&usbhid->ctrllock, flags);
-               warn("control queue full");
-               return;
-       }
-
-       usbhid->ctrl[usbhid->ctrlhead].report = report;
-       usbhid->ctrl[usbhid->ctrlhead].dir = dir;
-       usbhid->ctrlhead = head;
-
-       if (!test_and_set_bit(HID_CTRL_RUNNING, &usbhid->iofl))
-               if (hid_submit_ctrl(hid))
-                       clear_bit(HID_CTRL_RUNNING, &usbhid->iofl);
-
-       spin_unlock_irqrestore(&usbhid->ctrllock, flags);
-}
-
-static int usb_hidinput_input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
-{
-       struct hid_device *hid = dev->private;
-       struct hid_field *field;
-       int offset;
-
-       if (type == EV_FF)
-               return input_ff_event(dev, type, code, value);
-
-       if (type != EV_LED)
-               return -1;
-
-       if ((offset = hidinput_find_field(hid, type, code, &field)) == -1) {
-               warn("event field not found");
-               return -1;
-       }
-
-       hid_set_field(field, offset, value);
-       usbhid_submit_report(hid, field->report, USB_DIR_OUT);
-
-       return 0;
-}
-
-int usbhid_wait_io(struct hid_device *hid)
-{
-       struct usbhid_device *usbhid = hid->driver_data;
-
-       if (!wait_event_timeout(hid->wait, (!test_bit(HID_CTRL_RUNNING, &usbhid->iofl) &&
-                                       !test_bit(HID_OUT_RUNNING, &usbhid->iofl)),
-                                       10*HZ)) {
-               dbg("timeout waiting for ctrl or out queue to clear");
-               return -1;
-       }
-
-       return 0;
-}
-
-static int hid_set_idle(struct usb_device *dev, int ifnum, int report, int idle)
-{
-       return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
-               HID_REQ_SET_IDLE, USB_TYPE_CLASS | USB_RECIP_INTERFACE, (idle << 8) | report,
-               ifnum, NULL, 0, USB_CTRL_SET_TIMEOUT);
-}
-
-static int hid_get_class_descriptor(struct usb_device *dev, int ifnum,
-               unsigned char type, void *buf, int size)
-{
-       int result, retries = 4;
-
-       memset(buf, 0, size);
-
-       do {
-               result = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
-                               USB_REQ_GET_DESCRIPTOR, USB_RECIP_INTERFACE | USB_DIR_IN,
-                               (type << 8), ifnum, buf, size, USB_CTRL_GET_TIMEOUT);
-               retries--;
-       } while (result < size && retries);
-       return result;
-}
-
-int usbhid_open(struct hid_device *hid)
-{
-       ++hid->open;
-       if (hid_start_in(hid))
-               hid_io_error(hid);
-       return 0;
-}
-
-void usbhid_close(struct hid_device *hid)
-{
-       struct usbhid_device *usbhid = hid->driver_data;
-
-       if (!--hid->open)
-               usb_kill_urb(usbhid->urbin);
-}
-
-#define USB_VENDOR_ID_PANJIT           0x134c
-
-#define USB_VENDOR_ID_TURBOX           0x062a
-#define USB_DEVICE_ID_TURBOX_KEYBOARD  0x0201
-#define USB_VENDOR_ID_CIDC             0x1677
-
-/*
- * Initialize all reports
- */
-
-void usbhid_init_reports(struct hid_device *hid)
-{
-       struct hid_report *report;
-       struct usbhid_device *usbhid = hid->driver_data;
-       int err, ret;
-
-       list_for_each_entry(report, &hid->report_enum[HID_INPUT_REPORT].report_list, list)
-               usbhid_submit_report(hid, report, USB_DIR_IN);
-
-       list_for_each_entry(report, &hid->report_enum[HID_FEATURE_REPORT].report_list, list)
-               usbhid_submit_report(hid, report, USB_DIR_IN);
-
-       err = 0;
-       ret = usbhid_wait_io(hid);
-       while (ret) {
-               err |= ret;
-               if (test_bit(HID_CTRL_RUNNING, &usbhid->iofl))
-                       usb_kill_urb(usbhid->urbctrl);
-               if (test_bit(HID_OUT_RUNNING, &usbhid->iofl))
-                       usb_kill_urb(usbhid->urbout);
-               ret = usbhid_wait_io(hid);
-       }
-
-       if (err)
-               warn("timeout initializing reports");
-}
-
-#define USB_VENDOR_ID_GTCO             0x078c
-#define USB_DEVICE_ID_GTCO_90          0x0090
-#define USB_DEVICE_ID_GTCO_100         0x0100
-#define USB_DEVICE_ID_GTCO_101         0x0101
-#define USB_DEVICE_ID_GTCO_103         0x0103
-#define USB_DEVICE_ID_GTCO_104         0x0104
-#define USB_DEVICE_ID_GTCO_105         0x0105
-#define USB_DEVICE_ID_GTCO_106         0x0106
-#define USB_DEVICE_ID_GTCO_107         0x0107
-#define USB_DEVICE_ID_GTCO_108         0x0108
-#define USB_DEVICE_ID_GTCO_200         0x0200
-#define USB_DEVICE_ID_GTCO_201         0x0201
-#define USB_DEVICE_ID_GTCO_202         0x0202
-#define USB_DEVICE_ID_GTCO_203         0x0203
-#define USB_DEVICE_ID_GTCO_204         0x0204
-#define USB_DEVICE_ID_GTCO_205         0x0205
-#define USB_DEVICE_ID_GTCO_206         0x0206
-#define USB_DEVICE_ID_GTCO_207         0x0207
-#define USB_DEVICE_ID_GTCO_300         0x0300
-#define USB_DEVICE_ID_GTCO_301         0x0301
-#define USB_DEVICE_ID_GTCO_302         0x0302
-#define USB_DEVICE_ID_GTCO_303         0x0303
-#define USB_DEVICE_ID_GTCO_304         0x0304
-#define USB_DEVICE_ID_GTCO_305         0x0305
-#define USB_DEVICE_ID_GTCO_306         0x0306
-#define USB_DEVICE_ID_GTCO_307         0x0307
-#define USB_DEVICE_ID_GTCO_308         0x0308
-#define USB_DEVICE_ID_GTCO_309         0x0309
-#define USB_DEVICE_ID_GTCO_400         0x0400
-#define USB_DEVICE_ID_GTCO_401         0x0401
-#define USB_DEVICE_ID_GTCO_402         0x0402
-#define USB_DEVICE_ID_GTCO_403         0x0403
-#define USB_DEVICE_ID_GTCO_404         0x0404
-#define USB_DEVICE_ID_GTCO_405         0x0405
-#define USB_DEVICE_ID_GTCO_500         0x0500
-#define USB_DEVICE_ID_GTCO_501         0x0501
-#define USB_DEVICE_ID_GTCO_502         0x0502
-#define USB_DEVICE_ID_GTCO_503         0x0503
-#define USB_DEVICE_ID_GTCO_504         0x0504
-#define USB_DEVICE_ID_GTCO_1000                0x1000
-#define USB_DEVICE_ID_GTCO_1001                0x1001
-#define USB_DEVICE_ID_GTCO_1002                0x1002
-#define USB_DEVICE_ID_GTCO_1003                0x1003
-#define USB_DEVICE_ID_GTCO_1004                0x1004
-#define USB_DEVICE_ID_GTCO_1005                0x1005
-#define USB_DEVICE_ID_GTCO_1006                0x1006
-
-#define USB_VENDOR_ID_WACOM            0x056a
-
-#define USB_VENDOR_ID_ACECAD           0x0460
-#define USB_DEVICE_ID_ACECAD_FLAIR     0x0004
-#define USB_DEVICE_ID_ACECAD_302       0x0008
-
-#define USB_VENDOR_ID_KBGEAR           0x084e
-#define USB_DEVICE_ID_KBGEAR_JAMSTUDIO 0x1001
-
-#define USB_VENDOR_ID_AIPTEK           0x08ca
-#define USB_DEVICE_ID_AIPTEK_01                0x0001
-#define USB_DEVICE_ID_AIPTEK_10                0x0010
-#define USB_DEVICE_ID_AIPTEK_20                0x0020
-#define USB_DEVICE_ID_AIPTEK_21                0x0021
-#define USB_DEVICE_ID_AIPTEK_22                0x0022
-#define USB_DEVICE_ID_AIPTEK_23                0x0023
-#define USB_DEVICE_ID_AIPTEK_24                0x0024
-
-#define USB_VENDOR_ID_GRIFFIN          0x077d
-#define USB_DEVICE_ID_POWERMATE                0x0410
-#define USB_DEVICE_ID_SOUNDKNOB                0x04AA
-
-#define USB_VENDOR_ID_ATEN             0x0557
-#define USB_DEVICE_ID_ATEN_UC100KM     0x2004
-#define USB_DEVICE_ID_ATEN_CS124U      0x2202
-#define USB_DEVICE_ID_ATEN_2PORTKVM    0x2204
-#define USB_DEVICE_ID_ATEN_4PORTKVM    0x2205
-#define USB_DEVICE_ID_ATEN_4PORTKVMC   0x2208
-
-#define USB_VENDOR_ID_TOPMAX           0x0663
-#define USB_DEVICE_ID_TOPMAX_COBRAPAD  0x0103
-
-#define USB_VENDOR_ID_HAPP             0x078b
-#define USB_DEVICE_ID_UGCI_DRIVING     0x0010
-#define USB_DEVICE_ID_UGCI_FLYING      0x0020
-#define USB_DEVICE_ID_UGCI_FIGHTING    0x0030
-
-#define USB_VENDOR_ID_MGE              0x0463
-#define USB_DEVICE_ID_MGE_UPS          0xffff
-#define USB_DEVICE_ID_MGE_UPS1         0x0001
-
-#define USB_VENDOR_ID_ONTRAK           0x0a07
-#define USB_DEVICE_ID_ONTRAK_ADU100    0x0064
-
-#define USB_VENDOR_ID_ESSENTIAL_REALITY        0x0d7f
-#define USB_DEVICE_ID_ESSENTIAL_REALITY_P5 0x0100
-
-#define USB_VENDOR_ID_A4TECH           0x09da
-#define USB_DEVICE_ID_A4TECH_WCP32PU   0x0006
-
-#define USB_VENDOR_ID_AASHIMA          0x06d6
-#define USB_DEVICE_ID_AASHIMA_GAMEPAD  0x0025
-#define USB_DEVICE_ID_AASHIMA_PREDATOR 0x0026
-
-#define USB_VENDOR_ID_CYPRESS          0x04b4
-#define USB_DEVICE_ID_CYPRESS_MOUSE    0x0001
-#define USB_DEVICE_ID_CYPRESS_HIDCOM   0x5500
-#define USB_DEVICE_ID_CYPRESS_ULTRAMOUSE       0x7417
-
-#define USB_VENDOR_ID_BERKSHIRE                0x0c98
-#define USB_DEVICE_ID_BERKSHIRE_PCWD   0x1140
-
-#define USB_VENDOR_ID_ALPS             0x0433
-#define USB_DEVICE_ID_IBM_GAMEPAD      0x1101
-
-#define USB_VENDOR_ID_SAITEK           0x06a3
-#define USB_DEVICE_ID_SAITEK_RUMBLEPAD 0xff17
-
-#define USB_VENDOR_ID_NEC              0x073e
-#define USB_DEVICE_ID_NEC_USB_GAME_PAD 0x0301
-
-#define USB_VENDOR_ID_CHIC             0x05fe
-#define USB_DEVICE_ID_CHIC_GAMEPAD     0x0014
-
-#define USB_VENDOR_ID_GLAB             0x06c2
-#define USB_DEVICE_ID_4_PHIDGETSERVO_30        0x0038
-#define USB_DEVICE_ID_1_PHIDGETSERVO_30        0x0039
-#define USB_DEVICE_ID_0_0_4_IF_KIT     0x0040
-#define USB_DEVICE_ID_0_16_16_IF_KIT   0x0044
-#define USB_DEVICE_ID_8_8_8_IF_KIT     0x0045
-#define USB_DEVICE_ID_0_8_7_IF_KIT     0x0051
-#define USB_DEVICE_ID_0_8_8_IF_KIT     0x0053
-#define USB_DEVICE_ID_PHIDGET_MOTORCONTROL     0x0058
-
-#define USB_VENDOR_ID_WISEGROUP                0x0925
-#define USB_DEVICE_ID_1_PHIDGETSERVO_20        0x8101
-#define USB_DEVICE_ID_4_PHIDGETSERVO_20        0x8104
-#define USB_DEVICE_ID_8_8_4_IF_KIT     0x8201
-#define USB_DEVICE_ID_DUAL_USB_JOYPAD   0x8866
-
-#define USB_VENDOR_ID_WISEGROUP_LTD    0x6677
-#define USB_DEVICE_ID_SMARTJOY_DUAL_PLUS 0x8802
-
-#define USB_VENDOR_ID_CODEMERCS                0x07c0
-#define USB_DEVICE_ID_CODEMERCS_IOW_FIRST      0x1500
-#define USB_DEVICE_ID_CODEMERCS_IOW_LAST       0x15ff
-
-#define USB_VENDOR_ID_DELORME          0x1163
-#define USB_DEVICE_ID_DELORME_EARTHMATE 0x0100
-#define USB_DEVICE_ID_DELORME_EM_LT20  0x0200
-
-#define USB_VENDOR_ID_MCC              0x09db
-#define USB_DEVICE_ID_MCC_PMD1024LS    0x0076
-#define USB_DEVICE_ID_MCC_PMD1208LS    0x007a
-
-#define USB_VENDOR_ID_VERNIER          0x08f7
-#define USB_DEVICE_ID_VERNIER_LABPRO   0x0001
-#define USB_DEVICE_ID_VERNIER_GOTEMP   0x0002
-#define USB_DEVICE_ID_VERNIER_SKIP     0x0003
-#define USB_DEVICE_ID_VERNIER_CYCLOPS  0x0004
-
-#define USB_VENDOR_ID_LD               0x0f11
-#define USB_DEVICE_ID_LD_CASSY         0x1000
-#define USB_DEVICE_ID_LD_POCKETCASSY   0x1010
-#define USB_DEVICE_ID_LD_MOBILECASSY   0x1020
-#define USB_DEVICE_ID_LD_JWM           0x1080
-#define USB_DEVICE_ID_LD_DMMP          0x1081
-#define USB_DEVICE_ID_LD_UMIP          0x1090
-#define USB_DEVICE_ID_LD_XRAY1         0x1100
-#define USB_DEVICE_ID_LD_XRAY2         0x1101
-#define USB_DEVICE_ID_LD_VIDEOCOM      0x1200
-#define USB_DEVICE_ID_LD_COM3LAB       0x2000
-#define USB_DEVICE_ID_LD_TELEPORT      0x2010
-#define USB_DEVICE_ID_LD_NETWORKANALYSER 0x2020
-#define USB_DEVICE_ID_LD_POWERCONTROL  0x2030
-#define USB_DEVICE_ID_LD_MACHINETEST   0x2040
-
-#define USB_VENDOR_ID_APPLE            0x05ac
-#define USB_DEVICE_ID_APPLE_MIGHTYMOUSE        0x0304
-#define USB_DEVICE_ID_APPLE_FOUNTAIN_ANSI      0x020e
-#define USB_DEVICE_ID_APPLE_FOUNTAIN_ISO       0x020f
-#define USB_DEVICE_ID_APPLE_GEYSER_ANSI        0x0214
-#define USB_DEVICE_ID_APPLE_GEYSER_ISO 0x0215
-#define USB_DEVICE_ID_APPLE_GEYSER_JIS 0x0216
-#define USB_DEVICE_ID_APPLE_GEYSER3_ANSI       0x0217
-#define USB_DEVICE_ID_APPLE_GEYSER3_ISO        0x0218
-#define USB_DEVICE_ID_APPLE_GEYSER3_JIS        0x0219
-#define USB_DEVICE_ID_APPLE_GEYSER4_ANSI       0x021a
-#define USB_DEVICE_ID_APPLE_GEYSER4_ISO        0x021b
-#define USB_DEVICE_ID_APPLE_GEYSER4_JIS        0x021c
-#define USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY   0x030a
-#define USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY    0x030b
-#define USB_DEVICE_ID_APPLE_IR         0x8240
-
-#define USB_VENDOR_ID_CHERRY           0x046a
-#define USB_DEVICE_ID_CHERRY_CYMOTION  0x0023
-
-#define USB_VENDOR_ID_YEALINK          0x6993
-#define USB_DEVICE_ID_YEALINK_P1K_P4K_B2K      0xb001
-
-#define USB_VENDOR_ID_ALCOR            0x058f
-#define USB_DEVICE_ID_ALCOR_USBRS232   0x9720
-
-#define USB_VENDOR_ID_SUN              0x0430
-#define USB_DEVICE_ID_RARITAN_KVM_DONGLE       0xcdab
-
-#define USB_VENDOR_ID_AIRCABLE         0x16CA
-#define USB_DEVICE_ID_AIRCABLE1                0x1502
-
-#define USB_VENDOR_ID_LOGITECH         0x046d
-#define USB_DEVICE_ID_LOGITECH_USB_RECEIVER    0xc101
-#define USB_DEVICE_ID_LOGITECH_USB_RECEIVER_2  0xc517
-#define USB_DEVICE_ID_DINOVO_EDGE      0xc714
-
-#define USB_VENDOR_ID_IMATION          0x0718
-#define USB_DEVICE_ID_DISC_STAKKA      0xd000
-
-#define USB_VENDOR_ID_PANTHERLORD      0x0810
-#define USB_DEVICE_ID_PANTHERLORD_TWIN_USB_JOYSTICK    0x0001
-
-#define USB_VENDOR_ID_SONY                     0x054c
-#define USB_DEVICE_ID_SONY_PS3_CONTROLLER      0x0268
-
-/*
- * Alphabetically sorted blacklist by quirk type.
- */
-
-static const struct hid_blacklist {
-       __u16 idVendor;
-       __u16 idProduct;
-       unsigned quirks;
-} hid_blacklist[] = {
-
-       { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_EDGE, HID_QUIRK_DUPLICATE_USAGES },
-
-       { USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_01, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_10, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_20, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_21, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_22, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_23, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_24, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_AIRCABLE, USB_DEVICE_ID_AIRCABLE1, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_ALCOR, USB_DEVICE_ID_ALCOR_USBRS232, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_BERKSHIRE, USB_DEVICE_ID_BERKSHIRE_PCWD, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_HIDCOM, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_ULTRAMOUSE, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_DELORME, USB_DEVICE_ID_DELORME_EARTHMATE, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_DELORME, USB_DEVICE_ID_DELORME_EM_LT20, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_ESSENTIAL_REALITY, USB_DEVICE_ID_ESSENTIAL_REALITY_P5, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_GLAB, USB_DEVICE_ID_4_PHIDGETSERVO_30, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_GLAB, USB_DEVICE_ID_1_PHIDGETSERVO_30, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_GLAB, USB_DEVICE_ID_0_0_4_IF_KIT, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_GLAB, USB_DEVICE_ID_0_16_16_IF_KIT, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_GLAB, USB_DEVICE_ID_8_8_8_IF_KIT, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_GLAB, USB_DEVICE_ID_0_8_7_IF_KIT, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_GLAB, USB_DEVICE_ID_0_8_8_IF_KIT, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_GLAB, USB_DEVICE_ID_PHIDGET_MOTORCONTROL, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_GRIFFIN, USB_DEVICE_ID_POWERMATE, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_GRIFFIN, USB_DEVICE_ID_SOUNDKNOB, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_90, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_100, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_101, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_103, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_104, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_105, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_106, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_107, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_108, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_200, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_201, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_202, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_203, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_204, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_205, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_206, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_207, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_300, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_301, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_302, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_303, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_304, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_305, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_306, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_307, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_308, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_309, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_400, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_401, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_402, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_403, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_404, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_405, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_500, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_501, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_502, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_503, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_504, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1000, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1001, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1002, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1003, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1004, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1005, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1006, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_IMATION, USB_DEVICE_ID_DISC_STAKKA, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_KBGEAR, USB_DEVICE_ID_KBGEAR_JAMSTUDIO, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_CASSY, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_POCKETCASSY, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MOBILECASSY, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_JWM, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_DMMP, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_UMIP, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_XRAY1, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_XRAY2, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_VIDEOCOM, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_COM3LAB, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_TELEPORT, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_NETWORKANALYSER, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_POWERCONTROL, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MACHINETEST, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_MCC, USB_DEVICE_ID_MCC_PMD1024LS, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_MCC, USB_DEVICE_ID_MCC_PMD1208LS, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS1, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 20, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 30, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 100, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 108, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 118, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 200, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 300, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 400, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 500, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_LABPRO, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_GOTEMP, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_SKIP, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_CYCLOPS, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_4_PHIDGETSERVO_20, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_1_PHIDGETSERVO_20, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_8_8_4_IF_KIT, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_YEALINK, USB_DEVICE_ID_YEALINK_P1K_P4K_B2K, HID_QUIRK_IGNORE },
-
-       { USB_VENDOR_ID_ACECAD, USB_DEVICE_ID_ACECAD_FLAIR, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_ACECAD, USB_DEVICE_ID_ACECAD_302, HID_QUIRK_IGNORE },
-
-       { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_UC100KM, HID_QUIRK_NOGET },
-       { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_CS124U, HID_QUIRK_NOGET },
-       { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_2PORTKVM, HID_QUIRK_NOGET },
-       { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_4PORTKVM, HID_QUIRK_NOGET },
-       { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_4PORTKVMC, HID_QUIRK_NOGET },
-       { USB_VENDOR_ID_SUN, USB_DEVICE_ID_RARITAN_KVM_DONGLE, HID_QUIRK_NOGET },
-       { USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_DUAL_USB_JOYPAD, HID_QUIRK_NOGET | HID_QUIRK_MULTI_INPUT },
-       { USB_VENDOR_ID_WISEGROUP_LTD, USB_DEVICE_ID_SMARTJOY_DUAL_PLUS, HID_QUIRK_NOGET | HID_QUIRK_MULTI_INPUT },
-
-       { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MIGHTYMOUSE, HID_QUIRK_MIGHTYMOUSE | HID_QUIRK_INVERT_HWHEEL },
-       { USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_WCP32PU, HID_QUIRK_2WHEEL_MOUSE_HACK_7 },
-       { USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_MOUSE, HID_QUIRK_2WHEEL_MOUSE_HACK_5 },
-
-       { USB_VENDOR_ID_AASHIMA, USB_DEVICE_ID_AASHIMA_GAMEPAD, HID_QUIRK_BADPAD },
-       { USB_VENDOR_ID_AASHIMA, USB_DEVICE_ID_AASHIMA_PREDATOR, HID_QUIRK_BADPAD },
-       { USB_VENDOR_ID_ALPS, USB_DEVICE_ID_IBM_GAMEPAD, HID_QUIRK_BADPAD },
-       { USB_VENDOR_ID_CHIC, USB_DEVICE_ID_CHIC_GAMEPAD, HID_QUIRK_BADPAD },
-       { USB_VENDOR_ID_HAPP, USB_DEVICE_ID_UGCI_DRIVING, HID_QUIRK_BADPAD | HID_QUIRK_MULTI_INPUT },
-       { USB_VENDOR_ID_HAPP, USB_DEVICE_ID_UGCI_FLYING, HID_QUIRK_BADPAD | HID_QUIRK_MULTI_INPUT },
-       { USB_VENDOR_ID_HAPP, USB_DEVICE_ID_UGCI_FIGHTING, HID_QUIRK_BADPAD | HID_QUIRK_MULTI_INPUT },
-       { USB_VENDOR_ID_NEC, USB_DEVICE_ID_NEC_USB_GAME_PAD, HID_QUIRK_BADPAD },
-       { USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_RUMBLEPAD, HID_QUIRK_BADPAD },
-       { USB_VENDOR_ID_TOPMAX, USB_DEVICE_ID_TOPMAX_COBRAPAD, HID_QUIRK_BADPAD },
-
-       { USB_VENDOR_ID_CHERRY, USB_DEVICE_ID_CHERRY_CYMOTION, HID_QUIRK_CYMOTION },
-
-       { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_ANSI, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
-       { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_ISO, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
-       { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_ANSI, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
-       { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_ISO, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE | HID_QUIRK_POWERBOOK_ISO_KEYBOARD},
-       { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_JIS, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
-       { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_ANSI, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
-       { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_ISO, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE | HID_QUIRK_POWERBOOK_ISO_KEYBOARD},
-       { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_JIS, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
-       { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_ANSI, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
-       { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_ISO, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE | HID_QUIRK_POWERBOOK_ISO_KEYBOARD},
-       { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_JIS, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
-       { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
-       { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
-
-       { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IR, HID_QUIRK_IGNORE },
-
-       { USB_VENDOR_ID_PANJIT, 0x0001, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_PANJIT, 0x0002, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_PANJIT, 0x0003, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_PANJIT, 0x0004, HID_QUIRK_IGNORE },
-
-       { USB_VENDOR_ID_TURBOX, USB_DEVICE_ID_TURBOX_KEYBOARD, HID_QUIRK_NOGET },
-
-       { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_USB_RECEIVER, HID_QUIRK_BAD_RELATIVE_KEYS },
-       { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_USB_RECEIVER_2, HID_QUIRK_LOGITECH_S510_DESCRIPTOR },
-
-       { USB_VENDOR_ID_PANTHERLORD, USB_DEVICE_ID_PANTHERLORD_TWIN_USB_JOYSTICK, HID_QUIRK_MULTI_INPUT | HID_QUIRK_SKIP_OUTPUT_REPORTS },
-
-       { USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER, HID_QUIRK_SONY_PS3_CONTROLLER },
-
-       { USB_VENDOR_ID_CIDC, 0x0103, HID_QUIRK_IGNORE },
-
-       { 0, 0 }
-};
-
-/*
- * Traverse the supplied list of reports and find the longest
- */
-static void hid_find_max_report(struct hid_device *hid, unsigned int type, int *max)
-{
-       struct hid_report *report;
-       int size;
-
-       list_for_each_entry(report, &hid->report_enum[type].report_list, list) {
-               size = ((report->size - 1) >> 3) + 1;
-               if (type == HID_INPUT_REPORT && hid->report_enum[type].numbered)
-                       size++;
-               if (*max < size)
-                       *max = size;
-       }
-}
-
-static int hid_alloc_buffers(struct usb_device *dev, struct hid_device *hid)
-{
-       struct usbhid_device *usbhid = hid->driver_data;
-
-       if (!(usbhid->inbuf = usb_buffer_alloc(dev, usbhid->bufsize, GFP_ATOMIC, &usbhid->inbuf_dma)))
-               return -1;
-       if (!(usbhid->outbuf = usb_buffer_alloc(dev, usbhid->bufsize, GFP_ATOMIC, &usbhid->outbuf_dma)))
-               return -1;
-       if (!(usbhid->cr = usb_buffer_alloc(dev, sizeof(*(usbhid->cr)), GFP_ATOMIC, &usbhid->cr_dma)))
-               return -1;
-       if (!(usbhid->ctrlbuf = usb_buffer_alloc(dev, usbhid->bufsize, GFP_ATOMIC, &usbhid->ctrlbuf_dma)))
-               return -1;
-
-       return 0;
-}
-
-static void hid_free_buffers(struct usb_device *dev, struct hid_device *hid)
-{
-       struct usbhid_device *usbhid = hid->driver_data;
-
-       if (usbhid->inbuf)
-               usb_buffer_free(dev, usbhid->bufsize, usbhid->inbuf, usbhid->inbuf_dma);
-       if (usbhid->outbuf)
-               usb_buffer_free(dev, usbhid->bufsize, usbhid->outbuf, usbhid->outbuf_dma);
-       if (usbhid->cr)
-               usb_buffer_free(dev, sizeof(*(usbhid->cr)), usbhid->cr, usbhid->cr_dma);
-       if (usbhid->ctrlbuf)
-               usb_buffer_free(dev, usbhid->bufsize, usbhid->ctrlbuf, usbhid->ctrlbuf_dma);
-}
-
-/*
- * Cherry Cymotion keyboard have an invalid HID report descriptor,
- * that needs fixing before we can parse it.
- */
-
-static void hid_fixup_cymotion_descriptor(char *rdesc, int rsize)
-{
-       if (rsize >= 17 && rdesc[11] == 0x3c && rdesc[12] == 0x02) {
-               info("Fixing up Cherry Cymotion report descriptor");
-               rdesc[11] = rdesc[16] = 0xff;
-               rdesc[12] = rdesc[17] = 0x03;
-       }
-}
-
-/*
- * Sending HID_REQ_GET_REPORT changes the operation mode of the ps3 controller
- * to "operational".  Without this, the ps3 controller will not report any
- * events.
- */
-static void hid_fixup_sony_ps3_controller(struct usb_device *dev, int ifnum)
-{
-       int result;
-       char *buf = kmalloc(18, GFP_KERNEL);
-
-       if (!buf)
-               return;
-
-       result = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
-                                HID_REQ_GET_REPORT,
-                                USB_DIR_IN | USB_TYPE_CLASS |
-                                USB_RECIP_INTERFACE,
-                                (3 << 8) | 0xf2, ifnum, buf, 17,
-                                USB_CTRL_GET_TIMEOUT);
-
-       if (result < 0)
-               err("%s failed: %d\n", __func__, result);
-
-       kfree(buf);
-}
-
-/*
- * Logitech S510 keyboard sends in report #3 keys which are far
- * above the logical maximum described in descriptor. This extends
- * the original value of 0x28c of logical maximum to 0x104d
- */
-static void hid_fixup_s510_descriptor(unsigned char *rdesc, int rsize)
-{
-       if (rsize >= 90 && rdesc[83] == 0x26
-                       && rdesc[84] == 0x8c
-                       && rdesc[85] == 0x02) {
-               info("Fixing up Logitech S510 report descriptor");
-               rdesc[84] = rdesc[89] = 0x4d;
-               rdesc[85] = rdesc[90] = 0x10;
-       }
-}
-
-static struct hid_device *usb_hid_configure(struct usb_interface *intf)
-{
-       struct usb_host_interface *interface = intf->cur_altsetting;
-       struct usb_device *dev = interface_to_usbdev (intf);
-       struct hid_descriptor *hdesc;
-       struct hid_device *hid;
-       unsigned quirks = 0, rsize = 0;
-       char *rdesc;
-       int n, len, insize = 0;
-       struct usbhid_device *usbhid;
-
-       /* Ignore all Wacom devices */
-       if (le16_to_cpu(dev->descriptor.idVendor) == USB_VENDOR_ID_WACOM)
-               return NULL;
-       /* ignore all Code Mercenaries IOWarrior devices */
-       if (le16_to_cpu(dev->descriptor.idVendor) == USB_VENDOR_ID_CODEMERCS)
-               if (le16_to_cpu(dev->descriptor.idProduct) >= USB_DEVICE_ID_CODEMERCS_IOW_FIRST &&
-                   le16_to_cpu(dev->descriptor.idProduct) <= USB_DEVICE_ID_CODEMERCS_IOW_LAST)
-                       return NULL;
-
-       for (n = 0; hid_blacklist[n].idVendor; n++)
-               if ((hid_blacklist[n].idVendor == le16_to_cpu(dev->descriptor.idVendor)) &&
-                       (hid_blacklist[n].idProduct == le16_to_cpu(dev->descriptor.idProduct)))
-                               quirks = hid_blacklist[n].quirks;
-
-       /* Many keyboards and mice don't like to be polled for reports,
-        * so we will always set the HID_QUIRK_NOGET flag for them. */
-       if (interface->desc.bInterfaceSubClass == USB_INTERFACE_SUBCLASS_BOOT) {
-               if (interface->desc.bInterfaceProtocol == USB_INTERFACE_PROTOCOL_KEYBOARD ||
-                       interface->desc.bInterfaceProtocol == USB_INTERFACE_PROTOCOL_MOUSE)
-                               quirks |= HID_QUIRK_NOGET;
-       }
-
-       if (quirks & HID_QUIRK_IGNORE)
-               return NULL;
-
-       if ((quirks & HID_QUIRK_IGNORE_MOUSE) &&
-               (interface->desc.bInterfaceProtocol == USB_INTERFACE_PROTOCOL_MOUSE))
-                       return NULL;
-
-
-       if (usb_get_extra_descriptor(interface, HID_DT_HID, &hdesc) &&
-           (!interface->desc.bNumEndpoints ||
-            usb_get_extra_descriptor(&interface->endpoint[0], HID_DT_HID, &hdesc))) {
-               dbg("class descriptor not present\n");
-               return NULL;
-       }
-
-       for (n = 0; n < hdesc->bNumDescriptors; n++)
-               if (hdesc->desc[n].bDescriptorType == HID_DT_REPORT)
-                       rsize = le16_to_cpu(hdesc->desc[n].wDescriptorLength);
-
-       if (!rsize || rsize > HID_MAX_DESCRIPTOR_SIZE) {
-               dbg("weird size of report descriptor (%u)", rsize);
-               return NULL;
-       }
-
-       if (!(rdesc = kmalloc(rsize, GFP_KERNEL))) {
-               dbg("couldn't allocate rdesc memory");
-               return NULL;
-       }
-
-       hid_set_idle(dev, interface->desc.bInterfaceNumber, 0, 0);
-
-       if ((n = hid_get_class_descriptor(dev, interface->desc.bInterfaceNumber, HID_DT_REPORT, rdesc, rsize)) < 0) {
-               dbg("reading report descriptor failed");
-               kfree(rdesc);
-               return NULL;
-       }
-
-       if ((quirks & HID_QUIRK_CYMOTION))
-               hid_fixup_cymotion_descriptor(rdesc, rsize);
-
-       if (quirks & HID_QUIRK_LOGITECH_S510_DESCRIPTOR)
-               hid_fixup_s510_descriptor(rdesc, rsize);
-
-#ifdef CONFIG_HID_DEBUG
-       printk(KERN_DEBUG __FILE__ ": report descriptor (size %u, read %d) = ", rsize, n);
-       for (n = 0; n < rsize; n++)
-               printk(" %02x", (unsigned char) rdesc[n]);
-       printk("\n");
-#endif
-
-       if (!(hid = hid_parse_report(rdesc, n))) {
-               dbg("parsing report descriptor failed");
-               kfree(rdesc);
-               return NULL;
-       }
-
-       kfree(rdesc);
-       hid->quirks = quirks;
-
-       if (!(usbhid = kzalloc(sizeof(struct usbhid_device), GFP_KERNEL)))
-               goto fail;
-
-       hid->driver_data = usbhid;
-       usbhid->hid = hid;
-
-       usbhid->bufsize = HID_MIN_BUFFER_SIZE;
-       hid_find_max_report(hid, HID_INPUT_REPORT, &usbhid->bufsize);
-       hid_find_max_report(hid, HID_OUTPUT_REPORT, &usbhid->bufsize);
-       hid_find_max_report(hid, HID_FEATURE_REPORT, &usbhid->bufsize);
-
-       if (usbhid->bufsize > HID_MAX_BUFFER_SIZE)
-               usbhid->bufsize = HID_MAX_BUFFER_SIZE;
-
-       hid_find_max_report(hid, HID_INPUT_REPORT, &insize);
-
-       if (insize > HID_MAX_BUFFER_SIZE)
-               insize = HID_MAX_BUFFER_SIZE;
-
-       if (hid_alloc_buffers(dev, hid)) {
-               hid_free_buffers(dev, hid);
-               goto fail;
-       }
-
-       for (n = 0; n < interface->desc.bNumEndpoints; n++) {
-
-               struct usb_endpoint_descriptor *endpoint;
-               int pipe;
-               int interval;
-
-               endpoint = &interface->endpoint[n].desc;
-               if ((endpoint->bmAttributes & 3) != 3)          /* Not an interrupt endpoint */
-                       continue;
-
-               interval = endpoint->bInterval;
-
-               /* Change the polling interval of mice. */
-               if (hid->collection->usage == HID_GD_MOUSE && hid_mousepoll_interval > 0)
-                       interval = hid_mousepoll_interval;
-
-               if (usb_endpoint_dir_in(endpoint)) {
-                       if (usbhid->urbin)
-                               continue;
-                       if (!(usbhid->urbin = usb_alloc_urb(0, GFP_KERNEL)))
-                               goto fail;
-                       pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);
-                       usb_fill_int_urb(usbhid->urbin, dev, pipe, usbhid->inbuf, insize,
-                                        hid_irq_in, hid, interval);
-                       usbhid->urbin->transfer_dma = usbhid->inbuf_dma;
-                       usbhid->urbin->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
-               } else {
-                       if (usbhid->urbout)
-                               continue;
-                       if (!(usbhid->urbout = usb_alloc_urb(0, GFP_KERNEL)))
-                               goto fail;
-                       pipe = usb_sndintpipe(dev, endpoint->bEndpointAddress);
-                       usb_fill_int_urb(usbhid->urbout, dev, pipe, usbhid->outbuf, 0,
-                                        hid_irq_out, hid, interval);
-                       usbhid->urbout->transfer_dma = usbhid->outbuf_dma;
-                       usbhid->urbout->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
-               }
-       }
-
-       if (!usbhid->urbin) {
-               err("couldn't find an input interrupt endpoint");
-               goto fail;
-       }
-
-       init_waitqueue_head(&hid->wait);
-
-       INIT_WORK(&usbhid->reset_work, hid_reset);
-       setup_timer(&usbhid->io_retry, hid_retry_timeout, (unsigned long) hid);
-
-       spin_lock_init(&usbhid->inlock);
-       spin_lock_init(&usbhid->outlock);
-       spin_lock_init(&usbhid->ctrllock);
-
-       hid->version = le16_to_cpu(hdesc->bcdHID);
-       hid->country = hdesc->bCountryCode;
-       hid->dev = &intf->dev;
-       usbhid->intf = intf;
-       usbhid->ifnum = interface->desc.bInterfaceNumber;
-
-       hid->name[0] = 0;
-
-       if (dev->manufacturer)
-               strlcpy(hid->name, dev->manufacturer, sizeof(hid->name));
-
-       if (dev->product) {
-               if (dev->manufacturer)
-                       strlcat(hid->name, " ", sizeof(hid->name));
-               strlcat(hid->name, dev->product, sizeof(hid->name));
-       }
-
-       if (!strlen(hid->name))
-               snprintf(hid->name, sizeof(hid->name), "HID %04x:%04x",
-                        le16_to_cpu(dev->descriptor.idVendor),
-                        le16_to_cpu(dev->descriptor.idProduct));
-
-       hid->bus = BUS_USB;
-       hid->vendor = le16_to_cpu(dev->descriptor.idVendor);
-       hid->product = le16_to_cpu(dev->descriptor.idProduct);
-
-       usb_make_path(dev, hid->phys, sizeof(hid->phys));
-       strlcat(hid->phys, "/input", sizeof(hid->phys));
-       len = strlen(hid->phys);
-       if (len < sizeof(hid->phys) - 1)
-               snprintf(hid->phys + len, sizeof(hid->phys) - len,
-                        "%d", intf->altsetting[0].desc.bInterfaceNumber);
-
-       if (usb_string(dev, dev->descriptor.iSerialNumber, hid->uniq, 64) <= 0)
-               hid->uniq[0] = 0;
-
-       usbhid->urbctrl = usb_alloc_urb(0, GFP_KERNEL);
-       if (!usbhid->urbctrl)
-               goto fail;
-
-       usb_fill_control_urb(usbhid->urbctrl, dev, 0, (void *) usbhid->cr,
-                            usbhid->ctrlbuf, 1, hid_ctrl, hid);
-       usbhid->urbctrl->setup_dma = usbhid->cr_dma;
-       usbhid->urbctrl->transfer_dma = usbhid->ctrlbuf_dma;
-       usbhid->urbctrl->transfer_flags |= (URB_NO_TRANSFER_DMA_MAP | URB_NO_SETUP_DMA_MAP);
-       hid->hidinput_input_event = usb_hidinput_input_event;
-       hid->hid_open = usbhid_open;
-       hid->hid_close = usbhid_close;
-#ifdef CONFIG_USB_HIDDEV
-       hid->hiddev_hid_event = hiddev_hid_event;
-       hid->hiddev_report_event = hiddev_report_event;
-#endif
-       return hid;
-
-fail:
-       usb_free_urb(usbhid->urbin);
-       usb_free_urb(usbhid->urbout);
-       usb_free_urb(usbhid->urbctrl);
-       hid_free_buffers(dev, hid);
-       hid_free_device(hid);
-
-       return NULL;
-}
-
-static void hid_disconnect(struct usb_interface *intf)
-{
-       struct hid_device *hid = usb_get_intfdata (intf);
-       struct usbhid_device *usbhid;
-
-       if (!hid)
-               return;
-
-       usbhid = hid->driver_data;
-
-       spin_lock_irq(&usbhid->inlock); /* Sync with error handler */
-       usb_set_intfdata(intf, NULL);
-       spin_unlock_irq(&usbhid->inlock);
-       usb_kill_urb(usbhid->urbin);
-       usb_kill_urb(usbhid->urbout);
-       usb_kill_urb(usbhid->urbctrl);
-
-       del_timer_sync(&usbhid->io_retry);
-       flush_scheduled_work();
-
-       if (hid->claimed & HID_CLAIMED_INPUT)
-               hidinput_disconnect(hid);
-       if (hid->claimed & HID_CLAIMED_HIDDEV)
-               hiddev_disconnect(hid);
-
-       usb_free_urb(usbhid->urbin);
-       usb_free_urb(usbhid->urbctrl);
-       usb_free_urb(usbhid->urbout);
-
-       hid_free_buffers(hid_to_usb_dev(hid), hid);
-       hid_free_device(hid);
-}
-
-static int hid_probe(struct usb_interface *intf, const struct usb_device_id *id)
-{
-       struct hid_device *hid;
-       char path[64];
-       int i;
-       char *c;
-
-       dbg("HID probe called for ifnum %d",
-                       intf->altsetting->desc.bInterfaceNumber);
-
-       if (!(hid = usb_hid_configure(intf)))
-               return -ENODEV;
-
-       usbhid_init_reports(hid);
-       hid_dump_device(hid);
-
-       if (!hidinput_connect(hid))
-               hid->claimed |= HID_CLAIMED_INPUT;
-       if (!hiddev_connect(hid))
-               hid->claimed |= HID_CLAIMED_HIDDEV;
-
-       usb_set_intfdata(intf, hid);
-
-       if (!hid->claimed) {
-               printk ("HID device not claimed by input or hiddev\n");
-               hid_disconnect(intf);
-               return -ENODEV;
-       }
-
-       if ((hid->claimed & HID_CLAIMED_INPUT))
-               hid_ff_init(hid);
-
-       if (hid->quirks & HID_QUIRK_SONY_PS3_CONTROLLER)
-               hid_fixup_sony_ps3_controller(interface_to_usbdev(intf),
-                       intf->cur_altsetting->desc.bInterfaceNumber);
-
-       printk(KERN_INFO);
-
-       if (hid->claimed & HID_CLAIMED_INPUT)
-               printk("input");
-       if (hid->claimed == (HID_CLAIMED_INPUT | HID_CLAIMED_HIDDEV))
-               printk(",");
-       if (hid->claimed & HID_CLAIMED_HIDDEV)
-               printk("hiddev%d", hid->minor);
-
-       c = "Device";
-       for (i = 0; i < hid->maxcollection; i++) {
-               if (hid->collection[i].type == HID_COLLECTION_APPLICATION &&
-                   (hid->collection[i].usage & HID_USAGE_PAGE) == HID_UP_GENDESK &&
-                   (hid->collection[i].usage & 0xffff) < ARRAY_SIZE(hid_types)) {
-                       c = hid_types[hid->collection[i].usage & 0xffff];
-                       break;
-               }
-       }
-
-       usb_make_path(interface_to_usbdev(intf), path, 63);
-
-       printk(": USB HID v%x.%02x %s [%s] on %s\n",
-               hid->version >> 8, hid->version & 0xff, c, hid->name, path);
-
-       return 0;
-}
-
-static int hid_suspend(struct usb_interface *intf, pm_message_t message)
-{
-       struct hid_device *hid = usb_get_intfdata (intf);
-       struct usbhid_device *usbhid = hid->driver_data;
-
-       spin_lock_irq(&usbhid->inlock); /* Sync with error handler */
-       set_bit(HID_SUSPENDED, &usbhid->iofl);
-       spin_unlock_irq(&usbhid->inlock);
-       del_timer(&usbhid->io_retry);
-       usb_kill_urb(usbhid->urbin);
-       dev_dbg(&intf->dev, "suspend\n");
-       return 0;
-}
-
-static int hid_resume(struct usb_interface *intf)
-{
-       struct hid_device *hid = usb_get_intfdata (intf);
-       struct usbhid_device *usbhid = hid->driver_data;
-       int status;
-
-       clear_bit(HID_SUSPENDED, &usbhid->iofl);
-       usbhid->retry_delay = 0;
-       status = hid_start_in(hid);
-       dev_dbg(&intf->dev, "resume status %d\n", status);
-       return status;
-}
-
-/* Treat USB reset pretty much the same as suspend/resume */
-static void hid_pre_reset(struct usb_interface *intf)
-{
-       /* FIXME: What if the interface is already suspended? */
-       hid_suspend(intf, PMSG_ON);
-}
-
-static void hid_post_reset(struct usb_interface *intf)
-{
-       struct usb_device *dev = interface_to_usbdev (intf);
-
-       hid_set_idle(dev, intf->cur_altsetting->desc.bInterfaceNumber, 0, 0);
-       /* FIXME: Any more reinitialization needed? */
-
-       hid_resume(intf);
-}
-
-static struct usb_device_id hid_usb_ids [] = {
-       { .match_flags = USB_DEVICE_ID_MATCH_INT_CLASS,
-               .bInterfaceClass = USB_INTERFACE_CLASS_HID },
-       { }                                             /* Terminating entry */
-};
-
-MODULE_DEVICE_TABLE (usb, hid_usb_ids);
-
-static struct usb_driver hid_driver = {
-       .name =         "usbhid",
-       .probe =        hid_probe,
-       .disconnect =   hid_disconnect,
-       .suspend =      hid_suspend,
-       .resume =       hid_resume,
-       .pre_reset =    hid_pre_reset,
-       .post_reset =   hid_post_reset,
-       .id_table =     hid_usb_ids,
-};
-
-static int __init hid_init(void)
-{
-       int retval;
-       retval = hiddev_init();
-       if (retval)
-               goto hiddev_init_fail;
-       retval = usb_register(&hid_driver);
-       if (retval)
-               goto usb_register_fail;
-       info(DRIVER_VERSION ":" DRIVER_DESC);
-
-       return 0;
-usb_register_fail:
-       hiddev_exit();
-hiddev_init_fail:
-       return retval;
-}
-
-static void __exit hid_exit(void)
-{
-       usb_deregister(&hid_driver);
-       hiddev_exit();
-}
-
-module_init(hid_init);
-module_exit(hid_exit);
-
-MODULE_AUTHOR(DRIVER_AUTHOR);
-MODULE_DESCRIPTION(DRIVER_DESC);
-MODULE_LICENSE(DRIVER_LICENSE);
diff --git a/drivers/usb/input/hid-ff.c b/drivers/usb/input/hid-ff.c
deleted file mode 100644 (file)
index e431faa..0000000
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * $Id: hid-ff.c,v 1.2 2002/04/18 22:02:47 jdeneux Exp $
- *
- *  Force feedback support for hid devices.
- *  Not all hid devices use the same protocol. For example, some use PID,
- *  other use their own proprietary procotol.
- *
- *  Copyright (c) 2002-2004 Johann Deneux
- */
-
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Should you need to contact me, the author, you can do so by
- * e-mail - mail your message to <johann.deneux@it.uu.se>
- */
-
-#include <linux/input.h>
-
-#undef DEBUG
-#include <linux/usb.h>
-
-#include <linux/hid.h>
-#include "usbhid.h"
-
-/*
- * This table contains pointers to initializers. To add support for new
- * devices, you need to add the USB vendor and product ids here.
- */
-struct hid_ff_initializer {
-       u16 idVendor;
-       u16 idProduct;
-       int (*init)(struct hid_device*);
-};
-
-/*
- * We try pidff when no other driver is found because PID is the
- * standards compliant way of implementing force feedback in HID.
- * pidff_init() will quickly abort if the device doesn't appear to
- * be a PID device
- */
-static struct hid_ff_initializer inits[] = {
-#ifdef CONFIG_LOGITECH_FF
-       { 0x46d, 0xc211, hid_lgff_init }, /* Logitech Cordless rumble pad */
-       { 0x46d, 0xc219, hid_lgff_init }, /* Logitech Cordless rumble pad 2 */
-       { 0x46d, 0xc283, hid_lgff_init }, /* Logitech Wingman Force 3d */
-       { 0x46d, 0xc294, hid_lgff_init }, /* Logitech Formula Force EX */
-       { 0x46d, 0xc295, hid_lgff_init }, /* Logitech MOMO force wheel */
-       { 0x46d, 0xca03, hid_lgff_init }, /* Logitech MOMO force wheel */
-#endif
-#ifdef CONFIG_PANTHERLORD_FF
-       { 0x810, 0x0001, hid_plff_init },
-#endif
-#ifdef CONFIG_THRUSTMASTER_FF
-       { 0x44f, 0xb304, hid_tmff_init },
-#endif
-#ifdef CONFIG_ZEROPLUS_FF
-       { 0xc12, 0x0005, hid_zpff_init },
-       { 0xc12, 0x0030, hid_zpff_init },
-#endif
-       { 0,     0,      hid_pidff_init}  /* Matches anything */
-};
-
-int hid_ff_init(struct hid_device* hid)
-{
-       struct hid_ff_initializer *init;
-       int vendor = le16_to_cpu(hid_to_usb_dev(hid)->descriptor.idVendor);
-       int product = le16_to_cpu(hid_to_usb_dev(hid)->descriptor.idProduct);
-
-       for (init = inits; init->idVendor; init++)
-               if (init->idVendor == vendor && init->idProduct == product)
-                       break;
-
-       return init->init(hid);
-}
-EXPORT_SYMBOL_GPL(hid_ff_init);
-
diff --git a/drivers/usb/input/hid-lgff.c b/drivers/usb/input/hid-lgff.c
deleted file mode 100644 (file)
index e6f3af3..0000000
+++ /dev/null
@@ -1,150 +0,0 @@
-/*
- * Force feedback support for hid-compliant for some of the devices from
- * Logitech, namely:
- * - WingMan Cordless RumblePad
- * - WingMan Force 3D
- *
- *  Copyright (c) 2002-2004 Johann Deneux
- *  Copyright (c) 2006 Anssi Hannula <anssi.hannula@gmail.com>
- */
-
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Should you need to contact me, the author, you can do so by
- * e-mail - mail your message to <johann.deneux@it.uu.se>
- */
-
-#include <linux/input.h>
-#include <linux/usb.h>
-#include <linux/hid.h>
-#include "usbhid.h"
-
-struct dev_type {
-       u16 idVendor;
-       u16 idProduct;
-       const signed short *ff;
-};
-
-static const signed short ff_rumble[] = {
-       FF_RUMBLE,
-       -1
-};
-
-static const signed short ff_joystick[] = {
-       FF_CONSTANT,
-       -1
-};
-
-static const struct dev_type devices[] = {
-       { 0x046d, 0xc211, ff_rumble },
-       { 0x046d, 0xc219, ff_rumble },
-       { 0x046d, 0xc283, ff_joystick },
-       { 0x046d, 0xc294, ff_joystick },
-       { 0x046d, 0xc295, ff_joystick },
-       { 0x046d, 0xca03, ff_joystick },
-};
-
-static int hid_lgff_play(struct input_dev *dev, void *data, struct ff_effect *effect)
-{
-       struct hid_device *hid = dev->private;
-       struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list;
-       struct hid_report *report = list_entry(report_list->next, struct hid_report, list);
-       int x, y;
-       unsigned int left, right;
-
-#define CLAMP(x) if (x < 0) x = 0; if (x > 0xff) x = 0xff
-
-       switch (effect->type) {
-       case FF_CONSTANT:
-               x = effect->u.ramp.start_level + 0x7f;  /* 0x7f is center */
-               y = effect->u.ramp.end_level + 0x7f;
-               CLAMP(x);
-               CLAMP(y);
-               report->field[0]->value[0] = 0x51;
-               report->field[0]->value[1] = 0x08;
-               report->field[0]->value[2] = x;
-               report->field[0]->value[3] = y;
-               dbg("(x, y)=(%04x, %04x)", x, y);
-               usbhid_submit_report(hid, report, USB_DIR_OUT);
-               break;
-
-       case FF_RUMBLE:
-               right = effect->u.rumble.strong_magnitude;
-               left = effect->u.rumble.weak_magnitude;
-               right = right * 0xff / 0xffff;
-               left = left * 0xff / 0xffff;
-               CLAMP(left);
-               CLAMP(right);
-               report->field[0]->value[0] = 0x42;
-               report->field[0]->value[1] = 0x00;
-               report->field[0]->value[2] = left;
-               report->field[0]->value[3] = right;
-               dbg("(left, right)=(%04x, %04x)", left, right);
-               usbhid_submit_report(hid, report, USB_DIR_OUT);
-               break;
-       }
-       return 0;
-}
-
-int hid_lgff_init(struct hid_device* hid)
-{
-       struct hid_input *hidinput = list_entry(hid->inputs.next, struct hid_input, list);
-       struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list;
-       struct input_dev *dev = hidinput->input;
-       struct hid_report *report;
-       struct hid_field *field;
-       const signed short *ff_bits = ff_joystick;
-       int error;
-       int i;
-
-       /* Find the report to use */
-       if (list_empty(report_list)) {
-               err("No output report found");
-               return -1;
-       }
-
-       /* Check that the report looks ok */
-       report = list_entry(report_list->next, struct hid_report, list);
-       if (!report) {
-               err("NULL output report");
-               return -1;
-       }
-
-       field = report->field[0];
-       if (!field) {
-               err("NULL field");
-               return -1;
-       }
-
-       for (i = 0; i < ARRAY_SIZE(devices); i++) {
-               if (dev->id.vendor == devices[i].idVendor &&
-                   dev->id.product == devices[i].idProduct) {
-                       ff_bits = devices[i].ff;
-                       break;
-               }
-       }
-
-       for (i = 0; ff_bits[i] >= 0; i++)
-               set_bit(ff_bits[i], dev->ffbit);
-
-       error = input_ff_create_memless(dev, NULL, hid_lgff_play);
-       if (error)
-               return error;
-
-       printk(KERN_INFO "Force feedback for Logitech force feedback devices by Johann Deneux <johann.deneux@it.uu.se>\n");
-
-       return 0;
-}
diff --git a/drivers/usb/input/hid-pidff.c b/drivers/usb/input/hid-pidff.c
deleted file mode 100644 (file)
index f5a90e9..0000000
+++ /dev/null
@@ -1,1331 +0,0 @@
-/*
- *  Force feedback driver for USB HID PID compliant devices
- *
- *  Copyright (c) 2005, 2006 Anssi Hannula <anssi.hannula@gmail.com>
- */
-
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-/* #define DEBUG */
-
-#define debug(format, arg...) pr_debug("hid-pidff: " format "\n" , ## arg)
-
-#include <linux/input.h>
-#include <linux/usb.h>
-
-#include <linux/hid.h>
-
-#include "usbhid.h"
-
-#define        PID_EFFECTS_MAX         64
-
-/* Report usage table used to put reports into an array */
-
-#define PID_SET_EFFECT         0
-#define PID_EFFECT_OPERATION   1
-#define PID_DEVICE_GAIN                2
-#define PID_POOL               3
-#define PID_BLOCK_LOAD         4
-#define PID_BLOCK_FREE         5
-#define PID_DEVICE_CONTROL     6
-#define PID_CREATE_NEW_EFFECT  7
-
-#define PID_REQUIRED_REPORTS   7
-
-#define PID_SET_ENVELOPE       8
-#define PID_SET_CONDITION      9
-#define PID_SET_PERIODIC       10
-#define PID_SET_CONSTANT       11
-#define PID_SET_RAMP           12
-static const u8 pidff_reports[] = {
-       0x21, 0x77, 0x7d, 0x7f, 0x89, 0x90, 0x96, 0xab,
-       0x5a, 0x5f, 0x6e, 0x73, 0x74
-};
-
-/* device_control is really 0x95, but 0x96 specified as it is the usage of
-the only field in that report */
-
-/* Value usage tables used to put fields and values into arrays */
-
-#define PID_EFFECT_BLOCK_INDEX 0
-
-#define PID_DURATION           1
-#define PID_GAIN               2
-#define PID_TRIGGER_BUTTON     3
-#define PID_TRIGGER_REPEAT_INT 4
-#define PID_DIRECTION_ENABLE   5
-#define PID_START_DELAY                6
-static const u8 pidff_set_effect[] = {
-       0x22, 0x50, 0x52, 0x53, 0x54, 0x56, 0xa7
-};
-
-#define PID_ATTACK_LEVEL       1
-#define PID_ATTACK_TIME                2
-#define PID_FADE_LEVEL         3
-#define PID_FADE_TIME          4
-static const u8 pidff_set_envelope[] = { 0x22, 0x5b, 0x5c, 0x5d, 0x5e };
-
-#define PID_PARAM_BLOCK_OFFSET 1
-#define PID_CP_OFFSET          2
-#define PID_POS_COEFFICIENT    3
-#define PID_NEG_COEFFICIENT    4
-#define PID_POS_SATURATION     5
-#define PID_NEG_SATURATION     6
-#define PID_DEAD_BAND          7
-static const u8 pidff_set_condition[] = {
-       0x22, 0x23, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65
-};
-
-#define PID_MAGNITUDE          1
-#define PID_OFFSET             2
-#define PID_PHASE              3
-#define PID_PERIOD             4
-static const u8 pidff_set_periodic[] = { 0x22, 0x70, 0x6f, 0x71, 0x72 };
-static const u8 pidff_set_constant[] = { 0x22, 0x70 };
-
-#define PID_RAMP_START         1
-#define PID_RAMP_END           2
-static const u8 pidff_set_ramp[] = { 0x22, 0x75, 0x76 };
-
-#define PID_RAM_POOL_AVAILABLE 1
-static const u8 pidff_block_load[] = { 0x22, 0xac };
-
-#define PID_LOOP_COUNT         1
-static const u8 pidff_effect_operation[] = { 0x22, 0x7c };
-
-static const u8 pidff_block_free[] = { 0x22 };
-
-#define PID_DEVICE_GAIN_FIELD  0
-static const u8 pidff_device_gain[] = { 0x7e };
-
-#define PID_RAM_POOL_SIZE      0
-#define PID_SIMULTANEOUS_MAX   1
-#define PID_DEVICE_MANAGED_POOL        2
-static const u8 pidff_pool[] = { 0x80, 0x83, 0xa9 };
-
-/* Special field key tables used to put special field keys into arrays */
-
-#define PID_ENABLE_ACTUATORS   0
-#define PID_RESET              1
-static const u8 pidff_device_control[] = { 0x97, 0x9a };
-
-#define PID_CONSTANT   0
-#define PID_RAMP       1
-#define PID_SQUARE     2
-#define PID_SINE       3
-#define PID_TRIANGLE   4
-#define PID_SAW_UP     5
-#define PID_SAW_DOWN   6
-#define PID_SPRING     7
-#define PID_DAMPER     8
-#define PID_INERTIA    9
-#define PID_FRICTION   10
-static const u8 pidff_effect_types[] = {
-       0x26, 0x27, 0x30, 0x31, 0x32, 0x33, 0x34,
-       0x40, 0x41, 0x42, 0x43
-};
-
-#define PID_BLOCK_LOAD_SUCCESS 0
-#define PID_BLOCK_LOAD_FULL    1
-static const u8 pidff_block_load_status[] = { 0x8c, 0x8d };
-
-#define PID_EFFECT_START       0
-#define PID_EFFECT_STOP                1
-static const u8 pidff_effect_operation_status[] = { 0x79, 0x7b };
-
-struct pidff_usage {
-       struct hid_field *field;
-       s32 *value;
-};
-
-struct pidff_device {
-       struct hid_device *hid;
-
-       struct hid_report *reports[sizeof(pidff_reports)];
-
-       struct pidff_usage set_effect[sizeof(pidff_set_effect)];
-       struct pidff_usage set_envelope[sizeof(pidff_set_envelope)];
-       struct pidff_usage set_condition[sizeof(pidff_set_condition)];
-       struct pidff_usage set_periodic[sizeof(pidff_set_periodic)];
-       struct pidff_usage set_constant[sizeof(pidff_set_constant)];
-       struct pidff_usage set_ramp[sizeof(pidff_set_ramp)];
-
-       struct pidff_usage device_gain[sizeof(pidff_device_gain)];
-       struct pidff_usage block_load[sizeof(pidff_block_load)];
-       struct pidff_usage pool[sizeof(pidff_pool)];
-       struct pidff_usage effect_operation[sizeof(pidff_effect_operation)];
-       struct pidff_usage block_free[sizeof(pidff_block_free)];
-
-       /* Special field is a field that is not composed of
-          usage<->value pairs that pidff_usage values are */
-
-       /* Special field in create_new_effect */
-       struct hid_field *create_new_effect_type;
-
-       /* Special fields in set_effect */
-       struct hid_field *set_effect_type;
-       struct hid_field *effect_direction;
-
-       /* Special field in device_control */
-       struct hid_field *device_control;
-
-       /* Special field in block_load */
-       struct hid_field *block_load_status;
-
-       /* Special field in effect_operation */
-       struct hid_field *effect_operation_status;
-
-       int control_id[sizeof(pidff_device_control)];
-       int type_id[sizeof(pidff_effect_types)];
-       int status_id[sizeof(pidff_block_load_status)];
-       int operation_id[sizeof(pidff_effect_operation_status)];
-
-       int pid_id[PID_EFFECTS_MAX];
-};
-
-/*
- * Scale an unsigned value with range 0..max for the given field
- */
-static int pidff_rescale(int i, int max, struct hid_field *field)
-{
-       return i * (field->logical_maximum - field->logical_minimum) / max +
-           field->logical_minimum;
-}
-
-/*
- * Scale a signed value in range -0x8000..0x7fff for the given field
- */
-static int pidff_rescale_signed(int i, struct hid_field *field)
-{
-       return i == 0 ? 0 : i >
-           0 ? i * field->logical_maximum / 0x7fff : i *
-           field->logical_minimum / -0x8000;
-}
-
-static void pidff_set(struct pidff_usage *usage, u16 value)
-{
-       usage->value[0] = pidff_rescale(value, 0xffff, usage->field);
-       debug("calculated from %d to %d", value, usage->value[0]);
-}
-
-static void pidff_set_signed(struct pidff_usage *usage, s16 value)
-{
-       if (usage->field->logical_minimum < 0)
-               usage->value[0] = pidff_rescale_signed(value, usage->field);
-       else {
-               if (value < 0)
-                       usage->value[0] =
-                           pidff_rescale(-value, 0x8000, usage->field);
-               else
-                       usage->value[0] =
-                           pidff_rescale(value, 0x7fff, usage->field);
-       }
-       debug("calculated from %d to %d", value, usage->value[0]);
-}
-
-/*
- * Send envelope report to the device
- */
-static void pidff_set_envelope_report(struct pidff_device *pidff,
-                                     struct ff_envelope *envelope)
-{
-       pidff->set_envelope[PID_EFFECT_BLOCK_INDEX].value[0] =
-           pidff->block_load[PID_EFFECT_BLOCK_INDEX].value[0];
-
-       pidff->set_envelope[PID_ATTACK_LEVEL].value[0] =
-           pidff_rescale(envelope->attack_level >
-                         0x7fff ? 0x7fff : envelope->attack_level, 0x7fff,
-                         pidff->set_envelope[PID_ATTACK_LEVEL].field);
-       pidff->set_envelope[PID_FADE_LEVEL].value[0] =
-           pidff_rescale(envelope->fade_level >
-                         0x7fff ? 0x7fff : envelope->fade_level, 0x7fff,
-                         pidff->set_envelope[PID_FADE_LEVEL].field);
-
-       pidff->set_envelope[PID_ATTACK_TIME].value[0] = envelope->attack_length;
-       pidff->set_envelope[PID_FADE_TIME].value[0] = envelope->fade_length;
-
-       debug("attack %u => %d", envelope->attack_level,
-             pidff->set_envelope[PID_ATTACK_LEVEL].value[0]);
-
-       usbhid_submit_report(pidff->hid, pidff->reports[PID_SET_ENVELOPE],
-                         USB_DIR_OUT);
-}
-
-/*
- * Test if the new envelope differs from old one
- */
-static int pidff_needs_set_envelope(struct ff_envelope *envelope,
-                                   struct ff_envelope *old)
-{
-       return envelope->attack_level != old->attack_level ||
-              envelope->fade_level != old->fade_level ||
-              envelope->attack_length != old->attack_length ||
-              envelope->fade_length != old->fade_length;
-}
-
-/*
- * Send constant force report to the device
- */
-static void pidff_set_constant_force_report(struct pidff_device *pidff,
-                                           struct ff_effect *effect)
-{
-       pidff->set_constant[PID_EFFECT_BLOCK_INDEX].value[0] =
-               pidff->block_load[PID_EFFECT_BLOCK_INDEX].value[0];
-       pidff_set_signed(&pidff->set_constant[PID_MAGNITUDE],
-                        effect->u.constant.level);
-
-       usbhid_submit_report(pidff->hid, pidff->reports[PID_SET_CONSTANT],
-                         USB_DIR_OUT);
-}
-
-/*
- * Test if the constant parameters have changed between effects
- */
-static int pidff_needs_set_constant(struct ff_effect *effect,
-                                   struct ff_effect *old)
-{
-       return effect->u.constant.level != old->u.constant.level;
-}
-
-/*
- * Send set effect report to the device
- */
-static void pidff_set_effect_report(struct pidff_device *pidff,
-                                   struct ff_effect *effect)
-{
-       pidff->set_effect[PID_EFFECT_BLOCK_INDEX].value[0] =
-               pidff->block_load[PID_EFFECT_BLOCK_INDEX].value[0];
-       pidff->set_effect_type->value[0] =
-               pidff->create_new_effect_type->value[0];
-       pidff->set_effect[PID_DURATION].value[0] = effect->replay.length;
-       pidff->set_effect[PID_TRIGGER_BUTTON].value[0] = effect->trigger.button;
-       pidff->set_effect[PID_TRIGGER_REPEAT_INT].value[0] =
-               effect->trigger.interval;
-       pidff->set_effect[PID_GAIN].value[0] =
-               pidff->set_effect[PID_GAIN].field->logical_maximum;
-       pidff->set_effect[PID_DIRECTION_ENABLE].value[0] = 1;
-       pidff->effect_direction->value[0] =
-               pidff_rescale(effect->direction, 0xffff,
-                               pidff->effect_direction);
-       pidff->set_effect[PID_START_DELAY].value[0] = effect->replay.delay;
-
-       usbhid_submit_report(pidff->hid, pidff->reports[PID_SET_EFFECT],
-                         USB_DIR_OUT);
-}
-
-/*
- * Test if the values used in set_effect have changed
- */
-static int pidff_needs_set_effect(struct ff_effect *effect,
-                                 struct ff_effect *old)
-{
-       return effect->replay.length != old->replay.length ||
-              effect->trigger.interval != old->trigger.interval ||
-              effect->trigger.button != old->trigger.button ||
-              effect->direction != old->direction ||
-              effect->replay.delay != old->replay.delay;
-}
-
-/*
- * Send periodic effect report to the device
- */
-static void pidff_set_periodic_report(struct pidff_device *pidff,
-                                     struct ff_effect *effect)
-{
-       pidff->set_periodic[PID_EFFECT_BLOCK_INDEX].value[0] =
-               pidff->block_load[PID_EFFECT_BLOCK_INDEX].value[0];
-       pidff_set_signed(&pidff->set_periodic[PID_MAGNITUDE],
-                        effect->u.periodic.magnitude);
-       pidff_set_signed(&pidff->set_periodic[PID_OFFSET],
-                        effect->u.periodic.offset);
-       pidff_set(&pidff->set_periodic[PID_PHASE], effect->u.periodic.phase);
-       pidff->set_periodic[PID_PERIOD].value[0] = effect->u.periodic.period;
-
-       usbhid_submit_report(pidff->hid, pidff->reports[PID_SET_PERIODIC],
-                         USB_DIR_OUT);
-
-}
-
-/*
- * Test if periodic effect parameters have changed
- */
-static int pidff_needs_set_periodic(struct ff_effect *effect,
-                                   struct ff_effect *old)
-{
-       return effect->u.periodic.magnitude != old->u.periodic.magnitude ||
-              effect->u.periodic.offset != old->u.periodic.offset ||
-              effect->u.periodic.phase != old->u.periodic.phase ||
-              effect->u.periodic.period != old->u.periodic.period;
-}
-
-/*
- * Send condition effect reports to the device
- */
-static void pidff_set_condition_report(struct pidff_device *pidff,
-                                      struct ff_effect *effect)
-{
-       int i;
-
-       pidff->set_condition[PID_EFFECT_BLOCK_INDEX].value[0] =
-               pidff->block_load[PID_EFFECT_BLOCK_INDEX].value[0];
-
-       for (i = 0; i < 2; i++) {
-               pidff->set_condition[PID_PARAM_BLOCK_OFFSET].value[0] = i;
-               pidff_set_signed(&pidff->set_condition[PID_CP_OFFSET],
-                                effect->u.condition[i].center);
-               pidff_set_signed(&pidff->set_condition[PID_POS_COEFFICIENT],
-                                effect->u.condition[i].right_coeff);
-               pidff_set_signed(&pidff->set_condition[PID_NEG_COEFFICIENT],
-                                effect->u.condition[i].left_coeff);
-               pidff_set(&pidff->set_condition[PID_POS_SATURATION],
-                         effect->u.condition[i].right_saturation);
-               pidff_set(&pidff->set_condition[PID_NEG_SATURATION],
-                         effect->u.condition[i].left_saturation);
-               pidff_set(&pidff->set_condition[PID_DEAD_BAND],
-                         effect->u.condition[i].deadband);
-               usbhid_wait_io(pidff->hid);
-               usbhid_submit_report(pidff->hid, pidff->reports[PID_SET_CONDITION],
-                                 USB_DIR_OUT);
-       }
-}
-
-/*
- * Test if condition effect parameters have changed
- */
-static int pidff_needs_set_condition(struct ff_effect *effect,
-                                    struct ff_effect *old)
-{
-       int i;
-       int ret = 0;
-
-       for (i = 0; i < 2; i++) {
-               struct ff_condition_effect *cond = &effect->u.condition[i];
-               struct ff_condition_effect *old_cond = &old->u.condition[i];
-
-               ret |= cond->center != old_cond->center ||
-                      cond->right_coeff != old_cond->right_coeff ||
-                      cond->left_coeff != old_cond->left_coeff ||
-                      cond->right_saturation != old_cond->right_saturation ||
-                      cond->left_saturation != old_cond->left_saturation ||
-                      cond->deadband != old_cond->deadband;
-       }
-
-       return ret;
-}
-
-/*
- * Send ramp force report to the device
- */
-static void pidff_set_ramp_force_report(struct pidff_device *pidff,
-                                       struct ff_effect *effect)
-{
-       pidff->set_ramp[PID_EFFECT_BLOCK_INDEX].value[0] =
-               pidff->block_load[PID_EFFECT_BLOCK_INDEX].value[0];
-       pidff_set_signed(&pidff->set_ramp[PID_RAMP_START],
-                        effect->u.ramp.start_level);
-       pidff_set_signed(&pidff->set_ramp[PID_RAMP_END],
-                        effect->u.ramp.end_level);
-       usbhid_submit_report(pidff->hid, pidff->reports[PID_SET_RAMP],
-                         USB_DIR_OUT);
-}
-
-/*
- * Test if ramp force parameters have changed
- */
-static int pidff_needs_set_ramp(struct ff_effect *effect, struct ff_effect *old)
-{
-       return effect->u.ramp.start_level != old->u.ramp.start_level ||
-              effect->u.ramp.end_level != old->u.ramp.end_level;
-}
-
-/*
- * Send a request for effect upload to the device
- *
- * Returns 0 if device reported success, -ENOSPC if the device reported memory
- * is full. Upon unknown response the function will retry for 60 times, if
- * still unsuccessful -EIO is returned.
- */
-static int pidff_request_effect_upload(struct pidff_device *pidff, int efnum)
-{
-       int j;
-
-       pidff->create_new_effect_type->value[0] = efnum;
-       usbhid_submit_report(pidff->hid, pidff->reports[PID_CREATE_NEW_EFFECT],
-                         USB_DIR_OUT);
-       debug("create_new_effect sent, type: %d", efnum);
-
-       pidff->block_load[PID_EFFECT_BLOCK_INDEX].value[0] = 0;
-       pidff->block_load_status->value[0] = 0;
-       usbhid_wait_io(pidff->hid);
-
-       for (j = 0; j < 60; j++) {
-               debug("pid_block_load requested");
-               usbhid_submit_report(pidff->hid, pidff->reports[PID_BLOCK_LOAD],
-                                 USB_DIR_IN);
-               usbhid_wait_io(pidff->hid);
-               if (pidff->block_load_status->value[0] ==
-                   pidff->status_id[PID_BLOCK_LOAD_SUCCESS]) {
-                       debug("device reported free memory: %d bytes",
-                             pidff->block_load[PID_RAM_POOL_AVAILABLE].value ?
-                               pidff->block_load[PID_RAM_POOL_AVAILABLE].value[0] : -1);
-                       return 0;
-               }
-               if (pidff->block_load_status->value[0] ==
-                   pidff->status_id[PID_BLOCK_LOAD_FULL]) {
-                       debug("not enough memory free: %d bytes",
-                             pidff->block_load[PID_RAM_POOL_AVAILABLE].value ?
-                               pidff->block_load[PID_RAM_POOL_AVAILABLE].value[0] : -1);
-                       return -ENOSPC;
-               }
-       }
-       printk(KERN_ERR "hid-pidff: pid_block_load failed 60 times\n");
-       return -EIO;
-}
-
-/*
- * Play the effect with PID id n times
- */
-static void pidff_playback_pid(struct pidff_device *pidff, int pid_id, int n)
-{
-       pidff->effect_operation[PID_EFFECT_BLOCK_INDEX].value[0] = pid_id;
-
-       if (n == 0) {
-               pidff->effect_operation_status->value[0] =
-                       pidff->operation_id[PID_EFFECT_STOP];
-       } else {
-               pidff->effect_operation_status->value[0] =
-                       pidff->operation_id[PID_EFFECT_START];
-               pidff->effect_operation[PID_LOOP_COUNT].value[0] = n;
-       }
-
-       usbhid_wait_io(pidff->hid);
-       usbhid_submit_report(pidff->hid, pidff->reports[PID_EFFECT_OPERATION],
-                         USB_DIR_OUT);
-}
-
-/**
- * Play the effect with effect id @effect_id for @value times
- */
-static int pidff_playback(struct input_dev *dev, int effect_id, int value)
-{
-       struct pidff_device *pidff = dev->ff->private;
-
-       pidff_playback_pid(pidff, pidff->pid_id[effect_id], value);
-
-       return 0;
-}
-
-/*
- * Erase effect with PID id
- */
-static void pidff_erase_pid(struct pidff_device *pidff, int pid_id)
-{
-       pidff->block_free[PID_EFFECT_BLOCK_INDEX].value[0] = pid_id;
-       usbhid_submit_report(pidff->hid, pidff->reports[PID_BLOCK_FREE],
-                         USB_DIR_OUT);
-}
-
-/*
- * Stop and erase effect with effect_id
- */
-static int pidff_erase_effect(struct input_dev *dev, int effect_id)
-{
-       struct pidff_device *pidff = dev->ff->private;
-       int pid_id = pidff->pid_id[effect_id];
-
-       debug("starting to erase %d/%d", effect_id, pidff->pid_id[effect_id]);
-       pidff_playback_pid(pidff, pid_id, 0);
-       pidff_erase_pid(pidff, pid_id);
-
-       return 0;
-}
-
-/*
- * Effect upload handler
- */
-static int pidff_upload_effect(struct input_dev *dev, struct ff_effect *effect,
-                              struct ff_effect *old)
-{
-       struct pidff_device *pidff = dev->ff->private;
-       int type_id;
-       int error;
-
-       switch (effect->type) {
-       case FF_CONSTANT:
-               if (!old) {
-                       error = pidff_request_effect_upload(pidff,
-                                       pidff->type_id[PID_CONSTANT]);
-                       if (error)
-                               return error;
-               }
-               if (!old || pidff_needs_set_effect(effect, old))
-                       pidff_set_effect_report(pidff, effect);
-               if (!old || pidff_needs_set_constant(effect, old))
-                       pidff_set_constant_force_report(pidff, effect);
-               if (!old ||
-                   pidff_needs_set_envelope(&effect->u.constant.envelope,
-                                       &old->u.constant.envelope))
-                       pidff_set_envelope_report(pidff,
-                                       &effect->u.constant.envelope);
-               break;
-
-       case FF_PERIODIC:
-               if (!old) {
-                       switch (effect->u.periodic.waveform) {
-                       case FF_SQUARE:
-                               type_id = PID_SQUARE;
-                               break;
-                       case FF_TRIANGLE:
-                               type_id = PID_TRIANGLE;
-                               break;
-                       case FF_SINE:
-                               type_id = PID_SINE;
-                               break;
-                       case FF_SAW_UP:
-                               type_id = PID_SAW_UP;
-                               break;
-                       case FF_SAW_DOWN:
-                               type_id = PID_SAW_DOWN;
-                               break;
-                       default:
-                               printk(KERN_ERR
-                                      "hid-pidff: invalid waveform\n");
-                               return -EINVAL;
-                       }
-
-                       error = pidff_request_effect_upload(pidff,
-                                       pidff->type_id[type_id]);
-                       if (error)
-                               return error;
-               }
-               if (!old || pidff_needs_set_effect(effect, old))
-                       pidff_set_effect_report(pidff, effect);
-               if (!old || pidff_needs_set_periodic(effect, old))
-                       pidff_set_periodic_report(pidff, effect);
-               if (!old ||
-                   pidff_needs_set_envelope(&effect->u.periodic.envelope,
-                                       &old->u.periodic.envelope))
-                       pidff_set_envelope_report(pidff,
-                                       &effect->u.periodic.envelope);
-               break;
-
-       case FF_RAMP:
-               if (!old) {
-                       error = pidff_request_effect_upload(pidff,
-                                       pidff->type_id[PID_RAMP]);
-                       if (error)
-                               return error;
-               }
-               if (!old || pidff_needs_set_effect(effect, old))
-                       pidff_set_effect_report(pidff, effect);
-               if (!old || pidff_needs_set_ramp(effect, old))
-                       pidff_set_ramp_force_report(pidff, effect);
-               if (!old ||
-                   pidff_needs_set_envelope(&effect->u.ramp.envelope,
-                                       &old->u.ramp.envelope))
-                       pidff_set_envelope_report(pidff,
-                                       &effect->u.ramp.envelope);
-               break;
-
-       case FF_SPRING:
-               if (!old) {
-                       error = pidff_request_effect_upload(pidff,
-                                       pidff->type_id[PID_SPRING]);
-                       if (error)
-                               return error;
-               }
-               if (!old || pidff_needs_set_effect(effect, old))
-                       pidff_set_effect_report(pidff, effect);
-               if (!old || pidff_needs_set_condition(effect, old))
-                       pidff_set_condition_report(pidff, effect);
-               break;
-
-       case FF_FRICTION:
-               if (!old) {
-                       error = pidff_request_effect_upload(pidff,
-                                       pidff->type_id[PID_FRICTION]);
-                       if (error)
-                               return error;
-               }
-               if (!old || pidff_needs_set_effect(effect, old))
-                       pidff_set_effect_report(pidff, effect);
-               if (!old || pidff_needs_set_condition(effect, old))
-                       pidff_set_condition_report(pidff, effect);
-               break;
-
-       case FF_DAMPER:
-               if (!old) {
-                       error = pidff_request_effect_upload(pidff,
-                                       pidff->type_id[PID_DAMPER]);
-                       if (error)
-                               return error;
-               }
-               if (!old || pidff_needs_set_effect(effect, old))
-                       pidff_set_effect_report(pidff, effect);
-               if (!old || pidff_needs_set_condition(effect, old))
-                       pidff_set_condition_report(pidff, effect);
-               break;
-
-       case FF_INERTIA:
-               if (!old) {
-                       error = pidff_request_effect_upload(pidff,
-                                       pidff->type_id[PID_INERTIA]);
-                       if (error)
-                               return error;
-               }
-               if (!old || pidff_needs_set_effect(effect, old))
-                       pidff_set_effect_report(pidff, effect);
-               if (!old || pidff_needs_set_condition(effect, old))
-                       pidff_set_condition_report(pidff, effect);
-               break;
-
-       default:
-               printk(KERN_ERR "hid-pidff: invalid type\n");
-               return -EINVAL;
-       }
-
-       if (!old)
-               pidff->pid_id[effect->id] =
-                   pidff->block_load[PID_EFFECT_BLOCK_INDEX].value[0];
-
-       debug("uploaded");
-
-       return 0;
-}
-
-/*
- * set_gain() handler
- */
-static void pidff_set_gain(struct input_dev *dev, u16 gain)
-{
-       struct pidff_device *pidff = dev->ff->private;
-
-       pidff_set(&pidff->device_gain[PID_DEVICE_GAIN_FIELD], gain);
-       usbhid_submit_report(pidff->hid, pidff->reports[PID_DEVICE_GAIN],
-                         USB_DIR_OUT);
-}
-
-static void pidff_autocenter(struct pidff_device *pidff, u16 magnitude)
-{
-       struct hid_field *field =
-               pidff->block_load[PID_EFFECT_BLOCK_INDEX].field;
-
-       if (!magnitude) {
-               pidff_playback_pid(pidff, field->logical_minimum, 0);
-               return;
-       }
-
-       pidff_playback_pid(pidff, field->logical_minimum, 1);
-
-       pidff->set_effect[PID_EFFECT_BLOCK_INDEX].value[0] =
-               pidff->block_load[PID_EFFECT_BLOCK_INDEX].field->logical_minimum;
-       pidff->set_effect_type->value[0] = pidff->type_id[PID_SPRING];
-       pidff->set_effect[PID_DURATION].value[0] = 0;
-       pidff->set_effect[PID_TRIGGER_BUTTON].value[0] = 0;
-       pidff->set_effect[PID_TRIGGER_REPEAT_INT].value[0] = 0;
-       pidff_set(&pidff->set_effect[PID_GAIN], magnitude);
-       pidff->set_effect[PID_START_DELAY].value[0] = 0;
-
-       usbhid_submit_report(pidff->hid, pidff->reports[PID_SET_EFFECT],
-                         USB_DIR_OUT);
-}
-
-/*
- * pidff_set_autocenter() handler
- */
-static void pidff_set_autocenter(struct input_dev *dev, u16 magnitude)
-{
-       struct pidff_device *pidff = dev->ff->private;
-
-       pidff_autocenter(pidff, magnitude);
-}
-
-/*
- * Find fields from a report and fill a pidff_usage
- */
-static int pidff_find_fields(struct pidff_usage *usage, const u8 *table,
-                            struct hid_report *report, int count, int strict)
-{
-       int i, j, k, found;
-
-       for (k = 0; k < count; k++) {
-               found = 0;
-               for (i = 0; i < report->maxfield; i++) {
-                       if (report->field[i]->maxusage !=
-                           report->field[i]->report_count) {
-                               debug("maxusage and report_count do not match, "
-                                     "skipping");
-                               continue;
-                       }
-                       for (j = 0; j < report->field[i]->maxusage; j++) {
-                               if (report->field[i]->usage[j].hid ==
-                                   (HID_UP_PID | table[k])) {
-                                       debug("found %d at %d->%d", k, i, j);
-                                       usage[k].field = report->field[i];
-                                       usage[k].value =
-                                               &report->field[i]->value[j];
-                                       found = 1;
-                                       break;
-                               }
-                       }
-                       if (found)
-                               break;
-               }
-               if (!found && strict) {
-                       debug("failed to locate %d", k);
-                       return -1;
-               }
-       }
-       return 0;
-}
-
-/*
- * Return index into pidff_reports for the given usage
- */
-static int pidff_check_usage(int usage)
-{
-       int i;
-
-       for (i = 0; i < sizeof(pidff_reports); i++)
-               if (usage == (HID_UP_PID | pidff_reports[i]))
-                       return i;
-
-       return -1;
-}
-
-/*
- * Find the reports and fill pidff->reports[]
- * report_type specifies either OUTPUT or FEATURE reports
- */
-static void pidff_find_reports(struct hid_device *hid, int report_type,
-                              struct pidff_device *pidff)
-{
-       struct hid_report *report;
-       int i, ret;
-
-       list_for_each_entry(report,
-                           &hid->report_enum[report_type].report_list, list) {
-               if (report->maxfield < 1)
-                       continue;
-               ret = pidff_check_usage(report->field[0]->logical);
-               if (ret != -1) {
-                       debug("found usage 0x%02x from field->logical",
-                             pidff_reports[ret]);
-                       pidff->reports[ret] = report;
-                       continue;
-               }
-
-               /*
-                * Sometimes logical collections are stacked to indicate
-                * different usages for the report and the field, in which
-                * case we want the usage of the parent. However, Linux HID
-                * implementation hides this fact, so we have to dig it up
-                * ourselves
-                */
-               i = report->field[0]->usage[0].collection_index;
-               if (i <= 0 ||
-                   hid->collection[i - 1].type != HID_COLLECTION_LOGICAL)
-                       continue;
-               ret = pidff_check_usage(hid->collection[i - 1].usage);
-               if (ret != -1 && !pidff->reports[ret]) {
-                       debug("found usage 0x%02x from collection array",
-                             pidff_reports[ret]);
-                       pidff->reports[ret] = report;
-               }
-       }
-}
-
-/*
- * Test if the required reports have been found
- */
-static int pidff_reports_ok(struct pidff_device *pidff)
-{
-       int i;
-
-       for (i = 0; i <= PID_REQUIRED_REPORTS; i++) {
-               if (!pidff->reports[i]) {
-                       debug("%d missing", i);
-                       return 0;
-               }
-       }
-
-       return 1;
-}
-
-/*
- * Find a field with a specific usage within a report
- */
-static struct hid_field *pidff_find_special_field(struct hid_report *report,
-                                                 int usage, int enforce_min)
-{
-       int i;
-
-       for (i = 0; i < report->maxfield; i++) {
-               if (report->field[i]->logical == (HID_UP_PID | usage) &&
-                   report->field[i]->report_count > 0) {
-                       if (!enforce_min ||
-                           report->field[i]->logical_minimum == 1)
-                               return report->field[i];
-                       else {
-                               printk(KERN_ERR "hid-pidff: logical_minimum "
-                                       "is not 1 as it should be\n");
-                               return NULL;
-                       }
-               }
-       }
-       return NULL;
-}
-
-/*
- * Fill a pidff->*_id struct table
- */
-static int pidff_find_special_keys(int *keys, struct hid_field *fld,
-                                  const u8 *usagetable, int count)
-{
-
-       int i, j;
-       int found = 0;
-
-       for (i = 0; i < count; i++) {
-               for (j = 0; j < fld->maxusage; j++) {
-                       if (fld->usage[j].hid == (HID_UP_PID | usagetable[i])) {
-                               keys[i] = j + 1;
-                               found++;
-                               break;
-                       }
-               }
-       }
-       return found;
-}
-
-#define PIDFF_FIND_SPECIAL_KEYS(keys, field, name) \
-       pidff_find_special_keys(pidff->keys, pidff->field, pidff_ ## name, \
-               sizeof(pidff_ ## name))
-
-/*
- * Find and check the special fields
- */
-static int pidff_find_special_fields(struct pidff_device *pidff)
-{
-       debug("finding special fields");
-
-       pidff->create_new_effect_type =
-               pidff_find_special_field(pidff->reports[PID_CREATE_NEW_EFFECT],
-                                        0x25, 1);
-       pidff->set_effect_type =
-               pidff_find_special_field(pidff->reports[PID_SET_EFFECT],
-                                        0x25, 1);
-       pidff->effect_direction =
-               pidff_find_special_field(pidff->reports[PID_SET_EFFECT],
-                                        0x57, 0);
-       pidff->device_control =
-               pidff_find_special_field(pidff->reports[PID_DEVICE_CONTROL],
-                                        0x96, 1);
-       pidff->block_load_status =
-               pidff_find_special_field(pidff->reports[PID_BLOCK_LOAD],
-                                        0x8b, 1);
-       pidff->effect_operation_status =
-               pidff_find_special_field(pidff->reports[PID_EFFECT_OPERATION],
-                                        0x78, 1);
-
-       debug("search done");
-
-       if (!pidff->create_new_effect_type || !pidff->set_effect_type) {
-               printk(KERN_ERR "hid-pidff: effect lists not found\n");
-               return -1;
-       }
-
-       if (!pidff->effect_direction) {
-               printk(KERN_ERR "hid-pidff: direction field not found\n");
-               return -1;
-       }
-
-       if (!pidff->device_control) {
-               printk(KERN_ERR "hid-pidff: device control field not found\n");
-               return -1;
-       }
-
-       if (!pidff->block_load_status) {
-               printk(KERN_ERR
-                      "hid-pidff: block load status field not found\n");
-               return -1;
-       }
-
-       if (!pidff->effect_operation_status) {
-               printk(KERN_ERR
-                      "hid-pidff: effect operation field not found\n");
-               return -1;
-       }
-
-       pidff_find_special_keys(pidff->control_id, pidff->device_control,
-                               pidff_device_control,
-                               sizeof(pidff_device_control));
-
-       PIDFF_FIND_SPECIAL_KEYS(control_id, device_control, device_control);
-
-       if (!PIDFF_FIND_SPECIAL_KEYS(type_id, create_new_effect_type,
-                                    effect_types)) {
-               printk(KERN_ERR "hid-pidff: no effect types found\n");
-               return -1;
-       }
-
-       if (PIDFF_FIND_SPECIAL_KEYS(status_id, block_load_status,
-                                   block_load_status) !=
-                       sizeof(pidff_block_load_status)) {
-               printk(KERN_ERR
-                      "hidpidff: block load status identifiers not found\n");
-               return -1;
-       }
-
-       if (PIDFF_FIND_SPECIAL_KEYS(operation_id, effect_operation_status,
-                                   effect_operation_status) !=
-                       sizeof(pidff_effect_operation_status)) {
-               printk(KERN_ERR
-                      "hidpidff: effect operation identifiers not found\n");
-               return -1;
-       }
-
-       return 0;
-}
-
-/**
- * Find the implemented effect types
- */
-static int pidff_find_effects(struct pidff_device *pidff,
-                             struct input_dev *dev)
-{
-       int i;
-
-       for (i = 0; i < sizeof(pidff_effect_types); i++) {
-               int pidff_type = pidff->type_id[i];
-               if (pidff->set_effect_type->usage[pidff_type].hid !=
-                   pidff->create_new_effect_type->usage[pidff_type].hid) {
-                       printk(KERN_ERR "hid-pidff: "
-                              "effect type number %d is invalid\n", i);
-                       return -1;
-               }
-       }
-
-       if (pidff->type_id[PID_CONSTANT])
-               set_bit(FF_CONSTANT, dev->ffbit);
-       if (pidff->type_id[PID_RAMP])
-               set_bit(FF_RAMP, dev->ffbit);
-       if (pidff->type_id[PID_SQUARE]) {
-               set_bit(FF_SQUARE, dev->ffbit);
-               set_bit(FF_PERIODIC, dev->ffbit);
-       }
-       if (pidff->type_id[PID_SINE]) {
-               set_bit(FF_SINE, dev->ffbit);
-               set_bit(FF_PERIODIC, dev->ffbit);
-       }
-       if (pidff->type_id[PID_TRIANGLE]) {
-               set_bit(FF_TRIANGLE, dev->ffbit);
-               set_bit(FF_PERIODIC, dev->ffbit);
-       }
-       if (pidff->type_id[PID_SAW_UP]) {
-               set_bit(FF_SAW_UP, dev->ffbit);
-               set_bit(FF_PERIODIC, dev->ffbit);
-       }
-       if (pidff->type_id[PID_SAW_DOWN]) {
-               set_bit(FF_SAW_DOWN, dev->ffbit);
-               set_bit(FF_PERIODIC, dev->ffbit);
-       }
-       if (pidff->type_id[PID_SPRING])
-               set_bit(FF_SPRING, dev->ffbit);
-       if (pidff->type_id[PID_DAMPER])
-               set_bit(FF_DAMPER, dev->ffbit);
-       if (pidff->type_id[PID_INERTIA])
-               set_bit(FF_INERTIA, dev->ffbit);
-       if (pidff->type_id[PID_FRICTION])
-               set_bit(FF_FRICTION, dev->ffbit);
-
-       return 0;
-
-}
-
-#define PIDFF_FIND_FIELDS(name, report, strict) \
-       pidff_find_fields(pidff->name, pidff_ ## name, \
-               pidff->reports[report], \
-               sizeof(pidff_ ## name), strict)
-
-/*
- * Fill and check the pidff_usages
- */
-static int pidff_init_fields(struct pidff_device *pidff, struct input_dev *dev)
-{
-       int envelope_ok = 0;
-
-       if (PIDFF_FIND_FIELDS(set_effect, PID_SET_EFFECT, 1)) {
-               printk(KERN_ERR
-                      "hid-pidff: unknown set_effect report layout\n");
-               return -ENODEV;
-       }
-
-       PIDFF_FIND_FIELDS(block_load, PID_BLOCK_LOAD, 0);
-       if (!pidff->block_load[PID_EFFECT_BLOCK_INDEX].value) {
-               printk(KERN_ERR
-                      "hid-pidff: unknown pid_block_load report layout\n");
-               return -ENODEV;
-       }
-
-       if (PIDFF_FIND_FIELDS(effect_operation, PID_EFFECT_OPERATION, 1)) {
-               printk(KERN_ERR
-                      "hid-pidff: unknown effect_operation report layout\n");
-               return -ENODEV;
-       }
-
-       if (PIDFF_FIND_FIELDS(block_free, PID_BLOCK_FREE, 1)) {
-               printk(KERN_ERR
-                      "hid-pidff: unknown pid_block_free report layout\n");
-               return -ENODEV;
-       }
-
-       if (!PIDFF_FIND_FIELDS(set_envelope, PID_SET_ENVELOPE, 1))
-               envelope_ok = 1;
-
-       if (pidff_find_special_fields(pidff) || pidff_find_effects(pidff, dev))
-               return -ENODEV;
-
-       if (!envelope_ok) {
-               if (test_and_clear_bit(FF_CONSTANT, dev->ffbit))
-                       printk(KERN_WARNING "hid-pidff: "
-                              "has constant effect but no envelope\n");
-               if (test_and_clear_bit(FF_RAMP, dev->ffbit))
-                       printk(KERN_WARNING "hid-pidff: "
-                               "has ramp effect but no envelope\n");
-
-               if (test_and_clear_bit(FF_PERIODIC, dev->ffbit))
-                       printk(KERN_WARNING "hid-pidff: "
-                               "has periodic effect but no envelope\n");
-       }
-
-       if (test_bit(FF_CONSTANT, dev->ffbit) &&
-           PIDFF_FIND_FIELDS(set_constant, PID_SET_CONSTANT, 1)) {
-               printk(KERN_WARNING
-                      "hid-pidff: unknown constant effect layout\n");
-               clear_bit(FF_CONSTANT, dev->ffbit);
-       }
-
-       if (test_bit(FF_RAMP, dev->ffbit) &&
-           PIDFF_FIND_FIELDS(set_ramp, PID_SET_RAMP, 1)) {
-               printk(KERN_WARNING "hid-pidff: unknown ramp effect layout\n");
-               clear_bit(FF_RAMP, dev->ffbit);
-       }
-
-       if ((test_bit(FF_SPRING, dev->ffbit) ||
-            test_bit(FF_DAMPER, dev->ffbit) ||
-            test_bit(FF_FRICTION, dev->ffbit) ||
-            test_bit(FF_INERTIA, dev->ffbit)) &&
-           PIDFF_FIND_FIELDS(set_condition, PID_SET_CONDITION, 1)) {
-               printk(KERN_WARNING
-                      "hid-pidff: unknown condition effect layout\n");
-               clear_bit(FF_SPRING, dev->ffbit);
-               clear_bit(FF_DAMPER, dev->ffbit);
-               clear_bit(FF_FRICTION, dev->ffbit);
-               clear_bit(FF_INERTIA, dev->ffbit);
-       }
-
-       if (test_bit(FF_PERIODIC, dev->ffbit) &&
-           PIDFF_FIND_FIELDS(set_periodic, PID_SET_PERIODIC, 1)) {
-               printk(KERN_WARNING
-                      "hid-pidff: unknown periodic effect layout\n");
-               clear_bit(FF_PERIODIC, dev->ffbit);
-       }
-
-       PIDFF_FIND_FIELDS(pool, PID_POOL, 0);
-
-       if (!PIDFF_FIND_FIELDS(device_gain, PID_DEVICE_GAIN, 1))
-               set_bit(FF_GAIN, dev->ffbit);
-
-       return 0;
-}
-
-/*
- * Reset the device
- */
-static void pidff_reset(struct pidff_device *pidff)
-{
-       struct hid_device *hid = pidff->hid;
-       int i = 0;
-
-       pidff->device_control->value[0] = pidff->control_id[PID_RESET];
-       /* We reset twice as sometimes hid_wait_io isn't waiting long enough */
-       usbhid_submit_report(hid, pidff->reports[PID_DEVICE_CONTROL], USB_DIR_OUT);
-       usbhid_wait_io(hid);
-       usbhid_submit_report(hid, pidff->reports[PID_DEVICE_CONTROL], USB_DIR_OUT);
-       usbhid_wait_io(hid);
-
-       pidff->device_control->value[0] =
-               pidff->control_id[PID_ENABLE_ACTUATORS];
-       usbhid_submit_report(hid, pidff->reports[PID_DEVICE_CONTROL], USB_DIR_OUT);
-       usbhid_wait_io(hid);
-
-       /* pool report is sometimes messed up, refetch it */
-       usbhid_submit_report(hid, pidff->reports[PID_POOL], USB_DIR_IN);
-       usbhid_wait_io(hid);
-
-       if (pidff->pool[PID_SIMULTANEOUS_MAX].value) {
-               int sim_effects = pidff->pool[PID_SIMULTANEOUS_MAX].value[0];
-               while (sim_effects < 2) {
-                       if (i++ > 20) {
-                               printk(KERN_WARNING "hid-pidff: device reports "
-                                      "%d simultaneous effects\n",
-                                      sim_effects);
-                               break;
-                       }
-                       debug("pid_pool requested again");
-                       usbhid_submit_report(hid, pidff->reports[PID_POOL],
-                                         USB_DIR_IN);
-                       usbhid_wait_io(hid);
-               }
-       }
-}
-
-/*
- * Test if autocenter modification is using the supported method
- */
-static int pidff_check_autocenter(struct pidff_device *pidff,
-                                 struct input_dev *dev)
-{
-       int error;
-
-       /*
-        * Let's find out if autocenter modification is supported
-        * Specification doesn't specify anything, so we request an
-        * effect upload and cancel it immediately. If the approved
-        * effect id was one above the minimum, then we assume the first
-        * effect id is a built-in spring type effect used for autocenter
-        */
-
-       error = pidff_request_effect_upload(pidff, 1);
-       if (error) {
-               printk(KERN_ERR "hid-pidff: upload request failed\n");
-               return error;
-       }
-
-       if (pidff->block_load[PID_EFFECT_BLOCK_INDEX].value[0] ==
-           pidff->block_load[PID_EFFECT_BLOCK_INDEX].field->logical_minimum + 1) {
-               pidff_autocenter(pidff, 0xffff);
-               set_bit(FF_AUTOCENTER, dev->ffbit);
-       } else {
-               printk(KERN_NOTICE "hid-pidff: "
-                      "device has unknown autocenter control method\n");
-       }
-
-       pidff_erase_pid(pidff,
-                       pidff->block_load[PID_EFFECT_BLOCK_INDEX].value[0]);
-
-       return 0;
-
-}
-
-/*
- * Check if the device is PID and initialize it
- */
-int hid_pidff_init(struct hid_device *hid)
-{
-       struct pidff_device *pidff;
-       struct hid_input *hidinput = list_entry(hid->inputs.next,
-                                               struct hid_input, list);
-       struct input_dev *dev = hidinput->input;
-       struct ff_device *ff;
-       int max_effects;
-       int error;
-
-       debug("starting pid init");
-
-       if (list_empty(&hid->report_enum[HID_OUTPUT_REPORT].report_list)) {
-               debug("not a PID device, no output report");
-               return -ENODEV;
-       }
-
-       pidff = kzalloc(sizeof(*pidff), GFP_KERNEL);
-       if (!pidff)
-               return -ENOMEM;
-
-       pidff->hid = hid;
-
-       pidff_find_reports(hid, HID_OUTPUT_REPORT, pidff);
-       pidff_find_reports(hid, HID_FEATURE_REPORT, pidff);
-
-       if (!pidff_reports_ok(pidff)) {
-               debug("reports not ok, aborting");
-               error = -ENODEV;
-               goto fail;
-       }
-
-       error = pidff_init_fields(pidff, dev);
-       if (error)
-               goto fail;
-
-       pidff_reset(pidff);
-
-       if (test_bit(FF_GAIN, dev->ffbit)) {
-               pidff_set(&pidff->device_gain[PID_DEVICE_GAIN_FIELD], 0xffff);
-               usbhid_submit_report(pidff->hid, pidff->reports[PID_DEVICE_GAIN],
-                                 USB_DIR_OUT);
-       }
-
-       error = pidff_check_autocenter(pidff, dev);
-       if (error)
-               goto fail;
-
-       max_effects =
-           pidff->block_load[PID_EFFECT_BLOCK_INDEX].field->logical_maximum -
-           pidff->block_load[PID_EFFECT_BLOCK_INDEX].field->logical_minimum +
-           1;
-       debug("max effects is %d", max_effects);
-
-       if (max_effects > PID_EFFECTS_MAX)
-               max_effects = PID_EFFECTS_MAX;
-
-       if (pidff->pool[PID_SIMULTANEOUS_MAX].value)
-               debug("max simultaneous effects is %d",
-                     pidff->pool[PID_SIMULTANEOUS_MAX].value[0]);
-
-       if (pidff->pool[PID_RAM_POOL_SIZE].value)
-               debug("device memory size is %d bytes",
-                     pidff->pool[PID_RAM_POOL_SIZE].value[0]);
-
-       if (pidff->pool[PID_DEVICE_MANAGED_POOL].value &&
-           pidff->pool[PID_DEVICE_MANAGED_POOL].value[0] == 0) {
-               printk(KERN_NOTICE "hid-pidff: "
-                      "device does not support device managed pool\n");
-               goto fail;
-       }
-
-       error = input_ff_create(dev, max_effects);
-       if (error)
-               goto fail;
-
-       ff = dev->ff;
-       ff->private = pidff;
-       ff->upload = pidff_upload_effect;
-       ff->erase = pidff_erase_effect;
-       ff->set_gain = pidff_set_gain;
-       ff->set_autocenter = pidff_set_autocenter;
-       ff->playback = pidff_playback;
-
-       printk(KERN_INFO "Force feedback for USB HID PID devices by "
-              "Anssi Hannula <anssi.hannula@gmail.com>\n");
-
-       return 0;
-
- fail:
-       kfree(pidff);
-       return error;
-}
diff --git a/drivers/usb/input/hid-plff.c b/drivers/usb/input/hid-plff.c
deleted file mode 100644 (file)
index 76d2e6e..0000000
+++ /dev/null
@@ -1,129 +0,0 @@
-/*
- *  Force feedback support for PantherLord USB/PS2 2in1 Adapter devices
- *
- *  Copyright (c) 2007 Anssi Hannula <anssi.hannula@gmail.com>
- */
-
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-
-/* #define DEBUG */
-
-#define debug(format, arg...) pr_debug("hid-plff: " format "\n" , ## arg)
-
-#include <linux/input.h>
-#include <linux/usb.h>
-#include <linux/hid.h>
-#include "usbhid.h"
-
-struct plff_device {
-       struct hid_report *report;
-};
-
-static int hid_plff_play(struct input_dev *dev, void *data,
-                        struct ff_effect *effect)
-{
-       struct hid_device *hid = dev->private;
-       struct plff_device *plff = data;
-       int left, right;
-
-       left = effect->u.rumble.strong_magnitude;
-       right = effect->u.rumble.weak_magnitude;
-       debug("called with 0x%04x 0x%04x", left, right);
-
-       left = left * 0x7f / 0xffff;
-       right = right * 0x7f / 0xffff;
-
-       plff->report->field[0]->value[2] = left;
-       plff->report->field[0]->value[3] = right;
-       debug("running with 0x%02x 0x%02x", left, right);
-       usbhid_submit_report(hid, plff->report, USB_DIR_OUT);
-
-       return 0;
-}
-
-int hid_plff_init(struct hid_device *hid)
-{
-       struct plff_device *plff;
-       struct hid_report *report;
-       struct hid_input *hidinput;
-       struct list_head *report_list =
-                       &hid->report_enum[HID_OUTPUT_REPORT].report_list;
-       struct list_head *report_ptr = report_list;
-       struct input_dev *dev;
-       int error;
-
-       /* The device contains 2 output reports (one for each
-          HID_QUIRK_MULTI_INPUT device), both containing 1 field, which
-          contains 4 ff00.0002 usages and 4 16bit absolute values.
-
-          The 2 input reports also contain a field which contains
-          8 ff00.0001 usages and 8 boolean values. Their meaning is
-          currently unknown. */
-
-       if (list_empty(report_list)) {
-               printk(KERN_ERR "hid-plff: no output reports found\n");
-               return -ENODEV;
-       }
-
-       list_for_each_entry(hidinput, &hid->inputs, list) {
-
-               report_ptr = report_ptr->next;
-
-               if (report_ptr == report_list) {
-                       printk(KERN_ERR "hid-plff: required output report is missing\n");
-                       return -ENODEV;
-               }
-
-               report = list_entry(report_ptr, struct hid_report, list);
-               if (report->maxfield < 1) {
-                       printk(KERN_ERR "hid-plff: no fields in the report\n");
-                       return -ENODEV;
-               }
-
-               if (report->field[0]->report_count < 4) {
-                       printk(KERN_ERR "hid-plff: not enough values in the field\n");
-                       return -ENODEV;
-               }
-
-               plff = kzalloc(sizeof(struct plff_device), GFP_KERNEL);
-               if (!plff)
-                       return -ENOMEM;
-
-               dev = hidinput->input;
-
-               set_bit(FF_RUMBLE, dev->ffbit);
-
-               error = input_ff_create_memless(dev, plff, hid_plff_play);
-               if (error) {
-                       kfree(plff);
-                       return error;
-               }
-
-               plff->report = report;
-               plff->report->field[0]->value[0] = 0x00;
-               plff->report->field[0]->value[1] = 0x00;
-               plff->report->field[0]->value[2] = 0x00;
-               plff->report->field[0]->value[3] = 0x00;
-               usbhid_submit_report(hid, plff->report, USB_DIR_OUT);
-       }
-
-       printk(KERN_INFO "hid-plff: Force feedback for PantherLord USB/PS2 "
-              "2in1 Adapters by Anssi Hannula <anssi.hannula@gmail.com>\n");
-
-       return 0;
-}
diff --git a/drivers/usb/input/hid-tmff.c b/drivers/usb/input/hid-tmff.c
deleted file mode 100644 (file)
index ab67331..0000000
+++ /dev/null
@@ -1,147 +0,0 @@
-/*
- * Force feedback support for various HID compliant devices by ThrustMaster:
- *    ThrustMaster FireStorm Dual Power 2
- * and possibly others whose device ids haven't been added.
- *
- *  Modified to support ThrustMaster devices by Zinx Verituse
- *  on 2003-01-25 from the Logitech force feedback driver,
- *  which is by Johann Deneux.
- *
- *  Copyright (c) 2003 Zinx Verituse <zinx@epicsol.org>
- *  Copyright (c) 2002 Johann Deneux
- */
-
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#include <linux/input.h>
-
-#undef DEBUG
-#include <linux/usb.h>
-
-#include <linux/hid.h>
-#include "usbhid.h"
-
-/* Usages for thrustmaster devices I know about */
-#define THRUSTMASTER_USAGE_RUMBLE_LR   (HID_UP_GENDESK | 0xbb)
-
-
-struct tmff_device {
-       struct hid_report *report;
-       struct hid_field *rumble;
-};
-
-/* Changes values from 0 to 0xffff into values from minimum to maximum */
-static inline int hid_tmff_scale(unsigned int in, int minimum, int maximum)
-{
-       int ret;
-
-       ret = (in * (maximum - minimum) / 0xffff) + minimum;
-       if (ret < minimum)
-               return minimum;
-       if (ret > maximum)
-               return maximum;
-       return ret;
-}
-
-static int hid_tmff_play(struct input_dev *dev, void *data, struct ff_effect *effect)
-{
-       struct hid_device *hid = dev->private;
-       struct tmff_device *tmff = data;
-       int left, right;        /* Rumbling */
-
-       left = hid_tmff_scale(effect->u.rumble.weak_magnitude,
-               tmff->rumble->logical_minimum, tmff->rumble->logical_maximum);
-       right = hid_tmff_scale(effect->u.rumble.strong_magnitude,
-               tmff->rumble->logical_minimum, tmff->rumble->logical_maximum);
-
-       tmff->rumble->value[0] = left;
-       tmff->rumble->value[1] = right;
-       dbg("(left,right)=(%08x, %08x)", left, right);
-       usbhid_submit_report(hid, tmff->report, USB_DIR_OUT);
-
-       return 0;
-}
-
-int hid_tmff_init(struct hid_device *hid)
-{
-       struct tmff_device *tmff;
-       struct list_head *pos;
-       struct hid_input *hidinput = list_entry(hid->inputs.next, struct hid_input, list);
-       struct input_dev *input_dev = hidinput->input;
-       int error;
-
-       tmff = kzalloc(sizeof(struct tmff_device), GFP_KERNEL);
-       if (!tmff)
-               return -ENOMEM;
-
-       /* Find the report to use */
-       __list_for_each(pos, &hid->report_enum[HID_OUTPUT_REPORT].report_list) {
-               struct hid_report *report = (struct hid_report *)pos;
-               int fieldnum;
-
-               for (fieldnum = 0; fieldnum < report->maxfield; ++fieldnum) {
-                       struct hid_field *field = report->field[fieldnum];
-
-                       if (field->maxusage <= 0)
-                               continue;
-
-                       switch (field->usage[0].hid) {
-                               case THRUSTMASTER_USAGE_RUMBLE_LR:
-                                       if (field->report_count < 2) {
-                                               warn("ignoring THRUSTMASTER_USAGE_RUMBLE_LR with report_count < 2");
-                                               continue;
-                                       }
-
-                                       if (field->logical_maximum == field->logical_minimum) {
-                                               warn("ignoring THRUSTMASTER_USAGE_RUMBLE_LR with logical_maximum == logical_minimum");
-                                               continue;
-                                       }
-
-                                       if (tmff->report && tmff->report != report) {
-                                               warn("ignoring THRUSTMASTER_USAGE_RUMBLE_LR in other report");
-                                               continue;
-                                       }
-
-                                       if (tmff->rumble && tmff->rumble != field) {
-                                               warn("ignoring duplicate THRUSTMASTER_USAGE_RUMBLE_LR");
-                                               continue;
-                                       }
-
-                                       tmff->report = report;
-                                       tmff->rumble = field;
-
-                                       set_bit(FF_RUMBLE, input_dev->ffbit);
-                                       break;
-
-                               default:
-                                       warn("ignoring unknown output usage %08x", field->usage[0].hid);
-                                       continue;
-                       }
-               }
-       }
-
-       error = input_ff_create_memless(input_dev, tmff, hid_tmff_play);
-       if (error) {
-               kfree(tmff);
-               return error;
-       }
-
-       info("Force feedback for ThrustMaster rumble pad devices by Zinx Verituse <zinx@epicsol.org>");
-
-       return 0;
-}
-
diff --git a/drivers/usb/input/hid-zpff.c b/drivers/usb/input/hid-zpff.c
deleted file mode 100644 (file)
index 7bd8238..0000000
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- *  Force feedback support for Zeroplus based devices
- *
- *  Copyright (c) 2005, 2006 Anssi Hannula <anssi.hannula@gmail.com>
- */
-
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-
-/* #define DEBUG */
-
-#define debug(format, arg...) pr_debug("hid-zpff: " format "\n" , ## arg)
-
-#include <linux/input.h>
-#include <linux/usb.h>
-#include <linux/hid.h>
-#include "usbhid.h"
-
-struct zpff_device {
-       struct hid_report *report;
-};
-
-static int hid_zpff_play(struct input_dev *dev, void *data,
-                        struct ff_effect *effect)
-{
-       struct hid_device *hid = dev->private;
-       struct zpff_device *zpff = data;
-       int left, right;
-
-       /*
-        * The following is specified the other way around in the Zeroplus
-        * datasheet but the order below is correct for the XFX Executioner;
-        * however it is possible that the XFX Executioner is an exception
-        */
-
-       left = effect->u.rumble.strong_magnitude;
-       right = effect->u.rumble.weak_magnitude;
-       debug("called with 0x%04x 0x%04x", left, right);
-
-       left = left * 0x7f / 0xffff;
-       right = right * 0x7f / 0xffff;
-
-       zpff->report->field[2]->value[0] = left;
-       zpff->report->field[3]->value[0] = right;
-       debug("running with 0x%02x 0x%02x", left, right);
-       usbhid_submit_report(hid, zpff->report, USB_DIR_OUT);
-
-       return 0;
-}
-
-int hid_zpff_init(struct hid_device *hid)
-{
-       struct zpff_device *zpff;
-       struct hid_report *report;
-       struct hid_input *hidinput = list_entry(hid->inputs.next,
-                                               struct hid_input, list);
-       struct list_head *report_list =
-                       &hid->report_enum[HID_OUTPUT_REPORT].report_list;
-       struct input_dev *dev = hidinput->input;
-       int error;
-
-       if (list_empty(report_list)) {
-               printk(KERN_ERR "hid-zpff: no output report found\n");
-               return -ENODEV;
-       }
-
-       report = list_entry(report_list->next, struct hid_report, list);
-
-       if (report->maxfield < 4) {
-               printk(KERN_ERR "hid-zpff: not enough fields in report\n");
-               return -ENODEV;
-       }
-
-       zpff = kzalloc(sizeof(struct zpff_device), GFP_KERNEL);
-       if (!zpff)
-               return -ENOMEM;
-
-       set_bit(FF_RUMBLE, dev->ffbit);
-
-       error = input_ff_create_memless(dev, zpff, hid_zpff_play);
-       if (error) {
-               kfree(zpff);
-               return error;
-       }
-
-       zpff->report = report;
-       zpff->report->field[0]->value[0] = 0x00;
-       zpff->report->field[1]->value[0] = 0x02;
-       zpff->report->field[2]->value[0] = 0x00;
-       zpff->report->field[3]->value[0] = 0x00;
-       usbhid_submit_report(hid, zpff->report, USB_DIR_OUT);
-
-       printk(KERN_INFO "Force feedback for Zeroplus based devices by "
-              "Anssi Hannula <anssi.hannula@gmail.com>\n");
-
-       return 0;
-}
diff --git a/drivers/usb/input/hiddev.c b/drivers/usb/input/hiddev.c
deleted file mode 100644 (file)
index a8b3d66..0000000
+++ /dev/null
@@ -1,847 +0,0 @@
-/*
- *  Copyright (c) 2001 Paul Stewart
- *  Copyright (c) 2001 Vojtech Pavlik
- *
- *  HID char devices, giving access to raw HID device events.
- *
- */
-
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Should you need to contact me, the author, you can do so either by
- * e-mail - mail your message to Paul Stewart <stewart@wetlogic.net>
- */
-
-#include <linux/poll.h>
-#include <linux/slab.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/smp_lock.h>
-#include <linux/input.h>
-#include <linux/usb.h>
-#include <linux/hid.h>
-#include <linux/hiddev.h>
-#include "usbhid.h"
-
-#ifdef CONFIG_USB_DYNAMIC_MINORS
-#define HIDDEV_MINOR_BASE      0
-#define HIDDEV_MINORS          256
-#else
-#define HIDDEV_MINOR_BASE      96
-#define HIDDEV_MINORS          16
-#endif
-#define HIDDEV_BUFFER_SIZE     64
-
-struct hiddev {
-       int exist;
-       int open;
-       wait_queue_head_t wait;
-       struct hid_device *hid;
-       struct list_head list;
-};
-
-struct hiddev_list {
-       struct hiddev_usage_ref buffer[HIDDEV_BUFFER_SIZE];
-       int head;
-       int tail;
-       unsigned flags;
-       struct fasync_struct *fasync;
-       struct hiddev *hiddev;
-       struct list_head node;
-};
-
-static struct hiddev *hiddev_table[HIDDEV_MINORS];
-
-/*
- * Find a report, given the report's type and ID.  The ID can be specified
- * indirectly by REPORT_ID_FIRST (which returns the first report of the given
- * type) or by (REPORT_ID_NEXT | old_id), which returns the next report of the
- * given type which follows old_id.
- */
-static struct hid_report *
-hiddev_lookup_report(struct hid_device *hid, struct hiddev_report_info *rinfo)
-{
-       unsigned int flags = rinfo->report_id & ~HID_REPORT_ID_MASK;
-       unsigned int rid = rinfo->report_id & HID_REPORT_ID_MASK;
-       struct hid_report_enum *report_enum;
-       struct hid_report *report;
-       struct list_head *list;
-
-       if (rinfo->report_type < HID_REPORT_TYPE_MIN ||
-           rinfo->report_type > HID_REPORT_TYPE_MAX)
-               return NULL;
-
-       report_enum = hid->report_enum +
-               (rinfo->report_type - HID_REPORT_TYPE_MIN);
-
-       switch (flags) {
-       case 0: /* Nothing to do -- report_id is already set correctly */
-               break;
-
-       case HID_REPORT_ID_FIRST:
-               if (list_empty(&report_enum->report_list))
-                       return NULL;
-
-               list = report_enum->report_list.next;
-               report = list_entry(list, struct hid_report, list);
-               rinfo->report_id = report->id;
-               break;
-
-       case HID_REPORT_ID_NEXT:
-               report = report_enum->report_id_hash[rid];
-               if (!report)
-                       return NULL;
-
-               list = report->list.next;
-               if (list == &report_enum->report_list)
-                       return NULL;
-
-               report = list_entry(list, struct hid_report, list);
-               rinfo->report_id = report->id;
-               break;
-
-       default:
-               return NULL;
-       }
-
-       return report_enum->report_id_hash[rinfo->report_id];
-}
-
-/*
- * Perform an exhaustive search of the report table for a usage, given its
- * type and usage id.
- */
-static struct hid_field *
-hiddev_lookup_usage(struct hid_device *hid, struct hiddev_usage_ref *uref)
-{
-       int i, j;
-       struct hid_report *report;
-       struct hid_report_enum *report_enum;
-       struct hid_field *field;
-
-       if (uref->report_type < HID_REPORT_TYPE_MIN ||
-           uref->report_type > HID_REPORT_TYPE_MAX)
-               return NULL;
-
-       report_enum = hid->report_enum +
-               (uref->report_type - HID_REPORT_TYPE_MIN);
-
-       list_for_each_entry(report, &report_enum->report_list, list) {
-               for (i = 0; i < report->maxfield; i++) {
-                       field = report->field[i];
-                       for (j = 0; j < field->maxusage; j++) {
-                               if (field->usage[j].hid == uref->usage_code) {
-                                       uref->report_id = report->id;
-                                       uref->field_index = i;
-                                       uref->usage_index = j;
-                                       return field;
-                               }
-                       }
-               }
-       }
-
-       return NULL;
-}
-
-static void hiddev_send_event(struct hid_device *hid,
-                             struct hiddev_usage_ref *uref)
-{
-       struct hiddev *hiddev = hid->hiddev;
-       struct hiddev_list *list;
-
-       list_for_each_entry(list, &hiddev->list, node) {
-               if (uref->field_index != HID_FIELD_INDEX_NONE ||
-                   (list->flags & HIDDEV_FLAG_REPORT) != 0) {
-                       list->buffer[list->head] = *uref;
-                       list->head = (list->head + 1) &
-                               (HIDDEV_BUFFER_SIZE - 1);
-                       kill_fasync(&list->fasync, SIGIO, POLL_IN);
-               }
-       }
-
-       wake_up_interruptible(&hiddev->wait);
-}
-
-/*
- * This is where hid.c calls into hiddev to pass an event that occurred over
- * the interrupt pipe
- */
-void hiddev_hid_event(struct hid_device *hid, struct hid_field *field,
-                     struct hid_usage *usage, __s32 value)
-{
-       unsigned type = field->report_type;
-       struct hiddev_usage_ref uref;
-
-       uref.report_type =
-         (type == HID_INPUT_REPORT) ? HID_REPORT_TYPE_INPUT :
-         ((type == HID_OUTPUT_REPORT) ? HID_REPORT_TYPE_OUTPUT :
-          ((type == HID_FEATURE_REPORT) ? HID_REPORT_TYPE_FEATURE : 0));
-       uref.report_id = field->report->id;
-       uref.field_index = field->index;
-       uref.usage_index = (usage - field->usage);
-       uref.usage_code = usage->hid;
-       uref.value = value;
-
-       hiddev_send_event(hid, &uref);
-}
-EXPORT_SYMBOL_GPL(hiddev_hid_event);
-
-void hiddev_report_event(struct hid_device *hid, struct hid_report *report)
-{
-       unsigned type = report->type;
-       struct hiddev_usage_ref uref;
-
-       memset(&uref, 0, sizeof(uref));
-       uref.report_type =
-         (type == HID_INPUT_REPORT) ? HID_REPORT_TYPE_INPUT :
-         ((type == HID_OUTPUT_REPORT) ? HID_REPORT_TYPE_OUTPUT :
-          ((type == HID_FEATURE_REPORT) ? HID_REPORT_TYPE_FEATURE : 0));
-       uref.report_id = report->id;
-       uref.field_index = HID_FIELD_INDEX_NONE;
-
-       hiddev_send_event(hid, &uref);
-}
-
-/*
- * fasync file op
- */
-static int hiddev_fasync(int fd, struct file *file, int on)
-{
-       int retval;
-       struct hiddev_list *list = file->private_data;
-
-       retval = fasync_helper(fd, file, on, &list->fasync);
-
-       return retval < 0 ? retval : 0;
-}
-
-
-/*
- * release file op
- */
-static int hiddev_release(struct inode * inode, struct file * file)
-{
-       struct hiddev_list *list = file->private_data;
-
-       hiddev_fasync(-1, file, 0);
-       list_del(&list->node);
-
-       if (!--list->hiddev->open) {
-               if (list->hiddev->exist)
-                       usbhid_close(list->hiddev->hid);
-               else
-                       kfree(list->hiddev);
-       }
-
-       kfree(list);
-
-       return 0;
-}
-
-/*
- * open file op
- */
-static int hiddev_open(struct inode *inode, struct file *file)
-{
-       struct hiddev_list *list;
-
-       int i = iminor(inode) - HIDDEV_MINOR_BASE;
-
-       if (i >= HIDDEV_MINORS || !hiddev_table[i])
-               return -ENODEV;
-
-       if (!(list = kzalloc(sizeof(struct hiddev_list), GFP_KERNEL)))
-               return -ENOMEM;
-
-       list->hiddev = hiddev_table[i];
-       list_add_tail(&list->node, &hiddev_table[i]->list);
-       file->private_data = list;
-
-       if (!list->hiddev->open++)
-               if (list->hiddev->exist)
-                       usbhid_open(hiddev_table[i]->hid);
-
-       return 0;
-}
-
-/*
- * "write" file op
- */
-static ssize_t hiddev_write(struct file * file, const char __user * buffer, size_t count, loff_t *ppos)
-{
-       return -EINVAL;
-}
-
-/*
- * "read" file op
- */
-static ssize_t hiddev_read(struct file * file, char __user * buffer, size_t count, loff_t *ppos)
-{
-       DECLARE_WAITQUEUE(wait, current);
-       struct hiddev_list *list = file->private_data;
-       int event_size;
-       int retval = 0;
-
-       event_size = ((list->flags & HIDDEV_FLAG_UREF) != 0) ?
-               sizeof(struct hiddev_usage_ref) : sizeof(struct hiddev_event);
-
-       if (count < event_size)
-               return 0;
-
-       while (retval == 0) {
-               if (list->head == list->tail) {
-                       add_wait_queue(&list->hiddev->wait, &wait);
-                       set_current_state(TASK_INTERRUPTIBLE);
-
-                       while (list->head == list->tail) {
-                               if (file->f_flags & O_NONBLOCK) {
-                                       retval = -EAGAIN;
-                                       break;
-                               }
-                               if (signal_pending(current)) {
-                                       retval = -ERESTARTSYS;
-                                       break;
-                               }
-                               if (!list->hiddev->exist) {
-                                       retval = -EIO;
-                                       break;
-                               }
-
-                               schedule();
-                               set_current_state(TASK_INTERRUPTIBLE);
-                       }
-
-                       set_current_state(TASK_RUNNING);
-                       remove_wait_queue(&list->hiddev->wait, &wait);
-               }
-
-               if (retval)
-                       return retval;
-
-
-               while (list->head != list->tail &&
-                      retval + event_size <= count) {
-                       if ((list->flags & HIDDEV_FLAG_UREF) == 0) {
-                               if (list->buffer[list->tail].field_index !=
-                                   HID_FIELD_INDEX_NONE) {
-                                       struct hiddev_event event;
-                                       event.hid = list->buffer[list->tail].usage_code;
-                                       event.value = list->buffer[list->tail].value;
-                                       if (copy_to_user(buffer + retval, &event, sizeof(struct hiddev_event)))
-                                               return -EFAULT;
-                                       retval += sizeof(struct hiddev_event);
-                               }
-                       } else {
-                               if (list->buffer[list->tail].field_index != HID_FIELD_INDEX_NONE ||
-                                   (list->flags & HIDDEV_FLAG_REPORT) != 0) {
-                                       if (copy_to_user(buffer + retval, list->buffer + list->tail, sizeof(struct hiddev_usage_ref)))
-                                               return -EFAULT;
-                                       retval += sizeof(struct hiddev_usage_ref);
-                               }
-                       }
-                       list->tail = (list->tail + 1) & (HIDDEV_BUFFER_SIZE - 1);
-               }
-
-       }
-
-       return retval;
-}
-
-/*
- * "poll" file op
- * No kernel lock - fine
- */
-static unsigned int hiddev_poll(struct file *file, poll_table *wait)
-{
-       struct hiddev_list *list = file->private_data;
-
-       poll_wait(file, &list->hiddev->wait, wait);
-       if (list->head != list->tail)
-               return POLLIN | POLLRDNORM;
-       if (!list->hiddev->exist)
-               return POLLERR | POLLHUP;
-       return 0;
-}
-
-/*
- * "ioctl" file op
- */
-static int hiddev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
-{
-       struct hiddev_list *list = file->private_data;
-       struct hiddev *hiddev = list->hiddev;
-       struct hid_device *hid = hiddev->hid;
-       struct usb_device *dev = hid_to_usb_dev(hid);
-       struct hiddev_collection_info cinfo;
-       struct hiddev_report_info rinfo;
-       struct hiddev_field_info finfo;
-       struct hiddev_usage_ref_multi *uref_multi = NULL;
-       struct hiddev_usage_ref *uref;
-       struct hiddev_devinfo dinfo;
-       struct hid_report *report;
-       struct hid_field *field;
-       struct usbhid_device *usbhid = hid->driver_data;
-       void __user *user_arg = (void __user *)arg;
-       int i;
-
-       if (!hiddev->exist)
-               return -EIO;
-
-       switch (cmd) {
-
-       case HIDIOCGVERSION:
-               return put_user(HID_VERSION, (int __user *)arg);
-
-       case HIDIOCAPPLICATION:
-               if (arg < 0 || arg >= hid->maxapplication)
-                       return -EINVAL;
-
-               for (i = 0; i < hid->maxcollection; i++)
-                       if (hid->collection[i].type ==
-                           HID_COLLECTION_APPLICATION && arg-- == 0)
-                               break;
-
-               if (i == hid->maxcollection)
-                       return -EINVAL;
-
-               return hid->collection[i].usage;
-
-       case HIDIOCGDEVINFO:
-               dinfo.bustype = BUS_USB;
-               dinfo.busnum = dev->bus->busnum;
-               dinfo.devnum = dev->devnum;
-               dinfo.ifnum = usbhid->ifnum;
-               dinfo.vendor = le16_to_cpu(dev->descriptor.idVendor);
-               dinfo.product = le16_to_cpu(dev->descriptor.idProduct);
-               dinfo.version = le16_to_cpu(dev->descriptor.bcdDevice);
-               dinfo.num_applications = hid->maxapplication;
-               if (copy_to_user(user_arg, &dinfo, sizeof(dinfo)))
-                       return -EFAULT;
-
-               return 0;
-
-       case HIDIOCGFLAG:
-               if (put_user(list->flags, (int __user *)arg))
-                       return -EFAULT;
-
-               return 0;
-
-       case HIDIOCSFLAG:
-               {
-                       int newflags;
-                       if (get_user(newflags, (int __user *)arg))
-                               return -EFAULT;
-
-                       if ((newflags & ~HIDDEV_FLAGS) != 0 ||
-                           ((newflags & HIDDEV_FLAG_REPORT) != 0 &&
-                            (newflags & HIDDEV_FLAG_UREF) == 0))
-                               return -EINVAL;
-
-                       list->flags = newflags;
-
-                       return 0;
-               }
-
-       case HIDIOCGSTRING:
-               {
-                       int idx, len;
-                       char *buf;
-
-                       if (get_user(idx, (int __user *)arg))
-                               return -EFAULT;
-
-                       if ((buf = kmalloc(HID_STRING_SIZE, GFP_KERNEL)) == NULL)
-                               return -ENOMEM;
-
-                       if ((len = usb_string(dev, idx, buf, HID_STRING_SIZE-1)) < 0) {
-                               kfree(buf);
-                               return -EINVAL;
-                       }
-
-                       if (copy_to_user(user_arg+sizeof(int), buf, len+1)) {
-                               kfree(buf);
-                               return -EFAULT;
-                       }
-
-                       kfree(buf);
-
-                       return len;
-               }
-
-       case HIDIOCINITREPORT:
-               usbhid_init_reports(hid);
-
-               return 0;
-
-       case HIDIOCGREPORT:
-               if (copy_from_user(&rinfo, user_arg, sizeof(rinfo)))
-                       return -EFAULT;
-
-               if (rinfo.report_type == HID_REPORT_TYPE_OUTPUT)
-                       return -EINVAL;
-
-               if ((report = hiddev_lookup_report(hid, &rinfo)) == NULL)
-                       return -EINVAL;
-
-               usbhid_submit_report(hid, report, USB_DIR_IN);
-               usbhid_wait_io(hid);
-
-               return 0;
-
-       case HIDIOCSREPORT:
-               if (copy_from_user(&rinfo, user_arg, sizeof(rinfo)))
-                       return -EFAULT;
-
-               if (rinfo.report_type == HID_REPORT_TYPE_INPUT)
-                       return -EINVAL;
-
-               if ((report = hiddev_lookup_report(hid, &rinfo)) == NULL)
-                       return -EINVAL;
-
-               usbhid_submit_report(hid, report, USB_DIR_OUT);
-               usbhid_wait_io(hid);
-
-               return 0;
-
-       case HIDIOCGREPORTINFO:
-               if (copy_from_user(&rinfo, user_arg, sizeof(rinfo)))
-                       return -EFAULT;
-
-               if ((report = hiddev_lookup_report(hid, &rinfo)) == NULL)
-                       return -EINVAL;
-
-               rinfo.num_fields = report->maxfield;
-
-               if (copy_to_user(user_arg, &rinfo, sizeof(rinfo)))
-                       return -EFAULT;
-
-               return 0;
-
-       case HIDIOCGFIELDINFO:
-               if (copy_from_user(&finfo, user_arg, sizeof(finfo)))
-                       return -EFAULT;
-               rinfo.report_type = finfo.report_type;
-               rinfo.report_id = finfo.report_id;
-               if ((report = hiddev_lookup_report(hid, &rinfo)) == NULL)
-                       return -EINVAL;
-
-               if (finfo.field_index >= report->maxfield)
-                       return -EINVAL;
-
-               field = report->field[finfo.field_index];
-               memset(&finfo, 0, sizeof(finfo));
-               finfo.report_type = rinfo.report_type;
-               finfo.report_id = rinfo.report_id;
-               finfo.field_index = field->report_count - 1;
-               finfo.maxusage = field->maxusage;
-               finfo.flags = field->flags;
-               finfo.physical = field->physical;
-               finfo.logical = field->logical;
-               finfo.application = field->application;
-               finfo.logical_minimum = field->logical_minimum;
-               finfo.logical_maximum = field->logical_maximum;
-               finfo.physical_minimum = field->physical_minimum;
-               finfo.physical_maximum = field->physical_maximum;
-               finfo.unit_exponent = field->unit_exponent;
-               finfo.unit = field->unit;
-
-               if (copy_to_user(user_arg, &finfo, sizeof(finfo)))
-                       return -EFAULT;
-
-               return 0;
-
-       case HIDIOCGUCODE:
-               uref_multi = kmalloc(sizeof(struct hiddev_usage_ref_multi), GFP_KERNEL);
-               if (!uref_multi)
-                       return -ENOMEM;
-               uref = &uref_multi->uref;
-               if (copy_from_user(uref, user_arg, sizeof(*uref)))
-                       goto fault;
-
-               rinfo.report_type = uref->report_type;
-               rinfo.report_id = uref->report_id;
-               if ((report = hiddev_lookup_report(hid, &rinfo)) == NULL)
-                       goto inval;
-
-               if (uref->field_index >= report->maxfield)
-                       goto inval;
-
-               field = report->field[uref->field_index];
-               if (uref->usage_index >= field->maxusage)
-                       goto inval;
-
-               uref->usage_code = field->usage[uref->usage_index].hid;
-
-               if (copy_to_user(user_arg, uref, sizeof(*uref)))
-                       goto fault;
-
-               kfree(uref_multi);
-               return 0;
-
-       case HIDIOCGUSAGE:
-       case HIDIOCSUSAGE:
-       case HIDIOCGUSAGES:
-       case HIDIOCSUSAGES:
-       case HIDIOCGCOLLECTIONINDEX:
-               uref_multi = kmalloc(sizeof(struct hiddev_usage_ref_multi), GFP_KERNEL);
-               if (!uref_multi)
-                       return -ENOMEM;
-               uref = &uref_multi->uref;
-               if (cmd == HIDIOCGUSAGES || cmd == HIDIOCSUSAGES) {
-                       if (copy_from_user(uref_multi, user_arg,
-                                          sizeof(*uref_multi)))
-                               goto fault;
-               } else {
-                       if (copy_from_user(uref, user_arg, sizeof(*uref)))
-                               goto fault;
-               }
-
-               if (cmd != HIDIOCGUSAGE &&
-                   cmd != HIDIOCGUSAGES &&
-                   uref->report_type == HID_REPORT_TYPE_INPUT)
-                       goto inval;
-
-               if (uref->report_id == HID_REPORT_ID_UNKNOWN) {
-                       field = hiddev_lookup_usage(hid, uref);
-                       if (field == NULL)
-                               goto inval;
-               } else {
-                       rinfo.report_type = uref->report_type;
-                       rinfo.report_id = uref->report_id;
-                       if ((report = hiddev_lookup_report(hid, &rinfo)) == NULL)
-                               goto inval;
-
-                       if (uref->field_index >= report->maxfield)
-                               goto inval;
-
-                       field = report->field[uref->field_index];
-
-                       if (cmd == HIDIOCGCOLLECTIONINDEX) {
-                               if (uref->usage_index >= field->maxusage)
-                                       goto inval;
-                       } else if (uref->usage_index >= field->report_count)
-                               goto inval;
-
-                       else if ((cmd == HIDIOCGUSAGES || cmd == HIDIOCSUSAGES) &&
-                                (uref_multi->num_values > HID_MAX_MULTI_USAGES ||
-                                 uref->usage_index + uref_multi->num_values > field->report_count))
-                               goto inval;
-                       }
-
-               switch (cmd) {
-                       case HIDIOCGUSAGE:
-                               uref->value = field->value[uref->usage_index];
-                               if (copy_to_user(user_arg, uref, sizeof(*uref)))
-                                       goto fault;
-                               goto goodreturn;
-
-                       case HIDIOCSUSAGE:
-                               field->value[uref->usage_index] = uref->value;
-                               goto goodreturn;
-
-                       case HIDIOCGCOLLECTIONINDEX:
-                               kfree(uref_multi);
-                               return field->usage[uref->usage_index].collection_index;
-                       case HIDIOCGUSAGES:
-                               for (i = 0; i < uref_multi->num_values; i++)
-                                       uref_multi->values[i] =
-                                           field->value[uref->usage_index + i];
-                               if (copy_to_user(user_arg, uref_multi,
-                                                sizeof(*uref_multi)))
-                                       goto fault;
-                               goto goodreturn;
-                       case HIDIOCSUSAGES:
-                               for (i = 0; i < uref_multi->num_values; i++)
-                                       field->value[uref->usage_index + i] =
-                                           uref_multi->values[i];
-                               goto goodreturn;
-               }
-
-goodreturn:
-               kfree(uref_multi);
-               return 0;
-fault:
-               kfree(uref_multi);
-               return -EFAULT;
-inval:
-               kfree(uref_multi);
-               return -EINVAL;
-
-       case HIDIOCGCOLLECTIONINFO:
-               if (copy_from_user(&cinfo, user_arg, sizeof(cinfo)))
-                       return -EFAULT;
-
-               if (cinfo.index >= hid->maxcollection)
-                       return -EINVAL;
-
-               cinfo.type = hid->collection[cinfo.index].type;
-               cinfo.usage = hid->collection[cinfo.index].usage;
-               cinfo.level = hid->collection[cinfo.index].level;
-
-               if (copy_to_user(user_arg, &cinfo, sizeof(cinfo)))
-                       return -EFAULT;
-               return 0;
-
-       default:
-
-               if (_IOC_TYPE(cmd) != 'H' || _IOC_DIR(cmd) != _IOC_READ)
-                       return -EINVAL;
-
-               if (_IOC_NR(cmd) == _IOC_NR(HIDIOCGNAME(0))) {
-                       int len;
-                       if (!hid->name)
-                               return 0;
-                       len = strlen(hid->name) + 1;
-                       if (len > _IOC_SIZE(cmd))
-                                len = _IOC_SIZE(cmd);
-                       return copy_to_user(user_arg, hid->name, len) ?
-                               -EFAULT : len;
-               }
-
-               if (_IOC_NR(cmd) == _IOC_NR(HIDIOCGPHYS(0))) {
-                       int len;
-                       if (!hid->phys)
-                               return 0;
-                       len = strlen(hid->phys) + 1;
-                       if (len > _IOC_SIZE(cmd))
-                               len = _IOC_SIZE(cmd);
-                       return copy_to_user(user_arg, hid->phys, len) ?
-                               -EFAULT : len;
-               }
-       }
-       return -EINVAL;
-}
-
-static const struct file_operations hiddev_fops = {
-       .owner =        THIS_MODULE,
-       .read =         hiddev_read,
-       .write =        hiddev_write,
-       .poll =         hiddev_poll,
-       .open =         hiddev_open,
-       .release =      hiddev_release,
-       .ioctl =        hiddev_ioctl,
-       .fasync =       hiddev_fasync,
-};
-
-static struct usb_class_driver hiddev_class = {
-       .name =         "hiddev%d",
-       .fops =         &hiddev_fops,
-       .minor_base =   HIDDEV_MINOR_BASE,
-};
-
-/*
- * This is where hid.c calls us to connect a hid device to the hiddev driver
- */
-int hiddev_connect(struct hid_device *hid)
-{
-       struct hiddev *hiddev;
-       struct usbhid_device *usbhid = hid->driver_data;
-       int i;
-       int retval;
-
-       for (i = 0; i < hid->maxcollection; i++)
-               if (hid->collection[i].type ==
-                   HID_COLLECTION_APPLICATION &&
-                   !IS_INPUT_APPLICATION(hid->collection[i].usage))
-                       break;
-
-       if (i == hid->maxcollection && (hid->quirks & HID_QUIRK_HIDDEV) == 0)
-               return -1;
-
-       if (!(hiddev = kzalloc(sizeof(struct hiddev), GFP_KERNEL)))
-               return -1;
-
-       retval = usb_register_dev(usbhid->intf, &hiddev_class);
-       if (retval) {
-               err("Not able to get a minor for this device.");
-               kfree(hiddev);
-               return -1;
-       }
-
-       init_waitqueue_head(&hiddev->wait);
-       INIT_LIST_HEAD(&hiddev->list);
-       hiddev->hid = hid;
-       hiddev->exist = 1;
-
-       hid->minor = usbhid->intf->minor;
-       hid->hiddev = hiddev;
-
-       hiddev_table[usbhid->intf->minor - HIDDEV_MINOR_BASE] = hiddev;
-
-       return 0;
-}
-
-/*
- * This is where hid.c calls us to disconnect a hiddev device from the
- * corresponding hid device (usually because the usb device has disconnected)
- */
-static struct usb_class_driver hiddev_class;
-void hiddev_disconnect(struct hid_device *hid)
-{
-       struct hiddev *hiddev = hid->hiddev;
-       struct usbhid_device *usbhid = hid->driver_data;
-
-       hiddev->exist = 0;
-
-       hiddev_table[hiddev->hid->minor - HIDDEV_MINOR_BASE] = NULL;
-       usb_deregister_dev(usbhid->intf, &hiddev_class);
-
-       if (hiddev->open) {
-               usbhid_close(hiddev->hid);
-               wake_up_interruptible(&hiddev->wait);
-       } else {
-               kfree(hiddev);
-       }
-}
-
-/* Currently this driver is a USB driver.  It's not a conventional one in
- * the sense that it doesn't probe at the USB level.  Instead it waits to
- * be connected by HID through the hiddev_connect / hiddev_disconnect
- * routines.  The reason to register as a USB device is to gain part of the
- * minor number space from the USB major.
- *
- * In theory, should the HID code be generalized to more than one physical
- * medium (say, IEEE 1384), this driver will probably need to register its
- * own major number, and in doing so, no longer need to register with USB.
- * At that point the probe routine and hiddev_driver struct below will no
- * longer be useful.
- */
-
-
-/* We never attach in this manner, and rely on HID to connect us.  This
- * is why there is no disconnect routine defined in the usb_driver either.
- */
-static int hiddev_usbd_probe(struct usb_interface *intf,
-                            const struct usb_device_id *hiddev_info)
-{
-       return -ENODEV;
-}
-
-
-static /* const */ struct usb_driver hiddev_driver = {
-       .name =         "hiddev",
-       .probe =        hiddev_usbd_probe,
-};
-
-int __init hiddev_init(void)
-{
-       return usb_register(&hiddev_driver);
-}
-
-void hiddev_exit(void)
-{
-       usb_deregister(&hiddev_driver);
-}
diff --git a/drivers/usb/input/usbhid.h b/drivers/usb/input/usbhid.h
deleted file mode 100644 (file)
index 0023f96..0000000
+++ /dev/null
@@ -1,87 +0,0 @@
-#ifndef __USBHID_H
-#define __USBHID_H
-
-/*
- *  Copyright (c) 1999 Andreas Gal
- *  Copyright (c) 2000-2001 Vojtech Pavlik
- *  Copyright (c) 2006 Jiri Kosina
- */
-
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-#include <linux/types.h>
-#include <linux/slab.h>
-#include <linux/list.h>
-#include <linux/timer.h>
-#include <linux/workqueue.h>
-#include <linux/input.h>
-
-/*  API provided by hid-core.c for USB HID drivers */
-int usbhid_wait_io(struct hid_device* hid);
-void usbhid_close(struct hid_device *hid);
-int usbhid_open(struct hid_device *hid);
-void usbhid_init_reports(struct hid_device *hid);
-void usbhid_submit_report(struct hid_device *hid, struct hid_report *report, unsigned char dir);
-
-/*
- * USB-specific HID struct, to be pointed to
- * from struct hid_device->driver_data
- */
-
-struct usbhid_device {
-       struct hid_device *hid;                                         /* pointer to corresponding HID dev */
-
-       struct usb_interface *intf;                                     /* USB interface */
-       int ifnum;                                                      /* USB interface number */
-
-       unsigned int bufsize;                                           /* URB buffer size */
-
-       struct urb *urbin;                                              /* Input URB */
-       char *inbuf;                                                    /* Input buffer */
-       dma_addr_t inbuf_dma;                                           /* Input buffer dma */
-       spinlock_t inlock;                                              /* Input fifo spinlock */
-
-       struct urb *urbctrl;                                            /* Control URB */
-       struct usb_ctrlrequest *cr;                                     /* Control request struct */
-       dma_addr_t cr_dma;                                              /* Control request struct dma */
-       struct hid_control_fifo ctrl[HID_CONTROL_FIFO_SIZE];            /* Control fifo */
-       unsigned char ctrlhead, ctrltail;                               /* Control fifo head & tail */
-       char *ctrlbuf;                                                  /* Control buffer */
-       dma_addr_t ctrlbuf_dma;                                         /* Control buffer dma */
-       spinlock_t ctrllock;                                            /* Control fifo spinlock */
-
-       struct urb *urbout;                                             /* Output URB */
-       struct hid_report *out[HID_CONTROL_FIFO_SIZE];                  /* Output pipe fifo */
-       unsigned char outhead, outtail;                                 /* Output pipe fifo head & tail */
-       char *outbuf;                                                   /* Output buffer */
-       dma_addr_t outbuf_dma;                                          /* Output buffer dma */
-       spinlock_t outlock;                                             /* Output fifo spinlock */
-
-       unsigned long iofl;                                             /* I/O flags (CTRL_RUNNING, OUT_RUNNING) */
-       struct timer_list io_retry;                                     /* Retry timer */
-       unsigned long stop_retry;                                       /* Time to give up, in jiffies */
-       unsigned int retry_delay;                                       /* Delay length in ms */
-       struct work_struct reset_work;                                  /* Task context for resets */
-
-};
-
-#define        hid_to_usb_dev(hid_dev) \
-       container_of(hid_dev->dev->parent, struct usb_device, dev)
-
-#endif
-
diff --git a/drivers/usb/input/usbkbd.c b/drivers/usb/input/usbkbd.c
deleted file mode 100644 (file)
index 3749f4a..0000000
+++ /dev/null
@@ -1,362 +0,0 @@
-/*
- * $Id: usbkbd.c,v 1.27 2001/12/27 10:37:41 vojtech Exp $
- *
- *  Copyright (c) 1999-2001 Vojtech Pavlik
- *
- *  USB HIDBP Keyboard support
- */
-
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Should you need to contact me, the author, you can do so either by
- * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
- * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
- */
-
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/usb/input.h>
-#include <linux/hid.h>
-
-/*
- * Version Information
- */
-#define DRIVER_VERSION ""
-#define DRIVER_AUTHOR "Vojtech Pavlik <vojtech@ucw.cz>"
-#define DRIVER_DESC "USB HID Boot Protocol keyboard driver"
-#define DRIVER_LICENSE "GPL"
-
-MODULE_AUTHOR(DRIVER_AUTHOR);
-MODULE_DESCRIPTION(DRIVER_DESC);
-MODULE_LICENSE(DRIVER_LICENSE);
-
-static unsigned char usb_kbd_keycode[256] = {
-         0,  0,  0,  0, 30, 48, 46, 32, 18, 33, 34, 35, 23, 36, 37, 38,
-        50, 49, 24, 25, 16, 19, 31, 20, 22, 47, 17, 45, 21, 44,  2,  3,
-         4,  5,  6,  7,  8,  9, 10, 11, 28,  1, 14, 15, 57, 12, 13, 26,
-        27, 43, 43, 39, 40, 41, 51, 52, 53, 58, 59, 60, 61, 62, 63, 64,
-        65, 66, 67, 68, 87, 88, 99, 70,119,110,102,104,111,107,109,106,
-       105,108,103, 69, 98, 55, 74, 78, 96, 79, 80, 81, 75, 76, 77, 71,
-        72, 73, 82, 83, 86,127,116,117,183,184,185,186,187,188,189,190,
-       191,192,193,194,134,138,130,132,128,129,131,137,133,135,136,113,
-       115,114,  0,  0,  0,121,  0, 89, 93,124, 92, 94, 95,  0,  0,  0,
-       122,123, 90, 91, 85,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-         0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-         0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-         0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-         0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-        29, 42, 56,125, 97, 54,100,126,164,166,165,163,161,115,114,113,
-       150,158,159,128,136,177,178,176,142,152,173,140
-};
-
-struct usb_kbd {
-       struct input_dev *dev;
-       struct usb_device *usbdev;
-       unsigned char old[8];
-       struct urb *irq, *led;
-       unsigned char newleds;
-       char name[128];
-       char phys[64];
-
-       unsigned char *new;
-       struct usb_ctrlrequest *cr;
-       unsigned char *leds;
-       dma_addr_t cr_dma;
-       dma_addr_t new_dma;
-       dma_addr_t leds_dma;
-};
-
-static void usb_kbd_irq(struct urb *urb)
-{
-       struct usb_kbd *kbd = urb->context;
-       int i;
-
-       switch (urb->status) {
-       case 0:                 /* success */
-               break;
-       case -ECONNRESET:       /* unlink */
-       case -ENOENT:
-       case -ESHUTDOWN:
-               return;
-       /* -EPIPE:  should clear the halt */
-       default:                /* error */
-               goto resubmit;
-       }
-
-       for (i = 0; i < 8; i++)
-               input_report_key(kbd->dev, usb_kbd_keycode[i + 224], (kbd->new[0] >> i) & 1);
-
-       for (i = 2; i < 8; i++) {
-
-               if (kbd->old[i] > 3 && memscan(kbd->new + 2, kbd->old[i], 6) == kbd->new + 8) {
-                       if (usb_kbd_keycode[kbd->old[i]])
-                               input_report_key(kbd->dev, usb_kbd_keycode[kbd->old[i]], 0);
-                       else
-                               info("Unknown key (scancode %#x) released.", kbd->old[i]);
-               }
-
-               if (kbd->new[i] > 3 && memscan(kbd->old + 2, kbd->new[i], 6) == kbd->old + 8) {
-                       if (usb_kbd_keycode[kbd->new[i]])
-                               input_report_key(kbd->dev, usb_kbd_keycode[kbd->new[i]], 1);
-                       else
-                               info("Unknown key (scancode %#x) pressed.", kbd->new[i]);
-               }
-       }
-
-       input_sync(kbd->dev);
-
-       memcpy(kbd->old, kbd->new, 8);
-
-resubmit:
-       i = usb_submit_urb (urb, GFP_ATOMIC);
-       if (i)
-               err ("can't resubmit intr, %s-%s/input0, status %d",
-                               kbd->usbdev->bus->bus_name,
-                               kbd->usbdev->devpath, i);
-}
-
-static int usb_kbd_event(struct input_dev *dev, unsigned int type,
-                        unsigned int code, int value)
-{
-       struct usb_kbd *kbd = dev->private;
-
-       if (type != EV_LED)
-               return -1;
-
-
-       kbd->newleds = (!!test_bit(LED_KANA,    dev->led) << 3) | (!!test_bit(LED_COMPOSE, dev->led) << 3) |
-                      (!!test_bit(LED_SCROLLL, dev->led) << 2) | (!!test_bit(LED_CAPSL,   dev->led) << 1) |
-                      (!!test_bit(LED_NUML,    dev->led));
-
-       if (kbd->led->status == -EINPROGRESS)
-               return 0;
-
-       if (*(kbd->leds) == kbd->newleds)
-               return 0;
-
-       *(kbd->leds) = kbd->newleds;
-       kbd->led->dev = kbd->usbdev;
-       if (usb_submit_urb(kbd->led, GFP_ATOMIC))
-               err("usb_submit_urb(leds) failed");
-
-       return 0;
-}
-
-static void usb_kbd_led(struct urb *urb)
-{
-       struct usb_kbd *kbd = urb->context;
-
-       if (urb->status)
-               warn("led urb status %d received", urb->status);
-
-       if (*(kbd->leds) == kbd->newleds)
-               return;
-
-       *(kbd->leds) = kbd->newleds;
-       kbd->led->dev = kbd->usbdev;
-       if (usb_submit_urb(kbd->led, GFP_ATOMIC))
-               err("usb_submit_urb(leds) failed");
-}
-
-static int usb_kbd_open(struct input_dev *dev)
-{
-       struct usb_kbd *kbd = dev->private;
-
-       kbd->irq->dev = kbd->usbdev;
-       if (usb_submit_urb(kbd->irq, GFP_KERNEL))
-               return -EIO;
-
-       return 0;
-}
-
-static void usb_kbd_close(struct input_dev *dev)
-{
-       struct usb_kbd *kbd = dev->private;
-
-       usb_kill_urb(kbd->irq);
-}
-
-static int usb_kbd_alloc_mem(struct usb_device *dev, struct usb_kbd *kbd)
-{
-       if (!(kbd->irq = usb_alloc_urb(0, GFP_KERNEL)))
-               return -1;
-       if (!(kbd->led = usb_alloc_urb(0, GFP_KERNEL)))
-               return -1;
-       if (!(kbd->new = usb_buffer_alloc(dev, 8, GFP_ATOMIC, &kbd->new_dma)))
-               return -1;
-       if (!(kbd->cr = usb_buffer_alloc(dev, sizeof(struct usb_ctrlrequest), GFP_ATOMIC, &kbd->cr_dma)))
-               return -1;
-       if (!(kbd->leds = usb_buffer_alloc(dev, 1, GFP_ATOMIC, &kbd->leds_dma)))
-               return -1;
-
-       return 0;
-}
-
-static void usb_kbd_free_mem(struct usb_device *dev, struct usb_kbd *kbd)
-{
-       usb_free_urb(kbd->irq);
-       usb_free_urb(kbd->led);
-       if (kbd->new)
-               usb_buffer_free(dev, 8, kbd->new, kbd->new_dma);
-       if (kbd->cr)
-               usb_buffer_free(dev, sizeof(struct usb_ctrlrequest), kbd->cr, kbd->cr_dma);
-       if (kbd->leds)
-               usb_buffer_free(dev, 1, kbd->leds, kbd->leds_dma);
-}
-
-static int usb_kbd_probe(struct usb_interface *iface,
-                        const struct usb_device_id *id)
-{
-       struct usb_device *dev = interface_to_usbdev(iface);
-       struct usb_host_interface *interface;
-       struct usb_endpoint_descriptor *endpoint;
-       struct usb_kbd *kbd;
-       struct input_dev *input_dev;
-       int i, pipe, maxp;
-
-       interface = iface->cur_altsetting;
-
-       if (interface->desc.bNumEndpoints != 1)
-               return -ENODEV;
-
-       endpoint = &interface->endpoint[0].desc;
-       if (!usb_endpoint_is_int_in(endpoint))
-               return -ENODEV;
-
-       pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);
-       maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe));
-
-       kbd = kzalloc(sizeof(struct usb_kbd), GFP_KERNEL);
-       input_dev = input_allocate_device();
-       if (!kbd || !input_dev)
-               goto fail1;
-
-       if (usb_kbd_alloc_mem(dev, kbd))
-               goto fail2;
-
-       kbd->usbdev = dev;
-       kbd->dev = input_dev;
-
-       if (dev->manufacturer)
-               strlcpy(kbd->name, dev->manufacturer, sizeof(kbd->name));
-
-       if (dev->product) {
-               if (dev->manufacturer)
-                       strlcat(kbd->name, " ", sizeof(kbd->name));
-               strlcat(kbd->name, dev->product, sizeof(kbd->name));
-       }
-
-       if (!strlen(kbd->name))
-               snprintf(kbd->name, sizeof(kbd->name),
-                        "USB HIDBP Keyboard %04x:%04x",
-                        le16_to_cpu(dev->descriptor.idVendor),
-                        le16_to_cpu(dev->descriptor.idProduct));
-
-       usb_make_path(dev, kbd->phys, sizeof(kbd->phys));
-       strlcpy(kbd->phys, "/input0", sizeof(kbd->phys));
-
-       input_dev->name = kbd->name;
-       input_dev->phys = kbd->phys;
-       usb_to_input_id(dev, &input_dev->id);
-       input_dev->cdev.dev = &iface->dev;
-       input_dev->private = kbd;
-
-       input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_LED) | BIT(EV_REP);
-       input_dev->ledbit[0] = BIT(LED_NUML) | BIT(LED_CAPSL) | BIT(LED_SCROLLL) | BIT(LED_COMPOSE) | BIT(LED_KANA);
-
-       for (i = 0; i < 255; i++)
-               set_bit(usb_kbd_keycode[i], input_dev->keybit);
-       clear_bit(0, input_dev->keybit);
-
-       input_dev->event = usb_kbd_event;
-       input_dev->open = usb_kbd_open;
-       input_dev->close = usb_kbd_close;
-
-       usb_fill_int_urb(kbd->irq, dev, pipe,
-                        kbd->new, (maxp > 8 ? 8 : maxp),
-                        usb_kbd_irq, kbd, endpoint->bInterval);
-       kbd->irq->transfer_dma = kbd->new_dma;
-       kbd->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
-
-       kbd->cr->bRequestType = USB_TYPE_CLASS | USB_RECIP_INTERFACE;
-       kbd->cr->bRequest = 0x09;
-       kbd->cr->wValue = cpu_to_le16(0x200);
-       kbd->cr->wIndex = cpu_to_le16(interface->desc.bInterfaceNumber);
-       kbd->cr->wLength = cpu_to_le16(1);
-
-       usb_fill_control_urb(kbd->led, dev, usb_sndctrlpipe(dev, 0),
-                            (void *) kbd->cr, kbd->leds, 1,
-                            usb_kbd_led, kbd);
-       kbd->led->setup_dma = kbd->cr_dma;
-       kbd->led->transfer_dma = kbd->leds_dma;
-       kbd->led->transfer_flags |= (URB_NO_TRANSFER_DMA_MAP | URB_NO_SETUP_DMA_MAP);
-
-       input_register_device(kbd->dev);
-
-       usb_set_intfdata(iface, kbd);
-       return 0;
-
-fail2: usb_kbd_free_mem(dev, kbd);
-fail1: input_free_device(input_dev);
-       kfree(kbd);
-       return -ENOMEM;
-}
-
-static void usb_kbd_disconnect(struct usb_interface *intf)
-{
-       struct usb_kbd *kbd = usb_get_intfdata (intf);
-
-       usb_set_intfdata(intf, NULL);
-       if (kbd) {
-               usb_kill_urb(kbd->irq);
-               input_unregister_device(kbd->dev);
-               usb_kbd_free_mem(interface_to_usbdev(intf), kbd);
-               kfree(kbd);
-       }
-}
-
-static struct usb_device_id usb_kbd_id_table [] = {
-       { USB_INTERFACE_INFO(USB_INTERFACE_CLASS_HID, USB_INTERFACE_SUBCLASS_BOOT,
-               USB_INTERFACE_PROTOCOL_KEYBOARD) },
-       { }                                             /* Terminating entry */
-};
-
-MODULE_DEVICE_TABLE (usb, usb_kbd_id_table);
-
-static struct usb_driver usb_kbd_driver = {
-       .name =         "usbkbd",
-       .probe =        usb_kbd_probe,
-       .disconnect =   usb_kbd_disconnect,
-       .id_table =     usb_kbd_id_table,
-};
-
-static int __init usb_kbd_init(void)
-{
-       int result = usb_register(&usb_kbd_driver);
-       if (result == 0)
-               info(DRIVER_VERSION ":" DRIVER_DESC);
-       return result;
-}
-
-static void __exit usb_kbd_exit(void)
-{
-       usb_deregister(&usb_kbd_driver);
-}
-
-module_init(usb_kbd_init);
-module_exit(usb_kbd_exit);
diff --git a/drivers/usb/input/usbmouse.c b/drivers/usb/input/usbmouse.c
deleted file mode 100644 (file)
index 692fd60..0000000
+++ /dev/null
@@ -1,245 +0,0 @@
-/*
- * $Id: usbmouse.c,v 1.15 2001/12/27 10:37:41 vojtech Exp $
- *
- *  Copyright (c) 1999-2001 Vojtech Pavlik
- *
- *  USB HIDBP Mouse support
- */
-
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Should you need to contact me, the author, you can do so either by
- * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
- * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
- */
-
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/usb/input.h>
-#include <linux/hid.h>
-
-/*
- * Version Information
- */
-#define DRIVER_VERSION "v1.6"
-#define DRIVER_AUTHOR "Vojtech Pavlik <vojtech@ucw.cz>"
-#define DRIVER_DESC "USB HID Boot Protocol mouse driver"
-#define DRIVER_LICENSE "GPL"
-
-MODULE_AUTHOR(DRIVER_AUTHOR);
-MODULE_DESCRIPTION(DRIVER_DESC);
-MODULE_LICENSE(DRIVER_LICENSE);
-
-struct usb_mouse {
-       char name[128];
-       char phys[64];
-       struct usb_device *usbdev;
-       struct input_dev *dev;
-       struct urb *irq;
-
-       signed char *data;
-       dma_addr_t data_dma;
-};
-
-static void usb_mouse_irq(struct urb *urb)
-{
-       struct usb_mouse *mouse = urb->context;
-       signed char *data = mouse->data;
-       struct input_dev *dev = mouse->dev;
-       int status;
-
-       switch (urb->status) {
-       case 0:                 /* success */
-               break;
-       case -ECONNRESET:       /* unlink */
-       case -ENOENT:
-       case -ESHUTDOWN:
-               return;
-       /* -EPIPE:  should clear the halt */
-       default:                /* error */
-               goto resubmit;
-       }
-
-       input_report_key(dev, BTN_LEFT,   data[0] & 0x01);
-       input_report_key(dev, BTN_RIGHT,  data[0] & 0x02);
-       input_report_key(dev, BTN_MIDDLE, data[0] & 0x04);
-       input_report_key(dev, BTN_SIDE,   data[0] & 0x08);
-       input_report_key(dev, BTN_EXTRA,  data[0] & 0x10);
-
-       input_report_rel(dev, REL_X,     data[1]);
-       input_report_rel(dev, REL_Y,     data[2]);
-       input_report_rel(dev, REL_WHEEL, data[3]);
-
-       input_sync(dev);
-resubmit:
-       status = usb_submit_urb (urb, GFP_ATOMIC);
-       if (status)
-               err ("can't resubmit intr, %s-%s/input0, status %d",
-                               mouse->usbdev->bus->bus_name,
-                               mouse->usbdev->devpath, status);
-}
-
-static int usb_mouse_open(struct input_dev *dev)
-{
-       struct usb_mouse *mouse = dev->private;
-
-       mouse->irq->dev = mouse->usbdev;
-       if (usb_submit_urb(mouse->irq, GFP_KERNEL))
-               return -EIO;
-
-       return 0;
-}
-
-static void usb_mouse_close(struct input_dev *dev)
-{
-       struct usb_mouse *mouse = dev->private;
-
-       usb_kill_urb(mouse->irq);
-}
-
-static int usb_mouse_probe(struct usb_interface *intf, const struct usb_device_id *id)
-{
-       struct usb_device *dev = interface_to_usbdev(intf);
-       struct usb_host_interface *interface;
-       struct usb_endpoint_descriptor *endpoint;
-       struct usb_mouse *mouse;
-       struct input_dev *input_dev;
-       int pipe, maxp;
-
-       interface = intf->cur_altsetting;
-
-       if (interface->desc.bNumEndpoints != 1)
-               return -ENODEV;
-
-       endpoint = &interface->endpoint[0].desc;
-       if (!usb_endpoint_is_int_in(endpoint))
-               return -ENODEV;
-
-       pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);
-       maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe));
-
-       mouse = kzalloc(sizeof(struct usb_mouse), GFP_KERNEL);
-       input_dev = input_allocate_device();
-       if (!mouse || !input_dev)
-               goto fail1;
-
-       mouse->data = usb_buffer_alloc(dev, 8, GFP_ATOMIC, &mouse->data_dma);
-       if (!mouse->data)
-               goto fail1;
-
-       mouse->irq = usb_alloc_urb(0, GFP_KERNEL);
-       if (!mouse->irq)
-               goto fail2;
-
-       mouse->usbdev = dev;
-       mouse->dev = input_dev;
-
-       if (dev->manufacturer)
-               strlcpy(mouse->name, dev->manufacturer, sizeof(mouse->name));
-
-       if (dev->product) {
-               if (dev->manufacturer)
-                       strlcat(mouse->name, " ", sizeof(mouse->name));
-               strlcat(mouse->name, dev->product, sizeof(mouse->name));
-       }
-
-       if (!strlen(mouse->name))
-               snprintf(mouse->name, sizeof(mouse->name),
-                        "USB HIDBP Mouse %04x:%04x",
-                        le16_to_cpu(dev->descriptor.idVendor),
-                        le16_to_cpu(dev->descriptor.idProduct));
-
-       usb_make_path(dev, mouse->phys, sizeof(mouse->phys));
-       strlcat(mouse->phys, "/input0", sizeof(mouse->phys));
-
-       input_dev->name = mouse->name;
-       input_dev->phys = mouse->phys;
-       usb_to_input_id(dev, &input_dev->id);
-       input_dev->cdev.dev = &intf->dev;
-
-       input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REL);
-       input_dev->keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_RIGHT) | BIT(BTN_MIDDLE);
-       input_dev->relbit[0] = BIT(REL_X) | BIT(REL_Y);
-       input_dev->keybit[LONG(BTN_MOUSE)] |= BIT(BTN_SIDE) | BIT(BTN_EXTRA);
-       input_dev->relbit[0] |= BIT(REL_WHEEL);
-
-       input_dev->private = mouse;
-       input_dev->open = usb_mouse_open;
-       input_dev->close = usb_mouse_close;
-
-       usb_fill_int_urb(mouse->irq, dev, pipe, mouse->data,
-                        (maxp > 8 ? 8 : maxp),
-                        usb_mouse_irq, mouse, endpoint->bInterval);
-       mouse->irq->transfer_dma = mouse->data_dma;
-       mouse->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
-
-       input_register_device(mouse->dev);
-
-       usb_set_intfdata(intf, mouse);
-       return 0;
-
-fail2: usb_buffer_free(dev, 8, mouse->data, mouse->data_dma);
-fail1: input_free_device(input_dev);
-       kfree(mouse);
-       return -ENOMEM;
-}
-
-static void usb_mouse_disconnect(struct usb_interface *intf)
-{
-       struct usb_mouse *mouse = usb_get_intfdata (intf);
-
-       usb_set_intfdata(intf, NULL);
-       if (mouse) {
-               usb_kill_urb(mouse->irq);
-               input_unregister_device(mouse->dev);
-               usb_free_urb(mouse->irq);
-               usb_buffer_free(interface_to_usbdev(intf), 8, mouse->data, mouse->data_dma);
-               kfree(mouse);
-       }
-}
-
-static struct usb_device_id usb_mouse_id_table [] = {
-       { USB_INTERFACE_INFO(USB_INTERFACE_CLASS_HID, USB_INTERFACE_SUBCLASS_BOOT,
-               USB_INTERFACE_PROTOCOL_MOUSE) },
-       { }     /* Terminating entry */
-};
-
-MODULE_DEVICE_TABLE (usb, usb_mouse_id_table);
-
-static struct usb_driver usb_mouse_driver = {
-       .name           = "usbmouse",
-       .probe          = usb_mouse_probe,
-       .disconnect     = usb_mouse_disconnect,
-       .id_table       = usb_mouse_id_table,
-};
-
-static int __init usb_mouse_init(void)
-{
-       int retval = usb_register(&usb_mouse_driver);
-       if (retval == 0)
-               info(DRIVER_VERSION ":" DRIVER_DESC);
-       return retval;
-}
-
-static void __exit usb_mouse_exit(void)
-{
-       usb_deregister(&usb_mouse_driver);
-}
-
-module_init(usb_mouse_init);
-module_exit(usb_mouse_exit);