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. Signed-off-by: Daniel J. Ogorchock <djogorchock@xxxxxxxxx> --- drivers/hid/hid-nintendo.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/drivers/hid/hid-nintendo.c b/drivers/hid/hid-nintendo.c index 9376f20baab00..71aa676ba3907 100644 --- a/drivers/hid/hid-nintendo.c +++ b/drivers/hid/hid-nintendo.c @@ -431,6 +431,7 @@ struct joycon_ctlr { u8 usb_ack_match; u8 subcmd_ack_match; bool received_input_report; + unsigned int last_subcmd_sent_msecs; /* factory calibration data */ struct joycon_stick_cal left_stick_cal_x; @@ -582,6 +583,21 @@ static int joycon_send_usb(struct joycon_ctlr *ctlr, u8 cmd, u32 timeout) return ret; } +/* + * Sending subcommands and/or rumble data at too high a rate can cause bluetooth + * controller disconnections. + */ +static void joycon_enforce_subcmd_rate(struct joycon_ctlr *ctlr) +{ + static const unsigned int max_subcmd_rate_ms = 25; + unsigned int current_ms = jiffies_to_msecs(jiffies); + unsigned int delta_ms = current_ms - ctlr->last_subcmd_sent_msecs; + + if (delta_ms < max_subcmd_rate_ms) + msleep(max_subcmd_rate_ms - delta_ms); + ctlr->last_subcmd_sent_msecs = current_ms; +} + static int joycon_send_subcmd(struct joycon_ctlr *ctlr, struct joycon_subcmd_request *subcmd, size_t data_len, u32 timeout) @@ -589,6 +605,8 @@ static int joycon_send_subcmd(struct joycon_ctlr *ctlr, int ret; unsigned long flags; + joycon_enforce_subcmd_rate(ctlr); + spin_lock_irqsave(&ctlr->lock, flags); /* * If the controller has been removed, just return ENODEV so the LED @@ -1340,6 +1358,8 @@ static int joycon_send_rumble_data(struct joycon_ctlr *ctlr) unsigned long flags; struct joycon_rumble_output rumble_output = { 0 }; + joycon_enforce_subcmd_rate(ctlr); + spin_lock_irqsave(&ctlr->lock, flags); /* * If the controller has been removed, just return ENODEV so the LED -- 2.32.0