]> rtime.felk.cvut.cz Git - linux-imx.git/commitdiff
Merge branch 'upstream' into for-linus
authorJiri Kosina <jkosina@suse.cz>
Tue, 25 Oct 2011 07:59:04 +0000 (09:59 +0200)
committerJiri Kosina <jkosina@suse.cz>
Tue, 25 Oct 2011 07:59:04 +0000 (09:59 +0200)
Conflicts:
drivers/hid/hid-core.c
drivers/hid/hid-ids.h

13 files changed:
drivers/hid/Kconfig
drivers/hid/Makefile
drivers/hid/hid-apple.c
drivers/hid/hid-core.c
drivers/hid/hid-debug.c
drivers/hid/hid-ids.h
drivers/hid/hid-primax.c [new file with mode: 0644]
drivers/hid/hid-prodikeys.c
drivers/hid/hid-sjoy.c
drivers/hid/hid-zydacron.c
drivers/hid/hidraw.c
drivers/hid/usbhid/hid-quirks.c
include/linux/hid.h

index 2b006bfa09358704e07d8923c55aff7f002e6a5f..22a4a051f221e885d647d6db2e0a0f046074efae 100644 (file)
@@ -459,6 +459,13 @@ config HID_PICOLCD_LEDS
        ---help---
          Provide access to PicoLCD's GPO pins via leds class.
 
+config HID_PRIMAX
+       tristate "Primax non-fully HID-compliant devices"
+       depends on USB_HID
+       ---help---
+       Support for Primax devices that are not fully compliant with the
+       HID standard.
+
 config HID_QUANTA
        tristate "Quanta Optical Touch panels"
        depends on USB_HID
@@ -557,7 +564,11 @@ config HID_SMARTJOYPLUS
        tristate "SmartJoy PLUS PS2/USB adapter support"
        depends on USB_HID
        ---help---
-       Support for SmartJoy PLUS PS2/USB adapter.
+       Support for SmartJoy PLUS PS2/USB adapter, Super Dual Box,
+       Super Joy Box 3 Pro, Super Dual Box Pro, and Super Joy Box 5 Pro.
+
+       Note that DDR (Dance Dance Revolution) mode is not supported, nor
+       is pressure sensitive buttons on the pro models.
 
 config SMARTJOYPLUS_FF
        bool "SmartJoy PLUS PS2/USB adapter force feedback support"
index b7ddabb0b34cfd823f94210bd631e6735ba15c7a..1e0d2a638b28d71bdf0f0340e1e4bab062f17a62 100644 (file)
@@ -55,6 +55,7 @@ obj-$(CONFIG_HID_QUANTA)      += hid-quanta.o
 obj-$(CONFIG_HID_PANTHERLORD)  += hid-pl.o
 obj-$(CONFIG_HID_PETALYNX)     += hid-petalynx.o
 obj-$(CONFIG_HID_PICOLCD)      += hid-picolcd.o
+obj-$(CONFIG_HID_PRIMAX)       += hid-primax.o
 obj-$(CONFIG_HID_ROCCAT)       += hid-roccat.o
 obj-$(CONFIG_HID_ROCCAT_COMMON)        += hid-roccat-common.o
 obj-$(CONFIG_HID_ROCCAT_ARVO)  += hid-roccat-arvo.o
