1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * HID driver for MSI Claw Handheld PC gamepads. 4 * 5 * Provides configuration support for the MSI Claw series of handheld PC 6 * gamepads. Multiple iterations of the device firmware has led to some 7 * quirks for how certain attributes are handled. The original firmware 8 * did not support remapping of the M1 (right) and M2 (left) rear paddles. 9 * Additionally, the MCU RAM address for writing configuration data has 10 * changed twice. Checks are done during probe to enumerate these variances. 11 * 12 * Copyright (c) 2026 Zhouwang Huang <honjow311@gmail.com> 13 * Copyright (c) 2026 Denis Benato <denis.benato@linux.dev> 14 * Copyright (c) 2026 Valve Corporation 15 */ 16 17 #include <linux/array_size.h> 18 #include <linux/cleanup.h> 19 #include <linux/completion.h> 20 #include <linux/container_of.h> 21 #include <linux/delay.h> 22 #include <linux/device.h> 23 #include <linux/hid.h> 24 #include <linux/kobject.h> 25 #include <linux/leds.h> 26 #include <linux/module.h> 27 #include <linux/mutex.h> 28 #include <linux/pm.h> 29 #include <linux/spinlock.h> 30 #include <linux/sysfs.h> 31 #include <linux/types.h> 32 #include <linux/unaligned.h> 33 #include <linux/usb.h> 34 #include <linux/workqueue.h> 35 36 #include "hid-ids.h" 37 38 #define CLAW_OUTPUT_REPORT_ID 0x0f 39 #define CLAW_INPUT_REPORT_ID 0x10 40 41 #define CLAW_PACKET_SIZE 64 42 43 #define CLAW_DINPUT_CFG_INTF_IN 0x82 44 #define CLAW_XINPUT_CFG_INTF_IN 0x83 45 46 enum claw_command_index { 47 CLAW_COMMAND_TYPE_NONE = 0x00, 48 CLAW_COMMAND_TYPE_READ_PROFILE = 0x04, 49 CLAW_COMMAND_TYPE_READ_PROFILE_ACK = 0x05, 50 CLAW_COMMAND_TYPE_ACK = 0x06, 51 CLAW_COMMAND_TYPE_WRITE_PROFILE_DATA = 0x21, 52 CLAW_COMMAND_TYPE_SYNC_TO_ROM = 0x22, 53 CLAW_COMMAND_TYPE_SWITCH_MODE = 0x24, 54 CLAW_COMMAND_TYPE_READ_GAMEPAD_MODE = 0x26, 55 CLAW_COMMAND_TYPE_GAMEPAD_MODE_ACK = 0x27, 56 CLAW_COMMAND_TYPE_RESET_DEVICE = 0x28, 57 }; 58 59 enum claw_gamepad_mode_index { 60 CLAW_GAMEPAD_MODE_XINPUT = 0x01, 61 CLAW_GAMEPAD_MODE_DINPUT = 0x02, 62 CLAW_GAMEPAD_MODE_DESKTOP = 0x04, 63 }; 64 65 static const char * const claw_gamepad_mode_text[] = { 66 [CLAW_GAMEPAD_MODE_XINPUT] = "xinput", 67 [CLAW_GAMEPAD_MODE_DINPUT] = "dinput", 68 [CLAW_GAMEPAD_MODE_DESKTOP] = "desktop", 69 }; 70 71 enum claw_mkeys_function_index { 72 CLAW_MKEY_FUNCTION_MACRO, 73 CLAW_MKEY_FUNCTION_DISABLED, 74 CLAW_MKEY_FUNCTION_COMBO, 75 }; 76 77 enum claw_mode_field { 78 CLAW_FIELD_GAMEPAD_MODE, 79 CLAW_FIELD_MKEYS_FUNCTION, 80 }; 81 82 static const char * const claw_mkeys_function_text[] = { 83 [CLAW_MKEY_FUNCTION_MACRO] = "macro", 84 [CLAW_MKEY_FUNCTION_DISABLED] = "disabled", 85 [CLAW_MKEY_FUNCTION_COMBO] = "combination", 86 }; 87 88 struct claw_command_report { 89 u8 report_id; 90 u8 padding[2]; 91 u8 header_tail; 92 u8 cmd; 93 u8 data[59]; 94 } __packed; 95 96 struct claw_drvdata { 97 /* MCU General Variables */ 98 struct completion orphan_ack_complete; 99 struct completion send_cmd_complete; 100 struct delayed_work cfg_resume; 101 struct delayed_work cfg_setup; 102 spinlock_t registration_lock; /* Lock for registration read/write */ 103 struct hid_device *hdev; 104 bool orphan_ack_pending; 105 struct mutex cfg_mutex; /* mutex for synchronous data */ 106 spinlock_t cmd_lock; /* Lock for cmd data read/write */ 107 u8 waiting_cmd; 108 int cmd_status; 109 u8 ep; 110 111 /* Gamepad Variables */ 112 enum claw_mkeys_function_index mkeys_function; 113 enum claw_gamepad_mode_index gamepad_mode; 114 spinlock_t mode_lock; /* Lock for mode data read/write */ 115 bool gp_registered; 116 }; 117 118 static int get_endpoint_address(struct hid_device *hdev) 119 { 120 struct usb_host_endpoint *ep; 121 struct usb_interface *intf; 122 123 intf = to_usb_interface(hdev->dev.parent); 124 ep = intf->cur_altsetting->endpoint; 125 if (ep) 126 return ep->desc.bEndpointAddress; 127 128 return -ENODEV; 129 } 130 131 static int claw_gamepad_mode_event(struct claw_drvdata *drvdata, 132 struct claw_command_report *cmd_rep) 133 { 134 if (cmd_rep->data[0] >= ARRAY_SIZE(claw_gamepad_mode_text) || 135 !claw_gamepad_mode_text[cmd_rep->data[0]] || 136 cmd_rep->data[1] >= ARRAY_SIZE(claw_mkeys_function_text)) 137 return -EINVAL; 138 139 scoped_guard(spinlock_irqsave, &drvdata->mode_lock) { 140 drvdata->gamepad_mode = cmd_rep->data[0]; 141 drvdata->mkeys_function = cmd_rep->data[1]; 142 } 143 144 return 0; 145 } 146 147 static int claw_raw_event(struct claw_drvdata *drvdata, struct hid_report *report, 148 u8 *data, int size) 149 { 150 struct claw_command_report *cmd_rep; 151 int ret = 0; 152 153 if (size != CLAW_PACKET_SIZE) 154 return 0; 155 156 cmd_rep = (struct claw_command_report *)data; 157 158 if (cmd_rep->report_id != CLAW_INPUT_REPORT_ID || cmd_rep->header_tail != 0x3c) 159 return 0; 160 161 dev_dbg(&drvdata->hdev->dev, "Rx data as raw input report: [%*ph]\n", 162 CLAW_PACKET_SIZE, data); 163 164 guard(spinlock_irqsave)(&drvdata->cmd_lock); 165 switch (cmd_rep->cmd) { 166 case CLAW_COMMAND_TYPE_GAMEPAD_MODE_ACK: 167 ret = claw_gamepad_mode_event(drvdata, cmd_rep); 168 if (drvdata->waiting_cmd == CLAW_COMMAND_TYPE_READ_GAMEPAD_MODE) { 169 drvdata->cmd_status = ret; 170 complete(&drvdata->send_cmd_complete); 171 } 172 173 break; 174 case CLAW_COMMAND_TYPE_ACK: 175 if (drvdata->orphan_ack_pending) { 176 drvdata->orphan_ack_pending = false; 177 complete(&drvdata->orphan_ack_complete); 178 break; 179 } 180 181 if (drvdata->waiting_cmd == CLAW_COMMAND_TYPE_NONE) { 182 dev_warn(&drvdata->hdev->dev, "Got unexpected ACK from MCU, ignoring\n"); 183 break; 184 } 185 186 drvdata->cmd_status = 0; 187 complete(&drvdata->send_cmd_complete); 188 189 dev_dbg(&drvdata->hdev->dev, "Waiting CMD: %x\n", drvdata->waiting_cmd); 190 191 break; 192 default: 193 dev_dbg(&drvdata->hdev->dev, "Unknown command: %x\n", cmd_rep->cmd); 194 return 0; 195 } 196 197 return ret; 198 } 199 200 static int msi_raw_event(struct hid_device *hdev, struct hid_report *report, 201 u8 *data, int size) 202 { 203 struct claw_drvdata *drvdata = hid_get_drvdata(hdev); 204 205 if (!drvdata || (drvdata->ep != CLAW_XINPUT_CFG_INTF_IN && 206 drvdata->ep != CLAW_DINPUT_CFG_INTF_IN)) 207 return 0; 208 209 return claw_raw_event(drvdata, report, data, size); 210 } 211 212 /* Caller must hold drvdata->cfg_mutex. */ 213 static int __claw_hw_output_report(struct hid_device *hdev, u8 index, u8 *data, 214 size_t len, unsigned int timeout) 215 { 216 unsigned char *dmabuf __free(kfree) = NULL; 217 u8 header[] = { CLAW_OUTPUT_REPORT_ID, 0, 0, 0x3c, index }; 218 struct claw_drvdata *drvdata = hid_get_drvdata(hdev); 219 size_t header_size = ARRAY_SIZE(header); 220 bool orphaned; 221 int ret; 222 223 lockdep_assert_held(&drvdata->cfg_mutex); 224 225 /* If expecting an orphan ack, hold next event until MCU has time to clear it */ 226 scoped_guard(spinlock_irqsave, &drvdata->cmd_lock) 227 orphaned = drvdata->orphan_ack_pending; 228 229 if (orphaned) { 230 wait_for_completion_timeout(&drvdata->orphan_ack_complete, msecs_to_jiffies(25)); 231 scoped_guard(spinlock_irqsave, &drvdata->cmd_lock) 232 drvdata->orphan_ack_pending = false; 233 } 234 235 if (header_size + len > CLAW_PACKET_SIZE) 236 return -EINVAL; 237 238 /* We can't use a devm_alloc reusable buffer without side effects during suspend */ 239 dmabuf = kzalloc(CLAW_PACKET_SIZE, GFP_KERNEL); 240 if (!dmabuf) 241 return -ENOMEM; 242 243 memcpy(dmabuf, header, header_size); 244 if (data && len) 245 memcpy(dmabuf + header_size, data, len); 246 247 reinit_completion(&drvdata->send_cmd_complete); 248 249 scoped_guard(spinlock_irqsave, &drvdata->cmd_lock) { 250 if (timeout) { 251 drvdata->waiting_cmd = index; 252 drvdata->cmd_status = -ETIMEDOUT; 253 } else { 254 reinit_completion(&drvdata->orphan_ack_complete); 255 drvdata->waiting_cmd = CLAW_COMMAND_TYPE_NONE; 256 drvdata->orphan_ack_pending = true; 257 } 258 } 259 260 dev_dbg(&hdev->dev, "Send data as raw output report: [%*ph]\n", 261 CLAW_PACKET_SIZE, dmabuf); 262 263 ret = hid_hw_output_report(hdev, dmabuf, CLAW_PACKET_SIZE); 264 if (ret < 0) 265 goto err; 266 267 ret = ret == CLAW_PACKET_SIZE ? 0 : -EIO; 268 if (ret) 269 goto err; 270 271 if (timeout) { 272 ret = wait_for_completion_interruptible_timeout(&drvdata->send_cmd_complete, 273 msecs_to_jiffies(timeout)); 274 275 dev_dbg(&hdev->dev, "Remaining timeout: %u\n", ret); 276 ret = ret > 0 ? drvdata->cmd_status : ret ?: -EBUSY; 277 if (ret) 278 goto err; 279 } 280 281 scoped_guard(spinlock_irqsave, &drvdata->cmd_lock) 282 drvdata->waiting_cmd = CLAW_COMMAND_TYPE_NONE; 283 284 return ret; 285 286 err: 287 scoped_guard(spinlock_irqsave, &drvdata->cmd_lock) { 288 drvdata->waiting_cmd = CLAW_COMMAND_TYPE_NONE; 289 drvdata->orphan_ack_pending = false; 290 } 291 return ret; 292 } 293 294 static int claw_hw_output_report(struct hid_device *hdev, u8 index, u8 *data, 295 size_t len, unsigned int timeout) 296 { 297 struct claw_drvdata *drvdata = hid_get_drvdata(hdev); 298 299 guard(mutex)(&drvdata->cfg_mutex); 300 return __claw_hw_output_report(hdev, index, data, len, timeout); 301 } 302 303 static int claw_switch_mode(struct hid_device *hdev, enum claw_mode_field field, u8 val) 304 { 305 struct claw_drvdata *drvdata = hid_get_drvdata(hdev); 306 u8 data[2]; 307 308 guard(mutex)(&drvdata->cfg_mutex); 309 310 scoped_guard(spinlock_irqsave, &drvdata->mode_lock) { 311 switch (field) { 312 case CLAW_FIELD_GAMEPAD_MODE: 313 data[0] = val; 314 data[1] = drvdata->mkeys_function; 315 break; 316 case CLAW_FIELD_MKEYS_FUNCTION: 317 data[0] = drvdata->gamepad_mode; 318 data[1] = val; 319 break; 320 } 321 } 322 323 return __claw_hw_output_report(hdev, CLAW_COMMAND_TYPE_SWITCH_MODE, data, 324 ARRAY_SIZE(data), 0); 325 } 326 327 static ssize_t gamepad_mode_store(struct device *dev, struct device_attribute *attr, 328 const char *buf, size_t count) 329 { 330 struct hid_device *hdev = to_hid_device(dev); 331 struct claw_drvdata *drvdata = hid_get_drvdata(hdev); 332 int i, ret = -EINVAL; 333 334 scoped_guard(spinlock_irqsave, &drvdata->registration_lock) { 335 /* Pairs with smp_store_release from cfg_setup_fn in system_wq context */ 336 if (!smp_load_acquire(&drvdata->gp_registered)) 337 return -ENODEV; 338 } 339 340 for (i = 0; i < ARRAY_SIZE(claw_gamepad_mode_text); i++) { 341 if (claw_gamepad_mode_text[i] && sysfs_streq(buf, claw_gamepad_mode_text[i])) { 342 ret = i; 343 break; 344 } 345 } 346 if (ret < 0) 347 return ret; 348 349 ret = claw_switch_mode(hdev, CLAW_FIELD_GAMEPAD_MODE, ret); 350 if (ret) 351 return ret; 352 353 return count; 354 } 355 356 static ssize_t gamepad_mode_show(struct device *dev, 357 struct device_attribute *attr, char *buf) 358 { 359 struct hid_device *hdev = to_hid_device(dev); 360 struct claw_drvdata *drvdata = hid_get_drvdata(hdev); 361 int ret, i; 362 363 scoped_guard(spinlock_irqsave, &drvdata->registration_lock) { 364 /* Pairs with smp_store_release from cfg_setup_fn in system_wq context */ 365 if (!smp_load_acquire(&drvdata->gp_registered)) 366 return -ENODEV; 367 } 368 369 ret = claw_hw_output_report(hdev, CLAW_COMMAND_TYPE_READ_GAMEPAD_MODE, NULL, 0, 25); 370 if (ret) 371 return ret; 372 373 scoped_guard(spinlock_irqsave, &drvdata->mode_lock) 374 i = drvdata->gamepad_mode; 375 376 if (!claw_gamepad_mode_text[i] || claw_gamepad_mode_text[i][0] == '\0') 377 return sysfs_emit(buf, "unsupported\n"); 378 379 return sysfs_emit(buf, "%s\n", claw_gamepad_mode_text[i]); 380 } 381 static DEVICE_ATTR_RW(gamepad_mode); 382 383 static ssize_t gamepad_mode_index_show(struct device *dev, 384 struct device_attribute *attr, char *buf) 385 { 386 ssize_t count = 0; 387 int i; 388 389 for (i = 0; i < ARRAY_SIZE(claw_gamepad_mode_text); i++) { 390 if (!claw_gamepad_mode_text[i] || claw_gamepad_mode_text[i][0] == '\0') 391 continue; 392 count += sysfs_emit_at(buf, count, "%s ", claw_gamepad_mode_text[i]); 393 } 394 395 if (count) 396 buf[count - 1] = '\n'; 397 398 return count; 399 } 400 static DEVICE_ATTR_RO(gamepad_mode_index); 401 402 static ssize_t mkeys_function_store(struct device *dev, struct device_attribute *attr, 403 const char *buf, size_t count) 404 { 405 struct hid_device *hdev = to_hid_device(dev); 406 struct claw_drvdata *drvdata = hid_get_drvdata(hdev); 407 int i, ret = -EINVAL; 408 409 scoped_guard(spinlock_irqsave, &drvdata->registration_lock) { 410 /* Pairs with smp_store_release from cfg_setup_fn in system_wq context */ 411 if (!smp_load_acquire(&drvdata->gp_registered)) 412 return -ENODEV; 413 } 414 415 for (i = 0; i < ARRAY_SIZE(claw_mkeys_function_text); i++) { 416 if (claw_mkeys_function_text[i] && sysfs_streq(buf, claw_mkeys_function_text[i])) { 417 ret = i; 418 break; 419 } 420 } 421 if (ret < 0) 422 return ret; 423 424 ret = claw_switch_mode(hdev, CLAW_FIELD_MKEYS_FUNCTION, ret); 425 if (ret) 426 return ret; 427 428 return count; 429 } 430 431 static ssize_t mkeys_function_show(struct device *dev, struct device_attribute *attr, 432 char *buf) 433 { 434 struct hid_device *hdev = to_hid_device(dev); 435 struct claw_drvdata *drvdata = hid_get_drvdata(hdev); 436 int ret, i; 437 438 scoped_guard(spinlock_irqsave, &drvdata->registration_lock) { 439 /* Pairs with smp_store_release from cfg_setup_fn in system_wq context */ 440 if (!smp_load_acquire(&drvdata->gp_registered)) 441 return -ENODEV; 442 } 443 444 ret = claw_hw_output_report(hdev, CLAW_COMMAND_TYPE_READ_GAMEPAD_MODE, NULL, 0, 25); 445 if (ret) 446 return ret; 447 448 scoped_guard(spinlock_irqsave, &drvdata->mode_lock) 449 i = drvdata->mkeys_function; 450 451 if (i >= ARRAY_SIZE(claw_mkeys_function_text)) 452 return sysfs_emit(buf, "unsupported\n"); 453 454 return sysfs_emit(buf, "%s\n", claw_mkeys_function_text[i]); 455 } 456 static DEVICE_ATTR_RW(mkeys_function); 457 458 static ssize_t mkeys_function_index_show(struct device *dev, 459 struct device_attribute *attr, char *buf) 460 { 461 int i, count = 0; 462 463 for (i = 0; i < ARRAY_SIZE(claw_mkeys_function_text); i++) 464 count += sysfs_emit_at(buf, count, "%s ", claw_mkeys_function_text[i]); 465 466 if (count) 467 buf[count - 1] = '\n'; 468 469 return count; 470 } 471 static DEVICE_ATTR_RO(mkeys_function_index); 472 473 static ssize_t reset_store(struct device *dev, struct device_attribute *attr, 474 const char *buf, size_t count) 475 { 476 struct hid_device *hdev = to_hid_device(dev); 477 struct claw_drvdata *drvdata = hid_get_drvdata(hdev); 478 bool val; 479 int ret; 480 481 scoped_guard(spinlock_irqsave, &drvdata->registration_lock) { 482 /* Pairs with smp_store_release from cfg_setup_fn in system_wq context */ 483 if (!smp_load_acquire(&drvdata->gp_registered)) 484 return -ENODEV; 485 } 486 487 ret = kstrtobool(buf, &val); 488 if (ret) 489 return ret; 490 491 if (!val) 492 return -EINVAL; 493 494 ret = claw_hw_output_report(hdev, CLAW_COMMAND_TYPE_RESET_DEVICE, NULL, 0, 0); 495 if (ret) 496 return ret; 497 498 return count; 499 } 500 static DEVICE_ATTR_WO(reset); 501 502 static umode_t claw_gamepad_attr_is_visible(struct kobject *kobj, struct attribute *attr, 503 int n) 504 { 505 struct hid_device *hdev = to_hid_device(kobj_to_dev(kobj)); 506 struct claw_drvdata *drvdata = hid_get_drvdata(hdev); 507 508 if (!drvdata) { 509 dev_warn(&hdev->dev, 510 "Failed to get drvdata from kobj. Gamepad attributes are not available.\n"); 511 return 0; 512 } 513 514 return attr->mode; 515 } 516 517 static struct attribute *claw_gamepad_attrs[] = { 518 &dev_attr_gamepad_mode.attr, 519 &dev_attr_gamepad_mode_index.attr, 520 &dev_attr_mkeys_function.attr, 521 &dev_attr_mkeys_function_index.attr, 522 &dev_attr_reset.attr, 523 NULL, 524 }; 525 526 static const struct attribute_group claw_gamepad_attr_group = { 527 .attrs = claw_gamepad_attrs, 528 .is_visible = claw_gamepad_attr_is_visible, 529 }; 530 531 static void cfg_setup_fn(struct work_struct *work) 532 { 533 struct delayed_work *dwork = container_of(work, struct delayed_work, work); 534 struct claw_drvdata *drvdata = container_of(dwork, struct claw_drvdata, cfg_setup); 535 int ret; 536 537 ret = claw_hw_output_report(drvdata->hdev, CLAW_COMMAND_TYPE_READ_GAMEPAD_MODE, 538 NULL, 0, 25); 539 if (ret) { 540 dev_err(&drvdata->hdev->dev, 541 "Failed to setup device, can't read gamepad mode: %d\n", ret); 542 return; 543 } 544 545 /* Add sysfs attributes after we get the device state */ 546 ret = device_add_group(&drvdata->hdev->dev, &claw_gamepad_attr_group); 547 if (ret) { 548 dev_err(&drvdata->hdev->dev, 549 "Failed to setup device, can't create gamepad attrs: %d\n", ret); 550 return; 551 } 552 scoped_guard(spinlock_irqsave, &drvdata->registration_lock) 553 /* Pairs with smp_load_acquire in attribute show/store functions */ 554 smp_store_release(&drvdata->gp_registered, true); 555 556 kobject_uevent(&drvdata->hdev->dev.kobj, KOBJ_CHANGE); 557 } 558 559 static void cfg_resume_fn(struct work_struct *work) 560 { 561 struct delayed_work *dwork = container_of(work, struct delayed_work, work); 562 struct claw_drvdata *drvdata = container_of(dwork, struct claw_drvdata, cfg_resume); 563 564 guard(spinlock_irqsave)(&drvdata->registration_lock); 565 /* Pairs with smp_store_release from cfg_setup_fn in system_wq context */ 566 if (!smp_load_acquire(&drvdata->gp_registered)) 567 schedule_delayed_work(&drvdata->cfg_setup, msecs_to_jiffies(500)); 568 } 569 570 static int claw_probe(struct hid_device *hdev, u8 ep) 571 { 572 struct claw_drvdata *drvdata; 573 int ret; 574 575 drvdata = devm_kzalloc(&hdev->dev, sizeof(*drvdata), GFP_KERNEL); 576 if (!drvdata) 577 return -ENOMEM; 578 579 drvdata->gamepad_mode = CLAW_GAMEPAD_MODE_XINPUT; 580 drvdata->hdev = hdev; 581 drvdata->ep = ep; 582 583 mutex_init(&drvdata->cfg_mutex); 584 spin_lock_init(&drvdata->registration_lock); 585 spin_lock_init(&drvdata->cmd_lock); 586 spin_lock_init(&drvdata->mode_lock); 587 init_completion(&drvdata->orphan_ack_complete); 588 init_completion(&drvdata->send_cmd_complete); 589 INIT_DELAYED_WORK(&drvdata->cfg_resume, &cfg_resume_fn); 590 INIT_DELAYED_WORK(&drvdata->cfg_setup, &cfg_setup_fn); 591 592 /* For control interface: open the HID transport for sending commands. */ 593 ret = hid_hw_open(hdev); 594 if (ret) 595 return ret; 596 597 hid_set_drvdata(hdev, drvdata); 598 schedule_delayed_work(&drvdata->cfg_setup, msecs_to_jiffies(500)); 599 600 return 0; 601 } 602 603 static int msi_probe(struct hid_device *hdev, const struct hid_device_id *id) 604 { 605 int ret; 606 u8 ep; 607 608 if (!hid_is_usb(hdev)) { 609 ret = -ENODEV; 610 goto err_probe; 611 } 612 613 ret = hid_parse(hdev); 614 if (ret) 615 goto err_probe; 616 617 /* Set quirk to create separate input devices per HID application */ 618 hdev->quirks |= HID_QUIRK_INPUT_PER_APP | HID_QUIRK_MULTI_INPUT; 619 ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); 620 if (ret) 621 goto err_probe; 622 623 /* For non-control interfaces (keyboard/mouse), allow userspace to grab the devices. */ 624 ret = get_endpoint_address(hdev); 625 if (ret < 0) 626 goto err_stop_hw; 627 628 ep = ret; 629 if (ep == CLAW_XINPUT_CFG_INTF_IN || ep == CLAW_DINPUT_CFG_INTF_IN) { 630 ret = claw_probe(hdev, ep); 631 if (ret) 632 goto err_stop_hw; 633 } 634 635 return 0; 636 637 err_stop_hw: 638 hid_hw_stop(hdev); 639 err_probe: 640 return dev_err_probe(&hdev->dev, ret, "Failed to init device\n"); 641 } 642 643 static void claw_remove(struct hid_device *hdev) 644 { 645 struct claw_drvdata *drvdata = hid_get_drvdata(hdev); 646 bool gp_registered; 647 648 if (!drvdata) 649 return; 650 651 cancel_delayed_work_sync(&drvdata->cfg_resume); 652 cancel_delayed_work_sync(&drvdata->cfg_setup); 653 654 scoped_guard(spinlock_irqsave, &drvdata->registration_lock) { 655 /* Pairs with smp_store_release from cfg_setup_fn in system_wq context */ 656 gp_registered = smp_load_acquire(&drvdata->gp_registered); 657 /* Pairs with smp_load_acquire in attribute show/store functions */ 658 smp_store_release(&drvdata->gp_registered, false); 659 } 660 661 if (gp_registered) 662 device_remove_group(&hdev->dev, &claw_gamepad_attr_group); 663 664 hid_hw_close(hdev); 665 } 666 667 static void msi_remove(struct hid_device *hdev) 668 { 669 int ret; 670 u8 ep; 671 672 /* Safe assumption. SET_INTERFACE ioctl can't be used while driver is bound */ 673 ret = get_endpoint_address(hdev); 674 if (ret <= 0) 675 goto hw_stop; 676 677 ep = ret; 678 if (ep == CLAW_XINPUT_CFG_INTF_IN || ep == CLAW_DINPUT_CFG_INTF_IN) 679 claw_remove(hdev); 680 681 hw_stop: 682 hid_hw_stop(hdev); 683 } 684 685 static int claw_resume(struct hid_device *hdev) 686 { 687 struct claw_drvdata *drvdata = hid_get_drvdata(hdev); 688 689 if (!drvdata) 690 return -ENODEV; 691 692 /* MCU can take up to 500ms to be ready after resume */ 693 schedule_delayed_work(&drvdata->cfg_resume, msecs_to_jiffies(500)); 694 return 0; 695 } 696 697 static int msi_resume(struct hid_device *hdev) 698 { 699 int ret; 700 u8 ep; 701 702 /* Safe assumption. SET_INTERFACE ioctl can't be used while driver is bound */ 703 ret = get_endpoint_address(hdev); 704 if (ret <= 0) 705 return 0; 706 707 ep = ret; 708 if (ep == CLAW_XINPUT_CFG_INTF_IN || ep == CLAW_DINPUT_CFG_INTF_IN) 709 return claw_resume(hdev); 710 711 return 0; 712 } 713 714 static int claw_suspend(struct hid_device *hdev) 715 { 716 struct claw_drvdata *drvdata = hid_get_drvdata(hdev); 717 718 if (!drvdata) 719 return -ENODEV; 720 721 cancel_delayed_work_sync(&drvdata->cfg_resume); 722 cancel_delayed_work_sync(&drvdata->cfg_setup); 723 724 return 0; 725 } 726 727 static int msi_suspend(struct hid_device *hdev, pm_message_t msg) 728 { 729 int ret; 730 u8 ep; 731 732 /* Safe assumption. SET_INTERFACE ioctl can't be used while driver is bound */ 733 ret = get_endpoint_address(hdev); 734 if (ret <= 0) 735 return 0; 736 737 ep = ret; 738 if (ep == CLAW_XINPUT_CFG_INTF_IN || ep == CLAW_DINPUT_CFG_INTF_IN) 739 return claw_suspend(hdev); 740 741 return 0; 742 } 743 744 static const struct hid_device_id msi_devices[] = { 745 { HID_USB_DEVICE(USB_VENDOR_ID_MSI_2, USB_DEVICE_ID_MSI_CLAW_XINPUT) }, 746 { HID_USB_DEVICE(USB_VENDOR_ID_MSI_2, USB_DEVICE_ID_MSI_CLAW_DINPUT) }, 747 { HID_USB_DEVICE(USB_VENDOR_ID_MSI_2, USB_DEVICE_ID_MSI_CLAW_DESKTOP) }, 748 { HID_USB_DEVICE(USB_VENDOR_ID_MSI_2, USB_DEVICE_ID_MSI_CLAW_BIOS) }, 749 { } 750 }; 751 MODULE_DEVICE_TABLE(hid, msi_devices); 752 753 static struct hid_driver msi_driver = { 754 .name = "hid-msi", 755 .id_table = msi_devices, 756 .raw_event = msi_raw_event, 757 .probe = msi_probe, 758 .remove = msi_remove, 759 .resume = pm_ptr(msi_resume), 760 .suspend = pm_ptr(msi_suspend), 761 }; 762 module_hid_driver(msi_driver); 763 764 MODULE_LICENSE("GPL"); 765 MODULE_AUTHOR("Denis Benato <denis.benato@linux.dev>"); 766 MODULE_AUTHOR("Zhouwang Huang <honjow311@gmail.com>"); 767 MODULE_AUTHOR("Derek J. Clark <derekjohn.clark@gmail.com>"); 768 MODULE_DESCRIPTION("HID driver for MSI Claw Handheld PC gamepads"); 769