Merge branches 'doc', 'multitouch', 'upstream' and 'upstream-fixes' into for-linus
Jiri Kosina [Mon, 23 May 2011 10:49:25 +0000 (12:49 +0200)]
21 files changed:
Documentation/hid/hiddev.txt [moved from Documentation/usb/hiddev.txt with 100% similarity]
Documentation/hid/hidraw.txt [new file with mode: 0644]
drivers/hid/Kconfig
drivers/hid/Makefile
drivers/hid/hid-3m-pct.c [deleted file]
drivers/hid/hid-cando.c [deleted file]
drivers/hid/hid-core.c
drivers/hid/hid-ids.h
drivers/hid/hid-lg.c
drivers/hid/hid-lgff.c
drivers/hid/hid-magicmouse.c
drivers/hid/hid-mosart.c [deleted file]
drivers/hid/hid-multitouch.c
drivers/hid/hid-sony.c
drivers/hid/hid-stantum.c [deleted file]
drivers/hid/usbhid/hid-quirks.c
drivers/hid/usbhid/hiddev.c
samples/Kconfig
samples/Makefile
samples/hidraw/Makefile [new file with mode: 0644]
samples/hidraw/hid-example.c [new file with mode: 0644]

diff --git a/Documentation/hid/hidraw.txt b/Documentation/hid/hidraw.txt
new file mode 100644 (file)
index 0000000..029e6cb
--- /dev/null
@@ -0,0 +1,119 @@
+      HIDRAW - Raw Access to USB and Bluetooth Human Interface Devices
+     ==================================================================
+
+The hidraw driver provides a raw interface to USB and Bluetooth Human
+Interface Devices (HIDs).  It differs from hiddev in that reports sent and
+received are not parsed by the HID parser, but are sent to and received from
+the device unmodified.
+
+Hidraw should be used if the userspace application knows exactly how to
+communicate with the hardware device, and is able to construct the HID
+reports manually.  This is often the case when making userspace drivers for
+custom HID devices.
+
+Hidraw is also useful for communicating with non-conformant HID devices
+which send and receive data in a way that is inconsistent with their report
+descriptors.  Because hiddev parses reports which are sent and received
+through it, checking them against the device's report descriptor, such
+communication with these non-conformant devices is impossible using hiddev.
+Hidraw is the only alternative, short of writing a custom kernel driver, for
+these non-conformant devices.
+
+A benefit of hidraw is that its use by userspace applications is independent
+of the underlying hardware type.  Currently, Hidraw is implemented for USB
+and Bluetooth.  In the future, as new hardware bus types are developed which
+use the HID specification, hidraw will be expanded to add support for these
+new bus types.
+
+Hidraw uses a dynamic major number, meaning that udev should be relied on to
+create hidraw device nodes.  Udev will typically create the device nodes
+directly under /dev (eg: /dev/hidraw0).  As this location is distribution-
+and udev rule-dependent, applications should use libudev to locate hidraw
+devices attached to the system.  There is a tutorial on libudev with a
+working example at:
+       http://www.signal11.us/oss/udev/
+
+The HIDRAW API
+---------------
+
+read()
+-------
+read() will read a queued report received from the HID device. On USB
+devices, the reports read using read() are the reports sent from the device
+on the INTERRUPT IN endpoint.  By default, read() will block until there is
+a report available to be read.  read() can be made non-blocking, by passing
+the O_NONBLOCK flag to open(), or by setting the O_NONBLOCK flag using
+fcntl().
+
+On a device which uses numbered reports, the first byte of the returned data
+will be the report number; the report data follows, beginning in the second
+byte.  For devices which do not use numbered reports, the report data
+will begin at the first byte.
+
+write()
+--------
+The write() function will write a report to the device. For USB devices, if
+the device has an INTERRUPT OUT endpoint, the report will be sent on that
+endpoint. If it does not, the report will be sent over the control endpoint,
+using a SET_REPORT transfer.
+
+The first byte of the buffer passed to write() should be set to the report
+number.  If the device does not use numbered reports, the first byte should
+be set to 0. The report data itself should begin at the second byte.
+
+ioctl()
+--------
+Hidraw supports the following ioctls:
+
+HIDIOCGRDESCSIZE: Get Report Descriptor Size
+This ioctl will get the size of the device's report descriptor.
+
+HIDIOCGRDESC: Get Report Descriptor
+This ioctl returns the device's report descriptor using a
+hidraw_report_descriptor struct.  Make sure to set the size field of the
+hidraw_report_descriptor struct to the size returned from HIDIOCGRDESCSIZE.
+
+HIDIOCGRAWINFO: Get Raw Info
+This ioctl will return a hidraw_devinfo struct containing the bus type, the
+vendor ID (VID), and product ID (PID) of the device. The bus type can be one
+of:
+       BUS_USB
+       BUS_HIL
+       BUS_BLUETOOTH
+       BUS_VIRTUAL
+which are defined in linux/input.h.
+
+HIDIOCGRAWNAME(len): Get Raw Name
+This ioctl returns a string containing the vendor and product strings of
+the device.  The returned string is Unicode, UTF-8 encoded.
+
+HIDIOCGRAWPHYS(len): Get Physical Address
+This ioctl returns a string representing the physical address of the device.
+For USB devices, the string contains the physical path to the device (the
+USB controller, hubs, ports, etc).  For Bluetooth devices, the string
+contains the hardware (MAC) address of the device.
+
+HIDIOCSFEATURE(len): Send a Feature Report
+This ioctl will send a feature report to the device.  Per the HID
+specification, feature reports are always sent using the control endpoint.
+Set the first byte of the supplied buffer to the report number.  For devices
+which do not use numbered reports, set the first byte to 0. The report data
+begins in the second byte. Make sure to set len accordingly, to one more
+than the length of the report (to account for the report number).
+
+HIDIOCGFEATURE(len): Get a Feature Report
+This ioctl will request a feature report from the device using the control
+endpoint.  The first byte of the supplied buffer should be set to the report
+number of the requested report.  For devices which do not use numbered
+reports, set the first byte to 0.  The report will be returned starting at
+the first byte of the buffer (ie: the report number is not returned).
+
+Example
+---------
+In samples/, find hid-example.c, which shows examples of read(), write(),
+and all the ioctls for hidraw.  The code may be used by anyone for any
+purpose, and can serve as a starting point for developing applications using
+hidraw.
+
+Document by:
+       Alan Ott <alan@signal11.us>, Signal 11 Software
index 9de9e97..67d2a75 100644 (file)
@@ -55,12 +55,6 @@ source "drivers/hid/usbhid/Kconfig"
 menu "Special HID drivers"
        depends on HID
 
-config HID_3M_PCT
-       tristate "3M PCT touchscreen"
-       depends on USB_HID
-       ---help---
-       Support for 3M PCT touch screens.
-
 config HID_A4TECH
        tristate "A4 tech mice" if EXPERT
        depends on USB_HID
@@ -100,12 +94,6 @@ config HID_BELKIN
        ---help---
        Support for Belkin Flip KVM and Wireless keyboard.
 
-config HID_CANDO
-       tristate "Cando dual touch panel"
-       depends on USB_HID
-       ---help---
-       Support for Cando dual touch panel.
-
 config HID_CHERRY
        tristate "Cherry Cymotion keyboard" if EXPERT
        depends on USB_HID
@@ -300,12 +288,6 @@ config HID_MICROSOFT
        ---help---
        Support for Microsoft devices that are not fully compliant with HID standard.
 
-config HID_MOSART
-       tristate "MosArt dual-touch panels"
-       depends on USB_HID
-       ---help---
-       Support for MosArt dual-touch panels.
-
 config HID_MONTEREY
        tristate "Monterey Genius KB29E keyboard" if EXPERT
        depends on USB_HID
@@ -320,13 +302,25 @@ config HID_MULTITOUCH
          Generic support for HID multitouch panels.
 
          Say Y here if you have one of the following devices:
+         - 3M PCT touch screens
+         - ActionStar dual touch panels
+         - Cando dual touch panels
+         - CVTouch panels
          - Cypress TrueTouch panels
+         - Elo TouchSystems IntelliTouch Plus panels
+         - GeneralTouch 'Sensing Win7-TwoFinger' panels
+         - GoodTouch panels
          - Hanvon dual touch panels
+         - Ilitek dual touch panels
          - IrTouch Infrared USB panels
+         - Lumio CrystalTouch panels
+         - MosArt dual-touch panels
+         - PenMount dual touch panels
          - Pixcir dual touch panels
-         - 'Sensing Win7-TwoFinger' panel by GeneralTouch
-          - eGalax dual-touch panels, including the
-           Joojoo and Wetab tablets
+         - eGalax dual-touch panels, including the Joojoo and Wetab tablets
+         - Stantum multitouch panels
+         - Touch International Panels
+         - Unitec Panels
 
          If unsure, say N.
 
@@ -500,12 +494,6 @@ config HID_SONY
        ---help---
        Support for Sony PS3 controller.
 
-config HID_STANTUM
-       tristate "Stantum multitouch panel"
-       depends on USB_HID
-       ---help---
-       Support for Stantum multitouch panel.
-
 config HID_SUNPLUS
        tristate "Sunplus wireless desktop"
        depends on USB_HID
index 06c68ae..f8cc4ea 100644 (file)
@@ -25,12 +25,10 @@ ifdef CONFIG_LOGIWII_FF
        hid-logitech-y  += hid-lg4ff.o
 endif
 
-obj-$(CONFIG_HID_3M_PCT)       += hid-3m-pct.o
 obj-$(CONFIG_HID_A4TECH)       += hid-a4tech.o
 obj-$(CONFIG_HID_ACRUX)                += hid-axff.o
 obj-$(CONFIG_HID_APPLE)                += hid-apple.o
 obj-$(CONFIG_HID_BELKIN)       += hid-belkin.o
-obj-$(CONFIG_HID_CANDO)                += hid-cando.o
 obj-$(CONFIG_HID_CHERRY)       += hid-cherry.o
 obj-$(CONFIG_HID_CHICONY)      += hid-chicony.o
 obj-$(CONFIG_HID_CYPRESS)      += hid-cypress.o
@@ -47,7 +45,6 @@ obj-$(CONFIG_HID_LOGITECH)    += hid-logitech.o
 obj-$(CONFIG_HID_MAGICMOUSE)    += hid-magicmouse.o
 obj-$(CONFIG_HID_MICROSOFT)    += hid-microsoft.o
 obj-$(CONFIG_HID_MONTEREY)     += hid-monterey.o
-obj-$(CONFIG_HID_MOSART)       += hid-mosart.o
 obj-$(CONFIG_HID_MULTITOUCH)   += hid-multitouch.o
 obj-$(CONFIG_HID_NTRIG)                += hid-ntrig.o
 obj-$(CONFIG_HID_ORTEK)                += hid-ortek.o
@@ -66,7 +63,6 @@ obj-$(CONFIG_HID_ROCCAT_PYRA) += hid-roccat-pyra.o
 obj-$(CONFIG_HID_SAMSUNG)      += hid-samsung.o
 obj-$(CONFIG_HID_SMARTJOYPLUS) += hid-sjoy.o
 obj-$(CONFIG_HID_SONY)         += hid-sony.o
-obj-$(CONFIG_HID_STANTUM)      += hid-stantum.o
 obj-$(CONFIG_HID_SUNPLUS)      += hid-sunplus.o
 obj-$(CONFIG_HID_GREENASIA)    += hid-gaff.o
 obj-$(CONFIG_HID_THRUSTMASTER) += hid-tmff.o