index 18b3bc646bf322ee4a7d96f709bc667dd6a85c06..9bc7b03269dfbb130a7a2f8831c0884ce461a3ce 100644 (file)
@@ -183,6 +183,9 @@ static int hidinput_apple_event(struct hid_device *hid, struct input_dev *input,
                if (hid->product >= USB_DEVICE_ID_APPLE_WELLSPRING4_ANSI &&
                                hid->product <= USB_DEVICE_ID_APPLE_WELLSPRING4A_JIS)
                        table = macbookair_fn_keys;
+               else if (hid->product >= USB_DEVICE_ID_APPLE_WELLSPRING6_ANSI &&
+                               hid->product <= USB_DEVICE_ID_APPLE_WELLSPRING6_JIS)
+                       table = macbookair_fn_keys;
                else if (hid->product < 0x21d || hid->product >= 0x300)
                        table = powerbook_fn_keys;
                else
@@ -493,6 +496,18 @@ static const struct hid_device_id apple_devices[] = {
                .driver_data = APPLE_HAS_FN | APPLE_ISO_KEYBOARD },
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING5_JIS),
                .driver_data = APPLE_HAS_FN | APPLE_RDESC_JIS },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING6_ANSI),
+               .driver_data = APPLE_HAS_FN },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING6_ISO),
+               .driver_data = APPLE_HAS_FN | APPLE_ISO_KEYBOARD },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING6_JIS),
+               .driver_data = APPLE_HAS_FN | APPLE_RDESC_JIS },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING6A_ANSI),
+               .driver_data = APPLE_HAS_FN },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING6A_ISO),
+               .driver_data = APPLE_HAS_FN | APPLE_ISO_KEYBOARD },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING6A_JIS),
+               .driver_data = APPLE_HAS_FN | APPLE_RDESC_JIS },
        { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ANSI),
                .driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN },
        { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ISO),
index c5606724b77a0082dfb7d24aa36c8a3d0afe31a5..91adcc5bad284ea6cd28e301a237b554de959bb8 100644 (file)
@@ -29,6 +29,7 @@
 #include <linux/wait.h>
 #include <linux/vmalloc.h>
 #include <linux/sched.h>
+#include <linux/semaphore.h>
 
 #include <linux/hid.h>
 #include <linux/hiddev.h>
@@ -1085,16 +1086,25 @@ int hid_input_report(struct hid_device *hid, int type, u8 *data, int size, int i
        struct hid_report *report;
        char *buf;
        unsigned int i;
-       int ret;
+       int ret = 0;
 
-       if (!hid || !hid->driver)
+       if (!hid)
                return -ENODEV;
+
+       if (down_trylock(&hid->driver_lock))
+               return -EBUSY;
+
+       if (!hid->driver) {
+               ret = -ENODEV;
+               goto unlock;
+       }
        report_enum = hid->report_enum + type;
        hdrv = hid->driver;
 
        if (!size) {
                dbg_hid("empty report\n");
-               return -1;
+               ret = -1;
+               goto unlock;
        }
 
        buf = kmalloc(sizeof(char) * HID_DEBUG_BUFSIZE, GFP_ATOMIC);
@@ -1118,18 +1128,24 @@ int hid_input_report(struct hid_device *hid, int type, u8 *data, int size, int i
 nomem:
        report = hid_get_report(report_enum, data);
 
-       if (!report)
-               return -1;
+       if (!report) {
+               ret = -1;
+               goto unlock;
+       }
 
        if (hdrv && hdrv->raw_event && hid_match_report(hid, report)) {
                ret = hdrv->raw_event(hid, report, data, size);
-               if (ret != 0)
-                       return ret < 0 ? ret : 0;
+               if (ret != 0) {
+                       ret = ret < 0 ? ret : 0;
+                       goto unlock;
+               }
        }
 
        hid_report_raw_event(hid, type, data, size, interrupt);
 
-       return 0;
+unlock:
+       up(&hid->driver_lock);
+       return ret;
 }
 EXPORT_SYMBOL_GPL(hid_input_report);
 
@@ -1349,6 +1365,12 @@ static const struct hid_device_id hid_have_special_driver[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_REVB_ANSI) },
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_REVB_ISO) },
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_REVB_JIS) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING6_ANSI) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING6_ISO) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING6_JIS) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING6A_ANSI) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING6A_ISO) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING6A_JIS) },
        { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ANSI) },
        { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ISO) },
        { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_JIS) },
