2 * Force feedback support for Logitech Gaming Wheels
4 * Including G27, G25, DFP, DFGT, FFEX, Momo, Momo2 &
5 * Speed Force Wireless (WiiWheel)
7 * Copyright (c) 2010 Simon Wood <simon@mungewell.org>
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
27 #include <linux/input.h>
28 #include <linux/usb.h>
29 #include <linux/hid.h>
31 #include "usbhid/usbhid.h"
35 #define DFGT_REV_MAJ 0x13
36 #define DFGT_REV_MIN 0x22
37 #define DFP_REV_MAJ 0x11
38 #define DFP_REV_MIN 0x06
39 #define FFEX_REV_MAJ 0x21
40 #define FFEX_REV_MIN 0x00
41 #define G25_REV_MAJ 0x12
42 #define G25_REV_MIN 0x22
43 #define G27_REV_MAJ 0x12
44 #define G27_REV_MIN 0x38
46 #define to_hid_device(pdev) container_of(pdev, struct hid_device, dev)
48 static void hid_lg4ff_set_range_dfp(struct hid_device
*hid
, u16 range
);
49 static void hid_lg4ff_set_range_g25(struct hid_device
*hid
, u16 range
);
50 static ssize_t
lg4ff_range_show(struct device
*dev
, struct device_attribute
*attr
, char *buf
);
51 static ssize_t
lg4ff_range_store(struct device
*dev
, struct device_attribute
*attr
, const char *buf
, size_t count
);
53 static DEVICE_ATTR(range
, S_IRWXU
| S_IRWXG
| S_IRWXO
, lg4ff_range_show
, lg4ff_range_store
);
55 struct lg4ff_device_entry
{
59 #ifdef CONFIG_LEDS_CLASS
61 struct led_classdev
*led
[5];
63 struct list_head list
;
64 void (*set_range
)(struct hid_device
*hid
, u16 range
);
67 static const signed short lg4ff_wheel_effects
[] = {
74 const __u32 product_id
;
75 const signed short *ff_effects
;
76 const __u16 min_range
;
77 const __u16 max_range
;
78 void (*set_range
)(struct hid_device
*hid
, u16 range
);
81 static const struct lg4ff_wheel lg4ff_devices
[] = {
82 {USB_DEVICE_ID_LOGITECH_WHEEL
, lg4ff_wheel_effects
, 40, 270, NULL
},
83 {USB_DEVICE_ID_LOGITECH_MOMO_WHEEL
, lg4ff_wheel_effects
, 40, 270, NULL
},
84 {USB_DEVICE_ID_LOGITECH_DFP_WHEEL
, lg4ff_wheel_effects
, 40, 900, hid_lg4ff_set_range_dfp
},
85 {USB_DEVICE_ID_LOGITECH_G25_WHEEL
, lg4ff_wheel_effects
, 40, 900, hid_lg4ff_set_range_g25
},
86 {USB_DEVICE_ID_LOGITECH_DFGT_WHEEL
, lg4ff_wheel_effects
, 40, 900, hid_lg4ff_set_range_g25
},
87 {USB_DEVICE_ID_LOGITECH_G27_WHEEL
, lg4ff_wheel_effects
, 40, 900, hid_lg4ff_set_range_g25
},
88 {USB_DEVICE_ID_LOGITECH_MOMO_WHEEL2
, lg4ff_wheel_effects
, 40, 270, NULL
},
89 {USB_DEVICE_ID_LOGITECH_WII_WHEEL
, lg4ff_wheel_effects
, 40, 270, NULL
}
92 struct lg4ff_native_cmd
{
93 const __u8 cmd_num
; /* Number of commands to send */
97 struct lg4ff_usb_revision
{
100 const struct lg4ff_native_cmd
*command
;
103 static const struct lg4ff_native_cmd native_dfp
= {
105 {0xf8, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00}
108 static const struct lg4ff_native_cmd native_dfgt
= {
110 {0xf8, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, /* 1st command */
111 0xf8, 0x09, 0x03, 0x01, 0x00, 0x00, 0x00} /* 2nd command */
114 static const struct lg4ff_native_cmd native_g25
= {
116 {0xf8, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00}
119 static const struct lg4ff_native_cmd native_g27
= {
121 {0xf8, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, /* 1st command */
122 0xf8, 0x09, 0x04, 0x01, 0x00, 0x00, 0x00} /* 2nd command */
125 static const struct lg4ff_usb_revision lg4ff_revs
[] = {
126 {DFGT_REV_MAJ
, DFGT_REV_MIN
, &native_dfgt
}, /* Driving Force GT */
127 {DFP_REV_MAJ
, DFP_REV_MIN
, &native_dfp
}, /* Driving Force Pro */
128 {G25_REV_MAJ
, G25_REV_MIN
, &native_g25
}, /* G25 */
129 {G27_REV_MAJ
, G27_REV_MIN
, &native_g27
}, /* G27 */
132 static int hid_lg4ff_play(struct input_dev
*dev
, void *data
, struct ff_effect
*effect
)
134 struct hid_device
*hid
= input_get_drvdata(dev
);
135 struct list_head
*report_list
= &hid
->report_enum
[HID_OUTPUT_REPORT
].report_list
;
136 struct hid_report
*report
= list_entry(report_list
->next
, struct hid_report
, list
);
139 #define CLAMP(x) if (x < 0) x = 0; if (x > 0xff) x = 0xff
141 switch (effect
->type
) {
143 x
= effect
->u
.ramp
.start_level
+ 0x80; /* 0x80 is no force */
145 report
->field
[0]->value
[0] = 0x11; /* Slot 1 */
146 report
->field
[0]->value
[1] = 0x08;
147 report
->field
[0]->value
[2] = x
;
148 report
->field
[0]->value
[3] = 0x80;
149 report
->field
[0]->value
[4] = 0x00;
150 report
->field
[0]->value
[5] = 0x00;
151 report
->field
[0]->value
[6] = 0x00;
153 usbhid_submit_report(hid
, report
, USB_DIR_OUT
);
159 /* Sends default autocentering command compatible with
160 * all wheels except Formula Force EX */
161 static void hid_lg4ff_set_autocenter_default(struct input_dev
*dev
, u16 magnitude
)
163 struct hid_device
*hid
= input_get_drvdata(dev
);
164 struct list_head
*report_list
= &hid
->report_enum
[HID_OUTPUT_REPORT
].report_list
;
165 struct hid_report
*report
= list_entry(report_list
->next
, struct hid_report
, list
);
167 report
->field
[0]->value
[0] = 0xfe;
168 report
->field
[0]->value
[1] = 0x0d;
169 report
->field
[0]->value
[2] = magnitude
>> 13;
170 report
->field
[0]->value
[3] = magnitude
>> 13;
171 report
->field
[0]->value
[4] = magnitude
>> 8;
172 report
->field
[0]->value
[5] = 0x00;
173 report
->field
[0]->value
[6] = 0x00;
175 usbhid_submit_report(hid
, report
, USB_DIR_OUT
);
178 /* Sends autocentering command compatible with Formula Force EX */
179 static void hid_lg4ff_set_autocenter_ffex(struct input_dev
*dev
, u16 magnitude
)
181 struct hid_device
*hid
= input_get_drvdata(dev
);
182 struct list_head
*report_list
= &hid
->report_enum
[HID_OUTPUT_REPORT
].report_list
;
183 struct hid_report
*report
= list_entry(report_list
->next
, struct hid_report
, list
);
184 magnitude
= magnitude
* 90 / 65535;
187 report
->field
[0]->value
[0] = 0xfe;
188 report
->field
[0]->value
[1] = 0x03;
189 report
->field
[0]->value
[2] = magnitude
>> 14;
190 report
->field
[0]->value
[3] = magnitude
>> 14;
191 report
->field
[0]->value
[4] = magnitude
;
192 report
->field
[0]->value
[5] = 0x00;
193 report
->field
[0]->value
[6] = 0x00;
195 usbhid_submit_report(hid
, report
, USB_DIR_OUT
);
198 /* Sends command to set range compatible with G25/G27/Driving Force GT */
199 static void hid_lg4ff_set_range_g25(struct hid_device
*hid
, u16 range
)
201 struct list_head
*report_list
= &hid
->report_enum
[HID_OUTPUT_REPORT
].report_list
;
202 struct hid_report
*report
= list_entry(report_list
->next
, struct hid_report
, list
);
203 dbg_hid("G25/G27/DFGT: setting range to %u\n", range
);
205 report
->field
[0]->value
[0] = 0xf8;
206 report
->field
[0]->value
[1] = 0x81;
207 report
->field
[0]->value
[2] = range
& 0x00ff;
208 report
->field
[0]->value
[3] = (range
& 0xff00) >> 8;
209 report
->field
[0]->value
[4] = 0x00;
210 report
->field
[0]->value
[5] = 0x00;
211 report
->field
[0]->value
[6] = 0x00;
213 usbhid_submit_report(hid
, report
, USB_DIR_OUT
);
216 /* Sends commands to set range compatible with Driving Force Pro wheel */
217 static void hid_lg4ff_set_range_dfp(struct hid_device
*hid
, __u16 range
)
219 struct list_head
*report_list
= &hid
->report_enum
[HID_OUTPUT_REPORT
].report_list
;
220 struct hid_report
*report
= list_entry(report_list
->next
, struct hid_report
, list
);
221 int start_left
, start_right
, full_range
;
222 dbg_hid("Driving Force Pro: setting range to %u\n", range
);
224 /* Prepare "coarse" limit command */
225 report
->field
[0]->value
[0] = 0xf8;
226 report
->field
[0]->value
[1] = 0x00; /* Set later */
227 report
->field
[0]->value
[2] = 0x00;
228 report
->field
[0]->value
[3] = 0x00;
229 report
->field
[0]->value
[4] = 0x00;
230 report
->field
[0]->value
[5] = 0x00;
231 report
->field
[0]->value
[6] = 0x00;
234 report
->field
[0]->value
[1] = 0x03;
237 report
->field
[0]->value
[1] = 0x02;
240 usbhid_submit_report(hid
, report
, USB_DIR_OUT
);
242 /* Prepare "fine" limit command */
243 report
->field
[0]->value
[0] = 0x81;
244 report
->field
[0]->value
[1] = 0x0b;
245 report
->field
[0]->value
[2] = 0x00;
246 report
->field
[0]->value
[3] = 0x00;
247 report
->field
[0]->value
[4] = 0x00;
248 report
->field
[0]->value
[5] = 0x00;
249 report
->field
[0]->value
[6] = 0x00;
251 if (range
== 200 || range
== 900) { /* Do not apply any fine limit */
252 usbhid_submit_report(hid
, report
, USB_DIR_OUT
);
256 /* Construct fine limit command */
257 start_left
= (((full_range
- range
+ 1) * 2047) / full_range
);
258 start_right
= 0xfff - start_left
;
260 report
->field
[0]->value
[2] = start_left
>> 4;
261 report
->field
[0]->value
[3] = start_right
>> 4;
262 report
->field
[0]->value
[4] = 0xff;
263 report
->field
[0]->value
[5] = (start_right
& 0xe) << 4 | (start_left
& 0xe);
264 report
->field
[0]->value
[6] = 0xff;
266 usbhid_submit_report(hid
, report
, USB_DIR_OUT
);
269 static void hid_lg4ff_switch_native(struct hid_device
*hid
, const struct lg4ff_native_cmd
*cmd
)
271 struct list_head
*report_list
= &hid
->report_enum
[HID_OUTPUT_REPORT
].report_list
;
272 struct hid_report
*report
= list_entry(report_list
->next
, struct hid_report
, list
);
276 while (j
< 7*cmd
->cmd_num
) {
277 for (i
= 0; i
< 7; i
++)
278 report
->field
[0]->value
[i
] = cmd
->cmd
[j
++];
280 usbhid_submit_report(hid
, report
, USB_DIR_OUT
);
284 /* Read current range and display it in terminal */
285 static ssize_t
lg4ff_range_show(struct device
*dev
, struct device_attribute
*attr
, char *buf
)
287 struct hid_device
*hid
= to_hid_device(dev
);
288 struct lg4ff_device_entry
*entry
;
289 struct lg_drv_data
*drv_data
;
292 drv_data
= hid_get_drvdata(hid
);
294 hid_err(hid
, "Private driver data not found!\n");
298 entry
= drv_data
->device_props
;
300 hid_err(hid
, "Device properties not found!\n");
304 count
= scnprintf(buf
, PAGE_SIZE
, "%u\n", entry
->range
);
308 /* Set range to user specified value, call appropriate function
309 * according to the type of the wheel */
310 static ssize_t
lg4ff_range_store(struct device
*dev
, struct device_attribute
*attr
, const char *buf
, size_t count
)
312 struct hid_device
*hid
= to_hid_device(dev
);
313 struct lg4ff_device_entry
*entry
;
314 struct lg_drv_data
*drv_data
;
315 __u16 range
= simple_strtoul(buf
, NULL
, 10);
317 drv_data
= hid_get_drvdata(hid
);
319 hid_err(hid
, "Private driver data not found!\n");
323 entry
= drv_data
->device_props
;
325 hid_err(hid
, "Device properties not found!\n");
330 range
= entry
->max_range
;
332 /* Check if the wheel supports range setting
333 * and that the range is within limits for the wheel */
334 if (entry
->set_range
!= NULL
&& range
>= entry
->min_range
&& range
<= entry
->max_range
) {
335 entry
->set_range(hid
, range
);
336 entry
->range
= range
;
342 #ifdef CONFIG_LEDS_CLASS
343 static void lg4ff_set_leds(struct hid_device
*hid
, __u8 leds
)
345 struct list_head
*report_list
= &hid
->report_enum
[HID_OUTPUT_REPORT
].report_list
;
346 struct hid_report
*report
= list_entry(report_list
->next
, struct hid_report
, list
);
348 report
->field
[0]->value
[0] = 0xf8;
349 report
->field
[0]->value
[1] = 0x12;
350 report
->field
[0]->value
[2] = leds
;
351 report
->field
[0]->value
[3] = 0x00;
352 report
->field
[0]->value
[4] = 0x00;
353 report
->field
[0]->value
[5] = 0x00;
354 report
->field
[0]->value
[6] = 0x00;
355 usbhid_submit_report(hid
, report
, USB_DIR_OUT
);
358 static void lg4ff_led_set_brightness(struct led_classdev
*led_cdev
,
359 enum led_brightness value
)
361 struct device
*dev
= led_cdev
->dev
->parent
;
362 struct hid_device
*hid
= container_of(dev
, struct hid_device
, dev
);
363 struct lg_drv_data
*drv_data
= (struct lg_drv_data
*)hid_get_drvdata(hid
);
364 struct lg4ff_device_entry
*entry
;
368 hid_err(hid
, "Device data not found.");
372 entry
= (struct lg4ff_device_entry
*)drv_data
->device_props
;
375 hid_err(hid
, "Device properties not found.");
379 for (i
= 0; i
< 5; i
++) {
380 if (led_cdev
!= entry
->led
[i
])
382 state
= (entry
->led_state
>> i
) & 1;
383 if (value
== LED_OFF
&& state
) {
384 entry
->led_state
&= ~(1 << i
);
385 lg4ff_set_leds(hid
, entry
->led_state
);
386 } else if (value
!= LED_OFF
&& !state
) {
387 entry
->led_state
|= 1 << i
;
388 lg4ff_set_leds(hid
, entry
->led_state
);
394 static enum led_brightness
lg4ff_led_get_brightness(struct led_classdev
*led_cdev
)
396 struct device
*dev
= led_cdev
->dev
->parent
;
397 struct hid_device
*hid
= container_of(dev
, struct hid_device
, dev
);
398 struct lg_drv_data
*drv_data
= (struct lg_drv_data
*)hid_get_drvdata(hid
);
399 struct lg4ff_device_entry
*entry
;
403 hid_err(hid
, "Device data not found.");
407 entry
= (struct lg4ff_device_entry
*)drv_data
->device_props
;
410 hid_err(hid
, "Device properties not found.");
414 for (i
= 0; i
< 5; i
++)
415 if (led_cdev
== entry
->led
[i
]) {
416 value
= (entry
->led_state
>> i
) & 1;
420 return value
? LED_FULL
: LED_OFF
;
424 int lg4ff_init(struct hid_device
*hid
)
426 struct hid_input
*hidinput
= list_entry(hid
->inputs
.next
, struct hid_input
, list
);
427 struct list_head
*report_list
= &hid
->report_enum
[HID_OUTPUT_REPORT
].report_list
;
428 struct input_dev
*dev
= hidinput
->input
;
429 struct hid_report
*report
;
430 struct hid_field
*field
;
431 struct lg4ff_device_entry
*entry
;
432 struct lg_drv_data
*drv_data
;
433 struct usb_device_descriptor
*udesc
;
435 __u16 bcdDevice
, rev_maj
, rev_min
;
437 /* Find the report to use */
438 if (list_empty(report_list
)) {
439 hid_err(hid
, "No output report found\n");
443 /* Check that the report looks ok */
444 report
= list_entry(report_list
->next
, struct hid_report
, list
);
446 hid_err(hid
, "NULL output report\n");
450 field
= report
->field
[0];
452 hid_err(hid
, "NULL field\n");
456 /* Check what wheel has been connected */
457 for (i
= 0; i
< ARRAY_SIZE(lg4ff_devices
); i
++) {
458 if (hid
->product
== lg4ff_devices
[i
].product_id
) {
459 dbg_hid("Found compatible device, product ID %04X\n", lg4ff_devices
[i
].product_id
);
464 if (i
== ARRAY_SIZE(lg4ff_devices
)) {
465 hid_err(hid
, "Device is not supported by lg4ff driver. If you think it should be, consider reporting a bug to"
466 "LKML, Simon Wood <simon@mungewell.org> or Michal Maly <madcatxster@gmail.com>\n");
470 /* Attempt to switch wheel to native mode when applicable */
471 udesc
= &(hid_to_usb_dev(hid
)->descriptor
);
473 hid_err(hid
, "NULL USB device descriptor\n");
476 bcdDevice
= le16_to_cpu(udesc
->bcdDevice
);
477 rev_maj
= bcdDevice
>> 8;
478 rev_min
= bcdDevice
& 0xff;
480 if (lg4ff_devices
[i
].product_id
== USB_DEVICE_ID_LOGITECH_WHEEL
) {
481 dbg_hid("Generic wheel detected, can it do native?\n");
482 dbg_hid("USB revision: %2x.%02x\n", rev_maj
, rev_min
);
484 for (j
= 0; j
< ARRAY_SIZE(lg4ff_revs
); j
++) {
485 if (lg4ff_revs
[j
].rev_maj
== rev_maj
&& lg4ff_revs
[j
].rev_min
== rev_min
) {
486 hid_lg4ff_switch_native(hid
, lg4ff_revs
[j
].command
);
487 hid_info(hid
, "Switched to native mode\n");
492 /* Set supported force feedback capabilities */
493 for (j
= 0; lg4ff_devices
[i
].ff_effects
[j
] >= 0; j
++)
494 set_bit(lg4ff_devices
[i
].ff_effects
[j
], dev
->ffbit
);
496 error
= input_ff_create_memless(dev
, NULL
, hid_lg4ff_play
);
501 /* Check if autocentering is available and
502 * set the centering force to zero by default */
503 if (test_bit(FF_AUTOCENTER
, dev
->ffbit
)) {
504 if(rev_maj
== FFEX_REV_MAJ
&& rev_min
== FFEX_REV_MIN
) /* Formula Force EX expects different autocentering command */
505 dev
->ff
->set_autocenter
= hid_lg4ff_set_autocenter_ffex
;
507 dev
->ff
->set_autocenter
= hid_lg4ff_set_autocenter_default
;
509 dev
->ff
->set_autocenter(dev
, 0);
512 /* Get private driver data */
513 drv_data
= hid_get_drvdata(hid
);
515 hid_err(hid
, "Cannot add device, private driver data not allocated\n");
519 /* Initialize device properties */
520 entry
= kzalloc(sizeof(struct lg4ff_device_entry
), GFP_KERNEL
);
522 hid_err(hid
, "Cannot add device, insufficient memory to allocate device properties.\n");
525 drv_data
->device_props
= entry
;
527 entry
->min_range
= lg4ff_devices
[i
].min_range
;
528 entry
->max_range
= lg4ff_devices
[i
].max_range
;
529 entry
->set_range
= lg4ff_devices
[i
].set_range
;
531 /* Create sysfs interface */
532 error
= device_create_file(&hid
->dev
, &dev_attr_range
);
535 dbg_hid("sysfs interface created\n");
537 /* Set the maximum range to start with */
538 entry
->range
= entry
->max_range
;
539 if (entry
->set_range
!= NULL
)
540 entry
->set_range(hid
, entry
->range
);
542 #ifdef CONFIG_LEDS_CLASS
543 /* register led subsystem - G27 only */
544 entry
->led_state
= 0;
545 for (j
= 0; j
< 5; j
++)
546 entry
->led
[j
] = NULL
;
548 if (lg4ff_devices
[i
].product_id
== USB_DEVICE_ID_LOGITECH_G27_WHEEL
) {
549 struct led_classdev
*led
;
553 lg4ff_set_leds(hid
, 0);
555 name_sz
= strlen(dev_name(&hid
->dev
)) + 8;
557 for (j
= 0; j
< 5; j
++) {
558 led
= kzalloc(sizeof(struct led_classdev
)+name_sz
, GFP_KERNEL
);
560 hid_err(hid
, "can't allocate memory for LED %d\n", j
);
564 name
= (void *)(&led
[1]);
565 snprintf(name
, name_sz
, "%s::RPM%d", dev_name(&hid
->dev
), j
+1);
568 led
->max_brightness
= 1;
569 led
->brightness_get
= lg4ff_led_get_brightness
;
570 led
->brightness_set
= lg4ff_led_set_brightness
;
573 error
= led_classdev_register(&hid
->dev
, led
);
576 hid_err(hid
, "failed to register LED %d. Aborting.\n", j
);
578 /* Deregister LEDs (if any) */
579 for (j
= 0; j
< 5; j
++) {
581 entry
->led
[j
] = NULL
;
584 led_classdev_unregister(led
);
587 goto out
; /* Let the driver continue without LEDs */
593 hid_info(hid
, "Force feedback support for Logitech Gaming Wheels\n");
597 int lg4ff_deinit(struct hid_device
*hid
)
599 struct lg4ff_device_entry
*entry
;
600 struct lg_drv_data
*drv_data
;
602 device_remove_file(&hid
->dev
, &dev_attr_range
);
604 drv_data
= hid_get_drvdata(hid
);
606 hid_err(hid
, "Error while deinitializing device, no private driver data.\n");
609 entry
= drv_data
->device_props
;
611 hid_err(hid
, "Error while deinitializing device, no device properties data.\n");
615 #ifdef CONFIG_LEDS_CLASS
618 struct led_classdev
*led
;
620 /* Deregister LEDs (if any) */
621 for (j
= 0; j
< 5; j
++) {
624 entry
->led
[j
] = NULL
;
627 led_classdev_unregister(led
);
633 /* Deallocate memory */
636 dbg_hid("Device successfully unregistered\n");