summaryrefslogtreecommitdiff
path: root/drivers/hid
diff options
context:
space:
mode:
authorJiri Kosina <jkosina@suse.com>2026-08-19 09:20:17 +0200
committerJiri Kosina <jkosina@suse.com>2026-08-19 09:20:17 +0200
commit6fccb6015fbd14389ae5373a6ef34043df4d1edd (patch)
tree139ac2f3680191731ca9d5dfcd063f0b366e1e15 /drivers/hid
parent5c4364ae1caa9a857fe7cf5d98ee0d867dc9839f (diff)
parentd723bc1fe2e72b9252234e94c11af644ec477bf7 (diff)
Merge branch 'for-7.3/nintendo' into for-linus
- assorted fixes (Alexandre Derumier, Christos Maragkos, Jiangshan Yi)
Diffstat (limited to 'drivers/hid')
-rw-r--r--drivers/hid/hid-nintendo.c48
1 files changed, 42 insertions, 6 deletions
diff --git a/drivers/hid/hid-nintendo.c b/drivers/hid/hid-nintendo.c
index 99bfa6a12096..43e0f2aaea3b 100644
--- a/drivers/hid/hid-nintendo.c
+++ b/drivers/hid/hid-nintendo.c
@@ -609,6 +609,8 @@ struct joycon_ctlr {
unsigned int last_input_report_msecs;
unsigned int last_subcmd_sent_msecs;
unsigned int consecutive_valid_report_deltas;
+ unsigned int subcmd_rate_exhaustions;
+ bool subcmd_rate_relaxed;
/* factory calibration data */
struct joycon_stick_cal left_stick_cal_x;
@@ -841,10 +843,11 @@ static void joycon_wait_for_input_report(struct joycon_ctlr *ctlr)
#define JC_SUBCMD_TX_OFFSET_MS 4
#define JC_SUBCMD_VALID_DELTA_REQ 3
#define JC_SUBCMD_RATE_MAX_ATTEMPTS 25
+#define JC_SUBCMD_RATE_MAX_FAILURES 4
#define JC_SUBCMD_RATE_LIMITER_USB_MS 20
#define JC_SUBCMD_RATE_LIMITER_BT_MS 60
#define JC_SUBCMD_RATE_LIMITER_MS(ctlr) ((ctlr)->hdev->bus == BUS_USB ? JC_SUBCMD_RATE_LIMITER_USB_MS : JC_SUBCMD_RATE_LIMITER_BT_MS)
-static void joycon_enforce_subcmd_rate(struct joycon_ctlr *ctlr)
+static void joycon_enforce_subcmd_rate_strict(struct joycon_ctlr *ctlr)
{
unsigned int current_ms;
unsigned long subcmd_delta;
@@ -872,6 +875,14 @@ static void joycon_enforce_subcmd_rate(struct joycon_ctlr *ctlr)
if (attempts >= JC_SUBCMD_RATE_MAX_ATTEMPTS) {
hid_warn(ctlr->hdev, "%s: exceeded max attempts", __func__);
+
+ if (++ctlr->subcmd_rate_exhaustions == JC_SUBCMD_RATE_MAX_FAILURES) {
+ ctlr->subcmd_rate_relaxed = true;
+ hid_info(ctlr->hdev,
+ "input report cadence does not fit the %d-%dms window; using the legacy subcommand throttle\n",
+ JC_INPUT_REPORT_MIN_DELTA,
+ JC_INPUT_REPORT_MAX_DELTA);
+ }
return;
}
@@ -886,6 +897,32 @@ static void joycon_enforce_subcmd_rate(struct joycon_ctlr *ctlr)
msleep(JC_SUBCMD_TX_OFFSET_MS);
}
+/* The rate limiter as it was before commit d750d1480362, without the report
+ * cadence requirement.
+ */
+static void joycon_enforce_subcmd_rate_legacy(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;
+
+ while (delta_ms < max_subcmd_rate_ms &&
+ ctlr->ctlr_state == JOYCON_CTLR_STATE_READ) {
+ joycon_wait_for_input_report(ctlr);
+ current_ms = jiffies_to_msecs(jiffies);
+ delta_ms = current_ms - ctlr->last_subcmd_sent_msecs;
+ }
+ ctlr->last_subcmd_sent_msecs = current_ms;
+}
+
+static void joycon_enforce_subcmd_rate(struct joycon_ctlr *ctlr)
+{
+ if (ctlr->subcmd_rate_relaxed)
+ joycon_enforce_subcmd_rate_legacy(ctlr);
+ else
+ joycon_enforce_subcmd_rate_strict(ctlr);
+}
+
static int joycon_hid_send_sync(struct joycon_ctlr *ctlr, u8 *data, size_t len,
u32 timeout)
{
@@ -1474,7 +1511,6 @@ static void joycon_parse_imu_report(struct joycon_ctlr *ctlr,
dropped_threshold = ctlr->imu_avg_delta_ms * 3 / 2;
dropped_pkts = (delta - min(delta, dropped_threshold)) /
ctlr->imu_avg_delta_ms;
- ctlr->imu_timestamp_us += 1000 * ctlr->imu_avg_delta_ms;
if (dropped_pkts > JC_IMU_DROPPED_PKT_WARNING) {
hid_warn_ratelimited(ctlr->hdev,
"compensating for %u dropped IMU reports\n",
@@ -2162,10 +2198,6 @@ static int joycon_input_create(struct joycon_ctlr *ctlr)
ctlr->input->phys = hdev->phys;
input_set_drvdata(ctlr->input, ctlr);
- ret = input_register_device(ctlr->input);
- if (ret)
- return ret;
-
if (joycon_type_is_right_joycon(ctlr)) {
joycon_config_right_stick(ctlr->input);
joycon_config_buttons(ctlr->input, right_joycon_button_mappings);
@@ -2208,6 +2240,10 @@ static int joycon_input_create(struct joycon_ctlr *ctlr)
if (joycon_has_rumble(ctlr))
joycon_config_rumble(ctlr);
+ ret = input_register_device(ctlr->input);
+ if (ret)
+ return ret;
+
return 0;
}