diff --git a/drivers/hid/hid-3m-pct.c b/drivers/hid/hid-3m-pct.c
deleted file mode 100644 (file)
index 5243ae2..0000000
+++ /dev/null
@@ -1,305 +0,0 @@
-/*
- *  HID driver for 3M PCT multitouch panels
- *
- *  Copyright (c) 2009-2010 Stephane Chatty <chatty@enac.fr>
- *  Copyright (c) 2010      Henrik Rydberg <rydberg@euromail.se>
- *  Copyright (c) 2010      Canonical, Ltd.
- *
- */
-
-/*
- * 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/device.h>
-#include <linux/hid.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/usb.h>
-#include <linux/input/mt.h>
-
-MODULE_AUTHOR("Stephane Chatty <chatty@enac.fr>");
-MODULE_DESCRIPTION("3M PCT multitouch panels");
-MODULE_LICENSE("GPL");
-
-#include "hid-ids.h"
-
-#define MAX_SLOTS              60
-
-/* estimated signal-to-noise ratios */
-#define SN_MOVE                        2048
-#define SN_WIDTH               128
-
-struct mmm_finger {
-       __s32 x, y, w, h;
-       bool touch, valid;
-};
-
-struct mmm_data {
-       struct mmm_finger f[MAX_SLOTS];
-       __u8 curid;
-       __u8 nexp, nreal;
-       bool touch, valid;
-};
-
-static int mmm_input_mapping(struct hid_device *hdev, struct hid_input *hi,
-               struct hid_field *field, struct hid_usage *usage,
-               unsigned long **bit, int *max)
-{
-       int f1 = field->logical_minimum;
-       int f2 = field->logical_maximum;
-       int df = f2 - f1;
-
-       switch (usage->hid & HID_USAGE_PAGE) {
-
-       case HID_UP_BUTTON:
-               return -1;
-
-       case HID_UP_GENDESK:
-               switch (usage->hid) {
-               case HID_GD_X:
-                       hid_map_usage(hi, usage, bit, max,
-                                       EV_ABS, ABS_MT_POSITION_X);
-                       input_set_abs_params(hi->input, ABS_MT_POSITION_X,
-                                            f1, f2, df / SN_MOVE, 0);
-                       /* touchscreen emulation */
-                       input_set_abs_params(hi->input, ABS_X,
-                                            f1, f2, df / SN_MOVE, 0);
-                       return 1;
-               case HID_GD_Y:
-                       hid_map_usage(hi, usage, bit, max,
-                                       EV_ABS, ABS_MT_POSITION_Y);
-                       input_set_abs_params(hi->input, ABS_MT_POSITION_Y,
-                                            f1, f2, df / SN_MOVE, 0);
-                       /* touchscreen emulation */
-                       input_set_abs_params(hi->input, ABS_Y,
-                                            f1, f2, df / SN_MOVE, 0);
-                       return 1;
-               }
-               return 0;
-
-       case HID_UP_DIGITIZER:
-               switch (usage->hid) {
-               /* we do not want to map these: no input-oriented meaning */
-               case 0x14:
-               case 0x23:
-               case HID_DG_INPUTMODE:
-               case HID_DG_DEVICEINDEX:
-               case HID_DG_CONTACTCOUNT:
-               case HID_DG_CONTACTMAX:
-               case HID_DG_INRANGE:
-               case HID_DG_CONFIDENCE:
-                       return -1;
-               case HID_DG_TIPSWITCH:
-                       /* touchscreen emulation */
-                       hid_map_usage(hi, usage, bit, max, EV_KEY, BTN_TOUCH);
-                       input_set_capability(hi->input, EV_KEY, BTN_TOUCH);
-                       return 1;
-               case HID_DG_WIDTH:
-                       hid_map_usage(hi, usage, bit, max,
-                                       EV_ABS, ABS_MT_TOUCH_MAJOR);
-                       input_set_abs_params(hi->input, ABS_MT_TOUCH_MAJOR,
-                                            f1, f2, df / SN_WIDTH, 0);
-                       return 1;
-               case HID_DG_HEIGHT:
-                       hid_map_usage(hi, usage, bit, max,
-                                       EV_ABS, ABS_MT_TOUCH_MINOR);
-                       input_set_abs_params(hi->input, ABS_MT_TOUCH_MINOR,
-                                            f1, f2, df / SN_WIDTH, 0);
-                       input_set_abs_params(hi->input, ABS_MT_ORIENTATION,
-                                       0, 1, 0, 0);
-                       return 1;
-               case HID_DG_CONTACTID:
-                       input_mt_init_slots(hi->input, MAX_SLOTS);
-                       return 1;
-               }
-               /* let hid-input decide for the others */
-               return 0;
-
-       case 0xff000000:
-               /* we do not want to map these: no input-oriented meaning */
-               return -1;
-       }
-
-       return 0;
-}
-
-static int mmm_input_mapped(struct hid_device *hdev, struct hid_input *hi,
-               struct hid_field *field, struct hid_usage *usage,
-               unsigned long **bit, int *max)
-{
-       /* tell hid-input to skip setup of these event types */
-       if (usage->type == EV_KEY || usage->type == EV_ABS)
-               set_bit(usage->type, hi->input->evbit);
-       return -1;
-}
-
-/*
- * this function is called when a whole packet has been received and processed,
- * so that it can decide what to send to the input layer.
- */
-static void mmm_filter_event(struct mmm_data *md, struct input_dev *input)
-{
-       int i;
-       for (i = 0; i < MAX_SLOTS; ++i) {
-               struct mmm_finger *f = &md->f[i];
-               if (!f->valid) {
-                       /* this finger is just placeholder data, ignore */
-                       continue;
-               }
-               input_mt_slot(input, i);
-               input_mt_report_slot_state(input, MT_TOOL_FINGER, f->touch);
-               if (f->touch) {
-                       /* this finger is on the screen */
-                       int wide = (f->w > f->h);
-                       /* divided by two to match visual scale of touch */
-                       int major = max(f->w, f->h) >> 1;
-                       int minor = min(f->w, f->h) >> 1;
-
-                       input_event(input, EV_ABS, ABS_MT_POSITION_X, f->x);
-                       input_event(input, EV_ABS, ABS_MT_POSITION_Y, f->y);
-                       input_event(input, EV_ABS, ABS_MT_ORIENTATION, wide);
-                       input_event(input, EV_ABS, ABS_MT_TOUCH_MAJOR, major);
-                       input_event(input, EV_ABS, ABS_MT_TOUCH_MINOR, minor);
-               }
-               f->valid = 0;
-       }
-
-       input_mt_report_pointer_emulation(input, true);
-       input_sync(input);
-}
-
-/*
- * this function is called upon all reports
- * so that we can accumulate contact point information,
- * and call input_mt_sync after each point.
- */
-static int mmm_event(struct hid_device *hid, struct hid_field *field,
-                               struct hid_usage *usage, __s32 value)
-{
-       struct mmm_data *md = hid_get_drvdata(hid);
-       /*
-        * strangely, this function can be called before
-        * field->hidinput is initialized!
-        */
-       if (hid->claimed & HID_CLAIMED_INPUT) {
-               struct input_dev *input = field->hidinput->input;
-               switch (usage->hid) {
-               case HID_DG_TIPSWITCH:
-                       md->touch = value;
-                       break;
-               case HID_DG_CONFIDENCE:
-                       md->valid = value;
-                       break;
-               case HID_DG_WIDTH:
-                       if (md->valid)
-                               md->f[md->curid].w = value;
-                       break;
-               case HID_DG_HEIGHT:
-                       if (md->valid)
-                               md->f[md->curid].h = value;
-                       break;
-               case HID_DG_CONTACTID:
-                       value = clamp_val(value, 0, MAX_SLOTS - 1);
-                       if (md->valid) {
-                               md->curid = value;
-                               md->f[value].touch = md->touch;
-                               md->f[value].valid = 1;
-                               md->nreal++;
-                       }
-                       break;
-               case HID_GD_X:
-                       if (md->valid)
-                               md->f[md->curid].x = value;
-                       break;
-               case HID_GD_Y:
-                       if (md->valid)
-                               md->f[md->curid].y = value;
-                       break;
-               case HID_DG_CONTACTCOUNT:
-                       if (value)
-                               md->nexp = value;
-                       if (md->nreal >= md->nexp) {
-                               mmm_filter_event(md, input);
-                               md->nreal = 0;
-                       }
-                       break;
-               }
-       }
-
-       /* we have handled the hidinput part, now remains hiddev */
-       if (hid->claimed & HID_CLAIMED_HIDDEV && hid->hiddev_hid_event)
-               hid->hiddev_hid_event(hid, field, usage, value);
-
-       return 1;
-}
-
-static int mmm_probe(struct hid_device *hdev, const struct hid_device_id *id)
-{
-       int ret;
-       struct mmm_data *md;
-
-       hdev->quirks |= HID_QUIRK_NO_INPUT_SYNC;
-
-       md = kzalloc(sizeof(struct mmm_data), GFP_KERNEL);
-       if (!md) {
-               hid_err(hdev, "cannot allocate 3M data\n");
-               return -ENOMEM;
-       }
-       hid_set_drvdata(hdev, md);
-
-       ret = hid_parse(hdev);
-       if (!ret)
-               ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
-
-       if (ret)
-               kfree(md);
-       return ret;
-}
-
-static void mmm_remove(struct hid_device *hdev)
-{
-       hid_hw_stop(hdev);
-       kfree(hid_get_drvdata(hdev));
-       hid_set_drvdata(hdev, NULL);
-}
-
-static const struct hid_device_id mmm_devices[] = {
-       { HID_USB_DEVICE(USB_VENDOR_ID_3M, USB_DEVICE_ID_3M1968) },
-       { HID_USB_DEVICE(USB_VENDOR_ID_3M, USB_DEVICE_ID_3M2256) },
-       { }
-};
-MODULE_DEVICE_TABLE(hid, mmm_devices);
-
-static const struct hid_usage_id mmm_grabbed_usages[] = {
-       { HID_ANY_ID, HID_ANY_ID, HID_ANY_ID },
-       { HID_ANY_ID - 1, HID_ANY_ID - 1, HID_ANY_ID - 1}
-};
-
-static struct hid_driver mmm_driver = {
-       .name = "3m-pct",
-       .id_table = mmm_devices,
-       .probe = mmm_probe,
-       .remove = mmm_remove,
-       .input_mapping = mmm_input_mapping,
-       .input_mapped = mmm_input_mapped,
-       .usage_table = mmm_grabbed_usages,
-       .event = mmm_event,
-};
-
-static int __init mmm_init(void)
-{
-       return hid_register_driver(&mmm_driver);
-}
-
-static void __exit mmm_exit(void)
-{
-       hid_unregister_driver(&mmm_driver);
-}
-
-module_init(mmm_init);
-module_exit(mmm_exit);
-
diff --git a/drivers/hid/hid-cando.c b/drivers/hid/hid-cando.c
deleted file mode 100644 (file)
index 1ea066c..0000000
+++ /dev/null
@@ -1,276 +0,0 @@
-/*
- *  HID driver for Cando dual-touch panels
- *
- *  Copyright (c) 2010 Stephane Chatty <chatty@enac.fr>
- *
- */
-
-/*
- * 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/device.h>
-#include <linux/hid.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-
-MODULE_AUTHOR("Stephane Chatty <chatty@enac.fr>");
-MODULE_DESCRIPTION("Cando dual-touch panel");
-MODULE_LICENSE("GPL");
-
-#include "hid-ids.h"
-
-struct cando_data {
-       __u16 x, y;
-       __u8 id;
-       __s8 oldest;            /* id of the oldest finger in previous frame */
-       bool valid;             /* valid finger data, or just placeholder? */
-       bool first;             /* is this the first finger in this frame? */
-       __s8 firstid;           /* id of the first finger in the frame */
-       __u16 firstx, firsty;   /* (x, y) of the first finger in the frame */
-};
-
-static int cando_input_mapping(struct hid_device *hdev, struct hid_input *hi,
-               struct hid_field *field, struct hid_usage *usage,
-               unsigned long **bit, int *max)
-{
-       switch (usage->hid & HID_USAGE_PAGE) {
-
-       case HID_UP_GENDESK:
-               switch (usage->hid) {
-               case HID_GD_X:
-                       hid_map_usage(hi, usage, bit, max,
-                                       EV_ABS, ABS_MT_POSITION_X);
-                       /* touchscreen emulation */
-                       input_set_abs_params(hi->input, ABS_X,
-                                               field->logical_minimum,
-                                               field->logical_maximum, 0, 0);
-                       return 1;
-               case HID_GD_Y:
-                       hid_map_usage(hi, usage, bit, max,
-                                       EV_ABS, ABS_MT_POSITION_Y);
-                       /* touchscreen emulation */
-                       input_set_abs_params(hi->input, ABS_Y,
-                                               field->logical_minimum,
-                                               field->logical_maximum, 0, 0);
-                       return 1;
-               }
-               return 0;
-
-       case HID_UP_DIGITIZER:
-               switch (usage->hid) {
-               case HID_DG_TIPSWITCH:
-               case HID_DG_CONTACTMAX:
-                       return -1;
-               case HID_DG_INRANGE:
-                       /* touchscreen emulation */
-                       hid_map_usage(hi, usage, bit, max, EV_KEY, BTN_TOUCH);
-                       return 1;
-               case HID_DG_CONTACTID:
-                       hid_map_usage(hi, usage, bit, max,
-                                       EV_ABS, ABS_MT_TRACKING_ID);
-                       return 1;
-               }
-               return 0;
-       }
-
-       return 0;
-}
-
-static int cando_input_mapped(struct hid_device *hdev, struct hid_input *hi,
-               struct hid_field *field, struct hid_usage *usage,
-               unsigned long **bit, int *max)
-{
-       if (usage->type == EV_KEY || usage->type == EV_ABS)
-               clear_bit(usage->code, *bit);
-
-       return 0;
-}
-
-/*
- * this function is called when a whole finger has been parsed,
- * so that it can decide what to send to the input layer.
- */
-static void cando_filter_event(struct cando_data *td, struct input_dev *input)
-{
-       td->first = !td->first; /* touchscreen emulation */
-
-       if (!td->valid) {
-               /*
-                * touchscreen emulation: if this is the second finger and
-                * the first was valid, the first was the oldest; if the
-                * first was not valid and there was a valid finger in the
-                * previous frame, this is a release.
-                */
-               if (td->first) {
-                       td->firstid = -1;
-               } else if (td->firstid >= 0) {
-                       input_event(input, EV_ABS, ABS_X, td->firstx);
-                       input_event(input, EV_ABS, ABS_Y, td->firsty);
-                       td->oldest = td->firstid;
-               } else if (td->oldest >= 0) {
-                       input_event(input, EV_KEY, BTN_TOUCH, 0);
-                       td->oldest = -1;
-               }
-
-               return;
-       }
-       
-       input_event(input, EV_ABS, ABS_MT_TRACKING_ID, td->id);
-       input_event(input, EV_ABS, ABS_MT_POSITION_X, td->x);
-       input_event(input, EV_ABS, ABS_MT_POSITION_Y, td->y);
-
-       input_mt_sync(input);
-
-       /*
-        * touchscreen emulation: if there was no touching finger previously,
-        * emit touch event
-        */
-       if (td->oldest < 0) {
-               input_event(input, EV_KEY, BTN_TOUCH, 1);
-               td->oldest = td->id;
-       }
-
-       /*
-        * touchscreen emulation: if this is the first finger, wait for the
-        * second; the oldest is then the second if it was the oldest already
-        * or if there was no first, the first otherwise.
-        */
-       if (td->first) {
-               td->firstx = td->x;
-               td->firsty = td->y;
-               td->firstid = td->id;
-       } else {
-               int x, y, oldest;
-               if (td->id == td->oldest || td->firstid < 0) {
-                       x = td->x;
-                       y = td->y;
-                       oldest = td->id;
-               } else {
-                       x = td->firstx;
-                       y = td->firsty;
-                       oldest = td->firstid;
-               }
-               input_event(input, EV_ABS, ABS_X, x);
-               input_event(input, EV_ABS, ABS_Y, y);
-               td->oldest = oldest;
-       }
-}
-
-
-static int cando_event(struct hid_device *hid, struct hid_field *field,
-                               struct hid_usage *usage, __s32 value)
-{
-       struct cando_data *td = hid_get_drvdata(hid);
-
-       if (hid->claimed & HID_CLAIMED_INPUT) {
-               struct input_dev *input = field->hidinput->input;
-
-               switch (usage->hid) {
-               case HID_DG_INRANGE:
-                       td->valid = value;
-                       break;
-               case HID_DG_CONTACTID:
-                       td->id = value;
-                       break;
-               case HID_GD_X:
-                       td->x = value;
-                       break;
-               case HID_GD_Y:
-                       td->y = value;
-                       cando_filter_event(td, input);
-                       break;
-               case HID_DG_TIPSWITCH:
-                       /* avoid interference from generic hidinput handling */
-                       break;
-
-               default:
-                       /* fallback to the generic hidinput handling */
-                       return 0;
-               }
-       }
-
-       /* we have handled the hidinput part, now remains hiddev */
-       if (hid->claimed & HID_CLAIMED_HIDDEV && hid->hiddev_hid_event)
-               hid->hiddev_hid_event(hid, field, usage, value);
-
-       return 1;
-}
-
-static int cando_probe(struct hid_device *hdev, const struct hid_device_id *id)
-{
-       int ret;
-       struct cando_data *td;
-
-       td = kmalloc(sizeof(struct cando_data), GFP_KERNEL);
-       if (!td) {
-               hid_err(hdev, "cannot allocate Cando Touch data\n");
-               return -ENOMEM;
-       }
-       hid_set_drvdata(hdev, td);
-       td->first = false;
-       td->oldest = -1;
-       td->valid = false;
-
-       ret = hid_parse(hdev);
-       if (!ret)
-               ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
-
-       if (ret)
-               kfree(td);
-
-       return ret;
-}
-
-static void cando_remove(struct hid_device *hdev)
-{
-       hid_hw_stop(hdev);
-       kfree(hid_get_drvdata(hdev));
-       hid_set_drvdata(hdev, NULL);
-}
-
-static const struct hid_device_id cando_devices[] = {
-       { 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) },
-       { }
-};
-MODULE_DEVICE_TABLE(hid, cando_devices);
-
-static const struct hid_usage_id cando_grabbed_usages[] = {
-       { HID_ANY_ID, HID_ANY_ID, HID_ANY_ID },
-       { HID_ANY_ID - 1, HID_ANY_ID - 1, HID_ANY_ID - 1}
-};
-
-static struct hid_driver cando_driver = {
-       .name = "cando-touch",
-       .id_table = cando_devices,
-       .probe = cando_probe,
-       .remove = cando_remove,
-       .input_mapping = cando_input_mapping,
-       .input_mapped = cando_input_mapped,
-       .usage_table = cando_grabbed_usages,
-       .event = cando_event,
-};
-
-static int __init cando_init(void)
-{
-       return hid_register_driver(&cando_driver);
-}
-
-static void __exit cando_exit(void)
-{
-       hid_unregister_driver(&cando_driver);
-}
-
-module_init(cando_init);
-module_exit(cando_exit);
-
index 408c4be..4140fd2 100644 (file)
@@ -1045,6 +1045,9 @@ void hid_report_raw_event(struct hid_device *hid, int type, u8 *data, int size,
 
        rsize = ((report->size - 1) >> 3) + 1;
 
+       if (rsize > HID_MAX_BUFFER_SIZE)
+               rsize = HID_MAX_BUFFER_SIZE;
+
        if (csize < rsize) {
                dbg_hid("report %d is too short, (%d < %d)\n", report->id,
                                csize, rsize);
@@ -1290,6 +1293,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
        { 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) },
@@ -1356,6 +1360,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
        { 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_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) },
