aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/ABI/testing/sysfs-driver-hid-roccat-pyra98
-rw-r--r--Documentation/input/ntrig.txt126
-rw-r--r--drivers/hid/Kconfig19
-rw-r--r--drivers/hid/Makefile4
-rw-r--r--drivers/hid/hid-3m-pct.c127
-rw-r--r--drivers/hid/hid-core.c4
-rw-r--r--drivers/hid/hid-egalax.c16
-rw-r--r--drivers/hid/hid-ids.h5
-rw-r--r--drivers/hid/hid-input.c3
-rw-r--r--drivers/hid/hid-lg.c41
-rw-r--r--drivers/hid/hid-lg.h6
-rw-r--r--drivers/hid/hid-lg2ff.c4
-rw-r--r--drivers/hid/hid-lg4ff.c136
-rw-r--r--drivers/hid/hid-magicmouse.c325
-rw-r--r--drivers/hid/hid-ntrig.c69
-rw-r--r--drivers/hid/hid-roccat-pyra.c968
-rw-r--r--drivers/hid/hid-roccat-pyra.h186
-rw-r--r--drivers/hid/usbhid/hid-core.c2
-rw-r--r--drivers/hid/usbhid/hid-quirks.c1
-rw-r--r--include/linux/hid.h1
20 files changed, 1928 insertions, 213 deletions
diff --git a/Documentation/ABI/testing/sysfs-driver-hid-roccat-pyra b/Documentation/ABI/testing/sysfs-driver-hid-roccat-pyra
new file mode 100644
index 00000000000..ad1125b02ff
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-driver-hid-roccat-pyra
@@ -0,0 +1,98 @@
+What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/actual_cpi
+Date: August 2010
+Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
+Description: It is possible to switch the cpi setting of the mouse with the
+ press of a button.
+ When read, this file returns the raw number of the actual cpi
+ setting reported by the mouse. This number has to be further
+ processed to receive the real dpi value.
+
+ VALUE DPI
+ 1 400
+ 2 800
+ 4 1600
+
+ This file is readonly.
+
+What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/actual_profile
+Date: August 2010
+Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
+Description: When read, this file returns the number of the actual profile in
+ range 0-4.
+ This file is readonly.
+
+What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/firmware_version
+Date: August 2010
+Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
+Description: When read, this file returns the raw integer version number of the
+ firmware reported by the mouse. Using the integer value eases
+ further usage in other programs. To receive the real version
+ number the decimal point has to be shifted 2 positions to the
+ left. E.g. a returned value of 138 means 1.38
+ This file is readonly.
+
+What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/profile_settings
+Date: August 2010
+Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
+Description: The mouse can store 5 profiles which can be switched by the
+ press of a button. A profile is split in settings and buttons.
+ profile_settings holds informations like resolution, sensitivity
+ and light effects.
+ When written, this file lets one write the respective profile
+ settings back to the mouse. The data has to be 13 bytes long.
+ The mouse will reject invalid data.
+ Which profile to write is determined by the profile number
+ contained in the data.
+ This file is writeonly.
+
+What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/profile[1-5]_settings
+Date: August 2010
+Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
+Description: The mouse can store 5 profiles which can be switched by the
+ press of a button. A profile is split in settings and buttons.
+ profile_settings holds informations like resolution, sensitivity
+ and light effects.
+ When read, these files return the respective profile settings.
+ The returned data is 13 bytes in size.
+ This file is readonly.
+
+What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/profile_buttons
+Date: August 2010
+Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
+Description: The mouse can store 5 profiles which can be switched by the
+ press of a button. A profile is split in settings and buttons.
+ profile_buttons holds informations about button layout.
+ When written, this file lets one write the respective profile
+ buttons back to the mouse. The data has to be 19 bytes long.
+ The mouse will reject invalid data.
+ Which profile to write is determined by the profile number
+ contained in the data.
+ This file is writeonly.
+
+What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/profile[1-5]_buttons
+Date: August 2010
+Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
+Description: The mouse can store 5 profiles which can be switched by the
+ press of a button. A profile is split in settings and buttons.
+ profile_buttons holds informations about button layout.
+ When read, these files return the respective profile buttons.
+ The returned data is 19 bytes in size.
+ This file is readonly.
+
+What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/startup_profile
+Date: August 2010
+Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
+Description: The integer value of this attribute ranges from 0-4.
+ When read, this attribute returns the number of the profile
+ that's active when the mouse is powered on.
+ This file is readonly.
+
+What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/settings
+Date: August 2010
+Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
+Description: When read, this file returns the settings stored in the mouse.
+ The size of the data is 3 bytes and holds information on the
+ startup_profile.
+ When written, this file lets write settings back to the mouse.
+ The data has to be 3 bytes long. The mouse will reject invalid
+ data.
diff --git a/Documentation/input/ntrig.txt b/Documentation/input/ntrig.txt
new file mode 100644
index 00000000000..be1fd981f73
--- /dev/null
+++ b/Documentation/input/ntrig.txt
@@ -0,0 +1,126 @@
+N-Trig touchscreen Driver
+-------------------------
+ Copyright (c) 2008-2010 Rafi Rubin <rafi@seas.upenn.edu>
+ Copyright (c) 2009-2010 Stephane Chatty
+
+This driver provides support for N-Trig pen and multi-touch sensors. Single
+and multi-touch events are translated to the appropriate protocols for
+the hid and input systems. Pen events are sufficiently hid compliant and
+are left to the hid core. The driver also provides additional filtering
+and utility functions accessible with sysfs and module parameters.
+
+This driver has been reported to work properly with multiple N-Trig devices
+attached.
+
+
+Parameters
+----------
+
+Note: values set at load time are global and will apply to all applicable
+devices. Adjusting parameters with sysfs will override the load time values,
+but only for that one device.
+
+The following parameters are used to configure filters to reduce noise:
+
+activate_slack number of fingers to ignore before processing events
+
+activation_height size threshold to activate immediately
+activation_width
+
+min_height size threshold bellow which fingers are ignored
+min_width both to decide activation and during activity
+
+deactivate_slack the number of "no contact" frames to ignore before
+ propagating the end of activity events
+
+When the last finger is removed from the device, it sends a number of empty
+frames. By holding off on deactivation for a few frames we can tolerate false
+erroneous disconnects, where the sensor may mistakenly not detect a finger that
+is still present. Thus deactivate_slack addresses problems where a users might
+see breaks in lines during drawing, or drop an object during a long drag.
+
+
+Additional sysfs items
+----------------------
+
+These nodes just provide easy access to the ranges reported by the device.
+sensor_logical_height the range for positions reported during activity
+sensor_logical_width
+
+sensor_physical_height internal ranges not used for normal events but
+sensor_physical_width useful for tuning
+
+All N-Trig devices with product id of 1 report events in the ranges of
+X: 0-9600
+Y: 0-7200
+However not all of these devices have the same physical dimensions. Most
+seem to be 12" sensors (Dell Latitude XT and XT2 and the HP TX2), and
+at least one model (Dell Studio 17) has a 17" sensor. The ratio of physical
+to logical sizes is used to adjust the size based filter parameters.
+
+
+Filtering
+---------
+
+With the release of the early multi-touch firmwares it became increasingly
+obvious that these sensors were prone to erroneous events. Users reported
+seeing both inappropriately dropped contact and ghosts, contacts reported
+where no finger was actually touching the screen.
+
+Deactivation slack helps prevent dropped contact for single touch use, but does
+not address the problem of dropping one of more contacts while other contacts
+are still active. Drops in the multi-touch context require additional
+processing and should be handled in tandem with tacking.
+
+As observed ghost contacts are similar to actual use of the sensor, but they
+seem to have different profiles. Ghost activity typically shows up as small
+short lived touches. As such, I assume that the longer the continuous stream
+of events the more likely those events are from a real contact, and that the
+larger the size of each contact the more likely it is real. Balancing the
+goals of preventing ghosts and accepting real events quickly (to minimize
+user observable latency), the filter accumulates confidence for incoming
+events until it hits thresholds and begins propagating. In the interest in
+minimizing stored state as well as the cost of operations to make a decision,
+I've kept that decision simple.
+
+Time is measured in terms of the number of fingers reported, not frames since
+the probability of multiple simultaneous ghosts is expected to drop off
+dramatically with increasing numbers. Rather than accumulate weight as a
+function of size, I just use it as a binary threshold. A sufficiently large
+contact immediately overrides the waiting period and leads to activation.
+
+Setting the activation size thresholds to large values will result in deciding
+primarily on activation slack. If you see longer lived ghosts, turning up the
+activation slack while reducing the size thresholds may suffice to eliminate
+the ghosts while keeping the screen quite responsive to firm taps.
+
+Contacts continue to be filtered with min_height and min_width even after
+the initial activation filter is satisfied. The intent is to provide
+a mechanism for filtering out ghosts in the form of an extra finger while
+you actually are using the screen. In practice this sort of ghost has
+been far less problematic or relatively rare and I've left the defaults
+set to 0 for both parameters, effectively turning off that filter.
+
+I don't know what the optimal values are for these filters. If the defaults
+don't work for you, please play with the parameters. If you do find other
+values more comfortable, I would appreciate feedback.
+
+The calibration of these devices does drift over time. If ghosts or contact
+dropping worsen and interfere with the normal usage of your device, try
+recalibrating it.
+
+
+Calibration
+-----------
+
+The N-Trig windows tools provide calibration and testing routines. Also an
+unofficial unsupported set of user space tools including a calibrator is
+available at:
+http://code.launchpad.net/~rafi-seas/+junk/ntrig_calib
+
+
+Tracking
+--------
+
+As of yet, all tested N-Trig firmwares do not track fingers. When multiple
+contacts are active they seem to be sorted primarily by Y position.
diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
index 2072e0138e9..68a7e862068 100644
--- a/drivers/hid/Kconfig
+++ b/drivers/hid/Kconfig
@@ -220,12 +220,12 @@ config LOGITECH_FF
force feedback.
config LOGIRUMBLEPAD2_FF
- bool "Logitech Rumblepad 2 force feedback support"
+ bool "Logitech RumblePad/Rumblepad 2 force feedback support"
depends on HID_LOGITECH
select INPUT_FF_MEMLESS
help
Say Y here if you want to enable force feedback support for Logitech
- Rumblepad 2 devices.
+ RumblePad and Rumblepad 2 devices.
config LOGIG940_FF
bool "Logitech Flight System G940 force feedback support"
@@ -235,6 +235,14 @@ config LOGIG940_FF
Say Y here if you want to enable force feedback support for Logitech
Flight System G940 devices.
+config LOGIWII_FF
+ bool "Logitech Speed Force Wireless force feedback support"
+ depends on HID_LOGITECH
+ select INPUT_FF_MEMLESS
+ help
+ Say Y here if you want to enable force feedback support for Logitech
+ Speed Force Wireless (Wii) devices.
+
config HID_MAGICMOUSE
tristate "Apple MagicMouse multi-touch support"
depends on BT_HIDP
@@ -376,6 +384,13 @@ config HID_ROCCAT_KONE
---help---
Support for Roccat Kone mouse.
+config HID_ROCCAT_PYRA
+ tristate "Roccat Pyra mouse support"
+ depends on USB_HID
+ select HID_ROCCAT
+ ---help---
+ Support for Roccat Pyra mouse.
+
config HID_SAMSUNG
tristate "Samsung InfraRed remote control or keyboards"
depends on USB_HID
diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile
index 46f037f3df8..ad74abcc73d 100644
--- a/drivers/hid/Makefile
+++ b/drivers/hid/Makefile
@@ -21,6 +21,9 @@ endif
ifdef CONFIG_LOGIG940_FF
hid-logitech-objs += hid-lg3ff.o
endif
+ifdef CONFIG_LOGIWII_FF
+ hid-logitech-objs += hid-lg4ff.o
+endif
obj-$(CONFIG_HID_3M_PCT) += hid-3m-pct.o
obj-$(CONFIG_HID_A4TECH) += hid-a4tech.o
@@ -52,6 +55,7 @@ obj-$(CONFIG_HID_PETALYNX) += hid-petalynx.o
obj-$(CONFIG_HID_PICOLCD) += hid-picolcd.o
obj-$(CONFIG_HID_ROCCAT) += hid-roccat.o
obj-$(CONFIG_HID_ROCCAT_KONE) += hid-roccat-kone.o
+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
diff --git a/drivers/hid/hid-3m-pct.c b/drivers/hid/hid-3m-pct.c
index 2a0d56b7a02..02d8cd3b1b1 100644
--- a/drivers/hid/hid-3m-pct.c
+++ b/drivers/hid/hid-3m-pct.c
@@ -2,6 +2,8 @@
* 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.
*
*/
@@ -24,15 +26,26 @@ MODULE_LICENSE("GPL");
#include "hid-ids.h"
+#define MAX_SLOTS 60
+#define MAX_TRKID USHRT_MAX
+#define MAX_EVENTS 360
+
+/* estimated signal-to-noise ratios */
+#define SN_MOVE 2048
+#define SN_WIDTH 128
+
struct mmm_finger {
__s32 x, y, w, h;
- __u8 rank;
+ __u16 id;
+ bool prev_touch;
bool touch, valid;
};
struct mmm_data {
- struct mmm_finger f[10];
- __u8 curid, num;
+ struct mmm_finger f[MAX_SLOTS];
+ __u16 id;
+ __u8 curid;
+ __u8 nexp, nreal;
bool touch, valid;
};
@@ -40,6 +53,10 @@ 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:
@@ -50,18 +67,20 @@ static int mmm_input_mapping(struct hid_device *hdev, struct hid_input *hi,
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,
- field->logical_minimum,
- field->logical_maximum, 0, 0);
+ 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,
- field->logical_minimum,
- field->logical_maximum, 0, 0);
+ f1, f2, df / SN_MOVE, 0);
return 1;
}
return 0;
@@ -81,21 +100,31 @@ static int mmm_input_mapping(struct hid_device *hdev, struct hid_input *hi,
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,
- 1, 1, 0, 0);
+ 0, 1, 0, 0);
return 1;
case HID_DG_CONTACTID:
- field->logical_maximum = 59;
+ field->logical_maximum = MAX_TRKID;
hid_map_usage(hi, usage, bit, max,
EV_ABS, ABS_MT_TRACKING_ID);
+ input_set_abs_params(hi->input, ABS_MT_TRACKING_ID,
+ 0, MAX_TRKID, 0, 0);
+ if (!hi->input->mt)
+ input_mt_create_slots(hi->input, MAX_SLOTS);
+ input_set_events_per_packet(hi->input, MAX_EVENTS);
return 1;
}
/* let hid-input decide for the others */
@@ -113,10 +142,10 @@ 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)
- clear_bit(usage->code, *bit);
-
- return 0;
+ set_bit(usage->type, hi->input->evbit);
+ return -1;
}
/*
@@ -126,70 +155,49 @@ static int mmm_input_mapped(struct hid_device *hdev, struct hid_input *hi,
static void mmm_filter_event(struct mmm_data *md, struct input_dev *input)
{
struct mmm_finger *oldest = 0;
- bool pressed = false, released = false;
int i;
-
- /*
- * we need to iterate on all fingers to decide if we have a press
- * or a release event in our touchscreen emulation.
- */
- for (i = 0; i < 10; ++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 */
- } else if (f->touch) {
+ continue;
+ }
+ input_mt_slot(input, i);
+ if (f->touch) {
/* this finger is on the screen */
int wide = (f->w > f->h);
- input_event(input, EV_ABS, ABS_MT_TRACKING_ID, i);
+ /* 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;
+
+ if (!f->prev_touch)
+ f->id = md->id++;
+ input_event(input, EV_ABS, ABS_MT_TRACKING_ID, f->id);
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,
- wide ? f->w : f->h);
- input_event(input, EV_ABS, ABS_MT_TOUCH_MINOR,
- wide ? f->h : f->w);
- input_mt_sync(input);
- /*
- * touchscreen emulation: maintain the age rank
- * of this finger, decide if we have a press
- */
- if (f->rank == 0) {
- f->rank = ++(md->num);
- if (f->rank == 1)
- pressed = true;
- }
- if (f->rank == 1)
+ input_event(input, EV_ABS, ABS_MT_TOUCH_MAJOR, major);
+ input_event(input, EV_ABS, ABS_MT_TOUCH_MINOR, minor);
+ /* touchscreen emulation: pick the oldest contact */
+ if (!oldest || ((f->id - oldest->id) & (SHRT_MAX + 1)))
oldest = f;
} else {
/* this finger took off the screen */
- /* touchscreen emulation: maintain age rank of others */
- int j;
-
- for (j = 0; j < 10; ++j) {
- struct mmm_finger *g = &md->f[j];
- if (g->rank > f->rank) {
- g->rank--;
- if (g->rank == 1)
- oldest = g;
- }
- }
- f->rank = 0;
- --(md->num);
- if (md->num == 0)
- released = true;
+ input_event(input, EV_ABS, ABS_MT_TRACKING_ID, -1);
}
+ f->prev_touch = f->touch;
f->valid = 0;
}
/* touchscreen emulation */
if (oldest) {
- if (pressed)
- input_event(input, EV_KEY, BTN_TOUCH, 1);
+ input_event(input, EV_KEY, BTN_TOUCH, 1);
input_event(input, EV_ABS, ABS_X, oldest->x);
input_event(input, EV_ABS, ABS_Y, oldest->y);
- } else if (released) {
+ } else {
input_event(input, EV_KEY, BTN_TOUCH, 0);
}
+ input_sync(input);
}
/*
@@ -223,10 +231,12 @@ static int mmm_event(struct hid_device *hid, struct hid_field *field,
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:
@@ -238,7 +248,12 @@ static int mmm_event(struct hid_device *hid, struct hid_field *field,
md->f[md->curid].y = value;
break;
case HID_DG_CONTACTCOUNT:
- mmm_filter_event(md, input);
+ if (value)
+ md->nexp = value;
+ if (md->nreal >= md->nexp) {
+ mmm_filter_event(md, input);
+ md->nreal = 0;
+ }
break;
}
}
@@ -255,6 +270,8 @@ 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) {
dev_err(&hdev->dev, "cannot allocate 3M data\n");
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
index 5ac2be978c9..cb7dc99d8b2 100644
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -1249,6 +1249,7 @@ static const struct hid_device_id hid_blacklist[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL4) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MIGHTYMOUSE) },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGICMOUSE) },
+ { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGICTRACKPAD) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_ANSI) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_ISO) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_ANSI) },
@@ -1328,6 +1329,7 @@ static const struct hid_device_id hid_blacklist[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_CORDLESS_DESKTOP_LX500) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_EXTREME_3D) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WHEEL) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD_CORD) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD2_2) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WINGMAN_F3D) },
@@ -1337,6 +1339,7 @@ static const struct hid_device_id hid_blacklist[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOMO_WHEEL) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOMO_WHEEL2) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G25_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) },
@@ -1372,6 +1375,7 @@ static const struct hid_device_id hid_blacklist[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_QUANTA, USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH) },
{ HID_USB_DEVICE(USB_VENDOR_ID_QUANTA, USB_DEVICE_ID_PIXART_IMAGING_INC_OPTICAL_TOUCH_SCREEN) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_KONE) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_PYRA_WIRED) },
{ HID_USB_DEVICE(USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_IR_REMOTE) },
{ HID_USB_DEVICE(USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_WIRELESS_KBD_MOUSE) },
{ HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER) },
diff --git a/drivers/hid/hid-egalax.c b/drivers/hid/hid-egalax.c
index 8ca7f65cf2f..54b017ad258 100644
--- a/drivers/hid/hid-egalax.c
+++ b/drivers/hid/hid-egalax.c
@@ -31,7 +31,7 @@ struct egalax_data {
bool first; /* is this the first finger in the frame? */
bool valid; /* valid finger data, or just placeholder? */
bool activity; /* at least one active finger previously? */
- __u16 lastx, lasty; /* latest valid (x, y) in the frame */
+ __u16 lastx, lasty, lastz; /* latest valid (x, y, z) in the frame */
};
static int egalax_input_mapping(struct hid_device *hdev, struct hid_input *hi,
@@ -79,6 +79,10 @@ static int egalax_input_mapping(struct hid_device *hdev, struct hid_input *hi,
case HID_DG_TIPPRESSURE:
hid_map_usage(hi, usage, bit, max,
EV_ABS, ABS_MT_PRESSURE);
+ /* touchscreen emulation */
+ input_set_abs_params(hi->input, ABS_PRESSURE,
+ field->logical_minimum,
+ field->logical_maximum, 0, 0);
return 1;
}
return 0;
@@ -109,8 +113,8 @@ static void egalax_filter_event(struct egalax_data *td, struct input_dev *input)
if (td->valid) {
/* emit multitouch events */
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_event(input, EV_ABS, ABS_MT_POSITION_X, td->x >> 3);
+ input_event(input, EV_ABS, ABS_MT_POSITION_Y, td->y >> 3);
input_event(input, EV_ABS, ABS_MT_PRESSURE, td->z);
input_mt_sync(input);
@@ -121,6 +125,7 @@ static void egalax_filter_event(struct egalax_data *td, struct input_dev *input)
*/
td->lastx = td->x;
td->lasty = td->y;
+ td->lastz = td->z;
}
/*
@@ -129,8 +134,9 @@ static void egalax_filter_event(struct egalax_data *td, struct input_dev *input)
* the oldest on the panel, the one we want for single touch
*/
if (!td->first && td->activity) {
- input_event(input, EV_ABS, ABS_X, td->lastx);
- input_event(input, EV_ABS, ABS_Y, td->lasty);
+ input_event(input, EV_ABS, ABS_X, td->lastx >> 3);
+ input_event(input, EV_ABS, ABS_Y, td->lasty >> 3);
+ input_event(input, EV_ABS, ABS_PRESSURE, td->lastz);
}
if (!td->valid) {
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
index 5247f5bdb49..ae8f74431d9 100644
--- a/drivers/hid/hid-ids.h
+++ b/drivers/hid/hid-ids.h
@@ -64,6 +64,7 @@
#define USB_VENDOR_ID_APPLE 0x05ac
#define USB_DEVICE_ID_APPLE_MIGHTYMOUSE 0x0304
#define USB_DEVICE_ID_APPLE_MAGICMOUSE 0x030d
+#define USB_DEVICE_ID_APPLE_MAGICTRACKPAD 0x030e
#define USB_DEVICE_ID_APPLE_FOUNTAIN_ANSI 0x020e
#define USB_DEVICE_ID_APPLE_FOUNTAIN_ISO 0x020f
#define USB_DEVICE_ID_APPLE_GEYSER_ANSI 0x0214
@@ -345,6 +346,7 @@
#define USB_DEVICE_ID_LOGITECH_RECEIVER 0xc101
#define USB_DEVICE_ID_LOGITECH_HARMONY_FIRST 0xc110
#define USB_DEVICE_ID_LOGITECH_HARMONY_LAST 0xc14f
+#define USB_DEVICE_ID_LOGITECH_RUMBLEPAD_CORD 0xc20a
#define USB_DEVICE_ID_LOGITECH_RUMBLEPAD 0xc211
#define USB_DEVICE_ID_LOGITECH_EXTREME_3D 0xc215
#define USB_DEVICE_ID_LOGITECH_RUMBLEPAD2 0xc218
@@ -356,6 +358,7 @@
#define USB_DEVICE_ID_LOGITECH_WINGMAN_FFG 0xc293
#define USB_DEVICE_ID_LOGITECH_MOMO_WHEEL 0xc295
#define USB_DEVICE_ID_LOGITECH_G25_WHEEL 0xc299
+#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_S510_RECEIVER_2 0xc517
@@ -468,6 +471,8 @@
#define USB_VENDOR_ID_ROCCAT 0x1e7d
#define USB_DEVICE_ID_ROCCAT_KONE 0x2ced
+#define USB_DEVICE_ID_ROCCAT_PYRA_WIRED 0x2c24
+#define USB_DEVICE_ID_ROCCAT_PYRA_WIRELESS 0x2cf6
#define USB_VENDOR_ID_SAITEK 0x06a3
#define USB_DEVICE_ID_SAITEK_RUMBLEPAD 0xff17
diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c
index 8e733b6eae2..b9877a86eca 100644
--- a/drivers/hid/hid-input.c
+++ b/drivers/hid/hid-input.c
@@ -739,6 +739,9 @@ void hidinput_report_event(struct hid_device *hid, struct hid_report *report)
{
struct hid_input *hidinput;
+ if (hid->quirks & HID_QUIRK_NO_INPUT_SYNC)
+ return;
+
list_for_each_entry(hidinput, &hid->inputs, list)
input_sync(hidinput->input);
}
diff --git a/drivers/hid/hid-lg.c b/drivers/hid/hid-lg.c
index f6433d8050a..9e92c27002c 100644
--- a/drivers/hid/hid-lg.c
+++ b/drivers/hid/hid-lg.c
@@ -7,6 +7,7 @@
* Copyright (c) 2006-2007 Jiri Kosina
* Copyright (c) 2007 Paul Walmsley
* Copyright (c) 2008 Jiri Slaby
+ * Copyright (c) 2010 Hendrik Iben
*/
/*
@@ -19,6 +20,9 @@
#include <linux/device.h>
#include <linux/hid.h>
#include <linux/module.h>
+#include <linux/random.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
#include "hid-ids.h"
#include "hid-lg.h"
@@ -35,6 +39,7 @@
#define LG_FF2 0x400
#define LG_RDESC_REL_ABS 0x800
#define LG_FF3 0x1000
+#define LG_FF4 0x2000
/*
* Certain Logitech keyboards send in report #3 keys which are far
@@ -60,6 +65,17 @@ static void lg_report_fixup(struct hid_device *hdev, __u8 *rdesc,
"report descriptor\n");
rdesc[33] = rdesc[50] = 0x02;
}
+
+ if ((quirks & LG_FF4) && rsize >= 101 &&
+ rdesc[41] == 0x95 && rdesc[42] == 0x0B &&
+ rdesc[47] == 0x05 && rdesc[48] == 0x09) {
+ dev_info(&hdev->dev, "fixing up Logitech Speed Force Wireless "
+ "button descriptor\n");
+ rdesc[41] = 0x05;
+ rdesc[42] = 0x09;
+ rdesc[47] = 0x95;
+ rdesc[48] = 0x0B;
+ }
}
#define lg_map_key_clear(c) hid_map_usage_clear(hi, usage, bit, max, \
@@ -285,12 +301,33 @@ static int lg_probe(struct hid_device *hdev, const struct hid_device_id *id)
goto err_free;
}
+ if (quirks & LG_FF4) {
+ unsigned char buf[] = { 0x00, 0xAF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+
+ ret = hdev->hid_output_raw_report(hdev, buf, sizeof(buf), HID_FEATURE_REPORT);
+
+ if (ret >= 0) {
+ /* insert a little delay of 10 jiffies ~ 40ms */
+ wait_queue_head_t wait;
+ init_waitqueue_head (&wait);
+ wait_event_interruptible_timeout(wait, 0, 10);
+
+ /* Select random Address */
+ buf[1] = 0xB2;
+ get_random_bytes(&buf[2], 2);
+
+ ret = hdev->hid_output_raw_report(hdev, buf, sizeof(buf), HID_FEATURE_REPORT);
+ }
+ }
+
if (quirks & LG_FF)
lgff_init(hdev);
if (quirks & LG_FF2)
lg2ff_init(hdev);
if (quirks & LG_FF3)
lg3ff_init(hdev);
+ if (quirks & LG_FF4)
+ lg4ff_init(hdev);
return 0;
err_free:
@@ -325,6 +362,8 @@ static const struct hid_device_id lg_devices[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WHEEL),
.driver_data = LG_NOGET | LG_FF },
+ { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD_CORD),
+ .driver_data = LG_FF2 },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD),
.driver_data = LG_FF },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD2_2),
@@ -339,6 +378,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_WII_WHEEL),
+ .driver_data = LG_FF4 },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WINGMAN_FFG ),
.driver_data = LG_FF },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD2),
diff --git a/drivers/hid/hid-lg.h b/drivers/hid/hid-lg.h
index ce2ac867262..b0100ba2ae0 100644
--- a/drivers/hid/hid-lg.h
+++ b/drivers/hid/hid-lg.h
@@ -19,4 +19,10 @@ int lg3ff_init(struct hid_device *hdev);
static inline int lg3ff_init(struct hid_device *hdev) { return -1; }
#endif
+#ifdef CONFIG_LOGIWII_FF
+int lg4ff_init(struct hid_device *hdev);
+#else
+static inline int lg4ff_init(struct hid_device *hdev) { return -1; }
+#endif
+
#endif
diff --git a/drivers/hid/hid-lg2ff.c b/drivers/hid/hid-lg2ff.c
index d888f1e6794..4258253c36b 100644
--- a/drivers/hid/hid-lg2ff.c
+++ b/drivers/hid/hid-lg2ff.c
@@ -1,5 +1,5 @@
/*
- * Force feedback support for Logitech Rumblepad 2
+ * Force feedback support for Logitech RumblePad and Rumblepad 2
*
* Copyright (c) 2008 Anssi Hannula <anssi.hannula@gmail.com>
*/
@@ -110,7 +110,7 @@ int lg2ff_init(struct hid_device *hid)
usbhid_submit_report(hid, report, USB_DIR_OUT);
- dev_info(&hid->dev, "Force feedback for Logitech Rumblepad 2 by "
+ dev_info(&hid->dev, "Force feedback for Logitech RumblePad/Rumblepad 2 by "
"Anssi Hannula <anssi.hannula@gmail.com>\n");
return 0;
diff --git a/drivers/hid/hid-lg4ff.c b/drivers/hid/hid-lg4ff.c
new file mode 100644
index 00000000000..7eef5a2ce94
--- /dev/null
+++ b/