Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jikos/hid
authorLinus Torvalds <torvalds@linux-foundation.org>
Sun, 14 Jun 2009 20:45:49 +0000 (13:45 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Sun, 14 Jun 2009 20:45:49 +0000 (13:45 -0700)
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jikos/hid:
  HID: fix inverted wheel for bluetooth version of apple mighty mouse
  HID: no more reinitializtion is needed in post_reset
  HID: hidraw -- fix comment about accepted devices
  HID: Multitouch support for the N-Trig touchscreen
  HID: add new multitouch and digitizer contants
  HID: autocentering support for Logitech Force 3D Pro
  HID: fix hid-ff drivers so that devices work even without ff support
  HID: force feedback support for SmartJoy PLUS PS2/USB adapter
  HID: Wacom Graphire Bluetooth driver
  HID: autocentering support for Logitech G25 Racing Wheel

17 files changed:
drivers/hid/Kconfig
drivers/hid/Makefile
drivers/hid/hid-apple.c
drivers/hid/hid-core.c
drivers/hid/hid-debug.c
drivers/hid/hid-drff.c
drivers/hid/hid-gaff.c
drivers/hid/hid-ids.h
drivers/hid/hid-lgff.c
drivers/hid/hid-ntrig.c
drivers/hid/hid-sjoy.c [new file with mode: 0644]
drivers/hid/hid-tmff.c
drivers/hid/hid-wacom.c [new file with mode: 0644]
drivers/hid/hid-zpff.c
drivers/hid/hidraw.c
drivers/hid/usbhid/hid-core.c
include/linux/hid.h

index 7e67dcb..7831a03 100644 (file)
@@ -116,9 +116,16 @@ config HID_CYPRESS
        ---help---
        Support for cypress mouse and barcode readers.
 
-config DRAGONRISE_FF
-       tristate "DragonRise Inc. force feedback support"
+config HID_DRAGONRISE
+       tristate "DragonRise Inc. support" if EMBEDDED
        depends on USB_HID
+       default !EMBEDDED
+       ---help---
+       Say Y here if you have DragonRise Inc.game controllers.
+
+config DRAGONRISE_FF
+       bool "DragonRise Inc. force feedback support"
+       depends on HID_DRAGONRISE
        select INPUT_FF_MEMLESS
        ---help---
        Say Y here if you want to enable force feedback support for DragonRise Inc.
@@ -160,7 +167,7 @@ config HID_LOGITECH
        Support for Logitech devices that are not fully compliant with HID standard.
 
 config LOGITECH_FF
-       bool "Logitech force feedback"
+       bool "Logitech force feedback support"
        depends on HID_LOGITECH
        select INPUT_FF_MEMLESS
        help
@@ -176,7 +183,7 @@ config LOGITECH_FF
          force feedback.
 
 config LOGIRUMBLEPAD2_FF
-       bool "Logitech Rumblepad 2 force feedback"
+       bool "Logitech Rumblepad 2 force feedback support"
        depends on HID_LOGITECH
        select INPUT_FF_MEMLESS
        help
@@ -211,11 +218,19 @@ config HID_PANTHERLORD
        ---help---
        Support for PantherLord/GreenAsia based device support.
 
+config HID_PANTHERLORD
+       tristate "Pantherlord support" if EMBEDDED
+       depends on USB_HID
+       default !EMBEDDED
+       ---help---
+         Say Y here if you have a PantherLord/GreenAsia based game controller
+         or adapter.
+
 config PANTHERLORD_FF
        bool "Pantherlord force feedback support"
        depends on HID_PANTHERLORD
        select INPUT_FF_MEMLESS
-       help
+       ---help---
          Say Y here if you have a PantherLord/GreenAsia based game controller
          or adapter and want to enable force feedback support for it.
 
@@ -247,15 +262,38 @@ config HID_SUNPLUS
        ---help---
        Support for Sunplus wireless desktop.
 
-config GREENASIA_FF
-       tristate "GreenAsia (Product ID 0x12) force feedback support"
+config HID_GREENASIA
+       tristate "GreenAsia (Product ID 0x12) support" if EMBEDDED
        depends on USB_HID
+       default !EMBEDDED
+       ---help---
+         Say Y here if you have a GreenAsia (Product ID 0x12) based game
+         controller or adapter.
+
+config GREENASIA_FF
+       bool "GreenAsia (Product ID 0x12) force feedback support"
+       depends on HID_GREENASIA
        select INPUT_FF_MEMLESS
        ---help---
        Say Y here if you have a GreenAsia (Product ID 0x12) based game controller
        (like MANTA Warrior MM816 and SpeedLink Strike2 SL-6635) or adapter
        and want to enable force feedback support for it.
 
+config HID_SMARTJOYPLUS
+       tristate "SmartJoy PLUS PS2/USB adapter support" if EMBEDDED
+       depends on USB_HID
+       default !EMBEDDED
+       ---help---
+       Support for SmartJoy PLUS PS2/USB adapter.
+
+config SMARTJOYPLUS_FF
+       bool "SmartJoy PLUS PS2/USB adapter force feedback support"
+       depends on HID_SMARTJOYPLUS
+       select INPUT_FF_MEMLESS
+       ---help---
+       Say Y here if you have a SmartJoy PLUS PS2/USB adapter and want to
+       enable force feedback support for it.
+
 config HID_TOPSEED
        tristate "TopSeed Cyberlink remote control support" if EMBEDDED
        depends on USB_HID
@@ -263,21 +301,45 @@ config HID_TOPSEED
        ---help---
        Say Y if you have a TopSeed Cyberlink remote control.
 
-config THRUSTMASTER_FF
-       tristate "ThrustMaster devices support"
+config HID_THRUSTMASTER
+       tristate "ThrustMaster devices support" if EMBEDDED
        depends on USB_HID
+       default !EMBEDDED
+       ---help---
+         Say Y here if you have a THRUSTMASTER FireStore Dual Power 2 or
+         a THRUSTMASTER Ferrari GT Rumble Wheel.
+
+config THRUSTMASTER_FF
+       bool "ThrustMaster devices force feedback support"
+       depends on HID_THRUSTMASTER
        select INPUT_FF_MEMLESS
-       help
+       ---help---
          Say Y here if you have a THRUSTMASTER FireStore Dual Power 2 or
-         a THRUSTMASTER Ferrari GT Rumble Force or Force Feedback Wheel.
+         a THRUSTMASTER Ferrari GT Rumble Force or Force Feedback Wheel and
+         want to enable force feedback support for it.
 
-config ZEROPLUS_FF
-       tristate "Zeroplus based game controller support"
+config HID_WACOM
+       tristate "Wacom Bluetooth devices support" if EMBEDDED
+       depends on BT_HIDP
+       default !EMBEDDED
+       ---help---
+       Support for Wacom Graphire Bluetooth tablet.
+
+config HID_ZEROPLUS
+       tristate "Zeroplus based game controller support" if EMBEDDED
        depends on USB_HID
-       select INPUT_FF_MEMLESS
-       help
+       default !EMBEDDED
+       ---help---
          Say Y here if you have a Zeroplus based game controller.
 
+config ZEROPLUS_FF
+       bool "Zeroplus based game controller force feedback support"
+       depends on HID_ZEROPLUS
+       select INPUT_FF_MEMLESS
+       ---help---
+         Say Y here if you have a Zeroplus based game controller and want
+         to have force feedback support for it.
+
 endmenu
 
 endif # HID_SUPPORT
index 1f7cb0f..db35151 100644 (file)
@@ -22,7 +22,7 @@ obj-$(CONFIG_HID_BELKIN)      += hid-belkin.o
 obj-$(CONFIG_HID_CHERRY)       += hid-cherry.o
 obj-$(CONFIG_HID_CHICONY)      += hid-chicony.o
 obj-$(CONFIG_HID_CYPRESS)      += hid-cypress.o
-obj-$(CONFIG_DRAGONRISE_FF)    += hid-drff.o
+obj-$(CONFIG_HID_DRAGONRISE)   += hid-drff.o
 obj-$(CONFIG_HID_EZKEY)                += hid-ezkey.o
 obj-$(CONFIG_HID_GYRATION)     += hid-gyration.o
 obj-$(CONFIG_HID_KENSINGTON)   += hid-kensington.o
@@ -34,12 +34,14 @@ obj-$(CONFIG_HID_NTRIG)             += hid-ntrig.o
 obj-$(CONFIG_HID_PANTHERLORD)  += hid-pl.o
 obj-$(CONFIG_HID_PETALYNX)     += hid-petalynx.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_SUNPLUS)      += hid-sunplus.o
