Skip to content

Commit e93363f

Browse files
DanielOgorchockJiri Kosina
authored andcommitted
HID: nintendo: ratelimit subcommands and rumble
It has been found that sending subcommands and rumble data packets at too great a rate can result in controller disconnects. This patch limits the rate of subcommands/rumble to once every 25 milliseconds. Similar to sending subcommands, it is more reliable to send the rumble data packets immediately after we've received an input report from the controller. This results in far fewer bluetooth disconnects for the controller. Signed-off-by: Daniel J. Ogorchock <djogorchock@gmail.com> Signed-off-by: Jiri Kosina <jkosina@suse.cz>
1 parent 4c048f6 commit e93363f

1 file changed

Lines changed: 49 additions & 20 deletions

File tree

drivers/hid/hid-nintendo.c

Lines changed: 49 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
/*
33
* HID driver for Nintendo Switch Joy-Cons and Pro Controllers
44
*
5-
* Copyright (c) 2019-2020 Daniel J. Ogorchock <djogorchock@gmail.com>
5+
* Copyright (c) 2019-2021 Daniel J. Ogorchock <djogorchock@gmail.com>
66
*
77
* The following resources/projects were referenced for this driver:
88
* https://github.com/dekuNukem/Nintendo_Switch_Reverse_Engineering
@@ -431,6 +431,7 @@ struct joycon_ctlr {
431431
u8 usb_ack_match;
432432
u8 subcmd_ack_match;
433433
bool received_input_report;
434+
unsigned int last_subcmd_sent_msecs;
434435

435436
/* factory calibration data */
436437
struct joycon_stick_cal left_stick_cal_x;
@@ -510,6 +511,50 @@ static int __joycon_hid_send(struct hid_device *hdev, u8 *data, size_t len)
510511
return ret;
511512
}
512513

514+
static void joycon_wait_for_input_report(struct joycon_ctlr *ctlr)
515+
{
516+
int ret;
517+
518+
/*
519+
* If we are in the proper reporting mode, wait for an input
520+
* report prior to sending the subcommand. This improves
521+
* reliability considerably.
522+
*/
523+
if (ctlr->ctlr_state == JOYCON_CTLR_STATE_READ) {
524+
unsigned long flags;
525+
526+
spin_lock_irqsave(&ctlr->lock, flags);
527+
ctlr->received_input_report = false;
528+
spin_unlock_irqrestore(&ctlr->lock, flags);
529+
ret = wait_event_timeout(ctlr->wait,
530+
ctlr->received_input_report,
531+
HZ / 4);
532+
/* We will still proceed, even with a timeout here */
533+
if (!ret)
534+
hid_warn(ctlr->hdev,
535+
"timeout waiting for input report\n");
536+
}
537+
}
538+
539+
/*
540+
* Sending subcommands and/or rumble data at too high a rate can cause bluetooth
541+
* controller disconnections.
542+
*/
543+
static void joycon_enforce_subcmd_rate(struct joycon_ctlr *ctlr)
544+
{
545+
static const unsigned int max_subcmd_rate_ms = 25;
546+
unsigned int current_ms = jiffies_to_msecs(jiffies);
547+
unsigned int delta_ms = current_ms - ctlr->last_subcmd_sent_msecs;
548+
549+
while (delta_ms < max_subcmd_rate_ms &&
550+
ctlr->ctlr_state == JOYCON_CTLR_STATE_READ) {
551+
joycon_wait_for_input_report(ctlr);
552+
current_ms = jiffies_to_msecs(jiffies);
553+
delta_ms = current_ms - ctlr->last_subcmd_sent_msecs;
554+
}
555+
ctlr->last_subcmd_sent_msecs = current_ms;
556+
}
557+
513558
static int joycon_hid_send_sync(struct joycon_ctlr *ctlr, u8 *data, size_t len,
514559
u32 timeout)
515560
{
@@ -521,25 +566,7 @@ static int joycon_hid_send_sync(struct joycon_ctlr *ctlr, u8 *data, size_t len,
521566
* doing one retry after a timeout appears to always work.
522567
*/
523568
while (tries--) {
524-
/*
525-
* If we are in the proper reporting mode, wait for an input
526-
* report prior to sending the subcommand. This improves
527-
* reliability considerably.
528-
*/
529-
if (ctlr->ctlr_state == JOYCON_CTLR_STATE_READ) {
530-
unsigned long flags;
531-
532-
spin_lock_irqsave(&ctlr->lock, flags);
533-
ctlr->received_input_report = false;
534-
spin_unlock_irqrestore(&ctlr->lock, flags);
535-
ret = wait_event_timeout(ctlr->wait,
536-
ctlr->received_input_report,
537-
HZ / 4);
538-
/* We will still proceed, even with a timeout here */
539-
if (!ret)
540-
hid_warn(ctlr->hdev,
541-
"timeout waiting for input report\n");
542-
}
569+
joycon_enforce_subcmd_rate(ctlr);
543570

544571
ret = __joycon_hid_send(ctlr->hdev, data, len);
545572
if (ret < 0) {
@@ -1359,6 +1386,8 @@ static int joycon_send_rumble_data(struct joycon_ctlr *ctlr)
13591386
if (++ctlr->subcmd_num > 0xF)
13601387
ctlr->subcmd_num = 0;
13611388

1389+
joycon_enforce_subcmd_rate(ctlr);
1390+
13621391
ret = __joycon_hid_send(ctlr->hdev, (u8 *)&rumble_output,
13631392
sizeof(rumble_output));
13641393
return ret;

0 commit comments

Comments
 (0)