aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/hid
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/hid')
-rw-r--r--drivers/hid/usbhid/Kconfig5
-rw-r--r--drivers/hid/usbhid/hid-ff.c2
-rw-r--r--drivers/hid/usbhid/hid-tmff.c161
3 files changed, 124 insertions, 44 deletions
diff --git a/drivers/hid/usbhid/Kconfig b/drivers/hid/usbhid/Kconfig
index 1b4b572f899b..b27023f23c87 100644
--- a/drivers/hid/usbhid/Kconfig
+++ b/drivers/hid/usbhid/Kconfig
@@ -79,11 +79,12 @@ config PANTHERLORD_FF
79 to enable force feedback support for it. 79 to enable force feedback support for it.
80 80
81config THRUSTMASTER_FF 81config THRUSTMASTER_FF
82 bool "ThrustMaster FireStorm Dual Power 2 support (EXPERIMENTAL)" 82 bool "ThrustMaster devices support (EXPERIMENTAL)"
83 depends on HID_FF && EXPERIMENTAL 83 depends on HID_FF && EXPERIMENTAL
84 select INPUT_FF_MEMLESS if USB_HID 84 select INPUT_FF_MEMLESS if USB_HID
85 help 85 help
86 Say Y here if you have a THRUSTMASTER FireStore Dual Power 2, 86 Say Y here if you have a THRUSTMASTER FireStore Dual Power 2 or
87 a THRUSTMASTER Ferrari GT Rumble Force or Force Feedback Wheel,
87 and want to enable force feedback support for it. 88 and want to enable force feedback support for it.
88 Note: if you say N here, this device will still be supported, but without 89 Note: if you say N here, this device will still be supported, but without
89 force feedback. 90 force feedback.
diff --git a/drivers/hid/usbhid/hid-ff.c b/drivers/hid/usbhid/hid-ff.c
index 23431fbbc3d7..5dacd8ec8072 100644
--- a/drivers/hid/usbhid/hid-ff.c
+++ b/drivers/hid/usbhid/hid-ff.c
@@ -67,6 +67,8 @@ static struct hid_ff_initializer inits[] = {
67#ifdef CONFIG_THRUSTMASTER_FF 67#ifdef CONFIG_THRUSTMASTER_FF
68 { 0x44f, 0xb300, hid_tmff_init }, 68 { 0x44f, 0xb300, hid_tmff_init },
69 { 0x44f, 0xb304, hid_tmff_init }, 69 { 0x44f, 0xb304, hid_tmff_init },
70 { 0x44f, 0xb651, hid_tmff_init }, /* FGT Rumble Force Wheel */
71 { 0x44f, 0xb654, hid_tmff_init }, /* FGT Force Feedback Wheel */
70#endif 72#endif
71#ifdef CONFIG_ZEROPLUS_FF 73#ifdef CONFIG_ZEROPLUS_FF
72 { 0xc12, 0x0005, hid_zpff_init }, 74 { 0xc12, 0x0005, hid_zpff_init },
diff --git a/drivers/hid/usbhid/hid-tmff.c b/drivers/hid/usbhid/hid-tmff.c
index 555bb48b4295..69882a726e99 100644
--- a/drivers/hid/usbhid/hid-tmff.c
+++ b/drivers/hid/usbhid/hid-tmff.c
@@ -36,16 +36,39 @@
36#include "usbhid.h" 36#include "usbhid.h"
37 37
38/* Usages for thrustmaster devices I know about */ 38/* Usages for thrustmaster devices I know about */
39#define THRUSTMASTER_USAGE_RUMBLE_LR (HID_UP_GENDESK | 0xbb) 39#define THRUSTMASTER_USAGE_FF (HID_UP_GENDESK | 0xbb)
40 40
41struct dev_type {
42 u16 idVendor;
43 u16 idProduct;
44 const signed short *ff;
45};
46
47static const signed short ff_rumble[] = {
48 FF_RUMBLE,
49 -1
50};
51
52static const signed short ff_joystick[] = {
53 FF_CONSTANT,
54 -1
55};
56
57static const struct dev_type devices[] = {
58 { 0x44f, 0xb300, ff_rumble },
59 { 0x44f, 0xb304, ff_rumble },
60 { 0x44f, 0xb651, ff_rumble }, /* FGT Rumble Force Wheel */
61 { 0x44f, 0xb654, ff_joystick }, /* FGT Force Feedback Wheel */
62};
41 63
42struct tmff_device { 64struct tmff_device {
43 struct hid_report *report; 65 struct hid_report *report;
44 struct hid_field *rumble; 66 struct hid_field *ff_field;
45}; 67};
46 68
47/* Changes values from 0 to 0xffff into values from minimum to maximum */ 69/* Changes values from 0 to 0xffff into values from minimum to maximum */
48static inline int hid_tmff_scale(unsigned int in, int minimum, int maximum) 70static inline int hid_tmff_scale_u16(unsigned int in,
71 int minimum, int maximum)
49{ 72{
50 int ret; 73 int ret;
51 74
@@ -57,22 +80,57 @@ static inline int hid_tmff_scale(unsigned int in, int minimum, int maximum)
57 return ret; 80 return ret;
58} 81}
59 82
83/* Changes values from -0x80 to 0x7f into values from minimum to maximum */
84static inline int hid_tmff_scale_s8(int in,
85 int minimum, int maximum)
86{
87 int ret;
88
89 ret = (((in + 0x80) * (maximum - minimum)) / 0xff) + minimum;
90 if (ret < minimum)
91 return minimum;
92 if (ret > maximum)
93 return maximum;
94 return ret;
95}
96
60static int hid_tmff_play(struct input_dev *dev, void *data, struct ff_effect *effect) 97static int hid_tmff_play(struct input_dev *dev, void *data, struct ff_effect *effect)
61{ 98{
62 struct hid_device *hid = input_get_drvdata(dev); 99 struct hid_device *hid = input_get_drvdata(dev);
63 struct tmff_device *tmff = data; 100 struct tmff_device *tmff = data;
101 struct hid_field *ff_field = tmff->ff_field;
102 int x, y;
64 int left, right; /* Rumbling */ 103 int left, right; /* Rumbling */
65 104
66 left = hid_tmff_scale(effect->u.rumble.weak_magnitude, 105 switch (effect->type) {
67 tmff->rumble->logical_minimum, tmff->rumble->logical_maximum); 106 case FF_CONSTANT:
68 right = hid_tmff_scale(effect->u.rumble.strong_magnitude, 107 x = hid_tmff_scale_s8(effect->u.ramp.start_level,
69 tmff->rumble->logical_minimum, tmff->rumble->logical_maximum); 108 ff_field->logical_minimum,
70 109 ff_field->logical_maximum);
71 tmff->rumble->value[0] = left; 110 y = hid_tmff_scale_s8(effect->u.ramp.end_level,
72 tmff->rumble->value[1] = right; 111 ff_field->logical_minimum,
73 dbg_hid("(left,right)=(%08x, %08x)\n", left, right); 112 ff_field->logical_maximum);
74 usbhid_submit_report(hid, tmff->report, USB_DIR_OUT); 113
75 114 dbg_hid("(x, y)=(%04x, %04x)\n", x, y);
115 ff_field->value[0] = x;
116 ff_field->value[1] = y;
117 usbhid_submit_report(hid, tmff->report, USB_DIR_OUT);
118 break;
119
120 case FF_RUMBLE:
121 left = hid_tmff_scale_u16(effect->u.rumble.weak_magnitude,
122 ff_field->logical_minimum,
123 ff_field->logical_maximum);
124 right = hid_tmff_scale_u16(effect->u.rumble.strong_magnitude,
125 ff_field->logical_minimum,
126 ff_field->logical_maximum);
127
128 dbg_hid("(left,right)=(%08x, %08x)\n", left, right);
129 ff_field->value[0] = left;
130 ff_field->value[1] = right;
131 usbhid_submit_report(hid, tmff->report, USB_DIR_OUT);
132 break;
133 }
76 return 0; 134 return 0;
77} 135}
78 136
@@ -82,14 +140,16 @@ int hid_tmff_init(struct hid_device *hid)
82 struct list_head *pos; 140 struct list_head *pos;
83 struct hid_input *hidinput = list_entry(hid->inputs.next, struct hid_input, list); 141 struct hid_input *hidinput = list_entry(hid->inputs.next, struct hid_input, list);
84 struct input_dev *input_dev = hidinput->input; 142 struct input_dev *input_dev = hidinput->input;
143 const signed short *ff_bits = ff_joystick;
85 int error; 144 int error;
145 int i;
86 146
87 tmff = kzalloc(sizeof(struct tmff_device), GFP_KERNEL); 147 tmff = kzalloc(sizeof(struct tmff_device), GFP_KERNEL);
88 if (!tmff) 148 if (!tmff)
89 return -ENOMEM; 149 return -ENOMEM;
90 150
91 /* Find the report to use */ 151 /* Find the report to use */
92 __list_for_each(pos, &hid->report_enum[HID_OUTPUT_REPORT].report_list) { 152 list_for_each(pos, &hid->report_enum[HID_OUTPUT_REPORT].report_list) {
93 struct hid_report *report = (struct hid_report *)pos; 153 struct hid_report *report = (struct hid_report *)pos;
94 int fieldnum; 154 int fieldnum;
95 155
@@ -100,48 +160,65 @@ int hid_tmff_init(struct hid_device *hid)
100 continue; 160 continue;
101 161
102 switch (field->usage[0].hid) { 162 switch (field->usage[0].hid) {
103 case THRUSTMASTER_USAGE_RUMBLE_LR: 163 case THRUSTMASTER_USAGE_FF:
104 if (field->report_count < 2) { 164 if (field->report_count < 2) {
105 warn("ignoring THRUSTMASTER_USAGE_RUMBLE_LR with report_count < 2"); 165 warn("ignoring FF field with report_count < 2");
106 continue; 166 continue;
107 } 167 }
108 168
109 if (field->logical_maximum == field->logical_minimum) { 169 if (field->logical_maximum == field->logical_minimum) {
110 warn("ignoring THRUSTMASTER_USAGE_RUMBLE_LR with logical_maximum == logical_minimum"); 170 warn("ignoring FF field with logical_maximum == logical_minimum");
111 continue; 171 continue;
112 } 172 }
113 173
114 if (tmff->report && tmff->report != report) { 174 if (tmff->report && tmff->report != report) {
115 warn("ignoring THRUSTMASTER_USAGE_RUMBLE_LR in other report"); 175 warn("ignoring FF field in other report");
116 continue; 176 continue;
117 } 177 }
118 178
119 if (tmff->rumble && tmff->rumble != field) { 179 if (tmff->ff_field && tmff->ff_field != field) {
120 warn("ignoring duplicate THRUSTMASTER_USAGE_RUMBLE_LR"); 180 warn("ignoring duplicate FF field");
121 continue; 181 continue;
182 }
183
184 tmff->report = report;
185 tmff->ff_field = field;
186
187 for (i = 0; i < ARRAY_SIZE(devices); i++) {
188 if (input_dev->id.vendor == devices[i].idVendor &&
189 input_dev->id.product == devices[i].idProduct) {
190 ff_bits = devices[i].ff;
191 break;
122 } 192 }
193 }
123 194
124 tmff->report = report; 195 for (i = 0; ff_bits[i] >= 0; i++)
125 tmff->rumble = field; 196 set_bit(ff_bits[i], input_dev->ffbit);
126 197
127 set_bit(FF_RUMBLE, input_dev->ffbit); 198 break;
128 break;
129 199
130 default: 200 default:
131 warn("ignoring unknown output usage %08x", field->usage[0].hid); 201 warn("ignoring unknown output usage %08x", field->usage[0].hid);
132 continue; 202 continue;
133 } 203 }
134 } 204 }
135 } 205 }
136 206
137 error = input_ff_create_memless(input_dev, tmff, hid_tmff_play); 207 if (!tmff->report) {
138 if (error) { 208 err("cant find FF field in output reports\n");
139 kfree(tmff); 209 error = -ENODEV;
140 return error; 210 goto fail;
141 } 211 }
142 212
143 info("Force feedback for ThrustMaster rumble pad devices by Zinx Verituse <zinx@epicsol.org>"); 213 error = input_ff_create_memless(input_dev, tmff, hid_tmff_play);
214 if (error)
215 goto fail;
144 216
217 info("Force feedback for ThrustMaster devices by Zinx Verituse <zinx@epicsol.org>");
145 return 0; 218 return 0;
219
220 fail:
221 kfree(tmff);
222 return error;
146} 223}
147 224