-obj-$(CONFIG_GREENASIA_FF)     += hid-gaff.o
-obj-$(CONFIG_THRUSTMASTER_FF)  += hid-tmff.o
+obj-$(CONFIG_HID_GREENASIA)    += hid-gaff.o
+obj-$(CONFIG_HID_THRUSTMASTER) += hid-tmff.o
 obj-$(CONFIG_HID_TOPSEED)      += hid-topseed.o
-obj-$(CONFIG_ZEROPLUS_FF)      += hid-zpff.o
+obj-$(CONFIG_HID_ZEROPLUS)     += hid-zpff.o
+obj-$(CONFIG_HID_WACOM)                += hid-wacom.o
 
 obj-$(CONFIG_USB_HID)          += usbhid/
 obj-$(CONFIG_USB_MOUSE)                += usbhid/
index acbce57..303ccce 100644 (file)
@@ -436,10 +436,6 @@ static const struct hid_device_id apple_devices[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY),
                .driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN },
 
-       /* Apple wireless Mighty Mouse */
-       { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, 0x030c),
-               .driver_data = APPLE_MIGHTYMOUSE | APPLE_INVERT_HWHEEL },
-
        { }
 };
 MODULE_DEVICE_TABLE(hid, apple_devices);
index 8551693..f2c21d5 100644 (file)
@@ -1312,6 +1312,8 @@ static const struct hid_device_id hid_blacklist[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb651) },
        { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb654) },
        { HID_USB_DEVICE(USB_VENDOR_ID_TOPSEED, USB_DEVICE_ID_TOPSEED_CYBERLINK) },
+       { 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_ZEROPLUS, 0x0005) },
        { HID_USB_DEVICE(USB_VENDOR_ID_ZEROPLUS, 0x0030) },
 
