1 // SPDX-License-Identifier: GPL-2.0+ 2 3 /* 4 * LED & force feedback support for BigBen Interactive 5 * 6 * 0x146b:0x0902 "Bigben Interactive Bigben Game Pad" 7 * "Kid-friendly Wired Controller" PS3OFMINIPAD SONY 8 * sold for use with the PS3 9 * 10 * Copyright (c) 2018 Hanno Zulla <kontakt@hanno.de> 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 * The original descriptor for 0x146b:0x0902 24 * 25 * 0x05, 0x01, // Usage Page (Generic Desktop Ctrls) 26 * 0x09, 0x05, // Usage (Game Pad) 27 * 0xA1, 0x01, // Collection (Application) 28 * 0x15, 0x00, // Logical Minimum (0) 29 * 0x25, 0x01, // Logical Maximum (1) 30 * 0x35, 0x00, // Physical Minimum (0) 31 * 0x45, 0x01, // Physical Maximum (1) 32 * 0x75, 0x01, // Report Size (1) 33 * 0x95, 0x0D, // Report Count (13) 34 * 0x05, 0x09, // Usage Page (Button) 35 * 0x19, 0x01, // Usage Minimum (0x01) 36 * 0x29, 0x0D, // Usage Maximum (0x0D) 37 * 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) 38 * 0x95, 0x03, // Report Count (3) 39 * 0x81, 0x01, // Input (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position) 40 * 0x05, 0x01, // Usage Page (Generic Desktop Ctrls) 41 * 0x25, 0x07, // Logical Maximum (7) 42 * 0x46, 0x3B, 0x01, // Physical Maximum (315) 43 * 0x75, 0x04, // Report Size (4) 44 * 0x95, 0x01, // Report Count (1) 45 * 0x65, 0x14, // Unit (System: English Rotation, Length: Centimeter) 46 * 0x09, 0x39, // Usage (Hat switch) 47 * 0x81, 0x42, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,Null State) 48 * 0x65, 0x00, // Unit (None) 49 * 0x95, 0x01, // Report Count (1) 50 * 0x81, 0x01, // Input (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position) 51 * 0x26, 0xFF, 0x00, // Logical Maximum (255) 52 * 0x46, 0xFF, 0x00, // Physical Maximum (255) 53 * 0x09, 0x30, // Usage (X) 54 * 0x09, 0x31, // Usage (Y) 55 * 0x09, 0x32, // Usage (Z) 56 * 0x09, 0x35, // Usage (Rz) 57 * 0x75, 0x08, // Report Size (8) 58 * 0x95, 0x04, // Report Count (4) 59 * 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) 60 * 0x06, 0x00, 0xFF, // Usage Page (Vendor Defined 0xFF00) 61 * 0x09, 0x20, // Usage (0x20) 62 * 0x09, 0x21, // Usage (0x21) 63 * 0x09, 0x22, // Usage (0x22) 64 * 0x09, 0x23, // Usage (0x23) 65 * 0x09, 0x24, // Usage (0x24) 66 * 0x09, 0x25, // Usage (0x25) 67 * 0x09, 0x26, // Usage (0x26) 68 * 0x09, 0x27, // Usage (0x27) 69 * 0x09, 0x28, // Usage (0x28) 70 * 0x09, 0x29, // Usage (0x29) 71 * 0x09, 0x2A, // Usage (0x2A) 72 * 0x09, 0x2B, // Usage (0x2B) 73 * 0x95, 0x0C, // Report Count (12) 74 * 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) 75 * 0x0A, 0x21, 0x26, // Usage (0x2621) 76 * 0x95, 0x08, // Report Count (8) 77 * 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) 78 * 0x0A, 0x21, 0x26, // Usage (0x2621) 79 * 0x91, 0x02, // Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) 80 * 0x26, 0xFF, 0x03, // Logical Maximum (1023) 81 * 0x46, 0xFF, 0x03, // Physical Maximum (1023) 82 * 0x09, 0x2C, // Usage (0x2C) 83 * 0x09, 0x2D, // Usage (0x2D) 84 * 0x09, 0x2E, // Usage (0x2E) 85 * 0x09, 0x2F, // Usage (0x2F) 86 * 0x75, 0x10, // Report Size (16) 87 * 0x95, 0x04, // Report Count (4) 88 * 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) 89 * 0xC0, // End Collection 90 */ 91 92 #define PID0902_RDESC_ORIG_SIZE 137 93 94 /* 95 * The fixed descriptor for 0x146b:0x0902 96 * 97 * - map buttons according to gamepad.rst 98 * - assign right stick from Z/Rz to Rx/Ry 99 * - map previously unused analog trigger data to Z/RZ 100 * - simplify feature and output descriptor 101 */ 102 static const __u8 pid0902_rdesc_fixed[] = { 103 0x05, 0x01, /* Usage Page (Generic Desktop Ctrls) */ 104 0x09, 0x05, /* Usage (Game Pad) */ 105 0xA1, 0x01, /* Collection (Application) */ 106 0x15, 0x00, /* Logical Minimum (0) */ 107 0x25, 0x01, /* Logical Maximum (1) */ 108 0x35, 0x00, /* Physical Minimum (0) */ 109 0x45, 0x01, /* Physical Maximum (1) */ 110 0x75, 0x01, /* Report Size (1) */ 111 0x95, 0x0D, /* Report Count (13) */ 112 0x05, 0x09, /* Usage Page (Button) */ 113 0x09, 0x05, /* Usage (BTN_WEST) */ 114 0x09, 0x01, /* Usage (BTN_SOUTH) */ 115 0x09, 0x02, /* Usage (BTN_EAST) */ 116 0x09, 0x04, /* Usage (BTN_NORTH) */ 117 0x09, 0x07, /* Usage (BTN_TL) */ 118 0x09, 0x08, /* Usage (BTN_TR) */ 119 0x09, 0x09, /* Usage (BTN_TL2) */ 120 0x09, 0x0A, /* Usage (BTN_TR2) */ 121 0x09, 0x0B, /* Usage (BTN_SELECT) */ 122 0x09, 0x0C, /* Usage (BTN_START) */ 123 0x09, 0x0E, /* Usage (BTN_THUMBL) */ 124 0x09, 0x0F, /* Usage (BTN_THUMBR) */ 125 0x09, 0x0D, /* Usage (BTN_MODE) */ 126 0x81, 0x02, /* Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) */ 127 0x75, 0x01, /* Report Size (1) */ 128 0x95, 0x03, /* Report Count (3) */ 129 0x81, 0x01, /* Input (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position) */ 130 0x05, 0x01, /* Usage Page (Generic Desktop Ctrls) */ 131 0x25, 0x07, /* Logical Maximum (7) */ 132 0x46, 0x3B, 0x01, /* Physical Maximum (315) */ 133 0x75, 0x04, /* Report Size (4) */ 134 0x95, 0x01, /* Report Count (1) */ 135 0x65, 0x14, /* Unit (System: English Rotation, Length: Centimeter) */ 136 0x09, 0x39, /* Usage (Hat switch) */ 137 0x81, 0x42, /* Input (Data,Var,Abs,No Wrap,Linear,Preferred State,Null State) */ 138 0x65, 0x00, /* Unit (None) */ 139 0x95, 0x01, /* Report Count (1) */ 140 0x81, 0x01, /* Input (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position) */ 141 0x26, 0xFF, 0x00, /* Logical Maximum (255) */ 142 0x46, 0xFF, 0x00, /* Physical Maximum (255) */ 143 0x09, 0x30, /* Usage (X) */ 144 0x09, 0x31, /* Usage (Y) */ 145 0x09, 0x33, /* Usage (Rx) */ 146 0x09, 0x34, /* Usage (Ry) */ 147 0x75, 0x08, /* Report Size (8) */ 148 0x95, 0x04, /* Report Count (4) */ 149 0x81, 0x02, /* Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) */ 150 0x95, 0x0A, /* Report Count (10) */ 151 0x81, 0x01, /* Input (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position) */ 152 0x05, 0x01, /* Usage Page (Generic Desktop Ctrls) */ 153 0x26, 0xFF, 0x00, /* Logical Maximum (255) */ 154 0x46, 0xFF, 0x00, /* Physical Maximum (255) */ 155 0x09, 0x32, /* Usage (Z) */ 156 0x09, 0x35, /* Usage (Rz) */ 157 0x95, 0x02, /* Report Count (2) */ 158 0x81, 0x02, /* Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) */ 159 0x95, 0x08, /* Report Count (8) */ 160 0x81, 0x01, /* Input (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position) */ 161 0x06, 0x00, 0xFF, /* Usage Page (Vendor Defined 0xFF00) */ 162 0xB1, 0x02, /* Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) */ 163 0x0A, 0x21, 0x26, /* Usage (0x2621) */ 164 0x95, 0x08, /* Report Count (8) */ 165 0x91, 0x02, /* Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) */ 166 0x0A, 0x21, 0x26, /* Usage (0x2621) */ 167 0x95, 0x08, /* Report Count (8) */ 168 0x81, 0x02, /* Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) */ 169 0xC0, /* End Collection */ 170 }; 171 172 #define NUM_LEDS 4 173 174 struct bigben_device { 175 struct hid_device *hid; 176 struct hid_report *report; 177 spinlock_t lock; 178 bool removed; 179 u8 led_state; /* LED1 = 1 .. LED4 = 8 */ 180 u8 right_motor_on; /* right motor off/on 0/1 */ 181 u8 left_motor_force; /* left motor force 0-255 */ 182 struct led_classdev *leds[NUM_LEDS]; 183 bool work_led; 184 bool work_ff; 185 struct work_struct worker; 186 }; 187 188 static inline void bigben_schedule_work(struct bigben_device *bigben) 189 { 190 unsigned long flags; 191 192 spin_lock_irqsave(&bigben->lock, flags); 193 if (!bigben->removed) 194 schedule_work(&bigben->worker); 195 spin_unlock_irqrestore(&bigben->lock, flags); 196 } 197 198 static void bigben_worker(struct work_struct *work) 199 { 200 struct bigben_device *bigben = container_of(work, 201 struct bigben_device, worker); 202 struct hid_field *report_field = bigben->report->field[0]; 203 bool do_work_led = false; 204 bool do_work_ff = false; 205 u8 *buf; 206 u32 len; 207 unsigned long flags; 208 209 buf = hid_alloc_report_buf(bigben->report, GFP_KERNEL); 210 if (!buf) 211 return; 212 213 len = hid_report_len(bigben->report); 214 215 /* LED work */ 216 spin_lock_irqsave(&bigben->lock, flags); 217 218 if (bigben->work_led) { 219 bigben->work_led = false; 220 do_work_led = true; 221 report_field->value[0] = 0x01; /* 1 = led message */ 222 report_field->value[1] = 0x08; /* reserved value, always 8 */ 223 report_field->value[2] = bigben->led_state; 224 report_field->value[3] = 0x00; /* padding */ 225 report_field->value[4] = 0x00; /* padding */ 226 report_field->value[5] = 0x00; /* padding */ 227 report_field->value[6] = 0x00; /* padding */ 228 report_field->value[7] = 0x00; /* padding */ 229 hid_output_report(bigben->report, buf); 230 } 231 232 spin_unlock_irqrestore(&bigben->lock, flags); 233 234 if (do_work_led) { 235 hid_hw_raw_request(bigben->hid, bigben->report->id, buf, len, 236 bigben->report->type, HID_REQ_SET_REPORT); 237 } 238 239 /* FF work */ 240 spin_lock_irqsave(&bigben->lock, flags); 241 242 if (bigben->work_ff) { 243 bigben->work_ff = false; 244 do_work_ff = true; 245 report_field->value[0] = 0x02; /* 2 = rumble effect message */ 246 report_field->value[1] = 0x08; /* reserved value, always 8 */ 247 report_field->value[2] = bigben->right_motor_on; 248 report_field->value[3] = bigben->left_motor_force; 249 report_field->value[4] = 0xff; /* duration 0-254 (255 = nonstop) */ 250 report_field->value[5] = 0x00; /* padding */ 251 report_field->value[6] = 0x00; /* padding */ 252 report_field->value[7] = 0x00; /* padding */ 253 hid_output_report(bigben->report, buf); 254 } 255 256 spin_unlock_irqrestore(&bigben->lock, flags); 257 258 if (do_work_ff) { 259 hid_hw_raw_request(bigben->hid, bigben->report->id, buf, len, 260 bigben->report->type, HID_REQ_SET_REPORT); 261 } 262 263 kfree(buf); 264 } 265 266 static int hid_bigben_play_effect(struct input_dev *dev, void *data, 267 struct ff_effect *effect) 268 { 269 struct hid_device *hid = input_get_drvdata(dev); 270 struct bigben_device *bigben = hid_get_drvdata(hid); 271 u8 right_motor_on; 272 u8 left_motor_force; 273 unsigned long flags; 274 275 if (!bigben) { 276 hid_err(hid, "no device data\n"); 277 return 0; 278 } 279 280 if (effect->type != FF_RUMBLE) 281 return 0; 282 283 right_motor_on = effect->u.rumble.weak_magnitude ? 1 : 0; 284 left_motor_force = effect->u.rumble.strong_magnitude / 256; 285 286 if (right_motor_on != bigben->right_motor_on || 287 left_motor_force != bigben->left_motor_force) { 288 spin_lock_irqsave(&bigben->lock, flags); 289 bigben->right_motor_on = right_motor_on; 290 bigben->left_motor_force = left_motor_force; 291 bigben->work_ff = true; 292 spin_unlock_irqrestore(&bigben->lock, flags); 293 294 bigben_schedule_work(bigben); 295 } 296 297 return 0; 298 } 299 300 static void bigben_set_led(struct led_classdev *led, 301 enum led_brightness value) 302 { 303 struct device *dev = led->dev->parent; 304 struct hid_device *hid = to_hid_device(dev); 305 struct bigben_device *bigben = hid_get_drvdata(hid); 306 int n; 307 bool work; 308 unsigned long flags; 309 310 if (!bigben) { 311 hid_err(hid, "no device data\n"); 312 return; 313 } 314 315 for (n = 0; n < NUM_LEDS; n++) { 316 if (led == bigben->leds[n]) { 317 spin_lock_irqsave(&bigben->lock, flags); 318 if (value == LED_OFF) { 319 work = (bigben->led_state & BIT(n)); 320 bigben->led_state &= ~BIT(n); 321 } else { 322 work = !(bigben->led_state & BIT(n)); 323 bigben->led_state |= BIT(n); 324 } 325 spin_unlock_irqrestore(&bigben->lock, flags); 326 327 if (work) { 328 bigben->work_led = true; 329 bigben_schedule_work(bigben); 330 } 331 return; 332 } 333 } 334 } 335 336 static enum led_brightness bigben_get_led(struct led_classdev *led) 337 { 338 struct device *dev = led->dev->parent; 339 struct hid_device *hid = to_hid_device(dev); 340 struct bigben_device *bigben = hid_get_drvdata(hid); 341 int n; 342 343 if (!bigben) { 344 hid_err(hid, "no device data\n"); 345 return LED_OFF; 346 } 347 348 for (n = 0; n < NUM_LEDS; n++) { 349 if (led == bigben->leds[n]) 350 return (bigben->led_state & BIT(n)) ? LED_ON : LED_OFF; 351 } 352 353 return LED_OFF; 354 } 355 356 static void bigben_remove(struct hid_device *hid) 357 { 358 struct bigben_device *bigben = hid_get_drvdata(hid); 359 unsigned long flags; 360 361 spin_lock_irqsave(&bigben->lock, flags); 362 bigben->removed = true; 363 spin_unlock_irqrestore(&bigben->lock, flags); 364 365 cancel_work_sync(&bigben->worker); 366 hid_hw_stop(hid); 367 } 368 369 static int bigben_probe(struct hid_device *hid, 370 const struct hid_device_id *id) 371 { 372 struct bigben_device *bigben; 373 struct hid_input *hidinput; 374 struct led_classdev *led; 375 char *name; 376 size_t name_sz; 377 int n, error; 378 379 bigben = devm_kzalloc(&hid->dev, sizeof(*bigben), GFP_KERNEL); 380 if (!bigben) 381 return -ENOMEM; 382 hid_set_drvdata(hid, bigben); 383 bigben->hid = hid; 384 bigben->removed = false; 385 386 error = hid_parse(hid); 387 if (error) { 388 hid_err(hid, "parse failed\n"); 389 return error; 390 } 391 392 error = hid_hw_start(hid, HID_CONNECT_DEFAULT & ~HID_CONNECT_FF); 393 if (error) { 394 hid_err(hid, "hw start failed\n"); 395 return error; 396 } 397 398 bigben->report = hid_validate_values(hid, HID_OUTPUT_REPORT, 0, 0, 8); 399 if (!bigben->report) { 400 hid_err(hid, "no output report found\n"); 401 error = -ENODEV; 402 goto error_hw_stop; 403 } 404 405 if (list_empty(&hid->inputs)) { 406 hid_err(hid, "no inputs found\n"); 407 error = -ENODEV; 408 goto error_hw_stop; 409 } 410 411 hidinput = list_first_entry(&hid->inputs, struct hid_input, list); 412 set_bit(FF_RUMBLE, hidinput->input->ffbit); 413 414 INIT_WORK(&bigben->worker, bigben_worker); 415 spin_lock_init(&bigben->lock); 416 417 error = input_ff_create_memless(hidinput->input, NULL, 418 hid_bigben_play_effect); 419 if (error) 420 goto error_hw_stop; 421 422 name_sz = strlen(dev_name(&hid->dev)) + strlen(":red:bigben#") + 1; 423 424 for (n = 0; n < NUM_LEDS; n++) { 425 led = devm_kzalloc( 426 &hid->dev, 427 sizeof(struct led_classdev) + name_sz, 428 GFP_KERNEL 429 ); 430 if (!led) { 431 error = -ENOMEM; 432 goto error_hw_stop; 433 } 434 name = (void *)(&led[1]); 435 snprintf(name, name_sz, 436 "%s:red:bigben%d", 437 dev_name(&hid->dev), n + 1 438 ); 439 led->name = name; 440 led->brightness = (n == 0) ? LED_ON : LED_OFF; 441 led->max_brightness = 1; 442 led->brightness_get = bigben_get_led; 443 led->brightness_set = bigben_set_led; 444 bigben->leds[n] = led; 445 error = devm_led_classdev_register(&hid->dev, led); 446 if (error) 447 goto error_hw_stop; 448 } 449 450 /* initial state: LED1 is on, no rumble effect */ 451 bigben->led_state = BIT(0); 452 bigben->right_motor_on = 0; 453 bigben->left_motor_force = 0; 454 bigben->work_led = true; 455 bigben->work_ff = true; 456 bigben_schedule_work(bigben); 457 458 hid_info(hid, "LED and force feedback support for BigBen gamepad\n"); 459 460 return 0; 461 462 error_hw_stop: 463 hid_hw_stop(hid); 464 return error; 465 } 466 467 static const __u8 *bigben_report_fixup(struct hid_device *hid, __u8 *rdesc, 468 unsigned int *rsize) 469 { 470 if (*rsize == PID0902_RDESC_ORIG_SIZE) { 471 *rsize = sizeof(pid0902_rdesc_fixed); 472 return pid0902_rdesc_fixed; 473 } else 474 hid_warn(hid, "unexpected rdesc, please submit for review\n"); 475 return rdesc; 476 } 477 478 static const struct hid_device_id bigben_devices[] = { 479 { HID_USB_DEVICE(USB_VENDOR_ID_BIGBEN, USB_DEVICE_ID_BIGBEN_PS3OFMINIPAD) }, 480 { } 481 }; 482 MODULE_DEVICE_TABLE(hid, bigben_devices); 483 484 static struct hid_driver bigben_driver = { 485 .name = "bigben", 486 .id_table = bigben_devices, 487 .probe = bigben_probe, 488 .report_fixup = bigben_report_fixup, 489 .remove = bigben_remove, 490 }; 491 module_hid_driver(bigben_driver); 492 493 MODULE_DESCRIPTION("LED & force feedback support for BigBen Interactive"); 494 MODULE_LICENSE("GPL"); 495