HID: Autocentering support for Logitech MOMO Racing Wheel
authorSergey Belyashov <Sergey.Belyashov@gmail.com>
Tue, 2 Sep 2008 15:31:16 +0000 (17:31 +0200)
committerJiri Kosina <jkosina@suse.cz>
Tue, 14 Oct 2008 21:50:58 +0000 (23:50 +0200)
Current kernel has no support for autocentering for Logitech wheels.  By
default autocentering enabled in wheel and constant effect does not work
properly. Using USB sniffer I found command which change autocentering
settings: 0xFE, 0x0D, 0x0R, 0x0L, 0x80, 0x00, 0x00, where R - clockwise force,
L - counter-clockwise (0x0-0xF, 0xC = 100%).

Signed-off-by: Sergey Belyashov <Sergey.Belyashov@gmail.com>
Signed-off-by: Jiri Kosina <jkosina@suse.cz>
drivers/hid/hid-lgff.c

index e379c16..51aff08 100644 (file)
@@ -50,6 +50,12 @@ static const signed short ff_joystick[] = {
        -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 },
@@ -57,7 +63,7 @@ static const struct dev_type devices[] = {
        { 0x046d, 0xc286, ff_joystick },
        { 0x046d, 0xc294, ff_joystick },
        { 0x046d, 0xc295, ff_joystick },
-       { 0x046d, 0xca03, ff_joystick },
+       { 0x046d, 0xca03, ff_wheel },
 };
 
 static int hid_lgff_play(struct input_dev *dev, void *data, struct ff_effect *effect)
@@ -102,6 +108,23 @@ static int hid_lgff_play(struct input_dev *dev, void *data, struct ff_effect *ef
        return 0;
 }
 
+static void hid_lgff_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;
+       magnitude = (magnitude >> 12) & 0xf;
+       *value++ = 0xfe;
+       *value++ = 0x0d;
+       *value++ = magnitude;   /* clockwise strength */
+       *value++ = magnitude;   /* counter-clockwise strength */
+       *value++ = 0x80;
+       *value++ = 0x00;
+       *value = 0x00;
+       usbhid_submit_report(hid, report, USB_DIR_OUT);
+}
+
 int lgff_init(struct hid_device* hid)
 {
        struct hid_input *hidinput = list_entry(hid->inputs.next, struct hid_input, list);
@@ -147,6 +170,9 @@ int lgff_init(struct hid_device* hid)
        if (error)
                return error;
 
+       if ( test_bit(FF_AUTOCENTER, dev->ffbit) )
+               dev->ff->set_autocenter = hid_lgff_set_autocenter;
+
        printk(KERN_INFO "Force feedback for Logitech force feedback devices by Johann Deneux <johann.deneux@it.uu.se>\n");
 
        return 0;