@@ -1472,6 +1494,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_ORTEK, USB_DEVICE_ID_ORTEK_WKB2000) },
        { HID_USB_DEVICE(USB_VENDOR_ID_PENMOUNT, USB_DEVICE_ID_PENMOUNT_PCI) },
        { HID_USB_DEVICE(USB_VENDOR_ID_PETALYNX, USB_DEVICE_ID_PETALYNX_MAXTER_REMOTE) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_PRIMAX, USB_DEVICE_ID_PRIMAX_KEYBOARD) },
        { HID_USB_DEVICE(USB_VENDOR_ID_QUANTA, USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH) },
        { HID_USB_DEVICE(USB_VENDOR_ID_QUANTA, USB_DEVICE_ID_PIXART_IMAGING_INC_OPTICAL_TOUCH_SCREEN) },
        { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_KONE) },
@@ -1512,6 +1535,10 @@ static const struct hid_device_id hid_have_special_driver[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_UNITEC, USB_DEVICE_ID_UNITEC_USB_TOUCH_0709) },
        { HID_USB_DEVICE(USB_VENDOR_ID_UNITEC, USB_DEVICE_ID_UNITEC_USB_TOUCH_0A19) },
        { HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_SMARTJOY_PLUS) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_DUAL_USB_JOYPAD) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP_LTD, USB_DEVICE_ID_SUPER_JOY_BOX_3_PRO) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP_LTD, USB_DEVICE_ID_SUPER_DUAL_BOX_PRO) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP_LTD, USB_DEVICE_ID_SUPER_JOY_BOX_5_PRO) },
        { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_GRAPHIRE_BLUETOOTH) },
        { HID_USB_DEVICE(USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_SLIM_TABLET_5_8_INCH) },
        { HID_USB_DEVICE(USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_SLIM_TABLET_12_1_INCH) },
@@ -1631,10 +1658,15 @@ static int hid_device_probe(struct device *dev)
        const struct hid_device_id *id;
        int ret = 0;
 
+       if (down_interruptible(&hdev->driver_lock))
+               return -EINTR;
+
        if (!hdev->driver) {
                id = hid_match_device(hdev, hdrv);
-               if (id == NULL)
-                       return -ENODEV;
+               if (id == NULL) {
+                       ret = -ENODEV;
+                       goto unlock;
+               }
 
                hdev->driver = hdrv;
                if (hdrv->probe) {
@@ -1647,14 +1679,20 @@ static int hid_device_probe(struct device *dev)
                if (ret)
                        hdev->driver = NULL;
        }
+unlock:
+       up(&hdev->driver_lock);
        return ret;
 }
 
 static int hid_device_remove(struct device *dev)
 {
        struct hid_device *hdev = container_of(dev, struct hid_device, dev);
-       struct hid_driver *hdrv = hdev->driver;
+       struct hid_driver *hdrv;
+
+       if (down_interruptible(&hdev->driver_lock))
+               return -EINTR;
 
+       hdrv = hdev->driver;
        if (hdrv) {
                if (hdrv->remove)
                        hdrv->remove(hdev);
@@ -1663,6 +1701,7 @@ static int hid_device_remove(struct device *dev)
                hdev->driver = NULL;
        }
 
+       up(&hdev->driver_lock);
        return 0;
 }
 
@@ -1903,6 +1942,12 @@ static const struct hid_device_id hid_mouse_ignore_list[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING5_ANSI) },
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING5_ISO) },
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING5_JIS) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING6_ANSI) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING6_ISO) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING6_JIS) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING6A_ANSI) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING6A_ISO) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING6A_JIS) },
        { 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) },
        { }
@@ -2010,6 +2055,7 @@ struct hid_device *hid_allocate_device(void)
 
        init_waitqueue_head(&hdev->debug_wait);
        INIT_LIST_HEAD(&hdev->debug_list);