@@ -1369,17 +1374,20 @@ static const struct hid_device_id hid_have_special_driver[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_DWAV, USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH3) },
        { HID_USB_DEVICE(USB_VENDOR_ID_DWAV, USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH4) },
        { 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_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_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) },
@@ -1408,10 +1416,12 @@ static const struct hid_device_id hid_have_special_driver[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOMO_WHEEL2) },
        { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_DFP_WHEEL) },
        { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G25_WHEEL) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G27_WHEEL) },
        { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WII_WHEEL) },
        { 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_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_SIDEWINDER_GV) },
@@ -1441,6 +1451,7 @@ 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_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_QUANTA, USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH) },
        { HID_USB_DEVICE(USB_VENDOR_ID_QUANTA, USB_DEVICE_ID_PIXART_IMAGING_INC_OPTICAL_TOUCH_SCREEN) },
@@ -1454,6 +1465,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_WIRELESS_KBD_MOUSE) },
        { HID_USB_DEVICE(USB_VENDOR_ID_SKYCABLE, USB_DEVICE_ID_SKYCABLE_WIRELESS_PRESENTER) },
        { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER) },
+       { 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) },
@@ -1470,12 +1482,15 @@ static const struct hid_device_id hid_have_special_driver[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb65a) },
        { 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_UNITEC, USB_DEVICE_ID_UNITEC_USB_TOUCH_0709) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_UNITEC, USB_DEVICE_ID_UNITEC_USB_TOUCH_0A19) },
        { HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_SMARTJOY_PLUS) },
        { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_GRAPHIRE_BLUETOOTH) },
        { HID_USB_DEVICE(USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_SLIM_TABLET_5_8_INCH) },
index 00a94b5..e715c43 100644 (file)
@@ -37,6 +37,9 @@
 
 #define USB_VENDOR_ID_ACRUX            0x1a34
 
+#define USB_VENDOR_ID_ACTIONSTAR       0x2101
+#define USB_DEVICE_ID_ACTIONSTAR_1011  0x1011
+
 #define USB_VENDOR_ID_ADS_TECH                 0x06e1
 #define USB_DEVICE_ID_ADS_TECH_RADIO_SI470X    0xa155
 
 #define USB_VENDOR_ID_CREATIVELABS     0x041e
 #define USB_DEVICE_ID_PRODIKEYS_PCMIDI 0x2801
 
+#define USB_VENDOR_ID_CVTOUCH          0x1ff7
+#define USB_DEVICE_ID_CVTOUCH_SCREEN   0x0013
+
 #define USB_VENDOR_ID_CYGNAL           0x10c4
 #define USB_DEVICE_ID_CYGNAL_RADIO_SI470X      0x818a
 
 #define USB_VENDOR_ID_DREAM_CHEEKY     0x1d34
 
 #define USB_VENDOR_ID_ELO              0x04E7
