Skip to content

Commit decd946

Browse files
KontrabantJiri Kosina
authored andcommitted
HID: sony: Save and restore the controller state on suspend and resume
On hardware which provides standby power for charging devices the state of the LEDs and force-feedback on controllers can persist even when the system is in standby. Additionally, the state of the controllers on resume may be different from the state they were in at the time when they were suspended (ie. LEDs are cleared on resume). This implements the suspend and resume callbacks which saves and clears the state of the LEDs on suspend and restores them on resume. Force-feedback is stopped on suspend but not automatically restored on resume until a new event is received to avoid potentially damaging hardware. USB Sixaxis and navigation controllers must be reinitialized when the hardware is reset on resume or they won't send any input reports. Signed-off-by: Frank Praznik <[email protected]> Signed-off-by: Jiri Kosina <[email protected]>
1 parent d8aaccd commit decd946

File tree

1 file changed

+64
-1
lines changed

1 file changed

+64
-1
lines changed

drivers/hid/hid-sony.c

Lines changed: 64 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1045,6 +1045,7 @@ struct sony_sc {
10451045
__u8 battery_charging;
10461046
__u8 battery_capacity;
10471047
__u8 led_state[MAX_LEDS];
1048+
__u8 resume_led_state[MAX_LEDS];
10481049
__u8 led_delay_on[MAX_LEDS];
10491050
__u8 led_delay_off[MAX_LEDS];
10501051
__u8 led_count;
@@ -1912,6 +1913,12 @@ static void motion_send_output_report(struct sony_sc *sc)
19121913
hid_hw_output_report(hdev, (__u8 *)report, MOTION_REPORT_0x02_SIZE);
19131914
}
19141915

1916+
static inline void sony_send_output_report(struct sony_sc *sc)
1917+
{
1918+
if (sc->send_output_report)
1919+
sc->send_output_report(sc);
1920+
}
1921+
19151922
static void sony_state_worker(struct work_struct *work)
19161923
{
19171924
struct sony_sc *sc = container_of(work, struct sony_sc, state_worker);
@@ -2427,6 +2434,56 @@ static void sony_remove(struct hid_device *hdev)
24272434
hid_hw_stop(hdev);
24282435
}
24292436

2437+
#ifdef CONFIG_PM
2438+
2439+
static int sony_suspend(struct hid_device *hdev, pm_message_t message)
2440+
{
2441+
/*
2442+
* On suspend save the current LED state,
2443+
* stop running force-feedback and blank the LEDS.
2444+
*/
2445+
if (SONY_LED_SUPPORT || SONY_FF_SUPPORT) {
2446+
struct sony_sc *sc = hid_get_drvdata(hdev);
2447+
2448+
#ifdef CONFIG_SONY_FF
2449+
sc->left = sc->right = 0;
2450+
#endif
2451+
2452+
memcpy(sc->resume_led_state, sc->led_state,
2453+
sizeof(sc->resume_led_state));
2454+
memset(sc->led_state, 0, sizeof(sc->led_state));
2455+
2456+
sony_send_output_report(sc);
2457+
}
2458+
2459+
return 0;
2460+
}
2461+
2462+
static int sony_resume(struct hid_device *hdev)
2463+
{
2464+
/* Restore the state of controller LEDs on resume */
2465+
if (SONY_LED_SUPPORT) {
2466+
struct sony_sc *sc = hid_get_drvdata(hdev);
2467+
2468+
memcpy(sc->led_state, sc->resume_led_state,
2469+
sizeof(sc->led_state));
2470+
2471+
/*
2472+
* The Sixaxis and navigation controllers on USB need to be
2473+
* reinitialized on resume or they won't behave properly.
2474+
*/
2475+
if ((sc->quirks & SIXAXIS_CONTROLLER_USB) ||
2476+
(sc->quirks & NAVIGATION_CONTROLLER_USB))
2477+
sixaxis_set_operational_usb(sc->hdev);
2478+
2479+
sony_set_leds(sc);
2480+
}
2481+
2482+
return 0;
2483+
}
2484+
2485+
#endif
2486+
24302487
static const struct hid_device_id sony_devices[] = {
24312488
{ HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER),
24322489
.driver_data = SIXAXIS_CONTROLLER_USB },
@@ -2476,7 +2533,13 @@ static struct hid_driver sony_driver = {
24762533
.probe = sony_probe,
24772534
.remove = sony_remove,
24782535
.report_fixup = sony_report_fixup,
2479-
.raw_event = sony_raw_event
2536+
.raw_event = sony_raw_event,
2537+
2538+
#ifdef CONFIG_PM
2539+
.suspend = sony_suspend,
2540+
.resume = sony_resume,
2541+
.reset_resume = sony_resume,
2542+
#endif
24802543
};
24812544

24822545
static int __init sony_init(void)

0 commit comments

Comments
 (0)