diff mbox

[2/2] hid: sony: Save and restore controller state on suspend and resume

Message ID 1446909130-9168-3-git-send-email-frank.praznik@gmail.com (mailing list archive)
State New, archived
Delegated to: Jiri Kosina
Headers show

Commit Message

Frank Praznik Nov. 7, 2015, 3:12 p.m. UTC
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 remain off on resume).  This implements the suspend and
resume callbacks which saves and clears the state of the LEDs on suspend
and restores it on resume.  Force-feedback is stopped on suspend but
automatically restored on resume until a new event is received to avoid
potentially damaging hardware.

Signed-off-by: Frank Praznik <frank.praznik@gmail.com>
---
 drivers/hid/hid-sony.c | 51 +++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 50 insertions(+), 1 deletion(-)

Comments

Antonio Ospite Nov. 9, 2015, 2:03 p.m. UTC | #1
On Sat,  7 Nov 2015 10:12:10 -0500
Frank Praznik <frank.praznik@gmail.com> wrote:

> 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 remain off on resume).  This implements the suspend and
> resume callbacks which saves and clears the state of the LEDs on suspend
> and restores it on resume.  Force-feedback is stopped on suspend but
> automatically restored on resume until a new event is received to avoid
> potentially damaging hardware.
> 
> Signed-off-by: Frank Praznik <frank.praznik@gmail.com>

Acked-by: Antonio Ospite <ao2@ao2.it>

> ---
>  drivers/hid/hid-sony.c | 51 +++++++++++++++++++++++++++++++++++++++++++++++++-
>  1 file changed, 50 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/hid/hid-sony.c b/drivers/hid/hid-sony.c
> index b84b2ce..4eff8f7 100644
> --- a/drivers/hid/hid-sony.c
> +++ b/drivers/hid/hid-sony.c
> @@ -1044,6 +1044,7 @@ struct sony_sc {
>  	__u8 battery_charging;
>  	__u8 battery_capacity;
>  	__u8 led_state[MAX_LEDS];
> +	__u8 resume_led_state[MAX_LEDS];
>  	__u8 led_delay_on[MAX_LEDS];
>  	__u8 led_delay_off[MAX_LEDS];
>  	__u8 led_count;
> @@ -2427,6 +2428,48 @@ static void sony_remove(struct hid_device *hdev)
>  	hid_hw_stop(hdev);
>  }
>  
> +#ifdef CONFIG_PM
> +
> +static int sony_suspend(struct hid_device *hdev, pm_message_t message)
> +{
> +	/*
> +	 * On suspend save the current LED state,
> +	 * stop running force-feedback and blank the LEDS.
> +         */
> +	if (SONY_LED_SUPPORT || SONY_FF_SUPPORT) {
> +		struct sony_sc *sc = hid_get_drvdata(hdev);
> +
> +#ifdef CONFIG_SONY_FF
> +		sc->left = sc->right = 0;
> +#endif
> +
> +		memcpy(sc->resume_led_state, sc->led_state,
> +			sizeof(sc->resume_led_state));
> +		memset(sc->led_state, 0, sizeof(sc->led_state));
> +
> +		sony_send_output_report(sc);
> +	}
> +
> +	return 0;
> +}
> +
> +static int sony_resume(struct hid_device *hdev)
> +{
> +	/* Restore the state of controller LEDs on resume */
> +	if (SONY_LED_SUPPORT) {
> +		struct sony_sc *sc = hid_get_drvdata(hdev);
> +
> +		memcpy(sc->led_state, sc->resume_led_state,
> +			sizeof(sc->led_state));
> +
> +		sony_set_leds(sc);
> +	}
> +
> +	return 0;
> +}
> +
> +#endif
> +
>  static const struct hid_device_id sony_devices[] = {
>  	{ HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER),
>  		.driver_data = SIXAXIS_CONTROLLER_USB },
> @@ -2476,7 +2519,13 @@ static struct hid_driver sony_driver = {
>  	.probe            = sony_probe,
>  	.remove           = sony_remove,
>  	.report_fixup     = sony_report_fixup,
> -	.raw_event        = sony_raw_event
> +	.raw_event        = sony_raw_event,
> +
> +#ifdef CONFIG_PM
> +	.suspend          = sony_suspend,
> +	.resume	          = sony_resume,
> +	.reset_resume     = sony_resume,
> +#endif
>  };
>  
>  static int __init sony_init(void)
> -- 
> 2.4.3
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-input" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/drivers/hid/hid-sony.c b/drivers/hid/hid-sony.c
index b84b2ce..4eff8f7 100644
--- a/drivers/hid/hid-sony.c
+++ b/drivers/hid/hid-sony.c
@@ -1044,6 +1044,7 @@  struct sony_sc {
 	__u8 battery_charging;
 	__u8 battery_capacity;
 	__u8 led_state[MAX_LEDS];
+	__u8 resume_led_state[MAX_LEDS];
 	__u8 led_delay_on[MAX_LEDS];
 	__u8 led_delay_off[MAX_LEDS];
 	__u8 led_count;
@@ -2427,6 +2428,48 @@  static void sony_remove(struct hid_device *hdev)
 	hid_hw_stop(hdev);
 }
 
+#ifdef CONFIG_PM
+
+static int sony_suspend(struct hid_device *hdev, pm_message_t message)
+{
+	/*
+	 * On suspend save the current LED state,
+	 * stop running force-feedback and blank the LEDS.
+         */
+	if (SONY_LED_SUPPORT || SONY_FF_SUPPORT) {
+		struct sony_sc *sc = hid_get_drvdata(hdev);
+
+#ifdef CONFIG_SONY_FF
+		sc->left = sc->right = 0;
+#endif
+
+		memcpy(sc->resume_led_state, sc->led_state,
+			sizeof(sc->resume_led_state));
+		memset(sc->led_state, 0, sizeof(sc->led_state));
+
+		sony_send_output_report(sc);
+	}
+
+	return 0;
+}
+
+static int sony_resume(struct hid_device *hdev)
+{
+	/* Restore the state of controller LEDs on resume */
+	if (SONY_LED_SUPPORT) {
+		struct sony_sc *sc = hid_get_drvdata(hdev);
+
+		memcpy(sc->led_state, sc->resume_led_state,
+			sizeof(sc->led_state));
+
+		sony_set_leds(sc);
+	}
+
+	return 0;
+}
+
+#endif
+
 static const struct hid_device_id sony_devices[] = {
 	{ HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER),
 		.driver_data = SIXAXIS_CONTROLLER_USB },
@@ -2476,7 +2519,13 @@  static struct hid_driver sony_driver = {
 	.probe            = sony_probe,
 	.remove           = sony_remove,
 	.report_fixup     = sony_report_fixup,
-	.raw_event        = sony_raw_event
+	.raw_event        = sony_raw_event,
+
+#ifdef CONFIG_PM
+	.suspend          = sony_suspend,
+	.resume	          = sony_resume,
+	.reset_resume     = sony_resume,
+#endif
 };
 
 static int __init sony_init(void)