diff options
Diffstat (limited to 'drivers/input/joystick/xpad.c')
-rw-r--r-- | drivers/input/joystick/xpad.c | 455 |
1 files changed, 342 insertions, 113 deletions
diff --git a/drivers/input/joystick/xpad.c b/drivers/input/joystick/xpad.c index 18190b529bca..2959d80f7fdb 100644 --- a/drivers/input/joystick/xpad.c +++ b/drivers/input/joystick/xpad.c @@ -61,6 +61,7 @@ * Later changes can be tracked in SCM. */ +#include <linux/bits.h> #include <linux/kernel.h> #include <linux/input.h> #include <linux/rcupdate.h> @@ -80,6 +81,9 @@ #define MAP_TRIGGERS_TO_BUTTONS (1 << 1) #define MAP_STICKS_TO_NULL (1 << 2) #define MAP_SELECT_BUTTON (1 << 3) +#define MAP_PADDLES (1 << 4) +#define MAP_PROFILE_BUTTON (1 << 5) + #define DANCEPAD_MAP_CONFIG (MAP_DPAD_TO_BUTTONS | \ MAP_TRIGGERS_TO_BUTTONS | MAP_STICKS_TO_NULL) @@ -89,6 +93,17 @@ #define XTYPE_XBOXONE 3 #define XTYPE_UNKNOWN 4 +/* Send power-off packet to xpad360w after holding the mode button for this many + * seconds + */ +#define XPAD360W_POWEROFF_TIMEOUT 5 + +#define PKT_XB 0 +#define PKT_XBE1 1 +#define PKT_XBE2_FW_OLD 2 +#define PKT_XBE2_FW_5_EARLY 3 +#define PKT_XBE2_FW_5_11 4 + static bool dpad_to_buttons; module_param(dpad_to_buttons, bool, S_IRUGO); MODULE_PARM_DESC(dpad_to_buttons, "Map D-PAD to buttons rather than axes for unknown pads"); @@ -111,8 +126,11 @@ static const struct xpad_device { char *name; u8 mapping; u8 xtype; + u8 packet_type; } xpad_device[] = { { 0x0079, 0x18d4, "GPD Win 2 X-Box Controller", 0, XTYPE_XBOX360 }, + { 0x03eb, 0xff01, "Wooting One (Legacy)", 0, XTYPE_XBOX360 }, + { 0x03eb, 0xff02, "Wooting Two (Legacy)", 0, XTYPE_XBOX360 }, { 0x044f, 0x0f00, "Thrustmaster Wheel", 0, XTYPE_XBOX }, { 0x044f, 0x0f03, "Thrustmaster Wheel", 0, XTYPE_XBOX }, { 0x044f, 0x0f07, "Thrustmaster, Inc. Controller", 0, XTYPE_XBOX }, @@ -128,9 +146,11 @@ static const struct xpad_device { { 0x045e, 0x0291, "Xbox 360 Wireless Receiver (XBOX)", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360W }, { 0x045e, 0x02d1, "Microsoft X-Box One pad", 0, XTYPE_XBOXONE }, { 0x045e, 0x02dd, "Microsoft X-Box One pad (Firmware 2015)", 0, XTYPE_XBOXONE }, - { 0x045e, 0x02e3, "Microsoft X-Box One Elite pad", 0, XTYPE_XBOXONE }, + { 0x045e, 0x02e3, "Microsoft X-Box One Elite pad", MAP_PADDLES, XTYPE_XBOXONE }, + { 0x045e, 0x0b00, "Microsoft X-Box One Elite 2 pad", MAP_PADDLES, XTYPE_XBOXONE }, { 0x045e, 0x02ea, "Microsoft X-Box One S pad", 0, XTYPE_XBOXONE }, { 0x045e, 0x0719, "Xbox 360 Wireless Receiver", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360W }, + { 0x045e, 0x0b0a, "Microsoft X-Box Adaptive Controller", MAP_PROFILE_BUTTON, XTYPE_XBOXONE }, { 0x045e, 0x0b12, "Microsoft Xbox Series S|X Controller", MAP_SELECT_BUTTON, XTYPE_XBOXONE }, { 0x046d, 0xc21d, "Logitech Gamepad F310", 0, XTYPE_XBOX360 }, { 0x046d, 0xc21e, "Logitech Gamepad F510", 0, XTYPE_XBOX360 }, @@ -244,6 +264,7 @@ static const struct xpad_device { { 0x0f0d, 0x0063, "Hori Real Arcade Pro Hayabusa (USA) Xbox One", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOXONE }, { 0x0f0d, 0x0067, "HORIPAD ONE", 0, XTYPE_XBOXONE }, { 0x0f0d, 0x0078, "Hori Real Arcade Pro V Kai Xbox One", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOXONE }, + { 0x0f0d, 0x00c5, "Hori Fighting Commander ONE", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOXONE }, { 0x0f30, 0x010b, "Philips Recoil", 0, XTYPE_XBOX }, { 0x0f30, 0x0202, "Joytech Advanced Controller", 0, XTYPE_XBOX }, { 0x0f30, 0x8888, "BigBen XBMiniPad Controller", 0, XTYPE_XBOX }, @@ -260,6 +281,7 @@ static const struct xpad_device { { 0x1430, 0x8888, "TX6500+ Dance Pad (first generation)", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX }, { 0x1430, 0xf801, "RedOctane Controller", 0, XTYPE_XBOX360 }, { 0x146b, 0x0601, "BigBen Interactive XBOX 360 Controller", 0, XTYPE_XBOX360 }, + { 0x146b, 0x0604, "Bigben Interactive DAIJA Arcade Stick", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 }, { 0x1532, 0x0037, "Razer Sabertooth", 0, XTYPE_XBOX360 }, { 0x1532, 0x0a00, "Razer Atrox Arcade Stick", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOXONE }, { 0x1532, 0x0a03, "Razer Wildcat", 0, XTYPE_XBOXONE }, @@ -325,6 +347,7 @@ static const struct xpad_device { { 0x24c6, 0x5502, "Hori Fighting Stick VX Alt", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 }, { 0x24c6, 0x5503, "Hori Fighting Edge", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 }, { 0x24c6, 0x5506, "Hori SOULCALIBUR V Stick", 0, XTYPE_XBOX360 }, + { 0x24c6, 0x5510, "Hori Fighting Commander ONE (Xbox 360/PC Mode)", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 }, { 0x24c6, 0x550d, "Hori GEM Xbox controller", 0, XTYPE_XBOX360 }, { 0x24c6, 0x550e, "Hori Real Arcade Pro V Kai 360", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 }, { 0x24c6, 0x551a, "PowerA FUSION Pro Controller", 0, XTYPE_XBOXONE }, @@ -334,6 +357,14 @@ static const struct xpad_device { { 0x24c6, 0x5b03, "Thrustmaster Ferrari 458 Racing Wheel", 0, XTYPE_XBOX360 }, { 0x24c6, 0x5d04, "Razer Sabertooth", 0, XTYPE_XBOX360 }, { 0x24c6, 0xfafe, "Rock Candy Gamepad for Xbox 360", 0, XTYPE_XBOX360 }, + { 0x2563, 0x058d, "OneXPlayer Gamepad", 0, XTYPE_XBOX360 }, + { 0x2dc8, 0x2000, "8BitDo Pro 2 Wired Controller fox Xbox", 0, XTYPE_XBOXONE }, + { 0x31e3, 0x1100, "Wooting One", 0, XTYPE_XBOX360 }, + { 0x31e3, 0x1200, "Wooting Two", 0, XTYPE_XBOX360 }, + { 0x31e3, 0x1210, "Wooting Lekker", 0, XTYPE_XBOX360 }, + { 0x31e3, 0x1220, "Wooting Two HE", 0, XTYPE_XBOX360 }, + { 0x31e3, 0x1300, "Wooting 60HE (AVR)", 0, XTYPE_XBOX360 }, + { 0x31e3, 0x1310, "Wooting 60HE (ARM)", 0, XTYPE_XBOX360 }, { 0x3285, 0x0607, "Nacon GC-100", 0, XTYPE_XBOX360 }, { 0x3767, 0x0101, "Fanatec Speedster 3 Forceshock Wheel", 0, XTYPE_XBOX }, { 0xffff, 0xffff, "Chinese-made Xbox Controller", 0, XTYPE_XBOX }, @@ -390,6 +421,13 @@ static const signed short xpad_abs_triggers[] = { -1 }; +/* used when the controller has extra paddle buttons */ +static const signed short xpad_btn_paddles[] = { + BTN_TRIGGER_HAPPY5, BTN_TRIGGER_HAPPY6, /* paddle upper right, lower right */ + BTN_TRIGGER_HAPPY7, BTN_TRIGGER_HAPPY8, /* paddle upper left, lower left */ + -1 /* terminating entry */ +}; + /* * Xbox 360 has a vendor-specific class, so we cannot match it with only * USB_INTERFACE_INFO (also specifically refused by USB subsystem), so we @@ -419,6 +457,7 @@ static const signed short xpad_abs_triggers[] = { static const struct usb_device_id xpad_table[] = { { USB_INTERFACE_INFO('X', 'B', 0) }, /* X-Box USB-IF not approved class */ XPAD_XBOX360_VENDOR(0x0079), /* GPD Win 2 Controller */ + XPAD_XBOX360_VENDOR(0x03eb), /* Wooting Keyboards (Legacy) */ XPAD_XBOX360_VENDOR(0x044f), /* Thrustmaster X-Box 360 controllers */ XPAD_XBOX360_VENDOR(0x045e), /* Microsoft X-Box 360 controllers */ XPAD_XBOXONE_VENDOR(0x045e), /* Microsoft X-Box One controllers */ @@ -429,6 +468,7 @@ static const struct usb_device_id xpad_table[] = { { USB_DEVICE(0x0738, 0x4540) }, /* Mad Catz Beat Pad */ XPAD_XBOXONE_VENDOR(0x0738), /* Mad Catz FightStick TE 2 */ XPAD_XBOX360_VENDOR(0x07ff), /* Mad Catz GamePad */ + XPAD_XBOX360_VENDOR(0x0c12), /* Zeroplus X-Box 360 controllers */ XPAD_XBOX360_VENDOR(0x0e6f), /* 0x0e6f X-Box 360 controllers */ XPAD_XBOXONE_VENDOR(0x0e6f), /* 0x0e6f X-Box One controllers */ XPAD_XBOX360_VENDOR(0x0f0d), /* Hori Controllers */ @@ -450,8 +490,12 @@ static const struct usb_device_id xpad_table[] = { XPAD_XBOXONE_VENDOR(0x20d6), /* PowerA Controllers */ XPAD_XBOX360_VENDOR(0x24c6), /* PowerA Controllers */ XPAD_XBOXONE_VENDOR(0x24c6), /* PowerA Controllers */ + XPAD_XBOX360_VENDOR(0x2563), /* OneXPlayer Gamepad */ + XPAD_XBOX360_VENDOR(0x260d), /* Dareu H101 */ + XPAD_XBOXONE_VENDOR(0x2dc8), /* 8BitDo Pro 2 Wired Controller for Xbox */ XPAD_XBOXONE_VENDOR(0x2e24), /* Hyperkin Duke X-Box One pad */ XPAD_XBOX360_VENDOR(0x2f24), /* GameSir Controllers */ + XPAD_XBOX360_VENDOR(0x31e3), /* Wooting Keyboards */ XPAD_XBOX360_VENDOR(0x3285), /* Nacon GC-100 */ { } }; @@ -473,13 +517,52 @@ struct xboxone_init_packet { .len = ARRAY_SIZE(_data), \ } +/* + * starting with xbox one, the game input protocol is used + * magic numbers are taken from + * - https://github.com/xpadneo/gip-dissector/blob/main/src/gip-dissector.lua + * - https://github.com/medusalix/xone/blob/master/bus/protocol.c + */ +#define GIP_CMD_ACK 0x01 +#define GIP_CMD_IDENTIFY 0x04 +#define GIP_CMD_POWER 0x05 +#define GIP_CMD_AUTHENTICATE 0x06 +#define GIP_CMD_VIRTUAL_KEY 0x07 +#define GIP_CMD_RUMBLE 0x09 +#define GIP_CMD_LED 0x0a +#define GIP_CMD_FIRMWARE 0x0c +#define GIP_CMD_INPUT 0x20 + +#define GIP_SEQ0 0x00 + +#define GIP_OPT_ACK 0x10 +#define GIP_OPT_INTERNAL 0x20 + +/* + * length of the command payload encoded with + * https://en.wikipedia.org/wiki/LEB128 + * which is a no-op for N < 128 + */ +#define GIP_PL_LEN(N) (N) + +/* + * payload specific defines + */ +#define GIP_PWR_ON 0x00 +#define GIP_LED_ON 0x01 + +#define GIP_MOTOR_R BIT(0) +#define GIP_MOTOR_L BIT(1) +#define GIP_MOTOR_RT BIT(2) +#define GIP_MOTOR_LT BIT(3) +#define GIP_MOTOR_ALL (GIP_MOTOR_R | GIP_MOTOR_L | GIP_MOTOR_RT | GIP_MOTOR_LT) /* * This packet is required for all Xbox One pads with 2015 * or later firmware installed (or present from the factory). */ -static const u8 xboxone_fw2015_init[] = { - 0x05, 0x20, 0x00, 0x01, 0x00 +static const u8 xboxone_power_on[] = { + GIP_CMD_POWER, GIP_OPT_INTERNAL, GIP_SEQ0, GIP_PL_LEN(1), GIP_PWR_ON }; /* @@ -489,7 +572,16 @@ static const u8 xboxone_fw2015_init[] = { * Bluetooth mode. */ static const u8 xboxone_s_init[] = { - 0x05, 0x20, 0x00, 0x0f, 0x06 + GIP_CMD_POWER, GIP_OPT_INTERNAL, GIP_SEQ0, 0x0f, 0x06 +}; + +/* + * This packet is required to get additional input data + * from Xbox One Elite Series 2 (0x045e:0x0b00) pads. + * We mostly do this right now to get paddle data + */ +static const u8 extra_input_packet_init[] = { + 0x4d, 0x10, 0x01, 0x02, 0x07, 0x00 }; /* @@ -497,9 +589,9 @@ static const u8 xboxone_s_init[] = { * (0x0e6f:0x0165) to finish initialization and for Hori pads * (0x0f0d:0x0067) to make the analog sticks work. */ -static const u8 xboxone_hori_init[] = { - 0x01, 0x20, 0x00, 0x09, 0x00, 0x04, 0x20, 0x3a, - 0x00, 0x00, 0x00, 0x80, 0x00 +static const u8 xboxone_hori_ack_id[] = { + GIP_CMD_ACK, GIP_OPT_INTERNAL, GIP_SEQ0, GIP_PL_LEN(9), + 0x00, GIP_CMD_IDENTIFY, GIP_OPT_INTERNAL, 0x3a, 0x00, 0x00, 0x00, 0x80, 0x00 }; /* @@ -507,8 +599,8 @@ static const u8 xboxone_hori_init[] = { * sending input reports. These pads include: (0x0e6f:0x02ab), * (0x0e6f:0x02a4), (0x0e6f:0x02a6). */ -static const u8 xboxone_pdp_init1[] = { - 0x0a, 0x20, 0x00, 0x03, 0x00, 0x01, 0x14 +static const u8 xboxone_pdp_led_on[] = { + GIP_CMD_LED, GIP_OPT_INTERNAL, GIP_SEQ0, GIP_PL_LEN(3), 0x00, GIP_LED_ON, 0x14 }; /* @@ -516,8 +608,8 @@ static const u8 xboxone_pdp_init1[] = { * sending input reports. These pads include: (0x0e6f:0x02ab), * (0x0e6f:0x02a4), (0x0e6f:0x02a6). */ -static const u8 xboxone_pdp_init2[] = { - 0x06, 0x20, 0x00, 0x02, 0x01, 0x00 +static const u8 xboxone_pdp_auth[] = { + GIP_CMD_AUTHENTICATE, GIP_OPT_INTERNAL, GIP_SEQ0, GIP_PL_LEN(2), 0x01, 0x00 }; /* @@ -525,8 +617,8 @@ static const u8 xboxone_pdp_init2[] = { * sending input reports. One of those pads is (0x24c6:0x543a). */ static const u8 xboxone_rumblebegin_init[] = { - 0x09, 0x00, 0x00, 0x09, 0x00, 0x0F, 0x00, 0x00, - 0x1D, 0x1D, 0xFF, 0x00, 0x00 + GIP_CMD_RUMBLE, 0x00, GIP_SEQ0, GIP_PL_LEN(9), + 0x00, GIP_MOTOR_ALL, 0x00, 0x00, 0x1D, 0x1D, 0xFF, 0x00, 0x00 }; /* @@ -536,8 +628,8 @@ static const u8 xboxone_rumblebegin_init[] = { * spin up to enough speed to actually vibrate the gamepad. */ static const u8 xboxone_rumbleend_init[] = { - 0x09, 0x00, 0x00, 0x09, 0x00, 0x0F, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00 + GIP_CMD_RUMBLE, 0x00, GIP_SEQ0, GIP_PL_LEN(9), + 0x00, GIP_MOTOR_ALL, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; /* @@ -547,13 +639,14 @@ static const u8 xboxone_rumbleend_init[] = { * packet is going to be sent. */ static const struct xboxone_init_packet xboxone_init_packets[] = { - XBOXONE_INIT_PKT(0x0e6f, 0x0165, xboxone_hori_init), - XBOXONE_INIT_PKT(0x0f0d, 0x0067, xboxone_hori_init), - XBOXONE_INIT_PKT(0x0000, 0x0000, xboxone_fw2015_init), + XBOXONE_INIT_PKT(0x0e6f, 0x0165, xboxone_hori_ack_id), + XBOXONE_INIT_PKT(0x0f0d, 0x0067, xboxone_hori_ack_id), + XBOXONE_INIT_PKT(0x0000, 0x0000, xboxone_power_on), XBOXONE_INIT_PKT(0x045e, 0x02ea, xboxone_s_init), XBOXONE_INIT_PKT(0x045e, 0x0b00, xboxone_s_init), - XBOXONE_INIT_PKT(0x0e6f, 0x0000, xboxone_pdp_init1), - XBOXONE_INIT_PKT(0x0e6f, 0x0000, xboxone_pdp_init2), + XBOXONE_INIT_PKT(0x045e, 0x0b00, extra_input_packet_init), + XBOXONE_INIT_PKT(0x0e6f, 0x0000, xboxone_pdp_led_on), + XBOXONE_INIT_PKT(0x0e6f, 0x0000, xboxone_pdp_auth), XBOXONE_INIT_PKT(0x24c6, 0x541a, xboxone_rumblebegin_init), XBOXONE_INIT_PKT(0x24c6, 0x542a, xboxone_rumblebegin_init), XBOXONE_INIT_PKT(0x24c6, 0x543a, xboxone_rumblebegin_init), @@ -608,14 +701,17 @@ struct usb_xpad { int mapping; /* map d-pad to buttons or to axes */ int xtype; /* type of xbox device */ + int packet_type; /* type of the extended packet */ int pad_nr; /* the order x360 pads were attached */ const char *name; /* name of the device */ struct work_struct work; /* init/remove device from callback */ + time64_t mode_btn_down_ts; }; 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); +static void xpad360w_poweroff_controller(struct usb_xpad *xpad); /* * xpad_process_packet @@ -656,10 +752,10 @@ static void xpad_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char *d /* digital pad */ if (xpad->mapping & MAP_DPAD_TO_BUTTONS) { /* dpad as buttons (left, right, up, down) */ - input_report_key(dev, BTN_TRIGGER_HAPPY1, data[2] & 0x04); - input_report_key(dev, BTN_TRIGGER_HAPPY2, data[2] & 0x08); - input_report_key(dev, BTN_TRIGGER_HAPPY3, data[2] & 0x01); - input_report_key(dev, BTN_TRIGGER_HAPPY4, data[2] & 0x02); + input_report_key(dev, BTN_TRIGGER_HAPPY1, data[2] & BIT(2)); + input_report_key(dev, BTN_TRIGGER_HAPPY2, data[2] & BIT(3)); + input_report_key(dev, BTN_TRIGGER_HAPPY3, data[2] & BIT(0)); + input_report_key(dev, BTN_TRIGGER_HAPPY4, data[2] & BIT(1)); } else { input_report_abs(dev, ABS_HAT0X, !!(data[2] & 0x08) - !!(data[2] & 0x04)); @@ -668,10 +764,10 @@ static void xpad_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char *d } /* start/back buttons and stick press left/right */ - input_report_key(dev, BTN_START, data[2] & 0x10); - input_report_key(dev, BTN_SELECT, data[2] & 0x20); - input_report_key(dev, BTN_THUMBL, data[2] & 0x40); - input_report_key(dev, BTN_THUMBR, data[2] & 0x80); + input_report_key(dev, BTN_START, data[2] & BIT(4)); + input_report_key(dev, BTN_SELECT, data[2] & BIT(5)); + input_report_key(dev, BTN_THUMBL, data[2] & BIT(6)); + input_report_key(dev, BTN_THUMBR, data[2] & BIT(7)); /* "analog" buttons A, B, X, Y */ input_report_key(dev, BTN_A, data[4]); @@ -683,6 +779,10 @@ static void xpad_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char *d input_report_key(dev, BTN_C, data[8]); input_report_key(dev, BTN_Z, data[9]); + /* Profile button has a value of 0-3, so it is reported as an axis */ + if (xpad->mapping & MAP_PROFILE_BUTTON) + input_report_abs(dev, ABS_PROFILE, data[34]); + input_sync(dev); } @@ -706,10 +806,10 @@ static void xpad360_process_packet(struct usb_xpad *xpad, struct input_dev *dev, /* digital pad */ if (xpad->mapping & MAP_DPAD_TO_BUTTONS) { /* dpad as buttons (left, right, up, down) */ - input_report_key(dev, BTN_TRIGGER_HAPPY1, data[2] & 0x04); - input_report_key(dev, BTN_TRIGGER_HAPPY2, data[2] & 0x08); - input_report_key(dev, BTN_TRIGGER_HAPPY3, data[2] & 0x01); - input_report_key(dev, BTN_TRIGGER_HAPPY4, data[2] & 0x02); + input_report_key(dev, BTN_TRIGGER_HAPPY1, data[2] & BIT(2)); + input_report_key(dev, BTN_TRIGGER_HAPPY2, data[2] & BIT(3)); + input_report_key(dev, BTN_TRIGGER_HAPPY3, data[2] & BIT(0)); + input_report_key(dev, BTN_TRIGGER_HAPPY4, data[2] & BIT(1)); } /* @@ -727,21 +827,21 @@ static void xpad360_process_packet(struct usb_xpad *xpad, struct input_dev *dev, } /* start/back buttons */ - input_report_key(dev, BTN_START, data[2] & 0x10); - input_report_key(dev, BTN_SELECT, data[2] & 0x20); + input_report_key(dev, BTN_START, data[2] & BIT(4)); + input_report_key(dev, BTN_SELECT, data[2] & BIT(5)); /* stick press left/right */ - input_report_key(dev, BTN_THUMBL, data[2] & 0x40); - input_report_key(dev, BTN_THUMBR, data[2] & 0x80); + input_report_key(dev, BTN_THUMBL, data[2] & BIT(6)); + input_report_key(dev, BTN_THUMBR, data[2] & BIT(7)); /* buttons A,B,X,Y,TL,TR and MODE */ - input_report_key(dev, BTN_A, data[3] & 0x10); - input_report_key(dev, BTN_B, data[3] & 0x20); - input_report_key(dev, BTN_X, data[3] & 0x40); - input_report_key(dev, BTN_Y, data[3] & 0x80); - input_report_key(dev, BTN_TL, data[3] & 0x01); - input_report_key(dev, BTN_TR, data[3] & 0x02); - input_report_key(dev, BTN_MODE, data[3] & 0x04); + input_report_key(dev, BTN_A, data[3] & BIT(4)); + input_report_key(dev, BTN_B, data[3] & BIT(5)); + input_report_key(dev, BTN_X, data[3] & BIT(6)); + input_report_key(dev, BTN_Y, data[3] & BIT(7)); + input_report_key(dev, BTN_TL, data[3] & BIT(0)); + input_report_key(dev, BTN_TR, data[3] & BIT(1)); + input_report_key(dev, BTN_MODE, data[3] & BIT(2)); if (!(xpad->mapping & MAP_STICKS_TO_NULL)) { /* left stick */ @@ -767,6 +867,23 @@ static void xpad360_process_packet(struct usb_xpad *xpad, struct input_dev *dev, } input_sync(dev); + + /* XBOX360W controllers can't be turned off without driver assistance */ + if (xpad->xtype == XTYPE_XBOX360W) { + if (xpad->mode_btn_down_ts > 0 && xpad->pad_present && + ((ktime_get_seconds() - xpad->mode_btn_down_ts) >= + XPAD360W_POWEROFF_TIMEOUT)) { + xpad360w_poweroff_controller(xpad); + xpad->mode_btn_down_ts = 0; + return; + } + + /* mode button down/up */ + if (data[3] & BIT(2)) + xpad->mode_btn_down_ts = ktime_get_seconds(); + else + xpad->mode_btn_down_ts = 0; + } } static void xpad_presence_work(struct work_struct *work) @@ -846,87 +963,154 @@ static void xpad360w_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned cha static void xpadone_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char *data) { struct input_dev *dev = xpad->dev; + bool do_sync = false; /* the xbox button has its own special report */ - if (data[0] == 0X07) { + if (data[0] == GIP_CMD_VIRTUAL_KEY) { /* * 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) + if (data[1] == (GIP_OPT_ACK | GIP_OPT_INTERNAL)) xpadone_ack_mode_report(xpad, data[2]); - input_report_key(dev, BTN_MODE, data[4] & 0x01); + input_report_key(dev, BTN_MODE, data[4] & GENMASK(1, 0)); input_sync(dev); - return; - } - /* check invalid packet */ - else if (data[0] != 0X20) - return; - /* menu/view buttons */ - input_report_key(dev, BTN_START, data[4] & 0x04); - input_report_key(dev, BTN_SELECT, data[4] & 0x08); - if (xpad->mapping & MAP_SELECT_BUTTON) - input_report_key(dev, KEY_RECORD, data[22] & 0x01); + do_sync = true; + } else if (data[0] == GIP_CMD_FIRMWARE) { + /* Some packet formats force us to use this separate to poll paddle inputs */ + if (xpad->packet_type == PKT_XBE2_FW_5_11) { + /* Mute paddles if controller is in a custom profile slot + * Checked by looking at the active profile slot to + * verify it's the default slot + */ + if (data[19] != 0) + data[18] = 0; - /* buttons A,B,X,Y */ - input_report_key(dev, BTN_A, data[4] & 0x10); - input_report_key(dev, BTN_B, data[4] & 0x20); - input_report_key(dev, BTN_X, data[4] & 0x40); - input_report_key(dev, BTN_Y, data[4] & 0x80); + /* Elite Series 2 split packet paddle bits */ + input_report_key(dev, BTN_TRIGGER_HAPPY5, data[18] & BIT(0)); + input_report_key(dev, BTN_TRIGGER_HAPPY6, data[18] & BIT(1)); + input_report_key(dev, BTN_TRIGGER_HAPPY7, data[18] & BIT(2)); + input_report_key(dev, BTN_TRIGGER_HAPPY8, data[18] & BIT(3)); - /* digital pad */ - if (xpad->mapping & MAP_DPAD_TO_BUTTONS) { - /* dpad as buttons (left, right, up, down) */ - input_report_key(dev, BTN_TRIGGER_HAPPY1, data[5] & 0x04); - input_report_key(dev, BTN_TRIGGER_HAPPY2, data[5] & 0x08); - input_report_key(dev, BTN_TRIGGER_HAPPY3, data[5] & 0x01); - input_report_key(dev, BTN_TRIGGER_HAPPY4, data[5] & 0x02); - } else { - input_report_abs(dev, ABS_HAT0X, - !!(data[5] & 0x08) - !!(data[5] & 0x04)); - input_report_abs(dev, ABS_HAT0Y, - !!(data[5] & 0x02) - !!(data[5] & 0x01)); - } - - /* TL/TR */ - input_report_key(dev, BTN_TL, data[5] & 0x10); - input_report_key(dev, BTN_TR, data[5] & 0x20); + do_sync = true; + } + } else if (data[0] == GIP_CMD_INPUT) { /* The main valid packet type for inputs */ + /* menu/view buttons */ + input_report_key(dev, BTN_START, data[4] & BIT(2)); + input_report_key(dev, BTN_SELECT, data[4] & BIT(3)); + if (xpad->mapping & MAP_SELECT_BUTTON) + input_report_key(dev, KEY_RECORD, data[22] & BIT(0)); + + /* buttons A,B,X,Y */ + input_report_key(dev, BTN_A, data[4] & BIT(4)); + input_report_key(dev, BTN_B, data[4] & BIT(5)); + input_report_key(dev, BTN_X, data[4] & BIT(6)); + input_report_key(dev, BTN_Y, data[4] & BIT(7)); + + /* digital pad */ + if (xpad->mapping & MAP_DPAD_TO_BUTTONS) { + /* dpad as buttons (left, right, up, down) */ + input_report_key(dev, BTN_TRIGGER_HAPPY1, data[5] & BIT(2)); + input_report_key(dev, BTN_TRIGGER_HAPPY2, data[5] & BIT(3)); + input_report_key(dev, BTN_TRIGGER_HAPPY3, data[5] & BIT(0)); + input_report_key(dev, BTN_TRIGGER_HAPPY4, data[5] & BIT(1)); + } else { + input_report_abs(dev, ABS_HAT0X, + !!(data[5] & 0x08) - !!(data[5] & 0x04)); + input_report_abs(dev, ABS_HAT0Y, + !!(data[5] & 0x02) - !!(data[5] & 0x01)); + } - /* stick press left/right */ - input_report_key(dev, BTN_THUMBL, data[5] & 0x40); - input_report_key(dev, BTN_THUMBR, data[5] & 0x80); + /* TL/TR */ + input_report_key(dev, BTN_TL, data[5] & BIT(4)); + input_report_key(dev, BTN_TR, data[5] & BIT(5)); + + /* stick press left/right */ + input_report_key(dev, BTN_THUMBL, data[5] & BIT(6)); + input_report_key(dev, BTN_THUMBR, data[5] & BIT(7)); + + if (!(xpad->mapping & MAP_STICKS_TO_NULL)) { + /* left stick */ + input_report_abs(dev, ABS_X, + (__s16) le16_to_cpup((__le16 *)(data + 10))); + input_report_abs(dev, ABS_Y, + ~(__s16) le16_to_cpup((__le16 *)(data + 12))); + + /* right stick */ + input_report_abs(dev, ABS_RX, + (__s16) le16_to_cpup((__le16 *)(data + 14))); + input_report_abs(dev, ABS_RY, + ~(__s16) le16_to_cpup((__le16 *)(data + 16))); + } - if (!(xpad->mapping & MAP_STICKS_TO_NULL)) { - /* left stick */ - input_report_abs(dev, ABS_X, - (__s16) le16_to_cpup((__le16 *)(data + 10))); - input_report_abs(dev, ABS_Y, - ~(__s16) le16_to_cpup((__le16 *)(data + 12))); + /* triggers left/right */ + if (xpad->mapping & MAP_TRIGGERS_TO_BUTTONS) { + input_report_key(dev, BTN_TL2, + (__u16) le16_to_cpup((__le16 *)(data + 6))); + input_report_key(dev, BTN_TR2, + (__u16) le16_to_cpup((__le16 *)(data + 8))); + } else { + input_report_abs(dev, ABS_Z, + (__u16) le16_to_cpup((__le16 *)(data + 6))); + input_report_abs(dev, ABS_RZ, + (__u16) le16_to_cpup((__le16 *)(data + 8))); + } - /* right stick */ - input_report_abs(dev, ABS_RX, - (__s16) le16_to_cpup((__le16 *)(data + 14))); - input_report_abs(dev, ABS_RY, - ~(__s16) le16_to_cpup((__le16 *)(data + 16))); - } + /* paddle handling */ + /* based on SDL's SDL_hidapi_xboxone.c */ + if (xpad->mapping & MAP_PADDLES) { + if (xpad->packet_type == PKT_XBE1) { + /* Mute paddles if controller has a custom mapping applied. + * Checked by comparing the current mapping + * config against the factory mapping config + */ + if (memcmp(&data[4], &data[18], 2) != 0) + data[32] = 0; + + /* OG Elite Series Controller paddle bits */ + input_report_key(dev, BTN_TRIGGER_HAPPY5, data[32] & BIT(1)); + input_report_key(dev, BTN_TRIGGER_HAPPY6, data[32] & BIT(3)); + input_report_key(dev, BTN_TRIGGER_HAPPY7, data[32] & BIT(0)); + input_report_key(dev, BTN_TRIGGER_HAPPY8, data[32] & BIT(2)); + } else if (xpad->packet_type == PKT_XBE2_FW_OLD) { + /* Mute paddles if controller has a custom mapping applied. + * Checked by comparing the current mapping + * config against the factory mapping config + */ + if (data[19] != 0) + data[18] = 0; + + /* Elite Series 2 4.x firmware paddle bits */ + input_report_key(dev, BTN_TRIGGER_HAPPY5, data[18] & BIT(0)); + input_report_key(dev, BTN_TRIGGER_HAPPY6, data[18] & BIT(1)); + input_report_key(dev, BTN_TRIGGER_HAPPY7, data[18] & BIT(2)); + input_report_key(dev, BTN_TRIGGER_HAPPY8, data[18] & BIT(3)); + } else if (xpad->packet_type == PKT_XBE2_FW_5_EARLY) { + /* Mute paddles if controller has a custom mapping applied. + * Checked by comparing the current mapping + * config against the factory mapping config + */ + if (data[23] != 0) + data[22] = 0; + + /* Elite Series 2 5.x firmware paddle bits + * (before the packet was split) + */ + input_report_key(dev, BTN_TRIGGER_HAPPY5, data[22] & BIT(0)); + input_report_key(dev, BTN_TRIGGER_HAPPY6, data[22] & BIT(1)); + input_report_key(dev, BTN_TRIGGER_HAPPY7, data[22] & BIT(2)); + input_report_key(dev, BTN_TRIGGER_HAPPY8, data[22] & BIT(3)); + } + } - /* triggers left/right */ - if (xpad->mapping & MAP_TRIGGERS_TO_BUTTONS) { - input_report_key(dev, BTN_TL2, - (__u16) le16_to_cpup((__le16 *)(data + 6))); - input_report_key(dev, BTN_TR2, - (__u16) le16_to_cpup((__le16 *)(data + 8))); - } else { - input_report_abs(dev, ABS_Z, - (__u16) le16_to_cpup((__le16 *)(data + 6))); - input_report_abs(dev, ABS_RZ, - (__u16) le16_to_cpup((__le16 *)(data + 8))); + do_sync = true; } - input_sync(dev); + if (do_sync) + input_sync(dev); } static void xpad_irq_in(struct urb *urb) @@ -1226,8 +1410,8 @@ static void xpadone_ack_mode_report(struct usb_xpad *xpad, u8 seq_num) 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 + GIP_CMD_ACK, GIP_OPT_INTERNAL, GIP_SEQ0, GIP_PL_LEN(9), + 0x00, GIP_CMD_VIRTUAL_KEY, GIP_OPT_INTERNAL, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00 }; spin_lock_irqsave(&xpad->odata_lock, flags); @@ -1305,14 +1489,14 @@ static int xpad_play_effect(struct input_dev *dev, void *data, struct ff_effect break; case XTYPE_XBOXONE: - packet->data[0] = 0x09; /* activate rumble */ + packet->data[0] = GIP_CMD_RUMBLE; /* activate rumble */ packet->data[1] = 0x00; packet->data[2] = xpad->odata_serial++; - packet->data[3] = 0x09; + packet->data[3] = GIP_PL_LEN(9); packet->data[4] = 0x00; - packet->data[5] = 0x0F; - packet->data[6] = 0x00; - packet->data[7] = 0x00; + packet->data[5] = GIP_MOTOR_ALL; + packet->data[6] = 0x00; /* left trigger */ + packet->data[7] = 0x00; /* right trigger */ packet->data[8] = strong / 512; /* left actuator */ packet->data[9] = weak / 512; /* right actuator */ packet->data[10] = 0xFF; /* on period */ @@ -1622,6 +1806,9 @@ static void xpad_set_up_abs(struct input_dev *input_dev, signed short abs) case ABS_HAT0Y: /* the d-pad (only if dpad is mapped to axes */ input_set_abs_params(input_dev, abs, -1, 1, 0, 0); break; + case ABS_PROFILE: /* 4 value profile button (such as on XAC) */ + input_set_abs_params(input_dev, abs, 0, 4, 0, 0); + break; default: input_set_abs_params(input_dev, abs, 0, 0, 0, 0); break; @@ -1693,6 +1880,12 @@ static int xpad_init_input(struct usb_xpad *xpad) xpad_btn_pad[i]); } + /* set up paddles if the controller has them */ + if (xpad->mapping & MAP_PADDLES) { + for (i = 0; xpad_btn_paddles[i] >= 0; i++) + input_set_capability(input_dev, EV_KEY, xpad_btn_paddles[i]); + } + /* * This should be a simple else block. However historically * xbox360w has mapped DPAD to buttons while xbox360 did not. This @@ -1714,6 +1907,10 @@ static int xpad_init_input(struct usb_xpad *xpad) xpad_set_up_abs(input_dev, xpad_abs_triggers[i]); } + /* setup profile button as an axis with 4 possible values */ + if (xpad->mapping & MAP_PROFILE_BUTTON) + xpad_set_up_abs(input_dev, ABS_PROFILE); + error = xpad_init_ff(xpad); if (error) goto err_free_input; @@ -1779,6 +1976,7 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id xpad->mapping = xpad_device[i].mapping; xpad->xtype = xpad_device[i].xtype; xpad->name = xpad_device[i].name; + xpad->packet_type = PKT_XB; INIT_WORK(&xpad->work, xpad_presence_work); if (xpad->xtype == XTYPE_UNKNOWN) { @@ -1844,6 +2042,38 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id usb_set_intfdata(intf, xpad); + /* Packet type detection */ + if (le16_to_cpu(udev->descriptor.idVendor) == 0x045e) { /* Microsoft controllers */ + if (le16_to_cpu(udev->descriptor.idProduct) == 0x02e3) { + /* The original elite controller always uses the oldest + * type of extended packet + */ + xpad->packet_type = PKT_XBE1; + } else if (le16_to_cpu(udev->descriptor.idProduct) == 0x0b00) { + /* The elite 2 controller has seen multiple packet + * revisions. These are tied to specific firmware + * versions + */ + if (le16_to_cpu(udev->descriptor.bcdDevice) < 0x0500) { + /* This is the format that the Elite 2 used + * prior to the BLE update + */ + xpad->packet_type = PKT_XBE2_FW_OLD; + } else if (le16_to_cpu(udev->descriptor.bcdDevice) < + 0x050b) { + /* This is the format that the Elite 2 used + * prior to the update that split the packet + */ + xpad->packet_type = PKT_XBE2_FW_5_EARLY; + } else { + /* The split packet format that was introduced + * in firmware v5.11 + */ + xpad->packet_type = PKT_XBE2_FW_5_11; + } + } + } + if (xpad->xtype == XTYPE_XBOX360W) { /* * Submit the int URB immediately rather than waiting for open @@ -1972,7 +2202,6 @@ static struct usb_driver xpad_driver = { .disconnect = xpad_disconnect, .suspend = xpad_suspend, .resume = xpad_resume, - .reset_resume = xpad_resume, .id_table = xpad_table, }; |