+#define USB_DEVICE_ID_ELO_TS2515       0x0022
 #define USB_DEVICE_ID_ELO_TS2700       0x0020
 
 #define USB_VENDOR_ID_EMS              0x2006
 #define USB_DEVICE_ID_0_8_8_IF_KIT     0x0053
 #define USB_DEVICE_ID_PHIDGET_MOTORCONTROL     0x0058
 
+#define USB_VENDOR_ID_GOODTOUCH                0x1aad
+#define USB_DEVICE_ID_GOODTOUCH_000f   0x000f
+
 #define USB_VENDOR_ID_GOTOP            0x08f2
 #define USB_DEVICE_ID_SUPER_Q2         0x007f
 #define USB_DEVICE_ID_GOGOPEN          0x00ce
 #define USB_DEVICE_ID_UGCI_FLYING      0x0020
 #define USB_DEVICE_ID_UGCI_FIGHTING    0x0030
 
+#define USB_VENDOR_ID_ILITEK           0x222a
+#define USB_DEVICE_ID_ILITEK_MULTITOUCH        0x0001
+
 #define USB_VENDOR_ID_IMATION          0x0718
 #define USB_DEVICE_ID_DISC_STAKKA      0xd000
 
 #define USB_DEVICE_ID_LOGITECH_MOMO_WHEEL      0xc295
 #define USB_DEVICE_ID_LOGITECH_DFP_WHEEL       0xc298
 #define USB_DEVICE_ID_LOGITECH_G25_WHEEL       0xc299
+#define USB_DEVICE_ID_LOGITECH_G27_WHEEL       0xc29b
 #define USB_DEVICE_ID_LOGITECH_WII_WHEEL       0xc29c
 #define USB_DEVICE_ID_LOGITECH_ELITE_KBD       0xc30a
 #define USB_DEVICE_ID_S510_RECEIVER    0xc50c
 #define USB_DEVICE_ID_DINOVO_MINI      0xc71f
 #define USB_DEVICE_ID_LOGITECH_MOMO_WHEEL2     0xca03
 
+#define USB_VENDOR_ID_LUMIO            0x202e
+#define USB_DEVICE_ID_CRYSTALTOUCH     0x0006
+
 #define USB_VENDOR_ID_MCC              0x09db
 #define USB_DEVICE_ID_MCC_PMD1024LS    0x0076
 #define USB_DEVICE_ID_MCC_PMD1208LS    0x007a
 #define USB_VENDOR_ID_PANTHERLORD      0x0810
 #define USB_DEVICE_ID_PANTHERLORD_TWIN_USB_JOYSTICK    0x0001
 
+#define USB_VENDOR_ID_PENMOUNT         0x14e1
+#define USB_DEVICE_ID_PENMOUNT_PCI     0x3500
+
 #define USB_VENDOR_ID_PETALYNX         0x18b1
 #define USB_DEVICE_ID_PETALYNX_MAXTER_REMOTE   0x0037
 
 #define USB_VENDOR_ID_SONY                     0x054c
 #define USB_DEVICE_ID_SONY_VAIO_VGX_MOUSE      0x024b
 #define USB_DEVICE_ID_SONY_PS3_CONTROLLER      0x0268
+#define USB_DEVICE_ID_SONY_NAVIGATION_CONTROLLER       0x042f
 
 #define USB_VENDOR_ID_SOUNDGRAPH       0x15c2
 #define USB_DEVICE_ID_SOUNDGRAPH_IMON_FIRST    0x0034
 #define USB_VENDOR_ID_SUNPLUS          0x04fc
 #define USB_DEVICE_ID_SUNPLUS_WDESKTOP 0x05d8
 
+#define USB_VENDOR_ID_SYMBOL           0x05e0
+#define USB_DEVICE_ID_SYMBOL_SCANNER_1 0x0800
+#define USB_DEVICE_ID_SYMBOL_SCANNER_2 0x1300
+
 #define USB_VENDOR_ID_THRUSTMASTER     0x044f
 
 #define USB_VENDOR_ID_TOPSEED          0x0766
 #define USB_VENDOR_ID_TOPMAX           0x0663
 #define USB_DEVICE_ID_TOPMAX_COBRAPAD  0x0103
 
+#define USB_VENDOR_ID_TOUCH_INTL       0x1e5e
+#define USB_DEVICE_ID_TOUCH_INTL_MULTI_TOUCH   0x0313
+
 #define USB_VENDOR_ID_TOUCHPACK                0x1bfd
 #define USB_DEVICE_ID_TOUCHPACK_RTS    0x1688
 
 #define USB_DEVICE_ID_UCLOGIC_TABLET_WP5540U   0x0004
 #define USB_DEVICE_ID_UCLOGIC_TABLET_WP8060U   0x0005
 
+#define USB_VENDOR_ID_UNITEC   0x227d
+#define USB_DEVICE_ID_UNITEC_USB_TOUCH_0709    0x0709
+#define USB_DEVICE_ID_UNITEC_USB_TOUCH_0A19    0x0a19
+
 #define USB_VENDOR_ID_VERNIER          0x08f7
 #define USB_DEVICE_ID_VERNIER_LABPRO   0x0001
 #define USB_DEVICE_ID_VERNIER_GOTEMP   0x0002
index 3da9040..21f205f 100644 (file)
@@ -377,6 +377,8 @@ static const struct hid_device_id lg_devices[] = {
                .driver_data = LG_FF },
        { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G25_WHEEL),
                .driver_data = LG_FF },
+       { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G27_WHEEL),
+               .driver_data = LG_FF },
        { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_DFP_WHEEL),
                .driver_data = LG_FF },
        { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WII_WHEEL),
