]> git.kernelconcepts.de Git - karo-tx-linux.git/commitdiff
Merge branch 'upstream' into for-linus
authorJiri Kosina <jkosina@suse.cz>
Tue, 22 May 2012 09:32:31 +0000 (11:32 +0200)
committerJiri Kosina <jkosina@suse.cz>
Tue, 22 May 2012 09:32:31 +0000 (11:32 +0200)
Conflicts:
drivers/hid/hid-core.c

13 files changed:
drivers/hid/Kconfig
drivers/hid/Makefile
drivers/hid/hid-apple.c
drivers/hid/hid-aureal.c [new file with mode: 0644]
drivers/hid/hid-core.c
drivers/hid/hid-ids.h
drivers/hid/hid-uclogic.c
drivers/hid/hidraw.c
drivers/hid/usbhid/hid-core.c
drivers/hid/usbhid/hiddev.c
drivers/hid/usbhid/usbhid.h
include/linux/hid.h
include/linux/hidraw.h

index 9a581e1a19034667d9c3ceb4860966197355022c..80175c37a6a5752c8480c54e497fd48217a429cf 100644 (file)
@@ -104,6 +104,12 @@ config HID_APPLE
        Say Y here if you want support for keyboards of Apple iBooks, PowerBooks,
        MacBooks, MacBook Pros and Apple Aluminum.
 
+config HID_AUREAL
+       tristate "Aureal"
+       depends on USB_HID
+       ---help---
+       Support for Aureal Cy se W-01RN Remote Controller and other Aureal derived remotes.
+
 config HID_BELKIN
        tristate "Belkin Flip KVM and Wireless keyboard" if EXPERT
        depends on USB_HID
index a04cffa4784fb1da0e7ed4f579bf8d851ddaefa1..ca6cc9f0485c90d22fb11d0c6deeb6560ac36158 100644 (file)
@@ -38,6 +38,7 @@ endif
 obj-$(CONFIG_HID_A4TECH)       += hid-a4tech.o
 obj-$(CONFIG_HID_ACRUX)                += hid-axff.o
 obj-$(CONFIG_HID_APPLE)                += hid-apple.o
+obj-$(CONFIG_HID_AUREAL)        += hid-aureal.o
 obj-$(CONFIG_HID_BELKIN)       += hid-belkin.o
 obj-$(CONFIG_HID_CHERRY)       += hid-cherry.o
 obj-$(CONFIG_HID_CHICONY)      += hid-chicony.o
index 299d23871122f29f8651917caf2ccb461a4c8c1d..7a79e39efc7e76a61a3d3c807cb9ea57b665cbfb 100644 (file)
@@ -234,7 +234,7 @@ static int hidinput_apple_event(struct hid_device *hid, struct input_dev *input,
                }
        }
 