+       sema_init(&hdev->driver_lock, 1);
 
        return hdev;
 err:
index bae48745bb4281da2d77ee429882fa52093e60e2..9a243ca96e6db8fbb754b34e16e8c508ee289eab 100644 (file)
@@ -450,6 +450,11 @@ void hid_dump_field(struct hid_field *field, int n, struct seq_file *f) {
                seq_printf(f, "Logical(");
                hid_resolv_usage(field->logical, f); seq_printf(f, ")\n");
        }
+       if (field->application) {
+               tab(n, f);
+               seq_printf(f, "Application(");
+               hid_resolv_usage(field->application, f); seq_printf(f, ")\n");
+       }
        tab(n, f); seq_printf(f, "Usage(%d)\n", field->maxusage);
        for (j = 0; j < field->maxusage; j++) {
                tab(n+2, f); hid_resolv_usage(field->usage[j].hid, f); seq_printf(f, "\n");
index d5dbb1a4f76b2097fcbaf741645d0bb9362622d5..1680e99b4816a8558291293d38dcc43625640e9c 100644 (file)
 #define USB_DEVICE_ID_APPLE_ALU_REVB_ANSI      0x024f
 #define USB_DEVICE_ID_APPLE_ALU_REVB_ISO       0x0250
 #define USB_DEVICE_ID_APPLE_ALU_REVB_JIS       0x0251
+#define USB_DEVICE_ID_APPLE_WELLSPRING6A_ANSI  0x0249
+#define USB_DEVICE_ID_APPLE_WELLSPRING6A_ISO   0x024a
+#define USB_DEVICE_ID_APPLE_WELLSPRING6A_JIS   0x024b
+#define USB_DEVICE_ID_APPLE_WELLSPRING6_ANSI   0x024c
+#define USB_DEVICE_ID_APPLE_WELLSPRING6_ISO    0x024d
+#define USB_DEVICE_ID_APPLE_WELLSPRING6_JIS    0x024e
 #define USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ANSI  0x0239
 #define USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ISO   0x023a
 #define USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_JIS   0x023b
 #define USB_VENDOR_ID_WISEGROUP_LTD    0x6666
 #define USB_VENDOR_ID_WISEGROUP_LTD2   0x6677
 #define USB_DEVICE_ID_SMARTJOY_DUAL_PLUS 0x8802
+#define USB_DEVICE_ID_SUPER_JOY_BOX_3_PRO 0x8801
+#define USB_DEVICE_ID_SUPER_DUAL_BOX_PRO 0x8802
+#define USB_DEVICE_ID_SUPER_JOY_BOX_5_PRO 0x8804
 
 #define USB_VENDOR_ID_X_TENSIONS               0x1ae7
 #define USB_DEVICE_ID_SPEEDLINK_VAD_CEZANNE    0x9001
 #define USB_VENDOR_ID_ZYDACRON 0x13EC
 #define USB_DEVICE_ID_ZYDACRON_REMOTE_CONTROL  0x0006
 
+#define USB_VENDOR_ID_PRIMAX   0x0461
+#define USB_DEVICE_ID_PRIMAX_KEYBOARD  0x4e05
+
 #endif
diff --git a/drivers/hid/hid-primax.c b/drivers/hid/hid-primax.c
new file mode 100644 (file)
index 0000000..4d3c60d
--- /dev/null
@@ -0,0 +1,117 @@
+/*
+ * HID driver for primax and similar keyboards with in-band modifiers
+ *
+ * Copyright 2011 Google Inc. All Rights Reserved
+ *
+ * Author:
+ *     Terry Lambert <tlambert@google.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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.
+ */
+
+#include <linux/device.h>
+#include <linux/hid.h>
+#include <linux/module.h>
+
+#include "hid-ids.h"
+
+static int px_raw_event(struct hid_device *hid, struct hid_report *report,
+        u8 *data, int size)
+{
+       int idx = size;
+
+       switch (report->id) {
+       case 0:         /* keyboard input */
+               /*
+                * Convert in-band modifier key values into out of band
+                * modifier bits and pull the key strokes from the report.
+                * Thus a report data set which looked like:
+                *
+                * [00][00][E0][30][00][00][00][00]
+                * (no modifier bits + "Left Shift" key + "1" key)
+                *
+                * Would be converted to:
+                *
+                * [01][00][00][30][00][00][00][00]
+                * (Left Shift modifier bit + "1" key)
+                *
+                * As long as it's in the size range, the upper level
+                * drivers don't particularly care if there are in-band
+                * 0-valued keys, so they don't stop parsing.
+                */
+               while (--idx > 1) {
+                       if (data[idx] < 0xE0 || data[idx] > 0xE7)
+                               continue;
+                       data[0] |= (1 << (data[idx] - 0xE0));
+                       data[idx] = 0;
+               }
+               hid_report_raw_event(hid, HID_INPUT_REPORT, data, size, 0);
+               return 1;
+
+       default:        /* unknown report */
+               /* Unknown report type; pass upstream */
+               hid_info(hid, "unknown report type %d\n", report->id);
+               break;
+       }
+
+       return 0;
+}
+
+static int px_probe(struct hid_device *hid, const struct hid_device_id *id)
+{
+       int ret;
+
+       ret = hid_parse(hid);
+       if (ret) {
+               hid_err(hid, "parse failed\n");
+               goto fail;
+       }
+
+       ret = hid_hw_start(hid, HID_CONNECT_DEFAULT);
+       if (ret)
+               hid_err(hid, "hw start failed\n");
+
+fail:
+       return ret;
+}
+
+static void px_remove(struct hid_device *hid)
+{
+       hid_hw_stop(hid);
+}
+
+static const struct hid_device_id px_devices[] = {
+       { HID_USB_DEVICE(USB_VENDOR_ID_PRIMAX, USB_DEVICE_ID_PRIMAX_KEYBOARD) },
+       { }
+};
+MODULE_DEVICE_TABLE(hid, px_devices);
+
+static struct hid_driver px_driver = {
+       .name = "primax",
+       .id_table = px_devices,
+       .raw_event = px_raw_event,
+       .probe = px_probe,
+       .remove = px_remove,
+};
+
+static int __init px_init(void)
+{
+       return hid_register_driver(&px_driver);
+}
+
+static void __exit px_exit(void)
+{
+       hid_unregister_driver(&px_driver);
+}
+
+module_init(px_init);
+module_exit(px_exit);
+MODULE_AUTHOR("Terry Lambert <tlambert@google.com>");
+MODULE_LICENSE("GPL");
index 158b389d0fb796156a7f0a8e6ec368cd91c8f875..f779009104eb93f79b29c94d8eef84561d1e468a 100644 (file)
@@ -816,7 +816,7 @@ static int pk_probe(struct hid_device *hdev, const struct hid_device_id *id)
        if (pm == NULL) {
                hid_err(hdev, "can't alloc descriptor\n");
                ret = -ENOMEM;
-               goto err_free;
+               goto err_free_pk;
        }
 
        pm->pk = pk;
@@ -849,10 +849,10 @@ static int pk_probe(struct hid_device *hdev, const struct hid_device_id *id)
 err_stop:
        hid_hw_stop(hdev);
 err_free:
-       if (pm != NULL)
-               kfree(pm);
-
+       kfree(pm);
+err_free_pk:
        kfree(pk);
+
        return ret;
 }
 
