| From 98331ce36922d3ce85d1979be531db0c6b7e578c Mon Sep 17 00:00:00 2001 |
| From: Cameron Gutman <aicommander@gmail.com> |
| Date: Wed, 27 Jul 2016 14:24:55 -0700 |
| Subject: Input: xpad - power off wireless 360 controllers on suspend |
| |
| [ Upstream commit f712a5a05228058f6b74635546549d4a46e117fc ] |
| |
| When the USB wireless adapter is suspended, the controllers |
| lose their connection. This causes them to start flashing |
| their LED rings and searching for the wireless adapter |
| again, wasting the controller's battery power. |
| |
| Instead, we will tell the controllers to power down when |
| we suspend. This mirrors the behavior of the controllers |
| when connected to the console itself and how the official |
| Xbox One wireless adapter behaves on Windows. |
| |
| Signed-off-by: Cameron Gutman <aicommander@gmail.com> |
| Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com> |
| Signed-off-by: Sasha Levin <sashal@kernel.org> |
| --- |
| drivers/input/joystick/xpad.c | 43 +++++++++++++++++++++++++++++++++++ |
| 1 file changed, 43 insertions(+) |
| |
| diff --git a/drivers/input/joystick/xpad.c b/drivers/input/joystick/xpad.c |
| index 82c98e5b23ab..f397a5b6910f 100644 |
| --- a/drivers/input/joystick/xpad.c |
| +++ b/drivers/input/joystick/xpad.c |
| @@ -115,6 +115,10 @@ static bool sticks_to_null; |
| module_param(sticks_to_null, bool, S_IRUGO); |
| MODULE_PARM_DESC(sticks_to_null, "Do not map sticks at all for unknown pads"); |
| |
| +static bool auto_poweroff = true; |
| +module_param(auto_poweroff, bool, S_IWUSR | S_IRUGO); |
| +MODULE_PARM_DESC(auto_poweroff, "Power off wireless controllers on suspend"); |
| + |
| static const struct xpad_device { |
| u16 idVendor; |
| u16 idProduct; |
| @@ -1250,6 +1254,36 @@ static void xpad_stop_input(struct usb_xpad *xpad) |
| usb_kill_urb(xpad->irq_in); |
| } |
| |
| +static void xpad360w_poweroff_controller(struct usb_xpad *xpad) |
| +{ |
| + unsigned long flags; |
| + struct xpad_output_packet *packet = |
| + &xpad->out_packets[XPAD_OUT_CMD_IDX]; |
| + |
| + spin_lock_irqsave(&xpad->odata_lock, flags); |
| + |
| + packet->data[0] = 0x00; |
| + packet->data[1] = 0x00; |
| + packet->data[2] = 0x08; |
| + packet->data[3] = 0xC0; |
| + packet->data[4] = 0x00; |
| + packet->data[5] = 0x00; |
| + packet->data[6] = 0x00; |
| + packet->data[7] = 0x00; |
| + packet->data[8] = 0x00; |
| + packet->data[9] = 0x00; |
| + packet->data[10] = 0x00; |
| + packet->data[11] = 0x00; |
| + packet->len = 12; |
| + packet->pending = true; |
| + |
| + /* Reset the sequence so we send out poweroff now */ |
| + xpad->last_out_packet = -1; |
| + xpad_try_sending_next_out_packet(xpad); |
| + |
| + spin_unlock_irqrestore(&xpad->odata_lock, flags); |
| +} |
| + |
| static int xpad360w_start_input(struct usb_xpad *xpad) |
| { |
| int error; |
| @@ -1598,6 +1632,15 @@ static int xpad_suspend(struct usb_interface *intf, pm_message_t message) |
| * or goes away. |
| */ |
| xpad360w_stop_input(xpad); |
| + |
| + /* |
| + * The wireless adapter is going off now, so the |
| + * gamepads are going to become disconnected. |
| + * Unless explicitly disabled, power them down |
| + * so they don't just sit there flashing. |
| + */ |
| + if (auto_poweroff && xpad->pad_present) |
| + xpad360w_poweroff_controller(xpad); |
| } else { |
| mutex_lock(&input->mutex); |
| if (input->users) |
| -- |
| 2.17.1 |
| |