0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013 #include <linux/input.h>
0014 #include <linux/slab.h>
0015 #include <linux/module.h>
0016 #include <linux/leds.h>
0017 #include <linux/hid.h>
0018
0019 #include "hid-ids.h"
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047
0048
0049
0050
0051
0052
0053
0054
0055
0056
0057
0058
0059
0060
0061
0062
0063
0064
0065
0066
0067
0068
0069
0070
0071
0072
0073
0074
0075
0076
0077
0078
0079
0080
0081
0082
0083
0084
0085
0086
0087
0088
0089
0090
0091
0092 #define PID0902_RDESC_ORIG_SIZE 137
0093
0094
0095
0096
0097
0098
0099
0100
0101
0102 static __u8 pid0902_rdesc_fixed[] = {
0103 0x05, 0x01,
0104 0x09, 0x05,
0105 0xA1, 0x01,
0106 0x15, 0x00,
0107 0x25, 0x01,
0108 0x35, 0x00,
0109 0x45, 0x01,
0110 0x75, 0x01,
0111 0x95, 0x0D,
0112 0x05, 0x09,
0113 0x09, 0x05,
0114 0x09, 0x01,
0115 0x09, 0x02,
0116 0x09, 0x04,
0117 0x09, 0x07,
0118 0x09, 0x08,
0119 0x09, 0x09,
0120 0x09, 0x0A,
0121 0x09, 0x0B,
0122 0x09, 0x0C,
0123 0x09, 0x0E,
0124 0x09, 0x0F,
0125 0x09, 0x0D,
0126 0x81, 0x02,
0127 0x75, 0x01,
0128 0x95, 0x03,
0129 0x81, 0x01,
0130 0x05, 0x01,
0131 0x25, 0x07,
0132 0x46, 0x3B, 0x01,
0133 0x75, 0x04,
0134 0x95, 0x01,
0135 0x65, 0x14,
0136 0x09, 0x39,
0137 0x81, 0x42,
0138 0x65, 0x00,
0139 0x95, 0x01,
0140 0x81, 0x01,
0141 0x26, 0xFF, 0x00,
0142 0x46, 0xFF, 0x00,
0143 0x09, 0x30,
0144 0x09, 0x31,
0145 0x09, 0x33,
0146 0x09, 0x34,
0147 0x75, 0x08,
0148 0x95, 0x04,
0149 0x81, 0x02,
0150 0x95, 0x0A,
0151 0x81, 0x01,
0152 0x05, 0x01,
0153 0x26, 0xFF, 0x00,
0154 0x46, 0xFF, 0x00,
0155 0x09, 0x32,
0156 0x09, 0x35,
0157 0x95, 0x02,
0158 0x81, 0x02,
0159 0x95, 0x08,
0160 0x81, 0x01,
0161 0x06, 0x00, 0xFF,
0162 0xB1, 0x02,
0163 0x0A, 0x21, 0x26,
0164 0x95, 0x08,
0165 0x91, 0x02,
0166 0x0A, 0x21, 0x26,
0167 0x95, 0x08,
0168 0x81, 0x02,
0169 0xC0,
0170 };
0171
0172 #define NUM_LEDS 4
0173
0174 struct bigben_device {
0175 struct hid_device *hid;
0176 struct hid_report *report;
0177 bool removed;
0178 u8 led_state;
0179 u8 right_motor_on;
0180 u8 left_motor_force;
0181 struct led_classdev *leds[NUM_LEDS];
0182 bool work_led;
0183 bool work_ff;
0184 struct work_struct worker;
0185 };
0186
0187
0188 static void bigben_worker(struct work_struct *work)
0189 {
0190 struct bigben_device *bigben = container_of(work,
0191 struct bigben_device, worker);
0192 struct hid_field *report_field = bigben->report->field[0];
0193
0194 if (bigben->removed || !report_field)
0195 return;
0196
0197 if (bigben->work_led) {
0198 bigben->work_led = false;
0199 report_field->value[0] = 0x01;
0200 report_field->value[1] = 0x08;
0201 report_field->value[2] = bigben->led_state;
0202 report_field->value[3] = 0x00;
0203 report_field->value[4] = 0x00;
0204 report_field->value[5] = 0x00;
0205 report_field->value[6] = 0x00;
0206 report_field->value[7] = 0x00;
0207 hid_hw_request(bigben->hid, bigben->report, HID_REQ_SET_REPORT);
0208 }
0209
0210 if (bigben->work_ff) {
0211 bigben->work_ff = false;
0212 report_field->value[0] = 0x02;
0213 report_field->value[1] = 0x08;
0214 report_field->value[2] = bigben->right_motor_on;
0215 report_field->value[3] = bigben->left_motor_force;
0216 report_field->value[4] = 0xff;
0217 report_field->value[5] = 0x00;
0218 report_field->value[6] = 0x00;
0219 report_field->value[7] = 0x00;
0220 hid_hw_request(bigben->hid, bigben->report, HID_REQ_SET_REPORT);
0221 }
0222 }
0223
0224 static int hid_bigben_play_effect(struct input_dev *dev, void *data,
0225 struct ff_effect *effect)
0226 {
0227 struct hid_device *hid = input_get_drvdata(dev);
0228 struct bigben_device *bigben = hid_get_drvdata(hid);
0229 u8 right_motor_on;
0230 u8 left_motor_force;
0231
0232 if (!bigben) {
0233 hid_err(hid, "no device data\n");
0234 return 0;
0235 }
0236
0237 if (effect->type != FF_RUMBLE)
0238 return 0;
0239
0240 right_motor_on = effect->u.rumble.weak_magnitude ? 1 : 0;
0241 left_motor_force = effect->u.rumble.strong_magnitude / 256;
0242
0243 if (right_motor_on != bigben->right_motor_on ||
0244 left_motor_force != bigben->left_motor_force) {
0245 bigben->right_motor_on = right_motor_on;
0246 bigben->left_motor_force = left_motor_force;
0247 bigben->work_ff = true;
0248 schedule_work(&bigben->worker);
0249 }
0250
0251 return 0;
0252 }
0253
0254 static void bigben_set_led(struct led_classdev *led,
0255 enum led_brightness value)
0256 {
0257 struct device *dev = led->dev->parent;
0258 struct hid_device *hid = to_hid_device(dev);
0259 struct bigben_device *bigben = hid_get_drvdata(hid);
0260 int n;
0261 bool work;
0262
0263 if (!bigben) {
0264 hid_err(hid, "no device data\n");
0265 return;
0266 }
0267
0268 for (n = 0; n < NUM_LEDS; n++) {
0269 if (led == bigben->leds[n]) {
0270 if (value == LED_OFF) {
0271 work = (bigben->led_state & BIT(n));
0272 bigben->led_state &= ~BIT(n);
0273 } else {
0274 work = !(bigben->led_state & BIT(n));
0275 bigben->led_state |= BIT(n);
0276 }
0277
0278 if (work) {
0279 bigben->work_led = true;
0280 schedule_work(&bigben->worker);
0281 }
0282 return;
0283 }
0284 }
0285 }
0286
0287 static enum led_brightness bigben_get_led(struct led_classdev *led)
0288 {
0289 struct device *dev = led->dev->parent;
0290 struct hid_device *hid = to_hid_device(dev);
0291 struct bigben_device *bigben = hid_get_drvdata(hid);
0292 int n;
0293
0294 if (!bigben) {
0295 hid_err(hid, "no device data\n");
0296 return LED_OFF;
0297 }
0298
0299 for (n = 0; n < NUM_LEDS; n++) {
0300 if (led == bigben->leds[n])
0301 return (bigben->led_state & BIT(n)) ? LED_ON : LED_OFF;
0302 }
0303
0304 return LED_OFF;
0305 }
0306
0307 static void bigben_remove(struct hid_device *hid)
0308 {
0309 struct bigben_device *bigben = hid_get_drvdata(hid);
0310
0311 bigben->removed = true;
0312 cancel_work_sync(&bigben->worker);
0313 hid_hw_stop(hid);
0314 }
0315
0316 static int bigben_probe(struct hid_device *hid,
0317 const struct hid_device_id *id)
0318 {
0319 struct bigben_device *bigben;
0320 struct hid_input *hidinput;
0321 struct list_head *report_list;
0322 struct led_classdev *led;
0323 char *name;
0324 size_t name_sz;
0325 int n, error;
0326
0327 bigben = devm_kzalloc(&hid->dev, sizeof(*bigben), GFP_KERNEL);
0328 if (!bigben)
0329 return -ENOMEM;
0330 hid_set_drvdata(hid, bigben);
0331 bigben->hid = hid;
0332 bigben->removed = false;
0333
0334 error = hid_parse(hid);
0335 if (error) {
0336 hid_err(hid, "parse failed\n");
0337 return error;
0338 }
0339
0340 error = hid_hw_start(hid, HID_CONNECT_DEFAULT & ~HID_CONNECT_FF);
0341 if (error) {
0342 hid_err(hid, "hw start failed\n");
0343 return error;
0344 }
0345
0346 report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list;
0347 bigben->report = list_entry(report_list->next,
0348 struct hid_report, list);
0349
0350 if (list_empty(&hid->inputs)) {
0351 hid_err(hid, "no inputs found\n");
0352 error = -ENODEV;
0353 goto error_hw_stop;
0354 }
0355
0356 hidinput = list_first_entry(&hid->inputs, struct hid_input, list);
0357 set_bit(FF_RUMBLE, hidinput->input->ffbit);
0358
0359 INIT_WORK(&bigben->worker, bigben_worker);
0360
0361 error = input_ff_create_memless(hidinput->input, NULL,
0362 hid_bigben_play_effect);
0363 if (error)
0364 goto error_hw_stop;
0365
0366 name_sz = strlen(dev_name(&hid->dev)) + strlen(":red:bigben#") + 1;
0367
0368 for (n = 0; n < NUM_LEDS; n++) {
0369 led = devm_kzalloc(
0370 &hid->dev,
0371 sizeof(struct led_classdev) + name_sz,
0372 GFP_KERNEL
0373 );
0374 if (!led) {
0375 error = -ENOMEM;
0376 goto error_hw_stop;
0377 }
0378 name = (void *)(&led[1]);
0379 snprintf(name, name_sz,
0380 "%s:red:bigben%d",
0381 dev_name(&hid->dev), n + 1
0382 );
0383 led->name = name;
0384 led->brightness = (n == 0) ? LED_ON : LED_OFF;
0385 led->max_brightness = 1;
0386 led->brightness_get = bigben_get_led;
0387 led->brightness_set = bigben_set_led;
0388 bigben->leds[n] = led;
0389 error = devm_led_classdev_register(&hid->dev, led);
0390 if (error)
0391 goto error_hw_stop;
0392 }
0393
0394
0395 bigben->led_state = BIT(0);
0396 bigben->right_motor_on = 0;
0397 bigben->left_motor_force = 0;
0398 bigben->work_led = true;
0399 bigben->work_ff = true;
0400 schedule_work(&bigben->worker);
0401
0402 hid_info(hid, "LED and force feedback support for BigBen gamepad\n");
0403
0404 return 0;
0405
0406 error_hw_stop:
0407 hid_hw_stop(hid);
0408 return error;
0409 }
0410
0411 static __u8 *bigben_report_fixup(struct hid_device *hid, __u8 *rdesc,
0412 unsigned int *rsize)
0413 {
0414 if (*rsize == PID0902_RDESC_ORIG_SIZE) {
0415 rdesc = pid0902_rdesc_fixed;
0416 *rsize = sizeof(pid0902_rdesc_fixed);
0417 } else
0418 hid_warn(hid, "unexpected rdesc, please submit for review\n");
0419 return rdesc;
0420 }
0421
0422 static const struct hid_device_id bigben_devices[] = {
0423 { HID_USB_DEVICE(USB_VENDOR_ID_BIGBEN, USB_DEVICE_ID_BIGBEN_PS3OFMINIPAD) },
0424 { }
0425 };
0426 MODULE_DEVICE_TABLE(hid, bigben_devices);
0427
0428 static struct hid_driver bigben_driver = {
0429 .name = "bigben",
0430 .id_table = bigben_devices,
0431 .probe = bigben_probe,
0432 .report_fixup = bigben_report_fixup,
0433 .remove = bigben_remove,
0434 };
0435 module_hid_driver(bigben_driver);
0436
0437 MODULE_LICENSE("GPL");