This source file includes following definitions.
- bigben_worker
- hid_bigben_play_effect
- bigben_set_led
- bigben_get_led
- bigben_remove
- bigben_probe
- bigben_report_fixup
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
102 static __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
174 struct bigben_device {
175 struct hid_device *hid;
176 struct hid_report *report;
177 bool removed;
178 u8 led_state;
179 u8 right_motor_on;
180 u8 left_motor_force;
181 struct led_classdev *leds[NUM_LEDS];
182 bool work_led;
183 bool work_ff;
184 struct work_struct worker;
185 };
186
187
188 static void bigben_worker(struct work_struct *work)
189 {
190 struct bigben_device *bigben = container_of(work,
191 struct bigben_device, worker);
192 struct hid_field *report_field = bigben->report->field[0];
193
194 if (bigben->removed)
195 return;
196
197 if (bigben->work_led) {
198 bigben->work_led = false;
199 report_field->value[0] = 0x01;
200 report_field->value[1] = 0x08;
201 report_field->value[2] = bigben->led_state;
202 report_field->value[3] = 0x00;
203 report_field->value[4] = 0x00;
204 report_field->value[5] = 0x00;
205 report_field->value[6] = 0x00;
206 report_field->value[7] = 0x00;
207 hid_hw_request(bigben->hid, bigben->report, HID_REQ_SET_REPORT);
208 }
209
210 if (bigben->work_ff) {
211 bigben->work_ff = false;
212 report_field->value[0] = 0x02;
213 report_field->value[1] = 0x08;
214 report_field->value[2] = bigben->right_motor_on;
215 report_field->value[3] = bigben->left_motor_force;
216 report_field->value[4] = 0xff;
217 report_field->value[5] = 0x00;
218 report_field->value[6] = 0x00;
219 report_field->value[7] = 0x00;
220 hid_hw_request(bigben->hid, bigben->report, HID_REQ_SET_REPORT);
221 }
222 }
223
224 static int hid_bigben_play_effect(struct input_dev *dev, void *data,
225 struct ff_effect *effect)
226 {
227 struct hid_device *hid = input_get_drvdata(dev);
228 struct bigben_device *bigben = hid_get_drvdata(hid);
229 u8 right_motor_on;
230 u8 left_motor_force;
231
232 if (!bigben) {
233 hid_err(hid, "no device data\n");
234 return 0;
235 }
236
237 if (effect->type != FF_RUMBLE)
238 return 0;
239
240 right_motor_on = effect->u.rumble.weak_magnitude ? 1 : 0;
241 left_motor_force = effect->u.rumble.strong_magnitude / 256;
242
243 if (right_motor_on != bigben->right_motor_on ||
244 left_motor_force != bigben->left_motor_force) {
245 bigben->right_motor_on = right_motor_on;
246 bigben->left_motor_force = left_motor_force;
247 bigben->work_ff = true;
248 schedule_work(&bigben->worker);
249 }
250
251 return 0;
252 }
253
254 static void bigben_set_led(struct led_classdev *led,
255 enum led_brightness value)
256 {
257 struct device *dev = led->dev->parent;
258 struct hid_device *hid = to_hid_device(dev);
259 struct bigben_device *bigben = hid_get_drvdata(hid);
260 int n;
261 bool work;
262
263 if (!bigben) {
264 hid_err(hid, "no device data\n");
265 return;
266 }
267
268 for (n = 0; n < NUM_LEDS; n++) {
269 if (led == bigben->leds[n]) {
270 if (value == LED_OFF) {
271 work = (bigben->led_state & BIT(n));
272 bigben->led_state &= ~BIT(n);
273 } else {
274 work = !(bigben->led_state & BIT(n));
275 bigben->led_state |= BIT(n);
276 }
277
278 if (work) {
279 bigben->work_led = true;
280 schedule_work(&bigben->worker);
281 }
282 return;
283 }
284 }
285 }
286
287 static enum led_brightness bigben_get_led(struct led_classdev *led)
288 {
289 struct device *dev = led->dev->parent;
290 struct hid_device *hid = to_hid_device(dev);
291 struct bigben_device *bigben = hid_get_drvdata(hid);
292 int n;
293
294 if (!bigben) {
295 hid_err(hid, "no device data\n");
296 return LED_OFF;
297 }
298
299 for (n = 0; n < NUM_LEDS; n++) {
300 if (led == bigben->leds[n])
301 return (bigben->led_state & BIT(n)) ? LED_ON : LED_OFF;
302 }
303
304 return LED_OFF;
305 }
306
307 static void bigben_remove(struct hid_device *hid)
308 {
309 struct bigben_device *bigben = hid_get_drvdata(hid);
310
311 bigben->removed = true;
312 cancel_work_sync(&bigben->worker);
313 hid_hw_stop(hid);
314 }
315
316 static int bigben_probe(struct hid_device *hid,
317 const struct hid_device_id *id)
318 {
319 struct bigben_device *bigben;
320 struct hid_input *hidinput;
321 struct list_head *report_list;
322 struct led_classdev *led;
323 char *name;
324 size_t name_sz;
325 int n, error;
326
327 bigben = devm_kzalloc(&hid->dev, sizeof(*bigben), GFP_KERNEL);
328 if (!bigben)
329 return -ENOMEM;
330 hid_set_drvdata(hid, bigben);
331 bigben->hid = hid;
332 bigben->removed = false;
333
334 error = hid_parse(hid);
335 if (error) {
336 hid_err(hid, "parse failed\n");
337 return error;
338 }
339
340 error = hid_hw_start(hid, HID_CONNECT_DEFAULT & ~HID_CONNECT_FF);
341 if (error) {
342 hid_err(hid, "hw start failed\n");
343 return error;
344 }
345
346 report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list;
347 bigben->report = list_entry(report_list->next,
348 struct hid_report, list);
349
350 hidinput = list_first_entry(&hid->inputs, struct hid_input, list);
351 set_bit(FF_RUMBLE, hidinput->input->ffbit);
352
353 INIT_WORK(&bigben->worker, bigben_worker);
354
355 error = input_ff_create_memless(hidinput->input, NULL,
356 hid_bigben_play_effect);
357 if (error)
358 goto error_hw_stop;
359
360 name_sz = strlen(dev_name(&hid->dev)) + strlen(":red:bigben#") + 1;
361
362 for (n = 0; n < NUM_LEDS; n++) {
363 led = devm_kzalloc(
364 &hid->dev,
365 sizeof(struct led_classdev) + name_sz,
366 GFP_KERNEL
367 );
368 if (!led) {
369 error = -ENOMEM;
370 goto error_hw_stop;
371 }
372 name = (void *)(&led[1]);
373 snprintf(name, name_sz,
374 "%s:red:bigben%d",
375 dev_name(&hid->dev), n + 1
376 );
377 led->name = name;
378 led->brightness = (n == 0) ? LED_ON : LED_OFF;
379 led->max_brightness = 1;
380 led->brightness_get = bigben_get_led;
381 led->brightness_set = bigben_set_led;
382 bigben->leds[n] = led;
383 error = devm_led_classdev_register(&hid->dev, led);
384 if (error)
385 goto error_hw_stop;
386 }
387
388
389 bigben->led_state = BIT(0);
390 bigben->right_motor_on = 0;
391 bigben->left_motor_force = 0;
392 bigben->work_led = true;
393 bigben->work_ff = true;
394 schedule_work(&bigben->worker);
395
396 hid_info(hid, "LED and force feedback support for BigBen gamepad\n");
397
398 return 0;
399
400 error_hw_stop:
401 hid_hw_stop(hid);
402 return error;
403 }
404
405 static __u8 *bigben_report_fixup(struct hid_device *hid, __u8 *rdesc,
406 unsigned int *rsize)
407 {
408 if (*rsize == PID0902_RDESC_ORIG_SIZE) {
409 rdesc = pid0902_rdesc_fixed;
410 *rsize = sizeof(pid0902_rdesc_fixed);
411 } else
412 hid_warn(hid, "unexpected rdesc, please submit for review\n");
413 return rdesc;
414 }
415
416 static const struct hid_device_id bigben_devices[] = {
417 { HID_USB_DEVICE(USB_VENDOR_ID_BIGBEN, USB_DEVICE_ID_BIGBEN_PS3OFMINIPAD) },
418 { }
419 };
420 MODULE_DEVICE_TABLE(hid, bigben_devices);
421
422 static struct hid_driver bigben_driver = {
423 .name = "bigben",
424 .id_table = bigben_devices,
425 .probe = bigben_probe,
426 .report_fixup = bigben_report_fixup,
427 .remove = bigben_remove,
428 };
429 module_hid_driver(bigben_driver);
430
431 MODULE_LICENSE("GPL");