diff mbox

Fix autocentering command in hid-lgff driver

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

Commit Message

Michal Malý June 14, 2011, 8:42 p.m. UTC
Hello,

this patch fixes two issues with autocentering in lgff driver. Current implementation incorrectly assumes that the saturation force is always 0x80 which is 
inconsistent with behavior of the official driver. It also makes it impossible to disable autocentering on some wheels - at least Logitech Formula Force RX is 
the case. Values of stiffness coefficient were also calculated incorrectly. Formula used in this patch appears to generate the same commands as the official 
Logitech drivers. The patch also fixes two minor coding style issues.

Regards, Michal.


Signed-off-by: Michal Malý <madcatxster@gmail.com>
---
 drivers/hid/hid-lgff.c |   18 ++++++++++++------
 1 files changed, 12 insertions(+), 6 deletions(-)

Comments

simon@mungewell.org June 14, 2011, 9:20 p.m. UTC | #1
> Hello,
>
> this patch fixes two issues with autocentering in lgff driver. Current
> implementation incorrectly assumes that the saturation force is always
> 0x80 which is
> inconsistent with behavior of the official driver. It also makes it
> impossible to disable autocentering on some wheels - at least Logitech
> Formula Force RX is
> the case. Values of stiffness coefficient were also calculated
> incorrectly. Formula used in this patch appears to generate the same
> commands as the official
> Logitech drivers. The patch also fixes two minor coding style issues.

Hi Michal,
Can you elaborate more on the difference between stiffness and saturation?
And how these might work in the Linux FF system which only accounts a
single parameter.

On my reverse engineering of the Wii Wheel (1) I noticed that the
AutoCentre consisted of 3 variables, but did realise the precise details.
Perhaps I can factor in a similar adjustment....

BTW - I also discovered some other modes of feedback beyond AutoCentre and
CF which might be applicable to other Logitech wheels. (2)

Simon

1.
http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=blob;f=drivers/hid/hid-lg4ff.c;h=fa550c8e1d1bc639bd3e9c34a299903391bca44a;hb=3a2289a4a317e0290a8bc7af28c62c9830cb12e5#l72

2. http://wiibrew.org/wiki/Logitech_USB_steering_wheel

--
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
Michal Malý June 14, 2011, 10:26 p.m. UTC | #2
On Tuesday 14 of June 2011 17:20:52 you wrote:
> > Hello,
> > 
> > this patch fixes two issues with autocentering in lgff driver. Current
> > implementation incorrectly assumes that the saturation force is always
> > 0x80 which is
> > inconsistent with behavior of the official driver. It also makes it
> > impossible to disable autocentering on some wheels - at least Logitech
> > Formula Force RX is
> > the case. Values of stiffness coefficient were also calculated
> > incorrectly. Formula used in this patch appears to generate the same
> > commands as the official
> > Logitech drivers. The patch also fixes two minor coding style issues.
> 
> Hi Michal,
> Can you elaborate more on the difference between stiffness and saturation?
> And how these might work in the Linux FF system which only accounts a
> single parameter.
> 
> On my reverse engineering of the Wii Wheel (1) I noticed that the
> AutoCentre consisted of 3 variables, but did realise the precise details.
> Perhaps I can factor in a similar adjustment....
> 
> BTW - I also discovered some other modes of feedback beyond AutoCentre and
> CF which might be applicable to other Logitech wheels. (2)
> 
> Simon
> 
> 1.
> http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=blob;f=dr
> ivers/hid/hid-lg4ff.c;h=fa550c8e1d1bc639bd3e9c34a299903391bca44a;hb=3a2289a4
> a317e0290a8bc7af28c62c9830cb12e5#l72
> 
> 2. http://wiibrew.org/wiki/Logitech_USB_steering_wheel

Sure, but please don't take it like I have some inside knowledge of Logitech FF implementation. I've been given few bits of useful information, the rest I 
figured out from sniffed USB communication.

