summaryrefslogtreecommitdiff
path: root/drivers/hid
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/hid')
-rw-r--r--drivers/hid/hid-nintendo.c33
1 files changed, 33 insertions, 0 deletions
diff --git a/drivers/hid/hid-nintendo.c b/drivers/hid/hid-nintendo.c
index a95943c2fc6c..a000a287206e 100644
--- a/drivers/hid/hid-nintendo.c
+++ b/drivers/hid/hid-nintendo.c
@@ -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)