aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/hid/usbhid/hid-tmff.c
diff options
context:
space:
mode:
authorDmitry Torokhov <dtor@mail.ru>2007-07-30 08:56:26 -0400
committerJiri Kosina <jkosina@suse.cz>2007-10-14 07:40:00 -0400
commitb27c9590ca0f44681fe2504a7ec427ff1bb77e82 (patch)
tree7a9bb6cc6c0a09fe60888de4cb1efe8bc1dfaf85 /drivers/hid/usbhid/hid-tmff.c
parent933e3187d0042d9381d932757dc1f931d984e56d (diff)
HID: add support for Thrustmaster FGT Force Feedback wheel
Rework thrustmaster force-feedback module to support devices having different types of force feedback effects. Add signatures of Thrustmaster FGT Rumble Force and Thrustmaster FGT Force Feedback wheels to the list of devices dupported by the module. Parts of the patch were lifted off a simalar patch by Anssi Hannula <anssi.hannula@gmail.com> Signed-off-by: Dmitry Torokhov <dtor@mail.ru> Signed-off-by: Jiri Kosina <jkosina@suse.cz>
Diffstat (limited to 'drivers/hid/usbhid/hid-tmff.c')
-rw-r--r--drivers/hid/usbhid/hid-tmff.c161
1 files changed, 119 insertions, 42 deletions
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