diff mbox

PATCH [1/6] HID: lg4ff - Move handling of Logitech wheels to lg4ff driver

Message ID 1436421.MlUiXUhh2P@qosmio-x300 (mailing list archive)
State New, archived
Delegated to: Jiri Kosina
Headers show

Commit Message

Michal Malý July 31, 2011, 12:52 a.m. UTC
This is the first out of five patches me and Simon Wood (CC'd) have been working on. It separates the handling of Logitech wheels 
from the generic lgff driver and adds additional features specific for the Logitech wheels, namely
- Native mode support for Driving Force GT, Driving Force Pro, G25 and G27 wheels
  Every Logitech wheel reports itself as generic Logitech Driving Force wheel (VID 046d, PID c294). This is done to ensure that the 
wheel will work on every USB HID-aware system even when no Logitech driver is available. It however limits the capabilities of the 
wheel - range is limited to 200 degrees, G25/G27 don't report the clutch pedal and there is only one combined axis for throttle and 
brake. The switch to native mode is done via hardware-specific command which is different for each wheel. When the wheel 
receives such command, it simulates reconnect and reports to the OS with its actual PID.
- Adjustable wheel range
  DFGT, DFP, G25 and G27 have variable range of the steering wheel. The range is limited by applying a maximum constant FF force 
when the wheel is turned beyond the allowed range. The limit as also set by a hardware-specific command. There is a common 
command for DFGT, G25 and G27 and another one for DFP. It is probably possible to use the DFP command to limit the range on 
other Logitech wheels too, but this is not supported by the official Logitech driver for Windows.
  The patch adds a sysfs interface which allows for the range to be set from userspace.
- Fixed autocentering command
  All Logitech wheels support FF_AUTOCENTER effect. The original implementation in the lgff driver didn't work well with wheels, this 
patch fixes it. According to USB communication sniffs the Formula Force EX (pretty much rebranded original Driving Force) doesn't 
accept the generic autocentering command, this issue is also addressed by the patch

There are still some features this patch doesn't cover, but since some of them will most likely require modifications of the ff-
memless driver we have decided not to include them yet.

As first we decided to move the handling of Logitech wheels from hid-lgff driver to hid-lg4ff driver (originally used for Wii wheel only). 
At also adds PID of Logitech Driving Force GT.

Signed-off-by: Michal Malý <madcatxster@gmail.com>
---

--
To unsubscribe from this list: send the line "unsubscribe linux-input" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Comments

simon@mungewell.org July 31, 2011, 2:52 a.m. UTC | #1
> This is the first out of five patches me and Simon Wood (CC'd) have been
> working on.

As a formality I should state that I support this series of patches. I
think moving the FF code from 'hid-lgff.c' to 'hid-lg4ff' will enable us
to implement more features in the future without risk of inadverantly
affecting other (non-wheel) devices.

I have tested this code against the WiiWheel and DrivingForcePro.

signed-off-by: simon@mungewell.org

Cheers,
Simon.

--
To unsubscribe from this list: send the line "unsubscribe linux-input" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Jiri Kosina Aug. 3, 2011, 1:51 p.m. UTC | #2
On Sat, 30 Jul 2011, simon@mungewell.org wrote:

> > This is the first out of five patches me and Simon Wood (CC'd) have been
> > working on.
> 
> As a formality I should state that I support this series of patches. I
> think moving the FF code from 'hid-lgff.c' to 'hid-lg4ff' will enable us
> to implement more features in the future without risk of inadverantly
> affecting other (non-wheel) devices.
> 
> I have tested this code against the WiiWheel and DrivingForcePro.
> 
> signed-off-by: simon@mungewell.org

OK, thanks a lot guys for this effort.

I am finalizing the patch review and planning to merge it. Just one minor 
thing -- Michal, I am afraid that I'd rather avoid UTF-8 characters being 
passed to printk(). So could you please resping 1/6 patch with the 
diacritics removed there?

Thanks,
Jiri Kosina Aug. 4, 2011, 1:23 p.m. UTC | #3
On Sat, 30 Jul 2011, simon@mungewell.org wrote:

> > This is the first out of five patches me and Simon Wood (CC'd) have been
> > working on.
> 
> As a formality I should state that I support this series of patches. I
> think moving the FF code from 'hid-lgff.c' to 'hid-lg4ff' will enable us
> to implement more features in the future without risk of inadverantly
> affecting other (non-wheel) devices.
> 
> I have tested this code against the WiiWheel and DrivingForcePro.
> 
> signed-off-by: simon@mungewell.org

Michal, thanks a lot for resending with the UTF-8 stuff in printk() 
removed.

I am going to apply it, but the whole series has been line wrapped by your 
client. Could you please fix that up and resend, so that I could apply it?

Thanks,
simon@mungewell.org Aug. 9, 2011, 11:35 p.m. UTC | #4
>
> I am finalizing the patch review and planning to merge it.

Hi Jiri,
Saw that this is in the latest git grab, but I also noticed that (the new)
option 'LOGIWHEELS_FF' is not automatically selected if I grab an old
kernel config (say 2.6.38 on my ubuntu box) and do 'make oldconfig' with
the enter key held down.

Did Michal/myself miss something, or is it preferable to not enable by
default?

The down side is that the FF on these wheels will stop working (compared
to 3.0) if kernel builder does not enable this....

I can spin a patch if you'd like to point me the right direction.

Cheers,
Simon.

--
To unsubscribe from this list: send the line "unsubscribe linux-input" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
index db63ccf..ea2c338 100644
--- a/drivers/hid/hid-ids.h
+++ b/drivers/hid/hid-ids.h
@@ -436,6 +436,7 @@ 
 #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_DFGT_WHEEL	0xc29a
 #define USB_DEVICE_ID_LOGITECH_G27_WHEEL	0xc29b
 #define USB_DEVICE_ID_LOGITECH_WII_WHEEL	0xc29c
 #define USB_DEVICE_ID_LOGITECH_ELITE_KBD	0xc30a
diff --git a/drivers/hid/hid-lg.c b/drivers/hid/hid-lg.c
index a7f916e..e0ae4a0 100644
--- a/drivers/hid/hid-lg.c
+++ b/drivers/hid/hid-lg.c
@@ -363,7 +363,7 @@  static int lg_probe(struct hid_device *hdev, const struct hid_device_id *id)
 		goto err_free;
 	}
 
-	if (quirks & (LG_FF | LG_FF2 | LG_FF3))
+	if (quirks & (LG_FF | LG_FF2 | LG_FF3 | LG_FF4))
 		connect_mask &= ~HID_CONNECT_FF;
 
 	ret = hid_hw_start(hdev, connect_mask);
@@ -372,7 +372,8 @@  static int lg_probe(struct hid_device *hdev, const struct hid_device_id *id)
 		goto err_free;
 	}
 
-	if (quirks & LG_FF4) {
+	/* Setup wireless link with Logitech Wii wheel */
+	if(hdev->product == USB_DEVICE_ID_LOGITECH_WII_WHEEL) {
 		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);
@@ -431,7 +432,7 @@  static const struct hid_device_id lg_devices[] = {
 	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_EXTREME_3D),
 		.driver_data = LG_NOGET },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WHEEL),
-		.driver_data = LG_NOGET | LG_FF },
+		.driver_data = LG_NOGET | LG_FF4 },
 
 	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD_CORD),
 		.driver_data = LG_FF2 },