-        if (iso_layout) {
+       if (iso_layout) {
                if (asc->quirks & APPLE_ISO_KEYBOARD) {
                        trans = apple_find_translation(apple_iso_keyboard, usage->code);
                        if (trans) {
diff --git a/drivers/hid/hid-aureal.c b/drivers/hid/hid-aureal.c
new file mode 100644 (file)
index 0000000..ba64b04
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ *  HID driver for Aureal Cy se W-01RN USB_V3.1 devices
+ *
+ *  Copyright (c) 2010 Franco Catrin <fcatrin@gmail.com>
+ *  Copyright (c) 2010 Ben Cropley <bcropley@internode.on.net>
+ *
+ *  Based on HID sunplus driver by
+ *  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
+ *  Copyright (c) 2007 Paul Walmsley
+ *  Copyright (c) 2008 Jiri Slaby
+ */
+#include <linux/device.h>
+#include <linux/hid.h>
+#include <linux/module.h>
+
+#include "hid-ids.h"
+
+static __u8 *aureal_report_fixup(struct hid_device *hdev, __u8 *rdesc,
+               unsigned int *rsize)
+{
+       if (*rsize >= 54 && rdesc[52] == 0x25 && rdesc[53] == 0x01) {
+               dev_info(&hdev->dev, "fixing Aureal Cy se W-01RN USB_V3.1 report descriptor.\n");
+               rdesc[53] = 0x65;
+       } return rdesc;
+}
+
+static const struct hid_device_id aureal_devices[] = {
+       { HID_USB_DEVICE(USB_VENDOR_ID_AUREAL, USB_DEVICE_ID_AUREAL_W01RN) },
+       { }
+};
+MODULE_DEVICE_TABLE(hid, aureal_devices);
+
+static struct hid_driver aureal_driver = {
+       .name = "aureal",
+       .id_table = aureal_devices,
+       .report_fixup = aureal_report_fixup,
+};
+
+static int __init aureal_init(void)
+{
+       return hid_register_driver(&aureal_driver);
+}
+
+static void __exit aureal_exit(void)
+{
+       hid_unregister_driver(&aureal_driver);
+}
+
+module_init(aureal_init);
+module_exit(aureal_exit);
+MODULE_LICENSE("GPL");
index df2ca0af855f38769ac159c073e5bf4192d4de68..9831a2ccae3d48f2842e1ddca2ec63f4a1cb6158 100644 (file)
@@ -230,9 +230,16 @@ static int hid_add_field(struct hid_parser *parser, unsigned report_type, unsign
                return -1;
        }
 
-       if (parser->global.logical_maximum < parser->global.logical_minimum) {
-               hid_err(parser->device, "logical range invalid %d %d\n",
-                               parser->global.logical_minimum, parser->global.logical_maximum);
+       /* Handle both signed and unsigned cases properly */
+       if ((parser->global.logical_minimum < 0 &&
+               parser->global.logical_maximum <
+               parser->global.logical_minimum) ||
+               (parser->global.logical_minimum >= 0 &&
+               (__u32)parser->global.logical_maximum <
+               (__u32)parser->global.logical_minimum)) {
+               dbg_hid("logical range invalid 0x%x 0x%x\n",
+                       parser->global.logical_minimum,
+                       parser->global.logical_maximum);
                return -1;
        }
 
@@ -1149,7 +1156,7 @@ static struct hid_report *hid_get_report(struct hid_report_enum *report_enum,
        return report;
 }
 
-void hid_report_raw_event(struct hid_device *hid, int type, u8 *data, int size,
+int hid_report_raw_event(struct hid_device *hid, int type, u8 *data, int size,
                int interrupt)
 {
        struct hid_report_enum *report_enum = hid->report_enum + type;
@@ -1157,10 +1164,11 @@ void hid_report_raw_event(struct hid_device *hid, int type, u8 *data, int size,
        unsigned int a;
        int rsize, csize = size;
        u8 *cdata = data;
+       int ret = 0;
 
        report = hid_get_report(report_enum, data);
        if (!report)
-               return;
+               goto out;
 
        if (report_enum->numbered) {
                cdata++;
@@ -1180,14 +1188,19 @@ void hid_report_raw_event(struct hid_device *hid, int type, u8 *data, int size,
 
        if ((hid->claimed & HID_CLAIMED_HIDDEV) && hid->hiddev_report_event)
                hid->hiddev_report_event(hid, report);
-       if (hid->claimed & HID_CLAIMED_HIDRAW)
-               hidraw_report_event(hid, data, size);
+       if (hid->claimed & HID_CLAIMED_HIDRAW) {
+               ret = hidraw_report_event(hid, data, size);
+               if (ret)
+                       goto out;
+       }
 
        for (a = 0; a < report->maxfield; a++)
                hid_input_field(hid, report->field[a], cdata, interrupt);
 
        if (hid->claimed & HID_CLAIMED_INPUT)
                hidinput_report_event(hid, report);
+out:
+       return ret;
 }
 EXPORT_SYMBOL_GPL(hid_report_raw_event);
 
@@ -1264,7 +1277,7 @@ nomem:
                }
        }
 
-       hid_report_raw_event(hid, type, data, size, interrupt);
+       ret = hid_report_raw_event(hid, type, data, size, interrupt);
 
 unlock:
        up(&hid->driver_lock);
@@ -1496,6 +1509,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
        { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_ISO) },
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY) },
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_AUREAL, USB_DEVICE_ID_AUREAL_W01RN) },
        { HID_USB_DEVICE(USB_VENDOR_ID_BELKIN, USB_DEVICE_ID_FLIP_KVM) },
        { HID_USB_DEVICE(USB_VENDOR_ID_BAANTO, USB_DEVICE_ID_BAANTO_MT_190W2), },
        { HID_USB_DEVICE(USB_VENDOR_ID_BTC, USB_DEVICE_ID_BTC_EMPREX_REMOTE) },
@@ -1631,6 +1645,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_WP5540U) },
        { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_WP8060U) },
        { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_WP1062) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_WIRELESS_TABLET_TWHL850) },
        { HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_SMARTJOY_PLUS) },
        { HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_SUPER_JOY_BOX_3) },
        { HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_DUAL_USB_JOYPAD) },
