diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index 4c682c65070408..1165282ddd1381 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -164,6 +164,17 @@ config HID_ASUS - GL553V series - GL753V series +config HID_MSI_CLAW + tristate "MSI Claw" + depends on USB_HID + select POWER_SUPPLY + help + Support for MSI Claw HID device used to configure the device + to act either as an xbox controller or keyboard and mouse. + + Supported devices: + - MSI Claw + config HID_AUREAL tristate "Aureal" help diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile index 7eefb548e33a9d..cc7c2f141bef7d 100644 --- a/drivers/hid/Makefile +++ b/drivers/hid/Makefile @@ -87,6 +87,7 @@ obj-$(CONFIG_HID_MAYFLASH) += hid-mf.o obj-$(CONFIG_HID_MEGAWORLD_FF) += hid-megaworld.o obj-$(CONFIG_HID_MICROSOFT) += hid-microsoft.o obj-$(CONFIG_HID_MONTEREY) += hid-monterey.o +obj-$(CONFIG_HID_MSI_CLAW) += hid-msi-claw.o obj-$(CONFIG_HID_MULTITOUCH) += hid-multitouch.o obj-$(CONFIG_HID_NINTENDO) += hid-nintendo.o obj-$(CONFIG_HID_NTI) += hid-nti.o diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index ccc089cfd16c68..f712376e933cde 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -965,6 +965,9 @@ #define USB_VENDOR_ID_MONTEREY 0x0566 #define USB_DEVICE_ID_GENIUS_KB29E 0x3004 +#define USB_VENDOR_ID_MSI_FIRST 0x0DB0 +#define USB_DEVICE_ID_MSI_CLAW 0x1901 + #define USB_VENDOR_ID_MSI 0x1770 #define USB_DEVICE_ID_MSI_GT683R_LED_PANEL 0xff00 diff --git a/drivers/hid/hid-msi-claw.c b/drivers/hid/hid-msi-claw.c new file mode 100644 index 00000000000000..01265d583e622c --- /dev/null +++ b/drivers/hid/hid-msi-claw.c @@ -0,0 +1,188 @@ +#include +#include +#include +#include + +#include "hid-ids.h" + +#define FEATURE_GAMEPAD_REPORT_ID 0x0f + +enum msi_claw_gamepad_mode { + MSI_CLAW_GAMEPAD_MODE_OFFLINE = 0, + MSI_CLAW_GAMEPAD_MODE_XINPUT, + MSI_CLAW_GAMEPAD_MODE_DINPUT, + MSI_CLAW_GAMEPAD_MODE_MSI, + MSI_CLAW_GAMEPAD_MODE_DESKTOP, + MSI_CLAW_GAMEPAD_MODE_BIOS, + MSI_CLAW_GAMEPAD_MODE_TESTING, + MSI_CLAW_GAMEPAD_MODE_MAX +}; + +enum msi_claw_mkeys_function { + MSI_CLAW_MKEY_FUNCTION_MACRO, + MSI_CLAW_MKEY_FUNCTION_COMBINATION, +}; + +enum msi_claw_command_type { + MSI_CLAW_COMMAND_TYPE_ENTER_PROFILE_CONFIG = 1, + MSI_CLAW_COMMAND_TYPE_EXIT_PROFILE_CONFIG = 2, + MSI_CLAW_COMMAND_TYPE_WRITE_PROFILE = 3, + MSI_CLAW_COMMAND_TYPE_READ_PROFILE = 4, + MSI_CLAW_COMMAND_TYPE_READ_PROFILE_ACK = 5, + MSI_CLAW_COMMAND_TYPE_ACK = 6, + MSI_CLAW_COMMAND_TYPE_SWITCH_PROFILE = 7, + MSI_CLAW_COMMAND_TYPE_WRITE_PROFILE_TO_EEPROM = 8, + MSI_CLAW_COMMAND_TYPE_READ_FIRMWARE_VERSION = 9, + MSI_CLAW_COMMAND_TYPE_READ_RGB_STATUS_ACK = 10, + MSI_CLAW_COMMAND_TYPE_READ_CURRENT_PROFILE = 11, + MSI_CLAW_COMMAND_TYPE_READ_CURRENT_PROFILE_ACK = 12, + MSI_CLAW_COMMAND_TYPE_READ_RGB_STATUS = 13, + MSI_CLAW_COMMAND_TYPE_SYNC_TO_ROM = 34, + MSI_CLAW_COMMAND_TYPE_RESTORE_FROM_ROM = 35, + MSI_CLAW_COMMAND_TYPE_SWITCH_MODE = 36, + MSI_CLAW_COMMAND_TYPE_READ_GAMEPAD_MODE = 38, + MSI_CLAW_COMMAND_TYPE_GAMEPAD_MODE_ACK = 39, + MSI_CLAW_COMMAND_TYPE_RESET_DEVICE = 40, + MSI_CLAW_COMMAND_TYPE_RGB_CONTROL = 224, + MSI_CLAW_COMMAND_TYPE_CALIBRATION_CONTROL = 253, + MSI_CLAW_COMMAND_TYPE_CALIBRATION_ACK = 254, +}; + +struct msi_claw_drvdata { + struct hid_device *hdev; + struct input_dev *input; + struct input_dev *tp_kbd_input; +}; + +static int msi_claw_switch_gamepad_mode(struct hid_device *hdev, enum msi_claw_gamepad_mode mode, + enum msi_claw_mkeys_function mkeys) +{ + int ret; + const unsigned char buf[] = { + FEATURE_GAMEPAD_REPORT_ID, 0, 0, 60, MSI_CLAW_COMMAND_TYPE_SWITCH_MODE, (unsigned char)mode, (unsigned char)mkeys + }; + unsigned char *dmabuf = kmemdup(buf, sizeof(buf), GFP_KERNEL); + + if (!dmabuf) { + ret = -ENOMEM; + hid_err(hdev, "msi-claw failed to alloc dma buf: %d\n", ret); + return ret; + } + + ret = hid_hw_raw_request(hdev, dmabuf[0], dmabuf, sizeof(buf), + HID_FEATURE_REPORT, HID_REQ_SET_REPORT); + + kfree(dmabuf); + + if (ret != sizeof(buf)) { + hid_err(hdev, "msi-claw failed to switch controller mode: %d\n", ret); + return ret; + } + + return 0; +} + +static int msi_claw_raw_event(struct hid_device *hdev, + struct hid_report *report, u8 *data, int size) +{ + struct msi_claw_drvdata *drvdata = hid_get_drvdata(hdev); + + return 0; +} + +/* +#define asus_map_key_clear(c) hid_map_usage_clear(hi, usage, bit, \ + max, EV_KEY, (c)) +*/ +static int msi_claw_input_mapping(struct hid_device *hdev, + struct hid_input *hi, struct hid_field *field, + struct hid_usage *usage, unsigned long **bit, + int *max) +{ + struct msi_claw_drvdata *drvdata = hid_get_drvdata(hdev); + + /* + if ((usage->hid & HID_USAGE_PAGE) == HID_UP_ASUSVENDOR) { + switch (usage->hid & HID_USAGE) { + case 0x10: asus_map_key_clear(KEY_BRIGHTNESSDOWN); break; + */ + + return 0; +} + +static int msi_claw_event(struct hid_device *hdev, struct hid_field *field, + struct hid_usage *usage, __s32 value) +{ + struct msi_claw_drvdata *drvdata = hid_get_drvdata(hdev); + + return 0; +} + +static int msi_claw_probe(struct hid_device *hdev, const struct hid_device_id *id) +{ + int ret; + struct msi_claw_drvdata *drvdata; + + drvdata = devm_kzalloc(&hdev->dev, sizeof(*drvdata), GFP_KERNEL); + if (drvdata == NULL) { + hid_err(hdev, "msi-claw can't alloc descriptor\n"); + return -ENOMEM; + } + + hid_set_drvdata(hdev, drvdata); + + ret = hid_parse(hdev); + if (ret) { + hid_err(hdev, "msi-claw hid parse failed: %d\n", ret); + return ret; + } + + ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); + if (ret) { + hid_err(hdev, "msi-claw hw start failed: %d\n", ret); + return ret; + } + + // TODO: remove me + hid_err(hdev, "msi-claw started\n", ret); + + ret = msi_claw_switch_gamepad_mode(hdev, MSI_CLAW_GAMEPAD_MODE_MSI, MSI_CLAW_MKEY_FUNCTION_MACRO); + if (ret != 0) { + hid_err(hdev, "msi-claw failed to initialize controller mode: %d\n", ret); + goto err_stop_hw; + } + + return 0; + +err_stop_hw: + hid_hw_stop(hdev); + return ret; +} + +static void msi_claw_remove(struct hid_device *hdev) +{ + struct msi_claw_drvdata *drvdata = hid_get_drvdata(hdev); + + hid_hw_stop(hdev); +} + +static const struct hid_device_id msi_claw_devices[] = { + { HID_USB_DEVICE(USB_VENDOR_ID_MSI_FIRST, + USB_DEVICE_ID_MSI_CLAW) }, + { } +}; +MODULE_DEVICE_TABLE(hid, msi_claw_devices); + +static struct hid_driver msi_claw_driver = { + .name = "msi-claw", + .id_table = msi_claw_devices, + //.report_fixup = asus_report_fixup, + .probe = msi_claw_probe, + .remove = msi_claw_remove, + .input_mapping = msi_claw_input_mapping, + .event = msi_claw_event, + .raw_event = msi_claw_raw_event +}; +module_hid_driver(msi_claw_driver); + +MODULE_LICENSE("GPL");