@@ -444,15 +445,17 @@  static const struct hid_device_id lg_devices[] = {
 	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_FORCE3D_PRO),
 		.driver_data = LG_FF },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOMO_WHEEL),
-		.driver_data = LG_FF },
+		.driver_data = LG_FF4 },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOMO_WHEEL2),
-		.driver_data = LG_FF },
+		.driver_data = LG_FF4 },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G25_WHEEL),
-		.driver_data = LG_FF },
+		.driver_data = LG_FF4 },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_DFGT_WHEEL),
+		.driver_data = LG_FF4 },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G27_WHEEL),
-		.driver_data = LG_FF },
+		.driver_data = LG_FF4 },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_DFP_WHEEL),
-		.driver_data = LG_NOGET | LG_FF },
+		.driver_data = LG_NOGET | LG_FF4 },
 	{ 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 ),
diff --git a/drivers/hid/hid-lg4ff.c b/drivers/hid/hid-lg4ff.c
index fa550c8..6b357ac 100644
--- a/drivers/hid/hid-lg4ff.c
+++ b/drivers/hid/hid-lg4ff.c
@@ -29,17 +29,32 @@ 
 
 #include "usbhid/usbhid.h"
 #include "hid-lg.h"
+#include "hid-ids.h"
 
-struct lg4ff_device {
-	struct hid_report *report;
-};
-
-static const signed short ff4_wheel_ac[] = {
+static const signed short lg4ff_wheel_effects[] = {
 	FF_CONSTANT,
 	FF_AUTOCENTER,
 	-1
 };
 
+struct lg4ff_wheel {
+	const __u32 product_id;
+	const signed short *ff_effects;
+	const __u16 min_range;
+	const __u16 max_range;
+};
+
+static const struct lg4ff_wheel lg4ff_devices[] = {
+	{USB_DEVICE_ID_LOGITECH_WHEEL,       lg4ff_wheel_effects, 40, 270},
+	{USB_DEVICE_ID_LOGITECH_MOMO_WHEEL,  lg4ff_wheel_effects, 40, 270},
+	{USB_DEVICE_ID_LOGITECH_DFP_WHEEL,   lg4ff_wheel_effects, 40, 900},
+	{USB_DEVICE_ID_LOGITECH_G25_WHEEL,   lg4ff_wheel_effects, 40, 900},
+	{USB_DEVICE_ID_LOGITECH_DFGT_WHEEL,  lg4ff_wheel_effects, 40, 900},
+	{USB_DEVICE_ID_LOGITECH_G27_WHEEL,   lg4ff_wheel_effects, 40, 900},
+	{USB_DEVICE_ID_LOGITECH_MOMO_WHEEL2, lg4ff_wheel_effects, 40, 270},
+	{USB_DEVICE_ID_LOGITECH_WII_WHEEL,   lg4ff_wheel_effects, 40, 270}
+};
+
 static int hid_lg4ff_play(struct input_dev *dev, void *data,
 			 struct ff_effect *effect)
 {
@@ -55,13 +70,12 @@  static int hid_lg4ff_play(struct input_dev *dev, void *data,
 		x = effect->u.ramp.start_level + 0x80;	/* 0x80 is no force */
 		CLAMP(x);
 		report->field[0]->value[0] = 0x11;	/* Slot 1 */
-		report->field[0]->value[1] = 0x10;
+		report->field[0]->value[1] = 0x08;
 		report->field[0]->value[2] = x;
-		report->field[0]->value[3] = 0x00;
+		report->field[0]->value[3] = 0x80;
 		report->field[0]->value[4] = 0x00;
-		report->field[0]->value[5] = 0x08;
+		report->field[0]->value[5] = 0x00;
 		report->field[0]->value[6] = 0x00;
-		dbg_hid("Autocenter, x=0x%02X\n", x);
 
 		usbhid_submit_report(hid, report, USB_DIR_OUT);
 		break;
@@ -74,15 +88,14 @@  static void hid_lg4ff_set_autocenter(struct input_dev *dev, u16 magnitude)
 	struct hid_device *hid = input_get_drvdata(dev);
 	struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list;
 	struct hid_report *report = list_entry(report_list->next, struct hid_report, list);
-	__s32 *value = report->field[0]->value;
 
-	*value++ = 0xfe;
-	*value++ = 0x0d;
-	*value++ = 0x07;
-	*value++ = 0x07;
-	*value++ = (magnitude >> 8) & 0xff;
-	*value++ = 0x00;
-	*value = 0x00;
+	report->field[0]->value[0] = 0xfe;
+	report->field[0]->value[1] = 0x0d;
+	report->field[0]->value[2] = magnitude >> 13;
+	report->field[0]->value[3] = magnitude >> 13;
+	report->field[0]->value[4] = magnitude >> 8;
+	report->field[0]->value[5] = 0x00;
+	report->field[0]->value[6] = 0x00;
 
 	usbhid_submit_report(hid, report, USB_DIR_OUT);
 }
@@ -95,9 +108,7 @@  int lg4ff_init(struct hid_device *hid)
 	struct input_dev *dev = hidinput->input;
 	struct hid_report *report;
 	struct hid_field *field;
-	const signed short *ff_bits = ff4_wheel_ac;
-	int error;
-	int i;
+	int error, i, j;
 
 	/* Find the report to use */
 	if (list_empty(report_list)) {
@@ -117,9 +128,24 @@  int lg4ff_init(struct hid_device *hid)
 		hid_err(hid, "NULL field\n");
 		return -1;
 	}
+	
+	/* Check what wheel has been connected */
+	for (i = 0; i < ARRAY_SIZE(lg4ff_devices); i++) {
+		if (hid->product == lg4ff_devices[i].product_id) {
+			dbg_hid("Found compatible device, product ID %04X\n", lg4ff_devices[i].product_id);
+			break;
+		}
+	}
+
+	if (i == ARRAY_SIZE(lg4ff_devices)) {
+		hid_err(hid, "Device is not supported by lg4ff driver. If you think it should be, consider reporting a bug to"
+			     "LKML, Simon Wood <simon@mungewell.org> or Michal Malý <madcatxster@gmail.com>\n");
+		return -1;
+	}
 
-	for (i = 0; ff_bits[i] >= 0; i++)
-		set_bit(ff_bits[i], dev->ffbit);
+	/* Set supported force feedback capabilities */
+	for (j = 0; lg4ff_devices[i].ff_effects[j] >= 0; j++)
+		set_bit(lg4ff_devices[i].ff_effects[j], dev->ffbit);
 
 	error = input_ff_create_memless(dev, NULL, hid_lg4ff_play);
 
diff --git a/drivers/hid/hid-lgff.c b/drivers/hid/hid-lgff.c
index 088f850..27bc54f 100644
--- a/drivers/hid/hid-lgff.c
+++ b/drivers/hid/hid-lgff.c
@@ -58,12 +58,6 @@  static const signed short ff_joystick_ac[] = {
 	-1
 };
 
-static const signed short ff_wheel[] = {
-	FF_CONSTANT,
-	FF_AUTOCENTER,
-	-1
-};
-
 static const struct dev_type devices[] = {
 	{ 0x046d, 0xc211, ff_rumble },
 	{ 0x046d, 0xc219, ff_rumble },
@@ -71,14 +65,7 @@  static const struct dev_type devices[] = {
 	{ 0x046d, 0xc286, ff_joystick_ac },
 	{ 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 },
-	{ 0x046d, 0xca03, ff_wheel },
 };
 
 static int hid_lgff_play(struct input_dev *dev, void *data, struct ff_effect *effect)