1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-or-later
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * Force feedback support for various HID compliant devices by ThrustMaster:
4*4882a593Smuzhiyun * ThrustMaster FireStorm Dual Power 2
5*4882a593Smuzhiyun * and possibly others whose device ids haven't been added.
6*4882a593Smuzhiyun *
7*4882a593Smuzhiyun * Modified to support ThrustMaster devices by Zinx Verituse
8*4882a593Smuzhiyun * on 2003-01-25 from the Logitech force feedback driver,
9*4882a593Smuzhiyun * which is by Johann Deneux.
10*4882a593Smuzhiyun *
11*4882a593Smuzhiyun * Copyright (c) 2003 Zinx Verituse <zinx@epicsol.org>
12*4882a593Smuzhiyun * Copyright (c) 2002 Johann Deneux
13*4882a593Smuzhiyun */
14*4882a593Smuzhiyun
15*4882a593Smuzhiyun /*
16*4882a593Smuzhiyun */
17*4882a593Smuzhiyun
18*4882a593Smuzhiyun #include <linux/hid.h>
19*4882a593Smuzhiyun #include <linux/input.h>
20*4882a593Smuzhiyun #include <linux/slab.h>
21*4882a593Smuzhiyun #include <linux/module.h>
22*4882a593Smuzhiyun
23*4882a593Smuzhiyun #include "hid-ids.h"
24*4882a593Smuzhiyun
25*4882a593Smuzhiyun #define THRUSTMASTER_DEVICE_ID_2_IN_1_DT 0xb320
26*4882a593Smuzhiyun
27*4882a593Smuzhiyun static const signed short ff_rumble[] = {
28*4882a593Smuzhiyun FF_RUMBLE,
29*4882a593Smuzhiyun -1
30*4882a593Smuzhiyun };
31*4882a593Smuzhiyun
32*4882a593Smuzhiyun static const signed short ff_joystick[] = {
33*4882a593Smuzhiyun FF_CONSTANT,
34*4882a593Smuzhiyun -1
35*4882a593Smuzhiyun };
36*4882a593Smuzhiyun
37*4882a593Smuzhiyun #ifdef CONFIG_THRUSTMASTER_FF
38*4882a593Smuzhiyun
39*4882a593Smuzhiyun /* Usages for thrustmaster devices I know about */
40*4882a593Smuzhiyun #define THRUSTMASTER_USAGE_FF (HID_UP_GENDESK | 0xbb)
41*4882a593Smuzhiyun
42*4882a593Smuzhiyun struct tmff_device {
43*4882a593Smuzhiyun struct hid_report *report;
44*4882a593Smuzhiyun struct hid_field *ff_field;
45*4882a593Smuzhiyun };
46*4882a593Smuzhiyun
47*4882a593Smuzhiyun /* Changes values from 0 to 0xffff into values from minimum to maximum */
tmff_scale_u16(unsigned int in,int minimum,int maximum)48*4882a593Smuzhiyun static inline int tmff_scale_u16(unsigned int in, int minimum, int maximum)
49*4882a593Smuzhiyun {
50*4882a593Smuzhiyun int ret;
51*4882a593Smuzhiyun
52*4882a593Smuzhiyun ret = (in * (maximum - minimum) / 0xffff) + minimum;
53*4882a593Smuzhiyun if (ret < minimum)
54*4882a593Smuzhiyun return minimum;
55*4882a593Smuzhiyun if (ret > maximum)
56*4882a593Smuzhiyun return maximum;
57*4882a593Smuzhiyun return ret;
58*4882a593Smuzhiyun }
59*4882a593Smuzhiyun
60*4882a593Smuzhiyun /* Changes values from -0x80 to 0x7f into values from minimum to maximum */
tmff_scale_s8(int in,int minimum,int maximum)61*4882a593Smuzhiyun static inline int tmff_scale_s8(int in, int minimum, int maximum)
62*4882a593Smuzhiyun {
63*4882a593Smuzhiyun int ret;
64*4882a593Smuzhiyun
65*4882a593Smuzhiyun ret = (((in + 0x80) * (maximum - minimum)) / 0xff) + minimum;
66*4882a593Smuzhiyun if (ret < minimum)
67*4882a593Smuzhiyun return minimum;
68*4882a593Smuzhiyun if (ret > maximum)
69*4882a593Smuzhiyun return maximum;
70*4882a593Smuzhiyun return ret;
71*4882a593Smuzhiyun }
72*4882a593Smuzhiyun
tmff_play(struct input_dev * dev,void * data,struct ff_effect * effect)73*4882a593Smuzhiyun static int tmff_play(struct input_dev *dev, void *data,
74*4882a593Smuzhiyun struct ff_effect *effect)
75*4882a593Smuzhiyun {
76*4882a593Smuzhiyun struct hid_device *hid = input_get_drvdata(dev);
77*4882a593Smuzhiyun struct tmff_device *tmff = data;
78*4882a593Smuzhiyun struct hid_field *ff_field = tmff->ff_field;
79*4882a593Smuzhiyun int x, y;
80*4882a593Smuzhiyun int left, right; /* Rumbling */
81*4882a593Smuzhiyun int motor_swap;
82*4882a593Smuzhiyun
83*4882a593Smuzhiyun switch (effect->type) {
84*4882a593Smuzhiyun case FF_CONSTANT:
85*4882a593Smuzhiyun x = tmff_scale_s8(effect->u.ramp.start_level,
86*4882a593Smuzhiyun ff_field->logical_minimum,
87*4882a593Smuzhiyun ff_field->logical_maximum);
88*4882a593Smuzhiyun y = tmff_scale_s8(effect->u.ramp.end_level,
89*4882a593Smuzhiyun ff_field->logical_minimum,
90*4882a593Smuzhiyun ff_field->logical_maximum);
91*4882a593Smuzhiyun
92*4882a593Smuzhiyun dbg_hid("(x, y)=(%04x, %04x)\n", x, y);
93*4882a593Smuzhiyun ff_field->value[0] = x;
94*4882a593Smuzhiyun ff_field->value[1] = y;
95*4882a593Smuzhiyun hid_hw_request(hid, tmff->report, HID_REQ_SET_REPORT);
96*4882a593Smuzhiyun break;
97*4882a593Smuzhiyun
98*4882a593Smuzhiyun case FF_RUMBLE:
99*4882a593Smuzhiyun left = tmff_scale_u16(effect->u.rumble.weak_magnitude,
100*4882a593Smuzhiyun ff_field->logical_minimum,
101*4882a593Smuzhiyun ff_field->logical_maximum);
102*4882a593Smuzhiyun right = tmff_scale_u16(effect->u.rumble.strong_magnitude,
103*4882a593Smuzhiyun ff_field->logical_minimum,
104*4882a593Smuzhiyun ff_field->logical_maximum);
105*4882a593Smuzhiyun
106*4882a593Smuzhiyun /* 2-in-1 strong motor is left */
107*4882a593Smuzhiyun if (hid->product == THRUSTMASTER_DEVICE_ID_2_IN_1_DT) {
108*4882a593Smuzhiyun motor_swap = left;
109*4882a593Smuzhiyun left = right;
110*4882a593Smuzhiyun right = motor_swap;
111*4882a593Smuzhiyun }
112*4882a593Smuzhiyun
113*4882a593Smuzhiyun dbg_hid("(left,right)=(%08x, %08x)\n", left, right);
114*4882a593Smuzhiyun ff_field->value[0] = left;
115*4882a593Smuzhiyun ff_field->value[1] = right;
116*4882a593Smuzhiyun hid_hw_request(hid, tmff->report, HID_REQ_SET_REPORT);
117*4882a593Smuzhiyun break;
118*4882a593Smuzhiyun }
119*4882a593Smuzhiyun return 0;
120*4882a593Smuzhiyun }
121*4882a593Smuzhiyun
tmff_init(struct hid_device * hid,const signed short * ff_bits)122*4882a593Smuzhiyun static int tmff_init(struct hid_device *hid, const signed short *ff_bits)
123*4882a593Smuzhiyun {
124*4882a593Smuzhiyun struct tmff_device *tmff;
125*4882a593Smuzhiyun struct hid_report *report;
126*4882a593Smuzhiyun struct list_head *report_list;
127*4882a593Smuzhiyun struct hid_input *hidinput;
128*4882a593Smuzhiyun struct input_dev *input_dev;
129*4882a593Smuzhiyun int error;
130*4882a593Smuzhiyun int i;
131*4882a593Smuzhiyun
132*4882a593Smuzhiyun if (list_empty(&hid->inputs)) {
133*4882a593Smuzhiyun hid_err(hid, "no inputs found\n");
134*4882a593Smuzhiyun return -ENODEV;
135*4882a593Smuzhiyun }
136*4882a593Smuzhiyun hidinput = list_entry(hid->inputs.next, struct hid_input, list);
137*4882a593Smuzhiyun input_dev = hidinput->input;
138*4882a593Smuzhiyun
139*4882a593Smuzhiyun tmff = kzalloc(sizeof(struct tmff_device), GFP_KERNEL);
140*4882a593Smuzhiyun if (!tmff)
141*4882a593Smuzhiyun return -ENOMEM;
142*4882a593Smuzhiyun
143*4882a593Smuzhiyun /* Find the report to use */
144*4882a593Smuzhiyun report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list;
145*4882a593Smuzhiyun list_for_each_entry(report, report_list, list) {
146*4882a593Smuzhiyun int fieldnum;
147*4882a593Smuzhiyun
148*4882a593Smuzhiyun for (fieldnum = 0; fieldnum < report->maxfield; ++fieldnum) {
149*4882a593Smuzhiyun struct hid_field *field = report->field[fieldnum];
150*4882a593Smuzhiyun
151*4882a593Smuzhiyun if (field->maxusage <= 0)
152*4882a593Smuzhiyun continue;
153*4882a593Smuzhiyun
154*4882a593Smuzhiyun switch (field->usage[0].hid) {
155*4882a593Smuzhiyun case THRUSTMASTER_USAGE_FF:
156*4882a593Smuzhiyun if (field->report_count < 2) {
157*4882a593Smuzhiyun hid_warn(hid, "ignoring FF field with report_count < 2\n");
158*4882a593Smuzhiyun continue;
159*4882a593Smuzhiyun }
160*4882a593Smuzhiyun
161*4882a593Smuzhiyun if (field->logical_maximum ==
162*4882a593Smuzhiyun field->logical_minimum) {
163*4882a593Smuzhiyun hid_warn(hid, "ignoring FF field with logical_maximum == logical_minimum\n");
164*4882a593Smuzhiyun continue;
165*4882a593Smuzhiyun }
166*4882a593Smuzhiyun
167*4882a593Smuzhiyun if (tmff->report && tmff->report != report) {
168*4882a593Smuzhiyun hid_warn(hid, "ignoring FF field in other report\n");
169*4882a593Smuzhiyun continue;
170*4882a593Smuzhiyun }
171*4882a593Smuzhiyun
172*4882a593Smuzhiyun if (tmff->ff_field && tmff->ff_field != field) {
173*4882a593Smuzhiyun hid_warn(hid, "ignoring duplicate FF field\n");
174*4882a593Smuzhiyun continue;
175*4882a593Smuzhiyun }
176*4882a593Smuzhiyun
177*4882a593Smuzhiyun tmff->report = report;
178*4882a593Smuzhiyun tmff->ff_field = field;
179*4882a593Smuzhiyun
180*4882a593Smuzhiyun for (i = 0; ff_bits[i] >= 0; i++)
181*4882a593Smuzhiyun set_bit(ff_bits[i], input_dev->ffbit);
182*4882a593Smuzhiyun
183*4882a593Smuzhiyun break;
184*4882a593Smuzhiyun
185*4882a593Smuzhiyun default:
186*4882a593Smuzhiyun hid_warn(hid, "ignoring unknown output usage %08x\n",
187*4882a593Smuzhiyun field->usage[0].hid);
188*4882a593Smuzhiyun continue;
189*4882a593Smuzhiyun }
190*4882a593Smuzhiyun }
191*4882a593Smuzhiyun }
192*4882a593Smuzhiyun
193*4882a593Smuzhiyun if (!tmff->report) {
194*4882a593Smuzhiyun hid_err(hid, "can't find FF field in output reports\n");
195*4882a593Smuzhiyun error = -ENODEV;
196*4882a593Smuzhiyun goto fail;
197*4882a593Smuzhiyun }
198*4882a593Smuzhiyun
199*4882a593Smuzhiyun error = input_ff_create_memless(input_dev, tmff, tmff_play);
200*4882a593Smuzhiyun if (error)
201*4882a593Smuzhiyun goto fail;
202*4882a593Smuzhiyun
203*4882a593Smuzhiyun hid_info(hid, "force feedback for ThrustMaster devices by Zinx Verituse <zinx@epicsol.org>\n");
204*4882a593Smuzhiyun return 0;
205*4882a593Smuzhiyun
206*4882a593Smuzhiyun fail:
207*4882a593Smuzhiyun kfree(tmff);
208*4882a593Smuzhiyun return error;
209*4882a593Smuzhiyun }
210*4882a593Smuzhiyun #else
tmff_init(struct hid_device * hid,const signed short * ff_bits)211*4882a593Smuzhiyun static inline int tmff_init(struct hid_device *hid, const signed short *ff_bits)
212*4882a593Smuzhiyun {
213*4882a593Smuzhiyun return 0;
214*4882a593Smuzhiyun }
215*4882a593Smuzhiyun #endif
216*4882a593Smuzhiyun
tm_probe(struct hid_device * hdev,const struct hid_device_id * id)217*4882a593Smuzhiyun static int tm_probe(struct hid_device *hdev, const struct hid_device_id *id)
218*4882a593Smuzhiyun {
219*4882a593Smuzhiyun int ret;
220*4882a593Smuzhiyun
221*4882a593Smuzhiyun ret = hid_parse(hdev);
222*4882a593Smuzhiyun if (ret) {
223*4882a593Smuzhiyun hid_err(hdev, "parse failed\n");
224*4882a593Smuzhiyun goto err;
225*4882a593Smuzhiyun }
226*4882a593Smuzhiyun
227*4882a593Smuzhiyun ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT & ~HID_CONNECT_FF);
228*4882a593Smuzhiyun if (ret) {
229*4882a593Smuzhiyun hid_err(hdev, "hw start failed\n");
230*4882a593Smuzhiyun goto err;
231*4882a593Smuzhiyun }
232*4882a593Smuzhiyun
233*4882a593Smuzhiyun tmff_init(hdev, (void *)id->driver_data);
234*4882a593Smuzhiyun
235*4882a593Smuzhiyun return 0;
236*4882a593Smuzhiyun err:
237*4882a593Smuzhiyun return ret;
238*4882a593Smuzhiyun }
239*4882a593Smuzhiyun
240*4882a593Smuzhiyun static const struct hid_device_id tm_devices[] = {
241*4882a593Smuzhiyun { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb300),
242*4882a593Smuzhiyun .driver_data = (unsigned long)ff_rumble },
243*4882a593Smuzhiyun { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb304), /* FireStorm Dual Power 2 (and 3) */
244*4882a593Smuzhiyun .driver_data = (unsigned long)ff_rumble },
245*4882a593Smuzhiyun { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, THRUSTMASTER_DEVICE_ID_2_IN_1_DT), /* Dual Trigger 2-in-1 */
246*4882a593Smuzhiyun .driver_data = (unsigned long)ff_rumble },
247*4882a593Smuzhiyun { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb323), /* Dual Trigger 3-in-1 (PC Mode) */
248*4882a593Smuzhiyun .driver_data = (unsigned long)ff_rumble },
249*4882a593Smuzhiyun { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb324), /* Dual Trigger 3-in-1 (PS3 Mode) */
250*4882a593Smuzhiyun .driver_data = (unsigned long)ff_rumble },
251*4882a593Smuzhiyun { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb605), /* NASCAR PRO FF2 Wheel */
252*4882a593Smuzhiyun .driver_data = (unsigned long)ff_joystick },
253*4882a593Smuzhiyun { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb651), /* FGT Rumble Force Wheel */
254*4882a593Smuzhiyun .driver_data = (unsigned long)ff_rumble },
255*4882a593Smuzhiyun { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb653), /* RGT Force Feedback CLUTCH Raging Wheel */
256*4882a593Smuzhiyun .driver_data = (unsigned long)ff_joystick },
257*4882a593Smuzhiyun { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb654), /* FGT Force Feedback Wheel */
258*4882a593Smuzhiyun .driver_data = (unsigned long)ff_joystick },
259*4882a593Smuzhiyun { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb65a), /* F430 Force Feedback Wheel */
260*4882a593Smuzhiyun .driver_data = (unsigned long)ff_joystick },
261*4882a593Smuzhiyun { }
262*4882a593Smuzhiyun };
263*4882a593Smuzhiyun MODULE_DEVICE_TABLE(hid, tm_devices);
264*4882a593Smuzhiyun
265*4882a593Smuzhiyun static struct hid_driver tm_driver = {
266*4882a593Smuzhiyun .name = "thrustmaster",
267*4882a593Smuzhiyun .id_table = tm_devices,
268*4882a593Smuzhiyun .probe = tm_probe,
269*4882a593Smuzhiyun };
270*4882a593Smuzhiyun module_hid_driver(tm_driver);
271*4882a593Smuzhiyun
272*4882a593Smuzhiyun MODULE_LICENSE("GPL");
273