1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18#include <linux/input.h>
19#include <linux/slab.h>
20#include <linux/hid.h>
21#include <linux/module.h>
22
23#include "hid-ids.h"
24
25#ifdef CONFIG_DRAGONRISE_FF
26
27struct drff_device {
28 struct hid_report *report;
29};
30
31static int drff_play(struct input_dev *dev, void *data,
32 struct ff_effect *effect)
33{
34 struct hid_device *hid = input_get_drvdata(dev);
35 struct drff_device *drff = data;
36 int strong, weak;
37
38 strong = effect->u.rumble.strong_magnitude;
39 weak = effect->u.rumble.weak_magnitude;
40
41 dbg_hid("called with 0x%04x 0x%04x", strong, weak);
42
43 if (strong || weak) {
44 strong = strong * 0xff / 0xffff;
45 weak = weak * 0xff / 0xffff;
46
47
48
49
50 if (weak == 0x0a)
51 weak = 0x0b;
52
53 drff->report->field[0]->value[0] = 0x51;
54 drff->report->field[0]->value[1] = 0x00;
55 drff->report->field[0]->value[2] = weak;
56 drff->report->field[0]->value[4] = strong;
57 hid_hw_request(hid, drff->report, HID_REQ_SET_REPORT);
58
59 drff->report->field[0]->value[0] = 0xfa;
60 drff->report->field[0]->value[1] = 0xfe;
61 } else {
62 drff->report->field[0]->value[0] = 0xf3;
63 drff->report->field[0]->value[1] = 0x00;
64 }
65
66 drff->report->field[0]->value[2] = 0x00;
67 drff->report->field[0]->value[4] = 0x00;
68 dbg_hid("running with 0x%02x 0x%02x", strong, weak);
69 hid_hw_request(hid, drff->report, HID_REQ_SET_REPORT);
70
71 return 0;
72}
73
74static int drff_init(struct hid_device *hid)
75{
76 struct drff_device *drff;
77 struct hid_report *report;
78 struct hid_input *hidinput;
79 struct list_head *report_list =
80 &hid->report_enum[HID_OUTPUT_REPORT].report_list;
81 struct input_dev *dev;
82 int error;
83
84 if (list_empty(&hid->inputs)) {
85 hid_err(hid, "no inputs found\n");
86 return -ENODEV;
87 }
88 hidinput = list_first_entry(&hid->inputs, struct hid_input, list);
89 dev = hidinput->input;
90
91 if (list_empty(report_list)) {
92 hid_err(hid, "no output reports found\n");
93 return -ENODEV;
94 }
95
96 report = list_first_entry(report_list, struct hid_report, list);
97 if (report->maxfield < 1) {
98 hid_err(hid, "no fields in the report\n");
99 return -ENODEV;
100 }
101
102 if (report->field[0]->report_count < 7) {
103 hid_err(hid, "not enough values in the field\n");
104 return -ENODEV;
105 }
106
107 drff = kzalloc(sizeof(struct drff_device), GFP_KERNEL);
108 if (!drff)
109 return -ENOMEM;
110
111 set_bit(FF_RUMBLE, dev->ffbit);
112
113 error = input_ff_create_memless(dev, drff, drff_play);
114 if (error) {
115 kfree(drff);
116 return error;
117 }
118
119 drff->report = report;
120 drff->report->field[0]->value[0] = 0xf3;
121 drff->report->field[0]->value[1] = 0x00;
122 drff->report->field[0]->value[2] = 0x00;
123 drff->report->field[0]->value[3] = 0x00;
124 drff->report->field[0]->value[4] = 0x00;
125 drff->report->field[0]->value[5] = 0x00;
126 drff->report->field[0]->value[6] = 0x00;
127 hid_hw_request(hid, drff->report, HID_REQ_SET_REPORT);
128
129 hid_info(hid, "Force Feedback for DragonRise Inc. "
130 "game controllers by Richard Walmsley <richwalm@gmail.com>\n");
131
132 return 0;
133}
134#else
135static inline int drff_init(struct hid_device *hid)
136{
137 return 0;
138}
139#endif
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199#define PID0011_RDESC_ORIG_SIZE 101
200
201
202static __u8 pid0011_rdesc_fixed[] = {
203 0x05, 0x01,
204 0x09, 0x04,
205 0xA1, 0x01,
206 0xA1, 0x02,
207 0x14,
208 0x75, 0x08,
209 0x95, 0x03,
210 0x81, 0x01,
211 0x26, 0xFF, 0x00,
212 0x95, 0x02,
213 0x09, 0x30,
214 0x09, 0x31,
215 0x81, 0x02,
216 0x75, 0x01,
217 0x95, 0x04,
218 0x81, 0x01,
219 0x25, 0x01,
220 0x95, 0x0A,
221 0x05, 0x09,
222 0x19, 0x01,
223 0x29, 0x0A,
224 0x81, 0x02,
225 0x95, 0x0A,
226 0x81, 0x01,
227 0xC0,
228 0xC0
229};
230
231static __u8 *dr_report_fixup(struct hid_device *hdev, __u8 *rdesc,
232 unsigned int *rsize)
233{
234 switch (hdev->product) {
235 case 0x0011:
236 if (*rsize == PID0011_RDESC_ORIG_SIZE) {
237 rdesc = pid0011_rdesc_fixed;
238 *rsize = sizeof(pid0011_rdesc_fixed);
239 }
240 break;
241 }
242 return rdesc;
243}
244
245#define map_abs(c) hid_map_usage(hi, usage, bit, max, EV_ABS, (c))
246#define map_rel(c) hid_map_usage(hi, usage, bit, max, EV_REL, (c))
247
248static int dr_input_mapping(struct hid_device *hdev, struct hid_input *hi,
249 struct hid_field *field, struct hid_usage *usage,
250 unsigned long **bit, int *max)
251{
252 switch (usage->hid) {
253
254
255
256
257 case HID_GD_X: case HID_GD_Y: case HID_GD_Z:
258 case HID_GD_RX: case HID_GD_RY: case HID_GD_RZ:
259 if (field->flags & HID_MAIN_ITEM_RELATIVE)
260 map_rel(usage->hid & 0xf);
261 else
262 map_abs(usage->hid & 0xf);
263 return 1;
264 }
265
266 return 0;
267}
268
269static int dr_probe(struct hid_device *hdev, const struct hid_device_id *id)
270{
271 int ret;
272
273 dev_dbg(&hdev->dev, "DragonRise Inc. HID hardware probe...");
274
275 ret = hid_parse(hdev);
276 if (ret) {
277 hid_err(hdev, "parse failed\n");
278 goto err;
279 }
280
281 ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT & ~HID_CONNECT_FF);
282 if (ret) {
283 hid_err(hdev, "hw start failed\n");
284 goto err;
285 }
286
287 switch (hdev->product) {
288 case 0x0006:
289 ret = drff_init(hdev);
290 if (ret) {
291 dev_err(&hdev->dev, "force feedback init failed\n");
292 hid_hw_stop(hdev);
293 goto err;
294 }
295 break;
296 }
297
298 return 0;
299err:
300 return ret;
301}
302
303static const struct hid_device_id dr_devices[] = {
304 { HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, 0x0006), },
305 { HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, 0x0011), },
306 { }
307};
308MODULE_DEVICE_TABLE(hid, dr_devices);
309
310static struct hid_driver dr_driver = {
311 .name = "dragonrise",
312 .id_table = dr_devices,
313 .report_fixup = dr_report_fixup,
314 .probe = dr_probe,
315 .input_mapping = dr_input_mapping,
316};
317module_hid_driver(dr_driver);
318
319MODULE_LICENSE("GPL");
320