index f099079..088f850 100644 (file)
@@ -72,6 +72,9 @@ static const struct dev_type devices[] = {
        { 0x046d, 0xc287, ff_joystick_ac },
        { 0x046d, 0xc293, ff_joystick },
        { 0x046d, 0xc294, ff_wheel },
+       { 0x046d, 0xc298, ff_wheel },
+       { 0x046d, 0xc299, ff_wheel },
+       { 0x046d, 0xc29b, ff_wheel },
        { 0x046d, 0xc295, ff_joystick },
        { 0x046d, 0xc298, ff_wheel },
        { 0x046d, 0xc299, ff_wheel },
index 0ec91c1..a5eda4c 100644 (file)
@@ -501,9 +501,17 @@ static int magicmouse_probe(struct hid_device *hdev,
        }
        report->size = 6;
 
+       /*
+        * The device reponds with 'invalid report id' when feature
+        * report switching it into multitouch mode is sent to it.
+        *
+        * This results in -EIO from the _raw low-level transport callback,
+        * but there seems to be no other way of switching the mode.
+        * Thus the super-ugly hacky success check below.
+        */
        ret = hdev->hid_output_raw_report(hdev, feature, sizeof(feature),
                        HID_FEATURE_REPORT);
-       if (ret != sizeof(feature)) {
+       if (ret != -EIO) {
                hid_err(hdev, "unable to request touch data (%d)\n", ret);
                goto err_stop_hw;
        }
diff --git a/drivers/hid/hid-mosart.c b/drivers/hid/hid-mosart.c
deleted file mode 100644 (file)
index aed7ffe..0000000
+++ /dev/null
@@ -1,296 +0,0 @@
-/*
- *  HID driver for the multitouch panel on the ASUS EeePC T91MT
- *
- *  Copyright (c) 2009-2010 Stephane Chatty <chatty@enac.fr>
- *  Copyright (c) 2010 Teemu Tuominen <teemu.tuominen@cybercom.com>
- *
- */
-
-/*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the Free
- * Software Foundation; either version 2 of the License, or (at your option)
- * any later version.
- */
-
-#include <linux/device.h>
-#include <linux/hid.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/usb.h>
-#include "usbhid/usbhid.h"
-
-MODULE_AUTHOR("Stephane Chatty <chatty@enac.fr>");
-MODULE_DESCRIPTION("MosArt dual-touch panel");
-MODULE_LICENSE("GPL");
-
-#include "hid-ids.h"
-
-struct mosart_data {
-       __u16 x, y;
-       __u8 id;
-       bool valid;             /* valid finger data, or just placeholder? */
-       bool first;             /* is this the first finger in this frame? */
-       bool activity_now;      /* at least one active finger in this frame? */
-       bool activity;          /* at least one active finger previously? */
-};
-
-static int mosart_input_mapping(struct hid_device *hdev, struct hid_input *hi,
-               struct hid_field *field, struct hid_usage *usage,
-               unsigned long **bit, int *max)
-{
-       switch (usage->hid & HID_USAGE_PAGE) {
-
-       case HID_UP_GENDESK:
-               switch (usage->hid) {
-               case HID_GD_X:
-                       hid_map_usage(hi, usage, bit, max,
-                                       EV_ABS, ABS_MT_POSITION_X);
-                       /* touchscreen emulation */
-                       input_set_abs_params(hi->input, ABS_X,
-                                               field->logical_minimum,
-                                               field->logical_maximum, 0, 0);
-                       return 1;
-               case HID_GD_Y:
-                       hid_map_usage(hi, usage, bit, max,
-                                       EV_ABS, ABS_MT_POSITION_Y);
-                       /* touchscreen emulation */
-                       input_set_abs_params(hi->input, ABS_Y,
-                                               field->logical_minimum,
-                                               field->logical_maximum, 0, 0);
-                       return 1;
-               }
-               return 0;
-
-       case HID_UP_DIGITIZER:
-               switch (usage->hid) {
-               case HID_DG_CONFIDENCE:
-               case HID_DG_TIPSWITCH:
-               case HID_DG_INPUTMODE:
-               case HID_DG_DEVICEINDEX:
-               case HID_DG_CONTACTCOUNT:
-               case HID_DG_CONTACTMAX:
-               case HID_DG_TIPPRESSURE:
-               case HID_DG_WIDTH:
-               case HID_DG_HEIGHT:
-                       return -1;
-               case HID_DG_INRANGE:
-                       /* touchscreen emulation */
-                       hid_map_usage(hi, usage, bit, max, EV_KEY, BTN_TOUCH);
-                       return 1;
-
-               case HID_DG_CONTACTID:
-                       hid_map_usage(hi, usage, bit, max,
-                                       EV_ABS, ABS_MT_TRACKING_ID);
-                       return 1;
-
-               }
-               return 0;
-
-       case 0xff000000:
-               /* ignore HID features */
-               return -1;
-
-       case HID_UP_BUTTON:
-               /* ignore buttons */
-               return -1;
-       }
-
-       return 0;
-}
-
-static int mosart_input_mapped(struct hid_device *hdev, struct hid_input *hi,
-               struct hid_field *field, struct hid_usage *usage,
-               unsigned long **bit, int *max)
-{
-       if (usage->type == EV_KEY || usage->type == EV_ABS)
-               clear_bit(usage->code, *bit);
-
-       return 0;
-}
-
-/*
- * this function is called when a whole finger has been parsed,
- * so that it can decide what to send to the input layer.
- */
-static void mosart_filter_event(struct mosart_data *td, struct input_dev *input)
-{
-       td->first = !td->first; /* touchscreen emulation */
-
-       if (!td->valid) {
-               /*
-                * touchscreen emulation: if no finger in this frame is valid
-                * and there previously was finger activity, this is a release
-                */ 
-               if (!td->first && !td->activity_now && td->activity) {
-                       input_event(input, EV_KEY, BTN_TOUCH, 0);
-                       td->activity = false;
-               }
-               return;
-       }
-
-       input_event(input, EV_ABS, ABS_MT_TRACKING_ID, td->id);
-       input_event(input, EV_ABS, ABS_MT_POSITION_X, td->x);
-       input_event(input, EV_ABS, ABS_MT_POSITION_Y, td->y);
-
-       input_mt_sync(input);
-       td->valid = false;
-
-       /* touchscreen emulation: if first active finger in this frame... */
-       if (!td->activity_now) {
-               /* if there was no previous activity, emit touch event */
-               if (!td->activity) {
-                       input_event(input, EV_KEY, BTN_TOUCH, 1);
-                       td->activity = true;
-               }
-               td->activity_now = true;
-               /* and in any case this is our preferred finger */
-               input_event(input, EV_ABS, ABS_X, td->x);
-               input_event(input, EV_ABS, ABS_Y, td->y);
-       }
-}
-
-
-static int mosart_event(struct hid_device *hid, struct hid_field *field,
-                               struct hid_usage *usage, __s32 value)
-{
-       struct mosart_data *td = hid_get_drvdata(hid);
-
-       if (hid->claimed & HID_CLAIMED_INPUT) {
-               struct input_dev *input = field->hidinput->input;
-               switch (usage->hid) {
-               case HID_DG_INRANGE:
-                       td->valid = !!value;
-                       break;
-               case HID_GD_X:
-                       td->x = value;
-                       break;
-               case HID_GD_Y:
-                       td->y = value;
-                       mosart_filter_event(td, input);
-                       break;
-               case HID_DG_CONTACTID:
-                       td->id = value;
-                       break;
-               case HID_DG_CONTACTCOUNT:
-                       /* touch emulation: this is the last field in a frame */
-                       td->first = false;
-                       td->activity_now = false;
-                       break;
-               case HID_DG_CONFIDENCE:
-               case HID_DG_TIPSWITCH:
-                       /* avoid interference from generic hidinput handling */
-                       break;
-
-               default:
-                       /* fallback to the generic hidinput handling */
-                       return 0;
-               }
-       }
-
-       /* we have handled the hidinput part, now remains hiddev */
-       if (hid->claimed & HID_CLAIMED_HIDDEV && hid->hiddev_hid_event)
-               hid->hiddev_hid_event(hid, field, usage, value);
-
-       return 1;
-}
-
-static int mosart_probe(struct hid_device *hdev, const struct hid_device_id *id)
-{
-       int ret;
-       struct mosart_data *td;
-
-
-       td = kmalloc(sizeof(struct mosart_data), GFP_KERNEL);
-       if (!td) {
-               hid_err(hdev, "cannot allocate MosArt data\n");
-               return -ENOMEM;
-       }
-       td->valid = false;
-       td->activity = false;
-       td->activity_now = false;
-       td->first = false;
-       hid_set_drvdata(hdev, td);
-
-       /* currently, it's better to have one evdev device only */
-#if 0
-       hdev->quirks |= HID_QUIRK_MULTI_INPUT;
-#endif
-
-       ret = hid_parse(hdev);
-       if (ret == 0)
-               ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
-
-       if (ret == 0) {
-               struct hid_report_enum *re = hdev->report_enum
-                                               + HID_FEATURE_REPORT;
-               struct hid_report *r = re->report_id_hash[7];
-
-               r->field[0]->value[0] = 0x02;
-               usbhid_submit_report(hdev, r, USB_DIR_OUT);
-       } else 
-               kfree(td);
-
-       return ret;
-}
-
-#ifdef CONFIG_PM
-static int mosart_reset_resume(struct hid_device *hdev)
-{
-       struct hid_report_enum *re = hdev->report_enum
-                                               + HID_FEATURE_REPORT;
-       struct hid_report *r = re->report_id_hash[7];
-
-       r->field[0]->value[0] = 0x02;
-       usbhid_submit_report(hdev, r, USB_DIR_OUT);
-       return 0;
-}
-#endif
-
-static void mosart_remove(struct hid_device *hdev)
-{
-       hid_hw_stop(hdev);
-       kfree(hid_get_drvdata(hdev));
-       hid_set_drvdata(hdev, NULL);
-}
-
-static const struct hid_device_id mosart_devices[] = {
-       { 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_TURBOX, USB_DEVICE_ID_TURBOX_TOUCHSCREEN_MOSART) },
-       { }
-};
-MODULE_DEVICE_TABLE(hid, mosart_devices);
-
-static const struct hid_usage_id mosart_grabbed_usages[] = {
-       { HID_ANY_ID, HID_ANY_ID, HID_ANY_ID },
-       { HID_ANY_ID - 1, HID_ANY_ID - 1, HID_ANY_ID - 1}
-};
-
-static struct hid_driver mosart_driver = {
-       .name = "mosart",
-       .id_table = mosart_devices,
-       .probe = mosart_probe,
-       .remove = mosart_remove,
-       .input_mapping = mosart_input_mapping,
-       .input_mapped = mosart_input_mapped,
-       .usage_table = mosart_grabbed_usages,
-       .event = mosart_event,
-#ifdef CONFIG_PM
-       .reset_resume = mosart_reset_resume,
-#endif
-};
-
-static int __init mosart_init(void)
-{
-       return hid_register_driver(&mosart_driver);
-}
-
-static void __exit mosart_exit(void)
-{
-       hid_unregister_driver(&mosart_driver);
-}
-
-module_init(mosart_init);
-module_exit(mosart_exit);
-
index ee01e65..ecd4d2d 100644 (file)
  *  Copyright (c) 2010 Henrik Rydberg <rydberg@euromail.se>
  *  Copyright (c) 2010 Canonical, Ltd.
  *
+ *  This code is partly based on hid-3m-pct.c:
+ *
+ *  Copyright (c) 2009-2010 Stephane Chatty <chatty@enac.fr>
+ *  Copyright (c) 2010      Henrik Rydberg <rydberg@euromail.se>
+ *  Copyright (c) 2010      Canonical, Ltd.
+ *
  */
 
 /*
@@ -44,6 +50,7 @@ MODULE_LICENSE("GPL");
 #define MT_QUIRK_VALID_IS_INRANGE      (1 << 4)
 #define MT_QUIRK_VALID_IS_CONFIDENCE   (1 << 5)
 #define MT_QUIRK_EGALAX_XYZ_FIXUP      (1 << 6)
+#define MT_QUIRK_SLOT_IS_CONTACTID_MINUS_ONE   (1 << 7)
 
 struct mt_slot {
        __s32 x, y, p, w, h;
@@ -60,24 +67,36 @@ struct mt_device {
        __s8 inputmode;         /* InputMode HID feature, -1 if non-existent */
        __u8 num_received;      /* how many contacts we received */
        __u8 num_expected;      /* expected last contact index */
+       __u8 maxcontacts;
        bool curvalid;          /* is the current contact valid? */
-       struct mt_slot slots[0];        /* first slot */
+       struct mt_slot *slots;
 };
 
 struct mt_class {
        __s32 name;     /* MT_CLS */
        __s32 quirks;
        __s32 sn_move;  /* Signal/noise ratio for move events */
+       __s32 sn_width; /* Signal/noise ratio for width events */
+       __s32 sn_height;        /* Signal/noise ratio for height events */
        __s32 sn_pressure;      /* Signal/noise ratio for pressure events */
        __u8 maxcontacts;
 };
 
 /* classes of device behavior */
-#define MT_CLS_DEFAULT                         1
-#define MT_CLS_DUAL_INRANGE_CONTACTID          2
-#define MT_CLS_DUAL_INRANGE_CONTACTNUMBER      3
-#define MT_CLS_CYPRESS                         4
-#define MT_CLS_EGALAX                          5
+#define MT_CLS_DEFAULT                         0x0001
+
+#define MT_CLS_CONFIDENCE                      0x0002
+#define MT_CLS_CONFIDENCE_MINUS_ONE            0x0003
+#define MT_CLS_DUAL_INRANGE_CONTACTID          0x0004
+#define MT_CLS_DUAL_INRANGE_CONTACTNUMBER      0x0005
+#define MT_CLS_DUAL_NSMU_CONTACTID             0x0006
+
+/* vendor specific classes */
+#define MT_CLS_3M                              0x0101
+#define MT_CLS_CYPRESS                         0x0102
+#define MT_CLS_EGALAX                          0x0103
+
+#define MT_DEFAULT_MAXCONTACT  10
 
 /*
  * these device-dependent functions determine what slot corresponds
@@ -95,12 +114,12 @@ static int cypress_compute_slot(struct mt_device *td)
 static int find_slot_from_contactid(struct mt_device *td)
 {
        int i;
-       for (i = 0; i < td->mtclass->maxcontacts; ++i) {
+       for (i = 0; i < td->maxcontacts; ++i) {
                if (td->slots[i].contactid == td->curdata.contactid &&
                        td->slots[i].touch_state)
                        return i;
        }
-       for (i = 0; i < td->mtclass->maxcontacts; ++i) {
+       for (i = 0; i < td->maxcontacts; ++i) {
                if (!td->slots[i].seen_in_this_frame &&
                        !td->slots[i].touch_state)
                        return i;
@@ -113,8 +132,12 @@ static int find_slot_from_contactid(struct mt_device *td)
 
 struct mt_class mt_classes[] = {
        { .name = MT_CLS_DEFAULT,
-               .quirks = MT_QUIRK_NOT_SEEN_MEANS_UP,
-               .maxcontacts = 10 },
+               .quirks = MT_QUIRK_NOT_SEEN_MEANS_UP },
+       { .name = MT_CLS_CONFIDENCE,
+               .quirks = MT_QUIRK_VALID_IS_CONFIDENCE },
+       { .name = MT_CLS_CONFIDENCE_MINUS_ONE,
+               .quirks = MT_QUIRK_VALID_IS_CONFIDENCE |
+                       MT_QUIRK_SLOT_IS_CONTACTID_MINUS_ONE },
        { .name = MT_CLS_DUAL_INRANGE_CONTACTID,
                .quirks = MT_QUIRK_VALID_IS_INRANGE |
                        MT_QUIRK_SLOT_IS_CONTACTID,
@@ -123,11 +146,24 @@ struct mt_class mt_classes[] = {
                .quirks = MT_QUIRK_VALID_IS_INRANGE |
                        MT_QUIRK_SLOT_IS_CONTACTNUMBER,
                .maxcontacts = 2 },
+       { .name = MT_CLS_DUAL_NSMU_CONTACTID,
+               .quirks = MT_QUIRK_NOT_SEEN_MEANS_UP |
+                       MT_QUIRK_SLOT_IS_CONTACTID,
+               .maxcontacts = 2 },
+
+       /*
+        * vendor specific classes
+        */
+       { .name = MT_CLS_3M,
+               .quirks = MT_QUIRK_VALID_IS_CONFIDENCE |
+                       MT_QUIRK_SLOT_IS_CONTACTID,
+               .sn_move = 2048,
+               .sn_width = 128,
+               .sn_height = 128 },
        { .name = MT_CLS_CYPRESS,
                .quirks = MT_QUIRK_NOT_SEEN_MEANS_UP |
                        MT_QUIRK_CYPRESS,
                .maxcontacts = 10 },
