Skip to content

Commit 95ea4d9

Browse files
SuperSamusJiri Kosina
authored andcommitted
HID: nintendo: reinitialize USB Pro Controller after resuming from suspend
When suspending the computer, a Switch Pro Controller connected via USB will lose its internal status. However, because the USB connection was technically never lost, when resuming the computer, the driver will attempt to communicate with the controller as if nothing happened (and fail). Because of this, the user was forced to manually disconnect the controller (or to press the sync button on the controller to power it off), so that it can be re-initialized. With this patch, the controller will be automatically re-initialized after resuming from suspend. Closes: https://bugzilla.kernel.org/show_bug.cgi?id=216233 Signed-off-by: Martino Fontana <[email protected]> Reviewed-by: Daniel J. Ogorchock <[email protected]> Signed-off-by: Jiri Kosina <[email protected]>
1 parent aa80f39 commit 95ea4d9

File tree

1 file changed

+103
-72
lines changed

1 file changed

+103
-72
lines changed

drivers/hid/hid-nintendo.c

Lines changed: 103 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -2088,7 +2088,9 @@ static int joycon_read_info(struct joycon_ctlr *ctlr)
20882088
struct joycon_input_report *report;
20892089

20902090
req.subcmd_id = JC_SUBCMD_REQ_DEV_INFO;
2091+
mutex_lock(&ctlr->output_mutex);
20912092
ret = joycon_send_subcmd(ctlr, &req, 0, HZ);
2093+
mutex_unlock(&ctlr->output_mutex);
20922094
if (ret) {
20932095
hid_err(ctlr->hdev, "Failed to get joycon info; ret=%d\n", ret);
20942096
return ret;
@@ -2117,6 +2119,85 @@ static int joycon_read_info(struct joycon_ctlr *ctlr)
21172119
return 0;
21182120
}
21192121

