diff options
author | Simon Wood <simon@mungewell.org> | 2010-09-22 13:19:42 +0200 |
---|---|---|
committer | Jiri Kosina <jkosina@suse.cz> | 2010-09-22 13:25:39 +0200 |
commit | 32c88cbc3080f43c429f6456aa9cd845e37f3778 (patch) | |
tree | 18886cea811ef68ce20aea0fa975d8a3ca2b1589 /drivers/hid/hid-lg.c | |
parent | fe2c91ee245bd81230f1d67645237a684b90be2b (diff) |
HID: Add support for Logitech Speed Force Wireless gaming wheel
The following patch adds support for the Logitech Speed Force Wireless gaming
wheel. Originally designed for the WII console. Details on the protocol:
http://wiibrew.org/wiki/Logitech_USB_steering_wheel
This patch relies on previous patch:
"Don't Send Feature Reports on Interrupt Endpoint"
Logitech as produce a very similar wheel for the PS2/PS3, it is expected that
this patch could also support the PS2/PS3 wheel if the USB ID's are added and
(if required) the HID descriptor is modified.
Signed-off-by: Simon Wood <simon@mungewell.org>
Signed-off-by: Jiri Kosina <jkosina@suse.cz>
Diffstat (limited to 'drivers/hid/hid-lg.c')
-rw-r--r-- | drivers/hid/hid-lg.c | 38 |
1 files changed, 38 insertions, 0 deletions
diff --git a/drivers/hid/hid-lg.c b/drivers/hid/hid-lg.c index f6433d8050a..8989f151e0d 100644 --- a/drivers/hid/hid-lg.c +++ b/drivers/hid/hid-lg.c @@ -19,6 +19,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 +38,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 +64,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 +300,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: @@ -339,6 +375,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), |