]> git.kernelconcepts.de Git - karo-tx-linux.git/commitdiff
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jikos/hid
authorLinus Torvalds <torvalds@linux-foundation.org>
Wed, 23 May 2012 02:21:48 +0000 (19:21 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Wed, 23 May 2012 02:21:48 +0000 (19:21 -0700)
Pull HID subsystem updates from Jiri Kosina:
 "Apart from various driver updates and added support for a number of
  new devices (mostly multitouch ones, but not limited to), there is one
  change that is worth pointing out explicitly: creation of HID device
  groups and proper autoloading of hid-multitouch, implemented by Henrik
  Rydberg."

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jikos/hid: (50 commits)
  HID: wacom: fix build breakage without CONFIG_LEDS_CLASS
  HID: waltop: Extend barrel button fix
  HID: hyperv: Set the hid drvdata correctly
  HID: wacom: Unify speed setting
  HID: wacom: Add speed setting for Intuos4 WL
  HID: wacom: Move Graphire raport header check.
  HID: uclogic: Add support for UC-Logic TWHL850
  HID: explain the signed/unsigned handling in hid_add_field()
  HID: handle logical min/max signedness properly in parser
  HID: logitech: read all 32 bits of report type bitfield
  HID: wacom: Add LED selector control for Wacom Intuos4 WL
  HID: hid-multitouch: fix wrong protocol detection
  HID: wiimote: Fix IR data parser
  HID: wacom: Add tilt reporting for Intuos4 WL
  HID: multitouch: MT interface matching for Baanto
  HID: hid-multitouch: Only match MT interfaces
  HID: Create a common generic driver
  HID: hid-multitouch: Switch to device groups
  HID: Create a generic device group
  HID: Allow bus wildcard matching
  ...

29 files changed:
Documentation/ABI/testing/sysfs-driver-wacom
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-generic.c [new file with mode: 0644]
drivers/hid/hid-hyperv.c
drivers/hid/hid-ids.h
drivers/hid/hid-input.c
drivers/hid/hid-lg.c
drivers/hid/hid-lg.h
drivers/hid/hid-lg4ff.c
drivers/hid/hid-logitech-dj.c
drivers/hid/hid-multitouch.c
drivers/hid/hid-uclogic.c
drivers/hid/hid-wacom.c
drivers/hid/hid-waltop.c
drivers/hid/hid-wiimote-core.c
drivers/hid/hidraw.c
drivers/hid/usbhid/hid-core.c
drivers/hid/usbhid/hid-quirks.c
drivers/hid/usbhid/hiddev.c
drivers/hid/usbhid/usbhid.h
include/linux/hid.h
include/linux/hidraw.h
include/linux/mod_devicetable.h
net/bluetooth/hidp/core.c
scripts/mod/file2alias.c

index 0130d6683c14eecf01c3a9b6226aec0549487a81..56c54558c8a48e2163015b441f21aeecf58f950a 100644 (file)
@@ -9,6 +9,14 @@ Description:
                or 0 otherwise. Writing to this file one of these values
                switches reporting speed.
 
+What:          /sys/class/leds/0005\:056A\:00BD.0001\:selector\:*/
+Date:          May 2012
+Kernel Version:        3.5
+Contact:       linux-bluetooth@vger.kernel.org
+Description:
+               LED selector for Intuos4 WL. There are 4 leds, but only one LED
+               can be lit at a time. Max brightness is 127.
+
 What:          /sys/bus/usb/devices/<busnum>-<devnum>:<cfg>.<intf>/wacom_led/led
 Date:          August 2011
 Contact:       linux-input@vger.kernel.org
index ffddcba32af62b637baa09fd9487f515451fca4f..e9c68fedfcff0b90222cf6a48886fe5229f53d94 100644 (file)
@@ -32,9 +32,13 @@ config HID
          If unsure, say Y.
 
 config HID_BATTERY_STRENGTH
-       bool
+       bool "Battery level reporting for HID devices"
        depends on HID && POWER_SUPPLY && HID = POWER_SUPPLY
        default n
+       ---help---
+       This option adds support of reporting battery strength (for HID devices
+       that support this feature) through power_supply class so that userspace
+       tools, such as upower, can display it.
 
 config HIDRAW
        bool "/dev/hidraw raw HID device support"
@@ -60,6 +64,18 @@ source "drivers/hid/usbhid/Kconfig"
 menu "Special HID drivers"
        depends on HID
 
+config HID_GENERIC
+       tristate "Generic HID driver"
+       depends on HID
+       default y
+       ---help---
+       Support for generic HID devices.
+
+       To compile this driver as a module, choose M here: the module
+       will be called hid-generic.
+
+       If unsure, say Y.
+
 config HID_A4TECH
        tristate "A4 tech mice" if EXPERT
        depends on USB_HID
@@ -92,6 +108,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
@@ -595,16 +617,10 @@ config THRUSTMASTER_FF
 config HID_WACOM
        tristate "Wacom Bluetooth devices support"
        depends on BT_HIDP
-       ---help---
-       Support for Wacom Graphire Bluetooth tablet.
-
-config HID_WACOM_POWER_SUPPLY
-       bool "Wacom Bluetooth devices power supply status support"
-       depends on HID_WACOM
+       depends on LEDS_CLASS
        select POWER_SUPPLY
        ---help---
-         Say Y here if you want to enable power supply status monitoring for
-         Wacom Bluetooth devices.
+       Support for Wacom Graphire Bluetooth and Intuos4 WL tablets.
 
 config HID_WIIMOTE
        tristate "Nintendo Wii Remote support"
index 22f1d16cd79c7a680a6983812146459fd76ff1ab..ca6cc9f0485c90d22fb11d0c6deeb6560ac36158 100644 (file)
@@ -9,6 +9,8 @@ endif
 
 obj-$(CONFIG_HID)              += hid.o
 
+obj-$(CONFIG_HID_GENERIC)      += hid-generic.o
+
 hid-$(CONFIG_HIDRAW)           += hidraw.o
 
 hid-logitech-y         := hid-lg.o
@@ -36,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..fa10f847f7dbf163ba5856c296690039ba07b242 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) {
@@ -458,6 +458,9 @@ static const struct hid_device_id apple_devices[] = {
        { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_ISO),
                .driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN |
                        APPLE_ISO_KEYBOARD },
+       { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE,
+                               USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_ANSI),
+               .driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN },
        { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_JIS),
                .driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN },
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING_ANSI),
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 4da66b4b977c334df920200d1ee08d5ec6a1b164..8e3a6b261477d9866ec45c83df4b2766098d281d 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;
        }
 
@@ -546,12 +553,11 @@ static void hid_free_report(struct hid_report *report)
 }
 
 /*
- * Free a device structure, all reports, and all fields.
+ * Close report. This function returns the device
+ * state to the point prior to hid_open_report().
  */
-
-static void hid_device_release(struct device *dev)
+static void hid_close_report(struct hid_device *device)
 {
-       struct hid_device *device = container_of(dev, struct hid_device, dev);
        unsigned i, j;
 
        for (i = 0; i < HID_REPORT_TYPES; i++) {
@@ -562,11 +568,34 @@ static void hid_device_release(struct device *dev)
                        if (report)
                                hid_free_report(report);
                }
+               memset(report_enum, 0, sizeof(*report_enum));
+               INIT_LIST_HEAD(&report_enum->report_list);
        }
 
        kfree(device->rdesc);
+       device->rdesc = NULL;
+       device->rsize = 0;
+
        kfree(device->collection);
-       kfree(device);
+       device->collection = NULL;
+       device->collection_size = 0;
+       device->maxcollection = 0;
+       device->maxapplication = 0;
+
+       device->status &= ~HID_STAT_PARSED;
+}
+
+/*
+ * Free a device structure, all reports, and all fields.
+ */
+
+static void hid_device_release(struct device *dev)
+{
+       struct hid_device *hid = container_of(dev, struct hid_device, dev);
+
+       hid_close_report(hid);
+       kfree(hid->dev_rdesc);
+       kfree(hid);
 }
 
 /*
@@ -636,6 +665,60 @@ static u8 *fetch_item(__u8 *start, __u8 *end, struct hid_item *item)
        return NULL;
 }
 
+static void hid_scan_usage(struct hid_device *hid, u32 usage)
+{
+       if (usage == HID_DG_CONTACTID)
+               hid->group = HID_GROUP_MULTITOUCH;
+}
+
+/*
+ * Scan a report descriptor before the device is added to the bus.
+ * Sets device groups and other properties that determine what driver
+ * to load.
+ */
+static int hid_scan_report(struct hid_device *hid)
+{
+       unsigned int page = 0, delim = 0;
+       __u8 *start = hid->dev_rdesc;
+       __u8 *end = start + hid->dev_rsize;
+       unsigned int u, u_min = 0, u_max = 0;
+       struct hid_item item;
+
+       hid->group = HID_GROUP_GENERIC;
+       while ((start = fetch_item(start, end, &item)) != NULL) {
+               if (item.format != HID_ITEM_FORMAT_SHORT)
+                       return -EINVAL;
+               if (item.type == HID_ITEM_TYPE_GLOBAL) {
+                       if (item.tag == HID_GLOBAL_ITEM_TAG_USAGE_PAGE)
+                               page = item_udata(&item) << 16;
+               } else if (item.type == HID_ITEM_TYPE_LOCAL) {
+                       if (delim > 1)
+                               break;
+                       u = item_udata(&item);
+                       if (item.size <= 2)
+                               u += page;
+                       switch (item.tag) {
+                       case HID_LOCAL_ITEM_TAG_DELIMITER:
+                               delim += !!u;
+                               break;
+                       case HID_LOCAL_ITEM_TAG_USAGE:
+                               hid_scan_usage(hid, u);
+                               break;
+                       case HID_LOCAL_ITEM_TAG_USAGE_MINIMUM:
+                               u_min = u;
+                               break;
+                       case HID_LOCAL_ITEM_TAG_USAGE_MAXIMUM:
+                               u_max = u;
+                               for (u = u_min; u <= u_max; u++)
+                                       hid_scan_usage(hid, u);
+                               break;
+                       }
+               }
+       }
+
+       return 0;
+}
+
 /**
  * hid_parse_report - parse device report
  *
@@ -643,15 +726,37 @@ static u8 *fetch_item(__u8 *start, __u8 *end, struct hid_item *item)
  * @start: report start
  * @size: report size
  *
+ * Allocate the device report as read by the bus driver. This function should
+ * only be called from parse() in ll drivers.
+ */
+int hid_parse_report(struct hid_device *hid, __u8 *start, unsigned size)
+{
+       hid->dev_rdesc = kmemdup(start, size, GFP_KERNEL);
+       if (!hid->dev_rdesc)
+               return -ENOMEM;
+       hid->dev_rsize = size;
+       return 0;
+}
+EXPORT_SYMBOL_GPL(hid_parse_report);
+
+/**
+ * hid_open_report - open a driver-specific device report
+ *
+ * @device: hid device
+ *
  * Parse a report description into a hid_device structure. Reports are
  * enumerated, fields are attached to these reports.
  * 0 returned on success, otherwise nonzero error value.
+ *
+ * This function (or the equivalent hid_parse() macro) should only be
+ * called from probe() in drivers, before starting the device.
  */
-int hid_parse_report(struct hid_device *device, __u8 *start,
-               unsigned size)
+int hid_open_report(struct hid_device *device)
 {
        struct hid_parser *parser;
        struct hid_item item;
+       unsigned int size;
+       __u8 *start;
        __u8 *end;
        int ret;
        static int (*dispatch_type[])(struct hid_parser *parser,
@@ -662,6 +767,14 @@ int hid_parse_report(struct hid_device *device, __u8 *start,
                hid_parser_reserved
        };
 
+       if (WARN_ON(device->status & HID_STAT_PARSED))
+               return -EBUSY;
+
+       start = device->dev_rdesc;
+       if (WARN_ON(!start))
+               return -ENODEV;
+       size = device->dev_rsize;
+
        if (device->driver->report_fixup)
                start = device->driver->report_fixup(device, start, &size);
 
@@ -679,6 +792,15 @@ int hid_parse_report(struct hid_device *device, __u8 *start,
        parser->device = device;
 
        end = start + size;
+
+       device->collection = kcalloc(HID_DEFAULT_NUM_COLLECTIONS,
+                                    sizeof(struct hid_collection), GFP_KERNEL);
+       if (!device->collection) {
+               ret = -ENOMEM;
+               goto err;
+       }
+       device->collection_size = HID_DEFAULT_NUM_COLLECTIONS;
+
        ret = -EINVAL;
        while ((start = fetch_item(start, end, &item)) != NULL) {
 
@@ -704,6 +826,7 @@ int hid_parse_report(struct hid_device *device, __u8 *start,
                                goto err;
                        }
                        vfree(parser);
+                       device->status |= HID_STAT_PARSED;
                        return 0;
                }
        }
@@ -711,9 +834,10 @@ int hid_parse_report(struct hid_device *device, __u8 *start,
        hid_err(device, "item fetching failed at offset %d\n", (int)(end - start));
 err:
        vfree(parser);
+       hid_close_report(device);
        return ret;
 }
-EXPORT_SYMBOL_GPL(hid_parse_report);
+EXPORT_SYMBOL_GPL(hid_open_report);
 
 /*
  * Convert a signed n-bit integer to signed 32-bit integer. Common
@@ -1032,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;
@@ -1040,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++;
@@ -1063,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);
 
@@ -1147,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);
@@ -1158,7 +1288,8 @@ EXPORT_SYMBOL_GPL(hid_input_report);
 static bool hid_match_one_id(struct hid_device *hdev,
                const struct hid_device_id *id)
 {
-       return id->bus == hdev->bus &&
+       return (id->bus == HID_BUS_ANY || id->bus == hdev->bus) &&
+               (id->group == HID_GROUP_ANY || id->group == hdev->group) &&
                (id->vendor == HID_ANY_ID || id->vendor == hdev->vendor) &&
                (id->product == HID_ANY_ID || id->product == hdev->product);
 }
@@ -1234,10 +1365,6 @@ int hid_connect(struct hid_device *hdev, unsigned int connect_mask)
        if ((connect_mask & HID_CONNECT_HIDINPUT) && !hidinput_connect(hdev,
                                connect_mask & HID_CONNECT_HIDINPUT_FORCE))
                hdev->claimed |= HID_CLAIMED_INPUT;
-       if (hdev->quirks & HID_QUIRK_MULTITOUCH) {
-               /* this device should be handled by hid-multitouch, skip it */
-               return -ENODEV;
-       }
 
        if ((connect_mask & HID_CONNECT_HIDDEV) && hdev->hiddev_connect &&
                        !hdev->hiddev_connect(hdev,
@@ -1314,13 +1441,10 @@ EXPORT_SYMBOL_GPL(hid_disconnect);
 
 /* a list of devices for which there is a specialized driver on HID bus */
 static const struct hid_device_id hid_have_special_driver[] = {
-       { HID_USB_DEVICE(USB_VENDOR_ID_3M, USB_DEVICE_ID_3M1968) },
-       { HID_USB_DEVICE(USB_VENDOR_ID_3M, USB_DEVICE_ID_3M2256) },
        { HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_WCP32PU) },
        { HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_X5_005D) },
        { HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_RP_649) },
        { HID_USB_DEVICE(USB_VENDOR_ID_ACRUX, 0x0802) },
-       { HID_USB_DEVICE(USB_VENDOR_ID_ACTIONSTAR, USB_DEVICE_ID_ACTIONSTAR_1011) },
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ATV_IRCONTROL) },
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL4) },
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MIGHTYMOUSE) },
@@ -1385,60 +1509,33 @@ 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_ASUS, USB_DEVICE_ID_ASUS_T91MT) },
-       { HID_USB_DEVICE(USB_VENDOR_ID_ASUS, USB_DEVICE_ID_ASUSTEK_MULTITOUCH_YFO) },
+       { 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_BTC, USB_DEVICE_ID_BTC_EMPREX_REMOTE) },
        { HID_USB_DEVICE(USB_VENDOR_ID_BTC, USB_DEVICE_ID_BTC_EMPREX_REMOTE_2) },
-       { HID_USB_DEVICE(USB_VENDOR_ID_CANDO, USB_DEVICE_ID_CANDO_PIXCIR_MULTI_TOUCH) },
-       { HID_USB_DEVICE(USB_VENDOR_ID_CANDO, USB_DEVICE_ID_CANDO_MULTI_TOUCH) },
-       { HID_USB_DEVICE(USB_VENDOR_ID_CANDO, USB_DEVICE_ID_CANDO_MULTI_TOUCH_10_1) },
-       { HID_USB_DEVICE(USB_VENDOR_ID_CANDO, USB_DEVICE_ID_CANDO_MULTI_TOUCH_11_6) },
-       { HID_USB_DEVICE(USB_VENDOR_ID_CANDO, USB_DEVICE_ID_CANDO_MULTI_TOUCH_15_6) },
        { HID_USB_DEVICE(USB_VENDOR_ID_CHERRY, USB_DEVICE_ID_CHERRY_CYMOTION) },
        { HID_USB_DEVICE(USB_VENDOR_ID_CHERRY, USB_DEVICE_ID_CHERRY_CYMOTION_SOLAR) },
        { HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_TACTICAL_PAD) },
        { HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_WIRELESS) },
        { HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_WIRELESS2) },
-       { HID_USB_DEVICE(USB_VENDOR_ID_CHUNGHWAT, USB_DEVICE_ID_CHUNGHWAT_MULTITOUCH) },
        { HID_USB_DEVICE(USB_VENDOR_ID_CREATIVELABS, USB_DEVICE_ID_PRODIKEYS_PCMIDI) },
-       { HID_USB_DEVICE(USB_VENDOR_ID_CVTOUCH, USB_DEVICE_ID_CVTOUCH_SCREEN) },
        { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_1) },
        { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_2) },
        { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_3) },
        { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_MOUSE) },
