@@ -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
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@gmail.com> --- drivers/hid/hid-nintendo.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+)