-
        { .name = MT_CLS_EGALAX,
                .quirks =  MT_QUIRK_SLOT_IS_CONTACTID |
                        MT_QUIRK_VALID_IS_INRANGE |
@@ -136,15 +172,26 @@ struct mt_class mt_classes[] = {
                .sn_move = 4096,
                .sn_pressure = 32,
        },
+
        { }
 };
 
 static void mt_feature_mapping(struct hid_device *hdev,
                struct hid_field *field, struct hid_usage *usage)
 {
-       if (usage->hid == HID_DG_INPUTMODE) {
-               struct mt_device *td = hid_get_drvdata(hdev);
+       struct mt_device *td = hid_get_drvdata(hdev);
+
+       switch (usage->hid) {
+       case HID_DG_INPUTMODE:
                td->inputmode = field->report->id;
+               break;
+       case HID_DG_CONTACTMAX:
+               td->maxcontacts = field->value[0];
+               if (td->mtclass->maxcontacts)
+                       /* check if the maxcontacts is given by the class */
+                       td->maxcontacts = td->mtclass->maxcontacts;
+
+               break;
        }
 }
 
@@ -179,6 +226,7 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
                        /* touchscreen emulation */
                        set_abs(hi->input, ABS_X, field, cls->sn_move);
                        td->last_slot_field = usage->hid;
+                       td->last_field_index = field->index;
                        return 1;
                case HID_GD_Y:
                        if (quirks & MT_QUIRK_EGALAX_XYZ_FIXUP)
@@ -190,6 +238,7 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
                        /* touchscreen emulation */
                        set_abs(hi->input, ABS_Y, field, cls->sn_move);
                        td->last_slot_field = usage->hid;
+                       td->last_field_index = field->index;
                        return 1;
                }
                return 0;
@@ -198,32 +247,40 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
                switch (usage->hid) {
                case HID_DG_INRANGE:
                        td->last_slot_field = usage->hid;
+                       td->last_field_index = field->index;
                        return 1;
                case HID_DG_CONFIDENCE:
                        td->last_slot_field = usage->hid;
+                       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);
                        td->last_slot_field = usage->hid;
+                       td->last_field_index = field->index;
                        return 1;
                case HID_DG_CONTACTID:
-                       input_mt_init_slots(hi->input,
-                                       td->mtclass->maxcontacts);
+                       input_mt_init_slots(hi->input, td->maxcontacts);
                        td->last_slot_field = usage->hid;
+                       td->last_field_index = field->index;
                        return 1;
                case HID_DG_WIDTH:
                        hid_map_usage(hi, usage, bit, max,
                                        EV_ABS, ABS_MT_TOUCH_MAJOR);
+                       set_abs(hi->input, ABS_MT_TOUCH_MAJOR, field,
+                               cls->sn_width);
                        td->last_slot_field = usage->hid;
+                       td->last_field_index = field->index;
                        return 1;
                case HID_DG_HEIGHT:
                        hid_map_usage(hi, usage, bit, max,
                                        EV_ABS, ABS_MT_TOUCH_MINOR);
-                       field->logical_maximum = 1;
-                       field->logical_minimum = 0;
-                       set_abs(hi->input, ABS_MT_ORIENTATION, field, 0);
+                       set_abs(hi->input, ABS_MT_TOUCH_MINOR, field,
+                               cls->sn_height);
+                       input_set_abs_params(hi->input,
+                                       ABS_MT_ORIENTATION, 0, 1, 0, 0);
                        td->last_slot_field = usage->hid;
+                       td->last_field_index = field->index;
                        return 1;
                case HID_DG_TIPPRESSURE:
                        if (quirks & MT_QUIRK_EGALAX_XYZ_FIXUP)
@@ -236,13 +293,15 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
                        set_abs(hi->input, ABS_PRESSURE, field,
                                cls->sn_pressure);
                        td->last_slot_field = usage->hid;
+                       td->last_field_index = field->index;
                        return 1;
                case HID_DG_CONTACTCOUNT:
-                       td->last_field_index = field->report->maxfield - 1;
+                       td->last_field_index = field->index;
                        return 1;
                case HID_DG_CONTACTMAX:
                        /* we don't set td->last_slot_field as contactcount and
                         * contact max are global to the report */
+                       td->last_field_index = field->index;
                        return -1;
                }
                /* let hid-input decide for the others */
@@ -279,6 +338,9 @@ static int mt_compute_slot(struct mt_device *td)
        if (quirks & MT_QUIRK_SLOT_IS_CONTACTNUMBER)
                return td->num_received;
 
+       if (quirks & MT_QUIRK_SLOT_IS_CONTACTID_MINUS_ONE)
+               return td->curdata.contactid - 1;
+
        return find_slot_from_contactid(td);
 }
 
@@ -292,7 +354,7 @@ static void mt_complete_slot(struct mt_device *td)
        if (td->curvalid) {
                int slotnum = mt_compute_slot(td);
 
-               if (slotnum >= 0 && slotnum < td->mtclass->maxcontacts)
+               if (slotnum >= 0 && slotnum < td->maxcontacts)
                        td->slots[slotnum] = td->curdata;
        }
        td->num_received++;
