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