[PATCH v14 15/17] HID: nintendo: ratelimit subcommands and rumble

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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




[Index of Archives]     [Linux Media Devel]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Linux Wireless Networking]     [Linux Omap]

  Powered by Linux