
config [COLOR="red"]LOGIWHEELS_FF [/COLOR] 
    bool "Logitech force feedback support"  
    depends on HID_LOGITECH  
    [COLOR="Red"]default y [/COLOR] 
    select INPUT_FF_MEMLESS  
    help  
      Say Y here if you have one of these devices:  
      -Logitech WingMan Cordless RumblePad  
      -Logitech WingMan Cordless RumblePad 2  
      -Logitech WingMan Force 3D  
      -Logitech Formula Force EX  
      -Logitech WingMan Formula Force GP  
      -Logitech MOMO Force wheel  
      and if you want to enable force feedback for them.
      Note: if you say N here, this device will still be supported, but without
        force feedbacklinux-dopx:/home/anisha/ # fftest /dev/input/event4
Force feedback test program.
HOLD FIRMLY YOUR WHEEL OR JOYSTICK TO PREVENT DAMAGES
Device /dev/input/event4 opened
Axes query: 
Effects: Constant 
Number of simultaneous effects: 16
Upload effects[0]: Invalid argument
Upload effects[2]: Invalid argument
Upload effects[3]: Invalid argument
Upload effects[4]: Invalid argument
Upload effects[5]: Invalid argument
Enter effect number, -1 to exit
1
Now Playing: Constant Force
Enter effect number, -1 to exit
linux-dopx:/home/anisha/tarBalls/TripleSpeeder-LTWheelConf-665e227 # [B]./ltwheelconf --wheel DFGT --nativemode --range 900 --autocenter 0 --gain=100 -d /dev/input/event4[/B]
Found a Driving Force GT already in native mode.
Wheel rotation range of Driving Force GT is now set to 900 degrees.
Autocenter for Driving Force GT is now set to 0 with rampspeed 0.
Wheel forcefeedback gain is now set to 100.
linux-dopx:/home/anisha # [B]fftest /dev/input/event4[/b]
Force feedback test program.
HOLD FIRMLY YOUR WHEEL OR JOYSTICK TO PREVENT DAMAGES
Device /dev/input/event4 opened
Axes query: 
Effects: 
Number of simultaneous effects: 0
[B]Upload effects[0]: Function not implemented
Upload effects[1]: Function not implemented
Upload effects[2]: Function not implemented
Upload effects[3]: Function not implemented
Upload effects[4]: Function not implemented
Upload effects[5]: Function not implemented[/B]
Enter effect number, -1 to exit
^C
linux-dopx:/home/anisha # [B]ffcfstress -d /dev/input/event4[/B]
ERROR: device (or driver) has no force feedback support [ffcfstress.c:165]linux-dopx:/home/anisha/# [B]ffcfstress -d /dev/input/js0 [/B]
ERROR: can not get key bits (Invalid argument) [ffcfstress.c:118]
#include "writeToJoystickDriver.h"
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <linux/input.h>
#define TRANSFER_WAIT_TIMEOUT_MS 5000
#define CONFIGURE_WAIT_SEC 3
#define UDEV_WAIT_SEC 2
int get_nativemode_cmd_DFGT (cmdstruct *c)
{
	c->cmds[0][0] = 0xf8;
	c->cmds[0][1] = 0x0a;
	c->cmds[0][2] = 0x00;
	c->cmds[0][3] = 0x00;
	c->cmds[0][4] = 0x00;
	c->cmds[0][5] = 0x00;
	c->cmds[0][6] = 0x00;
	c->cmds[0][7] = 0x00;
	c->cmds[1][0] = 0xf8;
	c->cmds[1][1] = 0x09;
	c->cmds[1][2] = 0x03;
	c->cmds[1][3] = 0x01;
	c->cmds[1][4] = 0x00;
	c->cmds[1][5] = 0x00;
	c->cmds[1][6] = 0x00;
	c->cmds[1][7] = 0x00;
	c->numCmds = 2;
	return 0;
}
/* used by DFGT, G25, G27 */
int get_range_cmd(cmdstruct *c, int range)
{
	c->cmds[0][0] = 0xf8;
	c->cmds[0][1] = 0x81;
	c->cmds[0][2] = range & 0x00ff;
	c->cmds[0][3] = (range & 0xff00)>>8;
	c->cmds[0][4] = 0x00;
	c->cmds[0][5] = 0x00;
	c->cmds[0][6] = 0x00;
	c->cmds[0][7] = 0x00;
	c->numCmds = 1;
	return 0;
}
/* used by all wheels */
int get_autocenter_cmd(cmdstruct *c, int centerforce, int rampspeed)
{
	c->cmds[0][0] = 0xfe;
	c->cmds[0][1] = 0x0d;
	c->cmds[0][2] = rampspeed & 0x0f;
	c->cmds[0][3] = rampspeed & 0x0f;
	c->cmds[0][4] = centerforce & 0xff;
	c->cmds[0][5] = 0x00;
	c->cmds[0][6] = 0x00;
	c->cmds[0][7] = 0x00;
	c->numCmds = 1;
	return 0;
}
void [COLOR="Red"][B]print_cmd[/B][/COLOR](char *result, unsigned char cmd[8]) {
	sprintf(result, "%02X %02X %02X %02X %02X %02X %02X %02X", cmd[0], cmd[1], cmd[2], cmd[3], cmd[4], cmd[5], cmd[6], cmd[7]);
}
int [B][COLOR="Red"]send_command[/COLOR][/B](libusb_device_handle *handle, cmdstruct command ) {
	if (command.numCmds == 0) {
		printf( "send_command: Empty command provided! Not sending anything...\n");
		return 0;
	}
	int stat;
	stat = libusb_detach_kernel_driver(handle, 0);
	if ((stat < 0 ))// || verbose_flag) 
			perror("Detach kernel driver");
	stat = libusb_claim_interface( handle, 0 );
	if ( (stat < 0))
		{ //|| verbose_flag) 
		perror("Claiming USB interface");
	}
	int transferred = 0;
	// send all command strings provided in command
	int cmdCount;
	for (cmdCount=0; cmdCount < command.numCmds; cmdCount++) {
		if (1){//verbose_flag) {
			char raw_string[255];
			print_cmd(raw_string, command.cmds[cmdCount]);
			printf("\tSending string:   \"%s\"\n", raw_string);
		}
		stat = libusb_interrupt_transfer( handle, 1, command.cmds[cmdCount], sizeof( command.cmds[cmdCount] ), &transferred, TRANSFER_WAIT_TIMEOUT_MS );
		/*if ( stat < 0) {
			//|| verbose_flag)
			perror("Sending USB command");
		}*/
		if ( stat < 0) perror("Sending USB command");
	}
	/* In case the command just sent caused the device to switch from restricted mode to native mode
	* the following two commands will fail due to invalid device handle (because the device changed
	* its pid on the USB bus).
	* So it is not possible anymore to release the interface and re-attach kernel driver.
	* I am not sure if this produces a memory leak within libusb, but i do not think there is another
	* solution possible...
	*/
	stat = libusb_release_interface(handle, 0 );
	if (stat != LIBUSB_ERROR_NO_DEVICE) { // silently ignore "No such device" error due to reasons explained above.
		if ( (stat < 0)){// || verbose_flag) {
			perror("Releasing USB interface.");
		}
	}
	stat = libusb_attach_kernel_driver( handle, 0);
	if (stat != LIBUSB_ERROR_NO_DEVICE) { // silently ignore "No such device" error due to reasons explained above.
		if ( (stat < 0)){// || verbose_flag) {
			perror("Reattaching kernel driver");
		}
	}
	return 0;
}
int [COLOR="Red"][B]set_native_mode[/B][/COLOR](wheelstruct* w)
{
	// first check if wheel has restriced/native mode at all
	if (w->native_pid == w->restricted_pid) {
		printf( "%s is always in native mode.\n", w->name);
		return 0;
	}
	// check if wheel is already in native mode
	libusb_device_handle *handle = libusb_open_device_with_vid_pid(NULL, VID_LOGITECH, w->native_pid);
	if ( handle != NULL ) {
		printf( "Found a %s already in native mode.\n", w->name);
		return 0;
	}
	// try to get handle to device in restricted mode
	handle = libusb_open_device_with_vid_pid(NULL, VID_LOGITECH, w->restricted_pid );
	if ( handle == NULL ) {
		printf( "Can not find %s in restricted mode (PID %x). This should not happen :-(\n", w->name, w->restricted_pid);
		return -1;
	}
	// check if we know how to set native mode
	if (!w->get_nativemode_cmd) {
		printf( "Sorry, do not know how to set %s into native mode.\n", w->name);
		return -1;
	}
	cmdstruct c;
	memset(&c, 0, sizeof(c));
	w->get_nativemode_cmd(&c);
	send_command(handle, c);
	// wait until wheel reconfigures to new PID...
	sleep(CONFIGURE_WAIT_SEC);
	// If above command was successfully we should now find the wheel in extended mode
	handle = libusb_open_device_with_vid_pid(NULL, VID_LOGITECH, w->native_pid);
	if ( handle != NULL ) {
		printf ( "%s is now set to native mode.\n", w->name);
	} else {
		// this should not happen, just in case
		printf ( "Unable to set %s to native mode.\n", w->name );
		return -1;
	}
	libusb_close(handle);
	return 0;
}
short unsigned int [B][COLOR="Red"]clamprange[/COLOR][/B](wheelstruct* w, short unsigned int range)
{
	if (range < w->min_rotation) {
		printf("Minimum range for %s is %d degrees.\n", w->name, w->min_rotation);
		range = w->min_rotation;
	}
	if (range > w->max_rotation) {
		range = w->max_rotation;
		printf("Maximum range for %s is %d degrees.\n", w->name, w->max_rotation);
	}
	return range;
}
int [COLOR="Red"][B]set_range[/B][/COLOR](wheelstruct* w, short unsigned int range)
{
	libusb_device_handle *handle = libusb_open_device_with_vid_pid(NULL, VID_LOGITECH, w->native_pid );
	if ( handle == NULL ) {
		printf ( "%s not found. Make sure it is set to native mode (use --native).\n", w->name);
		return -1;
	}
	if (!w->get_range_cmd) {
		printf( "Sorry, do not know how to set rotation range for %s.\n", w->name);
		return -1;
	}
	cmdstruct c;
	memset(&c, 0, sizeof(c));
	w->get_range_cmd(&c, range);
	send_command(handle, c);
	printf ("Wheel rotation range of %s is now set to %d degrees.\n", w->name, range);
	libusb_close(handle);
	return 0;
}
int [B][COLOR="Red"]set_autocenter[/COLOR][/B](wheelstruct* w, int centerforce, int rampspeed)
{
	libusb_device_handle *handle = libusb_open_device_with_vid_pid(NULL, VID_LOGITECH, w->native_pid );
	if ( handle == NULL ) {
		printf ( "%s not found. Make sure it is set to native mode (use --native).\n", w->name);
		return -1;
	}
	if (!w->get_autocenter_cmd) {
		printf( "Sorry, do not know how to set autocenter force for %s. Please try generic implementation using --alt_autocenter.\n", w->name);
		return -1;
	}
	cmdstruct c;
	memset(&c, 0, sizeof(c));
	w->get_autocenter_cmd(&c, centerforce, rampspeed);
	send_command(handle, c);
	printf ("Autocenter for %s is now set to %d with rampspeed %d.\n", w->name, centerforce, rampspeed);
	libusb_close(handle);
	return 0;
}
int main () {
	[B]while (1)[/B]
	{
		unsigned short int range = 0;
		unsigned short int centerforce = 0;	
		char device_file_name[128];
		char shortname[255];
		memset(device_file_name, 0, sizeof(device_file_name));
		range = 900;
		centerforce = 0;
		strncpy(shortname, "DFGT", 255);
		libusb_init(NULL);
		libusb_set_debug(0, 3);
		wheelstruct* wheel = 0;
		// do_validate_wheel
		int numWheels = sizeof(wheels)/sizeof(wheelstruct);
		int i = 0;
		for (i=0; i < numWheels; i++) {
			if (strncasecmp(wheels[i].shortname, shortname, 255) == 0) {
			// found matching wheel
			wheel = &(wheels[i]);
			break;
			}
		}
		if (!wheel) {
			printf("Wheel \"%s\" not supported. Did you spell the shortname correctly?\n", shortname);
		}
		
		/[COLOR="Red"][B]/ do_native
		set_native_mode(wheel);
		// do_range
		set_range(wheel, clamprange(wheel, range));
		// do_autocenter
		set_autocenter (wheel, centerforce, 0);[/B][/COLOR]
			
		libusb_exit(NULL);
	}
	return 0;
}
int send_command(libusb_device_handle *handle, cmdstruct command ) {
	if (command.numCmds == 0) {
		printf( "send_command: Empty command provided! Not sending anything...\n");
		return 0;
	}
	int stat;
	[COLOR="Red"][B]stat = libusb_detach_kernel_driver(handle, 0);
	if ((stat < 0 ))// || verbose_flag) 
			perror("Detach kernel driver");
	stat = libusb_claim_interface( handle, 0 );
	if ( (stat < 0))
		{ //|| verbose_flag) 
		perror("Claiming USB interface");
	}[/B][/COLOR]
	int transferred = 0;
	// send all command strings provided in command
	int cmdCount;
	for (cmdCount=0; cmdCount < command.numCmds; cmdCount++) {
		if (1){//verbose_flag) {
			char raw_string[255];
			print_cmd(raw_string, command.cmds[cmdCount]);
			printf("\tSending string:   \"%s\"\n", raw_string);
		}
		stat = libusb_interrupt_transfer( handle, 1, command.cmds[cmdCount], sizeof( command.cmds[cmdCount] ), &transferred, TRANSFER_WAIT_TIMEOUT_MS );
		/*if ( stat < 0) {
			//|| verbose_flag)
			perror("Sending USB command");
		}*/
		if ( stat < 0) perror("Sending USB command");
	}
	[COLOR="SeaGreen"]/* In case the command just sent caused the device to switch from restricted mode to native mode
	* the following two commands will fail due to invalid device handle (because the device changed
	* its pid on the USB bus).
	* So it is not possible anymore to release the interface and re-attach kernel driver.
	* I am not sure if this produces a memory leak within libusb, but i do not think there is another
	* solution possible...
	*/[/COLOR]
	s[COLOR="Red"][B]tat = libusb_release_interface(handle, 0 );
	if (stat != LIBUSB_ERROR_NO_DEVICE) { // silently ignore "No such device" error due to reasons explained above.
		if ( (stat < 0)){// || verbose_flag) {
			perror("Releasing USB interface.");
		}
	}
	stat = libusb_attach_kernel_driver( handle, 0);
	if (stat != LIBUSB_ERROR_NO_DEVICE) { // silently ignore "No such device" error due to reasons explained above.
		if ( (stat < 0)){// || verbose_flag) {
			perror("Reattaching kernel driver");
		}
	}[/B][/COLOR]
	return 0;
}
Driving Force GT not found. Make sure it is set to native mode (use --native).
libusb:error [sysfs_scan_device] open busnum failed, errno=24
libusb:error [sysfs_scan_device] open busnum failed, errno=24
Can not find Driving Force GT in restricted mode (PID c294). This should not happen :-(
linux-dopx:# [B]dmesg[/B]
[ 8996.971013] usb 2-2: new full speed USB device using uhci_hcd and address 18
[ 8997.128002] usb 2-2: New USB device found, idVendor=046d, idProduct=c294
[ 8997.128006] usb 2-2: New USB device strings: Mfr=0, Product=2, SerialNumber=0
[ 8997.128009] usb 2-2: Product: Driving Force GT
[ 8997.137710] input: Driving Force GT as /devices/pci0000:00/0000:00:1d.0/usb2/2-2/2-2:1.0/input/input49
[COLOR=Red][B]
[ 8997.137837] logitech 0003:046D:C294.0036: input,hidraw0: USB HID v1.00 Joystick [Driving Force GT] on usb-0000:00:1d.0-2/input0[/B][/COLOR]
[ 8997.137842] Force feedback for Logitech force feedback devices by Johann Deneux <[email protected]>
[ 9005.319352] logitech 0003:046D:C294.0037: parse failed
[ 9005.319370] logitech: probe of 0003:046D:C294.0037 failed with error -71
[ 9005.454042] usb 2-2: USB disconnect, address 18
[ 9005.764015] usb 2-2: new full speed USB device using uhci_hcd and address 19
[ 9005.919296] usb 2-2: New USB device found, idVendor=046d, idProduct=c29a
[ 9005.919300] usb 2-2: New USB device strings: Mfr=0, Product=2, SerialNumber=0
[ 9005.919303] usb 2-2: Product: Driving Force GT
[ 9005.939561] input: Driving Force GT as /devices/pci0000:00/0000:00:1d.0/usb2/2-2/2-2:1.0/input/input50
[ 9005.939728] generic-usb 0003:046D:C29A.0038: input,hidraw0: USB HID v1.11 Joystick [Driving Force GT] on usb-0000:00:1d.0-2/input0
[ 9008.340387] input: Driving Force GT as /devices/pci0000:00/0000:00:1d.0/usb2/2-2/2-2:1.0/input/input51
[ 9008.340521] generic-usb 0003:046D:C29A.0039: input,hidraw0: USB HID v1.11 Joystick [Driving Force GT] on usb-0000:00:1d.0-2/input0
[ 9008.361374] input: Driving Force GT as /devices/pci0000:00/0000:00:1d.0/usb2/2-2/2-2:1.0/input/input52
[ 9008.361486] generic-usb 0003:046D:C29A.003A: input,hidraw0: USB HID v1.11 Joystick [Driving Force GT] on usb-0000:00:1d.0-2/input0
[ 9015.454167] usb 2-2: USB disconnect, address 19
[ 9021.533142] usb 2-2: new full speed USB device using uhci_hcd and address 20
[ 9021.690125] usb 2-2: New USB device found, idVendor=046d, idProduct=c294
[ 9021.690130] usb 2-2: New USB device strings: Mfr=0, Product=2, SerialNumber=0
[ 9021.690133] usb 2-2: Product: Driving Force GT
[ 9021.700145] input: Driving Force GT as /devices/pci0000:00/0000:00:1d.0/usb2/2-2/2-2:1.0/input/input53
[ 9021.700358] logitech 0003:046D:C294.003B: input,hidraw0: USB HID v1.00 Joystick [Driving Force GT] on usb-0000:00:1d.0-2/input0
[ 9021.700363] Force feedback for Logitech force feedback devices by Johann Deneux <[email protected]>
[ 9021.734120] logitech 0003:046D:C294.003C: parse failed
[ 9021.734126] logitech: probe of 0003:046D:C294.003C failed with error -71
[ 9022.047049] usb 2-2: USB disconnect, address 20
[ 9022.253018] usb 2-2: new full speed USB device using uhci_hcd and address 21
[ 9022.408065] usb 2-2: New USB device found, idVendor=046d, idProduct=c29a
[ 9022.408069] usb 2-2: New USB device strings: Mfr=0, Product=2, SerialNumber=0
[ 9022.408072] usb 2-2: Product: Driving Force GT
[ 9022.425328] input: Driving Force GT as /devices/pci0000:00/0000:00:1d.0/usb2/2-2/2-2:1.0/input/input54
[ 9022.425445] generic-usb 0003:046D:C29A.003D: input,hidraw0: USB HID v1.11 Joystick [Driving Force GT] on usb-0000:00:1d.0-2/input0
[ 9024.755225] input: Driving Force GT as /devices/pci0000:00/0000:00:1d.0/usb2/2-2/2-2:1.0/input/input55
[ 9024.755386] generic-usb 0003:046D:C29A.003E: input,hidraw0: USB HID v1.11 Joystick [Driving Force GT] on usb-0000:00:1d.0-2/input0
[ 9024.774162] input: Driving Force GT as /devices/pci0000:00/0000:00:1d.0/usb2/2-2/2-2:1.0/input/input56
[ 9024.774294] generic-usb 0003:046D:C29A.003F: input,hidraw0: USB HID v1.11 Joystick [Driving Force GT] on usb-0000:00:1d.0-2/input0
linux-dopx:/home/anisha/Desktop/wheel/finalMerge # 
[ 9022.425445] generic-usb 0003:046D:C29A.003D: input,hidraw0: USB HID v1.11 Joystick [Driving Force GT] on usb-0000:00:1d.0-2/input0
[ 9024.755225] input: Driving Force GT as /devices/pci0000:00/0000:00:1d.0/usb2/2-2/2-2:1.0/input/input55
[ 9024.755386] generic-usb 0003:046D:C29A.003E: input,hidraw0: USB HID v1.11 Joystick [Driving Force GT] on usb-0000:00:1d.0-2/input0
[ 9024.774162] input: Driving Force GT as /devices/pci0000:00/0000:00:1d.0/usb2/2-2/2-2:1.0/input/input56
[ 9024.774294] generic-usb 0003:046D:C29A.003F: input,hidraw0: USB HID v1.11 Joystick [Driving Force GT] on usb-0000:00:1d.0-2/input0
 :mad:
if (argcc > 0)
            {
            libusb_init(NULL);
            //if (verbose_flag > 1)
                libusb_set_debug(0, 3);
            int wait_for_udev = 0;
            wheelstruct* wheel = 0;
            if (do_help) {
                help();
            } else {
                if (do_validate_wheel) {
                int numWheels = sizeof(wheels)/sizeof(wheelstruct);
                int i = 0;
                for (i=0; i < numWheels; i++) {
                    if (strncasecmp(wheels[i].shortname, shortname, 255) == 0) {
                        // found matching wheel
                    cout << "\nfound matching wheel";
                        wheel = &(wheels[i]);
                        break;
                    }
                }
                if (!wheel) {
                    printf("Wheel \"%s\" not supported. Did you spell the shortname correctly?\n", shortname);
                }
                }
          [B][COLOR=Red]      if (do_native) {
                if (!wheel) {
                    printf("Please provide --wheel parameter!\n");
                } else {
                    cout << "\nfound matching wheel 2";
                    set_native_mode(wheel);
                    wait_for_udev = 1;
                }
                }[/COLOR][/B]
                if (do_reset) {
                if (!wheel) {
                    printf("Please provide --wheel parameter!\n");
                } else {
                    int h = reset_wheel(wheel);
                    cout << "\nReset value: " << h;
                    wait_for_udev = 1;
                }
                }
                if (do_range) {
                if (!wheel) {
                    printf("Please provide --wheel parameter!\n");
                } else {
                    cout << "\nfound matching wheel 3";
                    set_range(wheel, clamprange(wheel, range));
                    wait_for_udev = 1;
                }
                }
                if (do_autocenter) {
                if (!wheel) {
                    printf("Please provide --wheel parameter!\n");
                } else {
                    if (centerforce == 0) {
                    cout << "\nfound matching wheel 4";
                        set_autocenter(wheel, centerforce, 0);
                        wait_for_udev = 1;
                    } else if (rampspeed == -1) {
                        printf("Please provide '--rampspeed' parameter\n");
                    } else {
                    cout << "\nfound matching wheel 5";
                        set_autocenter(wheel, centerforce, rampspeed);
                        wait_for_udev = 1;
                    }
                }
                }
            }
            libusb_exit(NULL);
            } else {
            // display usage information if no arguments given
            help();
            }
 I am currently on 2.6.34 kernel (64 bit) Suse 11.3.
struct [URL="http://rrlib.informatik.uni-kl.de/fileadmin/rrlib/docs/mca2-kl/html/mcal_general_ext/structjs__corr.html"]js_corr[/URL] {    __s32 [URL="http://rrlib.informatik.uni-kl.de/fileadmin/rrlib/docs/mca2-kl/html/mcal_general_ext/structjs__corr.html#a8de9942afd2e0a7c204637b1bcc06b81"]coef[/URL][8];    __s16 [URL="http://rrlib.informatik.uni-kl.de/fileadmin/rrlib/docs/mca2-kl/html/mcal_general_ext/structjs__corr.html#a98f99c7733f4569d9c990ec2d99d2d03"]prec[/URL];    __u16 [URL="http://rrlib.informatik.uni-kl.de/fileadmin/rrlib/docs/mca2-kl/html/mcal_general_ext/structjs__corr.html#a31ac1577e9b707e4537958f5d3f5e283"]type[/URL]; };