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>
3536 THUNDERSTRIKE_FW_VERSION_UPDATE = 0 ,
3637 THUNDERSTRIKE_BOARD_INFO_UPDATE ,
3738 THUNDERSTRIKE_HAPTICS_UPDATE ,
39+ THUNDERSTRIKE_LED_UPDATE ,
3840};
3941
4042enum {
@@ -45,12 +47,19 @@ enum {
4547
4648enum {
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+
5463struct 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 ;
90106static_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+
295355static void
296356thunderstrike_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+
341419static 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+
398492static 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
429534static 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