summaryrefslogtreecommitdiffstats
path: root/drivers/hid
diff options
context:
space:
mode:
authorFrank Praznik <frank.praznik@oh.rr.com>2014-01-11 15:13:15 -0500
committerJiri Kosina <jkosina@suse.cz>2014-01-16 16:44:35 -0500
commit60781cf487e3aae5134b5fec85fe60ece31ff627 (patch)
tree9f89d7489e844cedfbb17539e834ffcfff51c5c1 /drivers/hid
parent0bd88dd3dd5e73e5d43b8d1e7a96b841978df562 (diff)
HID: sony: Add LED controls for the Dualshock 4
Add LED lightbar controls for the Dualshock 4. The Dualshock 4 light bar has 3 separate RGB LEDs that can range in brightness from 0 to 255 so a full byte is now needed to store each LED's state Changed the module to support an arbitrary number of LEDs instead of being hardcoded to 4. Signed-off-by: Frank Praznik <frank.praznik@oh.rr.com> Signed-off-by: Jiri Kosina <jkosina@suse.cz>
Diffstat (limited to 'drivers/hid')
-rw-r--r--drivers/hid/hid-sony.c77
1 files changed, 50 insertions, 27 deletions
diff --git a/drivers/hid/hid-sony.c b/drivers/hid/hid-sony.c
index 8020d10ce703..79e0d5808a92 100644
--- a/drivers/hid/hid-sony.c
+++ b/drivers/hid/hid-sony.c
@@ -40,7 +40,9 @@
40#define PS3REMOTE BIT(4) 40#define PS3REMOTE BIT(4)
41#define DUALSHOCK4_CONTROLLER BIT(5) 41#define DUALSHOCK4_CONTROLLER BIT(5)
42 42
43#define SONY_LED_SUPPORT (SIXAXIS_CONTROLLER_USB | BUZZ_CONTROLLER) 43#define SONY_LED_SUPPORT (SIXAXIS_CONTROLLER_USB | BUZZ_CONTROLLER | DUALSHOCK4_CONTROLLER)
44
45#define MAX_LEDS 4
44 46
45static const u8 sixaxis_rdesc_fixup[] = { 47static const u8 sixaxis_rdesc_fixup[] = {
46 0x95, 0x13, 0x09, 0x01, 0x81, 0x02, 0x95, 0x0C, 48 0x95, 0x13, 0x09, 0x01, 0x81, 0x02, 0x95, 0x0C,
@@ -227,7 +229,7 @@ static const unsigned int buzz_keymap[] = {
227 229
228struct sony_sc { 230struct sony_sc {
229 struct hid_device *hdev; 231 struct hid_device *hdev;
230 struct led_classdev *leds[4]; 232 struct led_classdev *leds[MAX_LEDS];
231 unsigned long quirks; 233 unsigned long quirks;
232 struct work_struct state_worker; 234 struct work_struct state_worker;
233 235
@@ -236,7 +238,8 @@ struct sony_sc {
236 __u8 right; 238 __u8 right;
237#endif 239#endif
238 240
239 __u8 led_state; 241 __u8 led_state[MAX_LEDS];
242 __u8 led_count;
240}; 243};
241 244
242static __u8 *ps3remote_fixup(struct hid_device *hdev, __u8 *rdesc, 245static __u8 *ps3remote_fixup(struct hid_device *hdev, __u8 *rdesc,
@@ -447,7 +450,7 @@ static int sixaxis_set_operational_bt(struct hid_device *hdev)
447 return hdev->hid_output_raw_report(hdev, buf, sizeof(buf), HID_FEATURE_REPORT); 450 return hdev->hid_output_raw_report(hdev, buf, sizeof(buf), HID_FEATURE_REPORT);
448} 451}
449 452
450static void buzz_set_leds(struct hid_device *hdev, int leds) 453static void buzz_set_leds(struct hid_device *hdev, const __u8 *leds)
451{ 454{
452 struct list_head *report_list = 455 struct list_head *report_list =
453 &hdev->report_enum[HID_OUTPUT_REPORT].report_list; 456 &hdev->report_enum[HID_OUTPUT_REPORT].report_list;
@@ -456,23 +459,28 @@ static void buzz_set_leds(struct hid_device *hdev, int leds)
456 __s32 *value = report->field[0]->value; 459 __s32 *value = report->field[0]->value;
457 460
458 value[0] = 0x00; 461 value[0] = 0x00;
459 value[1] = (leds & 1) ? 0xff : 0x00; 462 value[1] = leds[0] ? 0xff : 0x00;
460 value[2] = (leds & 2) ? 0xff : 0x00; 463 value[2] = leds[1] ? 0xff : 0x00;
461 value[3] = (leds & 4) ? 0xff : 0x00; 464 value[3] = leds[2] ? 0xff : 0x00;
462 value[4] = (leds & 8) ? 0xff : 0x00; 465 value[4] = leds[3] ? 0xff : 0x00;
463 value[5] = 0x00; 466 value[5] = 0x00;
464 value[6] = 0x00; 467 value[6] = 0x00;
465 hid_hw_request(hdev, report, HID_REQ_SET_REPORT); 468 hid_hw_request(hdev, report, HID_REQ_SET_REPORT);
466} 469}
467 470
468static void sony_set_leds(struct hid_device *hdev, __u8 leds) 471static void sony_set_leds(struct hid_device *hdev, const __u8 *leds, int count)
469{ 472{
470 struct sony_sc *drv_data = hid_get_drvdata(hdev); 473 struct sony_sc *drv_data = hid_get_drvdata(hdev);
474 int n;
471 475
472 if (drv_data->quirks & BUZZ_CONTROLLER) { 476 BUG_ON(count > MAX_LEDS);
477
478 if (drv_data->quirks & BUZZ_CONTROLLER && count == 4) {
473 buzz_set_leds(hdev, leds); 479 buzz_set_leds(hdev, leds);
474 } else if (drv_data->quirks & SIXAXIS_CONTROLLER_USB) { 480 } else if ((drv_data->quirks & SIXAXIS_CONTROLLER_USB) ||
475 drv_data->led_state = leds; 481 (drv_data->quirks & DUALSHOCK4_CONTROLLER)) {
482 for (n = 0; n < count; n++)
483 drv_data->led_state[n] = leds[n];
476 schedule_work(&drv_data->state_worker); 484 schedule_work(&drv_data->state_worker);
477 } 485 }
478} 486}
@@ -492,15 +500,11 @@ static void sony_led_set_brightness(struct led_classdev *led,
492 return; 500 return;
493 } 501 }
494 502
495 for (n = 0; n < 4; n++) { 503 for (n = 0; n < drv_data->led_count; n++) {
496 if (led == drv_data->leds[n]) { 504 if (led == drv_data->leds[n]) {
497 int on = !!(drv_data->led_state & (1 << n)); 505 if (value != drv_data->led_state[n]) {
498 if (value == LED_OFF && on) { 506 drv_data->led_state[n] = value;
499 drv_data->led_state &= ~(1 << n); 507 sony_set_leds(hdev, drv_data->led_state, drv_data->led_count);
500 sony_set_leds(hdev, drv_data->led_state);
501 } else if (value != LED_OFF && !on) {
502 drv_data->led_state |= (1 << n);
503 sony_set_leds(hdev, drv_data->led_state);
504 } 508 }
505 break; 509 break;
506 } 510 }
@@ -522,9 +526,9 @@ static enum led_brightness sony_led_get_brightness(struct led_classdev *led)
522 return LED_OFF; 526 return LED_OFF;
523 } 527 }
524 528
525 for (n = 0; n < 4; n++) { 529 for (n = 0; n < drv_data->led_count; n++) {
526 if (led == drv_data->leds[n]) { 530 if (led == drv_data->leds[n]) {
527 on = !!(drv_data->led_state & (1 << n)); 531 on = !!(drv_data->led_state[n]);
528 break; 532 break;
529 } 533 }
530 } 534 }
@@ -541,7 +545,7 @@ static void sony_leds_remove(struct hid_device *hdev)
541 drv_data = hid_get_drvdata(hdev); 545 drv_data = hid_get_drvdata(hdev);
542 BUG_ON(!(drv_data->quirks & SONY_LED_SUPPORT)); 546 BUG_ON(!(drv_data->quirks & SONY_LED_SUPPORT));
543 547
544 for (n = 0; n < 4; n++) { 548 for (n = 0; n < drv_data->led_count; n++) {
545 led = drv_data->leds[n]; 549 led = drv_data->leds[n];
546 drv_data->leds[n] = NULL; 550 drv_data->leds[n] = NULL;
547 if (!led) 551 if (!led)
@@ -549,17 +553,21 @@ static void sony_leds_remove(struct hid_device *hdev)
549 led_classdev_unregister(led); 553 led_classdev_unregister(led);
550 kfree(led); 554 kfree(led);
551 } 555 }
556
557 drv_data->led_count = 0;
552} 558}
553 559
554static int sony_leds_init(struct hid_device *hdev) 560static int sony_leds_init(struct hid_device *hdev)
555{ 561{
556 struct sony_sc *drv_data; 562 struct sony_sc *drv_data;
557 int n, ret = 0; 563 int n, ret = 0;
564 int max_brightness;
558 struct led_classdev *led; 565 struct led_classdev *led;
559 size_t name_sz; 566 size_t name_sz;
560 char *name; 567 char *name;
561 size_t name_len; 568 size_t name_len;
562 const char *name_fmt; 569 const char *name_fmt;
570 static const __u8 initial_values[MAX_LEDS] = { 0x00, 0x00, 0x00, 0x00 };
563 571
564 drv_data = hid_get_drvdata(hdev); 572 drv_data = hid_get_drvdata(hdev);
565 BUG_ON(!(drv_data->quirks & SONY_LED_SUPPORT)); 573 BUG_ON(!(drv_data->quirks & SONY_LED_SUPPORT));
@@ -575,14 +583,22 @@ static int sony_leds_init(struct hid_device *hdev)
575 name_fmt = "%s::sony%d"; 583 name_fmt = "%s::sony%d";
576 } 584 }
577 585
586 if (drv_data->quirks & DUALSHOCK4_CONTROLLER) {
587 drv_data->led_count = 3;
588 max_brightness = 255;
589 } else {
590 drv_data->led_count = 4;
591 max_brightness = 1;
592 }
593
578 /* Clear LEDs as we have no way of reading their initial state. This is 594 /* Clear LEDs as we have no way of reading their initial state. This is
579 * only relevant if the driver is loaded after somebody actively set the 595 * only relevant if the driver is loaded after somebody actively set the
580 * LEDs to on */ 596 * LEDs to on */
581 sony_set_leds(hdev, 0x00); 597 sony_set_leds(hdev, initial_values, drv_data->led_count);
582 598
583 name_sz = strlen(dev_name(&hdev->dev)) + name_len + 1; 599 name_sz = strlen(dev_name(&hdev->dev)) + name_len + 1;
584 600
585 for (n = 0; n < 4; n++) { 601 for (n = 0; n < drv_data->led_count; n++) {
586 led = kzalloc(sizeof(struct led_classdev) + name_sz, GFP_KERNEL); 602 led = kzalloc(sizeof(struct led_classdev) + name_sz, GFP_KERNEL);
587 if (!led) { 603 if (!led) {
588 hid_err(hdev, "Couldn't allocate memory for LED %d\n", n); 604 hid_err(hdev, "Couldn't allocate memory for LED %d\n", n);
@@ -594,7 +610,7 @@ static int sony_leds_init(struct hid_device *hdev)
594 snprintf(name, name_sz, name_fmt, dev_name(&hdev->dev), n + 1); 610 snprintf(name, name_sz, name_fmt, dev_name(&hdev->dev), n + 1);
595 led->name = name; 611 led->name = name;
596 led->brightness = 0; 612 led->brightness = 0;
597 led->max_brightness = 1; 613 led->max_brightness = max_brightness;
598 led->brightness_get = sony_led_get_brightness; 614 led->brightness_get = sony_led_get_brightness;
599 led->brightness_set = sony_led_set_brightness; 615 led->brightness_set = sony_led_set_brightness;
600 616
@@ -635,7 +651,10 @@ static void sony_state_worker(struct work_struct *work)
635 buf[5] = sc->left; 651 buf[5] = sc->left;
636#endif 652#endif
637 653
638 buf[10] |= (sc->led_state & 0xf) << 1; 654 buf[10] |= sc->led_state[0] << 1;
655 buf[10] |= sc->led_state[1] << 2;
656 buf[10] |= sc->led_state[2] << 3;
657 buf[10] |= sc->led_state[3] << 4;
639 658
640 sc->hdev->hid_output_raw_report(sc->hdev, buf, sizeof(buf), 659 sc->hdev->hid_output_raw_report(sc->hdev, buf, sizeof(buf),
641 HID_OUTPUT_REPORT); 660 HID_OUTPUT_REPORT);
@@ -660,6 +679,10 @@ static void dualshock4_state_worker(struct work_struct *work)
660 buf[5] = sc->left; 679 buf[5] = sc->left;
661#endif 680#endif
662 681
682 buf[6] = sc->led_state[0];
683 buf[7] = sc->led_state[1];
684 buf[8] = sc->led_state[2];
685
663 sc->hdev->hid_output_raw_report(sc->hdev, buf, sizeof(buf), 686 sc->hdev->hid_output_raw_report(sc->hdev, buf, sizeof(buf),
664 HID_OUTPUT_REPORT); 687 HID_OUTPUT_REPORT);
665} 688}