Merge branch 'for-6.4/nintendo' into for-linus
- drastically reducing Bluetooth disconnects on hid-nintendo driven devices (Daniel J. Ogorchock) - proper rumble queue overrun handling (Daniel J. Ogorchock)
This commit is contained in:
commit
67471b8998
@ -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;
|
||||
@ -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;
|
||||
|
||||
while (delta_ms < max_subcmd_rate_ms &&
|
||||
ctlr->ctlr_state == JOYCON_CTLR_STATE_READ) {
|
||||
if (unlikely(ctlr->ctlr_state != JOYCON_CTLR_STATE_READ))
|
||||
return;
|
||||
|
||||
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,
|
||||
@ -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 &&
|
||||
@ -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
|
||||
@ -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;
|
||||
@ -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);
|
||||
|
||||
@ -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…
Reference in New Issue
Block a user