Loading drivers/hid/hid-nintendo.c +86 −9 Original line number Diff line number Diff line Loading @@ -433,7 +433,9 @@ struct joycon_ctlr { u8 usb_ack_match; u8 subcmd_ack_match; bool received_input_report; unsigned int last_input_report_msecs; unsigned int last_subcmd_sent_msecs; unsigned int consecutive_valid_report_deltas; /* factory calibration data */ struct joycon_stick_cal left_stick_cal_x; Loading Loading @@ -543,19 +545,54 @@ static void joycon_wait_for_input_report(struct joycon_ctlr *ctlr) * Sending subcommands and/or rumble data at too high a rate can cause bluetooth * controller disconnections. */ #define JC_INPUT_REPORT_MIN_DELTA 8 #define JC_INPUT_REPORT_MAX_DELTA 17 #define JC_SUBCMD_TX_OFFSET_MS 4 #define JC_SUBCMD_VALID_DELTA_REQ 3 #define JC_SUBCMD_RATE_MAX_ATTEMPTS 500 #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 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; unsigned int current_ms; unsigned long subcmd_delta; int consecutive_valid_deltas = 0; int attempts = 0; unsigned long flags; if (unlikely(ctlr->ctlr_state != JOYCON_CTLR_STATE_READ)) return; while (delta_ms < max_subcmd_rate_ms && ctlr->ctlr_state == JOYCON_CTLR_STATE_READ) { do { joycon_wait_for_input_report(ctlr); current_ms = jiffies_to_msecs(jiffies); delta_ms = current_ms - ctlr->last_subcmd_sent_msecs; subcmd_delta = current_ms - ctlr->last_subcmd_sent_msecs; spin_lock_irqsave(&ctlr->lock, flags); consecutive_valid_deltas = ctlr->consecutive_valid_report_deltas; spin_unlock_irqrestore(&ctlr->lock, flags); attempts++; } while ((consecutive_valid_deltas < JC_SUBCMD_VALID_DELTA_REQ || subcmd_delta < JC_SUBCMD_RATE_LIMITER_MS(ctlr)) && ctlr->ctlr_state == JOYCON_CTLR_STATE_READ && attempts < JC_SUBCMD_RATE_MAX_ATTEMPTS); if (attempts >= JC_SUBCMD_RATE_MAX_ATTEMPTS) { hid_warn(ctlr->hdev, "%s: exceeded max attempts", __func__); return; } ctlr->last_subcmd_sent_msecs = current_ms; /* * Wait a short time after receiving an input report before * transmitting. This should reduce odds of a TX coinciding with an RX. * Minimizing concurrent BT traffic with the controller seems to lower * the rate of disconnections. */ msleep(JC_SUBCMD_TX_OFFSET_MS); } static int joycon_hid_send_sync(struct joycon_ctlr *ctlr, u8 *data, size_t len, Loading Loading @@ -1223,6 +1260,7 @@ static void joycon_parse_report(struct joycon_ctlr *ctlr, u8 tmp; u32 btns; unsigned long msecs = jiffies_to_msecs(jiffies); unsigned long report_delta_ms = msecs - ctlr->last_input_report_msecs; spin_lock_irqsave(&ctlr->lock, flags); if (IS_ENABLED(CONFIG_NINTENDO_FF) && rep->vibrator_report && Loading Loading @@ -1364,6 +1402,31 @@ static void joycon_parse_report(struct joycon_ctlr *ctlr, input_sync(dev); spin_lock_irqsave(&ctlr->lock, flags); ctlr->last_input_report_msecs = msecs; /* * Was this input report a reasonable time delta compared to the prior * report? We use this information to decide when a safe time is to send * rumble packets or subcommand packets. */ if (report_delta_ms >= JC_INPUT_REPORT_MIN_DELTA && report_delta_ms <= JC_INPUT_REPORT_MAX_DELTA) { if (ctlr->consecutive_valid_report_deltas < JC_SUBCMD_VALID_DELTA_REQ) ctlr->consecutive_valid_report_deltas++; } else { ctlr->consecutive_valid_report_deltas = 0; } /* * Our consecutive valid report tracking is only relevant for * bluetooth-connected controllers. For USB devices, we're beholden to * USB's underlying polling rate anyway. Always set to the consecutive * delta requirement. */ if (ctlr->hdev->bus == BUS_USB) ctlr->consecutive_valid_report_deltas = JC_SUBCMD_VALID_DELTA_REQ; spin_unlock_irqrestore(&ctlr->lock, flags); /* * Immediately after receiving a report is the most reliable time to * send a subcommand to the controller. Wake any subcommand senders Loading Loading @@ -1527,6 +1590,7 @@ static int joycon_set_rumble(struct joycon_ctlr *ctlr, u16 amp_r, u16 amp_l, u16 freq_l_low; u16 freq_l_high; unsigned long flags; int next_rq_head; spin_lock_irqsave(&ctlr->lock, flags); freq_r_low = ctlr->rumble_rl_freq; Loading @@ -1547,8 +1611,21 @@ static int joycon_set_rumble(struct joycon_ctlr *ctlr, u16 amp_r, u16 amp_l, joycon_encode_rumble(data, freq_l_low, freq_l_high, amp); spin_lock_irqsave(&ctlr->lock, flags); if (++ctlr->rumble_queue_head >= JC_RUMBLE_QUEUE_SIZE) ctlr->rumble_queue_head = 0; next_rq_head = ctlr->rumble_queue_head + 1; if (next_rq_head >= JC_RUMBLE_QUEUE_SIZE) next_rq_head = 0; /* Did we overrun the circular buffer? * If so, be sure we keep the latest intended rumble state. */ if (next_rq_head == ctlr->rumble_queue_tail) { hid_dbg(ctlr->hdev, "rumble queue is full"); /* overwrite the prior value at the end of the circular buf */ next_rq_head = ctlr->rumble_queue_head; } ctlr->rumble_queue_head = next_rq_head; memcpy(ctlr->rumble_data[ctlr->rumble_queue_head], data, JC_RUMBLE_DATA_SIZE); Loading Loading @@ -2128,7 +2205,7 @@ static int nintendo_hid_probe(struct hid_device *hdev, ctlr->hdev = hdev; ctlr->ctlr_state = JOYCON_CTLR_STATE_INIT; ctlr->rumble_queue_head = JC_RUMBLE_QUEUE_SIZE - 1; ctlr->rumble_queue_head = 0; ctlr->rumble_queue_tail = 0; hid_set_drvdata(hdev, ctlr); mutex_init(&ctlr->output_mutex); Loading Loading
drivers/hid/hid-nintendo.c +86 −9 Original line number Diff line number Diff line Loading @@ -433,7 +433,9 @@ struct joycon_ctlr { u8 usb_ack_match; u8 subcmd_ack_match; bool received_input_report; unsigned int last_input_report_msecs; unsigned int last_subcmd_sent_msecs; unsigned int consecutive_valid_report_deltas; /* factory calibration data */ struct joycon_stick_cal left_stick_cal_x; Loading Loading @@ -543,19 +545,54 @@ static void joycon_wait_for_input_report(struct joycon_ctlr *ctlr) * Sending subcommands and/or rumble data at too high a rate can cause bluetooth * controller disconnections. */ #define JC_INPUT_REPORT_MIN_DELTA 8 #define JC_INPUT_REPORT_MAX_DELTA 17 #define JC_SUBCMD_TX_OFFSET_MS 4 #define JC_SUBCMD_VALID_DELTA_REQ 3 #define JC_SUBCMD_RATE_MAX_ATTEMPTS 500 #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 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; unsigned int current_ms; unsigned long subcmd_delta; int consecutive_valid_deltas = 0; int attempts = 0; unsigned long flags; if (unlikely(ctlr->ctlr_state != JOYCON_CTLR_STATE_READ)) return; while (delta_ms < max_subcmd_rate_ms && ctlr->ctlr_state == JOYCON_CTLR_STATE_READ) { do { joycon_wait_for_input_report(ctlr); current_ms = jiffies_to_msecs(jiffies); delta_ms = current_ms - ctlr->last_subcmd_sent_msecs; subcmd_delta = current_ms - ctlr->last_subcmd_sent_msecs; spin_lock_irqsave(&ctlr->lock, flags); consecutive_valid_deltas = ctlr->consecutive_valid_report_deltas; spin_unlock_irqrestore(&ctlr->lock, flags); attempts++; } while ((consecutive_valid_deltas < JC_SUBCMD_VALID_DELTA_REQ || subcmd_delta < JC_SUBCMD_RATE_LIMITER_MS(ctlr)) && ctlr->ctlr_state == JOYCON_CTLR_STATE_READ && attempts < JC_SUBCMD_RATE_MAX_ATTEMPTS); if (attempts >= JC_SUBCMD_RATE_MAX_ATTEMPTS) { hid_warn(ctlr->hdev, "%s: exceeded max attempts", __func__); return; } ctlr->last_subcmd_sent_msecs = current_ms; /* * Wait a short time after receiving an input report before * transmitting. This should reduce odds of a TX coinciding with an RX. * Minimizing concurrent BT traffic with the controller seems to lower * the rate of disconnections. */ msleep(JC_SUBCMD_TX_OFFSET_MS); } static int joycon_hid_send_sync(struct joycon_ctlr *ctlr, u8 *data, size_t len, Loading Loading @@ -1223,6 +1260,7 @@ static void joycon_parse_report(struct joycon_ctlr *ctlr, u8 tmp; u32 btns; unsigned long msecs = jiffies_to_msecs(jiffies); unsigned long report_delta_ms = msecs - ctlr->last_input_report_msecs; spin_lock_irqsave(&ctlr->lock, flags); if (IS_ENABLED(CONFIG_NINTENDO_FF) && rep->vibrator_report && Loading Loading @@ -1364,6 +1402,31 @@ static void joycon_parse_report(struct joycon_ctlr *ctlr, input_sync(dev); spin_lock_irqsave(&ctlr->lock, flags); ctlr->last_input_report_msecs = msecs; /* * Was this input report a reasonable time delta compared to the prior * report? We use this information to decide when a safe time is to send * rumble packets or subcommand packets. */ if (report_delta_ms >= JC_INPUT_REPORT_MIN_DELTA && report_delta_ms <= JC_INPUT_REPORT_MAX_DELTA) { if (ctlr->consecutive_valid_report_deltas < JC_SUBCMD_VALID_DELTA_REQ) ctlr->consecutive_valid_report_deltas++; } else { ctlr->consecutive_valid_report_deltas = 0; } /* * Our consecutive valid report tracking is only relevant for * bluetooth-connected controllers. For USB devices, we're beholden to * USB's underlying polling rate anyway. Always set to the consecutive * delta requirement. */ if (ctlr->hdev->bus == BUS_USB) ctlr->consecutive_valid_report_deltas = JC_SUBCMD_VALID_DELTA_REQ; spin_unlock_irqrestore(&ctlr->lock, flags); /* * Immediately after receiving a report is the most reliable time to * send a subcommand to the controller. Wake any subcommand senders Loading Loading @@ -1527,6 +1590,7 @@ static int joycon_set_rumble(struct joycon_ctlr *ctlr, u16 amp_r, u16 amp_l, u16 freq_l_low; u16 freq_l_high; unsigned long flags; int next_rq_head; spin_lock_irqsave(&ctlr->lock, flags); freq_r_low = ctlr->rumble_rl_freq; Loading @@ -1547,8 +1611,21 @@ static int joycon_set_rumble(struct joycon_ctlr *ctlr, u16 amp_r, u16 amp_l, joycon_encode_rumble(data, freq_l_low, freq_l_high, amp); spin_lock_irqsave(&ctlr->lock, flags); if (++ctlr->rumble_queue_head >= JC_RUMBLE_QUEUE_SIZE) ctlr->rumble_queue_head = 0; next_rq_head = ctlr->rumble_queue_head + 1; if (next_rq_head >= JC_RUMBLE_QUEUE_SIZE) next_rq_head = 0; /* Did we overrun the circular buffer? * If so, be sure we keep the latest intended rumble state. */ if (next_rq_head == ctlr->rumble_queue_tail) { hid_dbg(ctlr->hdev, "rumble queue is full"); /* overwrite the prior value at the end of the circular buf */ next_rq_head = ctlr->rumble_queue_head; } ctlr->rumble_queue_head = next_rq_head; memcpy(ctlr->rumble_data[ctlr->rumble_queue_head], data, JC_RUMBLE_DATA_SIZE); Loading Loading @@ -2128,7 +2205,7 @@ static int nintendo_hid_probe(struct hid_device *hdev, ctlr->hdev = hdev; ctlr->ctlr_state = JOYCON_CTLR_STATE_INIT; ctlr->rumble_queue_head = JC_RUMBLE_QUEUE_SIZE - 1; ctlr->rumble_queue_head = 0; ctlr->rumble_queue_tail = 0; hid_set_drvdata(hdev, ctlr); mutex_init(&ctlr->output_mutex); Loading