The online racing simulator
Just for the record, the secret combo is Select+R3+Right Paddle.

Maybe you could try usbmon driver and capture the USB traffic for both G2x and DFP, I bet you'll spot a difference at some point. With some real data in hand it could be reported to LKML, the USB-layer maintaners seem like nice guys to me and they'll probably have some answers.
To make matters rather interesting, I think I figured out the formula to construct range setting commands for DFP. According to my logs the Logitech driver always sends F8 03 (or F8 02 is the range to set is 200 deg or less) command followed by the command that specifies the range.

Please check out the attached PDF for details about the range specifying command. It's not exactly a PhD thesis, but I hope it'll be useful

EDIT: To make my forensic investigation actually useful, I attached a patch for LTWC which (surprise!) seems to work! It works with 201+ degrees ranges only, but it's a good start

EDIT2: Uploaded a patch in proper format

EDIT3: Third time does it I fixed 2 typos in the PDF and added a bit broader description of the "algorithm".

EDIT4: A proper universal algorithm is described lower in this thread. See http://www.lfsforum.net/showthread.php?p=1603971#post1603971
Attached files
0001-Added-a-formula-to-calculate-DFP-wheel-range.txt - 2.1 KB - 476 views
DFP_rset.pdf - 51.6 KB - 753 views
Quote from MadCatX :To make matters rather interesting, I think I figured out the formula to construct range setting commands for DFP. According to my logs the Logitech driver always sends F8 03 (or F8 02 is the range to set is 200 deg or less) command followed by the command that specifies the range.

Please check out the attached PDF for details about the range specifying command. It's not exactly a PhD thesis, but I hope it'll be useful

EDIT: To make my forensic investigation actually useful, I attached a patch for LTWC which (surprise!) seems to work! It works with 201+ degrees ranges only, but it's a good start

EDIT2: Uploaded a patch in proper format

EDIT3: Third time does it I fixed 2 typos in the PDF and added a bit broader description of the "algorithm".

Wooho, great work! I just integrated your patch into LTWC and it is working fine. I added also support for setting ranges < 200 degree (but it seems the range calculation is not really correct here, e.g. setting a range of 100 results in effective ~50-60 degrees)


And even more good news:
There is a really simple kernel patch necessary to fix the "parse failed" kernel errors. The DFP needs the flag "LG_NOGET" added - thats all

Change in drivers/hid/hid-lg.c this line:
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_DFP_WHEEL),
.driver_data = LG_FF },

to that:

{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_DFP_WHEEL),
.driver_data = LG_NOGET | LG_FF },

and rebuild the modules.

I am waiting for the kernel 2.6.39 to be final, then i will provide a proper patch and cross fingers it gets integrated
Nice, how did you find out about that? If I get it right, the NOGET flag tells the HID core to not poll the device upon connecting but rather wait until the device reports its status by itself?

I'll take another look on the range setting for range <201, I suppose it won't be a big deal to make it right.