@@ -307,7 +369,7 @@ static void mt_emit_event(struct mt_device *td, struct input_dev *input)
 {
        int i;
 
-       for (i = 0; i < td->mtclass->maxcontacts; ++i) {
+       for (i = 0; i < td->maxcontacts; ++i) {
                struct mt_slot *s = &(td->slots[i]);
                if ((td->mtclass->quirks & MT_QUIRK_NOT_SEEN_MEANS_UP) &&
                        !s->seen_in_this_frame) {
@@ -318,11 +380,18 @@ static void mt_emit_event(struct mt_device *td, struct input_dev *input)
                input_mt_report_slot_state(input, MT_TOOL_FINGER,
                        s->touch_state);
                if (s->touch_state) {
+                       /* this finger is on the screen */
+                       int wide = (s->w > s->h);
+                       /* divided by two to match visual scale of touch */
+                       int major = max(s->w, s->h) >> 1;
+                       int minor = min(s->w, s->h) >> 1;
+
                        input_event(input, EV_ABS, ABS_MT_POSITION_X, s->x);
                        input_event(input, EV_ABS, ABS_MT_POSITION_Y, s->y);
+                       input_event(input, EV_ABS, ABS_MT_ORIENTATION, wide);
                        input_event(input, EV_ABS, ABS_MT_PRESSURE, s->p);
-                       input_event(input, EV_ABS, ABS_MT_TOUCH_MAJOR, s->w);
-                       input_event(input, EV_ABS, ABS_MT_TOUCH_MINOR, s->h);
+                       input_event(input, EV_ABS, ABS_MT_TOUCH_MAJOR, major);
+                       input_event(input, EV_ABS, ABS_MT_TOUCH_MINOR, minor);
                }
                s->seen_in_this_frame = false;
 
@@ -341,7 +410,7 @@ static int mt_event(struct hid_device *hid, struct hid_field *field,
        struct mt_device *td = hid_get_drvdata(hid);
        __s32 quirks = td->mtclass->quirks;
 
-       if (hid->claimed & HID_CLAIMED_INPUT) {
+       if (hid->claimed & HID_CLAIMED_INPUT && td->slots) {
                switch (usage->hid) {
                case HID_DG_INRANGE:
                        if (quirks & MT_QUIRK_VALID_IS_INRANGE)
@@ -390,8 +459,6 @@ static int mt_event(struct hid_device *hid, struct hid_field *field,
 
                if (usage->hid == td->last_slot_field) {
                        mt_complete_slot(td);
-                       if (!td->last_field_index)
-                               mt_emit_event(td, field->hidinput->input);
                }
 
                if (field->index == td->last_field_index
@@ -442,9 +509,7 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
         */
        hdev->quirks |= HID_QUIRK_NO_INPUT_SYNC;
 
-       td = kzalloc(sizeof(struct mt_device) +
-                               mtclass->maxcontacts * sizeof(struct mt_slot),
-                               GFP_KERNEL);
+       td = kzalloc(sizeof(struct mt_device), GFP_KERNEL);
        if (!td) {
                dev_err(&hdev->dev, "cannot allocate multitouch data\n");
                return -ENOMEM;
@@ -461,6 +526,18 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
        if (ret)
                goto fail;
 
+       if (!td->maxcontacts)
+               td->maxcontacts = MT_DEFAULT_MAXCONTACT;
+
+       td->slots = kzalloc(td->maxcontacts * sizeof(struct mt_slot),
+                               GFP_KERNEL);
+       if (!td->slots) {
+               dev_err(&hdev->dev, "cannot allocate multitouch slots\n");
+               hid_hw_stop(hdev);
+               ret = -ENOMEM;
+               goto fail;
+       }
+
        mt_set_input_mode(hdev);
 
        return 0;
@@ -482,27 +559,115 @@ static void mt_remove(struct hid_device *hdev)
 {
        struct mt_device *td = hid_get_drvdata(hdev);
        hid_hw_stop(hdev);
+       kfree(td->slots);
        kfree(td);
        hid_set_drvdata(hdev, NULL);
 }
 
 static const struct hid_device_id mt_devices[] = {
 
+       /* 3M panels */
+       { .driver_data = MT_CLS_3M,
+               HID_USB_DEVICE(USB_VENDOR_ID_3M,
+                       USB_DEVICE_ID_3M1968) },
+       { .driver_data = MT_CLS_3M,
+               HID_USB_DEVICE(USB_VENDOR_ID_3M,
+                       USB_DEVICE_ID_3M2256) },
+
+       /* ActionStar panels */
+       { .driver_data = MT_CLS_DEFAULT,
+               HID_USB_DEVICE(USB_VENDOR_ID_ACTIONSTAR,
+                       USB_DEVICE_ID_ACTIONSTAR_1011) },
+
+       /* Cando panels */
+       { .driver_data = MT_CLS_DUAL_INRANGE_CONTACTNUMBER,
+               HID_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,
+                       USB_DEVICE_ID_CANDO_MULTI_TOUCH_10_1) },
+       { .driver_data = MT_CLS_DUAL_INRANGE_CONTACTNUMBER,
+               HID_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,
+                       USB_DEVICE_ID_CANDO_MULTI_TOUCH_15_6) },
+
+       /* CVTouch panels */
+       { .driver_data = MT_CLS_DEFAULT,
+               HID_USB_DEVICE(USB_VENDOR_ID_CVTOUCH,
+                       USB_DEVICE_ID_CVTOUCH_SCREEN) },
+
        /* Cypress panel */
        { .driver_data = MT_CLS_CYPRESS,
                HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS,
                        USB_DEVICE_ID_CYPRESS_TRUETOUCH) },
 
+       /* eGalax devices (resistive) */
+       {  .driver_data = MT_CLS_EGALAX,
+               HID_USB_DEVICE(USB_VENDOR_ID_DWAV,
+                       USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH) },
+       {  .driver_data = MT_CLS_EGALAX,
+               HID_USB_DEVICE(USB_VENDOR_ID_DWAV,
+                       USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH3) },
+
+       /* eGalax devices (capacitive) */
+       {  .driver_data = MT_CLS_EGALAX,
+               HID_USB_DEVICE(USB_VENDOR_ID_DWAV,
+                       USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH1) },
+       {  .driver_data = MT_CLS_EGALAX,
+               HID_USB_DEVICE(USB_VENDOR_ID_DWAV,
+                       USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH2) },
+       {  .driver_data = MT_CLS_EGALAX,
+               HID_USB_DEVICE(USB_VENDOR_ID_DWAV,
+                       USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH4) },
+
+       /* Elo TouchSystems IntelliTouch Plus panel */
+       { .driver_data = MT_CLS_DUAL_NSMU_CONTACTID,
+               HID_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,
                        USB_DEVICE_ID_GENERAL_TOUCH_WIN7_TWOFINGERS) },
 
+       /* GoodTouch panels */
+       { .driver_data = MT_CLS_DEFAULT,
+               HID_USB_DEVICE(USB_VENDOR_ID_GOODTOUCH,
+                       USB_DEVICE_ID_GOODTOUCH_000f) },
+
+       /* Ilitek dual touch panel */
+       {  .driver_data = MT_CLS_DEFAULT,
+               HID_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,
                        USB_DEVICE_ID_IRTOUCH_INFRARED_USB) },
 
+       /* Lumio panels */
+       { .driver_data = MT_CLS_CONFIDENCE_MINUS_ONE,
+               HID_USB_DEVICE(USB_VENDOR_ID_LUMIO,
+                       USB_DEVICE_ID_CRYSTALTOUCH) },
+
+       /* MosArt panels */
+       { .driver_data = MT_CLS_CONFIDENCE_MINUS_ONE,
+               HID_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,
+                       USB_DEVICE_ID_ASUSTEK_MULTITOUCH_YFO) },
+       { .driver_data = MT_CLS_CONFIDENCE_MINUS_ONE,
+               HID_USB_DEVICE(USB_VENDOR_ID_TURBOX,
+                       USB_DEVICE_ID_TURBOX_TOUCHSCREEN_MOSART) },
+
+       /* PenMount panels */
+       { .driver_data = MT_CLS_CONFIDENCE,
+               HID_USB_DEVICE(USB_VENDOR_ID_PENMOUNT,
+                       USB_DEVICE_ID_PENMOUNT_PCI) },
+
        /* PixCir-based panels */
        { .driver_data = MT_CLS_DUAL_INRANGE_CONTACTID,
                HID_USB_DEVICE(USB_VENDOR_ID_HANVON,
@@ -511,24 +676,29 @@ static const struct hid_device_id mt_devices[] = {
                HID_USB_DEVICE(USB_VENDOR_ID_CANDO,
                        USB_DEVICE_ID_CANDO_PIXCIR_MULTI_TOUCH) },
 
-       /* Resistive eGalax devices */
-       {  .driver_data = MT_CLS_EGALAX,
-               HID_USB_DEVICE(USB_VENDOR_ID_DWAV,
-                       USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH) },
-       {  .driver_data = MT_CLS_EGALAX,
-               HID_USB_DEVICE(USB_VENDOR_ID_DWAV,
-                       USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH3) },
-
-       /* Capacitive eGalax devices */
-       {  .driver_data = MT_CLS_EGALAX,
-               HID_USB_DEVICE(USB_VENDOR_ID_DWAV,
-                       USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH1) },
-       {  .driver_data = MT_CLS_EGALAX,
-               HID_USB_DEVICE(USB_VENDOR_ID_DWAV,
-                       USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH2) },
-       {  .driver_data = MT_CLS_EGALAX,
-               HID_USB_DEVICE(USB_VENDOR_ID_DWAV,
-                       USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH4) },
+       /* Stantum panels */
+       { .driver_data = MT_CLS_CONFIDENCE,
+               HID_USB_DEVICE(USB_VENDOR_ID_STANTUM,
+                       USB_DEVICE_ID_MTP)},
+       { .driver_data = MT_CLS_CONFIDENCE,
+               HID_USB_DEVICE(USB_VENDOR_ID_STANTUM,
+                       USB_DEVICE_ID_MTP_STM)},
+       { .driver_data = MT_CLS_CONFIDENCE,
+               HID_USB_DEVICE(USB_VENDOR_ID_STANTUM,
+                       USB_DEVICE_ID_MTP_SITRONIX)},
+
+       /* Touch International panels */
+       { .driver_data = MT_CLS_DEFAULT,
+               HID_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,
+                       USB_DEVICE_ID_UNITEC_USB_TOUCH_0709) },
+       { .driver_data = MT_CLS_DEFAULT,
+               HID_USB_DEVICE(USB_VENDOR_ID_UNITEC,
+                       USB_DEVICE_ID_UNITEC_USB_TOUCH_0A19) },
 
        { }
 };
index 93819a0..936c911 100644 (file)
@@ -178,6 +178,8 @@ static void sony_remove(struct hid_device *hdev)
 static const struct hid_device_id sony_devices[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER),
                .driver_data = SIXAXIS_CONTROLLER_USB },
+       { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_NAVIGATION_CONTROLLER),
+               .driver_data = SIXAXIS_CONTROLLER_USB },
        { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER),
                .driver_data = SIXAXIS_CONTROLLER_BT },
        { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_VAIO_VGX_MOUSE),
diff --git a/drivers/hid/hid-stantum.c b/drivers/hid/hid-stantum.c
deleted file mode 100644 (file)
index b2be1d1..0000000
+++ /dev/null
@@ -1,286 +0,0 @@
-/*
- *  HID driver for Stantum multitouch panels
- *
- *  Copyright (c) 2009 Stephane Chatty <chatty@enac.fr>
- *
- */
-
-/*
- * 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/device.h>
-#include <linux/hid.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-
-MODULE_AUTHOR("Stephane Chatty <chatty@enac.fr>");
-MODULE_DESCRIPTION("Stantum HID multitouch panels");
-MODULE_LICENSE("GPL");
-
-#include "hid-ids.h"
-
-struct stantum_data {
-       __s32 x, y, z, w, h;    /* x, y, pressure, width, height */
-       __u16 id;               /* touch id */
-       bool valid;             /* valid finger data, or just placeholder? */
-       bool first;             /* first finger in the HID packet? */
-       bool activity;          /* at least one active finger so far? */
-};
-
-static int stantum_input_mapping(struct hid_device *hdev, struct hid_input *hi,
-               struct hid_field *field, struct hid_usage *usage,
-               unsigned long **bit, int *max)
-{
-       switch (usage->hid & HID_USAGE_PAGE) {
-
-       case HID_UP_GENDESK:
-               switch (usage->hid) {
-               case HID_GD_X:
-                       hid_map_usage(hi, usage, bit, max,
-                                       EV_ABS, ABS_MT_POSITION_X);
-                       /* touchscreen emulation */
-                       input_set_abs_params(hi->input, ABS_X,
-                                               field->logical_minimum,
-                                               field->logical_maximum, 0, 0);
-                       return 1;
-               case HID_GD_Y:
-                       hid_map_usage(hi, usage, bit, max,
-                                       EV_ABS, ABS_MT_POSITION_Y);
-                       /* touchscreen emulation */
-                       input_set_abs_params(hi->input, ABS_Y,
-                                               field->logical_minimum,
-                                               field->logical_maximum, 0, 0);
-                       return 1;
-               }
-               return 0;
-
-       case HID_UP_DIGITIZER:
-               switch (usage->hid) {
-               case HID_DG_INRANGE:
-               case HID_DG_CONFIDENCE:
-               case HID_DG_INPUTMODE:
-               case HID_DG_DEVICEINDEX:
-               case HID_DG_CONTACTCOUNT:
-               case HID_DG_CONTACTMAX:
-                       return -1;
-
-               case HID_DG_TIPSWITCH:
-                       /* touchscreen emulation */
-                       hid_map_usage(hi, usage, bit, max, EV_KEY, BTN_TOUCH);
-                       return 1;
-
-               case HID_DG_WIDTH:
-                       hid_map_usage(hi, usage, bit, max,
-                                       EV_ABS, ABS_MT_TOUCH_MAJOR);
-                       return 1;
-               case HID_DG_HEIGHT:
-                       hid_map_usage(hi, usage, bit, max,
-                                       EV_ABS, ABS_MT_TOUCH_MINOR);
-                       input_set_abs_params(hi->input, ABS_MT_ORIENTATION,
-                                       1, 1, 0, 0);
-                       return 1;
-               case HID_DG_TIPPRESSURE:
-                       hid_map_usage(hi, usage, bit, max,
-                                       EV_ABS, ABS_MT_PRESSURE);
-                       return 1;
-
-               case HID_DG_CONTACTID:
-                       hid_map_usage(hi, usage, bit, max,
-                                       EV_ABS, ABS_MT_TRACKING_ID);
-                       return 1;
-
-               }
-               return 0;
-
-       case 0xff000000:
-               /* no input-oriented meaning */
-               return -1;
-       }
-
-       return 0;
-}
-
-static int stantum_input_mapped(struct hid_device *hdev, struct hid_input *hi,
-               struct hid_field *field, struct hid_usage *usage,
-               unsigned long **bit, int *max)
-{
-       if (usage->type == EV_KEY || usage->type == EV_ABS)
-               clear_bit(usage->code, *bit);
-
-       return 0;
-}
-
-/*
- * this function is called when a whole finger has been parsed,
- * so that it can decide what to send to the input layer.
- */
-static void stantum_filter_event(struct stantum_data *sd,
-                                       struct input_dev *input)
-{
-       bool wide;
-
-       if (!sd->valid) {
-               /*
-                * touchscreen emulation: if the first finger is not valid and
-                * there previously was finger activity, this is a release
-                */
-               if (sd->first && sd->activity) {
-                       input_event(input, EV_KEY, BTN_TOUCH, 0);
-                       sd->activity = false;
-               }
-               return;
-       }
-
-       input_event(input, EV_ABS, ABS_MT_TRACKING_ID, sd->id);
-       input_event(input, EV_ABS, ABS_MT_POSITION_X, sd->x);
-       input_event(input, EV_ABS, ABS_MT_POSITION_Y, sd->y);
-
-       wide = (sd->w > sd->h);
-       input_event(input, EV_ABS, ABS_MT_ORIENTATION, wide);
-       input_event(input, EV_ABS, ABS_MT_TOUCH_MAJOR, wide ? sd->w : sd->h);
-       input_event(input, EV_ABS, ABS_MT_TOUCH_MINOR, wide ? sd->h : sd->w);
-
-       input_event(input, EV_ABS, ABS_MT_PRESSURE, sd->z);
-
-       input_mt_sync(input);
-       sd->valid = false;
-
-       /* touchscreen emulation */
-       if (sd->first) {
-               if (!sd->activity) {
-                       input_event(input, EV_KEY, BTN_TOUCH, 1);
-                       sd->activity = true;
-               }
-               input_event(input, EV_ABS, ABS_X, sd->x);
-               input_event(input, EV_ABS, ABS_Y, sd->y);
-       }
-       sd->first = false;
-}
-
-
-static int stantum_event(struct hid_device *hid, struct hid_field *field,
-                               struct hid_usage *usage, __s32 value)
-{
-       struct stantum_data *sd = hid_get_drvdata(hid);
-
-       if (hid->claimed & HID_CLAIMED_INPUT) {
-               struct input_dev *input = field->hidinput->input;
-
-               switch (usage->hid) {
-               case HID_DG_INRANGE:
-                       /* this is the last field in a finger */
-                       stantum_filter_event(sd, input);
-                       break;
-               case HID_DG_WIDTH:
-                       sd->w = value;
-                       break;
-               case HID_DG_HEIGHT:
-                       sd->h = value;
-                       break;
-               case HID_GD_X:
-                       sd->x = value;
-                       break;
-               case HID_GD_Y:
-                       sd->y = value;
-                       break;
-               case HID_DG_TIPPRESSURE:
-                       sd->z = value;
-                       break;
-               case HID_DG_CONTACTID:
-                       sd->id = value;
-                       break;
-               case HID_DG_CONFIDENCE:
-                       sd->valid = !!value;
-                       break;
-               case 0xff000002:
-                       /* this comes only before the first finger */
-                       sd->first = true;
-                       break;
-
-               default:
-                       /* ignore the others */
-                       return 1;
-               }
-       }
-
-       /* we have handled the hidinput part, now remains hiddev */
-       if (hid->claimed & HID_CLAIMED_HIDDEV && hid->hiddev_hid_event)
-               hid->hiddev_hid_event(hid, field, usage, value);
-
-       return 1;
-}
-
-static int stantum_probe(struct hid_device *hdev,
-                               const struct hid_device_id *id)
-{
-       int ret;
-       struct stantum_data *sd;
-
-       sd = kmalloc(sizeof(struct stantum_data), GFP_KERNEL);
-       if (!sd) {
-               hid_err(hdev, "cannot allocate Stantum data\n");
-               return -ENOMEM;
-       }
-       sd->valid = false;
-       sd->first = false;
-       sd->activity = false;
-       hid_set_drvdata(hdev, sd);
-
-       ret = hid_parse(hdev);
-       if (!ret)
-               ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
-
-       if (ret)
-               kfree(sd);
-
-       return ret;
-}
-
-static void stantum_remove(struct hid_device *hdev)
-{
-       hid_hw_stop(hdev);
-       kfree(hid_get_drvdata(hdev));
-       hid_set_drvdata(hdev, NULL);
-}
-
-static const struct hid_device_id stantum_devices[] = {
-       { 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) },
-       { }
-};
-MODULE_DEVICE_TABLE(hid, stantum_devices);
-
-static const struct hid_usage_id stantum_grabbed_usages[] = {
-       { HID_ANY_ID, HID_ANY_ID, HID_ANY_ID },
-       { HID_ANY_ID - 1, HID_ANY_ID - 1, HID_ANY_ID - 1}
-};
-
-static struct hid_driver stantum_driver = {
-       .name = "stantum",
-       .id_table = stantum_devices,
-       .probe = stantum_probe,
-       .remove = stantum_remove,
-       .input_mapping = stantum_input_mapping,
-       .input_mapped = stantum_input_mapped,
-       .usage_table = stantum_grabbed_usages,
-       .event = stantum_event,
-};
-
-static int __init stantum_init(void)
-{
-       return hid_register_driver(&stantum_driver);
-}
-
-static void __exit stantum_exit(void)
-{
-       hid_unregister_driver(&stantum_driver);
-}
-
-module_init(stantum_init);
-module_exit(stantum_exit);
-
index a8426f1..0e30b14 100644 (file)
@@ -68,6 +68,8 @@ static const struct hid_blacklist {
        { USB_VENDOR_ID_PRODIGE, USB_DEVICE_ID_PRODIGE_CORDLESS, HID_QUIRK_NOGET },
        { USB_VENDOR_ID_QUANTA, USB_DEVICE_ID_PIXART_IMAGING_INC_OPTICAL_TOUCH_SCREEN, HID_QUIRK_NOGET },
        { USB_VENDOR_ID_SUN, USB_DEVICE_ID_RARITAN_KVM_DONGLE, HID_QUIRK_NOGET },
+       { USB_VENDOR_ID_SYMBOL, USB_DEVICE_ID_SYMBOL_SCANNER_1, HID_QUIRK_NOGET },
+       { USB_VENDOR_ID_SYMBOL, USB_DEVICE_ID_SYMBOL_SCANNER_2, HID_QUIRK_NOGET },
        { USB_VENDOR_ID_TURBOX, USB_DEVICE_ID_TURBOX_KEYBOARD, HID_QUIRK_NOGET },
        { USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_PF1209, HID_QUIRK_MULTI_INPUT },
        { USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_WP4030U, HID_QUIRK_MULTI_INPUT },
index f4c67a5..ff3c644 100644 (file)
@@ -373,8 +373,10 @@ static ssize_t hiddev_read(struct file * file, char __user * buffer, size_t coun
                                /* let O_NONBLOCK tasks run */
                                mutex_unlock(&list->thread_lock);
                                schedule();
-                               if (mutex_lock_interruptible(&list->thread_lock))
+                               if (mutex_lock_interruptible(&list->thread_lock)) {
+                                       finish_wait(&list->hiddev->wait, &wait);
                                        return -EINTR;
+                               }
                                set_current_state(TASK_INTERRUPTIBLE);
                        }
                        finish_wait(&list->hiddev->wait, &wait);
index 41063e7..96a7572 100644 (file)
@@ -61,4 +61,10 @@ config SAMPLE_KDB
          Build an example of how to dynamically add the hello
          command to the kdb shell.
 
+config SAMPLE_HIDRAW
+       bool "Build simple hidraw example"
+       depends on HIDRAW && HEADERS_CHECK
+       help
+         Build an example of how to use hidraw from userspace.
+
 endif # SAMPLES
index f26c095..6280817 100644 (file)
@@ -1,4 +1,4 @@
 # Makefile for Linux samples code
 
 obj-$(CONFIG_SAMPLES)  += kobject/ kprobes/ tracepoints/ trace_events/ \
-                          hw_breakpoint/ kfifo/ kdb/
+                          hw_breakpoint/ kfifo/ kdb/ hidraw/
diff --git a/samples/hidraw/Makefile b/samples/hidraw/Makefile
new file mode 100644 (file)
index 0000000..382eeae
--- /dev/null
@@ -0,0 +1,10 @@
+# kbuild trick to avoid linker error. Can be omitted if a module is built.
+obj- := dummy.o
+
+# List of programs to build
+hostprogs-y := hid-example
+
+# Tell kbuild to always build the programs
+always := $(hostprogs-y)
+
+HOSTCFLAGS_hid-example.o += -I$(objtree)/usr/include
diff --git a/samples/hidraw/hid-example.c b/samples/hidraw/hid-example.c
new file mode 100644 (file)
index 0000000..816e2dc
--- /dev/null
@@ -0,0 +1,178 @@
+/*
+ * Hidraw Userspace Example
+ *
+ * Copyright (c) 2010 Alan Ott <alan@signal11.us>
+ * Copyright (c) 2010 Signal 11 Software
+ *
+ * The code may be used by anyone for any purpose,
+ * and can serve as a starting point for developing
+ * applications using hidraw.
+ */
+
+/* Linux */
+#include <linux/types.h>
+#include <linux/input.h>
+#include <linux/hidraw.h>
+
+/*
+ * Ugly hack to work around failing compilation on systems that don't
+ * yet populate new version of hidraw.h to userspace.
+ *
+ * If you need this, please have your distro update the kernel headers.
+ */
+#ifndef HIDIOCSFEATURE
+#define HIDIOCSFEATURE(len)    _IOC(_IOC_WRITE|_IOC_READ, 'H', 0x06, len)
+#define HIDIOCGFEATURE(len)    _IOC(_IOC_WRITE|_IOC_READ, 'H', 0x07, len)
+#endif
+
+/* Unix */
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+/* C */
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+
+const char *bus_str(int bus);
+
+int main(int argc, char **argv)
+{
+       int fd;
+       int i, res, desc_size = 0;
+       char buf[256];
+       struct hidraw_report_descriptor rpt_desc;
+       struct hidraw_devinfo info;
+
+       /* Open the Device with non-blocking reads. In real life,
+          don't use a hard coded path; use libudev instead. */
+       fd = open("/dev/hidraw0", O_RDWR|O_NONBLOCK);
+
+       if (fd < 0) {
+               perror("Unable to open device");
+               return 1;
+       }
+
+       memset(&rpt_desc, 0x0, sizeof(rpt_desc));
+       memset(&info, 0x0, sizeof(info));
+       memset(buf, 0x0, sizeof(buf));
+
+       /* Get Report Descriptor Size */
+       res = ioctl(fd, HIDIOCGRDESCSIZE, &desc_size);
+       if (res < 0)
+               perror("HIDIOCGRDESCSIZE");
+       else
+               printf("Report Descriptor Size: %d\n", desc_size);
+
+       /* Get Report Descriptor */
+       rpt_desc.size = desc_size;
+       res = ioctl(fd, HIDIOCGRDESC, &rpt_desc);
+       if (res < 0) {
+               perror("HIDIOCGRDESC");
+       } else {
+               printf("Report Descriptor:\n");
+               for (i = 0; i < rpt_desc.size; i++)
+                       printf("%hhx ", rpt_desc.value[i]);
+               puts("\n");
+       }
+
+       /* Get Raw Name */
+       res = ioctl(fd, HIDIOCGRAWNAME(256), buf);
+       if (res < 0)
+               perror("HIDIOCGRAWNAME");
+       else
+               printf("Raw Name: %s\n", buf);
+
+       /* Get Physical Location */
+       res = ioctl(fd, HIDIOCGRAWPHYS(256), buf);
+       if (res < 0)
+               perror("HIDIOCGRAWPHYS");
+       else
+               printf("Raw Phys: %s\n", buf);
+
+       /* Get Raw Info */
+       res = ioctl(fd, HIDIOCGRAWINFO, &info);
+       if (res < 0) {
+               perror("HIDIOCGRAWINFO");
+       } else {
+               printf("Raw Info:\n");
+               printf("\tbustype: %d (%s)\n",
+                       info.bustype, bus_str(info.bustype));
+               printf("\tvendor: 0x%04hx\n", info.vendor);
+               printf("\tproduct: 0x%04hx\n", info.product);
+       }
+
+       /* Set Feature */
+       buf[0] = 0x9; /* Report Number */
+       buf[1] = 0xff;
+       buf[2] = 0xff;
+       buf[3] = 0xff;
+       res = ioctl(fd, HIDIOCSFEATURE(4), buf);
+       if (res < 0)
+               perror("HIDIOCSFEATURE");
+       else
+               printf("ioctl HIDIOCGFEATURE returned: %d\n", res);
+
+       /* Get Feature */
+       buf[0] = 0x9; /* Report Number */
+       res = ioctl(fd, HIDIOCGFEATURE(256), buf);
+       if (res < 0) {
+               perror("HIDIOCGFEATURE");
+       } else {
+               printf("ioctl HIDIOCGFEATURE returned: %d\n", res);
+               printf("Report data (not containing the report number):\n\t");
+               for (i = 0; i < res; i++)
+                       printf("%hhx ", buf[i]);
+               puts("\n");
+       }
+
+       /* Send a Report to the Device */
+       buf[0] = 0x1; /* Report Number */
+       buf[1] = 0x77;
+       res = write(fd, buf, 2);
+       if (res < 0) {
+               printf("Error: %d\n", errno);
+               perror("write");
+       } else {
+               printf("write() wrote %d bytes\n", res);
+       }
+
+       /* Get a report from the device */
+       res = read(fd, buf, 16);
+       if (res < 0) {
+               perror("read");
+       } else {
+               printf("read() read %d bytes:\n\t", res);
+               for (i = 0; i < res; i++)
+                       printf("%hhx ", buf[i]);
+               puts("\n");
+       }
+       close(fd);
+       return 0;
+}
+
+const char *
+bus_str(int bus)
+{
+       switch (bus) {
+       case BUS_USB:
+               return "USB";
+               break;
+       case BUS_HIL:
+               return "HIL";
+               break;
+       case BUS_BLUETOOTH:
+               return "Bluetooth";
+               break;
+       case BUS_VIRTUAL:
+               return "Virtual";
+               break;
+       default:
+               return "Other";
+               break;
+       }
+}