index e44932af8da27290b6b356f4598482f7288adb52..4ff994166c04fea2ab7259792c730952471a807e 100644 (file)
 #define USB_DEVICE_ID_ATMEL_MULTITOUCH 0x211c
 #define USB_DEVICE_ID_ATMEL_MXT_DIGITIZER      0x2118
 
+#define USB_VENDOR_ID_AUREAL           0x0755
+#define USB_DEVICE_ID_AUREAL_W01RN     0x2626
+
 #define USB_VENDOR_ID_AVERMEDIA                0x07ca
 #define USB_DEVICE_ID_AVER_FM_MR800    0xb800
 
 #define USB_DEVICE_ID_UCLOGIC_TABLET_WP5540U   0x0004
 #define USB_DEVICE_ID_UCLOGIC_TABLET_WP8060U   0x0005
 #define USB_DEVICE_ID_UCLOGIC_TABLET_WP1062    0x0064
+#define USB_DEVICE_ID_UCLOGIC_WIRELESS_TABLET_TWHL850  0x0522
 
 #define USB_VENDOR_ID_UNITEC   0x227d
 #define USB_DEVICE_ID_UNITEC_USB_TOUCH_0709    0x0709
index 1f1128910337a5e004c60e4896c843d70b88b56c..3aba02be1f2664d6382625bd979ccd89c45941a3 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/device.h>
 #include <linux/hid.h>
 #include <linux/module.h>
+#include <linux/usb.h>
 
 #include "hid-ids.h"
 
@@ -352,9 +353,125 @@ static __u8 pf1209_rdesc_fixed[] = {
        0xC0                /*  End Collection                      */
 };
 
