Skip to content

Commit f88af60

Browse files
Binary-EaterJiri Kosina
authored andcommitted
HID: nvidia-shield: Support LED functionality for Thunderstrike
Expose the 2017 SHIELD controller (Thunderstrike) LED through the kernel LED API. Signed-off-by: Rahul Rameshbabu <[email protected]> Signed-off-by: Jiri Kosina <[email protected]>
1 parent 13d02c6 commit f88af60

File tree

1 file changed

+111
-5
lines changed

1 file changed

+111
-5
lines changed

drivers/hid/hid-nvidia-shield.c

Lines changed: 111 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#include <linux/hid.h>
99
#include <linux/input-event-codes.h>
1010
#include <linux/input.h>
11+
#include <linux/leds.h>
1112
#include <linux/module.h>
1213
#include <linux/spinlock.h>
1314
#include <linux/workqueue.h>
@@ -35,6 +36,7 @@ enum {
3536
THUNDERSTRIKE_FW_VERSION_UPDATE = 0,
3637
THUNDERSTRIKE_BOARD_INFO_UPDATE,
3738
THUNDERSTRIKE_HAPTICS_UPDATE,
39+
THUNDERSTRIKE_LED_UPDATE,
3840
};
3941

4042
enum {
@@ -45,12 +47,19 @@ enum {
4547

4648
enum {
4749
THUNDERSTRIKE_HOSTCMD_ID_FW_VERSION = 1,
50+
THUNDERSTRIKE_HOSTCMD_ID_LED = 6,
4851
THUNDERSTRIKE_HOSTCMD_ID_BOARD_INFO = 16,
4952
THUNDERSTRIKE_HOSTCMD_ID_USB_INIT = 53,
5053
THUNDERSTRIKE_HOSTCMD_ID_HAPTICS = 57,
5154
THUNDERSTRIKE_HOSTCMD_ID_BLUETOOTH_INIT = 58,
5255
};
5356

57+
enum thunderstrike_led_state {
58+
THUNDERSTRIKE_LED_OFF = 1,
59+
THUNDERSTRIKE_LED_ON = 8,
60+
} __packed;
61+
static_assert(sizeof(enum thunderstrike_led_state) == 1);
62+
5463
struct thunderstrike_hostcmd_board_info {
5564
__le16 revision;
5665
__le16 serial[7];
@@ -70,6 +79,7 @@ struct thunderstrike_hostcmd_resp_report {
7079
struct thunderstrike_hostcmd_board_info board_info;
7180
struct thunderstrike_hostcmd_haptics motors;
7281
__le16 fw_version;
82+
enum thunderstrike_led_state led_state;
7383
u8 payload[30];
7484
};
7585
} __packed;
@@ -81,10 +91,16 @@ struct thunderstrike_hostcmd_req_report {
8191
u8 cmd_id;
8292
u8 reserved_at_10;
8393

84-
struct {
85-
u8 update;
86-
struct thunderstrike_hostcmd_haptics motors;
87-
} haptics;
94+
union {
95+
struct {
96+
u8 update;
97+
enum thunderstrike_led_state state;
98+
} led;
99+
struct {
100+
u8 update;
101+
struct thunderstrike_hostcmd_haptics motors;
102+
} haptics;
103+
};
88104
u8 reserved_at_30[27];
89105
} __packed;
90106
static_assert(sizeof(struct thunderstrike_hostcmd_req_report) ==
@@ -108,12 +124,15 @@ struct thunderstrike {
108124

109125
/* Sub-devices */
110126
struct input_dev *haptics_dev;
127+
struct led_classdev led_dev;
111128

112129
/* Resources */
113130
void *req_report_dmabuf;
114131
unsigned long update_flags;
115132
struct thunderstrike_hostcmd_haptics haptics_val;
116133
spinlock_t haptics_update_lock;
134+
u8 led_state : 1;
135+
enum thunderstrike_led_state led_value;
117136
struct work_struct hostcmd_req_work;
118137
};
119138

@@ -221,6 +240,13 @@ static void thunderstrike_hostcmd_req_work_handler(struct work_struct *work)
221240
thunderstrike_send_hostcmd_request(ts);
222241
}
223242

243+
if (test_and_clear_bit(THUNDERSTRIKE_LED_UPDATE, &ts->update_flags)) {
244+
thunderstrike_hostcmd_req_report_init(report, THUNDERSTRIKE_HOSTCMD_ID_LED);
245+
report->led.update = 1;
246+
report->led.state = ts->led_value;
247+
thunderstrike_send_hostcmd_request(ts);
248+
}
249+
224250
if (test_and_clear_bit(THUNDERSTRIKE_BOARD_INFO_UPDATE, &ts->update_flags)) {
225251
thunderstrike_hostcmd_req_report_init(
226252
report, THUNDERSTRIKE_HOSTCMD_ID_BOARD_INFO);
@@ -292,6 +318,40 @@ static int thunderstrike_play_effect(struct input_dev *idev, void *data,
292318
return thunderstrike_update_haptics(ts, &motors);
293319
}
294320

321+
static enum led_brightness
322+
thunderstrike_led_get_brightness(struct led_classdev *led)
323+
{
324+
struct hid_device *hdev = to_hid_device(led->dev->parent);
325+
struct shield_device *shield_dev = hid_get_drvdata(hdev);
326+
struct thunderstrike *ts;
327+
328+
ts = container_of(shield_dev, struct thunderstrike, base);
329+
330+
return ts->led_state;
331+
}
332+
333+
static void thunderstrike_led_set_brightness(struct led_classdev *led,
334+
enum led_brightness value)
335+
{
336+
struct hid_device *hdev = to_hid_device(led->dev->parent);
337+
struct shield_device *shield_dev = hid_get_drvdata(hdev);
338+
struct thunderstrike *ts;
339+
340+
ts = container_of(shield_dev, struct thunderstrike, base);
341+
342+
switch (value) {
343+
case LED_OFF:
344+
ts->led_value = THUNDERSTRIKE_LED_OFF;
345+
break;
346+
default:
347+
ts->led_value = THUNDERSTRIKE_LED_ON;
348+
break;
349+
}
350+
351+
set_bit(THUNDERSTRIKE_LED_UPDATE, &ts->update_flags);
352+
schedule_work(&ts->hostcmd_req_work);
353+
}
354+
295355
static void
296356
thunderstrike_parse_fw_version_payload(struct shield_device *shield_dev,
297357
__le16 fw_version)
@@ -338,6 +398,24 @@ thunderstrike_parse_haptics_payload(struct shield_device *shield_dev,
338398
haptics->motor_left, haptics->motor_right);
339399
}
340400

401+
static void
402+
thunderstrike_parse_led_payload(struct shield_device *shield_dev,
403+
enum thunderstrike_led_state led_state)
404+
{
405+
struct thunderstrike *ts = container_of(shield_dev, struct thunderstrike, base);
406+
407+
switch (led_state) {
408+
case THUNDERSTRIKE_LED_OFF:
409+
ts->led_state = 0;
410+
break;
411+
case THUNDERSTRIKE_LED_ON:
412+
ts->led_state = 1;
413+
break;
414+
}
415+
416+
hid_dbg(shield_dev->hdev, "Thunderstrike led HOSTCMD response, 0x%02X\n", led_state);
417+
}
418+
341419
static int thunderstrike_parse_report(struct shield_device *shield_dev,
342420
struct hid_report *report, u8 *data,
343421
int size)
@@ -364,6 +442,9 @@ static int thunderstrike_parse_report(struct shield_device *shield_dev,
364442
thunderstrike_parse_fw_version_payload(
365443
shield_dev, hostcmd_resp_report->fw_version);
366444
break;
445+
case THUNDERSTRIKE_HOSTCMD_ID_LED:
446+
thunderstrike_parse_led_payload(shield_dev, hostcmd_resp_report->led_state);
447+
break;
367448
case THUNDERSTRIKE_HOSTCMD_ID_BOARD_INFO:
368449
thunderstrike_parse_board_info_payload(
369450
shield_dev, &hostcmd_resp_report->board_info);
@@ -395,10 +476,24 @@ static int thunderstrike_parse_report(struct shield_device *shield_dev,
395476
return 0;
396477
}
397478

479+
static inline int thunderstrike_led_create(struct thunderstrike *ts)
480+
{
481+
struct led_classdev *led = &ts->led_dev;
482+
483+
led->name = "thunderstrike:blue:led";
484+
led->max_brightness = 1;
485+
led->flags = LED_CORE_SUSPENDRESUME;
486+
led->brightness_get = &thunderstrike_led_get_brightness;
487+
led->brightness_set = &thunderstrike_led_set_brightness;
488+
489+
return led_classdev_register(&ts->base.hdev->dev, led);
490+
}
491+
398492
static struct shield_device *thunderstrike_create(struct hid_device *hdev)
399493
{
400494
struct shield_device *shield_dev;
401495
struct thunderstrike *ts;
496+
int ret;
402497

403498
ts = devm_kzalloc(&hdev->dev, sizeof(*ts), GFP_KERNEL);
404499
if (!ts)
@@ -418,12 +513,22 @@ static struct shield_device *thunderstrike_create(struct hid_device *hdev)
418513

419514
hid_set_drvdata(hdev, shield_dev);
420515

516+
ret = thunderstrike_led_create(ts);
517+
if (ret) {
518+
hid_err(hdev, "Failed to create Thunderstrike LED instance\n");
519+
return ERR_PTR(ret);
520+
}
521+
421522
ts->haptics_dev = shield_haptics_create(shield_dev, thunderstrike_play_effect);
422523
if (IS_ERR(ts->haptics_dev))
423-
return ERR_CAST(ts->haptics_dev);
524+
goto err;
424525

425526
hid_info(hdev, "Registered Thunderstrike controller\n");
426527
return shield_dev;
528+
529+
err:
530+
led_classdev_unregister(&ts->led_dev);
531+
return ERR_CAST(ts->haptics_dev);
427532
}
428533

429534
static int android_input_mapping(struct hid_device *hdev, struct hid_input *hi,
@@ -599,6 +704,7 @@ static void shield_remove(struct hid_device *hdev)
599704
ts = container_of(dev, struct thunderstrike, base);
600705

601706
hid_hw_close(hdev);
707+
led_classdev_unregister(&ts->led_dev);
602708
if (ts->haptics_dev)
603709
input_unregister_device(ts->haptics_dev);
604710
cancel_work_sync(&ts->hostcmd_req_work);

0 commit comments

Comments
 (0)