-       { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_TRUETOUCH) },
        { HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, 0x0006) },
        { HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, 0x0011) },
-       { HID_USB_DEVICE(USB_VENDOR_ID_DWAV, USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_480D) },
-       { HID_USB_DEVICE(USB_VENDOR_ID_DWAV, USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_480E) },
-       { HID_USB_DEVICE(USB_VENDOR_ID_DWAV, USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_720C) },
-       { HID_USB_DEVICE(USB_VENDOR_ID_DWAV, USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_7224) },
-       { HID_USB_DEVICE(USB_VENDOR_ID_DWAV, USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_725E) },
-       { HID_USB_DEVICE(USB_VENDOR_ID_DWAV, USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_726B) },
-       { HID_USB_DEVICE(USB_VENDOR_ID_DWAV, USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_72A1) },
-       { HID_USB_DEVICE(USB_VENDOR_ID_DWAV, USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_7302) },
-       { HID_USB_DEVICE(USB_VENDOR_ID_DWAV, USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_A001) },
        { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_BM084) },
-       { HID_USB_DEVICE(USB_VENDOR_ID_ELO, USB_DEVICE_ID_ELO_TS2515) },
        { HID_USB_DEVICE(USB_VENDOR_ID_EMS, USB_DEVICE_ID_EMS_TRIO_LINKER_PLUS_II) },
        { HID_USB_DEVICE(USB_VENDOR_ID_EZKEY, USB_DEVICE_ID_BTC_8193) },
-       { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_FRUCTEL, USB_DEVICE_ID_GAMETEL_MT_MODE) },
        { HID_USB_DEVICE(USB_VENDOR_ID_GAMERON, USB_DEVICE_ID_GAMERON_DUAL_PSX_ADAPTOR) },
        { HID_USB_DEVICE(USB_VENDOR_ID_GAMERON, USB_DEVICE_ID_GAMERON_DUAL_PCS_ADAPTOR) },
-       { HID_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH, USB_DEVICE_ID_GENERAL_TOUCH_WIN7_TWOFINGERS) },
-       { HID_USB_DEVICE(USB_VENDOR_ID_GOODTOUCH, USB_DEVICE_ID_GOODTOUCH_000f) },
        { HID_USB_DEVICE(USB_VENDOR_ID_GREENASIA, 0x0003) },
        { HID_USB_DEVICE(USB_VENDOR_ID_GREENASIA, 0x0012) },
        { HID_USB_DEVICE(USB_VENDOR_ID_GYRATION, USB_DEVICE_ID_GYRATION_REMOTE) },
        { HID_USB_DEVICE(USB_VENDOR_ID_GYRATION, USB_DEVICE_ID_GYRATION_REMOTE_2) },
        { HID_USB_DEVICE(USB_VENDOR_ID_GYRATION, USB_DEVICE_ID_GYRATION_REMOTE_3) },
-       { HID_USB_DEVICE(USB_VENDOR_ID_HANVON, USB_DEVICE_ID_HANVON_MULTITOUCH) },
-       { HID_USB_DEVICE(USB_VENDOR_ID_HANVON_ALT, USB_DEVICE_ID_HANVON_ALT_MULTITOUCH) },
-       { HID_USB_DEVICE(USB_VENDOR_ID_IDEACOM, USB_DEVICE_ID_IDEACOM_IDC6650) },
        { HID_USB_DEVICE(USB_VENDOR_ID_HOLTEK, USB_DEVICE_ID_HOLTEK_ON_LINE_GRIP) },
-       { HID_USB_DEVICE(USB_VENDOR_ID_ILITEK, USB_DEVICE_ID_ILITEK_MULTITOUCH) },
-       { HID_USB_DEVICE(USB_VENDOR_ID_IRTOUCHSYSTEMS, USB_DEVICE_ID_IRTOUCH_INFRARED_USB) },
        { HID_USB_DEVICE(USB_VENDOR_ID_KENSINGTON, USB_DEVICE_ID_KS_SLIMBLADE) },
        { HID_USB_DEVICE(USB_VENDOR_ID_KEYTOUCH, USB_DEVICE_ID_KEYTOUCH_IEC) },
        { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_ERGO_525V) },
@@ -1447,7 +1544,6 @@ static const struct hid_device_id hid_have_special_driver[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_EASYPEN_M610X) },
        { HID_USB_DEVICE(USB_VENDOR_ID_LABTEC, USB_DEVICE_ID_LABTEC_WIRELESS_KEYBOARD) },
        { HID_USB_DEVICE(USB_VENDOR_ID_LCPOWER, USB_DEVICE_ID_LCPOWER_LC1000 ) },
-       { HID_USB_DEVICE(USB_VENDOR_ID_LG, USB_DEVICE_ID_LG_MULTITOUCH) },
        { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_MX3000_RECEIVER) },
        { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER) },
        { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER_2) },
@@ -1480,8 +1576,6 @@ static const struct hid_device_id hid_have_special_driver[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD2) },
        { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_SPACETRAVELLER) },
        { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_SPACENAVIGATOR) },
-       { HID_USB_DEVICE(USB_VENDOR_ID_LUMIO, USB_DEVICE_ID_CRYSTALTOUCH) },
-       { HID_USB_DEVICE(USB_VENDOR_ID_LUMIO, USB_DEVICE_ID_CRYSTALTOUCH_DUAL) },
        { HID_USB_DEVICE(USB_VENDOR_ID_MICROCHIP, USB_DEVICE_ID_PICOLCD) },
        { HID_USB_DEVICE(USB_VENDOR_ID_MICROCHIP, USB_DEVICE_ID_PICOLCD_BOOTLOADER) },
        { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_COMFORT_MOUSE_4500) },
@@ -1513,15 +1607,8 @@ static const struct hid_device_id hid_have_special_driver[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_18) },
        { HID_USB_DEVICE(USB_VENDOR_ID_ORTEK, USB_DEVICE_ID_ORTEK_PKB1700) },
        { HID_USB_DEVICE(USB_VENDOR_ID_ORTEK, USB_DEVICE_ID_ORTEK_WKB2000) },
-       { HID_USB_DEVICE(USB_VENDOR_ID_PANASONIC, USB_DEVICE_ID_PANABOARD_UBT780) },
-       { HID_USB_DEVICE(USB_VENDOR_ID_PANASONIC, USB_DEVICE_ID_PANABOARD_UBT880) },
-       { 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_PIXART, USB_DEVICE_ID_PIXART_OPTICAL_TOUCH_SCREEN) },
-       { HID_USB_DEVICE(USB_VENDOR_ID_PIXART, USB_DEVICE_ID_PIXART_OPTICAL_TOUCH_SCREEN1) },
-       { HID_USB_DEVICE(USB_VENDOR_ID_PIXART, USB_DEVICE_ID_PIXART_OPTICAL_TOUCH_SCREEN2) },
        { 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) },
        { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_ARVO) },
@@ -1538,9 +1625,6 @@ static const struct hid_device_id hid_have_special_driver[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_NAVIGATION_CONTROLLER) },
        { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER) },
        { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_VAIO_VGX_MOUSE) },
-       { HID_USB_DEVICE(USB_VENDOR_ID_STANTUM, USB_DEVICE_ID_MTP) },
-       { HID_USB_DEVICE(USB_VENDOR_ID_STANTUM_STM, USB_DEVICE_ID_MTP_STM) },
-       { HID_USB_DEVICE(USB_VENDOR_ID_STANTUM_SITRONIX, USB_DEVICE_ID_MTP_SITRONIX) },
        { HID_USB_DEVICE(USB_VENDOR_ID_SUNPLUS, USB_DEVICE_ID_SUNPLUS_WDESKTOP) },
        { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb300) },
        { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb304) },
@@ -1554,16 +1638,13 @@ static const struct hid_device_id hid_have_special_driver[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_TIVO, USB_DEVICE_ID_TIVO_SLIDE) },
        { HID_USB_DEVICE(USB_VENDOR_ID_TOPSEED, USB_DEVICE_ID_TOPSEED_CYBERLINK) },
        { HID_USB_DEVICE(USB_VENDOR_ID_TOPSEED2, USB_DEVICE_ID_TOPSEED2_RF_COMBO) },
-       { HID_USB_DEVICE(USB_VENDOR_ID_TOUCH_INTL, USB_DEVICE_ID_TOUCH_INTL_MULTI_TOUCH) },
        { HID_USB_DEVICE(USB_VENDOR_ID_TWINHAN, USB_DEVICE_ID_TWINHAN_IR_REMOTE) },
-       { HID_USB_DEVICE(USB_VENDOR_ID_TURBOX, USB_DEVICE_ID_TURBOX_TOUCHSCREEN_MOSART) },
        { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_PF1209) },
        { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_WP4030U) },
        { 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_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_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) },
@@ -1578,16 +1659,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_PID_0038) },
        { HID_USB_DEVICE(USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_MEDIA_TABLET_10_6_INCH) },
        { HID_USB_DEVICE(USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_MEDIA_TABLET_14_1_INCH) },
-       { HID_USB_DEVICE(USB_VENDOR_ID_XAT, USB_DEVICE_ID_XAT_CSR) },
-       { HID_USB_DEVICE(USB_VENDOR_ID_XIROKU, USB_DEVICE_ID_XIROKU_SPX) },
-       { HID_USB_DEVICE(USB_VENDOR_ID_XIROKU, USB_DEVICE_ID_XIROKU_MPX) },
-       { HID_USB_DEVICE(USB_VENDOR_ID_XIROKU, USB_DEVICE_ID_XIROKU_CSR) },
-       { HID_USB_DEVICE(USB_VENDOR_ID_XIROKU, USB_DEVICE_ID_XIROKU_SPX1) },
-       { HID_USB_DEVICE(USB_VENDOR_ID_XIROKU, USB_DEVICE_ID_XIROKU_MPX1) },
-       { HID_USB_DEVICE(USB_VENDOR_ID_XIROKU, USB_DEVICE_ID_XIROKU_CSR1) },
-       { HID_USB_DEVICE(USB_VENDOR_ID_XIROKU, USB_DEVICE_ID_XIROKU_SPX2) },
-       { HID_USB_DEVICE(USB_VENDOR_ID_XIROKU, USB_DEVICE_ID_XIROKU_MPX2) },
-       { HID_USB_DEVICE(USB_VENDOR_ID_XIROKU, USB_DEVICE_ID_XIROKU_CSR2) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_SIRIUS_BATTERY_FREE_TABLET) },
        { HID_USB_DEVICE(USB_VENDOR_ID_X_TENSIONS, USB_DEVICE_ID_SPEEDLINK_VAD_CEZANNE) },
        { HID_USB_DEVICE(USB_VENDOR_ID_ZEROPLUS, 0x0005) },
        { HID_USB_DEVICE(USB_VENDOR_ID_ZEROPLUS, 0x0030) },
@@ -1631,6 +1703,7 @@ static ssize_t store_new_id(struct device_driver *drv, const char *buf,
                return -ENOMEM;
 
        dynid->id.bus = bus;
+       dynid->id.group = HID_GROUP_ANY;
        dynid->id.vendor = vendor;
        dynid->id.product = product;
        dynid->id.driver_data = driver_data;
@@ -1679,18 +1752,7 @@ static int hid_bus_match(struct device *dev, struct device_driver *drv)
        struct hid_driver *hdrv = container_of(drv, struct hid_driver, driver);
        struct hid_device *hdev = container_of(dev, struct hid_device, dev);
 
-       if ((hdev->quirks & HID_QUIRK_MULTITOUCH) &&
-               !strncmp(hdrv->name, "hid-multitouch", 14))
-               return 1;
-
-       if (!hid_match_device(hdev, hdrv))
-               return 0;
-
-       /* generic wants all that don't have specialized driver */
-       if (!strncmp(hdrv->name, "generic-", 8) && !hid_ignore_special_drivers)
-               return !hid_match_id(hdev, hid_have_special_driver);
-
-       return 1;
+       return hid_match_device(hdev, hdrv) != NULL;
 }
 
 static int hid_device_probe(struct device *dev)
@@ -1707,23 +1769,22 @@ static int hid_device_probe(struct device *dev)
        if (!hdev->driver) {
                id = hid_match_device(hdev, hdrv);
                if (id == NULL) {
-                       if (!((hdev->quirks & HID_QUIRK_MULTITOUCH) &&
-                               !strncmp(hdrv->name, "hid-multitouch", 14))) {
-                               ret = -ENODEV;
-                               goto unlock;
-                       }
+                       ret = -ENODEV;
+                       goto unlock;
                }
 
                hdev->driver = hdrv;
                if (hdrv->probe) {
                        ret = hdrv->probe(hdev, id);
                } else { /* default probe */
-                       ret = hid_parse(hdev);
+                       ret = hid_open_report(hdev);
                        if (!ret)
                                ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
                }
-               if (ret)
+               if (ret) {
+                       hid_close_report(hdev);
                        hdev->driver = NULL;
+               }
        }
 unlock:
        up(&hdev->driver_lock);
@@ -1744,6 +1805,7 @@ static int hid_device_remove(struct device *dev)
                        hdrv->remove(hdev);
                else /* default remove */
                        hid_hw_stop(hdev);
+               hid_close_report(hdev);
                hdev->driver = NULL;
        }
 
@@ -1751,6 +1813,23 @@ static int hid_device_remove(struct device *dev)
        return 0;
 }
 
+static ssize_t modalias_show(struct device *dev, struct device_attribute *a,
+                            char *buf)
+{
+       struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+       int len;
+
+       len = snprintf(buf, PAGE_SIZE, "hid:b%04Xg%04Xv%08Xp%08X\n",
+                      hdev->bus, hdev->group, hdev->vendor, hdev->product);
+
+       return (len >= PAGE_SIZE) ? (PAGE_SIZE - 1) : len;
+}
+
+static struct device_attribute hid_dev_attrs[] = {
+       __ATTR_RO(modalias),
+       __ATTR_NULL,
+};
+
 static int hid_uevent(struct device *dev, struct kobj_uevent_env *env)
 {
        struct hid_device *hdev = container_of(dev, struct hid_device, dev);
@@ -1768,8 +1847,8 @@ static int hid_uevent(struct device *dev, struct kobj_uevent_env *env)
        if (add_uevent_var(env, "HID_UNIQ=%s", hdev->uniq))
                return -ENOMEM;
 
-       if (add_uevent_var(env, "MODALIAS=hid:b%04Xv%08Xp%08X",
-                       hdev->bus, hdev->vendor, hdev->product))
+       if (add_uevent_var(env, "MODALIAS=hid:b%04Xg%04Xv%08Xp%08X",
+                          hdev->bus, hdev->group, hdev->vendor, hdev->product))
                return -ENOMEM;
 
        return 0;
@@ -1777,6 +1856,7 @@ static int hid_uevent(struct device *dev, struct kobj_uevent_env *env)
 
 static struct bus_type hid_bus_type = {
        .name           = "hid",
+       .dev_attrs      = hid_dev_attrs,
        .match          = hid_bus_match,
        .probe          = hid_device_probe,
        .remove         = hid_device_remove,
@@ -2075,6 +2155,26 @@ int hid_add_device(struct hid_device *hdev)
             && (hid_ignore(hdev) || (hdev->quirks & HID_QUIRK_IGNORE)))
                return -ENODEV;
 
+       /*
+        * Read the device report descriptor once and use as template
+        * for the driver-specific modifications.
+        */
+       ret = hdev->ll_driver->parse(hdev);
+       if (ret)
+               return ret;
+       if (!hdev->dev_rdesc)
+               return -ENODEV;
+
+       /*
+        * Scan generic devices for group information
+        */
+       if (hid_ignore_special_drivers ||
+           !hid_match_id(hdev, hid_have_special_driver)) {
+               ret = hid_scan_report(hdev);
+               if (ret)
+                       hid_warn(hdev, "bad device descriptor (%d)\n", ret);
+       }
+
        /* XXX hack, any other cleaner solution after the driver core
         * is converted to allow more than 20 bytes as the device name? */
        dev_set_name(&hdev->dev, "%04X:%04X:%04X.%04X", hdev->bus,
@@ -2103,7 +2203,6 @@ EXPORT_SYMBOL_GPL(hid_add_device);
 struct hid_device *hid_allocate_device(void)
 {
        struct hid_device *hdev;
-       unsigned int i;
        int ret = -ENOMEM;
 
        hdev = kzalloc(sizeof(*hdev), GFP_KERNEL);
@@ -2114,23 +2213,13 @@ struct hid_device *hid_allocate_device(void)
        hdev->dev.release = hid_device_release;
        hdev->dev.bus = &hid_bus_type;
 
-       hdev->collection = kcalloc(HID_DEFAULT_NUM_COLLECTIONS,
-                       sizeof(struct hid_collection), GFP_KERNEL);
-       if (hdev->collection == NULL)
-               goto err;
-       hdev->collection_size = HID_DEFAULT_NUM_COLLECTIONS;
-
-       for (i = 0; i < HID_REPORT_TYPES; i++)
-               INIT_LIST_HEAD(&hdev->report_enum[i].report_list);
+       hid_close_report(hdev);
 
        init_waitqueue_head(&hdev->debug_wait);
        INIT_LIST_HEAD(&hdev->debug_list);
        sema_init(&hdev->driver_lock, 1);
 
        return hdev;
-err:
-       put_device(&hdev->dev);
-       return ERR_PTR(ret);
 }
 EXPORT_SYMBOL_GPL(hid_allocate_device);
 
@@ -2141,6 +2230,9 @@ static void hid_remove_device(struct hid_device *hdev)
                hid_debug_unregister(hdev);
                hdev->status &= ~HID_STAT_ADDED;
        }
+       kfree(hdev->dev_rdesc);
+       hdev->dev_rdesc = NULL;
+       hdev->dev_rsize = 0;
 }
 
 /**
diff --git a/drivers/hid/hid-generic.c b/drivers/hid/hid-generic.c
new file mode 100644 (file)
index 0000000..a8b3148
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ *  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) 2007-2008 Oliver Neukum
+ *  Copyright (c) 2006-2012 Jiri Kosina
+ *  Copyright (c) 2012 Henrik Rydberg
+ */
+
+/*
+ * 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/kernel.h>
+#include <asm/unaligned.h>
+#include <asm/byteorder.h>
+
+#include <linux/hid.h>
+
+static const struct hid_device_id hid_table[] = {
+       { HID_DEVICE(HID_BUS_ANY, HID_GROUP_GENERIC, HID_ANY_ID, HID_ANY_ID) },
+       { }
+};
+MODULE_DEVICE_TABLE(hid, hid_table);
+
+static struct hid_driver hid_generic = {
+       .name = "hid-generic",
+       .id_table = hid_table,
+};
+
+static int __init hid_init(void)
+{
+       return hid_register_driver(&hid_generic);
+}
+
+static void __exit hid_exit(void)
+{
+       hid_unregister_driver(&hid_generic);
+}
+
+module_init(hid_init);
+module_exit(hid_exit);
+
+MODULE_AUTHOR("Henrik Rydberg");
+MODULE_DESCRIPTION("HID generic driver");
+MODULE_LICENSE("GPL");
index 406632472c1bb038cdf06dae37c7f115f479e94a..3d62781b89939126f856e69bee44e1f496e40185 100644 (file)
@@ -430,6 +430,15 @@ cleanup:
        return ret;
 }
 
+static int mousevsc_hid_parse(struct hid_device *hid)
+{
+       struct hv_device *dev = hid_get_drvdata(hid);
+       struct mousevsc_dev *input_dev = hv_get_drvdata(dev);
+
+       return hid_parse_report(hid, input_dev->report_desc,
+                               input_dev->report_desc_size);
+}
+
 static int mousevsc_hid_open(struct hid_device *hid)
 {
        return 0;
@@ -449,6 +458,7 @@ static void mousevsc_hid_stop(struct hid_device *hid)
 }
 
 static struct hid_ll_driver mousevsc_ll_driver = {
+       .parse = mousevsc_hid_parse,
        .open = mousevsc_hid_open,
        .close = mousevsc_hid_close,
        .start = mousevsc_hid_start,
@@ -506,13 +516,14 @@ static int mousevsc_probe(struct hv_device *device,
 
        sprintf(hid_dev->name, "%s", "Microsoft Vmbus HID-compliant Mouse");
 
+       hid_set_drvdata(hid_dev, device);
+
        ret = hid_add_device(hid_dev);
        if (ret)
                goto probe_err1;
 
-       ret = hid_parse_report(hid_dev, input_dev->report_desc,
-                               input_dev->report_desc_size);
 
+       ret = hid_parse(hid_dev);
        if (ret) {
                hid_err(hid_dev, "parse failed\n");
                goto probe_err2;
index e39aecb1f9f28def0a0490a3de0ef29021f49ede..9373f535dfe9908c14b8ff04afbe90a981693a54 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_VENDOR_ID_BAANTO           0x2453
+#define USB_DEVICE_ID_BAANTO_MT_190W2  0x0100
+
 #define USB_VENDOR_ID_BELKIN           0x050d
 #define USB_DEVICE_ID_FLIP_KVM         0x3201
 
 #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
 #define USB_DEVICE_ID_WALTOP_PID_0038                  0x0038
 #define USB_DEVICE_ID_WALTOP_MEDIA_TABLET_10_6_INCH    0x0501
 #define USB_DEVICE_ID_WALTOP_MEDIA_TABLET_14_1_INCH    0x0500
+#define USB_DEVICE_ID_WALTOP_SIRIUS_BATTERY_FREE_TABLET        0x0502
 
 #define USB_VENDOR_ID_WISEGROUP                0x0925
 #define USB_DEVICE_ID_SMARTJOY_PLUS    0x0005
index 002781c5a6164040e90a6a5bab40ed982e50b508..132b0019365eed9057eeaaf0a3b222eece0853ad 100644 (file)
@@ -225,7 +225,10 @@ static __s32 hidinput_calc_abs_res(const struct hid_field *field, __u16 code)
         * Verify and convert units.
         * See HID specification v1.11 6.2.2.7 Global Items for unit decoding
         */