+/*
+ * See TWHL850 description, device and HID report descriptors at
+ * http://sf.net/apps/mediawiki/digimend/?title=UC-Logic_Wireless_Tablet_TWHL850
+ */
+
+/* Size of the original descriptors of TWHL850 tablet */
+#define TWHL850_RDESC_ORIG_SIZE0       182
+#define TWHL850_RDESC_ORIG_SIZE1       161
+#define TWHL850_RDESC_ORIG_SIZE2       92
+
+/* Fixed PID 0522 tablet report descriptor, interface 0 (stylus) */
+static __u8 twhl850_rdesc_fixed0[] = {
+       0x05, 0x0D,         /*  Usage Page (Digitizer),             */
+       0x09, 0x02,         /*  Usage (Pen),                        */
+       0xA1, 0x01,         /*  Collection (Application),           */
+       0x85, 0x09,         /*      Report ID (9),                  */
+       0x09, 0x20,         /*      Usage (Stylus),                 */
+       0xA0,               /*      Collection (Physical),          */
+       0x14,               /*          Logical Minimum (0),        */
+       0x25, 0x01,         /*          Logical Maximum (1),        */
+       0x75, 0x01,         /*          Report Size (1),            */
+       0x95, 0x03,         /*          Report Count (3),           */
+       0x09, 0x42,         /*          Usage (Tip Switch),         */
+       0x09, 0x44,         /*          Usage (Barrel Switch),      */
+       0x09, 0x46,         /*          Usage (Tablet Pick),        */
+       0x81, 0x02,         /*          Input (Variable),           */
+       0x81, 0x03,         /*          Input (Constant, Variable), */
+       0x95, 0x01,         /*          Report Count (1),           */
+       0x09, 0x32,         /*          Usage (In Range),           */
+       0x81, 0x02,         /*          Input (Variable),           */
+       0x81, 0x03,         /*          Input (Constant, Variable), */
+       0x75, 0x10,         /*          Report Size (16),           */
+       0xA4,               /*          Push,                       */
+       0x05, 0x01,         /*          Usage Page (Desktop),       */
+       0x65, 0x13,         /*          Unit (Inch),                */
+       0x55, 0xFD,         /*          Unit Exponent (-3),         */
+       0x34,               /*          Physical Minimum (0),       */
+       0x09, 0x30,         /*          Usage (X),                  */
+       0x46, 0x40, 0x1F,   /*          Physical Maximum (8000),    */
+       0x26, 0x00, 0x7D,   /*          Logical Maximum (32000),    */
+       0x81, 0x02,         /*          Input (Variable),           */
+       0x09, 0x31,         /*          Usage (Y),                  */
+       0x46, 0x88, 0x13,   /*          Physical Maximum (5000),    */
+       0x26, 0x20, 0x4E,   /*          Logical Maximum (20000),    */
+       0x81, 0x02,         /*          Input (Variable),           */
+       0xB4,               /*          Pop,                        */
+       0x09, 0x30,         /*          Usage (Tip Pressure),       */
+       0x26, 0xFF, 0x03,   /*          Logical Maximum (1023),     */
+       0x81, 0x02,         /*          Input (Variable),           */
+       0xC0,               /*      End Collection,                 */
+       0xC0                /*  End Collection                      */
+};
+
+/* Fixed PID 0522 tablet report descriptor, interface 1 (mouse) */
+static __u8 twhl850_rdesc_fixed1[] = {
+       0x05, 0x01,         /*  Usage Page (Desktop),               */
+       0x09, 0x02,         /*  Usage (Mouse),                      */
+       0xA1, 0x01,         /*  Collection (Application),           */
+       0x85, 0x01,         /*      Report ID (1),                  */
+       0x09, 0x01,         /*      Usage (Pointer),                */
+       0xA0,               /*      Collection (Physical),          */
+       0x05, 0x09,         /*          Usage Page (Button),        */
+       0x75, 0x01,         /*          Report Size (1),            */
+       0x95, 0x03,         /*          Report Count (3),           */
+       0x19, 0x01,         /*          Usage Minimum (01h),        */
+       0x29, 0x03,         /*          Usage Maximum (03h),        */
+       0x14,               /*          Logical Minimum (0),        */
+       0x25, 0x01,         /*          Logical Maximum (1),        */
+       0x81, 0x02,         /*          Input (Variable),           */
+       0x95, 0x05,         /*          Report Count (5),           */
+       0x81, 0x03,         /*          Input (Constant, Variable), */
+       0x05, 0x01,         /*          Usage Page (Desktop),       */
+       0x09, 0x30,         /*          Usage (X),                  */
+       0x09, 0x31,         /*          Usage (Y),                  */
+       0x16, 0x00, 0x80,   /*          Logical Minimum (-32768),   */
+       0x26, 0xFF, 0x7F,   /*          Logical Maximum (32767),    */
+       0x75, 0x10,         /*          Report Size (16),           */
+       0x95, 0x02,         /*          Report Count (2),           */
+       0x81, 0x06,         /*          Input (Variable, Relative), */
+       0x09, 0x38,         /*          Usage (Wheel),              */
+       0x15, 0xFF,         /*          Logical Minimum (-1),       */
+       0x25, 0x01,         /*          Logical Maximum (1),        */
+       0x95, 0x01,         /*          Report Count (1),           */
+       0x75, 0x08,         /*          Report Size (8),            */
+       0x81, 0x06,         /*          Input (Variable, Relative), */
+       0x81, 0x03,         /*          Input (Constant, Variable), */
+       0xC0,               /*      End Collection,                 */
+       0xC0                /*  End Collection                      */
+};
+
+/* Fixed PID 0522 tablet report descriptor, interface 2 (frame buttons) */
+static __u8 twhl850_rdesc_fixed2[] = {
+       0x05, 0x01,         /*  Usage Page (Desktop),               */
+       0x09, 0x06,         /*  Usage (Keyboard),                   */
+       0xA1, 0x01,         /*  Collection (Application),           */
+       0x85, 0x03,         /*      Report ID (3),                  */
+       0x05, 0x07,         /*      Usage Page (Keyboard),          */
+       0x14,               /*      Logical Minimum (0),            */
+       0x19, 0xE0,         /*      Usage Minimum (KB Leftcontrol), */
+       0x29, 0xE7,         /*      Usage Maximum (KB Right GUI),   */
+       0x25, 0x01,         /*      Logical Maximum (1),            */
+       0x75, 0x01,         /*      Report Size (1),                */
+       0x95, 0x08,         /*      Report Count (8),               */
+       0x81, 0x02,         /*      Input (Variable),               */
+       0x18,               /*      Usage Minimum (None),           */
+       0x29, 0xFF,         /*      Usage Maximum (FFh),            */
+       0x26, 0xFF, 0x00,   /*      Logical Maximum (255),          */
+       0x75, 0x08,         /*      Report Size (8),                */
+       0x95, 0x06,         /*      Report Count (6),               */
+       0x80,               /*      Input,                          */
+       0xC0                /*  End Collection                      */
+};
+
 static __u8 *uclogic_report_fixup(struct hid_device *hdev, __u8 *rdesc,
                                        unsigned int *rsize)
 {
+       struct usb_interface *iface = to_usb_interface(hdev->dev.parent);
+       __u8 iface_num = iface->cur_altsetting->desc.bInterfaceNumber;
+
        switch (hdev->product) {
        case USB_DEVICE_ID_UCLOGIC_TABLET_PF1209:
                if (*rsize == PF1209_RDESC_ORIG_SIZE) {
@@ -386,6 +503,28 @@ static __u8 *uclogic_report_fixup(struct hid_device *hdev, __u8 *rdesc,
                        *rsize = sizeof(wp1062_rdesc_fixed);
                }
                break;
+       case USB_DEVICE_ID_UCLOGIC_WIRELESS_TABLET_TWHL850:
+               switch (iface_num) {
+               case 0:
+                       if (*rsize == TWHL850_RDESC_ORIG_SIZE0) {
+                               rdesc = twhl850_rdesc_fixed0;
+                               *rsize = sizeof(twhl850_rdesc_fixed0);
+                       }
+                       break;
+               case 1:
+                       if (*rsize == TWHL850_RDESC_ORIG_SIZE1) {
+                               rdesc = twhl850_rdesc_fixed1;
+                               *rsize = sizeof(twhl850_rdesc_fixed1);
+                       }
+                       break;
+               case 2:
+                       if (*rsize == TWHL850_RDESC_ORIG_SIZE2) {
+                               rdesc = twhl850_rdesc_fixed2;
+                               *rsize = sizeof(twhl850_rdesc_fixed2);
+                       }
+                       break;
+               }
+               break;
        }
 
        return rdesc;
@@ -402,6 +541,8 @@ static const struct hid_device_id uclogic_devices[] = {
                                USB_DEVICE_ID_UCLOGIC_TABLET_WP8060U) },
        { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC,
                                USB_DEVICE_ID_UCLOGIC_TABLET_WP1062) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC,
+                               USB_DEVICE_ID_UCLOGIC_WIRELESS_TABLET_TWHL850) },
        { }
 };
 MODULE_DEVICE_TABLE(hid, uclogic_devices);