index 16f7cafc9695b64377b07c5cca95c5bcea52824d..670da9109f86fa2b5aba02951eda62593a4e7d33 100644 (file)
@@ -65,8 +65,7 @@ static int sjoyff_init(struct hid_device *hid)
 {
        struct sjoyff_device *sjoyff;
        struct hid_report *report;
-       struct hid_input *hidinput = list_entry(hid->inputs.next,
-                                               struct hid_input, list);
+       struct hid_input *hidinput;
        struct list_head *report_list =
                        &hid->report_enum[HID_OUTPUT_REPORT].report_list;
        struct list_head *report_ptr = report_list;
@@ -78,43 +77,45 @@ static int sjoyff_init(struct hid_device *hid)
                return -ENODEV;
        }
 
-       report_ptr = report_ptr->next;
+       list_for_each_entry(hidinput, &hid->inputs, list) {
+               report_ptr = report_ptr->next;
 
-       if (report_ptr == report_list) {
-               hid_err(hid, "required output report is missing\n");
-               return -ENODEV;
-       }
+               if (report_ptr == report_list) {
+                       hid_err(hid, "required output report is missing\n");
+                       return -ENODEV;
+               }
 
-       report = list_entry(report_ptr, struct hid_report, list);
-       if (report->maxfield < 1) {
-               hid_err(hid, "no fields in the report\n");
-               return -ENODEV;
-       }
+               report = list_entry(report_ptr, struct hid_report, list);
+               if (report->maxfield < 1) {
+                       hid_err(hid, "no fields in the report\n");
+                       return -ENODEV;
+               }
 
-       if (report->field[0]->report_count < 3) {
-               hid_err(hid, "not enough values in the field\n");
-               return -ENODEV;
-       }
+               if (report->field[0]->report_count < 3) {
+                       hid_err(hid, "not enough values in the field\n");
+                       return -ENODEV;
+               }
 
-       sjoyff = kzalloc(sizeof(struct sjoyff_device), GFP_KERNEL);
-       if (!sjoyff)
-               return -ENOMEM;
+               sjoyff = kzalloc(sizeof(struct sjoyff_device), GFP_KERNEL);
+               if (!sjoyff)
+                       return -ENOMEM;
 
-       dev = hidinput->input;
+               dev = hidinput->input;
 
-       set_bit(FF_RUMBLE, dev->ffbit);
+               set_bit(FF_RUMBLE, dev->ffbit);
 
-       error = input_ff_create_memless(dev, sjoyff, hid_sjoyff_play);
-       if (error) {
-               kfree(sjoyff);
-               return error;
-       }
+               error = input_ff_create_memless(dev, sjoyff, hid_sjoyff_play);
+               if (error) {
+                       kfree(sjoyff);
+                       return error;
+               }
 
-       sjoyff->report = report;
-       sjoyff->report->field[0]->value[0] = 0x01;
-       sjoyff->report->field[0]->value[1] = 0x00;
-       sjoyff->report->field[0]->value[2] = 0x00;
-       usbhid_submit_report(hid, sjoyff->report, USB_DIR_OUT);
+               sjoyff->report = report;
+               sjoyff->report->field[0]->value[0] = 0x01;
+               sjoyff->report->field[0]->value[1] = 0x00;
+               sjoyff->report->field[0]->value[2] = 0x00;
+               usbhid_submit_report(hid, sjoyff->report, USB_DIR_OUT);
+       }
 
        hid_info(hid, "Force feedback for SmartJoy PLUS PS2/USB adapter\n");
 