-       if (code == ABS_X || code == ABS_Y || code == ABS_Z) {
+       switch (code) {
+       case ABS_X:
+       case ABS_Y:
+       case ABS_Z:
                if (field->unit == 0x11) {              /* If centimeters */
                        /* Convert to millimeters */
                        unit_exponent += 1;
@@ -239,7 +242,13 @@ static __s32 hidinput_calc_abs_res(const struct hid_field *field, __u16 code)
                } else {
                        return 0;
                }
-       } else if (code == ABS_RX || code == ABS_RY || code == ABS_RZ) {
+               break;
+
+       case ABS_RX:
+       case ABS_RY:
+       case ABS_RZ:
+       case ABS_TILT_X:
+       case ABS_TILT_Y:
                if (field->unit == 0x14) {              /* If degrees */
                        /* Convert to radians */
                        prev = logical_extents;
@@ -250,7 +259,9 @@ static __s32 hidinput_calc_abs_res(const struct hid_field *field, __u16 code)
                } else if (field->unit != 0x12) {       /* If not radians */
                        return 0;
                }
-       } else {
+               break;
+
+       default:
                return 0;
        }
 
@@ -623,6 +634,14 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
                        map_key_clear(BTN_TOOL_RUBBER);
                        break;
 
+               case 0x3d: /* X Tilt */
+                       map_abs_clear(ABS_TILT_X);
+                       break;
+
+               case 0x3e: /* Y Tilt */
+                       map_abs_clear(ABS_TILT_Y);
+                       break;
+
                case 0x33: /* Touch */
                case 0x42: /* TipSwitch */
                case 0x43: /* TipSwitch2 */
@@ -638,10 +657,6 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
                        map_key_clear(BTN_STYLUS2);
                        break;
 
-               case 0x51: /* ContactID */
-                       device->quirks |= HID_QUIRK_MULTITOUCH;
-                       goto unknown;
-
                default:  goto unknown;
                }
                break;
@@ -1208,13 +1223,6 @@ int hidinput_connect(struct hid_device *hid, unsigned int force)
                }
        }
 
-       if (hid->quirks & HID_QUIRK_MULTITOUCH) {
-               /* generic hid does not know how to handle multitouch devices */
-               if (hidinput)
-                       goto out_cleanup;
-               goto out_unwind;
-       }
-
        if (hidinput && input_register_device(hidinput->input))
                goto out_cleanup;
 
