| From 3d575ab974a0d3f4af65f0e10a97d03c98c133d1 Mon Sep 17 00:00:00 2001 |
| From: Cameron Gutman <aicommander@gmail.com> |
| Date: Mon, 6 Feb 2017 13:56:10 -0800 |
| Subject: Input: xpad - fix stuck mode button on Xbox One S pad |
| |
| [ Upstream commit 57b8443d3e5bd046a519ff714ca31c64c7f04309 ] |
| |
| The Xbox One S requires an ack to its mode button report, otherwise it |
| continuously retransmits the report. This makes the mode button appear to |
| be stuck down after it is pressed for the first time. |
| |
| 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 | 33 +++++++++++++++++++++++++++++++++ |
| 1 file changed, 33 insertions(+) |
| |
| diff --git a/drivers/input/joystick/xpad.c b/drivers/input/joystick/xpad.c |
| index dd0503562b1c..14da79ead653 100644 |
| --- a/drivers/input/joystick/xpad.c |
| +++ b/drivers/input/joystick/xpad.c |
| @@ -391,6 +391,7 @@ struct usb_xpad { |
| |
| static int xpad_init_input(struct usb_xpad *xpad); |
| static void xpad_deinit_input(struct usb_xpad *xpad); |
| +static void xpadone_ack_mode_report(struct usb_xpad *xpad, u8 seq_num); |
| |
| /* |
| * xpad_process_packet |
| @@ -624,6 +625,14 @@ static void xpadone_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char |
| |
| /* the xbox button has its own special report */ |
| if (data[0] == 0X07) { |
| + /* |
| + * The Xbox One S controller requires these reports to be |
| + * acked otherwise it continues sending them forever and |
| + * won't report further mode button events. |
| + */ |
| + if (data[1] == 0x30) |
| + xpadone_ack_mode_report(xpad, data[2]); |
| + |
| input_report_key(dev, BTN_MODE, data[4] & 0x01); |
| input_sync(dev); |
| return; |
| @@ -956,6 +965,30 @@ static int xpad_start_xbox_one(struct usb_xpad *xpad) |
| return retval; |
| } |
| |
| +static void xpadone_ack_mode_report(struct usb_xpad *xpad, u8 seq_num) |
| +{ |
| + unsigned long flags; |
| + struct xpad_output_packet *packet = |
| + &xpad->out_packets[XPAD_OUT_CMD_IDX]; |
| + static const u8 mode_report_ack[] = { |
| + 0x01, 0x20, 0x00, 0x09, 0x00, 0x07, 0x20, 0x02, |
| + 0x00, 0x00, 0x00, 0x00, 0x00 |
| + }; |
| + |
| + spin_lock_irqsave(&xpad->odata_lock, flags); |
| + |
| + packet->len = sizeof(mode_report_ack); |
| + memcpy(packet->data, mode_report_ack, packet->len); |
| + packet->data[2] = seq_num; |
| + packet->pending = true; |
| + |
| + /* Reset the sequence so we send out the ack now */ |
| + xpad->last_out_packet = -1; |
| + xpad_try_sending_next_out_packet(xpad); |
| + |
| + spin_unlock_irqrestore(&xpad->odata_lock, flags); |
| +} |
| + |
| #ifdef CONFIG_JOYSTICK_XPAD_FF |
| static int xpad_play_effect(struct input_dev *dev, void *data, struct ff_effect *effect) |
| { |
| -- |
| 2.17.1 |
| |