index cf7d6d58e79f25513dd0baedac00e3ddfd5f342f..36fa77b40ffbfcccabed691700d787bc10ea8402 100644 (file)
@@ -87,11 +87,13 @@ static ssize_t hidraw_read(struct file *file, char __user *buffer, size_t count,
                len = list->buffer[list->tail].len > count ?
                        count : list->buffer[list->tail].len;
 
-               if (copy_to_user(buffer, list->buffer[list->tail].value, len)) {
-                       ret = -EFAULT;
-                       goto out;
+               if (list->buffer[list->tail].value) {
+                       if (copy_to_user(buffer, list->buffer[list->tail].value, len)) {
+                               ret = -EFAULT;
+                               goto out;
+                       }
+                       ret = len;
                }
-               ret = len;
 
                kfree(list->buffer[list->tail].value);
                list->tail = (list->tail + 1) & (HIDRAW_BUFFER_SIZE - 1);
@@ -437,19 +439,24 @@ static const struct file_operations hidraw_ops = {
        .llseek =       noop_llseek,
 };
 
-void hidraw_report_event(struct hid_device *hid, u8 *data, int len)
+int hidraw_report_event(struct hid_device *hid, u8 *data, int len)
 {
        struct hidraw *dev = hid->hidraw;
        struct hidraw_list *list;
+       int ret = 0;
 
        list_for_each_entry(list, &dev->list, node) {
-               list->buffer[list->head].value = kmemdup(data, len, GFP_ATOMIC);
+               if (!(list->buffer[list->head].value = kmemdup(data, len, GFP_ATOMIC))) {
+                       ret = -ENOMEM;
+                       break;
+               }
                list->buffer[list->head].len = len;
                list->head = (list->head + 1) & (HIDRAW_BUFFER_SIZE - 1);
                kill_fasync(&list->fasync, SIGIO, POLL_IN);
        }
 
        wake_up_interruptible(&dev->wait);
+       return ret;
 }
 EXPORT_SYMBOL_GPL(hidraw_report_event);
 
index 9cba5006b5edf9af1d325c63a32f08a85ee23041..df3789f5d9a5f25e92a934e018938e3574dc47fb 100644 (file)
@@ -28,6 +28,7 @@
 #include <linux/input.h>
 #include <linux/wait.h>
 #include <linux/workqueue.h>
+#include <linux/string.h>
 
 #include <linux/usb.h>
 
@@ -86,8 +87,13 @@ static int hid_start_in(struct hid_device *hid)
                        !test_bit(HID_REPORTED_IDLE, &usbhid->iofl) &&
                        !test_and_set_bit(HID_IN_RUNNING, &usbhid->iofl)) {
                rc = usb_submit_urb(usbhid->urbin, GFP_ATOMIC);
-               if (rc != 0)
+               if (rc != 0) {
                        clear_bit(HID_IN_RUNNING, &usbhid->iofl);
+                       if (rc == -ENOSPC)
+                               set_bit(HID_NO_BANDWIDTH, &usbhid->iofl);
+               } else {
+                       clear_bit(HID_NO_BANDWIDTH, &usbhid->iofl);
+               }
        }
        spin_unlock_irqrestore(&usbhid->lock, flags);
        return rc;
@@ -173,8 +179,10 @@ static void hid_io_error(struct hid_device *hid)
 
        if (time_after(jiffies, usbhid->stop_retry)) {
 
-               /* Retries failed, so do a port reset */
-               if (!test_and_set_bit(HID_RESET_PENDING, &usbhid->iofl)) {
+               /* Retries failed, so do a port reset unless we lack bandwidth*/
+               if (test_bit(HID_NO_BANDWIDTH, &usbhid->iofl)
+                    && !test_and_set_bit(HID_RESET_PENDING, &usbhid->iofl)) {
+
                        schedule_work(&usbhid->reset_work);
                        goto done;
                }
@@ -700,7 +708,7 @@ static int hid_get_class_descriptor(struct usb_device *dev, int ifnum,
 int usbhid_open(struct hid_device *hid)
 {
        struct usbhid_device *usbhid = hid->driver_data;
-       int res;
+       int res = 0;
 
        mutex_lock(&hid_open_mut);
        if (!hid->open++) {
@@ -708,17 +716,27 @@ int usbhid_open(struct hid_device *hid)
                /* the device must be awake to reliably request remote wakeup */
                if (res < 0) {
                        hid->open--;
-                       mutex_unlock(&hid_open_mut);
-                       return -EIO;
+                       res = -EIO;
+                       goto done;
                }
                usbhid->intf->needs_remote_wakeup = 1;
-               if (hid_start_in(hid))
-                       hid_io_error(hid);
+               res = hid_start_in(hid);
+               if (res) {
+                       if (res != -ENOSPC) {
+                               hid_io_error(hid);
+                               res = 0;
+                       } else {
+                               /* no use opening if resources are insufficient */
+                               hid->open--;
+                               res = -EBUSY;
+                               usbhid->intf->needs_remote_wakeup = 0;
+                       }
+               }
                usb_autopm_put_interface(usbhid->intf);
        }
+done:
        mutex_unlock(&hid_open_mut);
-       return 0;
+       return res;
 }
 
 void usbhid_close(struct hid_device *hid)
@@ -1347,7 +1365,34 @@ static int hid_post_reset(struct usb_interface *intf)
        struct usb_device *dev = interface_to_usbdev (intf);
        struct hid_device *hid = usb_get_intfdata(intf);
        struct usbhid_device *usbhid = hid->driver_data;
+       struct usb_host_interface *interface = intf->cur_altsetting;
        int status;
+       char *rdesc;
+
+       /* Fetch and examine the HID report descriptor. If this
+        * has changed, then rebind. Since usbcore's check of the
+        * configuration descriptors passed, we already know that
+        * the size of the HID report descriptor has not changed.
+        */
+       rdesc = kmalloc(hid->rsize, GFP_KERNEL);
+       if (!rdesc) {
+               dbg_hid("couldn't allocate rdesc memory (post_reset)\n");
+               return 1;
+       }
+       status = hid_get_class_descriptor(dev,
+                               interface->desc.bInterfaceNumber,
+                               HID_DT_REPORT, rdesc, hid->rsize);
+       if (status < 0) {
+               dbg_hid("reading report descriptor failed (post_reset)\n");
+               kfree(rdesc);
+               return 1;
+       }
+       status = memcmp(rdesc, hid->rdesc, hid->rsize);
+       kfree(rdesc);
+       if (status != 0) {
+               dbg_hid("report descriptor changed\n");
+               return 1;
+       }
 
        spin_lock_irq(&usbhid->lock);
        clear_bit(HID_RESET_PENDING, &usbhid->iofl);
index b1ec0e2aeb57b0b26a66e17b067192cfc30689c1..14599e25679181cc00223675a7d4170cdff70174 100644 (file)
@@ -34,6 +34,7 @@
 #include <linux/hid.h>
 #include <linux/hiddev.h>
 #include <linux/compat.h>
+#include <linux/vmalloc.h>
 #include "usbhid.h"
 
 #ifdef CONFIG_USB_DYNAMIC_MINORS
@@ -250,13 +251,13 @@ static int hiddev_release(struct inode * inode, struct file * file)
                } else {
                        mutex_unlock(&list->hiddev->existancelock);
                        kfree(list->hiddev);
-                       kfree(list);
+                       vfree(list);
                        return 0;
                }
        }
 
        mutex_unlock(&list->hiddev->existancelock);
-       kfree(list);
+       vfree(list);
 
        return 0;
 }
@@ -278,7 +279,7 @@ static int hiddev_open(struct inode *inode, struct file *file)
        hid = usb_get_intfdata(intf);
        hiddev = hid->hiddev;
 
-       if (!(list = kzalloc(sizeof(struct hiddev_list), GFP_KERNEL)))
+       if (!(list = vzalloc(sizeof(struct hiddev_list))))
                return -ENOMEM;
        mutex_init(&list->thread_lock);
        list->hiddev = hiddev;
@@ -322,7 +323,7 @@ bail_unlock:
        mutex_unlock(&hiddev->existancelock);
 bail:
        file->private_data = NULL;
-       kfree(list);
+       vfree(list);
        return res;
 }
 
