1
2
3
4
5
6
7
8
9
10
11
12
13#include <linux/input.h>
14#include <linux/slab.h>
15#include <linux/module.h>
16#include <linux/leds.h>
17#include <linux/hid.h>
18
19#include "hid-ids.h"
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92#define PID0902_RDESC_ORIG_SIZE 137
93
94
95
96
97
98
99
100
101
102static __u8 pid0902_rdesc_fixed[] = {
103 0x05, 0x01,
104 0x09, 0x05,
105 0xA1, 0x01,
106 0x15, 0x00,
107 0x25, 0x01,
108 0x35, 0x00,
109 0x45, 0x01,
110 0x75, 0x01,
111 0x95, 0x0D,
112 0x05, 0x09,
113 0x09, 0x05,
114 0x09, 0x01,
115 0x09, 0x02,
116 0x09, 0x04,
117 0x09, 0x07,
118 0x09, 0x08,
119 0x09, 0x09,
120 0x09, 0x0A,
121 0x09, 0x0B,
122 0x09, 0x0C,
123 0x09, 0x0E,
124 0x09, 0x0F,
125 0x09, 0x0D,
126 0x81, 0x02,
127 0x75, 0x01,
128 0x95, 0x03,
129 0x81, 0x01,
130 0x05, 0x01,
131 0x25, 0x07,
132 0x46, 0x3B, 0x01,
133 0x75, 0x04,
134 0x95, 0x01,
135 0x65, 0x14,
136 0x09, 0x39,
137 0x81, 0x42,
138 0x65, 0x00,
139 0x95, 0x01,
140 0x81, 0x01,
141 0x26, 0xFF, 0x00,
142 0x46, 0xFF, 0x00,
143 0x09, 0x30,
144 0x09, 0x31,
145 0x09, 0x33,
146 0x09, 0x34,
147 0x75, 0x08,
148 0x95, 0x04,
149 0x81, 0x02,
150 0x95, 0x0A,
151 0x81, 0x01,
152 0x05, 0x01,
153 0x26, 0xFF, 0x00,
154 0x46, 0xFF, 0x00,
155 0x09, 0x32,
156 0x09, 0x35,
157 0x95, 0x02,
158 0x81, 0x02,
159 0x95, 0x08,
160 0x81, 0x01,
161 0x06, 0x00, 0xFF,
162 0xB1, 0x02,
163 0x0A, 0x21, 0x26,
164 0x95, 0x08,
165 0x91, 0x02,
166 0x0A, 0x21, 0x26,
167 0x95, 0x08,
168 0x81, 0x02,
169 0xC0,
170};
171
172#define NUM_LEDS 4
173
174struct bigben_device {
175 struct hid_device *hid;
176 struct hid_report *report;
177 u8 led_state;
178 u8 right_motor_on;
179 u8 left_motor_force;
180 struct led_classdev *leds[NUM_LEDS];
181 bool work_led;
182 bool work_ff;
183 struct work_struct worker;
184};
185
186
187static void bigben_worker(struct work_struct *work)
188{
189 struct bigben_device *bigben = container_of(work,
190 struct bigben_device, worker);
191 struct hid_field *report_field = bigben->report->field[0];
192
193 if (bigben->work_led) {
194 bigben->work_led = false;
195 report_field->value[0] = 0x01;
196 report_field->value[1] = 0x08;
197 report_field->value[2] = bigben->led_state;
198 report_field->value[3] = 0x00;
199 report_field->value[4] = 0x00;
200 report_field->value[5] = 0x00;
201 report_field->value[6] = 0x00;
202 report_field->value[7] = 0x00;
203 hid_hw_request(bigben->hid, bigben->report, HID_REQ_SET_REPORT);
204 }
205
206 if (bigben->work_ff) {
207 bigben->work_ff = false;
208 report_field->value[0] = 0x02;
209 report_field->value[1] = 0x08;
210 report_field->value[2] = bigben->right_motor_on;
211 report_field->value[3] = bigben->left_motor_force;
212 report_field->value[4] = 0xff;
213 report_field->value[5] = 0x00;
214 report_field->value[6] = 0x00;
215 report_field->value[7] = 0x00;
216 hid_hw_request(bigben->hid, bigben->report, HID_REQ_SET_REPORT);
217 }
218}
219
220static int hid_bigben_play_effect(struct input_dev *dev, void *data,
221 struct ff_effect *effect)
222{
223 struct bigben_device *bigben = data;
224 u8 right_motor_on;
225 u8 left_motor_force;
226
227 if (effect->type != FF_RUMBLE)
228 return 0;
229
230 right_motor_on = effect->u.rumble.weak_magnitude ? 1 : 0;
231 left_motor_force = effect->u.rumble.strong_magnitude / 256;
232
233 if (right_motor_on != bigben->right_motor_on ||
234 left_motor_force != bigben->left_motor_force) {
235 bigben->right_motor_on = right_motor_on;
236 bigben->left_motor_force = left_motor_force;
237 bigben->work_ff = true;
238 schedule_work(&bigben->worker);
239 }
240
241 return 0;
242}
243
244static void bigben_set_led(struct led_classdev *led,
245 enum led_brightness value)
246{
247 struct device *dev = led->dev->parent;
248 struct hid_device *hid = to_hid_device(dev);
249 struct bigben_device *bigben = hid_get_drvdata(hid);
250 int n;
251 bool work;
252
253 if (!bigben) {
254 hid_err(hid, "no device data\n");
255 return;
256 }
257
258 for (n = 0; n < NUM_LEDS; n++) {
259 if (led == bigben->leds[n]) {
260 if (value == LED_OFF) {
261 work = (bigben->led_state & BIT(n));
262 bigben->led_state &= ~BIT(n);
263 } else {
264 work = !(bigben->led_state & BIT(n));
265 bigben->led_state |= BIT(n);
266 }
267
268 if (work) {
269 bigben->work_led = true;
270 schedule_work(&bigben->worker);
271 }
272 return;
273 }
274 }
275}
276
277static enum led_brightness bigben_get_led(struct led_classdev *led)
278{
279 struct device *dev = led->dev->parent;
280 struct hid_device *hid = to_hid_device(dev);
281 struct bigben_device *bigben = hid_get_drvdata(hid);
282 int n;
283
284 if (!bigben) {
285 hid_err(hid, "no device data\n");
286 return LED_OFF;
287 }
288
289 for (n = 0; n < NUM_LEDS; n++) {
290 if (led == bigben->leds[n])
291 return (bigben->led_state & BIT(n)) ? LED_ON : LED_OFF;
292 }
293
294 return LED_OFF;
295}
296
297static void bigben_remove(struct hid_device *hid)
298{
299 struct bigben_device *bigben = hid_get_drvdata(hid);
300
301 cancel_work_sync(&bigben->worker);
302 hid_hw_close(hid);
303 hid_hw_stop(hid);
304}
305
306static int bigben_probe(struct hid_device *hid,
307 const struct hid_device_id *id)
308{
309 struct bigben_device *bigben;
310 struct hid_input *hidinput;
311 struct list_head *report_list;
312 struct led_classdev *led;
313 char *name;
314 size_t name_sz;
315 int n, error;
316
317 bigben = devm_kzalloc(&hid->dev, sizeof(*bigben), GFP_KERNEL);
318 if (!bigben)
319 return -ENOMEM;
320 hid_set_drvdata(hid, bigben);
321 bigben->hid = hid;
322
323 error = hid_parse(hid);
324 if (error) {
325 hid_err(hid, "parse failed\n");
326 return error;
327 }
328
329 error = hid_hw_start(hid, HID_CONNECT_DEFAULT & ~HID_CONNECT_FF);
330 if (error) {
331 hid_err(hid, "hw start failed\n");
332 return error;
333 }
334
335 report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list;
336 bigben->report = list_entry(report_list->next,
337 struct hid_report, list);
338
339 hidinput = list_first_entry(&hid->inputs, struct hid_input, list);
340 set_bit(FF_RUMBLE, hidinput->input->ffbit);
341
342 INIT_WORK(&bigben->worker, bigben_worker);
343
344 error = input_ff_create_memless(hidinput->input, bigben,
345 hid_bigben_play_effect);
346 if (error)
347 return error;
348
349 name_sz = strlen(dev_name(&hid->dev)) + strlen(":red:bigben#") + 1;
350
351 for (n = 0; n < NUM_LEDS; n++) {
352 led = devm_kzalloc(
353 &hid->dev,
354 sizeof(struct led_classdev) + name_sz,
355 GFP_KERNEL
356 );
357 if (!led)
358 return -ENOMEM;
359 name = (void *)(&led[1]);
360 snprintf(name, name_sz,
361 "%s:red:bigben%d",
362 dev_name(&hid->dev), n + 1
363 );
364 led->name = name;
365 led->brightness = (n == 0) ? LED_ON : LED_OFF;
366 led->max_brightness = 1;
367 led->brightness_get = bigben_get_led;
368 led->brightness_set = bigben_set_led;
369 bigben->leds[n] = led;
370 error = devm_led_classdev_register(&hid->dev, led);
371 if (error)
372 return error;
373 }
374
375
376 bigben->led_state = BIT(0);
377 bigben->right_motor_on = 0;
378 bigben->left_motor_force = 0;
379 bigben->work_led = true;
380 bigben->work_ff = true;
381 schedule_work(&bigben->worker);
382
383 hid_info(hid, "LED and force feedback support for BigBen gamepad\n");
384
385 return 0;
386}
387
388static __u8 *bigben_report_fixup(struct hid_device *hid, __u8 *rdesc,
389 unsigned int *rsize)
390{
391 if (*rsize == PID0902_RDESC_ORIG_SIZE) {
392 rdesc = pid0902_rdesc_fixed;
393 *rsize = sizeof(pid0902_rdesc_fixed);
394 } else
395 hid_warn(hid, "unexpected rdesc, please submit for review\n");
396 return rdesc;
397}
398
399static const struct hid_device_id bigben_devices[] = {
400 { HID_USB_DEVICE(USB_VENDOR_ID_BIGBEN, USB_DEVICE_ID_BIGBEN_PS3OFMINIPAD) },
401 { }
402};
403MODULE_DEVICE_TABLE(hid, bigben_devices);
404
405static struct hid_driver bigben_driver = {
406 .name = "bigben",
407 .id_table = bigben_devices,
408 .probe = bigben_probe,
409 .report_fixup = bigben_report_fixup,
410 .remove = bigben_remove,
411};
412module_hid_driver(bigben_driver);
413
414MODULE_LICENSE("GPL");
415