--- v14
+++ v16
@@ -1,94 +1,73 @@
-Similar to sending subcommands, it is more reliable to send the rumble
-data packets immediately after we've received an input report from the
-controller. This results in far fewer bluetooth disconnects for the
-controller.
+This patch adds a check for if the rumble queue ringbuffer is empty
+prior to queuing the rumble workqueue. If the current rumble setting is
+using a non-zero amplitude though, it will queue the worker anyway. This
+is because the controller will automatically disable the rumble effect
+if it isn't "refreshed".
+
+This change improves bluetooth communication reliability with the
+controller, since it reduces the amount of traffic.
+
+Note that we still send a few periodic zero packets to avoid scenarios
+where the controller fails to process the zero amplitude packet. Without
+sending a few to be sure, the rumble could get stuck on until the
+controller times out.
Signed-off-by: Daniel J. Ogorchock <djogorchock@gmail.com>
---
- drivers/hid/hid-nintendo.c | 49 ++++++++++++++++++++++----------------
- 1 file changed, 29 insertions(+), 20 deletions(-)
+ drivers/hid/hid-nintendo.c | 18 +++++++++++++++++-
+ 1 file changed, 17 insertions(+), 1 deletion(-)
diff --git a/drivers/hid/hid-nintendo.c b/drivers/hid/hid-nintendo.c
-index 71aa676ba3907..d3ec45de9649f 100644
+index ae3cd8ca9fa78..c4270499fc6f3 100644
--- a/drivers/hid/hid-nintendo.c
+++ b/drivers/hid/hid-nintendo.c
-@@ -2,7 +2,7 @@
- /*
- * HID driver for Nintendo Switch Joy-Cons and Pro Controllers
- *
-- * Copyright (c) 2019-2020 Daniel J. Ogorchock <djogorchock@gmail.com>
-+ * Copyright (c) 2019-2021 Daniel J. Ogorchock <djogorchock@gmail.com>
- *
- * The following resources/projects were referenced for this driver:
- * https://github.com/dekuNukem/Nintendo_Switch_Reverse_Engineering
-@@ -511,6 +511,31 @@ static int __joycon_hid_send(struct hid_device *hdev, u8 *data, size_t len)
- return ret;
- }
+@@ -400,6 +400,7 @@ struct joycon_input_report {
+ static const u16 JC_RUMBLE_DFLT_LOW_FREQ = 160;
+ static const u16 JC_RUMBLE_DFLT_HIGH_FREQ = 320;
+ static const u16 JC_RUMBLE_PERIOD_MS = 50;
++static const unsigned short JC_RUMBLE_ZERO_AMP_PKT_CNT = 5;
-+static void joycon_wait_for_input_report(struct joycon_ctlr *ctlr)
-+{
-+ int ret;
-+
-+ /*
-+ * If we are in the proper reporting mode, wait for an input
-+ * report prior to sending the subcommand. This improves
-+ * reliability considerably.
-+ */
-+ if (ctlr->ctlr_state == JOYCON_CTLR_STATE_READ) {
-+ unsigned long flags;
-+
-+ spin_lock_irqsave(&ctlr->lock, flags);
-+ ctlr->received_input_report = false;
-+ spin_unlock_irqrestore(&ctlr->lock, flags);
-+ ret = wait_event_timeout(ctlr->wait,
-+ ctlr->received_input_report,
-+ HZ / 4);
-+ /* We will still proceed, even with a timeout here */
-+ if (!ret)
-+ hid_warn(ctlr->hdev,
-+ "timeout waiting for input report\n");
+ static const char * const joycon_player_led_names[] = {
+ LED_FUNCTION_PLAYER1,
+@@ -464,6 +465,7 @@ struct joycon_ctlr {
+ u16 rumble_lh_freq;
+ u16 rumble_rl_freq;
+ u16 rumble_rh_freq;
++ unsigned short rumble_zero_countdown;
+
+ /* imu */
+ struct input_dev *imu_input;
+@@ -1218,8 +1220,19 @@ static void joycon_parse_report(struct joycon_ctlr *ctlr,
+
+ spin_lock_irqsave(&ctlr->lock, flags);
+ if (IS_ENABLED(CONFIG_NINTENDO_FF) && rep->vibrator_report &&
+- (msecs - ctlr->rumble_msecs) >= JC_RUMBLE_PERIOD_MS)
++ (msecs - ctlr->rumble_msecs) >= JC_RUMBLE_PERIOD_MS &&
++ (ctlr->rumble_queue_head != ctlr->rumble_queue_tail ||
++ ctlr->rumble_zero_countdown > 0)) {
++ /*
++ * When this value reaches 0, we know we've sent multiple
++ * packets to the controller instructing it to disable rumble.
++ * We can safely stop sending periodic rumble packets until the
++ * next ff effect.
++ */
++ if (ctlr->rumble_zero_countdown > 0)
++ ctlr->rumble_zero_countdown--;
+ queue_work(ctlr->rumble_queue, &ctlr->rumble_worker);
+ }
-+}
-+
- static int joycon_hid_send_sync(struct joycon_ctlr *ctlr, u8 *data, size_t len,
- u32 timeout)
- {
-@@ -522,25 +547,7 @@ static int joycon_hid_send_sync(struct joycon_ctlr *ctlr, u8 *data, size_t len,
- * doing one retry after a timeout appears to always work.
- */
- while (tries--) {
-- /*
-- * If we are in the proper reporting mode, wait for an input
-- * report prior to sending the subcommand. This improves
-- * reliability considerably.
-- */
-- if (ctlr->ctlr_state == JOYCON_CTLR_STATE_READ) {
-- unsigned long flags;
--
-- spin_lock_irqsave(&ctlr->lock, flags);
-- ctlr->received_input_report = false;
-- spin_unlock_irqrestore(&ctlr->lock, flags);
-- ret = wait_event_timeout(ctlr->wait,
-- ctlr->received_input_report,
-- HZ / 4);
-- /* We will still proceed, even with a timeout here */
-- if (!ret)
-- hid_warn(ctlr->hdev,
-- "timeout waiting for input report\n");
-- }
-+ joycon_wait_for_input_report(ctlr);
- ret = __joycon_hid_send(ctlr->hdev, data, len);
- if (ret < 0) {
-@@ -1379,6 +1386,8 @@ static int joycon_send_rumble_data(struct joycon_ctlr *ctlr)
- if (++ctlr->subcmd_num > 0xF)
- ctlr->subcmd_num = 0;
+ /* Parse the battery status */
+ tmp = rep->bat_con;
+@@ -1513,6 +1526,9 @@ static int joycon_set_rumble(struct joycon_ctlr *ctlr, u16 amp_r, u16 amp_l,
+ freq_r_high = ctlr->rumble_rh_freq;
+ freq_l_low = ctlr->rumble_ll_freq;
+ freq_l_high = ctlr->rumble_lh_freq;
++ /* limit number of silent rumble packets to reduce traffic */
++ if (amp_l != 0 || amp_r != 0)
++ ctlr->rumble_zero_countdown = JC_RUMBLE_ZERO_AMP_PKT_CNT;
+ spin_unlock_irqrestore(&ctlr->lock, flags);
-+ joycon_wait_for_input_report(ctlr);
-+
- ret = __joycon_hid_send(ctlr->hdev, (u8 *)&rumble_output,
- sizeof(rumble_output));
- return ret;
+ /* right joy-con */
--
-2.32.0
+2.33.0