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