109308562SRahul Rameshbabu // SPDX-License-Identifier: GPL-2.0-or-later 209308562SRahul Rameshbabu /* 309308562SRahul Rameshbabu * Copyright (c) 2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved. 409308562SRahul Rameshbabu * 509308562SRahul Rameshbabu * HID driver for NVIDIA SHIELD peripherals. 609308562SRahul Rameshbabu */ 709308562SRahul Rameshbabu 809308562SRahul Rameshbabu #include <linux/hid.h> 909308562SRahul Rameshbabu #include <linux/input-event-codes.h> 1009308562SRahul Rameshbabu #include <linux/input.h> 1109308562SRahul Rameshbabu #include <linux/module.h> 1209308562SRahul Rameshbabu #include <linux/spinlock.h> 1309308562SRahul Rameshbabu #include <linux/workqueue.h> 1409308562SRahul Rameshbabu 1509308562SRahul Rameshbabu #include "hid-ids.h" 1609308562SRahul Rameshbabu 1709308562SRahul Rameshbabu #define NOT_INIT_STR "NOT INITIALIZED" 18*13d02c69SRahul Rameshbabu #define android_map_key(c) hid_map_usage(hi, usage, bit, max, EV_KEY, (c)) 19*13d02c69SRahul Rameshbabu 20*13d02c69SRahul Rameshbabu enum { 21*13d02c69SRahul Rameshbabu HID_USAGE_ANDROID_PLAYPAUSE_BTN = 0xcd, /* Double-tap volume slider */ 22*13d02c69SRahul Rameshbabu HID_USAGE_ANDROID_VOLUMEUP_BTN = 0xe9, 23*13d02c69SRahul Rameshbabu HID_USAGE_ANDROID_VOLUMEDOWN_BTN = 0xea, 24*13d02c69SRahul Rameshbabu HID_USAGE_ANDROID_SEARCH_BTN = 0x221, /* NVIDIA btn on Thunderstrike */ 25*13d02c69SRahul Rameshbabu HID_USAGE_ANDROID_HOME_BTN = 0x223, 26*13d02c69SRahul Rameshbabu HID_USAGE_ANDROID_BACK_BTN = 0x224, 27*13d02c69SRahul Rameshbabu }; 2809308562SRahul Rameshbabu 2909308562SRahul Rameshbabu enum { 3009308562SRahul Rameshbabu SHIELD_FW_VERSION_INITIALIZED = 0, 3109308562SRahul Rameshbabu SHIELD_BOARD_INFO_INITIALIZED, 3209308562SRahul Rameshbabu }; 3309308562SRahul Rameshbabu 3409308562SRahul Rameshbabu enum { 3509308562SRahul Rameshbabu THUNDERSTRIKE_FW_VERSION_UPDATE = 0, 3609308562SRahul Rameshbabu THUNDERSTRIKE_BOARD_INFO_UPDATE, 3709308562SRahul Rameshbabu THUNDERSTRIKE_HAPTICS_UPDATE, 3809308562SRahul Rameshbabu }; 3909308562SRahul Rameshbabu 4009308562SRahul Rameshbabu enum { 4109308562SRahul Rameshbabu THUNDERSTRIKE_HOSTCMD_REPORT_SIZE = 33, 4209308562SRahul Rameshbabu THUNDERSTRIKE_HOSTCMD_REQ_REPORT_ID = 0x4, 4309308562SRahul Rameshbabu THUNDERSTRIKE_HOSTCMD_RESP_REPORT_ID = 0x3, 4409308562SRahul Rameshbabu }; 4509308562SRahul Rameshbabu 4609308562SRahul Rameshbabu enum { 4709308562SRahul Rameshbabu THUNDERSTRIKE_HOSTCMD_ID_FW_VERSION = 1, 4809308562SRahul Rameshbabu THUNDERSTRIKE_HOSTCMD_ID_BOARD_INFO = 16, 4909308562SRahul Rameshbabu THUNDERSTRIKE_HOSTCMD_ID_USB_INIT = 53, 5009308562SRahul Rameshbabu THUNDERSTRIKE_HOSTCMD_ID_HAPTICS = 57, 5109308562SRahul Rameshbabu THUNDERSTRIKE_HOSTCMD_ID_BLUETOOTH_INIT = 58, 5209308562SRahul Rameshbabu }; 5309308562SRahul Rameshbabu 5409308562SRahul Rameshbabu struct thunderstrike_hostcmd_board_info { 5509308562SRahul Rameshbabu __le16 revision; 5609308562SRahul Rameshbabu __le16 serial[7]; 5709308562SRahul Rameshbabu }; 5809308562SRahul Rameshbabu 5909308562SRahul Rameshbabu struct thunderstrike_hostcmd_haptics { 6009308562SRahul Rameshbabu u8 motor_left; 6109308562SRahul Rameshbabu u8 motor_right; 6209308562SRahul Rameshbabu }; 6309308562SRahul Rameshbabu 6409308562SRahul Rameshbabu struct thunderstrike_hostcmd_resp_report { 6509308562SRahul Rameshbabu u8 report_id; /* THUNDERSTRIKE_HOSTCMD_RESP_REPORT_ID */ 6609308562SRahul Rameshbabu u8 cmd_id; 6709308562SRahul Rameshbabu u8 reserved_at_10; 6809308562SRahul Rameshbabu 6909308562SRahul Rameshbabu union { 7009308562SRahul Rameshbabu struct thunderstrike_hostcmd_board_info board_info; 7109308562SRahul Rameshbabu struct thunderstrike_hostcmd_haptics motors; 7209308562SRahul Rameshbabu __le16 fw_version; 7309308562SRahul Rameshbabu u8 payload[30]; 7409308562SRahul Rameshbabu }; 7509308562SRahul Rameshbabu } __packed; 7609308562SRahul Rameshbabu static_assert(sizeof(struct thunderstrike_hostcmd_resp_report) == 7709308562SRahul Rameshbabu THUNDERSTRIKE_HOSTCMD_REPORT_SIZE); 7809308562SRahul Rameshbabu 7909308562SRahul Rameshbabu struct thunderstrike_hostcmd_req_report { 8009308562SRahul Rameshbabu u8 report_id; /* THUNDERSTRIKE_HOSTCMD_REQ_REPORT_ID */ 8109308562SRahul Rameshbabu u8 cmd_id; 8209308562SRahul Rameshbabu u8 reserved_at_10; 8309308562SRahul Rameshbabu 8409308562SRahul Rameshbabu struct { 8509308562SRahul Rameshbabu u8 update; 8609308562SRahul Rameshbabu struct thunderstrike_hostcmd_haptics motors; 8709308562SRahul Rameshbabu } haptics; 8809308562SRahul Rameshbabu u8 reserved_at_30[27]; 8909308562SRahul Rameshbabu } __packed; 9009308562SRahul Rameshbabu static_assert(sizeof(struct thunderstrike_hostcmd_req_report) == 9109308562SRahul Rameshbabu THUNDERSTRIKE_HOSTCMD_REPORT_SIZE); 9209308562SRahul Rameshbabu 9309308562SRahul Rameshbabu /* Common struct for shield accessories. */ 9409308562SRahul Rameshbabu struct shield_device { 9509308562SRahul Rameshbabu struct hid_device *hdev; 9609308562SRahul Rameshbabu 9709308562SRahul Rameshbabu unsigned long initialized_flags; 9809308562SRahul Rameshbabu const char *codename; 9909308562SRahul Rameshbabu u16 fw_version; 10009308562SRahul Rameshbabu struct { 10109308562SRahul Rameshbabu u16 revision; 10209308562SRahul Rameshbabu char serial_number[15]; 10309308562SRahul Rameshbabu } board_info; 10409308562SRahul Rameshbabu }; 10509308562SRahul Rameshbabu 10609308562SRahul Rameshbabu struct thunderstrike { 10709308562SRahul Rameshbabu struct shield_device base; 10809308562SRahul Rameshbabu 10909308562SRahul Rameshbabu /* Sub-devices */ 11009308562SRahul Rameshbabu struct input_dev *haptics_dev; 11109308562SRahul Rameshbabu 11209308562SRahul Rameshbabu /* Resources */ 11309308562SRahul Rameshbabu void *req_report_dmabuf; 11409308562SRahul Rameshbabu unsigned long update_flags; 11509308562SRahul Rameshbabu struct thunderstrike_hostcmd_haptics haptics_val; 11609308562SRahul Rameshbabu spinlock_t haptics_update_lock; 11709308562SRahul Rameshbabu struct work_struct hostcmd_req_work; 11809308562SRahul Rameshbabu }; 11909308562SRahul Rameshbabu 12009308562SRahul Rameshbabu static inline void thunderstrike_hostcmd_req_report_init( 12109308562SRahul Rameshbabu struct thunderstrike_hostcmd_req_report *report, u8 cmd_id) 12209308562SRahul Rameshbabu { 12309308562SRahul Rameshbabu memset(report, 0, sizeof(*report)); 12409308562SRahul Rameshbabu report->report_id = THUNDERSTRIKE_HOSTCMD_REQ_REPORT_ID; 12509308562SRahul Rameshbabu report->cmd_id = cmd_id; 12609308562SRahul Rameshbabu } 12709308562SRahul Rameshbabu 12809308562SRahul Rameshbabu static inline void shield_strrev(char *dest, size_t len, u16 rev) 12909308562SRahul Rameshbabu { 13009308562SRahul Rameshbabu dest[0] = ('A' - 1) + (rev >> 8); 13109308562SRahul Rameshbabu snprintf(&dest[1], len - 1, "%02X", 0xff & rev); 13209308562SRahul Rameshbabu } 13309308562SRahul Rameshbabu 13409308562SRahul Rameshbabu static struct input_dev *shield_allocate_input_dev(struct hid_device *hdev, 13509308562SRahul Rameshbabu const char *name_suffix) 13609308562SRahul Rameshbabu { 13709308562SRahul Rameshbabu struct input_dev *idev; 13809308562SRahul Rameshbabu 13909308562SRahul Rameshbabu idev = input_allocate_device(); 14009308562SRahul Rameshbabu if (!idev) 14109308562SRahul Rameshbabu goto err_device; 14209308562SRahul Rameshbabu 14309308562SRahul Rameshbabu idev->id.bustype = hdev->bus; 14409308562SRahul Rameshbabu idev->id.vendor = hdev->vendor; 14509308562SRahul Rameshbabu idev->id.product = hdev->product; 14609308562SRahul Rameshbabu idev->id.version = hdev->version; 14709308562SRahul Rameshbabu idev->uniq = hdev->uniq; 14809308562SRahul Rameshbabu idev->name = devm_kasprintf(&idev->dev, GFP_KERNEL, "%s %s", hdev->name, 14909308562SRahul Rameshbabu name_suffix); 15009308562SRahul Rameshbabu if (!idev->name) 15109308562SRahul Rameshbabu goto err_name; 15209308562SRahul Rameshbabu 15309308562SRahul Rameshbabu input_set_drvdata(idev, hdev); 15409308562SRahul Rameshbabu 15509308562SRahul Rameshbabu return idev; 15609308562SRahul Rameshbabu 15709308562SRahul Rameshbabu err_name: 15809308562SRahul Rameshbabu input_free_device(idev); 15909308562SRahul Rameshbabu err_device: 16009308562SRahul Rameshbabu return ERR_PTR(-ENOMEM); 16109308562SRahul Rameshbabu } 16209308562SRahul Rameshbabu 16309308562SRahul Rameshbabu static struct input_dev *shield_haptics_create( 16409308562SRahul Rameshbabu struct shield_device *dev, 16509308562SRahul Rameshbabu int (*play_effect)(struct input_dev *, void *, struct ff_effect *)) 16609308562SRahul Rameshbabu { 16709308562SRahul Rameshbabu struct input_dev *haptics; 16809308562SRahul Rameshbabu int ret; 16909308562SRahul Rameshbabu 17009308562SRahul Rameshbabu if (!IS_ENABLED(CONFIG_NVIDIA_SHIELD_FF)) 17109308562SRahul Rameshbabu return NULL; 17209308562SRahul Rameshbabu 17309308562SRahul Rameshbabu haptics = shield_allocate_input_dev(dev->hdev, "Haptics"); 17409308562SRahul Rameshbabu if (IS_ERR(haptics)) 17509308562SRahul Rameshbabu return haptics; 17609308562SRahul Rameshbabu 17709308562SRahul Rameshbabu input_set_capability(haptics, EV_FF, FF_RUMBLE); 17809308562SRahul Rameshbabu input_ff_create_memless(haptics, NULL, play_effect); 17909308562SRahul Rameshbabu 18009308562SRahul Rameshbabu ret = input_register_device(haptics); 18109308562SRahul Rameshbabu if (ret) 18209308562SRahul Rameshbabu goto err; 18309308562SRahul Rameshbabu 18409308562SRahul Rameshbabu return haptics; 18509308562SRahul Rameshbabu 18609308562SRahul Rameshbabu err: 18709308562SRahul Rameshbabu input_free_device(haptics); 18809308562SRahul Rameshbabu return ERR_PTR(ret); 18909308562SRahul Rameshbabu } 19009308562SRahul Rameshbabu 19109308562SRahul Rameshbabu static inline void thunderstrike_send_hostcmd_request(struct thunderstrike *ts) 19209308562SRahul Rameshbabu { 19309308562SRahul Rameshbabu struct thunderstrike_hostcmd_req_report *report = ts->req_report_dmabuf; 19409308562SRahul Rameshbabu struct shield_device *shield_dev = &ts->base; 19509308562SRahul Rameshbabu int ret; 19609308562SRahul Rameshbabu 19709308562SRahul Rameshbabu ret = hid_hw_raw_request(shield_dev->hdev, report->report_id, 19809308562SRahul Rameshbabu ts->req_report_dmabuf, 19909308562SRahul Rameshbabu THUNDERSTRIKE_HOSTCMD_REPORT_SIZE, 20009308562SRahul Rameshbabu HID_OUTPUT_REPORT, HID_REQ_SET_REPORT); 20109308562SRahul Rameshbabu 20209308562SRahul Rameshbabu if (ret < 0) { 20309308562SRahul Rameshbabu hid_err(shield_dev->hdev, 20409308562SRahul Rameshbabu "Failed to output Thunderstrike HOSTCMD request HID report due to %pe\n", 20509308562SRahul Rameshbabu ERR_PTR(ret)); 20609308562SRahul Rameshbabu } 20709308562SRahul Rameshbabu } 20809308562SRahul Rameshbabu 20909308562SRahul Rameshbabu static void thunderstrike_hostcmd_req_work_handler(struct work_struct *work) 21009308562SRahul Rameshbabu { 21109308562SRahul Rameshbabu struct thunderstrike *ts = 21209308562SRahul Rameshbabu container_of(work, struct thunderstrike, hostcmd_req_work); 21309308562SRahul Rameshbabu struct thunderstrike_hostcmd_req_report *report; 21409308562SRahul Rameshbabu unsigned long flags; 21509308562SRahul Rameshbabu 21609308562SRahul Rameshbabu report = ts->req_report_dmabuf; 21709308562SRahul Rameshbabu 21809308562SRahul Rameshbabu if (test_and_clear_bit(THUNDERSTRIKE_FW_VERSION_UPDATE, &ts->update_flags)) { 21909308562SRahul Rameshbabu thunderstrike_hostcmd_req_report_init( 22009308562SRahul Rameshbabu report, THUNDERSTRIKE_HOSTCMD_ID_FW_VERSION); 22109308562SRahul Rameshbabu thunderstrike_send_hostcmd_request(ts); 22209308562SRahul Rameshbabu } 22309308562SRahul Rameshbabu 22409308562SRahul Rameshbabu if (test_and_clear_bit(THUNDERSTRIKE_BOARD_INFO_UPDATE, &ts->update_flags)) { 22509308562SRahul Rameshbabu thunderstrike_hostcmd_req_report_init( 22609308562SRahul Rameshbabu report, THUNDERSTRIKE_HOSTCMD_ID_BOARD_INFO); 22709308562SRahul Rameshbabu thunderstrike_send_hostcmd_request(ts); 22809308562SRahul Rameshbabu } 22909308562SRahul Rameshbabu 23009308562SRahul Rameshbabu if (test_and_clear_bit(THUNDERSTRIKE_HAPTICS_UPDATE, &ts->update_flags)) { 23109308562SRahul Rameshbabu thunderstrike_hostcmd_req_report_init( 23209308562SRahul Rameshbabu report, THUNDERSTRIKE_HOSTCMD_ID_HAPTICS); 23309308562SRahul Rameshbabu 23409308562SRahul Rameshbabu report->haptics.update = 1; 23509308562SRahul Rameshbabu spin_lock_irqsave(&ts->haptics_update_lock, flags); 23609308562SRahul Rameshbabu report->haptics.motors = ts->haptics_val; 23709308562SRahul Rameshbabu spin_unlock_irqrestore(&ts->haptics_update_lock, flags); 23809308562SRahul Rameshbabu 23909308562SRahul Rameshbabu thunderstrike_send_hostcmd_request(ts); 24009308562SRahul Rameshbabu } 24109308562SRahul Rameshbabu } 24209308562SRahul Rameshbabu 24309308562SRahul Rameshbabu static inline void thunderstrike_request_firmware_version(struct thunderstrike *ts) 24409308562SRahul Rameshbabu { 24509308562SRahul Rameshbabu set_bit(THUNDERSTRIKE_FW_VERSION_UPDATE, &ts->update_flags); 24609308562SRahul Rameshbabu schedule_work(&ts->hostcmd_req_work); 24709308562SRahul Rameshbabu } 24809308562SRahul Rameshbabu 24909308562SRahul Rameshbabu static inline void thunderstrike_request_board_info(struct thunderstrike *ts) 25009308562SRahul Rameshbabu { 25109308562SRahul Rameshbabu set_bit(THUNDERSTRIKE_BOARD_INFO_UPDATE, &ts->update_flags); 25209308562SRahul Rameshbabu schedule_work(&ts->hostcmd_req_work); 25309308562SRahul Rameshbabu } 25409308562SRahul Rameshbabu 25509308562SRahul Rameshbabu static inline int 25609308562SRahul Rameshbabu thunderstrike_update_haptics(struct thunderstrike *ts, 25709308562SRahul Rameshbabu struct thunderstrike_hostcmd_haptics *motors) 25809308562SRahul Rameshbabu { 25909308562SRahul Rameshbabu unsigned long flags; 26009308562SRahul Rameshbabu 26109308562SRahul Rameshbabu spin_lock_irqsave(&ts->haptics_update_lock, flags); 26209308562SRahul Rameshbabu ts->haptics_val = *motors; 26309308562SRahul Rameshbabu spin_unlock_irqrestore(&ts->haptics_update_lock, flags); 26409308562SRahul Rameshbabu 26509308562SRahul Rameshbabu set_bit(THUNDERSTRIKE_HAPTICS_UPDATE, &ts->update_flags); 26609308562SRahul Rameshbabu schedule_work(&ts->hostcmd_req_work); 26709308562SRahul Rameshbabu 26809308562SRahul Rameshbabu return 0; 26909308562SRahul Rameshbabu } 27009308562SRahul Rameshbabu 27109308562SRahul Rameshbabu static int thunderstrike_play_effect(struct input_dev *idev, void *data, 27209308562SRahul Rameshbabu struct ff_effect *effect) 27309308562SRahul Rameshbabu { 27409308562SRahul Rameshbabu struct hid_device *hdev = input_get_drvdata(idev); 27509308562SRahul Rameshbabu struct thunderstrike_hostcmd_haptics motors; 27609308562SRahul Rameshbabu struct shield_device *shield_dev; 27709308562SRahul Rameshbabu struct thunderstrike *ts; 27809308562SRahul Rameshbabu 27909308562SRahul Rameshbabu if (effect->type != FF_RUMBLE) 28009308562SRahul Rameshbabu return 0; 28109308562SRahul Rameshbabu 28209308562SRahul Rameshbabu shield_dev = hid_get_drvdata(hdev); 28309308562SRahul Rameshbabu ts = container_of(shield_dev, struct thunderstrike, base); 28409308562SRahul Rameshbabu 28509308562SRahul Rameshbabu /* Thunderstrike motor values range from 0 to 32 inclusively */ 28609308562SRahul Rameshbabu motors.motor_left = effect->u.rumble.strong_magnitude / 2047; 28709308562SRahul Rameshbabu motors.motor_right = effect->u.rumble.weak_magnitude / 2047; 28809308562SRahul Rameshbabu 28909308562SRahul Rameshbabu hid_dbg(hdev, "Thunderstrike FF_RUMBLE request, left: %u right: %u\n", 29009308562SRahul Rameshbabu motors.motor_left, motors.motor_right); 29109308562SRahul Rameshbabu 29209308562SRahul Rameshbabu return thunderstrike_update_haptics(ts, &motors); 29309308562SRahul Rameshbabu } 29409308562SRahul Rameshbabu 29509308562SRahul Rameshbabu static void 29609308562SRahul Rameshbabu thunderstrike_parse_fw_version_payload(struct shield_device *shield_dev, 29709308562SRahul Rameshbabu __le16 fw_version) 29809308562SRahul Rameshbabu { 29909308562SRahul Rameshbabu shield_dev->fw_version = le16_to_cpu(fw_version); 30009308562SRahul Rameshbabu 30109308562SRahul Rameshbabu set_bit(SHIELD_FW_VERSION_INITIALIZED, &shield_dev->initialized_flags); 30209308562SRahul Rameshbabu 30309308562SRahul Rameshbabu hid_dbg(shield_dev->hdev, "Thunderstrike firmware version 0x%04X\n", 30409308562SRahul Rameshbabu shield_dev->fw_version); 30509308562SRahul Rameshbabu } 30609308562SRahul Rameshbabu 30709308562SRahul Rameshbabu static void 30809308562SRahul Rameshbabu thunderstrike_parse_board_info_payload(struct shield_device *shield_dev, 30909308562SRahul Rameshbabu struct thunderstrike_hostcmd_board_info *board_info) 31009308562SRahul Rameshbabu { 31109308562SRahul Rameshbabu char board_revision_str[4]; 31209308562SRahul Rameshbabu int i; 31309308562SRahul Rameshbabu 31409308562SRahul Rameshbabu shield_dev->board_info.revision = le16_to_cpu(board_info->revision); 31509308562SRahul Rameshbabu for (i = 0; i < 7; ++i) { 31609308562SRahul Rameshbabu u16 val = le16_to_cpu(board_info->serial[i]); 31709308562SRahul Rameshbabu 31809308562SRahul Rameshbabu shield_dev->board_info.serial_number[2 * i] = val & 0xFF; 31909308562SRahul Rameshbabu shield_dev->board_info.serial_number[2 * i + 1] = val >> 8; 32009308562SRahul Rameshbabu } 32109308562SRahul Rameshbabu shield_dev->board_info.serial_number[14] = '\0'; 32209308562SRahul Rameshbabu 32309308562SRahul Rameshbabu set_bit(SHIELD_BOARD_INFO_INITIALIZED, &shield_dev->initialized_flags); 32409308562SRahul Rameshbabu 32509308562SRahul Rameshbabu shield_strrev(board_revision_str, 4, shield_dev->board_info.revision); 32609308562SRahul Rameshbabu hid_dbg(shield_dev->hdev, 32709308562SRahul Rameshbabu "Thunderstrike BOARD_REVISION_%s (0x%04X) S/N: %s\n", 32809308562SRahul Rameshbabu board_revision_str, shield_dev->board_info.revision, 32909308562SRahul Rameshbabu shield_dev->board_info.serial_number); 33009308562SRahul Rameshbabu } 33109308562SRahul Rameshbabu 33209308562SRahul Rameshbabu static inline void 33309308562SRahul Rameshbabu thunderstrike_parse_haptics_payload(struct shield_device *shield_dev, 33409308562SRahul Rameshbabu struct thunderstrike_hostcmd_haptics *haptics) 33509308562SRahul Rameshbabu { 33609308562SRahul Rameshbabu hid_dbg(shield_dev->hdev, 33709308562SRahul Rameshbabu "Thunderstrike haptics HOSTCMD response, left: %u right: %u\n", 33809308562SRahul Rameshbabu haptics->motor_left, haptics->motor_right); 33909308562SRahul Rameshbabu } 34009308562SRahul Rameshbabu 34109308562SRahul Rameshbabu static int thunderstrike_parse_report(struct shield_device *shield_dev, 34209308562SRahul Rameshbabu struct hid_report *report, u8 *data, 34309308562SRahul Rameshbabu int size) 34409308562SRahul Rameshbabu { 34509308562SRahul Rameshbabu struct thunderstrike_hostcmd_resp_report *hostcmd_resp_report; 34609308562SRahul Rameshbabu struct thunderstrike *ts = 34709308562SRahul Rameshbabu container_of(shield_dev, struct thunderstrike, base); 34809308562SRahul Rameshbabu struct hid_device *hdev = shield_dev->hdev; 34909308562SRahul Rameshbabu 35009308562SRahul Rameshbabu switch (report->id) { 35109308562SRahul Rameshbabu case THUNDERSTRIKE_HOSTCMD_RESP_REPORT_ID: 35209308562SRahul Rameshbabu if (size != THUNDERSTRIKE_HOSTCMD_REPORT_SIZE) { 35309308562SRahul Rameshbabu hid_err(hdev, 35409308562SRahul Rameshbabu "Encountered Thunderstrike HOSTCMD HID report with unexpected size %d\n", 35509308562SRahul Rameshbabu size); 35609308562SRahul Rameshbabu return -EINVAL; 35709308562SRahul Rameshbabu } 35809308562SRahul Rameshbabu 35909308562SRahul Rameshbabu hostcmd_resp_report = 36009308562SRahul Rameshbabu (struct thunderstrike_hostcmd_resp_report *)data; 36109308562SRahul Rameshbabu 36209308562SRahul Rameshbabu switch (hostcmd_resp_report->cmd_id) { 36309308562SRahul Rameshbabu case THUNDERSTRIKE_HOSTCMD_ID_FW_VERSION: 36409308562SRahul Rameshbabu thunderstrike_parse_fw_version_payload( 36509308562SRahul Rameshbabu shield_dev, hostcmd_resp_report->fw_version); 36609308562SRahul Rameshbabu break; 36709308562SRahul Rameshbabu case THUNDERSTRIKE_HOSTCMD_ID_BOARD_INFO: 36809308562SRahul Rameshbabu thunderstrike_parse_board_info_payload( 36909308562SRahul Rameshbabu shield_dev, &hostcmd_resp_report->board_info); 37009308562SRahul Rameshbabu break; 37109308562SRahul Rameshbabu case THUNDERSTRIKE_HOSTCMD_ID_HAPTICS: 37209308562SRahul Rameshbabu thunderstrike_parse_haptics_payload( 37309308562SRahul Rameshbabu shield_dev, &hostcmd_resp_report->motors); 37409308562SRahul Rameshbabu break; 37509308562SRahul Rameshbabu 37609308562SRahul Rameshbabu case THUNDERSTRIKE_HOSTCMD_ID_USB_INIT: 37709308562SRahul Rameshbabu case THUNDERSTRIKE_HOSTCMD_ID_BLUETOOTH_INIT: 37809308562SRahul Rameshbabu /* May block HOSTCMD requests till received initially */ 37909308562SRahul Rameshbabu thunderstrike_request_firmware_version(ts); 38009308562SRahul Rameshbabu thunderstrike_request_board_info(ts); 38109308562SRahul Rameshbabu /* Only HOSTCMD that can be triggered without a request */ 38209308562SRahul Rameshbabu return 0; 38309308562SRahul Rameshbabu default: 38409308562SRahul Rameshbabu hid_warn(hdev, 38509308562SRahul Rameshbabu "Unhandled Thunderstrike HOSTCMD id %d\n", 38609308562SRahul Rameshbabu hostcmd_resp_report->cmd_id); 38709308562SRahul Rameshbabu return -ENOENT; 38809308562SRahul Rameshbabu } 38909308562SRahul Rameshbabu 39009308562SRahul Rameshbabu break; 39109308562SRahul Rameshbabu default: 39209308562SRahul Rameshbabu return 0; 39309308562SRahul Rameshbabu } 39409308562SRahul Rameshbabu 39509308562SRahul Rameshbabu return 0; 39609308562SRahul Rameshbabu } 39709308562SRahul Rameshbabu 39809308562SRahul Rameshbabu static struct shield_device *thunderstrike_create(struct hid_device *hdev) 39909308562SRahul Rameshbabu { 40009308562SRahul Rameshbabu struct shield_device *shield_dev; 40109308562SRahul Rameshbabu struct thunderstrike *ts; 40209308562SRahul Rameshbabu 40309308562SRahul Rameshbabu ts = devm_kzalloc(&hdev->dev, sizeof(*ts), GFP_KERNEL); 40409308562SRahul Rameshbabu if (!ts) 40509308562SRahul Rameshbabu return ERR_PTR(-ENOMEM); 40609308562SRahul Rameshbabu 40709308562SRahul Rameshbabu ts->req_report_dmabuf = devm_kzalloc( 40809308562SRahul Rameshbabu &hdev->dev, THUNDERSTRIKE_HOSTCMD_REPORT_SIZE, GFP_KERNEL); 40909308562SRahul Rameshbabu if (!ts->req_report_dmabuf) 41009308562SRahul Rameshbabu return ERR_PTR(-ENOMEM); 41109308562SRahul Rameshbabu 41209308562SRahul Rameshbabu shield_dev = &ts->base; 41309308562SRahul Rameshbabu shield_dev->hdev = hdev; 41409308562SRahul Rameshbabu shield_dev->codename = "Thunderstrike"; 41509308562SRahul Rameshbabu 41609308562SRahul Rameshbabu spin_lock_init(&ts->haptics_update_lock); 41709308562SRahul Rameshbabu INIT_WORK(&ts->hostcmd_req_work, thunderstrike_hostcmd_req_work_handler); 41809308562SRahul Rameshbabu 41909308562SRahul Rameshbabu hid_set_drvdata(hdev, shield_dev); 42009308562SRahul Rameshbabu 42109308562SRahul Rameshbabu ts->haptics_dev = shield_haptics_create(shield_dev, thunderstrike_play_effect); 42209308562SRahul Rameshbabu if (IS_ERR(ts->haptics_dev)) 42309308562SRahul Rameshbabu return ERR_CAST(ts->haptics_dev); 42409308562SRahul Rameshbabu 42509308562SRahul Rameshbabu hid_info(hdev, "Registered Thunderstrike controller\n"); 42609308562SRahul Rameshbabu return shield_dev; 42709308562SRahul Rameshbabu } 42809308562SRahul Rameshbabu 429*13d02c69SRahul Rameshbabu static int android_input_mapping(struct hid_device *hdev, struct hid_input *hi, 430*13d02c69SRahul Rameshbabu struct hid_field *field, 431*13d02c69SRahul Rameshbabu struct hid_usage *usage, unsigned long **bit, 432*13d02c69SRahul Rameshbabu int *max) 433*13d02c69SRahul Rameshbabu { 434*13d02c69SRahul Rameshbabu if ((usage->hid & HID_USAGE_PAGE) != HID_UP_CONSUMER) 435*13d02c69SRahul Rameshbabu return 0; 436*13d02c69SRahul Rameshbabu 437*13d02c69SRahul Rameshbabu switch (usage->hid & HID_USAGE) { 438*13d02c69SRahul Rameshbabu case HID_USAGE_ANDROID_PLAYPAUSE_BTN: 439*13d02c69SRahul Rameshbabu android_map_key(KEY_PLAYPAUSE); 440*13d02c69SRahul Rameshbabu break; 441*13d02c69SRahul Rameshbabu case HID_USAGE_ANDROID_VOLUMEUP_BTN: 442*13d02c69SRahul Rameshbabu android_map_key(KEY_VOLUMEUP); 443*13d02c69SRahul Rameshbabu break; 444*13d02c69SRahul Rameshbabu case HID_USAGE_ANDROID_VOLUMEDOWN_BTN: 445*13d02c69SRahul Rameshbabu android_map_key(KEY_VOLUMEDOWN); 446*13d02c69SRahul Rameshbabu break; 447*13d02c69SRahul Rameshbabu case HID_USAGE_ANDROID_SEARCH_BTN: 448*13d02c69SRahul Rameshbabu android_map_key(BTN_Z); 449*13d02c69SRahul Rameshbabu break; 450*13d02c69SRahul Rameshbabu case HID_USAGE_ANDROID_HOME_BTN: 451*13d02c69SRahul Rameshbabu android_map_key(BTN_MODE); 452*13d02c69SRahul Rameshbabu break; 453*13d02c69SRahul Rameshbabu case HID_USAGE_ANDROID_BACK_BTN: 454*13d02c69SRahul Rameshbabu android_map_key(BTN_SELECT); 455*13d02c69SRahul Rameshbabu break; 456*13d02c69SRahul Rameshbabu default: 457*13d02c69SRahul Rameshbabu return 0; 458*13d02c69SRahul Rameshbabu } 459*13d02c69SRahul Rameshbabu 460*13d02c69SRahul Rameshbabu return 1; 461*13d02c69SRahul Rameshbabu } 462*13d02c69SRahul Rameshbabu 46309308562SRahul Rameshbabu static ssize_t firmware_version_show(struct device *dev, 46409308562SRahul Rameshbabu struct device_attribute *attr, char *buf) 46509308562SRahul Rameshbabu { 46609308562SRahul Rameshbabu struct hid_device *hdev = to_hid_device(dev); 46709308562SRahul Rameshbabu struct shield_device *shield_dev; 46809308562SRahul Rameshbabu int ret; 46909308562SRahul Rameshbabu 47009308562SRahul Rameshbabu shield_dev = hid_get_drvdata(hdev); 47109308562SRahul Rameshbabu 47209308562SRahul Rameshbabu if (test_bit(SHIELD_FW_VERSION_INITIALIZED, &shield_dev->initialized_flags)) 47309308562SRahul Rameshbabu ret = sysfs_emit(buf, "0x%04X\n", shield_dev->fw_version); 47409308562SRahul Rameshbabu else 47509308562SRahul Rameshbabu ret = sysfs_emit(buf, NOT_INIT_STR "\n"); 47609308562SRahul Rameshbabu 47709308562SRahul Rameshbabu return ret; 47809308562SRahul Rameshbabu } 47909308562SRahul Rameshbabu 48009308562SRahul Rameshbabu static DEVICE_ATTR_RO(firmware_version); 48109308562SRahul Rameshbabu 48209308562SRahul Rameshbabu static ssize_t hardware_version_show(struct device *dev, 48309308562SRahul Rameshbabu struct device_attribute *attr, char *buf) 48409308562SRahul Rameshbabu { 48509308562SRahul Rameshbabu struct hid_device *hdev = to_hid_device(dev); 48609308562SRahul Rameshbabu struct shield_device *shield_dev; 48709308562SRahul Rameshbabu char board_revision_str[4]; 48809308562SRahul Rameshbabu int ret; 48909308562SRahul Rameshbabu 49009308562SRahul Rameshbabu shield_dev = hid_get_drvdata(hdev); 49109308562SRahul Rameshbabu 49209308562SRahul Rameshbabu if (test_bit(SHIELD_BOARD_INFO_INITIALIZED, &shield_dev->initialized_flags)) { 49309308562SRahul Rameshbabu shield_strrev(board_revision_str, 4, shield_dev->board_info.revision); 49409308562SRahul Rameshbabu ret = sysfs_emit(buf, "%s BOARD_REVISION_%s (0x%04X)\n", 49509308562SRahul Rameshbabu shield_dev->codename, board_revision_str, 49609308562SRahul Rameshbabu shield_dev->board_info.revision); 49709308562SRahul Rameshbabu } else 49809308562SRahul Rameshbabu ret = sysfs_emit(buf, NOT_INIT_STR "\n"); 49909308562SRahul Rameshbabu 50009308562SRahul Rameshbabu return ret; 50109308562SRahul Rameshbabu } 50209308562SRahul Rameshbabu 50309308562SRahul Rameshbabu static DEVICE_ATTR_RO(hardware_version); 50409308562SRahul Rameshbabu 50509308562SRahul Rameshbabu static ssize_t serial_number_show(struct device *dev, 50609308562SRahul Rameshbabu struct device_attribute *attr, char *buf) 50709308562SRahul Rameshbabu { 50809308562SRahul Rameshbabu struct hid_device *hdev = to_hid_device(dev); 50909308562SRahul Rameshbabu struct shield_device *shield_dev; 51009308562SRahul Rameshbabu int ret; 51109308562SRahul Rameshbabu 51209308562SRahul Rameshbabu shield_dev = hid_get_drvdata(hdev); 51309308562SRahul Rameshbabu 51409308562SRahul Rameshbabu if (test_bit(SHIELD_BOARD_INFO_INITIALIZED, &shield_dev->initialized_flags)) 51509308562SRahul Rameshbabu ret = sysfs_emit(buf, "%s\n", shield_dev->board_info.serial_number); 51609308562SRahul Rameshbabu else 51709308562SRahul Rameshbabu ret = sysfs_emit(buf, NOT_INIT_STR "\n"); 51809308562SRahul Rameshbabu 51909308562SRahul Rameshbabu return ret; 52009308562SRahul Rameshbabu } 52109308562SRahul Rameshbabu 52209308562SRahul Rameshbabu static DEVICE_ATTR_RO(serial_number); 52309308562SRahul Rameshbabu 52409308562SRahul Rameshbabu static struct attribute *shield_device_attrs[] = { 52509308562SRahul Rameshbabu &dev_attr_firmware_version.attr, 52609308562SRahul Rameshbabu &dev_attr_hardware_version.attr, 52709308562SRahul Rameshbabu &dev_attr_serial_number.attr, 52809308562SRahul Rameshbabu NULL, 52909308562SRahul Rameshbabu }; 53009308562SRahul Rameshbabu ATTRIBUTE_GROUPS(shield_device); 53109308562SRahul Rameshbabu 53209308562SRahul Rameshbabu static int shield_raw_event(struct hid_device *hdev, struct hid_report *report, 53309308562SRahul Rameshbabu u8 *data, int size) 53409308562SRahul Rameshbabu { 53509308562SRahul Rameshbabu struct shield_device *dev = hid_get_drvdata(hdev); 53609308562SRahul Rameshbabu 53709308562SRahul Rameshbabu return thunderstrike_parse_report(dev, report, data, size); 53809308562SRahul Rameshbabu } 53909308562SRahul Rameshbabu 54009308562SRahul Rameshbabu static int shield_probe(struct hid_device *hdev, const struct hid_device_id *id) 54109308562SRahul Rameshbabu { 54209308562SRahul Rameshbabu struct shield_device *shield_dev = NULL; 54309308562SRahul Rameshbabu struct thunderstrike *ts; 54409308562SRahul Rameshbabu int ret; 54509308562SRahul Rameshbabu 54609308562SRahul Rameshbabu ret = hid_parse(hdev); 54709308562SRahul Rameshbabu if (ret) { 54809308562SRahul Rameshbabu hid_err(hdev, "Parse failed\n"); 54909308562SRahul Rameshbabu return ret; 55009308562SRahul Rameshbabu } 55109308562SRahul Rameshbabu 55209308562SRahul Rameshbabu switch (id->product) { 55309308562SRahul Rameshbabu case USB_DEVICE_ID_NVIDIA_THUNDERSTRIKE_CONTROLLER: 55409308562SRahul Rameshbabu shield_dev = thunderstrike_create(hdev); 55509308562SRahul Rameshbabu break; 55609308562SRahul Rameshbabu } 55709308562SRahul Rameshbabu 55809308562SRahul Rameshbabu if (unlikely(!shield_dev)) { 55909308562SRahul Rameshbabu hid_err(hdev, "Failed to identify SHIELD device\n"); 56009308562SRahul Rameshbabu return -ENODEV; 56109308562SRahul Rameshbabu } 56209308562SRahul Rameshbabu if (IS_ERR(shield_dev)) { 56309308562SRahul Rameshbabu hid_err(hdev, "Failed to create SHIELD device\n"); 56409308562SRahul Rameshbabu return PTR_ERR(shield_dev); 56509308562SRahul Rameshbabu } 56609308562SRahul Rameshbabu 56709308562SRahul Rameshbabu ts = container_of(shield_dev, struct thunderstrike, base); 56809308562SRahul Rameshbabu 56909308562SRahul Rameshbabu ret = hid_hw_start(hdev, HID_CONNECT_HIDINPUT); 57009308562SRahul Rameshbabu if (ret) { 57109308562SRahul Rameshbabu hid_err(hdev, "Failed to start HID device\n"); 57209308562SRahul Rameshbabu goto err_haptics; 57309308562SRahul Rameshbabu } 57409308562SRahul Rameshbabu 57509308562SRahul Rameshbabu ret = hid_hw_open(hdev); 57609308562SRahul Rameshbabu if (ret) { 57709308562SRahul Rameshbabu hid_err(hdev, "Failed to open HID device\n"); 57809308562SRahul Rameshbabu goto err_stop; 57909308562SRahul Rameshbabu } 58009308562SRahul Rameshbabu 58109308562SRahul Rameshbabu thunderstrike_request_firmware_version(ts); 58209308562SRahul Rameshbabu thunderstrike_request_board_info(ts); 58309308562SRahul Rameshbabu 58409308562SRahul Rameshbabu return ret; 58509308562SRahul Rameshbabu 58609308562SRahul Rameshbabu err_stop: 58709308562SRahul Rameshbabu hid_hw_stop(hdev); 58809308562SRahul Rameshbabu err_haptics: 58909308562SRahul Rameshbabu if (ts->haptics_dev) 59009308562SRahul Rameshbabu input_unregister_device(ts->haptics_dev); 59109308562SRahul Rameshbabu return ret; 59209308562SRahul Rameshbabu } 59309308562SRahul Rameshbabu 59409308562SRahul Rameshbabu static void shield_remove(struct hid_device *hdev) 59509308562SRahul Rameshbabu { 59609308562SRahul Rameshbabu struct shield_device *dev = hid_get_drvdata(hdev); 59709308562SRahul Rameshbabu struct thunderstrike *ts; 59809308562SRahul Rameshbabu 59909308562SRahul Rameshbabu ts = container_of(dev, struct thunderstrike, base); 60009308562SRahul Rameshbabu 60109308562SRahul Rameshbabu hid_hw_close(hdev); 60209308562SRahul Rameshbabu if (ts->haptics_dev) 60309308562SRahul Rameshbabu input_unregister_device(ts->haptics_dev); 60409308562SRahul Rameshbabu cancel_work_sync(&ts->hostcmd_req_work); 60509308562SRahul Rameshbabu hid_hw_stop(hdev); 60609308562SRahul Rameshbabu } 60709308562SRahul Rameshbabu 60809308562SRahul Rameshbabu static const struct hid_device_id shield_devices[] = { 60909308562SRahul Rameshbabu { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_NVIDIA, 61009308562SRahul Rameshbabu USB_DEVICE_ID_NVIDIA_THUNDERSTRIKE_CONTROLLER) }, 61109308562SRahul Rameshbabu { HID_USB_DEVICE(USB_VENDOR_ID_NVIDIA, 61209308562SRahul Rameshbabu USB_DEVICE_ID_NVIDIA_THUNDERSTRIKE_CONTROLLER) }, 61309308562SRahul Rameshbabu { } 61409308562SRahul Rameshbabu }; 61509308562SRahul Rameshbabu MODULE_DEVICE_TABLE(hid, shield_devices); 61609308562SRahul Rameshbabu 61709308562SRahul Rameshbabu static struct hid_driver shield_driver = { 61809308562SRahul Rameshbabu .name = "shield", 61909308562SRahul Rameshbabu .id_table = shield_devices, 620*13d02c69SRahul Rameshbabu .input_mapping = android_input_mapping, 62109308562SRahul Rameshbabu .probe = shield_probe, 62209308562SRahul Rameshbabu .remove = shield_remove, 62309308562SRahul Rameshbabu .raw_event = shield_raw_event, 62409308562SRahul Rameshbabu .driver = { 62509308562SRahul Rameshbabu .dev_groups = shield_device_groups, 62609308562SRahul Rameshbabu }, 62709308562SRahul Rameshbabu }; 62809308562SRahul Rameshbabu module_hid_driver(shield_driver); 62909308562SRahul Rameshbabu 63009308562SRahul Rameshbabu MODULE_AUTHOR("Rahul Rameshbabu <rrameshbabu@nvidia.com>"); 63109308562SRahul Rameshbabu MODULE_DESCRIPTION("HID Driver for NVIDIA SHIELD peripherals."); 63209308562SRahul Rameshbabu MODULE_LICENSE("GPL"); 633