Centering force seems to be modeled as a spring effect. Force created by a spring can be calculated as "F = -k*x" where F = force, k = stiffness coefficient 
and x = deflection from centre. The higher the k is, the faster the centering force increases when the wheel is turned. Saturation force seems to be the limit 
centering force, so when kx > saturation_force => F = saturation_force.
Logitech driver has a slider which sets the centering force from 0 % to 150 % (it's actually from 0 % to 200 %, at least the values in the command suggest 
so) and both the stiffness coeff and saturation force increase gradually with the centering force according to the formula I provide in the patch, so just the 
magnitude value is enough. It looks like the stiffness coeff actually wraps around, because 0 = no stiffness, 7 = max stiffness, 8 = low stiffness, 15 = max 
stiffness. It'd be interesting to see if you can observe the same behavior on the Wii wheel.

As for the other FF effects, I guess these are things like "rumble" etc. I'm planning to look into it more when I'll have some extra free time.

Regards, Michal.
--
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
simon@mungewell.org June 14, 2011, 11:16 p.m. UTC | #3
>> 2. http://wiibrew.org/wiki/Logitech_USB_steering_wheel
>
> Sure, but please don't take it like I have some inside knowledge of
> Logitech FF implementation. I've been given few bits of useful
> information, the rest I figured out from sniffed USB communication.

Of course, we're all in the same boat of trying to figure it out. Our only
help is that Engineers are lazy and often reuse stuff they've done before.


> It looks like the stiffness coeff actually
> wraps around, because 0 = no stiffness, 7 = max stiffness, 8 = low
> stiffness, 15 = max
> stiffness. It'd be interesting to see if you can observe the same behavior
> on the Wii wheel.

Yes the Wii Wheel only does 0-7 and then loops too...

I actually meant to quantify the force produced and purchased a torque
meter, but its range wasn't low enough to be useful so I took it back. I
think I can do something with a 'luggage scale' pulling at a tangent to
the wheel so will give that a try.

My reverse engineer technique had a python-hid script so that I could
throw packets directly at the wheel to produce specific force setups. I
need to port this to python-libusb (as python-hid is dead), but that
should be relatively simple and can forward off list to anyone who wants a
copy.

>
> As for the other FF effects, I guess these are things like "rumble" etc.
> I'm planning to look into it more when I'll have some extra free time.

If you figure codes out, I'd love to try them against my Wheel. I did have
a PS3 Driving Force Wireless, but fried it's micro whilst I was hooking
the BusPirate up to it.

This would work under Windows and playback various effects in test mode as
you pushed buttons - if anybody can grab some USB logs of this I can
attempt to parse them for the codes....

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
Michal Malý June 15, 2011, 12:03 a.m. UTC | #4
On Tuesday 14 of June 2011 19:16:37 simon@mungewell.org wrote:
> My reverse engineer technique had a python-hid script so that I could
> throw packets directly at the wheel to produce specific force setups. I
> need to port this to python-libusb (as python-hid is dead), but that
> should be relatively simple and can forward off list to anyone who wants a
> copy.
>
You might want to check out Michael Bauer's LTWheelConf [1]. It's written in C so it's not the niftiest thing to use for 
playing around with the wheel, but adding support for the Wii wheel is a matter of 30 seconds. It uses libusb and I'm sure 
it can be easily modified to send whatever data you want to the wheel.

> This would work under Windows and playback various effects in test mode as
> you pushed buttons - if anybody can grab some USB logs of this I can
> attempt to parse them for the codes....
That's kind of my plan. I'll try to write some simple "effect generator" app using DirectInput and sniff the commands. By 
the way, I've been provided with the anti-center spring command description for my Driving Force Pro which I use to set 
the wheel's range. Is it accepted by the Wii wheel as well?

As I read the source of all lgff drivers, I wonder if all Logitech wheels shouldn't be handled in the lg4ff driver. I'm worried 
that further patching of lgff could break functionality with some older joysticks it's been originally meant to work with.

81 0B 19 E6 FF 4A FF:
 8* - set effect number 4, *1 - start effect command
 0B - effect type: spring
 19 - left hand ramp start (MSB)
 E6 - right hand ramp start (MSB)
 F* - RH stiffness (0xF:max), *F - LH stiffness (0xF:max)
 4* - RH ramp start (LSB) , LSbit is RH stiffness sign (0:+ 1:-)
 *A - LH ramp start (LSB), LSbit is LH stiffness sign (0:+ 1:-)
 FF - saturation level for spring force (0xFF = max)

In above example the wheel soft stops are set to
0x19A and 0xE64 or 410 and -412 where 0x7FF or 2047 corresponds to half a rotation range or 450 degrees. Therefore 
the wheel soft stops are set to +-360 degrees - the boundaries are calculated from the outsite.(410 / 2047 * 450)