@@ -131,6 +132,8 @@ static int sjoy_probe(struct hid_device *hdev, const struct hid_device_id *id)
 {
        int ret;
 
+       hdev->quirks |= id->driver_data;
+
        ret = hid_parse(hdev);
        if (ret) {
                hid_err(hdev, "parse failed\n");
@@ -151,7 +154,17 @@ err:
 }
 
 static const struct hid_device_id sjoy_devices[] = {
+       { HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP_LTD, USB_DEVICE_ID_SUPER_JOY_BOX_3_PRO) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP_LTD, USB_DEVICE_ID_SUPER_DUAL_BOX_PRO),
+               .driver_data = HID_QUIRK_MULTI_INPUT | HID_QUIRK_NOGET |
+                              HID_QUIRK_SKIP_OUTPUT_REPORTS },
+       { HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP_LTD, USB_DEVICE_ID_SUPER_JOY_BOX_5_PRO),
+               .driver_data = HID_QUIRK_MULTI_INPUT | HID_QUIRK_NOGET |
+                              HID_QUIRK_SKIP_OUTPUT_REPORTS },
        { HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_SMARTJOY_PLUS) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_DUAL_USB_JOYPAD),
+               .driver_data = HID_QUIRK_MULTI_INPUT | HID_QUIRK_NOGET |
+                              HID_QUIRK_SKIP_OUTPUT_REPORTS },
        { }
 };
 MODULE_DEVICE_TABLE(hid, sjoy_devices);