2122+
static int joycon_init(struct hid_device *hdev)
2123+
{
2124+
struct joycon_ctlr *ctlr = hid_get_drvdata(hdev);
2125+
int ret = 0;
2126+
2127+
mutex_lock(&ctlr->output_mutex);
2128+
/* if handshake command fails, assume ble pro controller */
2129+
if ((jc_type_is_procon(ctlr) || jc_type_is_chrggrip(ctlr)) &&
2130+
!joycon_send_usb(ctlr, JC_USB_CMD_HANDSHAKE, HZ)) {
2131+
hid_dbg(hdev, "detected USB controller\n");
2132+
/* set baudrate for improved latency */
2133+
ret = joycon_send_usb(ctlr, JC_USB_CMD_BAUDRATE_3M, HZ);
2134+
if (ret) {
2135+
hid_err(hdev, "Failed to set baudrate; ret=%d\n", ret);
2136+
goto out_unlock;
2137+
}
2138+
/* handshake */
2139+
ret = joycon_send_usb(ctlr, JC_USB_CMD_HANDSHAKE, HZ);
2140+
if (ret) {
2141+
hid_err(hdev, "Failed handshake; ret=%d\n", ret);
2142+
goto out_unlock;
2143+
}
2144+
/*
2145+
* Set no timeout (to keep controller in USB mode).
2146+
* This doesn't send a response, so ignore the timeout.
2147+
*/
2148+
joycon_send_usb(ctlr, JC_USB_CMD_NO_TIMEOUT, HZ/10);
2149+
} else if (jc_type_is_chrggrip(ctlr)) {
2150+
hid_err(hdev, "Failed charging grip handshake\n");
2151+
ret = -ETIMEDOUT;
2152+
goto out_unlock;
2153+
}
2154+
2155+
/* get controller calibration data, and parse it */
2156+
ret = joycon_request_calibration(ctlr);
2157+
if (ret) {
2158+
/*
2159+
* We can function with default calibration, but it may be
2160+
* inaccurate. Provide a warning, and continue on.
2161+
*/
2162+
hid_warn(hdev, "Analog stick positions may be inaccurate\n");
2163+
}
2164+
2165+
/* get IMU calibration data, and parse it */
2166+
ret = joycon_request_imu_calibration(ctlr);
2167+
if (ret) {
2168+
/*
2169+
* We can function with default calibration, but it may be
2170+
* inaccurate. Provide a warning, and continue on.
2171+
*/
2172+
hid_warn(hdev, "Unable to read IMU calibration data\n");
2173+
}
2174+
2175+
/* Set the reporting mode to 0x30, which is the full report mode */
2176+
ret = joycon_set_report_mode(ctlr);
2177+
if (ret) {
2178+
hid_err(hdev, "Failed to set report mode; ret=%d\n", ret);
2179+
goto out_unlock;
2180+
}
2181+
2182+
/* Enable rumble */
2183+
ret = joycon_enable_rumble(ctlr);
2184+
if (ret) {
2185+
hid_err(hdev, "Failed to enable rumble; ret=%d\n", ret);
2186+
goto out_unlock;
2187+
}
2188+
2189+
/* Enable the IMU */
2190+
ret = joycon_enable_imu(ctlr);
2191+
if (ret) {
2192+
hid_err(hdev, "Failed to enable the IMU; ret=%d\n", ret);
2193+
goto out_unlock;
2194+
}
2195+
2196+
out_unlock:
2197+
mutex_unlock(&ctlr->output_mutex);
2198+
return ret;
2199+
}
2200+
21202201
/* Common handler for parsing inputs */
21212202
static int joycon_ctlr_read_handler(struct joycon_ctlr *ctlr, u8 *data,
21222203
int size)
@@ -2248,85 +2329,19 @@ static int nintendo_hid_probe(struct hid_device *hdev,
22482329

22492330
hid_device_io_start(hdev);
22502331

2251-
/* Initialize the controller */
2252-
mutex_lock(&ctlr->output_mutex);
2253-
/* if handshake command fails, assume ble pro controller */
2254-
if ((jc_type_is_procon(ctlr) || jc_type_is_chrggrip(ctlr)) &&
2255-
!joycon_send_usb(ctlr, JC_USB_CMD_HANDSHAKE, HZ)) {
2256-
hid_dbg(hdev, "detected USB controller\n");
2257-
/* set baudrate for improved latency */
2258-
ret = joycon_send_usb(ctlr, JC_USB_CMD_BAUDRATE_3M, HZ);
2259-
if (ret) {
2260-
hid_err(hdev, "Failed to set baudrate; ret=%d\n", ret);
2261-
goto err_mutex;
2262-
}
2263-
/* handshake */
2264-
ret = joycon_send_usb(ctlr, JC_USB_CMD_HANDSHAKE, HZ);
2265-
if (ret) {
2266-
hid_err(hdev, "Failed handshake; ret=%d\n", ret);
2267-
goto err_mutex;
2268-
}
2269-
/*
2270-
* Set no timeout (to keep controller in USB mode).
2271-
* This doesn't send a response, so ignore the timeout.
2272-
*/
2273-
joycon_send_usb(ctlr, JC_USB_CMD_NO_TIMEOUT, HZ/10);
2274-
} else if (jc_type_is_chrggrip(ctlr)) {
2275-
hid_err(hdev, "Failed charging grip handshake\n");
2276-
ret = -ETIMEDOUT;
2277-
goto err_mutex;
2278-
}
2279-
2280-
/* get controller calibration data, and parse it */
2281-
ret = joycon_request_calibration(ctlr);
2332+
ret = joycon_init(hdev);
22822333
if (ret) {
2283-
/*
2284-
* We can function with default calibration, but it may be
2285-
* inaccurate. Provide a warning, and continue on.
2286-
*/
2287-
hid_warn(hdev, "Analog stick positions may be inaccurate\n");
2288-
}
2289-
2290-
/* get IMU calibration data, and parse it */
2291-
ret = joycon_request_imu_calibration(ctlr);
2292-
if (ret) {
2293-
/*
2294-
* We can function with default calibration, but it may be
2295-
* inaccurate. Provide a warning, and continue on.
2296-
*/
2297-
hid_warn(hdev, "Unable to read IMU calibration data\n");
2298-
}
2299-
2300-
/* Set the reporting mode to 0x30, which is the full report mode */
2301-
ret = joycon_set_report_mode(ctlr);
2302-
if (ret) {
2303-
hid_err(hdev, "Failed to set report mode; ret=%d\n", ret);
2304-
goto err_mutex;
2305-
}
2306-
2307-
/* Enable rumble */
2308-
ret = joycon_enable_rumble(ctlr);
2309-
if (ret) {
2310-
hid_err(hdev, "Failed to enable rumble; ret=%d\n", ret);
2311-
goto err_mutex;
2312-
}
2313-
2314-
/* Enable the IMU */
2315-
ret = joycon_enable_imu(ctlr);
2316-
if (ret) {
2317-
hid_err(hdev, "Failed to enable the IMU; ret=%d\n", ret);
2318-
goto err_mutex;
2334+
hid_err(hdev, "Failed to initialize controller; ret=%d\n", ret);
2335+
goto err_close;
23192336
}
23202337

23212338
ret = joycon_read_info(ctlr);
23222339
if (ret) {
23232340
hid_err(hdev, "Failed to retrieve controller info; ret=%d\n",
23242341
ret);
2325-
goto err_mutex;
2342+
goto err_close;
23262343
}
23272344

2328-
mutex_unlock(&ctlr->output_mutex);
2329-
23302345
/* Initialize the leds */
23312346
ret = joycon_leds_create(ctlr);
23322347
if (ret) {
@@ -2352,8 +2367,6 @@ static int nintendo_hid_probe(struct hid_device *hdev,
23522367
hid_dbg(hdev, "probe - success\n");
23532368
return 0;
23542369

2355-
err_mutex:
2356-
mutex_unlock(&ctlr->output_mutex);
23572370
err_close:
23582371
hid_hw_close(hdev);
23592372
err_stop:
@@ -2383,6 +2396,20 @@ static void nintendo_hid_remove(struct hid_device *hdev)
23832396
hid_hw_stop(hdev);
23842397
}
23852398

2399+
#ifdef CONFIG_PM
2400+
2401+
static int nintendo_hid_resume(struct hid_device *hdev)
2402+
{
2403+
int ret = joycon_init(hdev);
2404+
2405+
if (ret)
2406+
hid_err(hdev, "Failed to restore controller after resume");
2407+
2408+
return ret;
2409+
}
2410+
2411+
#endif
2412+
23862413
static const struct hid_device_id nintendo_hid_devices[] = {
23872414
{ HID_USB_DEVICE(USB_VENDOR_ID_NINTENDO,
23882415
USB_DEVICE_ID_NINTENDO_PROCON) },
@@ -2404,6 +2431,10 @@ static struct hid_driver nintendo_hid_driver = {
24042431
.probe = nintendo_hid_probe,
24052432
.remove = nintendo_hid_remove,
24062433
.raw_event = nintendo_hid_event,
2434+
2435+
#ifdef CONFIG_PM
2436+
.resume = nintendo_hid_resume,
2437+
#endif
24072438
};
24082439
module_hid_driver(nintendo_hid_driver);
24092440

0 commit comments

Comments
 (0)