Thread (21 messages) 21 messages, 3 authors, 2021-09-11
STALE1843d

Revision v14 of 4 in this series.

Revisions (4)
  1. v13 [diff vs current]
  2. v14 current
  3. v15 [diff vs current]
  4. v16 [diff vs current]

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

From: "Daniel J. Ogorchock" <djogorchock@gmail.com>
Date: 2021-07-25 03:28:03
Subsystem: hid core layer, nintendo hid driver, the rest · Maintainers: Jiri Kosina, Benjamin Tissoires, Daniel J. Ogorchock, Linus Torvalds

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(+)
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
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help