index e90371508fd2bf7a205cc56e31d47f1eda1a084e..1ad85f2257b4b46d4c48cd49f883fa95634c17e7 100644 (file)
@@ -201,9 +201,7 @@ static void zc_remove(struct hid_device *hdev)
        struct zc_device *zc = hid_get_drvdata(hdev);
 
        hid_hw_stop(hdev);
-
-       if (NULL != zc)
-               kfree(zc);
+       kfree(zc);
 }
 
 static const struct hid_device_id zc_devices[] = {
index 6d65d4e35120689ea8dd39827c12ed825060af42..cf7d6d58e79f25513dd0baedac00e3ddfd5f342f 100644 (file)
@@ -259,7 +259,6 @@ static int hidraw_open(struct inode *inode, struct file *file)
 
        mutex_lock(&minors_lock);
        if (!hidraw_table[minor]) {
-               kfree(list);
                err = -ENODEV;
                goto out_unlock;
        }
@@ -287,6 +286,8 @@ static int hidraw_open(struct inode *inode, struct file *file)
 out_unlock:
        mutex_unlock(&minors_lock);
 out:
+       if (err < 0)
+               kfree(list);
        return err;
 
 }
index 3146fdcda272cd33f199f13b686d28c092a4921c..4ea464151c3be0d53de577b0aec833136a5d85b5 100644 (file)
@@ -80,10 +80,8 @@ static const struct hid_blacklist {
        { USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_WP8060U, HID_QUIRK_MULTI_INPUT },
        { USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_MEDIA_TABLET_10_6_INCH, HID_QUIRK_MULTI_INPUT },
        { USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_MEDIA_TABLET_14_1_INCH, HID_QUIRK_MULTI_INPUT },
-       { USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_DUAL_USB_JOYPAD, HID_QUIRK_NOGET | HID_QUIRK_MULTI_INPUT | HID_QUIRK_SKIP_OUTPUT_REPORTS },
        { USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_QUAD_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_WISEGROUP_LTD2, USB_DEVICE_ID_SMARTJOY_DUAL_PLUS, HID_QUIRK_NOGET | HID_QUIRK_MULTI_INPUT },
 
        { USB_VENDOR_ID_PI_ENGINEERING, USB_DEVICE_ID_PI_ENGINEERING_VEC_USB_FOOTPEDAL, HID_QUIRK_HIDINPUT_FORCE },
index 6fb743d72bfefadd675f13d58df7e44c828c9431..deed5f9a1e1c5bf4dc73597b33823370b6254550 100644 (file)
@@ -71,6 +71,7 @@
 #include <linux/timer.h>
 #include <linux/workqueue.h>
 #include <linux/input.h>
+#include <linux/semaphore.h>
 
 /*
  * We parse each description item into this structure. Short items data
@@ -476,6 +477,7 @@ struct hid_device {                                                 /* device report descriptor */
        unsigned country;                                               /* HID country */
        struct hid_report_enum report_enum[HID_REPORT_TYPES];
 
+       struct semaphore driver_lock;                                   /* protects the current driver */
        struct device dev;                                              /* device */
        struct hid_driver *driver;
        struct hid_ll_driver *ll_driver;