EDIT: Just tried the LG_NOGET patch on the 2.6.39 (it's been out for a couple of hours, even the BFS is available already ) and... it WORKS! It would seem that the last thing to do is to get separate throttle/brake axes working. I suppose we could modify the module and make it create two devices in /dev/input, one reporting separated and the other combined axes.
Quote from MadCatX :Nice, how did you find out about that? If I get it right, the NOGET flag tells the HID core to not poll the device upon connecting but rather wait until the device reports its status by itself?

To be honest adding that flag was my first guess without really understanding what it does. Because it is also set for the basic Logitech wheel

Quote from MadCatX :I'll take another look on the range setting for range <201, I suppose it won't be a big deal to make it right.

EDIT: Just tried the LG_NOGET patch on the 2.6.39 (it's been out for a couple of hours, even the BFS is available already ) and... it WORKS! It would seem that the last thing to do is to get separate throttle/brake axes working. I suppose we could modify the module and make it create two devices in /dev/input, one reporting separated and the other combined axes.

Hmm, i did not try the pedals at all yet I assumed they should be automatically separated in native mode. Why do you think this requires kernel-side changes? Is this not a property of the DFP device itself if it reports combined/separate axes?
Well, when I think about it again, perhaps you're right. This is raw data output from the DFP axes position report. Win7 seems to recognize DFP even without the Logitech driver and switches it to native mode automatically, so I cannot check if it looks the same in default mode.

No thr/no bkr
X - 8214
Hat - 8
Y - 127
Z - 255
Rz - 255
Unk - 27

No thr/full brk
X - 8214
Hat - 8
Y - 255
Z - 255
Rz - 0
Unk - 27

Full thr/no brk
X - 8214
Hat - 8
Y - 0
Z - 0
Rz - 255
Unk - 27

This suggests that Z is the position of throttle, Rz position of brake and Y is their combined value. Un/ticking "combined pedals" in Control Panel doesn't seem to affect anything, wheel reports position of it's axes like this all the time.
JSCal reported the DFP as 4-axis device even when it wasn't in native mode, which would suggest that it reports it's axes position in the same format no matter what mode it's set to. However, only X and Y axes generated some input.
The windows driver seems to do some trickery to hide Z and Rz axes then "combined pedals" is ticked and there is no way to do that on Linux without some kernelspace-userspace interaction. That's the source of my concern.
Hmm, this correlates with my observation of G25. I tried to analyze what happens when you switch the pedals from combined to separate in the logitech software, but i could not see any specific USB traffic. So this also seems to be a "software-only" switch in the Logitech driver, not in the actual device.
It might be that DFP doesn't report changes of Z and Rz axes unless it's in the native mode and the missing kernel quirk just prevented me from testing it.

BTW, during reverse-engineering the formula for ranges<200 I noticed something peculiar. Windows driver seems to send both the G2x-type and the DFP-type command to set range (haven't noticed it before, no idea why). Can you confirm that? It leads me to the idea of multiple DFP versions with different firmware, one that accepts the "old" command and a newer one accepting the G2x-type command. Although it might be just some mess in the drivers, I can't tell...
I've been poking around this issue a bit and I think I know what's going on. I suggest looking at drivers/hid/hid-input.c, the "hidinput_configure_usage" function. I suspect that DFP doesn't report it's axes correctly so some kernel quirk is required to get it working.
Yep, this did not let me go to sleep :-) Accessign the hidraw interface i can get the seperate values from the DFP:

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>

#define BYTETOBINARYPATTERN "%d%d%d%d%d%d%d%d"
#define BYTETOBINARY(byte) \
(byte & 0x80 ? 1 : 0), \
(byte & 0x40 ? 1 : 0), \
(byte & 0x20 ? 1 : 0), \
(byte & 0x10 ? 1 : 0), \
(byte & 0x08 ? 1 : 0), \
(byte & 0x04 ? 1 : 0), \
(byte & 0x02 ? 1 : 0), \
(byte & 0x01 ? 1 : 0)

int main(int argc, char *argv[]) {
unsigned char buf[128];
int nr;

while ( (nr=read(0, buf, sizeof(buf))) ) {
if ( nr < 0 ) {
perror("read(stdin)");
exit(1);
}
printf (BYTETOBINARYPATTERN, BYTETOBINARY(buf[0]));
printf (" "BYTETOBINARYPATTERN" : ", BYTETOBINARY(buf[1]));
// Rotation is the first 14 bits, so we need to get 2 bytes
int ay = buf[1];
ay <<=8;
ay |= buf[0];
printf("wheelrotation: %4d ", ay);
// pedals are reported in bytes 4,5,6
printf("throttle: %03d ", buf[5]);
printf("brake: %03d ", buf[6]);
printf("combined: %03d ", buf[4]);

printf("unknown: %03d\n", buf[7]);
fflush(stdout);
}
return 0;
}

Usage (assuming compiled executable is named dfp_test):
sudo cat /dev/hidraw<number> | ./dfp_test

This data is basically derived from the HID descriptor provided by the DFP through /sys/kernel/debug/hid/<hid-device>/rdesc. There you can see that "offically" reported are only two axes, but additionally there are three more "anonymous" fields starting at byte 5.

Tomorrow i'll have a look at "hidinput_configure_usage", but for now its enough :-)
I came to pretty much the same conclusion, which made this part of "hidinput_configure_usage" particularly interesting:


case HID_UP_CUSTOM: /* Reported on Logitech and Apple USB keyboards */
/* Attempted workaround for DFP */
switch(usage->hid & HID_USAGE) {
case 0x00:
map_abs(HID_GD_Z & 0xf);
goto ignore;

case 0x02:
map_abs(HID_GD_RZ & 0xf);
goto ignore;
};

The switch case is my unsuccessful attempt to fix the problem. Perhaps trying to map ABS_Z or ABS_RZ instead might be worth a try. Anyway I guess this is a good place to continue from...
Quote from MikeB :I am waiting for the kernel 2.6.39 to be final, then i will provide a proper patch and cross fingers it gets integrated

i can arrange that if you like, you still will be credited

did anyone test that on any other wheel? i think this should generally be a good idea to add that flag to all logitech devices, which reconnect after initialisation.
Quote from MikeB :

{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_DFP_WHEEL),
.driver_data = LG_NOGET | LG_FF },

I am waiting for the kernel 2.6.39 to be final, then i will provide a proper patch and cross fingers it gets integrated

i can arrange that if you like (you still will be credited )

did anyone test that on any other wheel? i think this should generally be a good idea to add that flag to all logitech devices, which reconnect after initialisation.
Quote from slim.one :i can arrange that if you like (you still will be credited )

This would be great, i am currently so busy with work - I did not even install 2.6.39 yet So please go ahead - as i read the merge window will be somewhat shorter for the next linux version...

Quote from slim.one :did anyone test that on any other wheel? i think this should generally be a good idea to add that flag to all logitech devices, which reconnect after initialisation.

Hmm, at least the G25/G27 do not require this change. So i would rather not add this flag by default - Let's try to get some more enduser feedback
My brother has a Momo Force, i try to get some feedback from him...
Quote from MadCatX :To make matters rather interesting, I think I figured out the formula to construct range setting commands for DFP. According to my logs the Logitech driver always sends F8 03 (or F8 02 is the range to set is 200 deg or less) command followed by the command that specifies the range.

fwiw, i calculated a bit for myself and came up with:
x => (degrees - 5) / 7
byte3 => 128 - int(x)
byte4 => 128 + int(x)
byte6 => (x mod 1) × 7 × 30 + 14

now if someone could tell me that this isn't weird, please?

also, someone please verify that this actually works

edit: the value E0 for byte6 won't get calculated with this formula, dunno if thats a problem.
byte3 needs "byte3 = 127 - int(x)".
Also, is there a typo in the byte6, 'cause x mod 1 always returns 0.

But thanks a lot for trying a different approach. I can post some raw data for the range less than 200 deg, the algorithm appears to be a bit different and I haven't quite figured it out yet, so you're welcome to take look at it

EDIT: Gave it another thought and at least for 201-899 range the byte6 formula appears to be

int rem = (range - 5) mod 7;
if (rem == 6)
byte6 = 0xE0;
else
byte6 = rem * 30 + 14;

Quote from MadCatX :EDIT: Gave it another thought and at least for 201-899 range the byte6 formula appears to be

int rem = (range - 5) mod 7;
if (rem == 6)
byte6 = 0xE0;
else
byte6 = rem * 30 + 14;


jep, looks much less weird this way
In case somebody wants to knock himself out for a few hours, here's what I managed to figure out so far about ranges of 199 and less.

Bytes 3 and 4 are easy:

byte3 = (int)((200 - range) / 1.56);
byte4 = 255 - byte3;

The insanity begins with the 6th byte. As much as I've tried, there doesn't seem to by any clear and logical system to generate it's values. This mad algorithm produces correct values for byte 6 in range from 199 to 166, from 165 on it's wrong.

#include <stdio.h>
typedef unsigned char byte;

int main(int argc, char** argv) {
int rng, tmp;
byte b6 = 44;
byte alter = 90;
if(argc > 1)
rng = atoi(argv[1]);

int count = 199 - rng;
int shift = 0;
int steps = 0;
while(count > steps)
{
tmp = b6 + alter;
if(tmp == 314) {
b6 = 74;
} else if (tmp == 254 && ((steps % 2) == 0 || (steps % 5) == 0 || (steps % 7) == 1)) {
b6 = 14;
shift++;
} else if (tmp == 254 && (steps % 2) != 0) {
b6 = 74;
shift++;
} else if (tmp == 284 && (steps % 6) == 1) {
b6 = 14;
} else if (tmp == 284 && (((steps+1) % 11) == 0)) {
b6 = 44;
} else if (tmp == 104 && (shift == 2)) {
b6 = 74;
shift++;
} else if (tmp == 164 && shift == 4) {
b6 = 134;
shift = 0;
} else {
b6 = tmp;
}
steps++;
}

printf("%d %X %d %d\n", b6, b6, shift, steps);
}

I suppose you can use it to generate a sequence of numbers and try to figure out an universal formula.
btw, who would want to set a range value below 200 degrees anyway?
Sure, but figuring it out would be a nice ego booster Getting the separate axes working is much more important tho, any chance you might have or get some info as to how to map the custom fields in the HID descriptor to axes? My simple lame experiments turned out ineffective...
Quote from MadCatX :Sure, but figuring it out would be a nice ego booster Getting the separate axes working is much more important tho, any chance you might have or get some info as to how to map the custom fields in the HID descriptor to axes? My simple lame experiments turned out ineffective...

I'm currently playing around with rewriting the HID descriptor of the DFP to make the separate axes available "native" to the driver. In theory i read enough to know how it should work, in practice i hope to get first results tonight. I'll keep you posted
Fantastic, but do you think it's absolutely necessary to rewrite the descriptor? At least the custom field 4 (possibly throttle position?) is already there, I just don't know how to access it.
Anyway, I guess that if you eventually manage to do this, it'd be a good idea to remove the Y-axis from the descriptor, I can see it causing few problems if it's used along with the Thr/Brake axes.
BTW are there any recommended online materials worth reading regarding USB HID devices and Linux? Kernelnewbies aren't much of a help I'm afraid...
Quote from MadCatX :BTW are there any recommended online materials worth reading regarding USB HID devices and Linux? Kernelnewbies aren't much of a help I'm afraid...

if you find one, be sure to PM me
GOT IT

Please see attached patch for hid-lg.c driver - It replaces the HID descriptor for DFP in native mode:
  • remove combined Y-axis
  • Add Z and RZ axis for brake and throttle
Probably you have to remove the last few lines which add the NOGET flag as you already have this change on your codebase.

Funny enough i can not really test it with LFS atm as i did not yet bother to get nvidia driver with the new kernel and nouvea is not yet usable for any game

Please also try if all other buttons still work like expected - On my broken DFP only the shifter is working, the buttons on the wheel are dead...
Attached files
DFP.patch.txt - 5.8 KB - 294 views
Pure awesomeness, separate axes work perfectly. There are few minor issues though.
First, it's necessary to run jscal to get rid of the nasty deadzones, this command does the job for me

jscal -s 5,1,0,8176,8176,80730,80937,1,0,125,125,-4129650,-4294836,1,0,125,125,-4129650,-4294836,1,0,0,0,536854528,536854528,1,0,0,0,536854528,536854528 /dev/input/js0

I'm not sure if it can be used universally regardless to what's the wheel range set to, but it has to be run every time the wheel's settings is adjusted via LTWC.

A bit more serious issue is the lack of force feedback with the new HID descriptor. Not sure why that happens, I cannot see anything suspicious in the descriptor and dmesg informs me that the FF support is being used... weird
FF works fine when I leave my DFP in fallback mode...

Even though amazing job

LTWheelConf - Setup Logitech DFP/G25/G27 on linux
(269 posts, started )
FGED GREDG RDFGDR GSFDG