Commit 479da173 authored by Daniel J. Ogorchock's avatar Daniel J. Ogorchock Committed by Jiri Kosina

HID: nintendo: send subcommands after receiving input report

Waiting to send subcommands until right after receiving an input report
drastically improves subcommand reliability. If the driver has finished
initial controller configuration, it now waits until receiving an input
report for all subcommands.
Signed-off-by: default avatarDaniel J. Ogorchock <djogorchock@gmail.com>
Signed-off-by: default avatarJiri Kosina <jkosina@suse.cz>
parent 6b5dca2d
......@@ -335,6 +335,7 @@ struct joycon_ctlr {
bool received_resp;
u8 usb_ack_match;
u8 subcmd_ack_match;
bool received_input_report;
/* factory calibration data */
struct joycon_stick_cal left_stick_cal_x;
......@@ -388,6 +389,26 @@ 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");
}
ret = __joycon_hid_send(ctlr->hdev, data, len);
if (ret < 0) {
memset(ctlr->input_buf, 0, JC_MAX_RESP_SIZE);
......@@ -760,6 +781,18 @@ static void joycon_parse_report(struct joycon_ctlr *ctlr,
}
input_sync(dev);
/*
* Immediately after receiving a report is the most reliable time to
* send a subcommand to the controller. Wake any subcommand senders
* waiting for a report.
*/
if (unlikely(mutex_is_locked(&ctlr->output_mutex))) {
spin_lock_irqsave(&ctlr->lock, flags);
ctlr->received_input_report = true;
spin_unlock_irqrestore(&ctlr->lock, flags);
wake_up(&ctlr->wait);
}
}
static void joycon_rumble_worker(struct work_struct *work)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment