[PATCH] fallout from hcd-core patch
[safe/jmp/linux-2.6] / drivers / usb / input / hid-core.c
index 45f3130..3305fb6 100644 (file)
@@ -66,9 +66,8 @@ static struct hid_report *hid_register_report(struct hid_device *device, unsigne
        if (report_enum->report_id_hash[id])
                return report_enum->report_id_hash[id];
 
-       if (!(report = kmalloc(sizeof(struct hid_report), GFP_KERNEL)))
+       if (!(report = kzalloc(sizeof(struct hid_report), GFP_KERNEL)))
                return NULL;
-       memset(report, 0, sizeof(struct hid_report));
 
        if (id != 0)
                report_enum->numbered = 1;
@@ -97,12 +96,9 @@ static struct hid_field *hid_register_field(struct hid_report *report, unsigned
                return NULL;
        }
 
-       if (!(field = kmalloc(sizeof(struct hid_field) + usages * sizeof(struct hid_usage)
+       if (!(field = kzalloc(sizeof(struct hid_field) + usages * sizeof(struct hid_usage)
                + values * sizeof(unsigned), GFP_KERNEL))) return NULL;
 
-       memset(field, 0, sizeof(struct hid_field) + usages * sizeof(struct hid_usage)
-               + values * sizeof(unsigned));
-
        field->index = report->maxfield++;
        report->field[field->index] = field;
        field->usage = (struct hid_usage *)(field + 1);
@@ -651,17 +647,14 @@ static struct hid_device *hid_parse_report(__u8 *start, unsigned size)
                hid_parser_reserved
        };
 
-       if (!(device = kmalloc(sizeof(struct hid_device), GFP_KERNEL)))
+       if (!(device = kzalloc(sizeof(struct hid_device), GFP_KERNEL)))
                return NULL;
-       memset(device, 0, sizeof(struct hid_device));
 
-       if (!(device->collection = kmalloc(sizeof(struct hid_collection) *
+       if (!(device->collection = kzalloc(sizeof(struct hid_collection) *
                                   HID_DEFAULT_NUM_COLLECTIONS, GFP_KERNEL))) {
                kfree(device);
                return NULL;
        }
-       memset(device->collection, 0, sizeof(struct hid_collection) *
-               HID_DEFAULT_NUM_COLLECTIONS);
        device->collection_size = HID_DEFAULT_NUM_COLLECTIONS;
 
        for (i = 0; i < HID_REPORT_TYPES; i++)
@@ -675,13 +668,12 @@ static struct hid_device *hid_parse_report(__u8 *start, unsigned size)
        memcpy(device->rdesc, start, size);
        device->rsize = size;
 
-       if (!(parser = kmalloc(sizeof(struct hid_parser), GFP_KERNEL))) {
+       if (!(parser = kzalloc(sizeof(struct hid_parser), GFP_KERNEL))) {
                kfree(device->rdesc);
                kfree(device->collection);
                kfree(device);
                return NULL;
        }
-       memset(parser, 0, sizeof(struct hid_parser));
        parser->device = device;
 
        end = start + size;
@@ -893,8 +885,10 @@ static int hid_input_report(int type, struct urb *urb, int interrupt, struct pt_
 
        size = ((report->size - 1) >> 3) + 1;
 
-       if (len < size)
+       if (len < size) {
                dbg("report %d is too short, (%d < %d)", report->id, len, size);
+               memset(data + len, 0, size - len);
+       }
 
        if (hid->claimed & HID_CLAIMED_HIDDEV)
                hiddev_report_event(hid, report);
@@ -909,6 +903,106 @@ static int hid_input_report(int type, struct urb *urb, int interrupt, struct pt_
 }
 
 /*
+ * 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;
+
+       spin_lock_irqsave(&hid->inlock, flags);
+       if (hid->open > 0 && !test_bit(HID_SUSPENDED, &hid->iofl) &&
+                       !test_and_set_bit(HID_IN_RUNNING, &hid->iofl)) {
+               rc = usb_submit_urb(hid->urbin, GFP_ATOMIC);
+               if (rc != 0)
+                       clear_bit(HID_IN_RUNNING, &hid->iofl);
+       }
+       spin_unlock_irqrestore(&hid->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;
+
+       dev_dbg(&hid->intf->dev, "retrying intr urb\n");
+       if (hid_start_in(hid))
+               hid_io_error(hid);
+}
+
+/* Workqueue routine to reset the device */
+static void hid_reset(void *_hid)
+{
+       struct hid_device *hid = (struct hid_device *) _hid;
+       int rc_lock, rc;
+
+       dev_dbg(&hid->intf->dev, "resetting device\n");
+       rc = rc_lock = usb_lock_device_for_reset(hid->dev, hid->intf);
+       if (rc_lock >= 0) {
+               rc = usb_reset_composite_device(hid->dev, hid->intf);
+               if (rc_lock)
+                       usb_unlock_device(hid->dev);
+       }
+       clear_bit(HID_RESET_PENDING, &hid->iofl);
+
+       switch (rc) {
+       case 0:
+               if (!test_bit(HID_IN_RUNNING, &hid->iofl))
+                       hid_io_error(hid);
+               break;
+       default:
+               err("can't reset device, %s-%s/input%d, status %d",
+                               hid->dev->bus->bus_name,
+                               hid->dev->devpath,
+                               hid->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;
+
+       spin_lock_irqsave(&hid->inlock, flags);
+
+       /* Stop when disconnected */
+       if (usb_get_intfdata(hid->intf) == NULL)
+               goto done;
+
+       /* When an error occurs, retry at increasing intervals */
+       if (hid->retry_delay == 0) {
+               hid->retry_delay = 13;  /* Then 26, 52, 104, 104, ... */
+               hid->stop_retry = jiffies + msecs_to_jiffies(1000);
+       } else if (hid->retry_delay < 100)
+               hid->retry_delay *= 2;
+
+       if (time_after(jiffies, hid->stop_retry)) {
+
+               /* Retries failed, so do a port reset */
+               if (!test_and_set_bit(HID_RESET_PENDING, &hid->iofl)) {
+                       if (schedule_work(&hid->reset_work))
+                               goto done;
+                       clear_bit(HID_RESET_PENDING, &hid->iofl);
+               }
+       }
+
+       mod_timer(&hid->io_retry,
+                       jiffies + msecs_to_jiffies(hid->retry_delay));
+done:
+       spin_unlock_irqrestore(&hid->inlock, flags);
+}
+
+/*
  * Input interrupt completion handler.
  */
 
@@ -919,25 +1013,35 @@ static void hid_irq_in(struct urb *urb, struct pt_regs *regs)
 
        switch (urb->status) {
                case 0:                 /* success */
+                       hid->retry_delay = 0;
                        hid_input_report(HID_INPUT_REPORT, urb, 1, regs);
                        break;
                case -ECONNRESET:       /* unlink */
                case -ENOENT:
-               case -EPERM:
                case -ESHUTDOWN:        /* unplug */
-               case -EILSEQ:           /* unplug timeout on uhci */
+                       clear_bit(HID_IN_RUNNING, &hid->iofl);
                        return;
+               case -EILSEQ:           /* protocol error or unplug */
+               case -EPROTO:           /* protocol error or unplug */
                case -ETIMEDOUT:        /* NAK */
-                       break;
+                       clear_bit(HID_IN_RUNNING, &hid->iofl);
+                       hid_io_error(hid);
+                       return;
                default:                /* error */
                        warn("input irq status %d received", urb->status);
        }
 
        status = usb_submit_urb(urb, SLAB_ATOMIC);
-       if (status)
-               err("can't resubmit intr, %s-%s/input%d, status %d",
-                               hid->dev->bus->bus_name, hid->dev->devpath,
-                               hid->ifnum, status);
+       if (status) {
+               clear_bit(HID_IN_RUNNING, &hid->iofl);
+               if (status != -EPERM) {
+                       err("can't resubmit intr, %s-%s/input%d, status %d",
+                                       hid->dev->bus->bus_name,
+                                       hid->dev->devpath,
+                                       hid->ifnum, status);
+                       hid_io_error(hid);
+               }
+       }
 }
 
 /*
@@ -1099,8 +1203,9 @@ static void hid_irq_out(struct urb *urb, struct pt_regs *regs)
                case 0:                 /* success */
                        break;
                case -ESHUTDOWN:        /* unplug */
-               case -EILSEQ:           /* unplug timeout on uhci */
                        unplug = 1;
+               case -EILSEQ:           /* protocol error or unplug */
+               case -EPROTO:           /* protocol error or unplug */
                case -ECONNRESET:       /* unlink */
                case -ENOENT:
                        break;
@@ -1117,7 +1222,7 @@ static void hid_irq_out(struct urb *urb, struct pt_regs *regs)
 
        if (hid->outhead != hid->outtail) {
                if (hid_submit_out(hid)) {
-                       clear_bit(HID_OUT_RUNNING, &hid->iofl);;
+                       clear_bit(HID_OUT_RUNNING, &hid->iofl);
                        wake_up(&hid->wait);
                }
                spin_unlock_irqrestore(&hid->outlock, flags);
@@ -1147,8 +1252,9 @@ static void hid_ctrl(struct urb *urb, struct pt_regs *regs)
                                hid_input_report(hid->ctrl[hid->ctrltail].report->type, urb, 0, regs);
                        break;
                case -ESHUTDOWN:        /* unplug */
-               case -EILSEQ:           /* unplug timectrl on uhci */
                        unplug = 1;
+               case -EILSEQ:           /* protocol error or unplug */
+               case -EPROTO:           /* protocol error or unplug */
                case -ECONNRESET:       /* unlink */
                case -ENOENT:
                case -EPIPE:            /* report not available */
@@ -1261,14 +1367,9 @@ static int hid_get_class_descriptor(struct usb_device *dev, int ifnum,
 
 int hid_open(struct hid_device *hid)
 {
-       if (hid->open++)
-               return 0;
-
-       hid->urbin->dev = hid->dev;
-
-       if (usb_submit_urb(hid->urbin, GFP_KERNEL))
-               return -EIO;
-
+       ++hid->open;
+       if (hid_start_in(hid))
+               hid_io_error(hid);
        return 0;
 }
 
@@ -1278,6 +1379,8 @@ void hid_close(struct hid_device *hid)
                usb_kill_urb(hid->urbin);
 }
 
+#define USB_VENDOR_ID_PANJIT           0x134c
+
 /*
  * Initialize all reports
  */
@@ -1305,20 +1408,57 @@ void hid_init_reports(struct hid_device *hid)
        }
 
        if (err)
-               warn("timeout initializing reports\n");
+               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_DEVICE_ID_WACOM_PENPARTNER 0x0000
-#define USB_DEVICE_ID_WACOM_GRAPHIRE   0x0010
-#define USB_DEVICE_ID_WACOM_INTUOS     0x0020
-#define USB_DEVICE_ID_WACOM_PL         0x0030
-#define USB_DEVICE_ID_WACOM_INTUOS2    0x0040
-#define USB_DEVICE_ID_WACOM_VOLITO     0x0060
-#define USB_DEVICE_ID_WACOM_PTU                0x0003
-#define USB_DEVICE_ID_WACOM_INTUOS3    0x00B0
-#define USB_DEVICE_ID_WACOM_CINTIQ     0x003F
-#define USB_DEVICE_ID_WACOM_DTF         0x00C0
 
 #define USB_VENDOR_ID_ACECAD           0x0460
 #define USB_DEVICE_ID_ACECAD_FLAIR     0x0004
@@ -1362,9 +1502,6 @@ void hid_init_reports(struct hid_device *hid)
 #define USB_VENDOR_ID_ONTRAK           0x0a07
 #define USB_DEVICE_ID_ONTRAK_ADU100    0x0064
 
-#define USB_VENDOR_ID_TANGTOP          0x0d3d
-#define USB_DEVICE_ID_TANGTOP_USBPS2   0x0001
-
 #define USB_VENDOR_ID_ESSENTIAL_REALITY        0x0d7f
 #define USB_DEVICE_ID_ESSENTIAL_REALITY_P5 0x0100
 
@@ -1405,6 +1542,10 @@ void hid_init_reports(struct hid_device *hid)
 #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_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_IOW40  0x1500
@@ -1420,12 +1561,6 @@ void hid_init_reports(struct hid_device *hid)
 #define USB_DEVICE_ID_MCC_PMD1024LS    0x0076
 #define USB_DEVICE_ID_MCC_PMD1208LS    0x007a
 
-#define USB_VENDOR_ID_CHICONY          0x04f2
-#define USB_DEVICE_ID_CHICONY_USBHUB_KB        0x0100
-
-#define USB_VENDOR_ID_BTC              0x046e
-#define USB_DEVICE_ID_BTC_KEYBOARD     0x5303
-
 #define USB_VENDOR_ID_VERNIER          0x08f7
 #define USB_DEVICE_ID_VERNIER_LABPRO   0x0001
 #define USB_DEVICE_ID_VERNIER_GOTEMP   0x0002
@@ -1433,26 +1568,34 @@ void hid_init_reports(struct hid_device *hid)
 #define USB_DEVICE_ID_VERNIER_CYCLOPS  0x0004
 
 #define USB_VENDOR_ID_LD               0x0f11
-#define USB_DEVICE_ID_CASSY            0x1000
-#define USB_DEVICE_ID_POCKETCASSY      0x1010
-#define USB_DEVICE_ID_MOBILECASSY      0x1020
-#define USB_DEVICE_ID_JWM              0x1080
-#define USB_DEVICE_ID_DMMP             0x1081
-#define USB_DEVICE_ID_UMIP             0x1090
-#define USB_DEVICE_ID_VIDEOCOM         0x1200
-#define USB_DEVICE_ID_COM3LAB          0x2000
-#define USB_DEVICE_ID_TELEPORT         0x2010
-#define USB_DEVICE_ID_NETWORKANALYSER  0x2020
-#define USB_DEVICE_ID_POWERCONTROL     0x2030
+#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_POWERMOUSE 0x0304
+#define USB_DEVICE_ID_APPLE_MIGHTYMOUSE        0x0304
+
+#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
 /*
  * Alphabetically sorted blacklist by quirk type.
  */
 
-static struct hid_blacklist {
+static const struct hid_blacklist {
        __u16 idVendor;
        __u16 idProduct;
        unsigned quirks;
@@ -1482,18 +1625,66 @@ static struct hid_blacklist {
        { USB_VENDOR_ID_GLAB, USB_DEVICE_ID_0_8_8_IF_KIT, 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_KBGEAR, USB_DEVICE_ID_KBGEAR_JAMSTUDIO, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_LD, USB_DEVICE_ID_CASSY, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_LD, USB_DEVICE_ID_POCKETCASSY, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_LD, USB_DEVICE_ID_MOBILECASSY, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_LD, USB_DEVICE_ID_JWM, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_LD, USB_DEVICE_ID_DMMP, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_LD, USB_DEVICE_ID_UMIP, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_LD, USB_DEVICE_ID_VIDEOCOM, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_LD, USB_DEVICE_ID_COM3LAB, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_LD, USB_DEVICE_ID_TELEPORT, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_LD, USB_DEVICE_ID_NETWORKANALYSER, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_LD, USB_DEVICE_ID_POWERCONTROL, 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 },
@@ -1508,48 +1699,9 @@ static struct hid_blacklist {
        { 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_WACOM, USB_DEVICE_ID_WACOM_PENPARTNER, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_GRAPHIRE, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_GRAPHIRE + 1, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_GRAPHIRE + 2, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_GRAPHIRE + 3, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_GRAPHIRE + 4, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS + 1, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS + 2, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS + 3, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS + 4, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_PL, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_PL + 1, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_PL + 2, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_PL + 3, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_PL + 4, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_PL + 5, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_PL + 7, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_PL + 8, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_PL + 9, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS2 + 1, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS2 + 2, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS2 + 3, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS2 + 4, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS2 + 5, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS2 + 7, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_VOLITO, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_VOLITO + 1, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_VOLITO + 2, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_VOLITO + 3, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_VOLITO + 4, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_GRAPHIRE + 5, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_GRAPHIRE + 6, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_PTU, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS3, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS3 + 1, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS3 + 2, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS3 + 5, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_CINTIQ, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_DTF, 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_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 },
@@ -1559,11 +1711,10 @@ static struct hid_blacklist {
        { 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_BTC, USB_DEVICE_ID_BTC_KEYBOARD, HID_QUIRK_NOGET},
-       { USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_USBHUB_KB, HID_QUIRK_NOGET},
-       { USB_VENDOR_ID_TANGTOP, USB_DEVICE_ID_TANGTOP_USBPS2, 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_POWERMOUSE, HID_QUIRK_2WHEEL_POWERMOUSE },
+       { 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 },
 
@@ -1578,6 +1729,24 @@ static struct hid_blacklist {
        { 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, 0x020E, HID_QUIRK_POWERBOOK_HAS_FN },
+       { USB_VENDOR_ID_APPLE, 0x020F, HID_QUIRK_POWERBOOK_HAS_FN },
+       { USB_VENDOR_ID_APPLE, 0x0214, HID_QUIRK_POWERBOOK_HAS_FN },
+       { USB_VENDOR_ID_APPLE, 0x0215, HID_QUIRK_POWERBOOK_HAS_FN },
+       { USB_VENDOR_ID_APPLE, 0x0216, HID_QUIRK_POWERBOOK_HAS_FN },
+       { USB_VENDOR_ID_APPLE, 0x0217, HID_QUIRK_POWERBOOK_HAS_FN },
+       { USB_VENDOR_ID_APPLE, 0x0218, HID_QUIRK_POWERBOOK_HAS_FN },
+       { USB_VENDOR_ID_APPLE, 0x0219, HID_QUIRK_POWERBOOK_HAS_FN },
+       { USB_VENDOR_ID_APPLE, 0x030A, HID_QUIRK_POWERBOOK_HAS_FN },
+       { USB_VENDOR_ID_APPLE, 0x030B, HID_QUIRK_POWERBOOK_HAS_FN },
+
+       { 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 },
+
        { 0, 0 }
 };
 
@@ -1624,6 +1793,20 @@ static void hid_free_buffers(struct usb_device *dev, struct hid_device *hid)
                usb_buffer_free(dev, hid->bufsize, hid->ctrlbuf, hid->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;
+       }
+}
+
 static struct hid_device *usb_hid_configure(struct usb_interface *intf)
 {
        struct usb_host_interface *interface = intf->cur_altsetting;
@@ -1634,11 +1817,23 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf)
        char *rdesc;
        int n, len, insize = 0;
 
+        /* Ignore all Wacom devices */
+        if (le16_to_cpu(dev->descriptor.idVendor) == USB_VENDOR_ID_WACOM)
+                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;
 
@@ -1671,6 +1866,9 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf)
                return NULL;
        }
 
+       if ((quirks & HID_QUIRK_CYMOTION))
+               hid_fixup_cymotion_descriptor(rdesc, rsize);
+
 #ifdef DEBUG_DATA
        printk(KERN_DEBUG __FILE__ ": report descriptor (size %u, read %d) = ", rsize, n);
        for (n = 0; n < rsize; n++)
@@ -1751,6 +1949,10 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf)
 
        init_waitqueue_head(&hid->wait);
 
+       INIT_WORK(&hid->reset_work, hid_reset, hid);
+       setup_timer(&hid->io_retry, hid_retry_timeout, (unsigned long) hid);
+
+       spin_lock_init(&hid->inlock);
        spin_lock_init(&hid->outlock);
        spin_lock_init(&hid->ctrllock);
 
@@ -1796,9 +1998,6 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf)
        hid->urbctrl->transfer_dma = hid->ctrlbuf_dma;
        hid->urbctrl->transfer_flags |= (URB_NO_TRANSFER_DMA_MAP | URB_NO_SETUP_DMA_MAP);
 
-       /* May be needed for some devices */
-       usb_clear_halt(hid->dev, hid->urbin->pipe);
-
        return hid;
 
 fail:
@@ -1822,11 +2021,16 @@ static void hid_disconnect(struct usb_interface *intf)
        if (!hid)
                return;
 
+       spin_lock_irq(&hid->inlock);    /* Sync with error handler */
        usb_set_intfdata(intf, NULL);
+       spin_unlock_irq(&hid->inlock);
        usb_kill_urb(hid->urbin);
        usb_kill_urb(hid->urbout);
        usb_kill_urb(hid->urbctrl);
 
+       del_timer_sync(&hid->io_retry);
+       flush_scheduled_work();
+
        if (hid->claimed & HID_CLAIMED_INPUT)
                hidinput_disconnect(hid);
        if (hid->claimed & HID_CLAIMED_HIDDEV)
@@ -1901,6 +2105,10 @@ static int hid_suspend(struct usb_interface *intf, pm_message_t message)
 {
        struct hid_device *hid = usb_get_intfdata (intf);
 
+       spin_lock_irq(&hid->inlock);    /* Sync with error handler */
+       set_bit(HID_SUSPENDED, &hid->iofl);
+       spin_unlock_irq(&hid->inlock);
+       del_timer(&hid->io_retry);
        usb_kill_urb(hid->urbin);
        dev_dbg(&intf->dev, "suspend\n");
        return 0;
@@ -1911,14 +2119,30 @@ static int hid_resume(struct usb_interface *intf)
        struct hid_device *hid = usb_get_intfdata (intf);
        int status;
 
-       if (hid->open)
-               status = usb_submit_urb(hid->urbin, GFP_NOIO);
-       else
-               status = 0;
+       clear_bit(HID_SUSPENDED, &hid->iofl);
+       hid->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 },
@@ -1928,12 +2152,13 @@ static struct usb_device_id hid_usb_ids [] = {
 MODULE_DEVICE_TABLE (usb, hid_usb_ids);
 
 static struct usb_driver hid_driver = {
-       .owner =        THIS_MODULE,
        .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,
 };