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