index e7a7bd1eb34a55c9f200d92d983148ea6e317a70..fc37ed6b108cabd826c2b14b14ba59ea1d078359 100644 (file)
@@ -109,23 +109,23 @@ static __u8 dfp_rdesc_fixed[] = {
 static __u8 *lg_report_fixup(struct hid_device *hdev, __u8 *rdesc,
                unsigned int *rsize)
 {
-       unsigned long quirks = (unsigned long)hid_get_drvdata(hdev);
+       struct lg_drv_data *drv_data = (struct lg_drv_data *)hid_get_drvdata(hdev);
 
-       if ((quirks & LG_RDESC) && *rsize >= 90 && rdesc[83] == 0x26 &&
+       if ((drv_data->quirks & LG_RDESC) && *rsize >= 90 && rdesc[83] == 0x26 &&
                        rdesc[84] == 0x8c && rdesc[85] == 0x02) {
                hid_info(hdev,
                         "fixing up Logitech keyboard report descriptor\n");
                rdesc[84] = rdesc[89] = 0x4d;
                rdesc[85] = rdesc[90] = 0x10;
        }
-       if ((quirks & LG_RDESC_REL_ABS) && *rsize >= 50 &&
+       if ((drv_data->quirks & LG_RDESC_REL_ABS) && *rsize >= 50 &&
                        rdesc[32] == 0x81 && rdesc[33] == 0x06 &&
                        rdesc[49] == 0x81 && rdesc[50] == 0x06) {
                hid_info(hdev,
                         "fixing up rel/abs in Logitech report descriptor\n");
                rdesc[33] = rdesc[50] = 0x02;
        }
-       if ((quirks & LG_FF4) && *rsize >= 101 &&
+       if ((drv_data->quirks & LG_FF4) && *rsize >= 101 &&
                        rdesc[41] == 0x95 && rdesc[42] == 0x0B &&
                        rdesc[47] == 0x05 && rdesc[48] == 0x09) {
                hid_info(hdev, "fixing up Logitech Speed Force Wireless button descriptor\n");
@@ -278,7 +278,7 @@ static int lg_input_mapping(struct hid_device *hdev, struct hid_input *hi,
                  0,  0,  0,  0,  0,183,184,185,186,187,
                188,189,190,191,192,193,194,  0,  0,  0
        };
-       unsigned long quirks = (unsigned long)hid_get_drvdata(hdev);
+       struct lg_drv_data *drv_data = (struct lg_drv_data *)hid_get_drvdata(hdev);
        unsigned int hid = usage->hid;
 
        if (hdev->product == USB_DEVICE_ID_LOGITECH_RECEIVER &&
@@ -289,7 +289,7 @@ static int lg_input_mapping(struct hid_device *hdev, struct hid_input *hi,
                        lg_dinovo_mapping(hi, usage, bit, max))
                return 1;
 
-       if ((quirks & LG_WIRELESS) && lg_wireless_mapping(hi, usage, bit, max))
+       if ((drv_data->quirks & LG_WIRELESS) && lg_wireless_mapping(hi, usage, bit, max))
                return 1;
 
        if ((hid & HID_USAGE_PAGE) != HID_UP_BUTTON)
@@ -299,11 +299,11 @@ static int lg_input_mapping(struct hid_device *hdev, struct hid_input *hi,
 
        /* Special handling for Logitech Cordless Desktop */
        if (field->application == HID_GD_MOUSE) {
-               if ((quirks & LG_IGNORE_DOUBLED_WHEEL) &&
+               if ((drv_data->quirks & LG_IGNORE_DOUBLED_WHEEL) &&
                                (hid == 7 || hid == 8))
                        return -1;
        } else {
-               if ((quirks & LG_EXPANDED_KEYMAP) &&
+               if ((drv_data->quirks & LG_EXPANDED_KEYMAP) &&
                                hid < ARRAY_SIZE(e_keymap) &&
                                e_keymap[hid] != 0) {
                        hid_map_usage(hi, usage, bit, max, EV_KEY,
@@ -319,13 +319,13 @@ static int lg_input_mapped(struct hid_device *hdev, struct hid_input *hi,
                struct hid_field *field, struct hid_usage *usage,
                unsigned long **bit, int *max)
 {
-       unsigned long quirks = (unsigned long)hid_get_drvdata(hdev);
+       struct lg_drv_data *drv_data = (struct lg_drv_data *)hid_get_drvdata(hdev);
 
-       if ((quirks & LG_BAD_RELATIVE_KEYS) && usage->type == EV_KEY &&
+       if ((drv_data->quirks & LG_BAD_RELATIVE_KEYS) && usage->type == EV_KEY &&
                        (field->flags & HID_MAIN_ITEM_RELATIVE))
                field->flags &= ~HID_MAIN_ITEM_RELATIVE;
 
-       if ((quirks & LG_DUPLICATE_USAGES) && (usage->type == EV_KEY ||
+       if ((drv_data->quirks & LG_DUPLICATE_USAGES) && (usage->type == EV_KEY ||
                         usage->type == EV_REL || usage->type == EV_ABS))
                clear_bit(usage->code, *bit);
 
@@ -335,9 +335,9 @@ static int lg_input_mapped(struct hid_device *hdev, struct hid_input *hi,
 static int lg_event(struct hid_device *hdev, struct hid_field *field,
                struct hid_usage *usage, __s32 value)
 {
-       unsigned long quirks = (unsigned long)hid_get_drvdata(hdev);
+       struct lg_drv_data *drv_data = (struct lg_drv_data *)hid_get_drvdata(hdev);
 
-       if ((quirks & LG_INVERT_HWHEEL) && usage->code == REL_HWHEEL) {
+       if ((drv_data->quirks & LG_INVERT_HWHEEL) && usage->code == REL_HWHEEL) {
                input_event(field->hidinput->input, usage->type, usage->code,
                                -value);
                return 1;
@@ -348,13 +348,20 @@ static int lg_event(struct hid_device *hdev, struct hid_field *field,
 
 static int lg_probe(struct hid_device *hdev, const struct hid_device_id *id)
 {
-       unsigned long quirks = id->driver_data;
        unsigned int connect_mask = HID_CONNECT_DEFAULT;
+       struct lg_drv_data *drv_data;
        int ret;
 
-       hid_set_drvdata(hdev, (void *)quirks);
+       drv_data = kzalloc(sizeof(struct lg_drv_data), GFP_KERNEL);
+       if (!drv_data) {
+               hid_err(hdev, "Insufficient memory, cannot allocate driver data\n");
+               return -ENOMEM;
+       }
+       drv_data->quirks = id->driver_data;
+       
+       hid_set_drvdata(hdev, (void *)drv_data);
 
-       if (quirks & LG_NOGET)
+       if (drv_data->quirks & LG_NOGET)
                hdev->quirks |= HID_QUIRK_NOGET;
 
        ret = hid_parse(hdev);
@@ -363,7 +370,7 @@ static int lg_probe(struct hid_device *hdev, const struct hid_device_id *id)
                goto err_free;
        }
 
-       if (quirks & (LG_FF | LG_FF2 | LG_FF3 | LG_FF4))
+       if (drv_data->quirks & (LG_FF | LG_FF2 | LG_FF3 | LG_FF4))
                connect_mask &= ~HID_CONNECT_FF;
 
        ret = hid_hw_start(hdev, connect_mask);
@@ -392,27 +399,29 @@ static int lg_probe(struct hid_device *hdev, const struct hid_device_id *id)
                }
        }
 
-       if (quirks & LG_FF)
+       if (drv_data->quirks & LG_FF)
                lgff_init(hdev);
-       if (quirks & LG_FF2)
+       if (drv_data->quirks & LG_FF2)
                lg2ff_init(hdev);
-       if (quirks & LG_FF3)
+       if (drv_data->quirks & LG_FF3)
                lg3ff_init(hdev);
-       if (quirks & LG_FF4)
+       if (drv_data->quirks & LG_FF4)
                lg4ff_init(hdev);
 
        return 0;
 err_free:
+       kfree(drv_data);
        return ret;
 }
 
 static void lg_remove(struct hid_device *hdev)
 {
-       unsigned long quirks = (unsigned long)hid_get_drvdata(hdev);
-       if(quirks & LG_FF4)
+       struct lg_drv_data *drv_data = (struct lg_drv_data *)hid_get_drvdata(hdev);
+       if (drv_data->quirks & LG_FF4)
                lg4ff_deinit(hdev);
 
        hid_hw_stop(hdev);
+       kfree(drv_data);
 }
 
 static const struct hid_device_id lg_devices[] = {
index 4b097286dc789ab009b1df11630954d0f4d9631f..d64cf8d2751e51033b77a58b852dd1ba7ecc7e04 100644 (file)
@@ -1,6 +1,11 @@
 #ifndef __HID_LG_H
 #define __HID_LG_H
 
+struct lg_drv_data {
+       unsigned long quirks;
+       void *device_props;     /* Device specific properties */
+};
+
 #ifdef CONFIG_LOGITECH_FF
 int lgff_init(struct hid_device *hdev);
 #else
index 6ecc9e2204409c1451e90086a4edd7f0639cdb01..f3390ee6105caec4593b7a5482a771b6d38a7129 100644 (file)
@@ -1,7 +1,8 @@
 /*
- *  Force feedback support for Logitech Speed Force Wireless
+ *  Force feedback support for Logitech Gaming Wheels
  *
- *  http://wiibrew.org/wiki/Logitech_USB_steering_wheel
+ *  Including G27, G25, DFP, DFGT, FFEX, Momo, Momo2 &
+ *  Speed Force Wireless (WiiWheel)
  *
  *  Copyright (c) 2010 Simon Wood <simon@mungewell.org>
  */
@@ -51,20 +52,18 @@ static ssize_t lg4ff_range_store(struct device *dev, struct device_attribute *at
 
 static DEVICE_ATTR(range, S_IRWXU | S_IRWXG | S_IRWXO, lg4ff_range_show, lg4ff_range_store);
 
-static bool list_inited;
-
 struct lg4ff_device_entry {
-       char  *device_id;       /* Use name in respective kobject structure's address as the ID */
        __u16 range;
        __u16 min_range;
        __u16 max_range;
-       __u8  leds;
+#ifdef CONFIG_LEDS_CLASS
+       __u8  led_state;
+       struct led_classdev *led[5];
+#endif
        struct list_head list;
        void (*set_range)(struct hid_device *hid, u16 range);
 };
 
-static struct lg4ff_device_entry device_list;
-
 static const signed short lg4ff_wheel_effects[] = {
        FF_CONSTANT,
        FF_AUTOCENTER,
@@ -285,18 +284,20 @@ static void hid_lg4ff_switch_native(struct hid_device *hid, const struct lg4ff_n
 /* Read current range and display it in terminal */
 static ssize_t lg4ff_range_show(struct device *dev, struct device_attribute *attr, char *buf)
 {
-       struct lg4ff_device_entry *uninitialized_var(entry);
-       struct list_head *h;
        struct hid_device *hid = to_hid_device(dev);
+       struct lg4ff_device_entry *entry;
+       struct lg_drv_data *drv_data;
        size_t count;
 
-       list_for_each(h, &device_list.list) {
-               entry = list_entry(h, struct lg4ff_device_entry, list);
-               if (strcmp(entry->device_id, (&hid->dev)->kobj.name) == 0)
-                       break;
+       drv_data = hid_get_drvdata(hid);
+       if (!drv_data) {
+               hid_err(hid, "Private driver data not found!\n");
+               return 0;
        }
-       if (h == &device_list.list) {
-               dbg_hid("Device not found!");
+
+       entry = drv_data->device_props;
+       if (!entry) {
+               hid_err(hid, "Device properties not found!\n");
                return 0;
        }
 
@@ -308,19 +309,21 @@ static ssize_t lg4ff_range_show(struct device *dev, struct device_attribute *att
  * according to the type of the wheel */
 static ssize_t lg4ff_range_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
 {
-       struct lg4ff_device_entry *uninitialized_var(entry);
-       struct list_head *h;
        struct hid_device *hid = to_hid_device(dev);
+       struct lg4ff_device_entry *entry;
+       struct lg_drv_data *drv_data;
        __u16 range = simple_strtoul(buf, NULL, 10);
 
-       list_for_each(h, &device_list.list) {
-               entry = list_entry(h, struct lg4ff_device_entry, list);
-               if (strcmp(entry->device_id, (&hid->dev)->kobj.name) == 0)
-                       break;
+       drv_data = hid_get_drvdata(hid);
+       if (!drv_data) {
+               hid_err(hid, "Private driver data not found!\n");
+               return 0;
        }
-       if (h == &device_list.list) {
-               dbg_hid("Device not found!");
-               return count;
+
+       entry = drv_data->device_props;
+       if (!entry) {
+               hid_err(hid, "Device properties not found!\n");
+               return 0;
        }
 
        if (range == 0)
@@ -336,6 +339,88 @@ static ssize_t lg4ff_range_store(struct device *dev, struct device_attribute *at
        return count;
 }
 
+#ifdef CONFIG_LEDS_CLASS
+static void lg4ff_set_leds(struct hid_device *hid, __u8 leds)
+{
+       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);
+
+       report->field[0]->value[0] = 0xf8;
+       report->field[0]->value[1] = 0x12;
+       report->field[0]->value[2] = leds;
+       report->field[0]->value[3] = 0x00;
+       report->field[0]->value[4] = 0x00;
+       report->field[0]->value[5] = 0x00;
+       report->field[0]->value[6] = 0x00;
+       usbhid_submit_report(hid, report, USB_DIR_OUT);
+}
+
+static void lg4ff_led_set_brightness(struct led_classdev *led_cdev,
+                       enum led_brightness value)
+{
+       struct device *dev = led_cdev->dev->parent;
+       struct hid_device *hid = container_of(dev, struct hid_device, dev);
+       struct lg_drv_data *drv_data = (struct lg_drv_data *)hid_get_drvdata(hid);
+       struct lg4ff_device_entry *entry;
+       int i, state = 0;
+
+       if (!drv_data) {
+               hid_err(hid, "Device data not found.");
+               return;
+       }
+
+       entry = (struct lg4ff_device_entry *)drv_data->device_props;
+
+       if (!entry) {
+               hid_err(hid, "Device properties not found.");
+               return;
+       }
+
+       for (i = 0; i < 5; i++) {
+               if (led_cdev != entry->led[i])
+                       continue;
+               state = (entry->led_state >> i) & 1;
+               if (value == LED_OFF && state) {
+                       entry->led_state &= ~(1 << i);
+                       lg4ff_set_leds(hid, entry->led_state);
+               } else if (value != LED_OFF && !state) {
+                       entry->led_state |= 1 << i;
+                       lg4ff_set_leds(hid, entry->led_state);
+               }
+               break;
+       }
+}
+
+static enum led_brightness lg4ff_led_get_brightness(struct led_classdev *led_cdev)
+{
+       struct device *dev = led_cdev->dev->parent;
+       struct hid_device *hid = container_of(dev, struct hid_device, dev);
+       struct lg_drv_data *drv_data = (struct lg_drv_data *)hid_get_drvdata(hid);
+       struct lg4ff_device_entry *entry;
+       int i, value = 0;
+
+       if (!drv_data) {
+               hid_err(hid, "Device data not found.");
+               return LED_OFF;
+       }
+
+       entry = (struct lg4ff_device_entry *)drv_data->device_props;
+
+       if (!entry) {
+               hid_err(hid, "Device properties not found.");
+               return LED_OFF;
+       }
+
+       for (i = 0; i < 5; i++)
+               if (led_cdev == entry->led[i]) {
+                       value = (entry->led_state >> i) & 1;
+                       break;
+               }
+
+       return value ? LED_FULL : LED_OFF;
+}
+#endif
+
 int lg4ff_init(struct hid_device *hid)
 {
        struct hid_input *hidinput = list_entry(hid->inputs.next, struct hid_input, list);
@@ -344,6 +429,7 @@ int lg4ff_init(struct hid_device *hid)
        struct hid_report *report;
        struct hid_field *field;
        struct lg4ff_device_entry *entry;
+       struct lg_drv_data *drv_data;
        struct usb_device_descriptor *udesc;
        int error, i, j;
        __u16 bcdDevice, rev_maj, rev_min;
@@ -423,28 +509,24 @@ int lg4ff_init(struct hid_device *hid)
                dev->ff->set_autocenter(dev, 0);
        }
 
-               /* Initialize device_list if this is the first device to handle by lg4ff */
-       if (!list_inited) {
-               INIT_LIST_HEAD(&device_list.list);
-               list_inited = 1;
+       /* Get private driver data */
+       drv_data = hid_get_drvdata(hid);
+       if (!drv_data) {
+               hid_err(hid, "Cannot add device, private driver data not allocated\n");
+               return -1;
        }
 
-       /* Add the device to device_list */
+       /* Initialize device properties */
        entry = kzalloc(sizeof(struct lg4ff_device_entry), GFP_KERNEL);
        if (!entry) {
-               hid_err(hid, "Cannot add device, insufficient memory.\n");
-               return -ENOMEM;
-       }
-       entry->device_id = kstrdup((&hid->dev)->kobj.name, GFP_KERNEL);
-       if (!entry->device_id) {
-               hid_err(hid, "Cannot set device_id, insufficient memory.\n");
-               kfree(entry);
+               hid_err(hid, "Cannot add device, insufficient memory to allocate device properties.\n");
                return -ENOMEM;
        }
+       drv_data->device_props = entry;
+
        entry->min_range = lg4ff_devices[i].min_range;
        entry->max_range = lg4ff_devices[i].max_range;
        entry->set_range = lg4ff_devices[i].set_range;
-       list_add(&entry->list, &device_list.list);
 
        /* Create sysfs interface */
        error = device_create_file(&hid->dev, &dev_attr_range);
@@ -457,32 +539,100 @@ int lg4ff_init(struct hid_device *hid)
        if (entry->set_range != NULL)
                entry->set_range(hid, entry->range);
 
-       hid_info(hid, "Force feedback for Logitech Speed Force Wireless by Simon Wood <simon@mungewell.org>\n");
+#ifdef CONFIG_LEDS_CLASS
+       /* register led subsystem - G27 only */
+       entry->led_state = 0;
+       for (j = 0; j < 5; j++)
+               entry->led[j] = NULL;
+
+       if (lg4ff_devices[i].product_id == USB_DEVICE_ID_LOGITECH_G27_WHEEL) {
+               struct led_classdev *led;
+               size_t name_sz;
+               char *name;
+
+               lg4ff_set_leds(hid, 0);
+
+               name_sz = strlen(dev_name(&hid->dev)) + 8;
+
+               for (j = 0; j < 5; j++) {
+                       led = kzalloc(sizeof(struct led_classdev)+name_sz, GFP_KERNEL);
+                       if (!led) {
+                               hid_err(hid, "can't allocate memory for LED %d\n", j);
+                               goto err;
+                       }
+
+                       name = (void *)(&led[1]);
+                       snprintf(name, name_sz, "%s::RPM%d", dev_name(&hid->dev), j+1);
+                       led->name = name;
+                       led->brightness = 0;
+                       led->max_brightness = 1;
+                       led->brightness_get = lg4ff_led_get_brightness;
+                       led->brightness_set = lg4ff_led_set_brightness;
+
+                       entry->led[j] = led;
+                       error = led_classdev_register(&hid->dev, led);
+
+                       if (error) {
+                               hid_err(hid, "failed to register LED %d. Aborting.\n", j);
+err:
+                               /* Deregister LEDs (if any) */
+                               for (j = 0; j < 5; j++) {
+                                       led = entry->led[j];
+                                       entry->led[j] = NULL;
+                                       if (!led)
+                                               continue;
+                                       led_classdev_unregister(led);
+                                       kfree(led);
+                               }
+                               goto out;       /* Let the driver continue without LEDs */
+                       }
+               }
+       }
+out:
+#endif
+       hid_info(hid, "Force feedback support for Logitech Gaming Wheels\n");
        return 0;
 }
 
 int lg4ff_deinit(struct hid_device *hid)
 {
-       bool found = 0;
        struct lg4ff_device_entry *entry;
-       struct list_head *h, *g;
-       list_for_each_safe(h, g, &device_list.list) {
-               entry = list_entry(h, struct lg4ff_device_entry, list);
-               if (strcmp(entry->device_id, (&hid->dev)->kobj.name) == 0) {
-                       list_del(h);
-                       kfree(entry->device_id);
-                       kfree(entry);
-                       found = 1;
-                       break;
-               }
-       }
+       struct lg_drv_data *drv_data;
+
+       device_remove_file(&hid->dev, &dev_attr_range);
 
-       if (!found) {
-               dbg_hid("Device entry not found!\n");
+       drv_data = hid_get_drvdata(hid);
+       if (!drv_data) {
+               hid_err(hid, "Error while deinitializing device, no private driver data.\n");
+               return -1;
+       }
+       entry = drv_data->device_props;
+       if (!entry) {
+               hid_err(hid, "Error while deinitializing device, no device properties data.\n");
                return -1;
        }
 
-       device_remove_file(&hid->dev, &dev_attr_range);
+#ifdef CONFIG_LEDS_CLASS
+       {
+               int j;
+               struct led_classdev *led;
+
+               /* Deregister LEDs (if any) */
+               for (j = 0; j < 5; j++) {
+
+                       led = entry->led[j];
+                       entry->led[j] = NULL;
+                       if (!led)
+                               continue;
+                       led_classdev_unregister(led);
+                       kfree(led);
+               }
+       }
+#endif
+
+       /* Deallocate memory */
+       kfree(entry);
+
        dbg_hid("Device successfully unregistered\n");
        return 0;
 }
index 2b56efcbdf61f23d984bb49cc4c04a280e32ef4f..5e8a7ed42344d67d1c874fe3e3242766aed1b537 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/hid.h>
 #include <linux/module.h>
 #include <linux/usb.h>
+#include <asm/unaligned.h>
 #include "usbhid/usbhid.h"
 #include "hid-ids.h"
 #include "hid-logitech-dj.h"
@@ -155,6 +156,14 @@ static const char media_descriptor[] = {
 /* Maximum size of all defined hid reports in bytes (including report id) */
 #define MAX_REPORT_SIZE 8
 
+/* Make sure all descriptors are present here */
+#define MAX_RDESC_SIZE                         \
+       (sizeof(kbd_descriptor) +               \
+        sizeof(mse_descriptor) +               \
+        sizeof(consumer_descriptor) +          \
+        sizeof(syscontrol_descriptor) +        \
+        sizeof(media_descriptor))
+
 /* Number of possible hid report types that can be created by this driver.
  *
  * Right now, RF report types have the same report types (or report id's)
@@ -265,8 +274,8 @@ static void logi_dj_recv_add_djhid_device(struct dj_receiver_dev *djrcv_dev,
                goto dj_device_allocate_fail;
        }
 
-       dj_dev->reports_supported = le32_to_cpu(
-               dj_report->report_params[DEVICE_PAIRED_RF_REPORT_TYPE]);
+       dj_dev->reports_supported = get_unaligned_le32(
+               dj_report->report_params + DEVICE_PAIRED_RF_REPORT_TYPE);
        dj_dev->hdev = dj_hiddev;
        dj_dev->dj_receiver_dev = djrcv_dev;
        dj_dev->device_index = dj_report->device_index;
@@ -473,9 +482,17 @@ static int logi_dj_output_hidraw_report(struct hid_device *hid, u8 * buf,
        return 0;
 }
 
+static void rdcat(char **rdesc, unsigned int *rsize, const char *data, unsigned int size)
+{
+       memcpy(*rdesc + *rsize, data, size);
+       *rsize += size;
+}
+
 static int logi_dj_ll_parse(struct hid_device *hid)
 {
        struct dj_device *djdev = hid->driver_data;
+       unsigned int rsize = 0;
+       char *rdesc;
        int retval;
 
        dbg_hid("%s\n", __func__);
@@ -483,70 +500,38 @@ static int logi_dj_ll_parse(struct hid_device *hid)
        djdev->hdev->version = 0x0111;
        djdev->hdev->country = 0x00;
 
+       rdesc = kmalloc(MAX_RDESC_SIZE, GFP_KERNEL);
+       if (!rdesc)
+               return -ENOMEM;
+
        if (djdev->reports_supported & STD_KEYBOARD) {
                dbg_hid("%s: sending a kbd descriptor, reports_supported: %x\n",
                        __func__, djdev->reports_supported);
-               retval = hid_parse_report(hid,
-                                         (u8 *) kbd_descriptor,
-                                         sizeof(kbd_descriptor));
-               if (retval) {
-                       dbg_hid("%s: sending a kbd descriptor, hid_parse failed"
-                               " error: %d\n", __func__, retval);
-                       return retval;
-               }
+               rdcat(&rdesc, &rsize, kbd_descriptor, sizeof(kbd_descriptor));
        }
 
        if (djdev->reports_supported & STD_MOUSE) {
                dbg_hid("%s: sending a mouse descriptor, reports_supported: "
                        "%x\n", __func__, djdev->reports_supported);
-               retval = hid_parse_report(hid,
-                                         (u8 *) mse_descriptor,
-                                         sizeof(mse_descriptor));
-               if (retval) {
-                       dbg_hid("%s: sending a mouse descriptor, hid_parse "
-                               "failed error: %d\n", __func__, retval);
-                       return retval;
-               }
+               rdcat(&rdesc, &rsize, mse_descriptor, sizeof(mse_descriptor));
        }
 
        if (djdev->reports_supported & MULTIMEDIA) {
                dbg_hid("%s: sending a multimedia report descriptor: %x\n",
                        __func__, djdev->reports_supported);
-               retval = hid_parse_report(hid,
-                                         (u8 *) consumer_descriptor,
-                                         sizeof(consumer_descriptor));
-               if (retval) {
-                       dbg_hid("%s: sending a consumer_descriptor, hid_parse "
-                               "failed error: %d\n", __func__, retval);
-                       return retval;
-               }
+               rdcat(&rdesc, &rsize, consumer_descriptor, sizeof(consumer_descriptor));
        }
 
        if (djdev->reports_supported & POWER_KEYS) {
                dbg_hid("%s: sending a power keys report descriptor: %x\n",
                        __func__, djdev->reports_supported);
-               retval = hid_parse_report(hid,
-                                         (u8 *) syscontrol_descriptor,
-                                         sizeof(syscontrol_descriptor));
-               if (retval) {
-                       dbg_hid("%s: sending a syscontrol_descriptor, "
-                               "hid_parse failed error: %d\n",
-                               __func__, retval);
-                       return retval;
-               }
+               rdcat(&rdesc, &rsize, syscontrol_descriptor, sizeof(syscontrol_descriptor));
        }
 
        if (djdev->reports_supported & MEDIA_CENTER) {
                dbg_hid("%s: sending a media center report descriptor: %x\n",
                        __func__, djdev->reports_supported);
-               retval = hid_parse_report(hid,
-                                         (u8 *) media_descriptor,
-                                         sizeof(media_descriptor));
-               if (retval) {
-                       dbg_hid("%s: sending a media_descriptor, hid_parse "
-                               "failed error: %d\n", __func__, retval);
-                       return retval;
-               }
+               rdcat(&rdesc, &rsize, media_descriptor, sizeof(media_descriptor));
        }
 
        if (djdev->reports_supported & KBD_LEDS) {
@@ -554,7 +539,10 @@ static int logi_dj_ll_parse(struct hid_device *hid)
                        __func__, djdev->reports_supported);
        }
 
-       return 0;
+       retval = hid_parse_report(hid, rdesc, rsize);
+       kfree(rdesc);
+
+       return retval;
 }
 
 static int logi_dj_ll_input_event(struct input_dev *dev, unsigned int type,
index 1d5b94167b521566268d91077b307c68a29d04cc..6e3332a99976d669e008131e0851ae8788113749 100644 (file)
@@ -70,9 +70,16 @@ struct mt_class {
        bool is_indirect;       /* true for touchpads */
 };
 
+struct mt_fields {
+       unsigned usages[HID_MAX_FIELDS];
+       unsigned int length;
+};
+
 struct mt_device {
        struct mt_slot curdata; /* placeholder of incoming data */
        struct mt_class mtclass;        /* our mt device class */
+       struct mt_fields *fields;       /* temporary placeholder for storing the
+                                          multitouch fields */
        unsigned last_field_index;      /* last field index of the report */
        unsigned last_slot_field;       /* the last field of a slot */
        __s8 inputmode;         /* InputMode HID feature, -1 if non-existent */
@@ -110,6 +117,9 @@ struct mt_device {
 
 #define MT_DEFAULT_MAXCONTACT  10
 
+#define MT_USB_DEVICE(v, p)    HID_DEVICE(BUS_USB, HID_GROUP_MULTITOUCH, v, p)
+#define MT_BT_DEVICE(v, p)     HID_DEVICE(BUS_BLUETOOTH, HID_GROUP_MULTITOUCH, v, p)
+
 /*
  * these device-dependent functions determine what slot corresponds
  * to a valid contact that was just read.
@@ -275,11 +285,15 @@ static void set_abs(struct input_dev *input, unsigned int code,
        input_set_abs_params(input, code, fmin, fmax, fuzz, 0);
 }
 
-static void set_last_slot_field(struct hid_usage *usage, struct mt_device *td,
+static void mt_store_field(struct hid_usage *usage, struct mt_device *td,
                struct hid_input *hi)
 {
-       if (!test_bit(usage->hid, hi->input->absbit))
-               td->last_slot_field = usage->hid;
+       struct mt_fields *f = td->fields;
+
+       if (f->length >= HID_MAX_FIELDS)
+               return;
+
+       f->usages[f->length++] = usage->hid;
 }
 
 static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
@@ -330,7 +344,7 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
                                cls->sn_move);
                        /* touchscreen emulation */
                        set_abs(hi->input, ABS_X, field, cls->sn_move);
-                       set_last_slot_field(usage, td, hi);
+                       mt_store_field(usage, td, hi);
                        td->last_field_index = field->index;
                        return 1;
                case HID_GD_Y:
@@ -340,7 +354,7 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
                                cls->sn_move);
                        /* touchscreen emulation */
                        set_abs(hi->input, ABS_Y, field, cls->sn_move);
-                       set_last_slot_field(usage, td, hi);
+                       mt_store_field(usage, td, hi);
                        td->last_field_index = field->index;
                        return 1;
                }
@@ -349,24 +363,24 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
        case HID_UP_DIGITIZER:
                switch (usage->hid) {
                case HID_DG_INRANGE:
-                       set_last_slot_field(usage, td, hi);
+                       mt_store_field(usage, td, hi);
                        td->last_field_index = field->index;
                        return 1;
                case HID_DG_CONFIDENCE:
-                       set_last_slot_field(usage, td, hi);
+                       mt_store_field(usage, td, hi);
                        td->last_field_index = field->index;
                        return 1;
                case HID_DG_TIPSWITCH:
                        hid_map_usage(hi, usage, bit, max, EV_KEY, BTN_TOUCH);
                        input_set_capability(hi->input, EV_KEY, BTN_TOUCH);
-                       set_last_slot_field(usage, td, hi);
+                       mt_store_field(usage, td, hi);
                        td->last_field_index = field->index;
                        return 1;
                case HID_DG_CONTACTID:
                        if (!td->maxcontacts)
                                td->maxcontacts = MT_DEFAULT_MAXCONTACT;
                        input_mt_init_slots(hi->input, td->maxcontacts);
-                       td->last_slot_field = usage->hid;
+                       mt_store_field(usage, td, hi);
                        td->last_field_index = field->index;
                        td->touches_by_report++;
                        return 1;
@@ -375,7 +389,7 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
                                        EV_ABS, ABS_MT_TOUCH_MAJOR);
                        set_abs(hi->input, ABS_MT_TOUCH_MAJOR, field,
                                cls->sn_width);
-                       set_last_slot_field(usage, td, hi);
+                       mt_store_field(usage, td, hi);
                        td->last_field_index = field->index;
                        return 1;
                case HID_DG_HEIGHT:
@@ -385,7 +399,7 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
                                cls->sn_height);
                        input_set_abs_params(hi->input,
                                        ABS_MT_ORIENTATION, 0, 1, 0, 0);
-                       set_last_slot_field(usage, td, hi);
+                       mt_store_field(usage, td, hi);
                        td->last_field_index = field->index;
                        return 1;
                case HID_DG_TIPPRESSURE:
@@ -396,7 +410,7 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
                        /* touchscreen emulation */
                        set_abs(hi->input, ABS_PRESSURE, field,
                                cls->sn_pressure);
-                       set_last_slot_field(usage, td, hi);
+                       mt_store_field(usage, td, hi);
                        td->last_field_index = field->index;
                        return 1;
                case HID_DG_CONTACTCOUNT:
@@ -635,6 +649,31 @@ static void mt_set_maxcontacts(struct hid_device *hdev)
        }
 }
 
+static void mt_post_parse_default_settings(struct mt_device *td)
+{
+       __s32 quirks = td->mtclass.quirks;
+
+       /* unknown serial device needs special quirks */
+       if (td->touches_by_report == 1) {
+               quirks |= MT_QUIRK_ALWAYS_VALID;
+               quirks &= ~MT_QUIRK_NOT_SEEN_MEANS_UP;
+               quirks &= ~MT_QUIRK_VALID_IS_INRANGE;
+               quirks &= ~MT_QUIRK_VALID_IS_CONFIDENCE;
+       }
+
+       td->mtclass.quirks = quirks;
+}
+
+static void mt_post_parse(struct mt_device *td)
+{
+       struct mt_fields *f = td->fields;
+
+       if (td->touches_by_report > 0) {
+               int field_count_per_touch = f->length / td->touches_by_report;
+               td->last_slot_field = f->usages[field_count_per_touch - 1];
+       }
+}
+
 static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
 {
        int ret, i;
@@ -654,7 +693,6 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
         * that emit events over several HID messages.
         */
        hdev->quirks |= HID_QUIRK_NO_INPUT_SYNC;
-       hdev->quirks &= ~HID_QUIRK_MULTITOUCH;
 
        td = kzalloc(sizeof(struct mt_device), GFP_KERNEL);
        if (!td) {
@@ -666,6 +704,13 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
        td->maxcontact_report_id = -1;
        hid_set_drvdata(hdev, td);
 
+       td->fields = kzalloc(sizeof(struct mt_fields), GFP_KERNEL);
+       if (!td->fields) {
+               dev_err(&hdev->dev, "cannot allocate multitouch fields data\n");
+               ret = -ENOMEM;
+               goto fail;
+       }
+
        ret = hid_parse(hdev);
        if (ret != 0)
                goto fail;
@@ -674,14 +719,10 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
        if (ret)
                goto fail;
 
-       if (!id && td->touches_by_report == 1) {
-               /* the device has been sent by hid-generic */
-               mtclass = &td->mtclass;
-               mtclass->quirks |= MT_QUIRK_ALWAYS_VALID;
-               mtclass->quirks &= ~MT_QUIRK_NOT_SEEN_MEANS_UP;
-               mtclass->quirks &= ~MT_QUIRK_VALID_IS_INRANGE;
-               mtclass->quirks &= ~MT_QUIRK_VALID_IS_CONFIDENCE;
-       }
+       mt_post_parse(td);
+
+       if (id->vendor == HID_ANY_ID && id->product == HID_ANY_ID)
+               mt_post_parse_default_settings(td);
 
        td->slots = kzalloc(td->maxcontacts * sizeof(struct mt_slot),
                                GFP_KERNEL);
@@ -697,9 +738,13 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
        mt_set_maxcontacts(hdev);
        mt_set_input_mode(hdev);
 
+       kfree(td->fields);
+       td->fields = NULL;
+
        return 0;
 
 fail:
+       kfree(td->fields);
        kfree(td);
        return ret;
 }
@@ -727,50 +772,54 @@ static const struct hid_device_id mt_devices[] = {
 
        /* 3M panels */
        { .driver_data = MT_CLS_3M,
-               HID_USB_DEVICE(USB_VENDOR_ID_3M,
+               MT_USB_DEVICE(USB_VENDOR_ID_3M,
                        USB_DEVICE_ID_3M1968) },
        { .driver_data = MT_CLS_3M,
-               HID_USB_DEVICE(USB_VENDOR_ID_3M,
+               MT_USB_DEVICE(USB_VENDOR_ID_3M,
                        USB_DEVICE_ID_3M2256) },
        { .driver_data = MT_CLS_3M,
-               HID_USB_DEVICE(USB_VENDOR_ID_3M,
+               MT_USB_DEVICE(USB_VENDOR_ID_3M,
                        USB_DEVICE_ID_3M3266) },
 
        /* ActionStar panels */
        { .driver_data = MT_CLS_DEFAULT,
-               HID_USB_DEVICE(USB_VENDOR_ID_ACTIONSTAR,
+               MT_USB_DEVICE(USB_VENDOR_ID_ACTIONSTAR,
                        USB_DEVICE_ID_ACTIONSTAR_1011) },
 
        /* Atmel panels */
        { .driver_data = MT_CLS_SERIAL,
-               HID_USB_DEVICE(USB_VENDOR_ID_ATMEL,
+               MT_USB_DEVICE(USB_VENDOR_ID_ATMEL,
                        USB_DEVICE_ID_ATMEL_MULTITOUCH) },
        { .driver_data = MT_CLS_SERIAL,
-               HID_USB_DEVICE(USB_VENDOR_ID_ATMEL,
+               MT_USB_DEVICE(USB_VENDOR_ID_ATMEL,
                        USB_DEVICE_ID_ATMEL_MXT_DIGITIZER) },
 
+       /* Baanto multitouch devices */
+       { .driver_data = MT_CLS_DEFAULT,
+               MT_USB_DEVICE(USB_VENDOR_ID_BAANTO,
+                       USB_DEVICE_ID_BAANTO_MT_190W2) },
        /* Cando panels */
        { .driver_data = MT_CLS_DUAL_INRANGE_CONTACTNUMBER,
-               HID_USB_DEVICE(USB_VENDOR_ID_CANDO,
+               MT_USB_DEVICE(USB_VENDOR_ID_CANDO,
                        USB_DEVICE_ID_CANDO_MULTI_TOUCH) },
        { .driver_data = MT_CLS_DUAL_INRANGE_CONTACTNUMBER,
-               HID_USB_DEVICE(USB_VENDOR_ID_CANDO,
+               MT_USB_DEVICE(USB_VENDOR_ID_CANDO,
                        USB_DEVICE_ID_CANDO_MULTI_TOUCH_10_1) },
        { .driver_data = MT_CLS_DUAL_INRANGE_CONTACTNUMBER,
-               HID_USB_DEVICE(USB_VENDOR_ID_CANDO,
+               MT_USB_DEVICE(USB_VENDOR_ID_CANDO,
                        USB_DEVICE_ID_CANDO_MULTI_TOUCH_11_6) },
        { .driver_data = MT_CLS_DUAL_INRANGE_CONTACTNUMBER,
-               HID_USB_DEVICE(USB_VENDOR_ID_CANDO,
+               MT_USB_DEVICE(USB_VENDOR_ID_CANDO,
                        USB_DEVICE_ID_CANDO_MULTI_TOUCH_15_6) },
 
        /* Chunghwa Telecom touch panels */
        {  .driver_data = MT_CLS_DEFAULT,
-               HID_USB_DEVICE(USB_VENDOR_ID_CHUNGHWAT,
+               MT_USB_DEVICE(USB_VENDOR_ID_CHUNGHWAT,
                        USB_DEVICE_ID_CHUNGHWAT_MULTITOUCH) },
 
        /* CVTouch panels */
        { .driver_data = MT_CLS_DEFAULT,
-               HID_USB_DEVICE(USB_VENDOR_ID_CVTOUCH,
+               MT_USB_DEVICE(USB_VENDOR_ID_CVTOUCH,
                        USB_DEVICE_ID_CVTOUCH_SCREEN) },
 
        /* Cypress panel */
@@ -780,225 +829,227 @@ static const struct hid_device_id mt_devices[] = {
 
        /* eGalax devices (resistive) */
        { .driver_data = MT_CLS_EGALAX,
-               HID_USB_DEVICE(USB_VENDOR_ID_DWAV,
+               MT_USB_DEVICE(USB_VENDOR_ID_DWAV,
                        USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_480D) },
        { .driver_data = MT_CLS_EGALAX,
-               HID_USB_DEVICE(USB_VENDOR_ID_DWAV,
+               MT_USB_DEVICE(USB_VENDOR_ID_DWAV,
                        USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_480E) },
 
        /* eGalax devices (capacitive) */
        { .driver_data = MT_CLS_EGALAX,
-               HID_USB_DEVICE(USB_VENDOR_ID_DWAV,
+               MT_USB_DEVICE(USB_VENDOR_ID_DWAV,
                        USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_720C) },
        { .driver_data = MT_CLS_EGALAX_SERIAL,
-               HID_USB_DEVICE(USB_VENDOR_ID_DWAV,
+               MT_USB_DEVICE(USB_VENDOR_ID_DWAV,
                        USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_7207) },
        { .driver_data = MT_CLS_EGALAX_SERIAL,
-               HID_USB_DEVICE(USB_VENDOR_ID_DWAV,
+               MT_USB_DEVICE(USB_VENDOR_ID_DWAV,
                        USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_725E) },
        { .driver_data = MT_CLS_EGALAX_SERIAL,
-               HID_USB_DEVICE(USB_VENDOR_ID_DWAV,
+               MT_USB_DEVICE(USB_VENDOR_ID_DWAV,
                        USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_7224) },
        { .driver_data = MT_CLS_EGALAX_SERIAL,
-               HID_USB_DEVICE(USB_VENDOR_ID_DWAV,
+               MT_USB_DEVICE(USB_VENDOR_ID_DWAV,
                        USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_722A) },
        { .driver_data = MT_CLS_EGALAX,
-               HID_USB_DEVICE(USB_VENDOR_ID_DWAV,
+               MT_USB_DEVICE(USB_VENDOR_ID_DWAV,
                        USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_726B) },
        { .driver_data = MT_CLS_EGALAX_SERIAL,
-               HID_USB_DEVICE(USB_VENDOR_ID_DWAV,
+               MT_USB_DEVICE(USB_VENDOR_ID_DWAV,
                        USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_7262) },
        { .driver_data = MT_CLS_EGALAX,
-               HID_USB_DEVICE(USB_VENDOR_ID_DWAV,
+               MT_USB_DEVICE(USB_VENDOR_ID_DWAV,
                        USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_72A1) },
        { .driver_data = MT_CLS_EGALAX_SERIAL,
-               HID_USB_DEVICE(USB_VENDOR_ID_DWAV,
+               MT_USB_DEVICE(USB_VENDOR_ID_DWAV,
                        USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_72AA) },
        { .driver_data = MT_CLS_EGALAX,
-               HID_USB_DEVICE(USB_VENDOR_ID_DWAV,
+               MT_USB_DEVICE(USB_VENDOR_ID_DWAV,
                        USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_72FA) },
        { .driver_data = MT_CLS_EGALAX,
-               HID_USB_DEVICE(USB_VENDOR_ID_DWAV,
+               MT_USB_DEVICE(USB_VENDOR_ID_DWAV,
                        USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_7302) },
        { .driver_data = MT_CLS_EGALAX_SERIAL,
-               HID_USB_DEVICE(USB_VENDOR_ID_DWAV,
+               MT_USB_DEVICE(USB_VENDOR_ID_DWAV,
                        USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_7349) },
        { .driver_data = MT_CLS_EGALAX_SERIAL,
-               HID_USB_DEVICE(USB_VENDOR_ID_DWAV,
+               MT_USB_DEVICE(USB_VENDOR_ID_DWAV,
                        USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_A001) },
 
        /* Elo TouchSystems IntelliTouch Plus panel */
        { .driver_data = MT_CLS_DUAL_NSMU_CONTACTID,
-               HID_USB_DEVICE(USB_VENDOR_ID_ELO,
+               MT_USB_DEVICE(USB_VENDOR_ID_ELO,
                        USB_DEVICE_ID_ELO_TS2515) },
 
        /* GeneralTouch panel */
        { .driver_data = MT_CLS_DUAL_INRANGE_CONTACTNUMBER,
-               HID_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH,
+               MT_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH,
                        USB_DEVICE_ID_GENERAL_TOUCH_WIN7_TWOFINGERS) },
 
        /* Gametel game controller */
        { .driver_data = MT_CLS_DEFAULT,
-               HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_FRUCTEL,
+               MT_BT_DEVICE(USB_VENDOR_ID_FRUCTEL,
                        USB_DEVICE_ID_GAMETEL_MT_MODE) },
 
        /* GoodTouch panels */
        { .driver_data = MT_CLS_DEFAULT,
-               HID_USB_DEVICE(USB_VENDOR_ID_GOODTOUCH,
+               MT_USB_DEVICE(USB_VENDOR_ID_GOODTOUCH,
                        USB_DEVICE_ID_GOODTOUCH_000f) },
 
        /* Hanvon panels */
        { .driver_data = MT_CLS_DUAL_INRANGE_CONTACTID,
-               HID_USB_DEVICE(USB_VENDOR_ID_HANVON_ALT,
+               MT_USB_DEVICE(USB_VENDOR_ID_HANVON_ALT,
                        USB_DEVICE_ID_HANVON_ALT_MULTITOUCH) },
 
        /* Ideacom panel */
        { .driver_data = MT_CLS_SERIAL,
-               HID_USB_DEVICE(USB_VENDOR_ID_IDEACOM,
+               MT_USB_DEVICE(USB_VENDOR_ID_IDEACOM,
                        USB_DEVICE_ID_IDEACOM_IDC6650) },
        { .driver_data = MT_CLS_SERIAL,
-               HID_USB_DEVICE(USB_VENDOR_ID_IDEACOM,
+               MT_USB_DEVICE(USB_VENDOR_ID_IDEACOM,
                        USB_DEVICE_ID_IDEACOM_IDC6651) },
 
        /* Ilitek dual touch panel */
        {  .driver_data = MT_CLS_DEFAULT,
-               HID_USB_DEVICE(USB_VENDOR_ID_ILITEK,
+               MT_USB_DEVICE(USB_VENDOR_ID_ILITEK,
                        USB_DEVICE_ID_ILITEK_MULTITOUCH) },
 
        /* IRTOUCH panels */
        { .driver_data = MT_CLS_DUAL_INRANGE_CONTACTID,
-               HID_USB_DEVICE(USB_VENDOR_ID_IRTOUCHSYSTEMS,
+               MT_USB_DEVICE(USB_VENDOR_ID_IRTOUCHSYSTEMS,
                        USB_DEVICE_ID_IRTOUCH_INFRARED_USB) },
 
        /* LG Display panels */
        { .driver_data = MT_CLS_DEFAULT,
-               HID_USB_DEVICE(USB_VENDOR_ID_LG,
+               MT_USB_DEVICE(USB_VENDOR_ID_LG,
                        USB_DEVICE_ID_LG_MULTITOUCH) },
 
        /* Lumio panels */
        { .driver_data = MT_CLS_CONFIDENCE_MINUS_ONE,
-               HID_USB_DEVICE(USB_VENDOR_ID_LUMIO,
+               MT_USB_DEVICE(USB_VENDOR_ID_LUMIO,
                        USB_DEVICE_ID_CRYSTALTOUCH) },
        { .driver_data = MT_CLS_CONFIDENCE_MINUS_ONE,
-               HID_USB_DEVICE(USB_VENDOR_ID_LUMIO,
+               MT_USB_DEVICE(USB_VENDOR_ID_LUMIO,
                        USB_DEVICE_ID_CRYSTALTOUCH_DUAL) },
 
        /* MosArt panels */
        { .driver_data = MT_CLS_CONFIDENCE_MINUS_ONE,
-               HID_USB_DEVICE(USB_VENDOR_ID_ASUS,
+               MT_USB_DEVICE(USB_VENDOR_ID_ASUS,
                        USB_DEVICE_ID_ASUS_T91MT)},
        { .driver_data = MT_CLS_CONFIDENCE_MINUS_ONE,
-               HID_USB_DEVICE(USB_VENDOR_ID_ASUS,
+               MT_USB_DEVICE(USB_VENDOR_ID_ASUS,
                        USB_DEVICE_ID_ASUSTEK_MULTITOUCH_YFO) },
        { .driver_data = MT_CLS_CONFIDENCE_MINUS_ONE,
-               HID_USB_DEVICE(USB_VENDOR_ID_TURBOX,
+               MT_USB_DEVICE(USB_VENDOR_ID_TURBOX,
                        USB_DEVICE_ID_TURBOX_TOUCHSCREEN_MOSART) },
 
        /* Panasonic panels */
        { .driver_data = MT_CLS_PANASONIC,
-               HID_USB_DEVICE(USB_VENDOR_ID_PANASONIC,
+               MT_USB_DEVICE(USB_VENDOR_ID_PANASONIC,
                        USB_DEVICE_ID_PANABOARD_UBT780) },
        { .driver_data = MT_CLS_PANASONIC,
-               HID_USB_DEVICE(USB_VENDOR_ID_PANASONIC,
+               MT_USB_DEVICE(USB_VENDOR_ID_PANASONIC,
                        USB_DEVICE_ID_PANABOARD_UBT880) },
 
        /* PenMount panels */
        { .driver_data = MT_CLS_CONFIDENCE,
-               HID_USB_DEVICE(USB_VENDOR_ID_PENMOUNT,
+               MT_USB_DEVICE(USB_VENDOR_ID_PENMOUNT,
                        USB_DEVICE_ID_PENMOUNT_PCI) },
 
        /* PixArt optical touch screen */
        { .driver_data = MT_CLS_INRANGE_CONTACTNUMBER,
-               HID_USB_DEVICE(USB_VENDOR_ID_PIXART,
+               MT_USB_DEVICE(USB_VENDOR_ID_PIXART,
                        USB_DEVICE_ID_PIXART_OPTICAL_TOUCH_SCREEN) },
        { .driver_data = MT_CLS_INRANGE_CONTACTNUMBER,
-               HID_USB_DEVICE(USB_VENDOR_ID_PIXART,
+               MT_USB_DEVICE(USB_VENDOR_ID_PIXART,
                        USB_DEVICE_ID_PIXART_OPTICAL_TOUCH_SCREEN1) },
        { .driver_data = MT_CLS_INRANGE_CONTACTNUMBER,
-               HID_USB_DEVICE(USB_VENDOR_ID_PIXART,
+               MT_USB_DEVICE(USB_VENDOR_ID_PIXART,
                        USB_DEVICE_ID_PIXART_OPTICAL_TOUCH_SCREEN2) },
 
        /* PixCir-based panels */
        { .driver_data = MT_CLS_DUAL_INRANGE_CONTACTID,
-               HID_USB_DEVICE(USB_VENDOR_ID_HANVON,
+               MT_USB_DEVICE(USB_VENDOR_ID_HANVON,
                        USB_DEVICE_ID_HANVON_MULTITOUCH) },
        { .driver_data = MT_CLS_DUAL_INRANGE_CONTACTID,
-               HID_USB_DEVICE(USB_VENDOR_ID_CANDO,
+               MT_USB_DEVICE(USB_VENDOR_ID_CANDO,
                        USB_DEVICE_ID_CANDO_PIXCIR_MULTI_TOUCH) },
 
        /* Quanta-based panels */
        { .driver_data = MT_CLS_CONFIDENCE_CONTACT_ID,
-               HID_USB_DEVICE(USB_VENDOR_ID_QUANTA,
+               MT_USB_DEVICE(USB_VENDOR_ID_QUANTA,
                        USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH) },
        { .driver_data = MT_CLS_CONFIDENCE_CONTACT_ID,
-               HID_USB_DEVICE(USB_VENDOR_ID_QUANTA,
+               MT_USB_DEVICE(USB_VENDOR_ID_QUANTA,
                        USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH_3001) },
        { .driver_data = MT_CLS_CONFIDENCE_CONTACT_ID,
-               HID_USB_DEVICE(USB_VENDOR_ID_QUANTA,
+               MT_USB_DEVICE(USB_VENDOR_ID_QUANTA,
                        USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH_3008) },
 
        /* Stantum panels */
        { .driver_data = MT_CLS_CONFIDENCE,
-               HID_USB_DEVICE(USB_VENDOR_ID_STANTUM,
+               MT_USB_DEVICE(USB_VENDOR_ID_STANTUM,
                        USB_DEVICE_ID_MTP)},
        { .driver_data = MT_CLS_CONFIDENCE,
-               HID_USB_DEVICE(USB_VENDOR_ID_STANTUM_STM,
+               MT_USB_DEVICE(USB_VENDOR_ID_STANTUM_STM,
                        USB_DEVICE_ID_MTP_STM)},
        { .driver_data = MT_CLS_CONFIDENCE,
-               HID_USB_DEVICE(USB_VENDOR_ID_STANTUM_SITRONIX,
+               MT_USB_DEVICE(USB_VENDOR_ID_STANTUM_SITRONIX,
                        USB_DEVICE_ID_MTP_SITRONIX)},
 
        /* TopSeed panels */
        { .driver_data = MT_CLS_TOPSEED,
-               HID_USB_DEVICE(USB_VENDOR_ID_TOPSEED2,
+               MT_USB_DEVICE(USB_VENDOR_ID_TOPSEED2,
                        USB_DEVICE_ID_TOPSEED2_PERIPAD_701) },
 
        /* Touch International panels */
        { .driver_data = MT_CLS_DEFAULT,
-               HID_USB_DEVICE(USB_VENDOR_ID_TOUCH_INTL,
+               MT_USB_DEVICE(USB_VENDOR_ID_TOUCH_INTL,
                        USB_DEVICE_ID_TOUCH_INTL_MULTI_TOUCH) },
 
        /* Unitec panels */
        { .driver_data = MT_CLS_DEFAULT,
-               HID_USB_DEVICE(USB_VENDOR_ID_UNITEC,
+               MT_USB_DEVICE(USB_VENDOR_ID_UNITEC,
                        USB_DEVICE_ID_UNITEC_USB_TOUCH_0709) },
        { .driver_data = MT_CLS_DEFAULT,
-               HID_USB_DEVICE(USB_VENDOR_ID_UNITEC,
+               MT_USB_DEVICE(USB_VENDOR_ID_UNITEC,
                        USB_DEVICE_ID_UNITEC_USB_TOUCH_0A19) },
        /* XAT */
        { .driver_data = MT_CLS_DEFAULT,
-               HID_USB_DEVICE(USB_VENDOR_ID_XAT,
+               MT_USB_DEVICE(USB_VENDOR_ID_XAT,
                        USB_DEVICE_ID_XAT_CSR) },
 
        /* Xiroku */
        { .driver_data = MT_CLS_DEFAULT,
-               HID_USB_DEVICE(USB_VENDOR_ID_XIROKU,
+               MT_USB_DEVICE(USB_VENDOR_ID_XIROKU,
                        USB_DEVICE_ID_XIROKU_SPX) },
        { .driver_data = MT_CLS_DEFAULT,
-               HID_USB_DEVICE(USB_VENDOR_ID_XIROKU,
+               MT_USB_DEVICE(USB_VENDOR_ID_XIROKU,
                        USB_DEVICE_ID_XIROKU_MPX) },
        { .driver_data = MT_CLS_DEFAULT,
-               HID_USB_DEVICE(USB_VENDOR_ID_XIROKU,
+               MT_USB_DEVICE(USB_VENDOR_ID_XIROKU,
                        USB_DEVICE_ID_XIROKU_CSR) },
        { .driver_data = MT_CLS_DEFAULT,
-               HID_USB_DEVICE(USB_VENDOR_ID_XIROKU,
+               MT_USB_DEVICE(USB_VENDOR_ID_XIROKU,
                        USB_DEVICE_ID_XIROKU_SPX1) },
        { .driver_data = MT_CLS_DEFAULT,
-               HID_USB_DEVICE(USB_VENDOR_ID_XIROKU,
+               MT_USB_DEVICE(USB_VENDOR_ID_XIROKU,
                        USB_DEVICE_ID_XIROKU_MPX1) },
        { .driver_data = MT_CLS_DEFAULT,
-               HID_USB_DEVICE(USB_VENDOR_ID_XIROKU,
+               MT_USB_DEVICE(USB_VENDOR_ID_XIROKU,
                        USB_DEVICE_ID_XIROKU_CSR1) },
        { .driver_data = MT_CLS_DEFAULT,
-               HID_USB_DEVICE(USB_VENDOR_ID_XIROKU,
+               MT_USB_DEVICE(USB_VENDOR_ID_XIROKU,
                        USB_DEVICE_ID_XIROKU_SPX2) },
        { .driver_data = MT_CLS_DEFAULT,
-               HID_USB_DEVICE(USB_VENDOR_ID_XIROKU,
+               MT_USB_DEVICE(USB_VENDOR_ID_XIROKU,
                        USB_DEVICE_ID_XIROKU_MPX2) },
        { .driver_data = MT_CLS_DEFAULT,
-               HID_USB_DEVICE(USB_VENDOR_ID_XIROKU,
+               MT_USB_DEVICE(USB_VENDOR_ID_XIROKU,
                        USB_DEVICE_ID_XIROKU_CSR2) },
 
+       /* Generic MT device */
+       { HID_DEVICE(HID_BUS_ANY, HID_GROUP_MULTITOUCH, HID_ANY_ID, HID_ANY_ID) },
        { }
 };
 MODULE_DEVICE_TABLE(hid, mt_devices);
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 067e2963314c6882a9f7854267048658388d2aea..fe23a1eb586bdc6d30e049aaae8c34d49fdc7499 100644 (file)
 #include <linux/device.h>
 #include <linux/hid.h>
 #include <linux/module.h>
+#include <linux/leds.h>
 #include <linux/slab.h>
-#ifdef CONFIG_HID_WACOM_POWER_SUPPLY
 #include <linux/power_supply.h>
-#endif
 
 #include "hid-ids.h"
 
 #define PAD_DEVICE_ID  0x0F
 
+#define WAC_CMD_LED_CONTROL     0x20
+
 struct wacom_data {
        __u16 tool;
        __u16 butstate;
@@ -41,16 +42,20 @@ struct wacom_data {
        __u32 id;
        __u32 serial;
        unsigned char high_speed;
-#ifdef CONFIG_HID_WACOM_POWER_SUPPLY
-       int battery_capacity;
+       __u8 battery_capacity;
+       __u8 power_raw;
+       __u8 ps_connected;
        struct power_supply battery;
        struct power_supply ac;
-#endif
+       __u8 led_selector;
+       struct led_classdev *leds[4];
 };
 
-#ifdef CONFIG_HID_WACOM_POWER_SUPPLY
-/*percent of battery capacity, 0 means AC online*/
-static unsigned short batcap[8] = { 1, 15, 25, 35, 50, 70, 100, 0 };
+/*percent of battery capacity for Graphire
+  8th value means AC online and show 100% capacity */
+static unsigned short batcap_gr[8] = { 1, 15, 25, 35, 50, 70, 100, 100 };
+/*percent of battery capacity for Intuos4 WL, AC has a separate bit*/
+static unsigned short batcap_i4[8] = { 1, 15, 30, 45, 60, 70, 85, 100 };
 
 static enum power_supply_property wacom_battery_props[] = {
        POWER_SUPPLY_PROP_PRESENT,
@@ -64,13 +69,123 @@ static enum power_supply_property wacom_ac_props[] = {
        POWER_SUPPLY_PROP_SCOPE,
 };
 
+static void wacom_leds_set_brightness(struct led_classdev *led_dev,
+                                               enum led_brightness value)
+{
+       struct device *dev = led_dev->dev->parent;
+       struct hid_device *hdev;
+       struct wacom_data *wdata;
+       unsigned char *buf;
+       __u8 led = 0;
+       int i;
+
+       hdev = container_of(dev, struct hid_device, dev);
+       wdata = hid_get_drvdata(hdev);
+       for (i = 0; i < 4; ++i) {
+               if (wdata->leds[i] == led_dev)
+                       wdata->led_selector = i;
+       }
+
+       led = wdata->led_selector | 0x04;
+       buf = kzalloc(9, GFP_KERNEL);
+       if (buf) {
+               buf[0] = WAC_CMD_LED_CONTROL;
+               buf[1] = led;
+               buf[2] = value;
+               hdev->hid_output_raw_report(hdev, buf, 9, HID_FEATURE_REPORT);
+               kfree(buf);
+       }
+
+       return;
+}
+
+static enum led_brightness wacom_leds_get_brightness(struct led_classdev *led_dev)
+{
+       struct wacom_data *wdata;
+       struct device *dev = led_dev->dev->parent;
+       int value = 0;
+       int i;
+
+       wdata = hid_get_drvdata(container_of(dev, struct hid_device, dev));
+
+       for (i = 0; i < 4; ++i) {
+               if (wdata->leds[i] == led_dev) {
+                       value = wdata->leds[i]->brightness;
+                       break;
+               }
+       }
+
+       return value;
+}
+
+
+static int wacom_initialize_leds(struct hid_device *hdev)
+{
+       struct wacom_data *wdata = hid_get_drvdata(hdev);
+       struct led_classdev *led;
+       struct device *dev = &hdev->dev;
+       size_t namesz = strlen(dev_name(dev)) + 12;
+       char *name;
+       int i, ret;
+
+       wdata->led_selector = 0;
+
+       for (i = 0; i < 4; i++) {
+               led = kzalloc(sizeof(struct led_classdev) + namesz, GFP_KERNEL);
+               if (!led) {
+                       hid_warn(hdev,
+                                "can't allocate memory for LED selector\n");
+                       ret = -ENOMEM;
+                       goto err;
+               }
+
+               name = (void *)&led[1];
+               snprintf(name, namesz, "%s:selector:%d", dev_name(dev), i);
+               led->name = name;
+               led->brightness = 0;
+               led->max_brightness = 127;
+               led->brightness_get = wacom_leds_get_brightness;
+               led->brightness_set = wacom_leds_set_brightness;
+
+               wdata->leds[i] = led;
+
+               ret = led_classdev_register(dev, wdata->leds[i]);
+
+               if (ret) {
+                       wdata->leds[i] = NULL;
+                       kfree(led);
+                       hid_warn(hdev, "can't register LED\n");
+                       goto err;
+               }
+       }
+
+err:
+       return ret;
+}
+
+static void wacom_destroy_leds(struct hid_device *hdev)
+{
+       struct wacom_data *wdata = hid_get_drvdata(hdev);
+       struct led_classdev *led;
+       int i;
+
+       for (i = 0; i < 4; ++i) {
+               if (wdata->leds[i]) {
+                       led = wdata->leds[i];
+                       wdata->leds[i] = NULL;
+                       led_classdev_unregister(led);
+                       kfree(led);
+               }
+       }
+
+}
+
 static int wacom_battery_get_property(struct power_supply *psy,
                                enum power_supply_property psp,
                                union power_supply_propval *val)
 {
        struct wacom_data *wdata = container_of(psy,
                                        struct wacom_data, battery);
-       int power_state = batcap[wdata->battery_capacity];
        int ret = 0;
 
        switch (psp) {
@@ -81,11 +196,7 @@ static int wacom_battery_get_property(struct power_supply *psy,
                val->intval = POWER_SUPPLY_SCOPE_DEVICE;
                break;
        case POWER_SUPPLY_PROP_CAPACITY:
-               /* show 100% battery capacity when charging */
-               if (power_state == 0)
-                       val->intval = 100;
-               else
-                       val->intval = power_state;
+               val->intval = wdata->battery_capacity;
                break;
        default:
                ret = -EINVAL;
@@ -99,17 +210,13 @@ static int wacom_ac_get_property(struct power_supply *psy,
                                union power_supply_propval *val)
 {
        struct wacom_data *wdata = container_of(psy, struct wacom_data, ac);
-       int power_state = batcap[wdata->battery_capacity];
        int ret = 0;
 
        switch (psp) {
        case POWER_SUPPLY_PROP_PRESENT:
                /* fall through */
        case POWER_SUPPLY_PROP_ONLINE:
-               if (power_state == 0)
-                       val->intval = 1;
-               else
-                       val->intval = 0;
+               val->intval = wdata->ps_connected;
                break;
        case POWER_SUPPLY_PROP_SCOPE:
                val->intval = POWER_SUPPLY_SCOPE_DEVICE;
@@ -120,41 +227,16 @@ static int wacom_ac_get_property(struct power_supply *psy,
        }
        return ret;
 }
-#endif
-
-static void wacom_set_features(struct hid_device *hdev)
-{
-       int ret;
-       __u8 rep_data[2];
-
-       /*set high speed, tablet mode*/
-       rep_data[0] = 0x03;
-       rep_data[1] = 0x20;
-       ret = hdev->hid_output_raw_report(hdev, rep_data, 2,
-                               HID_FEATURE_REPORT);
-       return;
-}
 
-static void wacom_poke(struct hid_device *hdev, u8 speed)
+static void wacom_set_features(struct hid_device *hdev, u8 speed)
 {
        struct wacom_data *wdata = hid_get_drvdata(hdev);
        int limit, ret;
-       char rep_data[2];
-
-       rep_data[0] = 0x03 ; rep_data[1] = 0x00;
-       limit = 3;
-       do {
-               ret = hdev->hid_output_raw_report(hdev, rep_data, 2,
-                               HID_FEATURE_REPORT);
-       } while (ret < 0 && limit-- > 0);
-
-       if (ret >= 0) {
-               if (speed == 0)
-                       rep_data[0] = 0x05;
-               else
-                       rep_data[0] = 0x06;
+       __u8 rep_data[2];
 
-               rep_data[1] = 0x00;
+       switch (hdev->product) {
+       case USB_DEVICE_ID_WACOM_GRAPHIRE_BLUETOOTH:
+               rep_data[0] = 0x03 ; rep_data[1] = 0x00;
                limit = 3;
                do {
                        ret = hdev->hid_output_raw_report(hdev, rep_data, 2,
@@ -162,17 +244,47 @@ static void wacom_poke(struct hid_device *hdev, u8 speed)
                } while (ret < 0 && limit-- > 0);
 
                if (ret >= 0) {
-                       wdata->high_speed = speed;
-                       return;
+                       if (speed == 0)
+                               rep_data[0] = 0x05;
+                       else
+                               rep_data[0] = 0x06;
+
+                       rep_data[1] = 0x00;
+                       limit = 3;
+                       do {
+                               ret = hdev->hid_output_raw_report(hdev,
+                                       rep_data, 2, HID_FEATURE_REPORT);
+                       } while (ret < 0 && limit-- > 0);
+
+                       if (ret >= 0) {
+                               wdata->high_speed = speed;
+                               return;
+                       }
                }
+
+               /*
+                * Note that if the raw queries fail, it's not a hard failure
+                * and it is safe to continue
+                */
+               hid_warn(hdev, "failed to poke device, command %d, err %d\n",
+                        rep_data[0], ret);
+               break;
+       case USB_DEVICE_ID_WACOM_INTUOS4_BLUETOOTH:
+               if (speed == 1)
+                       wdata->features &= ~0x20;
+               else
+                       wdata->features |= 0x20;
+
+               rep_data[0] = 0x03;
+               rep_data[1] = wdata->features;
+
+               ret = hdev->hid_output_raw_report(hdev, rep_data, 2,
+                                       HID_FEATURE_REPORT);
+               if (ret >= 0)
+                       wdata->high_speed = speed;
+               break;
        }
 
-       /*
-        * Note that if the raw queries fail, it's not a hard failure and it
-        * is safe to continue
-        */
-       hid_warn(hdev, "failed to poke device, command %d, err %d\n",
-                rep_data[0], ret);
        return;
 }
 
@@ -196,7 +308,7 @@ static ssize_t wacom_store_speed(struct device *dev,
                return -EINVAL;
 
        if (new_speed == 0 || new_speed == 1) {
-               wacom_poke(hdev, new_speed);
+               wacom_set_features(hdev, new_speed);
                return strnlen(buf, PAGE_SIZE);
        } else
                return -EINVAL;
@@ -310,12 +422,16 @@ static int wacom_gr_parse_report(struct hid_device *hdev,
                input_sync(input);
        }
 
-#ifdef CONFIG_HID_WACOM_POWER_SUPPLY
-       /* Store current battery capacity */
+       /* Store current battery capacity and power supply state*/
        rw = (data[7] >> 2 & 0x07);
-       if (rw != wdata->battery_capacity)
-               wdata->battery_capacity = rw;
-#endif
+       if (rw != wdata->power_raw) {
+               wdata->power_raw = rw;
+               wdata->battery_capacity = batcap_gr[rw];
+               if (rw == 7)
+                       wdata->ps_connected = 1;
+               else
+                       wdata->ps_connected = 0;
+       }
        return 1;
 }
 
@@ -369,6 +485,7 @@ static void wacom_i4_parse_pen_report(struct wacom_data *wdata,
 {
        __u16 x, y, pressure;
        __u8 distance;
+       __u8 tilt_x, tilt_y;
 
        switch (data[1]) {
        case 0x80: /* Out of proximity report */
@@ -405,6 +522,8 @@ static void wacom_i4_parse_pen_report(struct wacom_data *wdata,
                pressure = (data[6] << 3) | ((data[7] & 0xC0) >> 5)
                        | (data[1] & 0x01);
                distance = (data[9] >> 2) & 0x3f;
+               tilt_x = ((data[7] << 1) & 0x7e) | (data[8] >> 7);
+               tilt_y = data[8] & 0x7f;
 
                input_report_key(input, BTN_TOUCH, pressure > 1);
 
@@ -415,6 +534,8 @@ static void wacom_i4_parse_pen_report(struct wacom_data *wdata,
                input_report_abs(input, ABS_Y, y);
                input_report_abs(input, ABS_PRESSURE, pressure);
                input_report_abs(input, ABS_DISTANCE, distance);
+               input_report_abs(input, ABS_TILT_X, tilt_x);
+               input_report_abs(input, ABS_TILT_Y, tilt_y);
                input_report_abs(input, ABS_MISC, wdata->id);
                input_event(input, EV_MSC, MSC_SERIAL, wdata->serial);
                input_report_key(input, wdata->tool, 1);
@@ -455,6 +576,7 @@ static int wacom_raw_event(struct hid_device *hdev, struct hid_report *report,
        struct input_dev *input;
        unsigned char *data = (unsigned char *) raw_data;
        int i;
+       __u8 power_raw;
 
        if (!(hdev->claimed & HID_CLAIMED_INPUT))
                return 0;
@@ -462,13 +584,15 @@ static int wacom_raw_event(struct hid_device *hdev, struct hid_report *report,
        hidinput = list_entry(hdev->inputs.next, struct hid_input, list);
        input = hidinput->input;
 
-       /* Check if this is a tablet report */
-       if (data[0] != 0x03)
-               return 0;
-
        switch (hdev->product) {
        case USB_DEVICE_ID_WACOM_GRAPHIRE_BLUETOOTH:
-               return wacom_gr_parse_report(hdev, wdata, input, data);
+               if (data[0] == 0x03) {
+                       return wacom_gr_parse_report(hdev, wdata, input, data);
+               } else {
+                       hid_err(hdev, "Unknown report: %d,%d size:%d\n",
+                                       data[0], data[1], size);
+                       return 0;
+               }
                break;
        case USB_DEVICE_ID_WACOM_INTUOS4_BLUETOOTH:
                i = 1;
@@ -482,6 +606,13 @@ static int wacom_raw_event(struct hid_device *hdev, struct hid_report *report,
                        wacom_i4_parse_report(hdev, wdata, input, data + i);
                        i += 10;
                        wacom_i4_parse_report(hdev, wdata, input, data + i);
+                       power_raw = data[i+10];
+                       if (power_raw != wdata->power_raw) {
+                               wdata->power_raw = power_raw;
+                               wdata->battery_capacity = batcap_i4[power_raw & 0x07];
+                               wdata->ps_connected = power_raw & 0x08;
+                       }
+
                        break;
                default:
                        hid_err(hdev, "Unknown report: %d,%d size:%d\n",
@@ -546,6 +677,8 @@ static int wacom_input_mapped(struct hid_device *hdev, struct hid_input *hi,
                input_set_abs_params(input, ABS_Y, 0, 25400, 4, 0);
                input_set_abs_params(input, ABS_PRESSURE, 0, 2047, 0, 0);
                input_set_abs_params(input, ABS_DISTANCE, 0, 63, 0, 0);
+               input_set_abs_params(input, ABS_TILT_X, 0, 127, 0, 0);
+               input_set_abs_params(input, ABS_TILT_Y, 0, 127, 0, 0);
                break;
        }
 
@@ -584,19 +717,19 @@ static int wacom_probe(struct hid_device *hdev,
                hid_warn(hdev,
                         "can't create sysfs speed attribute err: %d\n", ret);
 
-       switch (hdev->product) {
-       case USB_DEVICE_ID_WACOM_GRAPHIRE_BLUETOOTH:
-               /* Set Wacom mode 2 with high reporting speed */
-               wacom_poke(hdev, 1);
-               break;
-       case USB_DEVICE_ID_WACOM_INTUOS4_BLUETOOTH:
+       wdata->features = 0;
+       wacom_set_features(hdev, 1);
+
+       if (hdev->product == USB_DEVICE_ID_WACOM_INTUOS4_BLUETOOTH) {
                sprintf(hdev->name, "%s", "Wacom Intuos4 WL");
-               wdata->features = 0;
-               wacom_set_features(hdev);
-               break;
+               ret = wacom_initialize_leds(hdev);
+               if (ret) {
+                       hid_warn(hdev,
+                                "can't create led attribute, err: %d\n", ret);
+                       goto destroy_leds;
+               }
        }
 
-#ifdef CONFIG_HID_WACOM_POWER_SUPPLY
        wdata->battery.properties = wacom_battery_props;
        wdata->battery.num_properties = ARRAY_SIZE(wacom_battery_props);
        wdata->battery.get_property = wacom_battery_get_property;
@@ -629,16 +762,15 @@ static int wacom_probe(struct hid_device *hdev,
        }
 
        power_supply_powers(&wdata->ac, &hdev->dev);
-#endif
        return 0;
 
-#ifdef CONFIG_HID_WACOM_POWER_SUPPLY
 err_ac:
        power_supply_unregister(&wdata->battery);
 err_battery:
        device_remove_file(&hdev->dev, &dev_attr_speed);
        hid_hw_stop(hdev);
-#endif
+destroy_leds:
+       wacom_destroy_leds(hdev);
 err_free:
        kfree(wdata);
        return ret;
@@ -646,16 +778,14 @@ err_free:
 
 static void wacom_remove(struct hid_device *hdev)
 {
-#ifdef CONFIG_HID_WACOM_POWER_SUPPLY
        struct wacom_data *wdata = hid_get_drvdata(hdev);
-#endif
+
+       wacom_destroy_leds(hdev);
        device_remove_file(&hdev->dev, &dev_attr_speed);
        hid_hw_stop(hdev);
 
-#ifdef CONFIG_HID_WACOM_POWER_SUPPLY
        power_supply_unregister(&wdata->battery);
        power_supply_unregister(&wdata->ac);
-#endif
        kfree(hid_get_drvdata(hdev));
 }
 
@@ -693,5 +823,5 @@ static void __exit wacom_exit(void)
 
 module_init(wacom_init);
 module_exit(wacom_exit);
+MODULE_DESCRIPTION("Driver for Wacom Graphire Bluetooth and Wacom Intuos4 WL");
 MODULE_LICENSE("GPL");
-
index 2cfd95c4467b651f7f82c940f4e23f26a104fd70..745e4e9a8cf21d3b24840ac47050b563ae8bc3fb 100644 (file)
@@ -502,28 +502,146 @@ static __u8 media_tablet_14_1_inch_rdesc_fixed[] = {
        0xC0                /*  End Collection                      */
 };
 
-struct waltop_state {
-       u8 pressure0;
-       u8 pressure1;
+/*
+ * See Sirius Battery Free Tablet description, device and HID report descriptors
+ * at
+ * http://sf.net/apps/mediawiki/digimend/?title=Waltop_Sirius_Battery_Free_Tablet
+ */
+
+/* Size of the original report descriptor of Sirius Battery Free Tablet */
+#define SIRIUS_BATTERY_FREE_TABLET_RDESC_ORIG_SIZE     335
+
+/* Fixed Sirius Battery Free Tablet descriptor */
+static __u8 sirius_battery_free_tablet_rdesc_fixed[] = {
+       0x05, 0x0D,         /*  Usage Page (Digitizer),             */
+       0x09, 0x02,         /*  Usage (Pen),                        */
+       0xA1, 0x01,         /*  Collection (Application),           */
+       0x85, 0x10,         /*      Report ID (16),                 */
+       0x09, 0x20,         /*      Usage (Stylus),                 */
+       0xA0,               /*      Collection (Physical),          */
+       0x95, 0x01,         /*          Report Count (1),           */
+       0x15, 0x01,         /*          Logical Minimum (1),        */
+       0x25, 0x03,         /*          Logical Maximum (3),        */
+       0x75, 0x02,         /*          Report Size (2),            */
+       0x09, 0x42,         /*          Usage (Tip Switch),         */
+       0x09, 0x44,         /*          Usage (Barrel Switch),      */
+       0x09, 0x46,         /*          Usage (Tablet Pick),        */
+       0x80,               /*          Input,                      */
+       0x14,               /*          Logical Minimum (0),        */
+       0x25, 0x01,         /*          Logical Maximum (1),        */
+       0x75, 0x01,         /*          Report Size (1),            */
+       0x09, 0x3C,         /*          Usage (Invert),             */
+       0x81, 0x02,         /*          Input (Variable),           */
+       0x81, 0x03,         /*          Input (Constant, Variable), */
+       0x09, 0x32,         /*          Usage (In Range),           */
+       0x81, 0x02,         /*          Input (Variable),           */
+       0x95, 0x03,         /*          Report Count (3),           */
+       0x81, 0x03,         /*          Input (Constant, Variable), */
+       0xA4,               /*          Push,                       */
+       0x05, 0x01,         /*          Usage Page (Desktop),       */
+       0x55, 0xFD,         /*          Unit Exponent (-3),         */
+       0x65, 0x13,         /*          Unit (Inch),                */
+       0x34,               /*          Physical Minimum (0),       */
+       0x14,               /*          Logical Minimum (0),        */
+       0x75, 0x10,         /*          Report Size (16),           */
+       0x95, 0x01,         /*          Report Count (1),           */
+       0x46, 0x10, 0x27,   /*          Physical Maximum (10000),   */
+       0x26, 0x20, 0x4E,   /*          Logical Maximum (20000),    */
+       0x09, 0x30,         /*          Usage (X),                  */
+       0x81, 0x02,         /*          Input (Variable),           */
+       0x46, 0x70, 0x17,   /*          Physical Maximum (6000),    */
+       0x26, 0xE0, 0x2E,   /*          Logical Maximum (12000),    */
+       0x09, 0x31,         /*          Usage (Y),                  */
+       0x81, 0x02,         /*          Input (Variable),           */
+       0xB4,               /*          Pop,                        */
+       0x75, 0x10,         /*          Report Size (16),           */
+       0x95, 0x01,         /*          Report Count (1),           */
+       0x14,               /*          Logical Minimum (0),        */
+       0x26, 0xFF, 0x03,   /*          Logical Maximum (1023),     */
+       0x09, 0x30,         /*          Usage (Tip Pressure),       */
+       0x81, 0x02,         /*          Input (Variable),           */
+       0xA4,               /*          Push,                       */
+       0x55, 0xFE,         /*          Unit Exponent (-2),         */
+       0x65, 0x12,         /*          Unit (Radians),             */
+       0x35, 0x97,         /*          Physical Minimum (-105),    */
+       0x45, 0x69,         /*          Physical Maximum (105),     */
+       0x15, 0x97,         /*          Logical Minimum (-105),     */
+       0x25, 0x69,         /*          Logical Maximum (105),      */
+       0x75, 0x08,         /*          Report Size (8),            */
+       0x95, 0x02,         /*          Report Count (2),           */
+       0x09, 0x3D,         /*          Usage (X Tilt),             */
+       0x09, 0x3E,         /*          Usage (Y Tilt),             */
+       0x81, 0x02,         /*          Input (Variable),           */
+       0xB4,               /*          Pop,                        */
+       0xC0,               /*      End Collection,                 */
+       0xC0,               /*  End Collection,                     */
+       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),          */
+       0x75, 0x08,         /*          Report Size (8),            */
+       0x95, 0x03,         /*          Report Count (3),           */
+       0x81, 0x03,         /*          Input (Constant, Variable), */
+       0x09, 0x38,         /*          Usage (Wheel),              */
+       0x15, 0xFF,         /*          Logical Minimum (-1),       */
+       0x25, 0x01,         /*          Logical Maximum (1),        */
+       0x75, 0x08,         /*          Report Size (8),            */
+       0x95, 0x01,         /*          Report Count (1),           */
+       0x81, 0x06,         /*          Input (Variable, Relative), */
+       0x75, 0x08,         /*          Report Size (8),            */
+       0x95, 0x03,         /*          Report Count (3),           */
+       0x81, 0x03,         /*          Input (Constant, Variable), */
+       0xC0,               /*      End Collection,                 */
+       0xC0,               /*  End Collection,                     */
+       0x05, 0x01,         /*  Usage Page (Desktop),               */
+       0x09, 0x06,         /*  Usage (Keyboard),                   */
+       0xA1, 0x01,         /*  Collection (Application),           */
+       0x85, 0x0D,         /*      Report ID (13),                 */
+       0x05, 0x07,         /*      Usage Page (Keyboard),          */
+       0x19, 0xE0,         /*      Usage Minimum (KB Leftcontrol), */
+       0x29, 0xE7,         /*      Usage Maximum (KB Right GUI),   */
+       0x14,               /*      Logical Minimum (0),            */
+       0x25, 0x01,         /*      Logical Maximum (1),            */
+       0x75, 0x01,         /*      Report Size (1),                */
+       0x95, 0x08,         /*      Report Count (8),               */
+       0x81, 0x02,         /*      Input (Variable),               */
+       0x75, 0x08,         /*      Report Size (8),                */
+       0x95, 0x01,         /*      Report Count (1),               */
+       0x81, 0x01,         /*      Input (Constant),               */
+       0x18,               /*      Usage Minimum (None),           */
+       0x29, 0x65,         /*      Usage Maximum (KB Application), */
+       0x14,               /*      Logical Minimum (0),            */
+       0x25, 0x65,         /*      Logical Maximum (101),          */
+       0x75, 0x08,         /*      Report Size (8),                */
+       0x95, 0x05,         /*      Report Count (5),               */
+       0x80,               /*      Input,                          */
+       0xC0,               /*  End Collection,                     */
+       0x05, 0x0C,         /*  Usage Page (Consumer),              */
+       0x09, 0x01,         /*  Usage (Consumer Control),           */
+       0xA1, 0x01,         /*  Collection (Application),           */
+       0x85, 0x0C,         /*      Report ID (12),                 */
+       0x09, 0xE9,         /*      Usage (Volume Inc),             */
+       0x09, 0xEA,         /*      Usage (Volume Dec),             */
+       0x14,               /*      Logical Minimum (0),            */
+       0x25, 0x01,         /*      Logical Maximum (1),            */
+       0x75, 0x01,         /*      Report Size (1),                */
+       0x95, 0x02,         /*      Report Count (2),               */
+       0x81, 0x02,         /*      Input (Variable),               */
+       0x75, 0x06,         /*      Report Size (6),                */
+       0x95, 0x01,         /*      Report Count (1),               */
+       0x81, 0x03,         /*      Input (Constant, Variable),     */
+       0x75, 0x10,         /*      Report Size (16),               */
+       0x95, 0x03,         /*      Report Count (3),               */
+       0x81, 0x03,         /*      Input (Constant, Variable),     */
+       0xC0                /*  End Collection                      */
 };
 
 static int waltop_probe(struct hid_device *hdev,
                        const struct hid_device_id *id)
 {
        int ret;
-       struct waltop_state *s;
-
-       s = kzalloc(sizeof(*s), GFP_KERNEL);
-       if (s == NULL) {
-               hid_err(hdev, "can't allocate device state\n");
-               ret = -ENOMEM;
-               goto err;
-       }
-
-       s->pressure0 = 0;
-       s->pressure1 = 0;
-
-       hid_set_drvdata(hdev, s);
 
        ret = hid_parse(hdev);
        if (ret) {
@@ -539,7 +657,6 @@ static int waltop_probe(struct hid_device *hdev,
 
        return 0;
 err:
-       kfree(s);
        return ret;
 }
 
@@ -583,6 +700,12 @@ static __u8 *waltop_report_fixup(struct hid_device *hdev, __u8 *rdesc,
                        *rsize = sizeof(media_tablet_14_1_inch_rdesc_fixed);
                }
                break;
+       case USB_DEVICE_ID_WALTOP_SIRIUS_BATTERY_FREE_TABLET:
+               if (*rsize == SIRIUS_BATTERY_FREE_TABLET_RDESC_ORIG_SIZE) {
+                       rdesc = sirius_battery_free_tablet_rdesc_fixed;
+                       *rsize = sizeof(sirius_battery_free_tablet_rdesc_fixed);
+               }
+               break;
        }
        return rdesc;
 }
@@ -590,39 +713,72 @@ static __u8 *waltop_report_fixup(struct hid_device *hdev, __u8 *rdesc,
 static int waltop_raw_event(struct hid_device *hdev, struct hid_report *report,
                     u8 *data, int size)
 {
-       /* If this is a pen input report of a tablet with PID 0038 */
-       if (hdev->product == USB_DEVICE_ID_WALTOP_PID_0038 &&
-           report->type == HID_INPUT_REPORT &&
-           report->id == 16 &&
-           size == 8) {
-               struct waltop_state *s = hid_get_drvdata(hdev);
-
+       /* If this is a pen input report */
+       if (report->type == HID_INPUT_REPORT && report->id == 16 && size >= 8) {
                /*
-                * Ignore maximum pressure reported when a barrel button is
-                * pressed.
+                * Ignore reported pressure when a barrel button is pressed,
+                * because it is rarely correct.
                 */
 
                /* If a barrel button is pressed */
                if ((data[1] & 0xF) > 1) {
-                       /* Use the last known pressure */
-                       data[6] = s->pressure0;
-                       data[7] = s->pressure1;
-               } else {
-                       /* Remember reported pressure */
-                       s->pressure0 = data[6];
-                       s->pressure1 = data[7];
+                       /* Report zero pressure */
+                       data[6] = 0;
+                       data[7] = 0;
                }
        }
 
+       /* If this is a pen input report of Sirius Battery Free Tablet */
+       if (hdev->product == USB_DEVICE_ID_WALTOP_SIRIUS_BATTERY_FREE_TABLET &&
+           report->type == HID_INPUT_REPORT &&
+           report->id == 16 &&
+           size == 10) {
+               /*
+                * The tablet reports tilt as roughly sin(a)*21 (18 means 60
+                * degrees).
+                *
+                * This array stores angles as radians * 100, corresponding to
+                * reported values up to 60 degrees, as expected by userspace.
+                */
+               static const s8 tilt_to_radians[] = {
+                       0, 5, 10, 14, 19, 24, 29, 34, 40, 45,
+                       50, 56, 62, 68, 74, 81, 88, 96, 105
+               };
+
+               s8 tilt_x = (s8)data[8];
+               s8 tilt_y = (s8)data[9];
+               s8 sign_x = tilt_x >= 0 ? 1 : -1;
+               s8 sign_y = tilt_y >= 0 ? 1 : -1;
+
+               tilt_x *= sign_x;
+               tilt_y *= sign_y;
+
+               /*
+                * Reverse the Y Tilt direction to match the HID standard and
+                * userspace expectations. See HID Usage Tables v1.12 16.3.2
+                * Tilt Orientation.
+                */
+               sign_y *= -1;
+
+               /*
+                * This effectively clamps reported tilt to 60 degrees - the
+                * range expected by userspace
+                */
+               if (tilt_x > ARRAY_SIZE(tilt_to_radians) - 1)
+                       tilt_x = ARRAY_SIZE(tilt_to_radians) - 1;
+               if (tilt_y > ARRAY_SIZE(tilt_to_radians) - 1)
+                       tilt_y = ARRAY_SIZE(tilt_to_radians) - 1;
+
+               data[8] = tilt_to_radians[tilt_x] * sign_x;
+               data[9] = tilt_to_radians[tilt_y] * sign_y;
+       }
+
        return 0;
 }
 
 static void waltop_remove(struct hid_device *hdev)
 {
-       struct waltop_state *s = hid_get_drvdata(hdev);
-
        hid_hw_stop(hdev);
-       kfree(s);
 }
 
 static const struct hid_device_id waltop_devices[] = {
@@ -638,6 +794,8 @@ static const struct hid_device_id waltop_devices[] = {
                                USB_DEVICE_ID_WALTOP_MEDIA_TABLET_10_6_INCH) },
        { HID_USB_DEVICE(USB_VENDOR_ID_WALTOP,
                                USB_DEVICE_ID_WALTOP_MEDIA_TABLET_14_1_INCH) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_WALTOP,
+                        USB_DEVICE_ID_WALTOP_SIRIUS_BATTERY_FREE_TABLET) },
        { }
 };
 MODULE_DEVICE_TABLE(hid, waltop_devices);
index cac3589b1ed5ac192455b804db0ea321d603ec8a..84e2fbec5fbb8ecb84c5139766caafdcc8cc53af 100644 (file)
@@ -769,7 +769,7 @@ static void __ir_to_input(struct wiimote_data *wdata, const __u8 *ir,
 
        /*
         * Basic IR data is encoded into 3 bytes. The first two bytes are the
-        * upper 8 bit of the X/Y data, the 3rd byte contains the lower 2 bits
+        * lower 8 bit of the X/Y data, the 3rd byte contains the upper 2 bits
         * of both.
         * If data is packed, then the 3rd byte is put first and slightly
         * reordered. This allows to interleave packed and non-packed data to
@@ -778,17 +778,11 @@ static void __ir_to_input(struct wiimote_data *wdata, const __u8 *ir,
         */
 
        if (packed) {
-               x = ir[1] << 2;
-               y = ir[2] << 2;
-
-               x |= ir[0] & 0x3;
-               y |= (ir[0] >> 2) & 0x3;
+               x = ir[1] | ((ir[0] & 0x03) << 8);
+               y = ir[2] | ((ir[0] & 0x0c) << 6);
        } else {
-               x = ir[0] << 2;
-               y = ir[1] << 2;
-
-               x |= (ir[2] >> 4) & 0x3;
-               y |= (ir[2] >> 6) & 0x3;
+               x = ir[0] | ((ir[2] & 0x30) << 4);
+               y = ir[1] | ((ir[2] & 0xc0) << 2);
        }
 
        input_report_abs(wdata->ir, xid, x);
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 340d6ae646edc7cdfb5f1cf8e02e8a39f00e12d4..482f936fc29b0deb04b3ddb3b7fe894a60c95b57 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;
                }
@@ -749,7 +757,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++) {
@@ -757,17 +765,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)
@@ -1396,7 +1414,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);
@@ -1553,28 +1598,15 @@ static struct usb_driver hid_driver = {
        .supports_autosuspend = 1,
 };
 
-static const struct hid_device_id hid_usb_table[] = {
-       { HID_USB_DEVICE(HID_ANY_ID, HID_ANY_ID) },
-       { }
-};
-
 struct usb_interface *usbhid_find_interface(int minor)
 {
        return usb_find_interface(&hid_driver, minor);
 }
 
-static struct hid_driver hid_usb_driver = {
-       .name = "generic-usb",
-       .id_table = hid_usb_table,
-};
-
 static int __init hid_init(void)
 {
        int retval = -ENOMEM;
 
-       retval = hid_register_driver(&hid_usb_driver);
-       if (retval)
-               goto hid_register_fail;
        retval = usbhid_quirks_init(quirks_param);
        if (retval)
                goto usbhid_quirks_init_fail;
@@ -1587,8 +1619,6 @@ static int __init hid_init(void)
 usb_register_fail:
        usbhid_quirks_exit();
 usbhid_quirks_init_fail:
-       hid_unregister_driver(&hid_usb_driver);
-hid_register_fail:
        return retval;
 }
 
@@ -1596,7 +1626,6 @@ static void __exit hid_exit(void)
 {
        usb_deregister(&hid_driver);
        usbhid_quirks_exit();
-       hid_unregister_driver(&hid_usb_driver);
 }
 
 module_init(hid_init);
index 782c63955f2953d0098c3838d65a96c5c5c4e0bb..0597ee604f6e1d096bf1404a6161949df73de154 100644 (file)
@@ -88,6 +88,7 @@ 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_WALTOP, USB_DEVICE_ID_WALTOP_SIRIUS_BATTERY_FREE_TABLET, HID_QUIRK_MULTI_INPUT },
        { USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_QUAD_USB_JOYPAD, 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 },
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 3a95da60fd3e5cda95617fffc824168437373d95..449fa385703df5375db5cad0786bbc4a7f35b716 100644 (file)
@@ -317,13 +317,18 @@ struct hid_item {
 #define HID_QUIRK_BADPAD                       0x00000020
 #define HID_QUIRK_MULTI_INPUT                  0x00000040
 #define HID_QUIRK_HIDINPUT_FORCE               0x00000080
-#define HID_QUIRK_MULTITOUCH                   0x00000100
 #define HID_QUIRK_SKIP_OUTPUT_REPORTS          0x00010000
 #define HID_QUIRK_FULLSPEED_INTERVAL           0x10000000
 #define HID_QUIRK_NO_INIT_REPORTS              0x20000000
 #define HID_QUIRK_NO_IGNORE                    0x40000000
 #define HID_QUIRK_NO_INPUT_SYNC                        0x80000000
 
+/*
+ * HID device groups
+ */
+#define HID_GROUP_GENERIC                      0x0001
+#define HID_GROUP_MULTITOUCH                   0x0002
+
 /*
  * This is the global environment of the parser. This information is
  * persistent for main-items. The global environment can be saved and
@@ -467,6 +472,8 @@ struct hid_driver;
 struct hid_ll_driver;
 
 struct hid_device {                                                    /* device report descriptor */
+       __u8 *dev_rdesc;
+       unsigned dev_rsize;
        __u8 *rdesc;
        unsigned rsize;
        struct hid_collection *collection;                              /* List of HID collections */
@@ -474,6 +481,7 @@ struct hid_device {                                                 /* device report descriptor */
        unsigned maxcollection;                                         /* Number of parsed collections */
        unsigned maxapplication;                                        /* Number of applications */
        __u16 bus;                                                      /* BUS ID */
+       __u16 group;                                                    /* Report group */
        __u32 vendor;                                                   /* Vendor ID */
        __u32 product;                                                  /* Product ID */
        __u32 version;                                                  /* HID version */
@@ -578,12 +586,12 @@ struct hid_descriptor {
        struct hid_class_descriptor desc[1];
 } __attribute__ ((packed));
 
-#define HID_DEVICE(b, ven, prod) \
-       .bus = (b), \
-       .vendor = (ven), .product = (prod)
-
-#define HID_USB_DEVICE(ven, prod)      HID_DEVICE(BUS_USB, ven, prod)
-#define HID_BLUETOOTH_DEVICE(ven, prod)        HID_DEVICE(BUS_BLUETOOTH, ven, prod)
+#define HID_DEVICE(b, g, ven, prod)                                    \
+       .bus = (b), .group = (g), .vendor = (ven), .product = (prod)
+#define HID_USB_DEVICE(ven, prod)                              \
+       .bus = BUS_USB, .vendor = (ven), .product = (prod)
+#define HID_BLUETOOTH_DEVICE(ven, prod)                                        \
+       .bus = BUS_BLUETOOTH, .vendor = (ven), .product = (prod)
 
 #define HID_REPORT_ID(rep) \
        .report_type = (rep)
@@ -735,6 +743,7 @@ void hid_output_report(struct hid_report *report, __u8 *data);
 struct hid_device *hid_allocate_device(void);
 struct hid_report *hid_register_report(struct hid_device *device, unsigned type, unsigned id);
 int hid_parse_report(struct hid_device *hid, __u8 *start, unsigned size);
+int hid_open_report(struct hid_device *device);
 int hid_check_keys_pressed(struct hid_device *hid);
 int hid_connect(struct hid_device *hid, unsigned int connect_mask);
 void hid_disconnect(struct hid_device *hid);
@@ -805,16 +814,7 @@ static inline void hid_map_usage_clear(struct hid_input *hidinput,
  */
 static inline int __must_check hid_parse(struct hid_device *hdev)
 {
-       int ret;
-
-       if (hdev->status & HID_STAT_PARSED)
-               return 0;
-
-       ret = hdev->ll_driver->parse(hdev);
-       if (!ret)
-               hdev->status |= HID_STAT_PARSED;
-
-       return ret;
+       return hid_open_report(hdev);
 }
 
 /**
@@ -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
index 501da4cb8a6de02ecd0dbe8b6759c26b298d2c12..5db93821f9c7d473d1d4fe87f9e3fc5d988044bb 100644 (file)
@@ -132,10 +132,12 @@ struct usb_device_id {
 #define USB_DEVICE_ID_MATCH_INT_PROTOCOL       0x0200
 
 #define HID_ANY_ID                             (~0)
+#define HID_BUS_ANY                            0xffff
+#define HID_GROUP_ANY                          0x0000
 
 struct hid_device_id {
        __u16 bus;
-       __u16 pad1;
+       __u16 group;
        __u32 vendor;
        __u32 product;
        kernel_ulong_t driver_data
index d478be11d562995ae08c65bc8198c187ee686d61..2c20d765b394841bf878c331b4f7c69a897e6e28 100644 (file)
@@ -1195,41 +1195,16 @@ int hidp_get_conninfo(struct hidp_conninfo *ci)
        return err;
 }
 
-static const struct hid_device_id hidp_table[] = {
-       { HID_BLUETOOTH_DEVICE(HID_ANY_ID, HID_ANY_ID) },
-       { }
-};
-
-static struct hid_driver hidp_driver = {
-       .name = "generic-bluetooth",
-       .id_table = hidp_table,
-};
-
 static int __init hidp_init(void)
 {
-       int ret;
-
        BT_INFO("HIDP (Human Interface Emulation) ver %s", VERSION);
 
-       ret = hid_register_driver(&hidp_driver);
-       if (ret)
-               goto err;
-
-       ret = hidp_init_sockets();
-       if (ret)
-               goto err_drv;
-
-       return 0;
-err_drv:
-       hid_unregister_driver(&hidp_driver);
-err:
-       return ret;
+       return hidp_init_sockets();
 }
 
 static void __exit hidp_exit(void)
 {
        hidp_cleanup_sockets();
-       hid_unregister_driver(&hidp_driver);
 }
 
 module_init(hidp_init);
index 44ddaa542db6fbb6612560ac312b65ffca330b4c..5759751a1f61212ec02e16de995a8a0482b37c11 100644 (file)
@@ -336,10 +336,13 @@ static int do_hid_entry(const char *filename,
                             struct hid_device_id *id, char *alias)
 {
        id->bus = TO_NATIVE(id->bus);
+       id->group = TO_NATIVE(id->group);
        id->vendor = TO_NATIVE(id->vendor);
        id->product = TO_NATIVE(id->product);
 
-       sprintf(alias, "hid:b%04X", id->bus);
+       sprintf(alias, "hid:");
+       ADD(alias, "b", id->bus != HID_BUS_ANY, id->bus);
+       ADD(alias, "g", id->group != HID_GROUP_ANY, id->group);
        ADD(alias, "v", id->vendor != HID_ANY_ID, id->vendor);
        ADD(alias, "p", id->product != HID_ANY_ID, id->product);