Skip to content

Commit d750d14

Browse files
DanielOgorchockJiri Kosina
authored andcommitted
HID: nintendo: fix rumble rate limiter
It's been discovered that BT controller disconnect events correlate to erratic input report timestamp deltas. In experimentation, it's been found that ensuring that multiple timestamp deltas are consistent prior to transmitting a rumble packet drastically reduces the occurence rate of BT disconnects. Alter the joycon_enforce_subcmd_rate() function to use this new approach. Signed-off-by: Daniel J. Ogorchock <[email protected]> Reviewed-by: Silvan Jegen <[email protected] Signed-off-by: Jiri Kosina <[email protected]>
1 parent bcba9f3 commit d750d14

File tree

1 file changed

+69
-6
lines changed

1 file changed

+69
-6
lines changed

drivers/hid/hid-nintendo.c

Lines changed: 69 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -433,7 +433,9 @@ struct joycon_ctlr {
433433
u8 usb_ack_match;
434434
u8 subcmd_ack_match;
435435
bool received_input_report;
436+
unsigned int last_input_report_msecs;
436437
unsigned int last_subcmd_sent_msecs;
438+
unsigned int consecutive_valid_report_deltas;
437439

438440
/* factory calibration data */
439441
struct joycon_stick_cal left_stick_cal_x;
@@ -543,19 +545,54 @@ static void joycon_wait_for_input_report(struct joycon_ctlr *ctlr)
543545
* Sending subcommands and/or rumble data at too high a rate can cause bluetooth
544546
* controller disconnections.
545547
*/
548+
#define JC_INPUT_REPORT_MIN_DELTA 8
549+
#define JC_INPUT_REPORT_MAX_DELTA 17
550+
#define JC_SUBCMD_TX_OFFSET_MS 4
551+
#define JC_SUBCMD_VALID_DELTA_REQ 3
552+
#define JC_SUBCMD_RATE_MAX_ATTEMPTS 500
553+
#define JC_SUBCMD_RATE_LIMITER_USB_MS 20
554+
#define JC_SUBCMD_RATE_LIMITER_BT_MS 60
555+
#define JC_SUBCMD_RATE_LIMITER_MS(ctlr) ((ctlr)->hdev->bus == BUS_USB ? JC_SUBCMD_RATE_LIMITER_USB_MS : JC_SUBCMD_RATE_LIMITER_BT_MS)
546556
static void joycon_enforce_subcmd_rate(struct joycon_ctlr *ctlr)
547557
{
548-
static const unsigned int max_subcmd_rate_ms = 25;
549-
unsigned int current_ms = jiffies_to_msecs(jiffies);
550-
unsigned int delta_ms = current_ms - ctlr->last_subcmd_sent_msecs;
558+
unsigned int current_ms;
559+
unsigned long subcmd_delta;
560+
int consecutive_valid_deltas = 0;
561+
int attempts = 0;
562+
unsigned long flags;
563+
564+
if (unlikely(ctlr->ctlr_state != JOYCON_CTLR_STATE_READ))
565+
return;
551566

552-
while (delta_ms < max_subcmd_rate_ms &&
553-
ctlr->ctlr_state == JOYCON_CTLR_STATE_READ) {
567+
do {
554568
joycon_wait_for_input_report(ctlr);
555569
current_ms = jiffies_to_msecs(jiffies);
556-
delta_ms = current_ms - ctlr->last_subcmd_sent_msecs;
570+
subcmd_delta = current_ms - ctlr->last_subcmd_sent_msecs;
571+
572+
spin_lock_irqsave(&ctlr->lock, flags);
573+
consecutive_valid_deltas = ctlr->consecutive_valid_report_deltas;
574+
spin_unlock_irqrestore(&ctlr->lock, flags);
575+
576+
attempts++;
577+
} while ((consecutive_valid_deltas < JC_SUBCMD_VALID_DELTA_REQ ||
578+
subcmd_delta < JC_SUBCMD_RATE_LIMITER_MS(ctlr)) &&
579+
ctlr->ctlr_state == JOYCON_CTLR_STATE_READ &&
580+
attempts < JC_SUBCMD_RATE_MAX_ATTEMPTS);
581+
582+
if (attempts >= JC_SUBCMD_RATE_MAX_ATTEMPTS) {
583+
hid_warn(ctlr->hdev, "%s: exceeded max attempts", __func__);
584+
return;
557585
}
586+
558587
ctlr->last_subcmd_sent_msecs = current_ms;
588+
589+
/*
590+
* Wait a short time after receiving an input report before
591+
* transmitting. This should reduce odds of a TX coinciding with an RX.
592+
* Minimizing concurrent BT traffic with the controller seems to lower
593+
* the rate of disconnections.
594+
*/
595+
msleep(JC_SUBCMD_TX_OFFSET_MS);
559596
}
560597

561598
static int joycon_hid_send_sync(struct joycon_ctlr *ctlr, u8 *data, size_t len,
@@ -1223,6 +1260,7 @@ static void joycon_parse_report(struct joycon_ctlr *ctlr,
12231260
u8 tmp;
12241261
u32 btns;
12251262
unsigned long msecs = jiffies_to_msecs(jiffies);
1263+
unsigned long report_delta_ms = msecs - ctlr->last_input_report_msecs;
12261264

12271265
spin_lock_irqsave(&ctlr->lock, flags);
12281266
if (IS_ENABLED(CONFIG_NINTENDO_FF) && rep->vibrator_report &&
@@ -1364,6 +1402,31 @@ static void joycon_parse_report(struct joycon_ctlr *ctlr,
13641402

13651403
input_sync(dev);
13661404

1405+
spin_lock_irqsave(&ctlr->lock, flags);
1406+
ctlr->last_input_report_msecs = msecs;
1407+
/*
1408+
* Was this input report a reasonable time delta compared to the prior
1409+
* report? We use this information to decide when a safe time is to send
1410+
* rumble packets or subcommand packets.
1411+
*/
1412+
if (report_delta_ms >= JC_INPUT_REPORT_MIN_DELTA &&
1413+
report_delta_ms <= JC_INPUT_REPORT_MAX_DELTA) {
1414+
if (ctlr->consecutive_valid_report_deltas < JC_SUBCMD_VALID_DELTA_REQ)
1415+
ctlr->consecutive_valid_report_deltas++;
1416+
} else {
1417+
ctlr->consecutive_valid_report_deltas = 0;
1418+
}
1419+
/*
1420+
* Our consecutive valid report tracking is only relevant for
1421+
* bluetooth-connected controllers. For USB devices, we're beholden to
1422+
* USB's underlying polling rate anyway. Always set to the consecutive
1423+
* delta requirement.
1424+
*/
1425+
if (ctlr->hdev->bus == BUS_USB)
1426+
ctlr->consecutive_valid_report_deltas = JC_SUBCMD_VALID_DELTA_REQ;
1427+
1428+
spin_unlock_irqrestore(&ctlr->lock, flags);
1429+
13671430
/*
13681431
* Immediately after receiving a report is the most reliable time to
13691432
* send a subcommand to the controller. Wake any subcommand senders

0 commit comments

Comments
 (0)