(Description provided by lbondar, original can be found here [2])

[1] https://github.com/TripleSpeeder/LTWheelConf
[2] http://www.lfsforum.net/showthread.php?p=1603971#post1603971
--
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
Michal Malý June 15, 2011, 9:56 p.m. UTC | #5
After some followup discussion with Simon we figured that there might be a
better and more thorough solution. We'll submit the patch again when it's
ready.

Michal.
--
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
simon@mungewell.org June 27, 2011, 4:15 p.m. UTC | #6
Hi Guys,
Just to summerise the situation as I see it, and try to get a feel where
we should/could go.

Michael B. has figured out all of the 'compatible->native' commands, which
cause the wheels to renegoiate their USB ID's and have extended features
(up to 900' turn) to made available.

Michal M. wrote up a little C script to exercise the various effects that
we have found (FF_AUTOCENTER, FF_CONSTANT, FF_SPRING, FF_FRICTION,
FF_INTERIA). I had to modify this a little to work with the Wii wheel and
haven't had confirmation that it still works with the other wheels.

I think that we need to build a list/matrix and confirm that _all_ wheels
are OK with a single set of commands (autocenter for the FX excluded).


I think that the way forward is to move all of the wheels to 'lg4ff' and
change that for a more complete FF support. I suggest that we drop the
link to 'ff-memless' and implement our own system to register effects into
1 of the 4 available slots as they are requested.

'lg4ff' could also take on the role of managing the switch between
'compat->native' as it should know the range (<200' or >200') for
correctly setting the spring location.

A resent patch (https://patchwork.kernel.org/patch/921052/) for the
WiiMote gives a good example how to implement '/sys/' files and we could
use these to control the wheel's modes, such as:

/sys/bus/hid/drivers/lg4ff/<dev>/native - write 1 to switch to native,
read to get current state
/sys/bus/hid/drivers/lg4ff/<dev>/range - write angular range, read to get
current range

(rampspeed, autocenter, gain should be handled within FF framework)

Q. Do we need the ability to switch between split/combined pedals?


I think that all of the above is relatively simple to implement and can't
see that it would cause any existing users a problem. So what do you guys
think?

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
Michal Malý June 27, 2011, 8:58 p.m. UTC | #7
> I think that we need to build a list/matrix and confirm that _all_ wheels
> are OK with a single set of commands (autocenter for the FX excluded).
I've tested your modded script and it worked fine with DFP. Peter who asked to be CC'ed too (I added him to CC) tried it 
out in G27 and reported that all was OK.

> I think that the way forward is to move all of the wheels to 'lg4ff' and
> change that for a more complete FF support. I suggest that we drop the
> link to 'ff-memless' and implement our own system to register effects into
> 1 of the 4 available slots as they are requested.
I have mixed feelings about dropping ff-memless. Currently the ff-memless driver does all the dirty job for us, it also does 
some simple maths like calculating X and Y force strength for FF_CONSTANT effect so we'd be duplicating code here.
On the other hand there are Logitech-specific features that ff-memless can't possibly handle like the effect reset, range 
setting, even the leds on G27 are controlled by some sort of custom FF command. Can you foreshadow how we could 
drop the ff-memless without creating any unnecessary mess in the force feedback stack?

> 'lg4ff' could also take on the role of managing the switch between
> 'compat->native' as it should know the range (<200' or >200') for
> correctly setting the spring location.
> 
> A resent patch (https://patchwork.kernel.org/patch/921052/) for the
> WiiMote gives a good example how to implement '/sys/' files and we could
> use these to control the wheel's modes, such as:
> 
> /sys/bus/hid/drivers/lg4ff/<dev>/native - write 1 to switch to native,
> read to get current state
> /sys/bus/hid/drivers/lg4ff/<dev>/range - write angular range, read to get
> current range
> Q. Do we need the ability to switch between split/combined pedals?
> 
I guess I answered that above, I'd absolutely love to get this into the kernel. Using /sys sounds like the best way to me. 
There are two issues I can think of. First wheels actually simulate reconnect when they're switched to the native mode, 
so I guess we'd have to be careful and not cause any memory leaks and stuff. Second all Logitech wheels short of 
G25/27 need a replaced HID descriptor to get separate pedals working, so unless there's a reasonable way how to read 
the anonymous fields reported in the original descriptor, I say keep the pedals always separate for now.

To sum it up, I think we have a plan.

Michal
--
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
Michael Bauer June 29, 2011, 9:28 a.m. UTC | #8
Am 27.06.2011 22:58, schrieb Michal Malý:
>> I think that we need to build a list/matrix and confirm that _all_ wheels
>> are OK with a single set of commands (autocenter for the FX excluded).
> I've tested your modded script and it worked fine with DFP. Peter who asked to be CC'ed too (I added him to CC) tried it
> out in G27 and reported that all was OK.
DFP, G25 and Momo Racing also worked fine on my side.

>> A resent patch (https://patchwork.kernel.org/patch/921052/) for the
>> WiiMote gives a good example how to implement '/sys/' files and we could
>> use these to control the wheel's modes, such as:
>>
>> /sys/bus/hid/drivers/lg4ff/<dev>/native - write 1 to switch to native,
>> read to get current state
>> /sys/bus/hid/drivers/lg4ff/<dev>/range - write angular range, read to get
>> current range
Yes, i also vote for something like this. Just keep in mind that we 
still need to find a reliable way to identify exactly the correct wheel, 
as they all register initially with the same VID/PID but need different 
commands for native mode and range.
This might be possible using the revision number - I am trying to get 
this implemented in ltwheelconf soon to have some more users test if it 
works.

>> Q. Do we need the ability to switch between split/combined pedals?
I am not sure on this - on the one hand i would love to provide all 
options to the user.
On the other hand i am not sure how this could be done. I do not think 
it is possible to change the report descriptor of a connected device on 
the fly without (not necessarily physically) reconnecting it?
And from my understanding the combined axes are just some kind of legacy 
stuff to support really old games which can not handle the separate axes.
So from my opinion we should at least initially just provide separate 
axes and don't try to implement complicated stuff to allow switching to 
combined mode.

> I guess I answered that above, I'd absolutely love to get this into the kernel. Using /sys sounds like the best way to me.
> There are two issues I can think of. First wheels actually simulate reconnect when they're switched to the native mode,
> so I guess we'd have to be careful and not cause any memory leaks and stuff. Second all Logitech wheels short of
> G25/27 need a replaced HID descriptor to get separate pedals working, so unless there's a reasonable way how to read
> the anonymous fields reported in the original descriptor, I say keep the pedals always separate for now.
I agree as stated above :-)

Best regards
Michael
--
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
Michael Bauer June 29, 2011, 3:23 p.m. UTC | #9
Hi,

another small note:
>>> /sys/bus/hid/drivers/lg4ff/<dev>/native - write 1 to switch to native,
>>> read to get current state
Is there any reason the switch to native mode should not be done 
automatically by the driver? I would prefer to have it working 
out-of-the-box instead of having to wait for userspace interaction. 
(This could be done by some udev rule(s), but then this would need to be 
adopted by all distributions...)

I do not see any point in using the wheel in restricted mode when native 
mode is possible...

Best regards
Michael

> --
> 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

--
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
simon@mungewell.org June 29, 2011, 3:50 p.m. UTC | #10
>>> Q. Do we need the ability to switch between split/combined pedals?

> I am not sure on this - on the one hand i would love to provide all
> options to the user.

> On the other hand i am not sure how this could be done. I do not think
> it is possible to change the report descriptor of a connected device on
> the fly without (not necessarily physically) reconnecting it?

> And from my understanding the combined axes are just some kind of legacy
> stuff to support really old games which can not handle the separate axes.

Can you (someone?) clarify which wheels do not have a command to switch
into 'native mode' (which causes a USB ID change) and do these wheels use
a unified brake/acc.?

Do any wheels have a 'native mode' which stay with the generic USB ID?

Wouldn't the device descriptor only be re-written for the new USB ID's in
'native' mode.

Note: The Wii wheel does not have a 'native' command/mode, but has a
unique ID which is always used.


> Is there any reason the switch to native mode should not be done
> automatically by the driver? I would prefer to have it working
> out-of-the-box instead of having to wait for userspace interaction.
> (This could be done by some udev rule(s), but then this would need to be
> adopted by all distributions...)

> I do not see any point in using the wheel in restricted mode when native
> mode is possible...

If we force the 'native command' to be issued then we might affect/prevent
any 'old game' play.

Note 2: At present the re-writing of descriptor is done in 'hid-lg.c'
(based on USB ID), whereas we are proposing the 'native' command to be
issued by 'hid-lg4ff.c' which might not be complied/enabled.

Perhaps disabling/blacklisting 'hid-lg4ff' is a sufficient workaround to
get older games working... or a module option of 'no-native' could prevent
the command being sent.



Also I noticed that the second part of the 'DFP native command', is very
similar to a strong spring set to slot 4....

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
Michal Malý June 29, 2011, 9:37 p.m. UTC | #11
> Can you (someone?) clarify which wheels do not have a command to switch
> into 'native mode' (which causes a USB ID change) and do these wheels use
> a unified brake/acc.?
> Do any wheels have a 'native mode' which stay with the generic USB ID?
To my knowledge all wheels except original Driving Force and Formula Force 
have the fallback and native mode. Every Logitech wheel in fallback mode 
reports PID 0x294 which is the PID of the original Driving Force wheel. If 
DFP/G25/G27/DFGT receives specific command, it simulates reconnect and reports 
its "real" PID upon reconnection. 

> Wouldn't the device descriptor only be re-written for the new USB ID's in
> 'native' mode.
DF/DFP/FEX hides the separate throttle and brake axes in the original 
descriptor so we definitely need to replace it. G25/27 don't need such a hack, 
I don't know how about DFGT or Momo, I'll try to find that out.
IMHO we need to replace the descriptor only if the wheel has PID 0x294 and is 
either DF or FEX. DFP has PID 0x298 and needs a fixed descriptor too.

> If we force the 'native command' to be issued then we might affect/prevent
> any 'old game' play.
Problem is that not all wheels actually have the native mode as I mentioned 
above, but all support separate pedal axes. Unless we somehow read the 
anonymous fields reported by the original descriptor, I guess we'll have to 
decide whether to have separate or combined pedal axes.
Another (rather hackish) way around this would be a "combined" value in /sys 
interface. When set to 1, we'd trigger reconnection (can we do that?) and not 
replace the descriptor (or replace it in case of G25/27).


I've given some thought bypassing the ff-memless driver and I don't think it's 
necessary. We can patch ff-memless and add support for the missing effects. I 
guess that passing the device-specific commands like effect reset, G27 leds and 
range setting could be done via /sys interface too.
However that's just a thought...

Michal
--
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-lgff.c b/drivers/hid/hid-lgff.c
index 088f850..3d30a8e 100644
--- a/drivers/hid/hid-lgff.c
+++ b/drivers/hid/hid-lgff.c
@@ -129,18 +129,24 @@  static void hid_lgff_set_autocenter(struct input_dev *dev, u16 magnitude)
 	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;
+	u8 saturation_force = magnitude >> 8;
+	u8 stiffness_coeff;
+	if (magnitude <= 32768)
+		stiffness_coeff = saturation_force / 10;
+	else
+		stiffness_coeff = (saturation_force / 62) + 11;
+
 	*value++ = 0xfe;
 	*value++ = 0x0d;
-	*value++ = magnitude;   /* clockwise strength */
-	*value++ = magnitude;   /* counter-clockwise strength */
-	*value++ = 0x80;
+	*value++ = stiffness_coeff;   /* clockwise strength */
+	*value++ = stiffness_coeff;   /* counter-clockwise strength */
+	*value++ = saturation_force;
 	*value++ = 0x00;
 	*value = 0x00;
 	usbhid_submit_report(hid, report, USB_DIR_OUT);
 }
 
-int lgff_init(struct hid_device* hid)
+int lgff_init(struct hid_device *hid)
 {
 	struct hid_input *hidinput = list_entry(hid->inputs.next, struct hid_input, list);
 	struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list;
@@ -180,7 +186,7 @@  int lgff_init(struct hid_device* hid)
 	if (error)
 		return error;
 
-	if ( test_bit(FF_AUTOCENTER, dev->ffbit) )
+	if (test_bit(FF_AUTOCENTER, dev->ffbit))
 		dev->ff->set_autocenter = hid_lgff_set_autocenter;
 
 	pr_info("Force feedback for Logitech force feedback devices by Johann Deneux <johann.deneux@it.uu.se>\n");