Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 32c88cbc authored by Simon Wood's avatar Simon Wood Committed by Jiri Kosina
Browse files

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: default avatarSimon Wood <simon@mungewell.org>
Signed-off-by: default avatarJiri Kosina <jkosina@suse.cz>
parent fe2c91ee
Loading
Loading
Loading
Loading
+8 −0
Original line number Diff line number Diff line
@@ -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
+3 −0
Original line number Diff line number Diff line
@@ -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
+1 −0
Original line number Diff line number Diff line
@@ -1335,6 +1335,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) },
+1 −0
Original line number Diff line number Diff line
@@ -350,6 +350,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
+38 −0
Original line number Diff line number Diff line
@@ -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),
Loading