* [PATCH RFC v1 1/3] HID: nvidia-shield: Add mappings for consumer HID USAGE buttons
2023-05-29 22:20 [PATCH RFC v1 0/3] HID: nvidia-shield: More functionality on top of initial driver Rahul Rameshbabu
@ 2023-05-29 22:20 ` Rahul Rameshbabu
2023-05-29 22:20 ` [PATCH RFC v1 2/3] HID: nvidia-shield: Support LED functionality for Thunderstrike Rahul Rameshbabu
` (2 subsequent siblings)
3 siblings, 0 replies; 5+ messages in thread
From: Rahul Rameshbabu @ 2023-05-29 22:20 UTC (permalink / raw)
To: Benjamin Tissoires, Jiri Kosina
Cc: linux-input, linux-kernel, Rahul Rameshbabu
Map Android Home, Back, Search, VolumeUp, VolumeDown, and PlayPause buttons
to the appropriate input event codes.
Signed-off-by: Rahul Rameshbabu <rrameshbabu@nvidia.com>
---
drivers/hid/hid-nvidia-shield.c | 55 ++++++++++++++++++++++++++++++---
1 file changed, 50 insertions(+), 5 deletions(-)
diff --git a/drivers/hid/hid-nvidia-shield.c b/drivers/hid/hid-nvidia-shield.c
index bcf345e365c0..1a9d32b2c80c 100644
--- a/drivers/hid/hid-nvidia-shield.c
+++ b/drivers/hid/hid-nvidia-shield.c
@@ -15,6 +15,16 @@
#include "hid-ids.h"
#define NOT_INIT_STR "NOT INITIALIZED"
+#define android_map_key(c) hid_map_usage(hi, usage, bit, max, EV_KEY, (c))
+
+enum {
+ HID_USAGE_ANDROID_PLAYPAUSE_BTN = 0xcd, /* Double-tap volume slider */
+ HID_USAGE_ANDROID_VOLUMEUP_BTN = 0xe9,
+ HID_USAGE_ANDROID_VOLUMEDOWN_BTN = 0xea,
+ HID_USAGE_ANDROID_SEARCH_BTN = 0x221, /* NVIDIA btn on Thunderstrike */
+ HID_USAGE_ANDROID_HOME_BTN = 0x223,
+ HID_USAGE_ANDROID_BACK_BTN = 0x224,
+};
enum {
SHIELD_FW_VERSION_INITIALIZED = 0,
@@ -416,6 +426,40 @@ static struct shield_device *thunderstrike_create(struct hid_device *hdev)
return shield_dev;
}
+static int android_input_mapping(struct hid_device *hdev, struct hid_input *hi,
+ struct hid_field *field,
+ struct hid_usage *usage, unsigned long **bit,
+ int *max)
+{
+ if ((usage->hid & HID_USAGE_PAGE) != HID_UP_CONSUMER)
+ return 0;
+
+ switch (usage->hid & HID_USAGE) {
+ case HID_USAGE_ANDROID_PLAYPAUSE_BTN:
+ android_map_key(KEY_PLAYPAUSE);
+ break;
+ case HID_USAGE_ANDROID_VOLUMEUP_BTN:
+ android_map_key(KEY_VOLUMEUP);
+ break;
+ case HID_USAGE_ANDROID_VOLUMEDOWN_BTN:
+ android_map_key(KEY_VOLUMEDOWN);
+ break;
+ case HID_USAGE_ANDROID_SEARCH_BTN:
+ android_map_key(BTN_Z);
+ break;
+ case HID_USAGE_ANDROID_HOME_BTN:
+ android_map_key(BTN_MODE);
+ break;
+ case HID_USAGE_ANDROID_BACK_BTN:
+ android_map_key(BTN_SELECT);
+ break;
+ default:
+ return 0;
+ }
+
+ return 1;
+}
+
static ssize_t firmware_version_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
@@ -571,11 +615,12 @@ static const struct hid_device_id shield_devices[] = {
MODULE_DEVICE_TABLE(hid, shield_devices);
static struct hid_driver shield_driver = {
- .name = "shield",
- .id_table = shield_devices,
- .probe = shield_probe,
- .remove = shield_remove,
- .raw_event = shield_raw_event,
+ .name = "shield",
+ .id_table = shield_devices,
+ .input_mapping = android_input_mapping,
+ .probe = shield_probe,
+ .remove = shield_remove,
+ .raw_event = shield_raw_event,
.driver = {
.dev_groups = shield_device_groups,
},
--
2.38.4
^ permalink raw reply related [flat|nested] 5+ messages in thread* [PATCH RFC v1 2/3] HID: nvidia-shield: Support LED functionality for Thunderstrike
2023-05-29 22:20 [PATCH RFC v1 0/3] HID: nvidia-shield: More functionality on top of initial driver Rahul Rameshbabu
2023-05-29 22:20 ` [PATCH RFC v1 1/3] HID: nvidia-shield: Add mappings for consumer HID USAGE buttons Rahul Rameshbabu
@ 2023-05-29 22:20 ` Rahul Rameshbabu
2023-05-29 22:20 ` [PATCH RFC v1 3/3] HID: nvidia-shield: Remove space prefix from label in shield_haptics_create Rahul Rameshbabu
2023-06-09 15:53 ` [PATCH RFC v1 0/3] HID: nvidia-shield: More functionality on top of initial driver Jiri Kosina
3 siblings, 0 replies; 5+ messages in thread
From: Rahul Rameshbabu @ 2023-05-29 22:20 UTC (permalink / raw)
To: Benjamin Tissoires, Jiri Kosina
Cc: linux-input, linux-kernel, Rahul Rameshbabu
Expose the 2017 SHIELD controller (Thunderstrike) LED through the kernel
LED API.
Signed-off-by: Rahul Rameshbabu <rrameshbabu@nvidia.com>
---
drivers/hid/hid-nvidia-shield.c | 116 ++++++++++++++++++++++++++++++--
1 file changed, 111 insertions(+), 5 deletions(-)
diff --git a/drivers/hid/hid-nvidia-shield.c b/drivers/hid/hid-nvidia-shield.c
index 1a9d32b2c80c..7dfaec1c07e2 100644
--- a/drivers/hid/hid-nvidia-shield.c
+++ b/drivers/hid/hid-nvidia-shield.c
@@ -8,6 +8,7 @@
#include <linux/hid.h>
#include <linux/input-event-codes.h>
#include <linux/input.h>
+#include <linux/leds.h>
#include <linux/module.h>
#include <linux/spinlock.h>
#include <linux/workqueue.h>
@@ -35,6 +36,7 @@ enum {
THUNDERSTRIKE_FW_VERSION_UPDATE = 0,
THUNDERSTRIKE_BOARD_INFO_UPDATE,
THUNDERSTRIKE_HAPTICS_UPDATE,
+ THUNDERSTRIKE_LED_UPDATE,
};
enum {
@@ -45,12 +47,19 @@ enum {
enum {
THUNDERSTRIKE_HOSTCMD_ID_FW_VERSION = 1,
+ THUNDERSTRIKE_HOSTCMD_ID_LED = 6,
THUNDERSTRIKE_HOSTCMD_ID_BOARD_INFO = 16,
THUNDERSTRIKE_HOSTCMD_ID_USB_INIT = 53,
THUNDERSTRIKE_HOSTCMD_ID_HAPTICS = 57,
THUNDERSTRIKE_HOSTCMD_ID_BLUETOOTH_INIT = 58,
};
+enum thunderstrike_led_state {
+ THUNDERSTRIKE_LED_OFF = 1,
+ THUNDERSTRIKE_LED_ON = 8,
+} __packed;
+static_assert(sizeof(enum thunderstrike_led_state) == 1);
+
struct thunderstrike_hostcmd_board_info {
__le16 revision;
__le16 serial[7];
@@ -70,6 +79,7 @@ struct thunderstrike_hostcmd_resp_report {
struct thunderstrike_hostcmd_board_info board_info;
struct thunderstrike_hostcmd_haptics motors;
__le16 fw_version;
+ enum thunderstrike_led_state led_state;
u8 payload[30];
};
} __packed;
@@ -81,10 +91,16 @@ struct thunderstrike_hostcmd_req_report {
u8 cmd_id;
u8 reserved_at_10;
- struct {
- u8 update;
- struct thunderstrike_hostcmd_haptics motors;
- } haptics;
+ union {
+ struct {
+ u8 update;
+ enum thunderstrike_led_state state;
+ } led;
+ struct {
+ u8 update;
+ struct thunderstrike_hostcmd_haptics motors;
+ } haptics;
+ };
u8 reserved_at_30[27];
} __packed;
static_assert(sizeof(struct thunderstrike_hostcmd_req_report) ==
@@ -108,12 +124,15 @@ struct thunderstrike {
/* Sub-devices */
struct input_dev *haptics_dev;
+ struct led_classdev led_dev;
/* Resources */
void *req_report_dmabuf;
unsigned long update_flags;
struct thunderstrike_hostcmd_haptics haptics_val;
spinlock_t haptics_update_lock;
+ u8 led_state : 1;
+ enum thunderstrike_led_state led_value;
struct work_struct hostcmd_req_work;
};
@@ -221,6 +240,13 @@ static void thunderstrike_hostcmd_req_work_handler(struct work_struct *work)
thunderstrike_send_hostcmd_request(ts);
}
+ if (test_and_clear_bit(THUNDERSTRIKE_LED_UPDATE, &ts->update_flags)) {
+ thunderstrike_hostcmd_req_report_init(report, THUNDERSTRIKE_HOSTCMD_ID_LED);
+ report->led.update = 1;
+ report->led.state = ts->led_value;
+ thunderstrike_send_hostcmd_request(ts);
+ }
+
if (test_and_clear_bit(THUNDERSTRIKE_BOARD_INFO_UPDATE, &ts->update_flags)) {
thunderstrike_hostcmd_req_report_init(
report, THUNDERSTRIKE_HOSTCMD_ID_BOARD_INFO);
@@ -292,6 +318,40 @@ static int thunderstrike_play_effect(struct input_dev *idev, void *data,
return thunderstrike_update_haptics(ts, &motors);
}
+static enum led_brightness
+thunderstrike_led_get_brightness(struct led_classdev *led)
+{
+ struct hid_device *hdev = to_hid_device(led->dev->parent);
+ struct shield_device *shield_dev = hid_get_drvdata(hdev);
+ struct thunderstrike *ts;
+
+ ts = container_of(shield_dev, struct thunderstrike, base);
+
+ return ts->led_state;
+}
+
+static void thunderstrike_led_set_brightness(struct led_classdev *led,
+ enum led_brightness value)
+{
+ struct hid_device *hdev = to_hid_device(led->dev->parent);
+ struct shield_device *shield_dev = hid_get_drvdata(hdev);
+ struct thunderstrike *ts;
+
+ ts = container_of(shield_dev, struct thunderstrike, base);
+
+ switch (value) {
+ case LED_OFF:
+ ts->led_value = THUNDERSTRIKE_LED_OFF;
+ break;
+ default:
+ ts->led_value = THUNDERSTRIKE_LED_ON;
+ break;
+ }
+
+ set_bit(THUNDERSTRIKE_LED_UPDATE, &ts->update_flags);
+ schedule_work(&ts->hostcmd_req_work);
+}
+
static void
thunderstrike_parse_fw_version_payload(struct shield_device *shield_dev,
__le16 fw_version)
@@ -338,6 +398,24 @@ thunderstrike_parse_haptics_payload(struct shield_device *shield_dev,
haptics->motor_left, haptics->motor_right);
}
+static void
+thunderstrike_parse_led_payload(struct shield_device *shield_dev,
+ enum thunderstrike_led_state led_state)
+{
+ struct thunderstrike *ts = container_of(shield_dev, struct thunderstrike, base);
+
+ switch (led_state) {
+ case THUNDERSTRIKE_LED_OFF:
+ ts->led_state = 0;
+ break;
+ case THUNDERSTRIKE_LED_ON:
+ ts->led_state = 1;
+ break;
+ }
+
+ hid_dbg(shield_dev->hdev, "Thunderstrike led HOSTCMD response, 0x%02X\n", led_state);
+}
+
static int thunderstrike_parse_report(struct shield_device *shield_dev,
struct hid_report *report, u8 *data,
int size)
@@ -364,6 +442,9 @@ static int thunderstrike_parse_report(struct shield_device *shield_dev,
thunderstrike_parse_fw_version_payload(
shield_dev, hostcmd_resp_report->fw_version);
break;
+ case THUNDERSTRIKE_HOSTCMD_ID_LED:
+ thunderstrike_parse_led_payload(shield_dev, hostcmd_resp_report->led_state);
+ break;
case THUNDERSTRIKE_HOSTCMD_ID_BOARD_INFO:
thunderstrike_parse_board_info_payload(
shield_dev, &hostcmd_resp_report->board_info);
@@ -395,10 +476,24 @@ static int thunderstrike_parse_report(struct shield_device *shield_dev,
return 0;
}
+static inline int thunderstrike_led_create(struct thunderstrike *ts)
+{
+ struct led_classdev *led = &ts->led_dev;
+
+ led->name = "thunderstrike:blue:led";
+ led->max_brightness = 1;
+ led->flags = LED_CORE_SUSPENDRESUME;
+ led->brightness_get = &thunderstrike_led_get_brightness;
+ led->brightness_set = &thunderstrike_led_set_brightness;
+
+ return led_classdev_register(&ts->base.hdev->dev, led);
+}
+
static struct shield_device *thunderstrike_create(struct hid_device *hdev)
{
struct shield_device *shield_dev;
struct thunderstrike *ts;
+ int ret;
ts = devm_kzalloc(&hdev->dev, sizeof(*ts), GFP_KERNEL);
if (!ts)
@@ -418,12 +513,22 @@ static struct shield_device *thunderstrike_create(struct hid_device *hdev)
hid_set_drvdata(hdev, shield_dev);
+ ret = thunderstrike_led_create(ts);
+ if (ret) {
+ hid_err(hdev, "Failed to create Thunderstrike LED instance\n");
+ return ERR_PTR(ret);
+ }
+
ts->haptics_dev = shield_haptics_create(shield_dev, thunderstrike_play_effect);
if (IS_ERR(ts->haptics_dev))
- return ERR_CAST(ts->haptics_dev);
+ goto err;
hid_info(hdev, "Registered Thunderstrike controller\n");
return shield_dev;
+
+err:
+ led_classdev_unregister(&ts->led_dev);
+ return ERR_CAST(ts->haptics_dev);
}
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)
ts = container_of(dev, struct thunderstrike, base);
hid_hw_close(hdev);
+ led_classdev_unregister(&ts->led_dev);
if (ts->haptics_dev)
input_unregister_device(ts->haptics_dev);
cancel_work_sync(&ts->hostcmd_req_work);
--
2.38.4
^ permalink raw reply related [flat|nested] 5+ messages in thread