Skip to content

Commit 4a03810

Browse files
DanielOgorchockJiri Kosina
authored andcommitted
HID: nintendo: avoid bluetooth suspend/resume stalls
Ensure we don't stall or panic the kernel when using bluetooth-connected controllers. This was reported as an issue on android devices using kernel 6.6 due to the resume hook which had been added for usb joycons. First, set a new state value to JOYCON_CTLR_STATE_SUSPENDED in a newly-added nintendo_hid_suspend. This makes sure we will not stall out the kernel waiting for input reports during led classdev suspend. The stalls could happen if connectivity is unreliable or lost to the controller prior to suspend. Second, since we lose connectivity during suspend, do not try joycon_init() for bluetooth controllers in the nintendo_hid_resume path. Tested via multiple suspend/resume flows when using the controller both in USB and bluetooth modes. Signed-off-by: Daniel J. Ogorchock <[email protected]> Reviewed-by: Silvan Jegen <[email protected]> Signed-off-by: Jiri Kosina <[email protected]>
1 parent 85a720f commit 4a03810

File tree

1 file changed

+36
-2
lines changed

1 file changed

+36
-2
lines changed

drivers/hid/hid-nintendo.c

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -308,6 +308,7 @@ enum joycon_ctlr_state {
308308
JOYCON_CTLR_STATE_INIT,
309309
JOYCON_CTLR_STATE_READ,
310310
JOYCON_CTLR_STATE_REMOVED,
311+
JOYCON_CTLR_STATE_SUSPENDED,
311312
};
312313

313314
/* Controller type received as part of device info */
@@ -2750,14 +2751,46 @@ static void nintendo_hid_remove(struct hid_device *hdev)
27502751

27512752
static int nintendo_hid_resume(struct hid_device *hdev)
27522753
{
2753-
int ret = joycon_init(hdev);
2754+
struct joycon_ctlr *ctlr = hid_get_drvdata(hdev);
2755+
int ret;
2756+
2757+
hid_dbg(hdev, "resume\n");
2758+
if (!joycon_using_usb(ctlr)) {
2759+
hid_dbg(hdev, "no-op resume for bt ctlr\n");
2760+
ctlr->ctlr_state = JOYCON_CTLR_STATE_READ;
2761+
return 0;
2762+
}
27542763

2764+
ret = joycon_init(hdev);
27552765
if (ret)
2756-
hid_err(hdev, "Failed to restore controller after resume");
2766+
hid_err(hdev,
2767+
"Failed to restore controller after resume: %d\n",
2768+
ret);
2769+
else
2770+
ctlr->ctlr_state = JOYCON_CTLR_STATE_READ;
27572771

27582772
return ret;
27592773
}
27602774

2775+
static int nintendo_hid_suspend(struct hid_device *hdev, pm_message_t message)
2776+
{
2777+
struct joycon_ctlr *ctlr = hid_get_drvdata(hdev);
2778+
2779+
hid_dbg(hdev, "suspend: %d\n", message.event);
2780+
/*
2781+
* Avoid any blocking loops in suspend/resume transitions.
2782+
*
2783+
* joycon_enforce_subcmd_rate() can result in repeated retries if for
2784+
* whatever reason the controller stops providing input reports.
2785+
*
2786+
* This has been observed with bluetooth controllers which lose
2787+
* connectivity prior to suspend (but not long enough to result in
2788+
* complete disconnection).
2789+
*/
2790+
ctlr->ctlr_state = JOYCON_CTLR_STATE_SUSPENDED;
2791+
return 0;
2792+
}
2793+
27612794
#endif
27622795

27632796
static const struct hid_device_id nintendo_hid_devices[] = {
@@ -2796,6 +2829,7 @@ static struct hid_driver nintendo_hid_driver = {
27962829

27972830
#ifdef CONFIG_PM
27982831
.resume = nintendo_hid_resume,
2832+
.suspend = nintendo_hid_suspend,
27992833
#endif
28002834
};
28012835
static int __init nintendo_init(void)

0 commit comments

Comments
 (0)