2 * Force feedback support for Logitech Speed Force Wireless
4 * http://wiibrew.org/wiki/Logitech_USB_steering_wheel
6 * Copyright (c) 2010 Simon Wood <simon@mungewell.org>
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
26 #include <linux/input.h>
27 #include <linux/usb.h>
28 #include <linux/hid.h>
30 #include "usbhid/usbhid.h"
34 #define DFGT_REV_MAJ 0x13
35 #define DFGT_REV_MIN 0x22
36 #define DFP_REV_MAJ 0x11
37 #define DFP_REV_MIN 0x06
38 #define FFEX_REV_MAJ 0x21
39 #define FFEX_REV_MIN 0x00
40 #define G25_REV_MAJ 0x12
41 #define G25_REV_MIN 0x22
42 #define G27_REV_MAJ 0x12
43 #define G27_REV_MIN 0x38
45 #define to_hid_device(pdev) container_of(pdev, struct hid_device, dev)
47 static void hid_lg4ff_set_range_dfp(struct hid_device
*hid
, u16 range
);
48 static void hid_lg4ff_set_range_g25(struct hid_device
*hid
, u16 range
);
49 static ssize_t
lg4ff_range_show(struct device
*dev
, struct device_attribute
*attr
, char *buf
);
50 static ssize_t
lg4ff_range_store(struct device
*dev
, struct device_attribute
*attr
, const char *buf
, size_t count
);
52 static DEVICE_ATTR(range
, S_IRWXU
| S_IRWXG
| S_IRWXO
, lg4ff_range_show
, lg4ff_range_store
);
54 static bool list_inited
;
56 struct lg4ff_device_entry
{
57 char *device_id
; /* Use name in respective kobject structure's address as the ID */
62 struct list_head list
;
63 void (*set_range
)(struct hid_device
*hid
, u16 range
);
66 static struct lg4ff_device_entry device_list
;
68 static const signed short lg4ff_wheel_effects
[] = {
75 const __u32 product_id
;
76 const signed short *ff_effects
;
77 const __u16 min_range
;
78 const __u16 max_range
;
79 void (*set_range
)(struct hid_device
*hid
, u16 range
);
82 static const struct lg4ff_wheel lg4ff_devices
[] = {
83 {USB_DEVICE_ID_LOGITECH_WHEEL
, lg4ff_wheel_effects
, 40, 270, NULL
},
84 {USB_DEVICE_ID_LOGITECH_MOMO_WHEEL
, lg4ff_wheel_effects
, 40, 270, NULL
},
85 {USB_DEVICE_ID_LOGITECH_DFP_WHEEL
, lg4ff_wheel_effects
, 40, 900, hid_lg4ff_set_range_dfp
},
86 {USB_DEVICE_ID_LOGITECH_G25_WHEEL
, lg4ff_wheel_effects
, 40, 900, hid_lg4ff_set_range_g25
},
87 {USB_DEVICE_ID_LOGITECH_DFGT_WHEEL
, lg4ff_wheel_effects
, 40, 900, hid_lg4ff_set_range_g25
},
88 {USB_DEVICE_ID_LOGITECH_G27_WHEEL
, lg4ff_wheel_effects
, 40, 900, hid_lg4ff_set_range_g25
},
89 {USB_DEVICE_ID_LOGITECH_MOMO_WHEEL2
, lg4ff_wheel_effects
, 40, 270, NULL
},
90 {USB_DEVICE_ID_LOGITECH_WII_WHEEL
, lg4ff_wheel_effects
, 40, 270, NULL
}
93 struct lg4ff_native_cmd
{
94 const __u8 cmd_num
; /* Number of commands to send */
98 struct lg4ff_usb_revision
{
101 const struct lg4ff_native_cmd
*command
;
104 static const struct lg4ff_native_cmd native_dfp
= {
106 {0xf8, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00}
109 static const struct lg4ff_native_cmd native_dfgt
= {
111 {0xf8, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, /* 1st command */
112 0xf8, 0x09, 0x03, 0x01, 0x00, 0x00, 0x00} /* 2nd command */
115 static const struct lg4ff_native_cmd native_g25
= {
117 {0xf8, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00}
120 static const struct lg4ff_native_cmd native_g27
= {
122 {0xf8, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, /* 1st command */
123 0xf8, 0x09, 0x04, 0x01, 0x00, 0x00, 0x00} /* 2nd command */
126 static const struct lg4ff_usb_revision lg4ff_revs
[] = {
127 {DFGT_REV_MAJ
, DFGT_REV_MIN
, &native_dfgt
}, /* Driving Force GT */
128 {DFP_REV_MAJ
, DFP_REV_MIN
, &native_dfp
}, /* Driving Force Pro */
129 {G25_REV_MAJ
, G25_REV_MIN
, &native_g25
}, /* G25 */
130 {G27_REV_MAJ
, G27_REV_MIN
, &native_g27
}, /* G27 */
133 static int hid_lg4ff_play(struct input_dev
*dev
, void *data
, struct ff_effect
*effect
)
135 struct hid_device
*hid
= input_get_drvdata(dev
);
136 struct list_head
*report_list
= &hid
->report_enum
[HID_OUTPUT_REPORT
].report_list
;
137 struct hid_report
*report
= list_entry(report_list
->next
, struct hid_report
, list
);
140 #define CLAMP(x) if (x < 0) x = 0; if (x > 0xff) x = 0xff
142 switch (effect
->type
) {
144 x
= effect
->u
.ramp
.start_level
+ 0x80; /* 0x80 is no force */
146 report
->field
[0]->value
[0] = 0x11; /* Slot 1 */
147 report
->field
[0]->value
[1] = 0x08;
148 report
->field
[0]->value
[2] = x
;
149 report
->field
[0]->value
[3] = 0x80;
150 report
->field
[0]->value
[4] = 0x00;
151 report
->field
[0]->value
[5] = 0x00;
152 report
->field
[0]->value
[6] = 0x00;
154 usbhid_submit_report(hid
, report
, USB_DIR_OUT
);
160 /* Sends default autocentering command compatible with
161 * all wheels except Formula Force EX */
162 static void hid_lg4ff_set_autocenter_default(struct input_dev
*dev
, u16 magnitude
)
164 struct hid_device
*hid
= input_get_drvdata(dev
);
165 struct list_head
*report_list
= &hid
->report_enum
[HID_OUTPUT_REPORT
].report_list
;
166 struct hid_report
*report
= list_entry(report_list
->next
, struct hid_report
, list
);
168 report
->field
[0]->value
[0] = 0xfe;
169 report
->field
[0]->value
[1] = 0x0d;
170 report
->field
[0]->value
[2] = magnitude
>> 13;
171 report
->field
[0]->value
[3] = magnitude
>> 13;
172 report
->field
[0]->value
[4] = magnitude
>> 8;
173 report
->field
[0]->value
[5] = 0x00;
174 report
->field
[0]->value
[6] = 0x00;
176 usbhid_submit_report(hid
, report
, USB_DIR_OUT
);
179 /* Sends autocentering command compatible with Formula Force EX */
180 static void hid_lg4ff_set_autocenter_ffex(struct input_dev
*dev
, u16 magnitude
)
182 struct hid_device
*hid
= input_get_drvdata(dev
);
183 struct list_head
*report_list
= &hid
->report_enum
[HID_OUTPUT_REPORT
].report_list
;
184 struct hid_report
*report
= list_entry(report_list
->next
, struct hid_report
, list
);
185 magnitude
= magnitude
* 90 / 65535;
188 report
->field
[0]->value
[0] = 0xfe;
189 report
->field
[0]->value
[1] = 0x03;
190 report
->field
[0]->value
[2] = magnitude
>> 14;
191 report
->field
[0]->value
[3] = magnitude
>> 14;
192 report
->field
[0]->value
[4] = magnitude
;
193 report
->field
[0]->value
[5] = 0x00;
194 report
->field
[0]->value
[6] = 0x00;
196 usbhid_submit_report(hid
, report
, USB_DIR_OUT
);
199 /* Sends command to set range compatible with G25/G27/Driving Force GT */
200 static void hid_lg4ff_set_range_g25(struct hid_device
*hid
, u16 range
)
202 struct list_head
*report_list
= &hid
->report_enum
[HID_OUTPUT_REPORT
].report_list
;
203 struct hid_report
*report
= list_entry(report_list
->next
, struct hid_report
, list
);
204 dbg_hid("G25/G27/DFGT: setting range to %u\n", range
);
206 report
->field
[0]->value
[0] = 0xf8;
207 report
->field
[0]->value
[1] = 0x81;
208 report
->field
[0]->value
[2] = range
& 0x00ff;
209 report
->field
[0]->value
[3] = (range
& 0xff00) >> 8;
210 report
->field
[0]->value
[4] = 0x00;
211 report
->field
[0]->value
[5] = 0x00;
212 report
->field
[0]->value
[6] = 0x00;
214 usbhid_submit_report(hid
, report
, USB_DIR_OUT
);
217 /* Sends commands to set range compatible with Driving Force Pro wheel */
218 static void hid_lg4ff_set_range_dfp(struct hid_device
*hid
, __u16 range
)
220 struct list_head
*report_list
= &hid
->report_enum
[HID_OUTPUT_REPORT
].report_list
;
221 struct hid_report
*report
= list_entry(report_list
->next
, struct hid_report
, list
);
222 int start_left
, start_right
, full_range
;
223 dbg_hid("Driving Force Pro: setting range to %u\n", range
);
225 /* Prepare "coarse" limit command */
226 report
->field
[0]->value
[0] = 0xf8;
227 report
->field
[0]->value
[1] = 0x00; /* Set later */
228 report
->field
[0]->value
[2] = 0x00;
229 report
->field
[0]->value
[3] = 0x00;
230 report
->field
[0]->value
[4] = 0x00;
231 report
->field
[0]->value
[5] = 0x00;
232 report
->field
[0]->value
[6] = 0x00;
235 report
->field
[0]->value
[1] = 0x03;
238 report
->field
[0]->value
[1] = 0x02;
241 usbhid_submit_report(hid
, report
, USB_DIR_OUT
);
243 /* Prepare "fine" limit command */
244 report
->field
[0]->value
[0] = 0x81;
245 report
->field
[0]->value
[1] = 0x0b;
246 report
->field
[0]->value
[2] = 0x00;
247 report
->field
[0]->value
[3] = 0x00;
248 report
->field
[0]->value
[4] = 0x00;
249 report
->field
[0]->value
[5] = 0x00;
250 report
->field
[0]->value
[6] = 0x00;
252 if (range
== 200 || range
== 900) { /* Do not apply any fine limit */
253 usbhid_submit_report(hid
, report
, USB_DIR_OUT
);
257 /* Construct fine limit command */
258 start_left
= (((full_range
- range
+ 1) * 2047) / full_range
);
259 start_right
= 0xfff - start_left
;
261 report
->field
[0]->value
[2] = start_left
>> 4;
262 report
->field
[0]->value
[3] = start_right
>> 4;
263 report
->field
[0]->value
[4] = 0xff;
264 report
->field
[0]->value
[5] = (start_right
& 0xe) << 4 | (start_left
& 0xe);
265 report
->field
[0]->value
[6] = 0xff;
267 usbhid_submit_report(hid
, report
, USB_DIR_OUT
);
270 static void hid_lg4ff_switch_native(struct hid_device
*hid
, const struct lg4ff_native_cmd
*cmd
)
272 struct list_head
*report_list
= &hid
->report_enum
[HID_OUTPUT_REPORT
].report_list
;
273 struct hid_report
*report
= list_entry(report_list
->next
, struct hid_report
, list
);
277 while (j
< 7*cmd
->cmd_num
) {
278 for (i
= 0; i
< 7; i
++)
279 report
->field
[0]->value
[i
] = cmd
->cmd
[j
++];
281 usbhid_submit_report(hid
, report
, USB_DIR_OUT
);
285 /* Read current range and display it in terminal */
286 static ssize_t
lg4ff_range_show(struct device
*dev
, struct device_attribute
*attr
, char *buf
)
288 struct lg4ff_device_entry
*uninitialized_var(entry
);
290 struct hid_device
*hid
= to_hid_device(dev
);
293 list_for_each(h
, &device_list
.list
) {
294 entry
= list_entry(h
, struct lg4ff_device_entry
, list
);
295 if (strcmp(entry
->device_id
, (&hid
->dev
)->kobj
.name
) == 0)
298 if (h
== &device_list
.list
) {
299 dbg_hid("Device not found!");
303 count
= scnprintf(buf
, PAGE_SIZE
, "%u\n", entry
->range
);
307 /* Set range to user specified value, call appropriate function
308 * according to the type of the wheel */
309 static ssize_t
lg4ff_range_store(struct device
*dev
, struct device_attribute
*attr
, const char *buf
, size_t count
)
311 struct lg4ff_device_entry
*uninitialized_var(entry
);
313 struct hid_device
*hid
= to_hid_device(dev
);
314 __u16 range
= simple_strtoul(buf
, NULL
, 10);
316 list_for_each(h
, &device_list
.list
) {
317 entry
= list_entry(h
, struct lg4ff_device_entry
, list
);
318 if (strcmp(entry
->device_id
, (&hid
->dev
)->kobj
.name
) == 0)
321 if (h
== &device_list
.list
) {
322 dbg_hid("Device not found!");
327 range
= entry
->max_range
;
329 /* Check if the wheel supports range setting
330 * and that the range is within limits for the wheel */
331 if (entry
->set_range
!= NULL
&& range
>= entry
->min_range
&& range
<= entry
->max_range
) {
332 entry
->set_range(hid
, range
);
333 entry
->range
= range
;
339 int lg4ff_init(struct hid_device
*hid
)
341 struct hid_input
*hidinput
= list_entry(hid
->inputs
.next
, struct hid_input
, list
);
342 struct list_head
*report_list
= &hid
->report_enum
[HID_OUTPUT_REPORT
].report_list
;
343 struct input_dev
*dev
= hidinput
->input
;
344 struct hid_report
*report
;
345 struct hid_field
*field
;
346 struct lg4ff_device_entry
*entry
;
347 struct usb_device_descriptor
*udesc
;
349 __u16 bcdDevice
, rev_maj
, rev_min
;
351 /* Find the report to use */
352 if (list_empty(report_list
)) {
353 hid_err(hid
, "No output report found\n");
357 /* Check that the report looks ok */
358 report
= list_entry(report_list
->next
, struct hid_report
, list
);
360 hid_err(hid
, "NULL output report\n");
364 field
= report
->field
[0];
366 hid_err(hid
, "NULL field\n");
370 /* Check what wheel has been connected */
371 for (i
= 0; i
< ARRAY_SIZE(lg4ff_devices
); i
++) {
372 if (hid
->product
== lg4ff_devices
[i
].product_id
) {
373 dbg_hid("Found compatible device, product ID %04X\n", lg4ff_devices
[i
].product_id
);
378 if (i
== ARRAY_SIZE(lg4ff_devices
)) {
379 hid_err(hid
, "Device is not supported by lg4ff driver. If you think it should be, consider reporting a bug to"
380 "LKML, Simon Wood <simon@mungewell.org> or Michal Maly <madcatxster@gmail.com>\n");
384 /* Attempt to switch wheel to native mode when applicable */
385 udesc
= &(hid_to_usb_dev(hid
)->descriptor
);
387 hid_err(hid
, "NULL USB device descriptor\n");
390 bcdDevice
= le16_to_cpu(udesc
->bcdDevice
);
391 rev_maj
= bcdDevice
>> 8;
392 rev_min
= bcdDevice
& 0xff;
394 if (lg4ff_devices
[i
].product_id
== USB_DEVICE_ID_LOGITECH_WHEEL
) {
395 dbg_hid("Generic wheel detected, can it do native?\n");
396 dbg_hid("USB revision: %2x.%02x\n", rev_maj
, rev_min
);
398 for (j
= 0; j
< ARRAY_SIZE(lg4ff_revs
); j
++) {
399 if (lg4ff_revs
[j
].rev_maj
== rev_maj
&& lg4ff_revs
[j
].rev_min
== rev_min
) {
400 hid_lg4ff_switch_native(hid
, lg4ff_revs
[j
].command
);
401 hid_info(hid
, "Switched to native mode\n");
406 /* Set supported force feedback capabilities */
407 for (j
= 0; lg4ff_devices
[i
].ff_effects
[j
] >= 0; j
++)
408 set_bit(lg4ff_devices
[i
].ff_effects
[j
], dev
->ffbit
);
410 error
= input_ff_create_memless(dev
, NULL
, hid_lg4ff_play
);
415 /* Check if autocentering is available and
416 * set the centering force to zero by default */
417 if (test_bit(FF_AUTOCENTER
, dev
->ffbit
)) {
418 if(rev_maj
== FFEX_REV_MAJ
&& rev_min
== FFEX_REV_MIN
) /* Formula Force EX expects different autocentering command */
419 dev
->ff
->set_autocenter
= hid_lg4ff_set_autocenter_ffex
;
421 dev
->ff
->set_autocenter
= hid_lg4ff_set_autocenter_default
;
423 dev
->ff
->set_autocenter(dev
, 0);
426 /* Initialize device_list if this is the first device to handle by lg4ff */
428 INIT_LIST_HEAD(&device_list
.list
);
432 /* Add the device to device_list */
433 entry
= (struct lg4ff_device_entry
*)kzalloc(sizeof(struct lg4ff_device_entry
), GFP_KERNEL
);
435 hid_err(hid
, "Cannot add device, insufficient memory.\n");
438 entry
->device_id
= kstrdup((&hid
->dev
)->kobj
.name
, GFP_KERNEL
);
439 if (!entry
->device_id
) {
440 hid_err(hid
, "Cannot set device_id, insufficient memory.\n");
444 entry
->min_range
= lg4ff_devices
[i
].min_range
;
445 entry
->max_range
= lg4ff_devices
[i
].max_range
;
446 entry
->set_range
= lg4ff_devices
[i
].set_range
;
447 list_add(&entry
->list
, &device_list
.list
);
449 /* Create sysfs interface */
450 error
= device_create_file(&hid
->dev
, &dev_attr_range
);
453 dbg_hid("sysfs interface created\n");
455 /* Set the maximum range to start with */
456 entry
->range
= entry
->max_range
;
457 if (entry
->set_range
!= NULL
)
458 entry
->set_range(hid
, entry
->range
);
460 hid_info(hid
, "Force feedback for Logitech Speed Force Wireless by Simon Wood <simon@mungewell.org>\n");
464 int lg4ff_deinit(struct hid_device
*hid
)
467 struct lg4ff_device_entry
*entry
;
468 struct list_head
*h
, *g
;
469 list_for_each_safe(h
, g
, &device_list
.list
) {
470 entry
= list_entry(h
, struct lg4ff_device_entry
, list
);
471 if (strcmp(entry
->device_id
, (&hid
->dev
)->kobj
.name
) == 0) {
473 kfree(entry
->device_id
);
481 dbg_hid("Device entry not found!\n");
485 device_remove_file(&hid
->dev
, &dev_attr_range
);
486 dbg_hid("Device successfully unregistered\n");