index 47ac1a7..04359ed 100644 (file)
@@ -137,6 +137,14 @@ static const struct hid_usage_entry hid_usage_table[] = {
     {0, 0x44, "BarrelSwitch"},
     {0, 0x45, "Eraser"},
     {0, 0x46, "TabletPick"},
+    {0, 0x47, "Confidence"},
+    {0, 0x48, "Width"},
+    {0, 0x49, "Height"},
+    {0, 0x51, "ContactID"},
+    {0, 0x52, "InputMode"},
+    {0, 0x53, "DeviceIndex"},
+    {0, 0x54, "ContactCount"},
+    {0, 0x55, "ContactMaximumNumber"},
   { 15, 0, "PhysicalInterfaceDevice" },
     {0, 0x00, "Undefined"},
     {0, 0x01, "Physical_Interface_Device"},
@@ -514,9 +522,11 @@ static const char *events[EV_MAX + 1] = {
        [EV_FF_STATUS] = "ForceFeedbackStatus",
 };
 
-static const char *syncs[2] = {
+static const char *syncs[3] = {
        [SYN_REPORT] = "Report",                [SYN_CONFIG] = "Config",
+       [SYN_MT_REPORT] = "MT Report",
 };
+
 static const char *keys[KEY_MAX + 1] = {
        [KEY_RESERVED] = "Reserved",            [KEY_ESC] = "Esc",
        [KEY_1] = "1",                          [KEY_2] = "2",
@@ -734,8 +744,17 @@ static const char *absolutes[ABS_MAX + 1] = {
        [ABS_HAT2Y] = "Hat2Y",          [ABS_HAT3X] = "Hat3X",
        [ABS_HAT3Y] = "Hat 3Y",         [ABS_PRESSURE] = "Pressure",
        [ABS_DISTANCE] = "Distance",    [ABS_TILT_X] = "XTilt",
-       [ABS_TILT_Y] = "YTilt",         [ABS_TOOL_WIDTH] = "Tool Width",
+       [ABS_TILT_Y] = "YTilt",         [ABS_TOOL_WIDTH] = "ToolWidth",
        [ABS_VOLUME] = "Volume",        [ABS_MISC] = "Misc",
+       [ABS_MT_TOUCH_MAJOR] = "MTMajor",
+       [ABS_MT_TOUCH_MINOR] = "MTMinor",
+       [ABS_MT_WIDTH_MAJOR] = "MTMajorW",
+       [ABS_MT_WIDTH_MINOR] = "MTMinorW",
+       [ABS_MT_ORIENTATION] = "MTOrientation",
+       [ABS_MT_POSITION_X] = "MTPositionX",
+       [ABS_MT_POSITION_Y] = "MTPositionY",
+       [ABS_MT_TOOL_TYPE] = "MTToolType",
+       [ABS_MT_BLOB_ID] = "MTBlobID",
 };
 
 static const char *misc[MSC_MAX + 1] = {
index 34f3eb6..a239d20 100644 (file)
@@ -32,6 +32,8 @@
 #include <linux/hid.h>
 
 #include "hid-ids.h"
+
+#ifdef CONFIG_DRAGONRISE_FF
 #include "usbhid/usbhid.h"
 
 struct drff_device {
@@ -135,6 +137,12 @@ static int drff_init(struct hid_device *hid)
 
        return 0;
 }
+#else
+static inline int drff_init(struct hid_device *hid)
+{
+       return 0;
+}
+#endif
 
 static int dr_probe(struct hid_device *hdev, const struct hid_device_id *id)
 {
index 510ad3a..8a11ccd 100644 (file)
@@ -31,6 +31,8 @@
 #include <linux/usb.h>
 #include <linux/hid.h>
 #include "hid-ids.h"
+
+#ifdef CONFIG_GREENASIA_FF
 #include "usbhid/usbhid.h"
 
 struct gaff_device {
@@ -130,6 +132,12 @@ static int gaff_init(struct hid_device *hid)
 
        return 0;
 }
+#else
+static inline int gaff_init(struct hid_device *hdev)
+{
+       return 0;
+}
+#endif
 
 static int ga_probe(struct hid_device *hdev, const struct hid_device_id *id)
 {
index 4d5ee2b..6301010 100644 (file)
 #define USB_DEVICE_ID_VERNIER_LCSPEC   0x0006
 
 #define USB_VENDOR_ID_WACOM            0x056a
+#define USB_DEVICE_ID_WACOM_GRAPHIRE_BLUETOOTH 0x81
 
 #define USB_VENDOR_ID_WISEGROUP                0x0925
+#define USB_DEVICE_ID_SMARTJOY_PLUS    0x0005
 #define USB_DEVICE_ID_1_PHIDGETSERVO_20        0x8101
 #define USB_DEVICE_ID_4_PHIDGETSERVO_20        0x8104
 #define USB_DEVICE_ID_8_8_4_IF_KIT     0x8201
index 51aff08..5609970 100644 (file)
@@ -50,6 +50,12 @@ static const signed short ff_joystick[] = {
        -1
 };
 
+static const signed short ff_joystick_ac[] = {
+       FF_CONSTANT,
+       FF_AUTOCENTER,
+       -1
+};
+
 static const signed short ff_wheel[] = {
        FF_CONSTANT,
        FF_AUTOCENTER,
@@ -60,8 +66,8 @@ static const struct dev_type devices[] = {
        { 0x046d, 0xc211, ff_rumble },
        { 0x046d, 0xc219, ff_rumble },
        { 0x046d, 0xc283, ff_joystick },
-       { 0x046d, 0xc286, ff_joystick },
-       { 0x046d, 0xc294, ff_joystick },
+       { 0x046d, 0xc286, ff_joystick_ac },
+       { 0x046d, 0xc294, ff_wheel },
        { 0x046d, 0xc295, ff_joystick },
        { 0x046d, 0xca03, ff_wheel },
 };
index c5b252b..75ed9d2 100644 (file)
@@ -1,13 +1,8 @@
 /*
- *  HID driver for some ntrig "special" devices
+ *  HID driver for N-Trig touchscreens
  *
- *  Copyright (c) 1999 Andreas Gal
- *  Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz>
- *  Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc
- *  Copyright (c) 2006-2007 Jiri Kosina
- *  Copyright (c) 2007 Paul Walmsley
- *  Copyright (c) 2008 Jiri Slaby
  *  Copyright (c) 2008 Rafi Rubin
+ *  Copyright (c) 2009 Stephane Chatty
  *
  */
 
 #define nt_map_key_clear(c)    hid_map_usage_clear(hi, usage, bit, max, \
                                        EV_KEY, (c))
 
+struct ntrig_data {
+       __s32 x, y, id, w, h;
+       char reading_a_point, found_contact_id;
+};
+
+/*
+ * this driver is aimed at two firmware versions in circulation:
+ *  - dual pen/finger single touch
+ *  - finger multitouch, pen not working
+ */
+
 static int ntrig_input_mapping(struct hid_device *hdev, struct hid_input *hi,
                struct hid_field *field, struct hid_usage *usage,
                unsigned long **bit, int *max)
 {
-       if ((usage->hid & HID_USAGE_PAGE) == HID_UP_DIGITIZER &&
-                       (usage->hid & 0xff) == 0x47) {
-               nt_map_key_clear(BTN_TOOL_DOUBLETAP);
-               return 1;
+       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);
+                       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);
+                       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) {
+               /* we do not want to map these for now */
+               case HID_DG_INVERT: /* value is always 0 */
+               case HID_DG_ERASER: /* value is always 0 */
+               case HID_DG_CONTACTID: /* value is useless */
+               case HID_DG_BARRELSWITCH:  /* doubtful */
+               case HID_DG_INPUTMODE:
+               case HID_DG_DEVICEINDEX:
+               case HID_DG_CONTACTCOUNT:
+               case HID_DG_CONTACTMAX:
+                       return -1;
+
+               /* original mapping by Rafi Rubin */
+               case HID_DG_CONFIDENCE:
+                       nt_map_key_clear(BTN_TOOL_DOUBLETAP);
+                       return 1;
+
+               /* width/height mapped on TouchMajor/TouchMinor/Orientation */
+               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,
+                                       0, 1, 0, 0);
+                       return 1;
+               }
+               return 0;
+
+       case 0xff000000:
+               /* we do not want to map these: no input-oriented meaning */
+               return -1;
        }
+
        return 0;
 }
 
@@ -51,6 +110,138 @@ static int ntrig_input_mapped(struct hid_device *hdev, struct hid_input *hi,
 
        return 0;
 }
+
+/*
+ * this function is called upon all reports
+ * so that we can filter contact point information,
+ * decide whether we are in multi or single touch mode
+ * and call input_mt_sync after each point if necessary
+ */
+static int ntrig_event (struct hid_device *hid, struct hid_field *field,
+                                       struct hid_usage *usage, __s32 value)
+{
+       struct input_dev *input = field->hidinput->input;
+       struct ntrig_data *nd = hid_get_drvdata(hid);
+
+        if (hid->claimed & HID_CLAIMED_INPUT) {
+               switch (usage->hid) {
+               case HID_GD_X:
+                       nd->x = value;
+                       nd->reading_a_point = 1;
+                       break;
+               case HID_GD_Y:
+                       nd->y = value;
+                       break;
+               case HID_DG_CONTACTID:
+                       nd->id = value;
+                       /* we receive this only when in multitouch mode */
+                       nd->found_contact_id = 1;
+                       break;
+               case HID_DG_WIDTH:
+                       nd->w = value;
+                       break;
+               case HID_DG_HEIGHT:
+                       nd->h = value;
+                       /*
+                        * when in single touch mode, this is the last
+                        * report received in a finger event. We want
+                        * to emit a normal (X, Y) position
+                        */
+                       if (! nd->found_contact_id) {
+                               input_event(input, EV_ABS, ABS_X, nd->x);
+                               input_event(input, EV_ABS, ABS_Y, nd->y);
+                       }
+                       break;
+               case HID_DG_TIPPRESSURE:
+                       /*
+                        * when in single touch mode, this is the last
+                        * report received in a pen event. We want
+                        * to emit a normal (X, Y) position
+                        */
+                       if (! nd->found_contact_id) {
+                               input_event(input, EV_ABS, ABS_X, nd->x);
+                               input_event(input, EV_ABS, ABS_Y, nd->y);
+                               input_event(input, EV_ABS, ABS_PRESSURE, value);
+                       }
+                       break;
+               case 0xff000002:
+                       /*
+                        * we receive this when the device is in multitouch
+                        * mode. The first of the three values tagged with
+                        * this usage tells if the contact point is real
+                        * or a placeholder
+                        */
+                       if (!nd->reading_a_point || value != 1)
+                               break;
+                       /* emit a normal (X, Y) for the first point only */
+                       if (nd->id == 0) {
+                               input_event(input, EV_ABS, ABS_X, nd->x);
+                               input_event(input, EV_ABS, ABS_Y, nd->y);
+                       }
+                       input_event(input, EV_ABS, ABS_MT_POSITION_X, nd->x);
+                       input_event(input, EV_ABS, ABS_MT_POSITION_Y, nd->y);
+                       if (nd->w > nd->h) {
+                               input_event(input, EV_ABS,
+                                               ABS_MT_ORIENTATION, 1);
+                               input_event(input, EV_ABS,
+                                               ABS_MT_TOUCH_MAJOR, nd->w);
+                               input_event(input, EV_ABS,
+                                               ABS_MT_TOUCH_MINOR, nd->h);
+                       } else {
+                               input_event(input, EV_ABS,
+                                               ABS_MT_ORIENTATION, 0);
+                               input_event(input, EV_ABS,
+                                               ABS_MT_TOUCH_MAJOR, nd->h);
+                               input_event(input, EV_ABS,
+                                               ABS_MT_TOUCH_MINOR, nd->w);
+                       }
+                       input_mt_sync(field->hidinput->input);
+                       nd->reading_a_point = 0;
+                       nd->found_contact_id = 0;
+                       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 ntrig_probe(struct hid_device *hdev, const struct hid_device_id *id)
+{
+       int ret;
+       struct ntrig_data *nd;
+
+       nd = kmalloc(sizeof(struct ntrig_data), GFP_KERNEL);
+       if (!nd) {
+               dev_err(&hdev->dev, "cannot allocate N-Trig data\n");
+               return -ENOMEM;
+       }
+       nd->reading_a_point = 0;
+       nd->found_contact_id = 0;
+       hid_set_drvdata(hdev, nd);
+
+       ret = hid_parse(hdev);
+       if (!ret)
+               ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
+
+       if (ret)
+               kfree (nd);
+       return ret;
+}
+
+static void ntrig_remove(struct hid_device *hdev)
+{
+       hid_hw_stop(hdev);
+       kfree(hid_get_drvdata(hdev));
+}
+
 static const struct hid_device_id ntrig_devices[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN),
                .driver_data = NTRIG_DUPLICATE_USAGES },
@@ -58,11 +249,20 @@ static const struct hid_device_id ntrig_devices[] = {
 };
 MODULE_DEVICE_TABLE(hid, ntrig_devices);
 
+static const struct hid_usage_id ntrig_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 ntrig_driver = {
        .name = "ntrig",
        .id_table = ntrig_devices,
+       .probe = ntrig_probe,
+       .remove = ntrig_remove,
        .input_mapping = ntrig_input_mapping,
        .input_mapped = ntrig_input_mapped,
+       .usage_table = ntrig_grabbed_usages,
+       .event = ntrig_event,
 };
 
 static int ntrig_init(void)
diff --git a/drivers/hid/hid-sjoy.c b/drivers/hid/hid-sjoy.c
new file mode 100644 (file)
index 0000000..eab169e
--- /dev/null
@@ -0,0 +1,180 @@
+/*
+ *  Force feedback support for SmartJoy PLUS PS2->USB adapter
+ *
+ *  Copyright (c) 2009 Jussi Kivilinna <jussi.kivilinna@mbnet.fi>
+ *
+ *  Based of hid-pl.c and hid-gaff.c
+ *   Copyright (c) 2007, 2009 Anssi Hannula <anssi.hannula@gmail.com>
+ *   Copyright (c) 2008 Lukasz Lubojanski <lukasz@lubojanski.info>
+ */
+
+/*
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/* #define DEBUG */
+
+#include <linux/input.h>
+#include <linux/usb.h>
+#include <linux/hid.h>
+#include "hid-ids.h"
+
+#ifdef CONFIG_SMARTJOYPLUS_FF
+#include "usbhid/usbhid.h"
+
+struct sjoyff_device {
+       struct hid_report *report;
+};
+
+static int hid_sjoyff_play(struct input_dev *dev, void *data,
+                        struct ff_effect *effect)
+{
+       struct hid_device *hid = input_get_drvdata(dev);
+       struct sjoyff_device *sjoyff = data;
+       u32 left, right;
+
+       left = effect->u.rumble.strong_magnitude;
+       right = effect->u.rumble.weak_magnitude;
+       dev_dbg(&dev->dev, "called with 0x%08x 0x%08x\n", left, right);
+
+       left = left * 0xff / 0xffff;
+       right = (right != 0); /* on/off only */
+
+       sjoyff->report->field[0]->value[1] = right;
+       sjoyff->report->field[0]->value[2] = left;
+       dev_dbg(&dev->dev, "running with 0x%02x 0x%02x\n", left, right);
+       usbhid_submit_report(hid, sjoyff->report, USB_DIR_OUT);
+
+       return 0;
+}
+
+static int sjoyff_init(struct hid_device *hid)
+{
+       struct sjoyff_device *sjoyff;
+       struct hid_report *report;
+       struct hid_input *hidinput = list_entry(hid->inputs.next,
+                                               struct hid_input, list);
+       struct list_head *report_list =
+                       &hid->report_enum[HID_OUTPUT_REPORT].report_list;
+       struct list_head *report_ptr = report_list;
+       struct input_dev *dev;
+       int error;
+
+       if (list_empty(report_list)) {
+               dev_err(&hid->dev, "no output reports found\n");
+               return -ENODEV;
+       }
+
+       report_ptr = report_ptr->next;
+
+       if (report_ptr == report_list) {
+               dev_err(&hid->dev, "required output report is "
+                               "missing\n");
+               return -ENODEV;
+       }
+
+       report = list_entry(report_ptr, struct hid_report, list);
+       if (report->maxfield < 1) {
+               dev_err(&hid->dev, "no fields in the report\n");
+               return -ENODEV;
+       }
+
+       if (report->field[0]->report_count < 3) {
+               dev_err(&hid->dev, "not enough values in the field\n");
+               return -ENODEV;
+       }
+
+       sjoyff = kzalloc(sizeof(struct sjoyff_device), GFP_KERNEL);
+       if (!sjoyff)
+               return -ENOMEM;
+
+       dev = hidinput->input;
+
+       set_bit(FF_RUMBLE, dev->ffbit);
+
+       error = input_ff_create_memless(dev, sjoyff, hid_sjoyff_play);
+       if (error) {
+               kfree(sjoyff);
+               return error;
+       }
+
+       sjoyff->report = report;
+       sjoyff->report->field[0]->value[0] = 0x01;
+       sjoyff->report->field[0]->value[1] = 0x00;
+       sjoyff->report->field[0]->value[2] = 0x00;
+       usbhid_submit_report(hid, sjoyff->report, USB_DIR_OUT);
+
+       dev_info(&hid->dev,
+               "Force feedback for SmartJoy PLUS PS2/USB adapter\n");
+
+       return 0;
+}
+#else
+static inline int sjoyff_init(struct hid_device *hid)
+{
+       return 0;
+}
+#endif
+
+static int sjoy_probe(struct hid_device *hdev, const struct hid_device_id *id)
+{
+       int ret;
+
+       ret = hid_parse(hdev);
+       if (ret) {
+               dev_err(&hdev->dev, "parse failed\n");
+               goto err;
+       }
+
+       ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT & ~HID_CONNECT_FF);
+       if (ret) {
+               dev_err(&hdev->dev, "hw start failed\n");
+               goto err;
+       }
+
+       sjoyff_init(hdev);
+
+       return 0;
+err:
+       return ret;
+}
+
+static const struct hid_device_id sjoy_devices[] = {
+       { HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_SMARTJOY_PLUS) },
+       { }
+};
+MODULE_DEVICE_TABLE(hid, sjoy_devices);
+
+static struct hid_driver sjoy_driver = {
+       .name = "smartjoyplus",
+       .id_table = sjoy_devices,
+       .probe = sjoy_probe,
+};
+
+static int sjoy_init(void)
+{
+       return hid_register_driver(&sjoy_driver);
+}
+
+static void sjoy_exit(void)
+{
+       hid_unregister_driver(&sjoy_driver);
+}
+
+module_init(sjoy_init);
+module_exit(sjoy_exit);
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Jussi Kivilinna");
+
index 7c1f7b5..fcd6ccd 100644 (file)
 
 #include "hid-ids.h"
 
-#include "usbhid/usbhid.h"
-
-/* Usages for thrustmaster devices I know about */
-#define THRUSTMASTER_USAGE_FF  (HID_UP_GENDESK | 0xbb)
-
 static const signed short ff_rumble[] = {
        FF_RUMBLE,
        -1
@@ -48,6 +43,12 @@ static const signed short ff_joystick[] = {
        -1
 };
 
+#ifdef CONFIG_THRUSTMASTER_FF
+#include "usbhid/usbhid.h"
+
+/* Usages for thrustmaster devices I know about */
+#define THRUSTMASTER_USAGE_FF  (HID_UP_GENDESK | 0xbb)
+
 struct tmff_device {
        struct hid_report *report;
        struct hid_field *ff_field;
@@ -209,6 +210,12 @@ fail:
        kfree(tmff);
        return error;
 }
+#else
+static inline int tmff_init(struct hid_device *hid, const signed short *ff_bits)
+{
+       return 0;
+}
+#endif
 
 static int tm_probe(struct hid_device *hdev, const struct hid_device_id *id)
 {
diff --git a/drivers/hid/hid-wacom.c b/drivers/hid/hid-wacom.c
new file mode 100644 (file)
index 0000000..1f9237f
--- /dev/null
@@ -0,0 +1,259 @@
+/*
+ *  Bluetooth Wacom Tablet support
+ *
+ *  Copyright (c) 1999 Andreas Gal
+ *  Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz>
+ *  Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc
+ *  Copyright (c) 2006-2007 Jiri Kosina
+ *  Copyright (c) 2007 Paul Walmsley
+ *  Copyright (c) 2008 Jiri Slaby <jirislaby@gmail.com>
+ *  Copyright (c) 2006 Andrew Zabolotny <zap@homelink.ru>
+ *  Copyright (c) 2009 Bastien Nocera <hadess@hadess.net>
+ */
+
+/*
+ * 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 "hid-ids.h"
+
+struct wacom_data {
+       __u16 tool;
+       unsigned char butstate;
+};
+
+static int wacom_raw_event(struct hid_device *hdev, struct hid_report *report,
+               u8 *raw_data, int size)
+{
+       struct wacom_data *wdata = hid_get_drvdata(hdev);
+       struct hid_input *hidinput;
+       struct input_dev *input;
+       unsigned char *data = (unsigned char *) raw_data;
+       int tool, x, y, rw;
+
+       if (!(hdev->claimed & HID_CLAIMED_INPUT))
+               return 0;
+
+       tool = 0;
+       hidinput = list_entry(hdev->inputs.next, struct hid_input, list);
+       input = hidinput->input;
+
+       /* Check if this is a tablet report */
+       if (data[0] != 0x03)
+               return 0;
+
+       /* Get X & Y positions */
+       x = le16_to_cpu(*(__le16 *) &data[2]);
+       y = le16_to_cpu(*(__le16 *) &data[4]);
+
+       /* Get current tool identifier */
+       if (data[1] & 0x90) { /* If pen is in the in/active area */
+               switch ((data[1] >> 5) & 3) {
+               case 0: /* Pen */
+                       tool = BTN_TOOL_PEN;
+                       break;
+
+               case 1: /* Rubber */
+                       tool = BTN_TOOL_RUBBER;
+                       break;
+
+               case 2: /* Mouse with wheel */
+               case 3: /* Mouse without wheel */
+                       tool = BTN_TOOL_MOUSE;
+                       break;
+               }
+
+               /* Reset tool if out of active tablet area */
+               if (!(data[1] & 0x10))
+                       tool = 0;
+       }
+
+       /* If tool changed, notify input subsystem */
+       if (wdata->tool != tool) {
+               if (wdata->tool) {
+                       /* Completely reset old tool state */
+                       if (wdata->tool == BTN_TOOL_MOUSE) {
+                               input_report_key(input, BTN_LEFT, 0);
+                               input_report_key(input, BTN_RIGHT, 0);
+                               input_report_key(input, BTN_MIDDLE, 0);
+                               input_report_abs(input, ABS_DISTANCE,
+                                               input->absmax[ABS_DISTANCE]);
+                       } else {
+                               input_report_key(input, BTN_TOUCH, 0);
+                               input_report_key(input, BTN_STYLUS, 0);
+                               input_report_key(input, BTN_STYLUS2, 0);
+                               input_report_abs(input, ABS_PRESSURE, 0);
+                       }
+                       input_report_key(input, wdata->tool, 0);
+                       input_sync(input);
+               }
+               wdata->tool = tool;
+               if (tool)
+                       input_report_key(input, tool, 1);
+       }
+
+       if (tool) {
+               input_report_abs(input, ABS_X, x);
+               input_report_abs(input, ABS_Y, y);
+
+               switch ((data[1] >> 5) & 3) {
+               case 2: /* Mouse with wheel */
+                       input_report_key(input, BTN_MIDDLE, data[1] & 0x04);
+                       rw = (data[6] & 0x01) ? -1 :
+                               (data[6] & 0x02) ? 1 : 0;
+                       input_report_rel(input, REL_WHEEL, rw);
+                       /* fall through */
+
+               case 3: /* Mouse without wheel */
+                       input_report_key(input, BTN_LEFT, data[1] & 0x01);
+                       input_report_key(input, BTN_RIGHT, data[1] & 0x02);
+                       /* Compute distance between mouse and tablet */
+                       rw = 44 - (data[6] >> 2);
+                       if (rw < 0)
+                               rw = 0;
+                       else if (rw > 31)
+                               rw = 31;
+                       input_report_abs(input, ABS_DISTANCE, rw);
+                       break;
+
+               default:
+                       input_report_abs(input, ABS_PRESSURE,
+                                       data[6] | (((__u16) (data[1] & 0x08)) << 5));
+                       input_report_key(input, BTN_TOUCH, data[1] & 0x01);
+                       input_report_key(input, BTN_STYLUS, data[1] & 0x02);
+                       input_report_key(input, BTN_STYLUS2, (tool == BTN_TOOL_PEN) && data[1] & 0x04);
+                       break;
+               }
+
+               input_sync(input);
+       }
+
+       /* Report the state of the two buttons at the top of the tablet
+        * as two extra fingerpad keys (buttons 4 & 5). */
+       rw = data[7] & 0x03;
+       if (rw != wdata->butstate) {
+               wdata->butstate = rw;
+               input_report_key(input, BTN_0, rw & 0x02);
+               input_report_key(input, BTN_1, rw & 0x01);
+               input_event(input, EV_MSC, MSC_SERIAL, 0xf0);
+               input_sync(input);
+       }
+
+       return 1;
+}
+
+static int wacom_probe(struct hid_device *hdev,
+               const struct hid_device_id *id)
+{
+       struct hid_input *hidinput;
+       struct input_dev *input;
+       struct wacom_data *wdata;
+       int ret;
+
+       wdata = kzalloc(sizeof(*wdata), GFP_KERNEL);
+       if (wdata == NULL) {
+               dev_err(&hdev->dev, "can't alloc wacom descriptor\n");
+               return -ENOMEM;
+       }
+
+       hid_set_drvdata(hdev, wdata);
+
+       ret = hid_parse(hdev);
+       if (ret) {
+               dev_err(&hdev->dev, "parse failed\n");
+               goto err_free;
+       }
+
+       ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
+       if (ret) {
+               dev_err(&hdev->dev, "hw start failed\n");
+               goto err_free;
+       }
+
+       hidinput = list_entry(hdev->inputs.next, struct hid_input, list);
+       input = hidinput->input;
+
+       /* Basics */
+       input->evbit[0] |= BIT(EV_KEY) | BIT(EV_ABS) | BIT(EV_REL);
+       input->absbit[0] |= BIT(ABS_X) | BIT(ABS_Y) |
+               BIT(ABS_PRESSURE) | BIT(ABS_DISTANCE);
+       input->relbit[0] |= BIT(REL_WHEEL);
+       set_bit(BTN_TOOL_PEN, input->keybit);
+       set_bit(BTN_TOUCH, input->keybit);
+       set_bit(BTN_STYLUS, input->keybit);
+       set_bit(BTN_STYLUS2, input->keybit);
+       set_bit(BTN_LEFT, input->keybit);
+       set_bit(BTN_RIGHT, input->keybit);
+       set_bit(BTN_MIDDLE, input->keybit);
+
+       /* Pad */
+       input->evbit[0] |= BIT(EV_MSC);
+       input->mscbit[0] |= BIT(MSC_SERIAL);
+
+       /* Distance, rubber and mouse */
+       input->absbit[0] |= BIT(ABS_DISTANCE);
+       set_bit(BTN_TOOL_RUBBER, input->keybit);
+       set_bit(BTN_TOOL_MOUSE, input->keybit);
+
+       input->absmax[ABS_PRESSURE] = 511;
+       input->absmax[ABS_DISTANCE] = 32;
+
+       input->absmax[ABS_X] = 16704;
+       input->absmax[ABS_Y] = 12064;
+       input->absfuzz[ABS_X] = 4;
+       input->absfuzz[ABS_Y] = 4;
+
+       return 0;
+err_free:
+       kfree(wdata);
+       return ret;
+}
+
+static void wacom_remove(struct hid_device *hdev)
+{
+       hid_hw_stop(hdev);
+       kfree(hid_get_drvdata(hdev));
+}
+
+static const struct hid_device_id wacom_devices[] = {
+       { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_GRAPHIRE_BLUETOOTH) },
+
+       { }
+};
+MODULE_DEVICE_TABLE(hid, wacom_devices);
+
+static struct hid_driver wacom_driver = {
+       .name = "wacom",
+       .id_table = wacom_devices,
+       .probe = wacom_probe,
+       .remove = wacom_remove,
+       .raw_event = wacom_raw_event,
+};
+
+static int wacom_init(void)
+{
+       int ret;
+
+       ret = hid_register_driver(&wacom_driver);
+       if (ret)
+               printk(KERN_ERR "can't register wacom driver\n");
+       printk(KERN_ERR "wacom driver registered\n");
+       return ret;
+}
+
+static void wacom_exit(void)
+{
+       hid_unregister_driver(&wacom_driver);
+}
+
+module_init(wacom_init);
+module_exit(wacom_exit);
+MODULE_LICENSE("GPL");
+
index 85a198a..57f7107 100644 (file)
@@ -27,6 +27,7 @@
 
 #include "hid-ids.h"
 
+#ifdef CONFIG_ZEROPLUS_FF
 #include "usbhid/usbhid.h"
 
 struct zpff_device {
@@ -108,6 +109,12 @@ static int zpff_init(struct hid_device *hid)
 
        return 0;
 }
+#else
+static inline int zpff_init(struct hid_device *hid)
+{
+       return 0;
+}
+#endif
 
 static int zp_probe(struct hid_device *hdev, const struct hid_device_id *id)
 {
index 00ccf4b..0c6639e 100644 (file)
@@ -349,10 +349,7 @@ int hidraw_connect(struct hid_device *hid)
        int minor, result;
        struct hidraw *dev;
 
-       /* TODO currently we accept any HID device. This should later
-        * probably be fixed to accept only those devices which provide
-        * non-input applications
-        */
+       /* we accept any HID device, no matter the applications */
 
        dev = kzalloc(sizeof(struct hidraw), GFP_KERNEL);
        if (!dev)
index ac8049b..76c4bbe 100644 (file)
@@ -1234,12 +1234,11 @@ static int hid_post_reset(struct usb_interface *intf)
        struct hid_device *hid = usb_get_intfdata(intf);
        struct usbhid_device *usbhid = hid->driver_data;
        int status;
+
        spin_lock_irq(&usbhid->lock);
        clear_bit(HID_RESET_PENDING, &usbhid->iofl);
        spin_unlock_irq(&usbhid->lock);
        hid_set_idle(dev, intf->cur_altsetting->desc.bInterfaceNumber, 0, 0);
-       /* FIXME: Any more reinitialization needed? */
        status = hid_start_in(hid);
        if (status < 0)
                hid_io_error(hid);
@@ -1251,14 +1250,14 @@ static int hid_post_reset(struct usb_interface *intf)
 int usbhid_get_power(struct hid_device *hid)
 {
        struct usbhid_device *usbhid = hid->driver_data;
+
        return usb_autopm_get_interface(usbhid->intf);
 }
 
 void usbhid_put_power(struct hid_device *hid)
 {
        struct usbhid_device *usbhid = hid->driver_data;
+
        usb_autopm_put_interface(usbhid->intf);
 }
 
index a72876e..53489fd 100644 (file)
@@ -238,6 +238,42 @@ struct hid_item {
 #define HID_GD_RIGHT           0x00010092
 #define HID_GD_LEFT            0x00010093
 
+#define HID_DG_DIGITIZER       0x000d0001
+#define HID_DG_PEN             0x000d0002
+#define HID_DG_LIGHTPEN                0x000d0003
+#define HID_DG_TOUCHSCREEN     0x000d0004
+#define HID_DG_TOUCHPAD                0x000d0005
+#define HID_DG_STYLUS          0x000d0020
+#define HID_DG_PUCK            0x000d0021
+#define HID_DG_FINGER          0x000d0022
+#define HID_DG_TIPPRESSURE     0x000d0030
+#define HID_DG_BARRELPRESSURE  0x000d0031
+#define HID_DG_INRANGE         0x000d0032
+#define HID_DG_TOUCH           0x000d0033
+#define HID_DG_UNTOUCH         0x000d0034
+#define HID_DG_TAP             0x000d0035
+#define HID_DG_TABLETFUNCTIONKEY       0x000d0039
+#define HID_DG_PROGRAMCHANGEKEY        0x000d003a
+#define HID_DG_INVERT          0x000d003c
+#define HID_DG_TIPSWITCH       0x000d0042
+#define HID_DG_TIPSWITCH2      0x000d0043
+#define HID_DG_BARRELSWITCH    0x000d0044
+#define HID_DG_ERASER          0x000d0045
+#define HID_DG_TABLETPICK      0x000d0046
+/*
+ * as of May 20, 2009 the usages below are not yet in the official USB spec
+ * but are being pushed by Microsft as described in their paper "Digitizer
+ * Drivers for Windows Touch and Pen-Based Computers"
+ */
+#define HID_DG_CONFIDENCE      0x000d0047
+#define HID_DG_WIDTH           0x000d0048
+#define HID_DG_HEIGHT          0x000d0049
+#define HID_DG_CONTACTID       0x000d0051
+#define HID_DG_INPUTMODE       0x000d0052
+#define HID_DG_DEVICEINDEX     0x000d0053
+#define HID_DG_CONTACTCOUNT    0x000d0054
+#define HID_DG_CONTACTMAX      0x000d0055
+
 /*
  * HID report types --- Ouch! HID spec says 1 2 3!
  */