index cb8f703efde5a00747b77d1bebc313e17864ae86..1883d7b94870d7542827aa443dc3cc32d0de24da 100644 (file)
@@ -55,6 +55,7 @@ struct usb_interface *usbhid_find_interface(int minor);
 #define HID_STARTED            8
 #define HID_REPORTED_IDLE      9
 #define HID_KEYS_PRESSED       10
+#define HID_NO_BANDWIDTH       11
 
 /*
  * USB-specific HID struct, to be pointed to
index 2c7a19515c3a040d76f9b144da1997e24ce710bf..449fa385703df5375db5cad0786bbc4a7f35b716 100644 (file)
@@ -896,7 +896,7 @@ static inline int hid_hw_power(struct hid_device *hdev, int level)
        return hdev->ll_driver->power ? hdev->ll_driver->power(hdev, level) : 0;
 }
 
-void hid_report_raw_event(struct hid_device *hid, int type, u8 *data, int size,
+int hid_report_raw_event(struct hid_device *hid, int type, u8 *data, int size,
                int interrupt);
 
 extern int hid_generic_init(void);
index 4b88e697c4e9b4367a8620b0cd0d2c55ee968dc7..45e9fcb8d8777884e0ecf0c428b3c8015d189f9f 100644 (file)
@@ -76,13 +76,13 @@ struct hidraw_list {
 #ifdef CONFIG_HIDRAW
 int hidraw_init(void);
 void hidraw_exit(void);
-void hidraw_report_event(struct hid_device *, u8 *, int);
+int hidraw_report_event(struct hid_device *, u8 *, int);
 int hidraw_connect(struct hid_device *);
 void hidraw_disconnect(struct hid_device *);
 #else
 static inline int hidraw_init(void) { return 0; }
 static inline void hidraw_exit(void) { }
-static inline void hidraw_report_event(struct hid_device *hid, u8 *data, int len) { }
+static inline int hidraw_report_event(struct hid_device *hid, u8 *data, int len) { return 0; }
 static inline int hidraw_connect(struct hid_device *hid) { return -1; }
 static inline void hidraw_disconnect(struct hid_device *hid) { }
 #endif