162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Xbox gamepad driver 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (c) 2002 Marko Friedemann <mfr@bmx-chemnitz.de> 662306a36Sopenharmony_ci * 2004 Oliver Schwartz <Oliver.Schwartz@gmx.de>, 762306a36Sopenharmony_ci * Steven Toth <steve@toth.demon.co.uk>, 862306a36Sopenharmony_ci * Franz Lehner <franz@caos.at>, 962306a36Sopenharmony_ci * Ivan Hawkes <blackhawk@ivanhawkes.com> 1062306a36Sopenharmony_ci * 2005 Dominic Cerquetti <binary1230@yahoo.com> 1162306a36Sopenharmony_ci * 2006 Adam Buchbinder <adam.buchbinder@gmail.com> 1262306a36Sopenharmony_ci * 2007 Jan Kratochvil <honza@jikos.cz> 1362306a36Sopenharmony_ci * 2010 Christoph Fritz <chf.fritz@googlemail.com> 1462306a36Sopenharmony_ci * 1562306a36Sopenharmony_ci * This driver is based on: 1662306a36Sopenharmony_ci * - information from http://euc.jp/periphs/xbox-controller.ja.html 1762306a36Sopenharmony_ci * - the iForce driver drivers/char/joystick/iforce.c 1862306a36Sopenharmony_ci * - the skeleton-driver drivers/usb/usb-skeleton.c 1962306a36Sopenharmony_ci * - Xbox 360 information http://www.free60.org/wiki/Gamepad 2062306a36Sopenharmony_ci * - Xbox One information https://github.com/quantus/xbox-one-controller-protocol 2162306a36Sopenharmony_ci * 2262306a36Sopenharmony_ci * Thanks to: 2362306a36Sopenharmony_ci * - ITO Takayuki for providing essential xpad information on his website 2462306a36Sopenharmony_ci * - Vojtech Pavlik - iforce driver / input subsystem 2562306a36Sopenharmony_ci * - Greg Kroah-Hartman - usb-skeleton driver 2662306a36Sopenharmony_ci * - Xbox Linux project - extra USB IDs 2762306a36Sopenharmony_ci * - Pekka Pöyry (quantus) - Xbox One controller reverse-engineering 2862306a36Sopenharmony_ci * 2962306a36Sopenharmony_ci * TODO: 3062306a36Sopenharmony_ci * - fine tune axes (especially trigger axes) 3162306a36Sopenharmony_ci * - fix "analog" buttons (reported as digital now) 3262306a36Sopenharmony_ci * - get rumble working 3362306a36Sopenharmony_ci * - need USB IDs for other dance pads 3462306a36Sopenharmony_ci * 3562306a36Sopenharmony_ci * History: 3662306a36Sopenharmony_ci * 3762306a36Sopenharmony_ci * 2002-06-27 - 0.0.1 : first version, just said "XBOX HID controller" 3862306a36Sopenharmony_ci * 3962306a36Sopenharmony_ci * 2002-07-02 - 0.0.2 : basic working version 4062306a36Sopenharmony_ci * - all axes and 9 of the 10 buttons work (german InterAct device) 4162306a36Sopenharmony_ci * - the black button does not work 4262306a36Sopenharmony_ci * 4362306a36Sopenharmony_ci * 2002-07-14 - 0.0.3 : rework by Vojtech Pavlik 4462306a36Sopenharmony_ci * - indentation fixes 4562306a36Sopenharmony_ci * - usb + input init sequence fixes 4662306a36Sopenharmony_ci * 4762306a36Sopenharmony_ci * 2002-07-16 - 0.0.4 : minor changes, merge with Vojtech's v0.0.3 4862306a36Sopenharmony_ci * - verified the lack of HID and report descriptors 4962306a36Sopenharmony_ci * - verified that ALL buttons WORK 5062306a36Sopenharmony_ci * - fixed d-pad to axes mapping 5162306a36Sopenharmony_ci * 5262306a36Sopenharmony_ci * 2002-07-17 - 0.0.5 : simplified d-pad handling 5362306a36Sopenharmony_ci * 5462306a36Sopenharmony_ci * 2004-10-02 - 0.0.6 : DDR pad support 5562306a36Sopenharmony_ci * - borrowed from the Xbox Linux kernel 5662306a36Sopenharmony_ci * - USB id's for commonly used dance pads are present 5762306a36Sopenharmony_ci * - dance pads will map D-PAD to buttons, not axes 5862306a36Sopenharmony_ci * - pass the module paramater 'dpad_to_buttons' to force 5962306a36Sopenharmony_ci * the D-PAD to map to buttons if your pad is not detected 6062306a36Sopenharmony_ci * 6162306a36Sopenharmony_ci * Later changes can be tracked in SCM. 6262306a36Sopenharmony_ci */ 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci#include <linux/bits.h> 6562306a36Sopenharmony_ci#include <linux/kernel.h> 6662306a36Sopenharmony_ci#include <linux/input.h> 6762306a36Sopenharmony_ci#include <linux/rcupdate.h> 6862306a36Sopenharmony_ci#include <linux/slab.h> 6962306a36Sopenharmony_ci#include <linux/stat.h> 7062306a36Sopenharmony_ci#include <linux/module.h> 7162306a36Sopenharmony_ci#include <linux/usb/input.h> 7262306a36Sopenharmony_ci#include <linux/usb/quirks.h> 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci#define XPAD_PKT_LEN 64 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci/* 7762306a36Sopenharmony_ci * xbox d-pads should map to buttons, as is required for DDR pads 7862306a36Sopenharmony_ci * but we map them to axes when possible to simplify things 7962306a36Sopenharmony_ci */ 8062306a36Sopenharmony_ci#define MAP_DPAD_TO_BUTTONS (1 << 0) 8162306a36Sopenharmony_ci#define MAP_TRIGGERS_TO_BUTTONS (1 << 1) 8262306a36Sopenharmony_ci#define MAP_STICKS_TO_NULL (1 << 2) 8362306a36Sopenharmony_ci#define MAP_SELECT_BUTTON (1 << 3) 8462306a36Sopenharmony_ci#define MAP_PADDLES (1 << 4) 8562306a36Sopenharmony_ci#define MAP_PROFILE_BUTTON (1 << 5) 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci#define DANCEPAD_MAP_CONFIG (MAP_DPAD_TO_BUTTONS | \ 8862306a36Sopenharmony_ci MAP_TRIGGERS_TO_BUTTONS | MAP_STICKS_TO_NULL) 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci#define XTYPE_XBOX 0 9162306a36Sopenharmony_ci#define XTYPE_XBOX360 1 9262306a36Sopenharmony_ci#define XTYPE_XBOX360W 2 9362306a36Sopenharmony_ci#define XTYPE_XBOXONE 3 9462306a36Sopenharmony_ci#define XTYPE_UNKNOWN 4 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci/* Send power-off packet to xpad360w after holding the mode button for this many 9762306a36Sopenharmony_ci * seconds 9862306a36Sopenharmony_ci */ 9962306a36Sopenharmony_ci#define XPAD360W_POWEROFF_TIMEOUT 5 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci#define PKT_XB 0 10262306a36Sopenharmony_ci#define PKT_XBE1 1 10362306a36Sopenharmony_ci#define PKT_XBE2_FW_OLD 2 10462306a36Sopenharmony_ci#define PKT_XBE2_FW_5_EARLY 3 10562306a36Sopenharmony_ci#define PKT_XBE2_FW_5_11 4 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_cistatic bool dpad_to_buttons; 10862306a36Sopenharmony_cimodule_param(dpad_to_buttons, bool, S_IRUGO); 10962306a36Sopenharmony_ciMODULE_PARM_DESC(dpad_to_buttons, "Map D-PAD to buttons rather than axes for unknown pads"); 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_cistatic bool triggers_to_buttons; 11262306a36Sopenharmony_cimodule_param(triggers_to_buttons, bool, S_IRUGO); 11362306a36Sopenharmony_ciMODULE_PARM_DESC(triggers_to_buttons, "Map triggers to buttons rather than axes for unknown pads"); 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_cistatic bool sticks_to_null; 11662306a36Sopenharmony_cimodule_param(sticks_to_null, bool, S_IRUGO); 11762306a36Sopenharmony_ciMODULE_PARM_DESC(sticks_to_null, "Do not map sticks at all for unknown pads"); 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_cistatic bool auto_poweroff = true; 12062306a36Sopenharmony_cimodule_param(auto_poweroff, bool, S_IWUSR | S_IRUGO); 12162306a36Sopenharmony_ciMODULE_PARM_DESC(auto_poweroff, "Power off wireless controllers on suspend"); 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_cistatic const struct xpad_device { 12462306a36Sopenharmony_ci u16 idVendor; 12562306a36Sopenharmony_ci u16 idProduct; 12662306a36Sopenharmony_ci char *name; 12762306a36Sopenharmony_ci u8 mapping; 12862306a36Sopenharmony_ci u8 xtype; 12962306a36Sopenharmony_ci} xpad_device[] = { 13062306a36Sopenharmony_ci { 0x0079, 0x18d4, "GPD Win 2 X-Box Controller", 0, XTYPE_XBOX360 }, 13162306a36Sopenharmony_ci { 0x03eb, 0xff01, "Wooting One (Legacy)", 0, XTYPE_XBOX360 }, 13262306a36Sopenharmony_ci { 0x03eb, 0xff02, "Wooting Two (Legacy)", 0, XTYPE_XBOX360 }, 13362306a36Sopenharmony_ci { 0x03f0, 0x0495, "HyperX Clutch Gladiate", 0, XTYPE_XBOXONE }, 13462306a36Sopenharmony_ci { 0x044f, 0x0f00, "Thrustmaster Wheel", 0, XTYPE_XBOX }, 13562306a36Sopenharmony_ci { 0x044f, 0x0f03, "Thrustmaster Wheel", 0, XTYPE_XBOX }, 13662306a36Sopenharmony_ci { 0x044f, 0x0f07, "Thrustmaster, Inc. Controller", 0, XTYPE_XBOX }, 13762306a36Sopenharmony_ci { 0x044f, 0x0f10, "Thrustmaster Modena GT Wheel", 0, XTYPE_XBOX }, 13862306a36Sopenharmony_ci { 0x044f, 0xb326, "Thrustmaster Gamepad GP XID", 0, XTYPE_XBOX360 }, 13962306a36Sopenharmony_ci { 0x045e, 0x0202, "Microsoft X-Box pad v1 (US)", 0, XTYPE_XBOX }, 14062306a36Sopenharmony_ci { 0x045e, 0x0285, "Microsoft X-Box pad (Japan)", 0, XTYPE_XBOX }, 14162306a36Sopenharmony_ci { 0x045e, 0x0287, "Microsoft Xbox Controller S", 0, XTYPE_XBOX }, 14262306a36Sopenharmony_ci { 0x045e, 0x0288, "Microsoft Xbox Controller S v2", 0, XTYPE_XBOX }, 14362306a36Sopenharmony_ci { 0x045e, 0x0289, "Microsoft X-Box pad v2 (US)", 0, XTYPE_XBOX }, 14462306a36Sopenharmony_ci { 0x045e, 0x028e, "Microsoft X-Box 360 pad", 0, XTYPE_XBOX360 }, 14562306a36Sopenharmony_ci { 0x045e, 0x028f, "Microsoft X-Box 360 pad v2", 0, XTYPE_XBOX360 }, 14662306a36Sopenharmony_ci { 0x045e, 0x0291, "Xbox 360 Wireless Receiver (XBOX)", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360W }, 14762306a36Sopenharmony_ci { 0x045e, 0x02d1, "Microsoft X-Box One pad", 0, XTYPE_XBOXONE }, 14862306a36Sopenharmony_ci { 0x045e, 0x02dd, "Microsoft X-Box One pad (Firmware 2015)", 0, XTYPE_XBOXONE }, 14962306a36Sopenharmony_ci { 0x045e, 0x02e3, "Microsoft X-Box One Elite pad", MAP_PADDLES, XTYPE_XBOXONE }, 15062306a36Sopenharmony_ci { 0x045e, 0x0b00, "Microsoft X-Box One Elite 2 pad", MAP_PADDLES, XTYPE_XBOXONE }, 15162306a36Sopenharmony_ci { 0x045e, 0x02ea, "Microsoft X-Box One S pad", 0, XTYPE_XBOXONE }, 15262306a36Sopenharmony_ci { 0x045e, 0x0719, "Xbox 360 Wireless Receiver", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360W }, 15362306a36Sopenharmony_ci { 0x045e, 0x0b0a, "Microsoft X-Box Adaptive Controller", MAP_PROFILE_BUTTON, XTYPE_XBOXONE }, 15462306a36Sopenharmony_ci { 0x045e, 0x0b12, "Microsoft Xbox Series S|X Controller", MAP_SELECT_BUTTON, XTYPE_XBOXONE }, 15562306a36Sopenharmony_ci { 0x046d, 0xc21d, "Logitech Gamepad F310", 0, XTYPE_XBOX360 }, 15662306a36Sopenharmony_ci { 0x046d, 0xc21e, "Logitech Gamepad F510", 0, XTYPE_XBOX360 }, 15762306a36Sopenharmony_ci { 0x046d, 0xc21f, "Logitech Gamepad F710", 0, XTYPE_XBOX360 }, 15862306a36Sopenharmony_ci { 0x046d, 0xc242, "Logitech Chillstream Controller", 0, XTYPE_XBOX360 }, 15962306a36Sopenharmony_ci { 0x046d, 0xca84, "Logitech Xbox Cordless Controller", 0, XTYPE_XBOX }, 16062306a36Sopenharmony_ci { 0x046d, 0xca88, "Logitech Compact Controller for Xbox", 0, XTYPE_XBOX }, 16162306a36Sopenharmony_ci { 0x046d, 0xca8a, "Logitech Precision Vibration Feedback Wheel", 0, XTYPE_XBOX }, 16262306a36Sopenharmony_ci { 0x046d, 0xcaa3, "Logitech DriveFx Racing Wheel", 0, XTYPE_XBOX360 }, 16362306a36Sopenharmony_ci { 0x056e, 0x2004, "Elecom JC-U3613M", 0, XTYPE_XBOX360 }, 16462306a36Sopenharmony_ci { 0x05fd, 0x1007, "Mad Catz Controller (unverified)", 0, XTYPE_XBOX }, 16562306a36Sopenharmony_ci { 0x05fd, 0x107a, "InterAct 'PowerPad Pro' X-Box pad (Germany)", 0, XTYPE_XBOX }, 16662306a36Sopenharmony_ci { 0x05fe, 0x3030, "Chic Controller", 0, XTYPE_XBOX }, 16762306a36Sopenharmony_ci { 0x05fe, 0x3031, "Chic Controller", 0, XTYPE_XBOX }, 16862306a36Sopenharmony_ci { 0x062a, 0x0020, "Logic3 Xbox GamePad", 0, XTYPE_XBOX }, 16962306a36Sopenharmony_ci { 0x062a, 0x0033, "Competition Pro Steering Wheel", 0, XTYPE_XBOX }, 17062306a36Sopenharmony_ci { 0x06a3, 0x0200, "Saitek Racing Wheel", 0, XTYPE_XBOX }, 17162306a36Sopenharmony_ci { 0x06a3, 0x0201, "Saitek Adrenalin", 0, XTYPE_XBOX }, 17262306a36Sopenharmony_ci { 0x06a3, 0xf51a, "Saitek P3600", 0, XTYPE_XBOX360 }, 17362306a36Sopenharmony_ci { 0x0738, 0x4506, "Mad Catz 4506 Wireless Controller", 0, XTYPE_XBOX }, 17462306a36Sopenharmony_ci { 0x0738, 0x4516, "Mad Catz Control Pad", 0, XTYPE_XBOX }, 17562306a36Sopenharmony_ci { 0x0738, 0x4520, "Mad Catz Control Pad Pro", 0, XTYPE_XBOX }, 17662306a36Sopenharmony_ci { 0x0738, 0x4522, "Mad Catz LumiCON", 0, XTYPE_XBOX }, 17762306a36Sopenharmony_ci { 0x0738, 0x4526, "Mad Catz Control Pad Pro", 0, XTYPE_XBOX }, 17862306a36Sopenharmony_ci { 0x0738, 0x4530, "Mad Catz Universal MC2 Racing Wheel and Pedals", 0, XTYPE_XBOX }, 17962306a36Sopenharmony_ci { 0x0738, 0x4536, "Mad Catz MicroCON", 0, XTYPE_XBOX }, 18062306a36Sopenharmony_ci { 0x0738, 0x4540, "Mad Catz Beat Pad", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX }, 18162306a36Sopenharmony_ci { 0x0738, 0x4556, "Mad Catz Lynx Wireless Controller", 0, XTYPE_XBOX }, 18262306a36Sopenharmony_ci { 0x0738, 0x4586, "Mad Catz MicroCon Wireless Controller", 0, XTYPE_XBOX }, 18362306a36Sopenharmony_ci { 0x0738, 0x4588, "Mad Catz Blaster", 0, XTYPE_XBOX }, 18462306a36Sopenharmony_ci { 0x0738, 0x45ff, "Mad Catz Beat Pad (w/ Handle)", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX }, 18562306a36Sopenharmony_ci { 0x0738, 0x4716, "Mad Catz Wired Xbox 360 Controller", 0, XTYPE_XBOX360 }, 18662306a36Sopenharmony_ci { 0x0738, 0x4718, "Mad Catz Street Fighter IV FightStick SE", 0, XTYPE_XBOX360 }, 18762306a36Sopenharmony_ci { 0x0738, 0x4726, "Mad Catz Xbox 360 Controller", 0, XTYPE_XBOX360 }, 18862306a36Sopenharmony_ci { 0x0738, 0x4728, "Mad Catz Street Fighter IV FightPad", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 }, 18962306a36Sopenharmony_ci { 0x0738, 0x4736, "Mad Catz MicroCon Gamepad", 0, XTYPE_XBOX360 }, 19062306a36Sopenharmony_ci { 0x0738, 0x4738, "Mad Catz Wired Xbox 360 Controller (SFIV)", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 }, 19162306a36Sopenharmony_ci { 0x0738, 0x4740, "Mad Catz Beat Pad", 0, XTYPE_XBOX360 }, 19262306a36Sopenharmony_ci { 0x0738, 0x4743, "Mad Catz Beat Pad Pro", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX }, 19362306a36Sopenharmony_ci { 0x0738, 0x4758, "Mad Catz Arcade Game Stick", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 }, 19462306a36Sopenharmony_ci { 0x0738, 0x4a01, "Mad Catz FightStick TE 2", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOXONE }, 19562306a36Sopenharmony_ci { 0x0738, 0x6040, "Mad Catz Beat Pad Pro", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX }, 19662306a36Sopenharmony_ci { 0x0738, 0x9871, "Mad Catz Portable Drum", 0, XTYPE_XBOX360 }, 19762306a36Sopenharmony_ci { 0x0738, 0xb726, "Mad Catz Xbox controller - MW2", 0, XTYPE_XBOX360 }, 19862306a36Sopenharmony_ci { 0x0738, 0xb738, "Mad Catz MVC2TE Stick 2", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 }, 19962306a36Sopenharmony_ci { 0x0738, 0xbeef, "Mad Catz JOYTECH NEO SE Advanced GamePad", XTYPE_XBOX360 }, 20062306a36Sopenharmony_ci { 0x0738, 0xcb02, "Saitek Cyborg Rumble Pad - PC/Xbox 360", 0, XTYPE_XBOX360 }, 20162306a36Sopenharmony_ci { 0x0738, 0xcb03, "Saitek P3200 Rumble Pad - PC/Xbox 360", 0, XTYPE_XBOX360 }, 20262306a36Sopenharmony_ci { 0x0738, 0xcb29, "Saitek Aviator Stick AV8R02", 0, XTYPE_XBOX360 }, 20362306a36Sopenharmony_ci { 0x0738, 0xf738, "Super SFIV FightStick TE S", 0, XTYPE_XBOX360 }, 20462306a36Sopenharmony_ci { 0x07ff, 0xffff, "Mad Catz GamePad", 0, XTYPE_XBOX360 }, 20562306a36Sopenharmony_ci { 0x0c12, 0x0005, "Intec wireless", 0, XTYPE_XBOX }, 20662306a36Sopenharmony_ci { 0x0c12, 0x8801, "Nyko Xbox Controller", 0, XTYPE_XBOX }, 20762306a36Sopenharmony_ci { 0x0c12, 0x8802, "Zeroplus Xbox Controller", 0, XTYPE_XBOX }, 20862306a36Sopenharmony_ci { 0x0c12, 0x8809, "RedOctane Xbox Dance Pad", DANCEPAD_MAP_CONFIG, XTYPE_XBOX }, 20962306a36Sopenharmony_ci { 0x0c12, 0x880a, "Pelican Eclipse PL-2023", 0, XTYPE_XBOX }, 21062306a36Sopenharmony_ci { 0x0c12, 0x8810, "Zeroplus Xbox Controller", 0, XTYPE_XBOX }, 21162306a36Sopenharmony_ci { 0x0c12, 0x9902, "HAMA VibraX - *FAULTY HARDWARE*", 0, XTYPE_XBOX }, 21262306a36Sopenharmony_ci { 0x0d2f, 0x0002, "Andamiro Pump It Up pad", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX }, 21362306a36Sopenharmony_ci { 0x0e4c, 0x1097, "Radica Gamester Controller", 0, XTYPE_XBOX }, 21462306a36Sopenharmony_ci { 0x0e4c, 0x1103, "Radica Gamester Reflex", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX }, 21562306a36Sopenharmony_ci { 0x0e4c, 0x2390, "Radica Games Jtech Controller", 0, XTYPE_XBOX }, 21662306a36Sopenharmony_ci { 0x0e4c, 0x3510, "Radica Gamester", 0, XTYPE_XBOX }, 21762306a36Sopenharmony_ci { 0x0e6f, 0x0003, "Logic3 Freebird wireless Controller", 0, XTYPE_XBOX }, 21862306a36Sopenharmony_ci { 0x0e6f, 0x0005, "Eclipse wireless Controller", 0, XTYPE_XBOX }, 21962306a36Sopenharmony_ci { 0x0e6f, 0x0006, "Edge wireless Controller", 0, XTYPE_XBOX }, 22062306a36Sopenharmony_ci { 0x0e6f, 0x0008, "After Glow Pro Controller", 0, XTYPE_XBOX }, 22162306a36Sopenharmony_ci { 0x0e6f, 0x0105, "HSM3 Xbox360 dancepad", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360 }, 22262306a36Sopenharmony_ci { 0x0e6f, 0x0113, "Afterglow AX.1 Gamepad for Xbox 360", 0, XTYPE_XBOX360 }, 22362306a36Sopenharmony_ci { 0x0e6f, 0x011f, "Rock Candy Gamepad Wired Controller", 0, XTYPE_XBOX360 }, 22462306a36Sopenharmony_ci { 0x0e6f, 0x0131, "PDP EA Sports Controller", 0, XTYPE_XBOX360 }, 22562306a36Sopenharmony_ci { 0x0e6f, 0x0133, "Xbox 360 Wired Controller", 0, XTYPE_XBOX360 }, 22662306a36Sopenharmony_ci { 0x0e6f, 0x0139, "Afterglow Prismatic Wired Controller", 0, XTYPE_XBOXONE }, 22762306a36Sopenharmony_ci { 0x0e6f, 0x013a, "PDP Xbox One Controller", 0, XTYPE_XBOXONE }, 22862306a36Sopenharmony_ci { 0x0e6f, 0x0146, "Rock Candy Wired Controller for Xbox One", 0, XTYPE_XBOXONE }, 22962306a36Sopenharmony_ci { 0x0e6f, 0x0147, "PDP Marvel Xbox One Controller", 0, XTYPE_XBOXONE }, 23062306a36Sopenharmony_ci { 0x0e6f, 0x015c, "PDP Xbox One Arcade Stick", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOXONE }, 23162306a36Sopenharmony_ci { 0x0e6f, 0x0161, "PDP Xbox One Controller", 0, XTYPE_XBOXONE }, 23262306a36Sopenharmony_ci { 0x0e6f, 0x0162, "PDP Xbox One Controller", 0, XTYPE_XBOXONE }, 23362306a36Sopenharmony_ci { 0x0e6f, 0x0163, "PDP Xbox One Controller", 0, XTYPE_XBOXONE }, 23462306a36Sopenharmony_ci { 0x0e6f, 0x0164, "PDP Battlefield One", 0, XTYPE_XBOXONE }, 23562306a36Sopenharmony_ci { 0x0e6f, 0x0165, "PDP Titanfall 2", 0, XTYPE_XBOXONE }, 23662306a36Sopenharmony_ci { 0x0e6f, 0x0201, "Pelican PL-3601 'TSZ' Wired Xbox 360 Controller", 0, XTYPE_XBOX360 }, 23762306a36Sopenharmony_ci { 0x0e6f, 0x0213, "Afterglow Gamepad for Xbox 360", 0, XTYPE_XBOX360 }, 23862306a36Sopenharmony_ci { 0x0e6f, 0x021f, "Rock Candy Gamepad for Xbox 360", 0, XTYPE_XBOX360 }, 23962306a36Sopenharmony_ci { 0x0e6f, 0x0246, "Rock Candy Gamepad for Xbox One 2015", 0, XTYPE_XBOXONE }, 24062306a36Sopenharmony_ci { 0x0e6f, 0x02a0, "PDP Xbox One Controller", 0, XTYPE_XBOXONE }, 24162306a36Sopenharmony_ci { 0x0e6f, 0x02a1, "PDP Xbox One Controller", 0, XTYPE_XBOXONE }, 24262306a36Sopenharmony_ci { 0x0e6f, 0x02a2, "PDP Wired Controller for Xbox One - Crimson Red", 0, XTYPE_XBOXONE }, 24362306a36Sopenharmony_ci { 0x0e6f, 0x02a4, "PDP Wired Controller for Xbox One - Stealth Series", 0, XTYPE_XBOXONE }, 24462306a36Sopenharmony_ci { 0x0e6f, 0x02a6, "PDP Wired Controller for Xbox One - Camo Series", 0, XTYPE_XBOXONE }, 24562306a36Sopenharmony_ci { 0x0e6f, 0x02a7, "PDP Xbox One Controller", 0, XTYPE_XBOXONE }, 24662306a36Sopenharmony_ci { 0x0e6f, 0x02a8, "PDP Xbox One Controller", 0, XTYPE_XBOXONE }, 24762306a36Sopenharmony_ci { 0x0e6f, 0x02ab, "PDP Controller for Xbox One", 0, XTYPE_XBOXONE }, 24862306a36Sopenharmony_ci { 0x0e6f, 0x02ad, "PDP Wired Controller for Xbox One - Stealth Series", 0, XTYPE_XBOXONE }, 24962306a36Sopenharmony_ci { 0x0e6f, 0x02b3, "Afterglow Prismatic Wired Controller", 0, XTYPE_XBOXONE }, 25062306a36Sopenharmony_ci { 0x0e6f, 0x02b8, "Afterglow Prismatic Wired Controller", 0, XTYPE_XBOXONE }, 25162306a36Sopenharmony_ci { 0x0e6f, 0x0301, "Logic3 Controller", 0, XTYPE_XBOX360 }, 25262306a36Sopenharmony_ci { 0x0e6f, 0x0346, "Rock Candy Gamepad for Xbox One 2016", 0, XTYPE_XBOXONE }, 25362306a36Sopenharmony_ci { 0x0e6f, 0x0401, "Logic3 Controller", 0, XTYPE_XBOX360 }, 25462306a36Sopenharmony_ci { 0x0e6f, 0x0413, "Afterglow AX.1 Gamepad for Xbox 360", 0, XTYPE_XBOX360 }, 25562306a36Sopenharmony_ci { 0x0e6f, 0x0501, "PDP Xbox 360 Controller", 0, XTYPE_XBOX360 }, 25662306a36Sopenharmony_ci { 0x0e6f, 0xf900, "PDP Afterglow AX.1", 0, XTYPE_XBOX360 }, 25762306a36Sopenharmony_ci { 0x0e8f, 0x0201, "SmartJoy Frag Xpad/PS2 adaptor", 0, XTYPE_XBOX }, 25862306a36Sopenharmony_ci { 0x0e8f, 0x3008, "Generic xbox control (dealextreme)", 0, XTYPE_XBOX }, 25962306a36Sopenharmony_ci { 0x0f0d, 0x000a, "Hori Co. DOA4 FightStick", 0, XTYPE_XBOX360 }, 26062306a36Sopenharmony_ci { 0x0f0d, 0x000c, "Hori PadEX Turbo", 0, XTYPE_XBOX360 }, 26162306a36Sopenharmony_ci { 0x0f0d, 0x000d, "Hori Fighting Stick EX2", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 }, 26262306a36Sopenharmony_ci { 0x0f0d, 0x0016, "Hori Real Arcade Pro.EX", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 }, 26362306a36Sopenharmony_ci { 0x0f0d, 0x001b, "Hori Real Arcade Pro VX", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 }, 26462306a36Sopenharmony_ci { 0x0f0d, 0x0063, "Hori Real Arcade Pro Hayabusa (USA) Xbox One", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOXONE }, 26562306a36Sopenharmony_ci { 0x0f0d, 0x0067, "HORIPAD ONE", 0, XTYPE_XBOXONE }, 26662306a36Sopenharmony_ci { 0x0f0d, 0x0078, "Hori Real Arcade Pro V Kai Xbox One", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOXONE }, 26762306a36Sopenharmony_ci { 0x0f0d, 0x00c5, "Hori Fighting Commander ONE", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOXONE }, 26862306a36Sopenharmony_ci { 0x0f0d, 0x00dc, "HORIPAD FPS for Nintendo Switch", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 }, 26962306a36Sopenharmony_ci { 0x0f30, 0x010b, "Philips Recoil", 0, XTYPE_XBOX }, 27062306a36Sopenharmony_ci { 0x0f30, 0x0202, "Joytech Advanced Controller", 0, XTYPE_XBOX }, 27162306a36Sopenharmony_ci { 0x0f30, 0x8888, "BigBen XBMiniPad Controller", 0, XTYPE_XBOX }, 27262306a36Sopenharmony_ci { 0x102c, 0xff0c, "Joytech Wireless Advanced Controller", 0, XTYPE_XBOX }, 27362306a36Sopenharmony_ci { 0x1038, 0x1430, "SteelSeries Stratus Duo", 0, XTYPE_XBOX360 }, 27462306a36Sopenharmony_ci { 0x1038, 0x1431, "SteelSeries Stratus Duo", 0, XTYPE_XBOX360 }, 27562306a36Sopenharmony_ci { 0x11c9, 0x55f0, "Nacon GC-100XF", 0, XTYPE_XBOX360 }, 27662306a36Sopenharmony_ci { 0x11ff, 0x0511, "PXN V900", 0, XTYPE_XBOX360 }, 27762306a36Sopenharmony_ci { 0x1209, 0x2882, "Ardwiino Controller", 0, XTYPE_XBOX360 }, 27862306a36Sopenharmony_ci { 0x12ab, 0x0004, "Honey Bee Xbox360 dancepad", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360 }, 27962306a36Sopenharmony_ci { 0x12ab, 0x0301, "PDP AFTERGLOW AX.1", 0, XTYPE_XBOX360 }, 28062306a36Sopenharmony_ci { 0x12ab, 0x0303, "Mortal Kombat Klassic FightStick", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 }, 28162306a36Sopenharmony_ci { 0x12ab, 0x8809, "Xbox DDR dancepad", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX }, 28262306a36Sopenharmony_ci { 0x1430, 0x4748, "RedOctane Guitar Hero X-plorer", 0, XTYPE_XBOX360 }, 28362306a36Sopenharmony_ci { 0x1430, 0x8888, "TX6500+ Dance Pad (first generation)", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX }, 28462306a36Sopenharmony_ci { 0x1430, 0xf801, "RedOctane Controller", 0, XTYPE_XBOX360 }, 28562306a36Sopenharmony_ci { 0x146b, 0x0601, "BigBen Interactive XBOX 360 Controller", 0, XTYPE_XBOX360 }, 28662306a36Sopenharmony_ci { 0x146b, 0x0604, "Bigben Interactive DAIJA Arcade Stick", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 }, 28762306a36Sopenharmony_ci { 0x1532, 0x0a00, "Razer Atrox Arcade Stick", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOXONE }, 28862306a36Sopenharmony_ci { 0x1532, 0x0a03, "Razer Wildcat", 0, XTYPE_XBOXONE }, 28962306a36Sopenharmony_ci { 0x1532, 0x0a29, "Razer Wolverine V2", 0, XTYPE_XBOXONE }, 29062306a36Sopenharmony_ci { 0x15e4, 0x3f00, "Power A Mini Pro Elite", 0, XTYPE_XBOX360 }, 29162306a36Sopenharmony_ci { 0x15e4, 0x3f0a, "Xbox Airflo wired controller", 0, XTYPE_XBOX360 }, 29262306a36Sopenharmony_ci { 0x15e4, 0x3f10, "Batarang Xbox 360 controller", 0, XTYPE_XBOX360 }, 29362306a36Sopenharmony_ci { 0x162e, 0xbeef, "Joytech Neo-Se Take2", 0, XTYPE_XBOX360 }, 29462306a36Sopenharmony_ci { 0x1689, 0xfd00, "Razer Onza Tournament Edition", 0, XTYPE_XBOX360 }, 29562306a36Sopenharmony_ci { 0x1689, 0xfd01, "Razer Onza Classic Edition", 0, XTYPE_XBOX360 }, 29662306a36Sopenharmony_ci { 0x1689, 0xfe00, "Razer Sabertooth", 0, XTYPE_XBOX360 }, 29762306a36Sopenharmony_ci { 0x17ef, 0x6182, "Lenovo Legion Controller for Windows", 0, XTYPE_XBOX360 }, 29862306a36Sopenharmony_ci { 0x1949, 0x041a, "Amazon Game Controller", 0, XTYPE_XBOX360 }, 29962306a36Sopenharmony_ci { 0x1bad, 0x0002, "Harmonix Rock Band Guitar", 0, XTYPE_XBOX360 }, 30062306a36Sopenharmony_ci { 0x1bad, 0x0003, "Harmonix Rock Band Drumkit", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360 }, 30162306a36Sopenharmony_ci { 0x1bad, 0x0130, "Ion Drum Rocker", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360 }, 30262306a36Sopenharmony_ci { 0x1bad, 0xf016, "Mad Catz Xbox 360 Controller", 0, XTYPE_XBOX360 }, 30362306a36Sopenharmony_ci { 0x1bad, 0xf018, "Mad Catz Street Fighter IV SE Fighting Stick", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 }, 30462306a36Sopenharmony_ci { 0x1bad, 0xf019, "Mad Catz Brawlstick for Xbox 360", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 }, 30562306a36Sopenharmony_ci { 0x1bad, 0xf021, "Mad Cats Ghost Recon FS GamePad", 0, XTYPE_XBOX360 }, 30662306a36Sopenharmony_ci { 0x1bad, 0xf023, "MLG Pro Circuit Controller (Xbox)", 0, XTYPE_XBOX360 }, 30762306a36Sopenharmony_ci { 0x1bad, 0xf025, "Mad Catz Call Of Duty", 0, XTYPE_XBOX360 }, 30862306a36Sopenharmony_ci { 0x1bad, 0xf027, "Mad Catz FPS Pro", 0, XTYPE_XBOX360 }, 30962306a36Sopenharmony_ci { 0x1bad, 0xf028, "Street Fighter IV FightPad", 0, XTYPE_XBOX360 }, 31062306a36Sopenharmony_ci { 0x1bad, 0xf02e, "Mad Catz Fightpad", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 }, 31162306a36Sopenharmony_ci { 0x1bad, 0xf030, "Mad Catz Xbox 360 MC2 MicroCon Racing Wheel", 0, XTYPE_XBOX360 }, 31262306a36Sopenharmony_ci { 0x1bad, 0xf036, "Mad Catz MicroCon GamePad Pro", 0, XTYPE_XBOX360 }, 31362306a36Sopenharmony_ci { 0x1bad, 0xf038, "Street Fighter IV FightStick TE", 0, XTYPE_XBOX360 }, 31462306a36Sopenharmony_ci { 0x1bad, 0xf039, "Mad Catz MvC2 TE", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 }, 31562306a36Sopenharmony_ci { 0x1bad, 0xf03a, "Mad Catz SFxT Fightstick Pro", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 }, 31662306a36Sopenharmony_ci { 0x1bad, 0xf03d, "Street Fighter IV Arcade Stick TE - Chun Li", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 }, 31762306a36Sopenharmony_ci { 0x1bad, 0xf03e, "Mad Catz MLG FightStick TE", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 }, 31862306a36Sopenharmony_ci { 0x1bad, 0xf03f, "Mad Catz FightStick SoulCaliber", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 }, 31962306a36Sopenharmony_ci { 0x1bad, 0xf042, "Mad Catz FightStick TES+", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 }, 32062306a36Sopenharmony_ci { 0x1bad, 0xf080, "Mad Catz FightStick TE2", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 }, 32162306a36Sopenharmony_ci { 0x1bad, 0xf501, "HoriPad EX2 Turbo", 0, XTYPE_XBOX360 }, 32262306a36Sopenharmony_ci { 0x1bad, 0xf502, "Hori Real Arcade Pro.VX SA", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 }, 32362306a36Sopenharmony_ci { 0x1bad, 0xf503, "Hori Fighting Stick VX", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 }, 32462306a36Sopenharmony_ci { 0x1bad, 0xf504, "Hori Real Arcade Pro. EX", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 }, 32562306a36Sopenharmony_ci { 0x1bad, 0xf505, "Hori Fighting Stick EX2B", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 }, 32662306a36Sopenharmony_ci { 0x1bad, 0xf506, "Hori Real Arcade Pro.EX Premium VLX", 0, XTYPE_XBOX360 }, 32762306a36Sopenharmony_ci { 0x1bad, 0xf900, "Harmonix Xbox 360 Controller", 0, XTYPE_XBOX360 }, 32862306a36Sopenharmony_ci { 0x1bad, 0xf901, "Gamestop Xbox 360 Controller", 0, XTYPE_XBOX360 }, 32962306a36Sopenharmony_ci { 0x1bad, 0xf903, "Tron Xbox 360 controller", 0, XTYPE_XBOX360 }, 33062306a36Sopenharmony_ci { 0x1bad, 0xf904, "PDP Versus Fighting Pad", 0, XTYPE_XBOX360 }, 33162306a36Sopenharmony_ci { 0x1bad, 0xf906, "MortalKombat FightStick", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 }, 33262306a36Sopenharmony_ci { 0x1bad, 0xfa01, "MadCatz GamePad", 0, XTYPE_XBOX360 }, 33362306a36Sopenharmony_ci { 0x1bad, 0xfd00, "Razer Onza TE", 0, XTYPE_XBOX360 }, 33462306a36Sopenharmony_ci { 0x1bad, 0xfd01, "Razer Onza", 0, XTYPE_XBOX360 }, 33562306a36Sopenharmony_ci { 0x20d6, 0x2001, "BDA Xbox Series X Wired Controller", 0, XTYPE_XBOXONE }, 33662306a36Sopenharmony_ci { 0x20d6, 0x2009, "PowerA Enhanced Wired Controller for Xbox Series X|S", 0, XTYPE_XBOXONE }, 33762306a36Sopenharmony_ci { 0x20d6, 0x281f, "PowerA Wired Controller For Xbox 360", 0, XTYPE_XBOX360 }, 33862306a36Sopenharmony_ci { 0x2e24, 0x0652, "Hyperkin Duke X-Box One pad", 0, XTYPE_XBOXONE }, 33962306a36Sopenharmony_ci { 0x24c6, 0x5000, "Razer Atrox Arcade Stick", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 }, 34062306a36Sopenharmony_ci { 0x24c6, 0x5300, "PowerA MINI PROEX Controller", 0, XTYPE_XBOX360 }, 34162306a36Sopenharmony_ci { 0x24c6, 0x5303, "Xbox Airflo wired controller", 0, XTYPE_XBOX360 }, 34262306a36Sopenharmony_ci { 0x24c6, 0x530a, "Xbox 360 Pro EX Controller", 0, XTYPE_XBOX360 }, 34362306a36Sopenharmony_ci { 0x24c6, 0x531a, "PowerA Pro Ex", 0, XTYPE_XBOX360 }, 34462306a36Sopenharmony_ci { 0x24c6, 0x5397, "FUS1ON Tournament Controller", 0, XTYPE_XBOX360 }, 34562306a36Sopenharmony_ci { 0x24c6, 0x541a, "PowerA Xbox One Mini Wired Controller", 0, XTYPE_XBOXONE }, 34662306a36Sopenharmony_ci { 0x24c6, 0x542a, "Xbox ONE spectra", 0, XTYPE_XBOXONE }, 34762306a36Sopenharmony_ci { 0x24c6, 0x543a, "PowerA Xbox One wired controller", 0, XTYPE_XBOXONE }, 34862306a36Sopenharmony_ci { 0x24c6, 0x5500, "Hori XBOX 360 EX 2 with Turbo", 0, XTYPE_XBOX360 }, 34962306a36Sopenharmony_ci { 0x24c6, 0x5501, "Hori Real Arcade Pro VX-SA", 0, XTYPE_XBOX360 }, 35062306a36Sopenharmony_ci { 0x24c6, 0x5502, "Hori Fighting Stick VX Alt", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 }, 35162306a36Sopenharmony_ci { 0x24c6, 0x5503, "Hori Fighting Edge", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 }, 35262306a36Sopenharmony_ci { 0x24c6, 0x5506, "Hori SOULCALIBUR V Stick", 0, XTYPE_XBOX360 }, 35362306a36Sopenharmony_ci { 0x24c6, 0x5510, "Hori Fighting Commander ONE (Xbox 360/PC Mode)", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 }, 35462306a36Sopenharmony_ci { 0x24c6, 0x550d, "Hori GEM Xbox controller", 0, XTYPE_XBOX360 }, 35562306a36Sopenharmony_ci { 0x24c6, 0x550e, "Hori Real Arcade Pro V Kai 360", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 }, 35662306a36Sopenharmony_ci { 0x24c6, 0x551a, "PowerA FUSION Pro Controller", 0, XTYPE_XBOXONE }, 35762306a36Sopenharmony_ci { 0x24c6, 0x561a, "PowerA FUSION Controller", 0, XTYPE_XBOXONE }, 35862306a36Sopenharmony_ci { 0x24c6, 0x5b00, "ThrustMaster Ferrari 458 Racing Wheel", 0, XTYPE_XBOX360 }, 35962306a36Sopenharmony_ci { 0x24c6, 0x5b02, "Thrustmaster, Inc. GPX Controller", 0, XTYPE_XBOX360 }, 36062306a36Sopenharmony_ci { 0x24c6, 0x5b03, "Thrustmaster Ferrari 458 Racing Wheel", 0, XTYPE_XBOX360 }, 36162306a36Sopenharmony_ci { 0x24c6, 0x5d04, "Razer Sabertooth", 0, XTYPE_XBOX360 }, 36262306a36Sopenharmony_ci { 0x24c6, 0xfafe, "Rock Candy Gamepad for Xbox 360", 0, XTYPE_XBOX360 }, 36362306a36Sopenharmony_ci { 0x2563, 0x058d, "OneXPlayer Gamepad", 0, XTYPE_XBOX360 }, 36462306a36Sopenharmony_ci { 0x2dc8, 0x2000, "8BitDo Pro 2 Wired Controller fox Xbox", 0, XTYPE_XBOXONE }, 36562306a36Sopenharmony_ci { 0x2dc8, 0x3106, "8BitDo Pro 2 Wired Controller", 0, XTYPE_XBOX360 }, 36662306a36Sopenharmony_ci { 0x31e3, 0x1100, "Wooting One", 0, XTYPE_XBOX360 }, 36762306a36Sopenharmony_ci { 0x31e3, 0x1200, "Wooting Two", 0, XTYPE_XBOX360 }, 36862306a36Sopenharmony_ci { 0x31e3, 0x1210, "Wooting Lekker", 0, XTYPE_XBOX360 }, 36962306a36Sopenharmony_ci { 0x31e3, 0x1220, "Wooting Two HE", 0, XTYPE_XBOX360 }, 37062306a36Sopenharmony_ci { 0x31e3, 0x1300, "Wooting 60HE (AVR)", 0, XTYPE_XBOX360 }, 37162306a36Sopenharmony_ci { 0x31e3, 0x1310, "Wooting 60HE (ARM)", 0, XTYPE_XBOX360 }, 37262306a36Sopenharmony_ci { 0x3285, 0x0607, "Nacon GC-100", 0, XTYPE_XBOX360 }, 37362306a36Sopenharmony_ci { 0x3537, 0x1004, "GameSir T4 Kaleid", 0, XTYPE_XBOX360 }, 37462306a36Sopenharmony_ci { 0x3767, 0x0101, "Fanatec Speedster 3 Forceshock Wheel", 0, XTYPE_XBOX }, 37562306a36Sopenharmony_ci { 0xffff, 0xffff, "Chinese-made Xbox Controller", 0, XTYPE_XBOX }, 37662306a36Sopenharmony_ci { 0x0000, 0x0000, "Generic X-Box pad", 0, XTYPE_UNKNOWN } 37762306a36Sopenharmony_ci}; 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci/* buttons shared with xbox and xbox360 */ 38062306a36Sopenharmony_cistatic const signed short xpad_common_btn[] = { 38162306a36Sopenharmony_ci BTN_A, BTN_B, BTN_X, BTN_Y, /* "analog" buttons */ 38262306a36Sopenharmony_ci BTN_START, BTN_SELECT, BTN_THUMBL, BTN_THUMBR, /* start/back/sticks */ 38362306a36Sopenharmony_ci -1 /* terminating entry */ 38462306a36Sopenharmony_ci}; 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_ci/* original xbox controllers only */ 38762306a36Sopenharmony_cistatic const signed short xpad_btn[] = { 38862306a36Sopenharmony_ci BTN_C, BTN_Z, /* "analog" buttons */ 38962306a36Sopenharmony_ci -1 /* terminating entry */ 39062306a36Sopenharmony_ci}; 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_ci/* used when dpad is mapped to buttons */ 39362306a36Sopenharmony_cistatic const signed short xpad_btn_pad[] = { 39462306a36Sopenharmony_ci BTN_TRIGGER_HAPPY1, BTN_TRIGGER_HAPPY2, /* d-pad left, right */ 39562306a36Sopenharmony_ci BTN_TRIGGER_HAPPY3, BTN_TRIGGER_HAPPY4, /* d-pad up, down */ 39662306a36Sopenharmony_ci -1 /* terminating entry */ 39762306a36Sopenharmony_ci}; 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_ci/* used when triggers are mapped to buttons */ 40062306a36Sopenharmony_cistatic const signed short xpad_btn_triggers[] = { 40162306a36Sopenharmony_ci BTN_TL2, BTN_TR2, /* triggers left/right */ 40262306a36Sopenharmony_ci -1 40362306a36Sopenharmony_ci}; 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_cistatic const signed short xpad360_btn[] = { /* buttons for x360 controller */ 40662306a36Sopenharmony_ci BTN_TL, BTN_TR, /* Button LB/RB */ 40762306a36Sopenharmony_ci BTN_MODE, /* The big X button */ 40862306a36Sopenharmony_ci -1 40962306a36Sopenharmony_ci}; 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_cistatic const signed short xpad_abs[] = { 41262306a36Sopenharmony_ci ABS_X, ABS_Y, /* left stick */ 41362306a36Sopenharmony_ci ABS_RX, ABS_RY, /* right stick */ 41462306a36Sopenharmony_ci -1 /* terminating entry */ 41562306a36Sopenharmony_ci}; 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_ci/* used when dpad is mapped to axes */ 41862306a36Sopenharmony_cistatic const signed short xpad_abs_pad[] = { 41962306a36Sopenharmony_ci ABS_HAT0X, ABS_HAT0Y, /* d-pad axes */ 42062306a36Sopenharmony_ci -1 /* terminating entry */ 42162306a36Sopenharmony_ci}; 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_ci/* used when triggers are mapped to axes */ 42462306a36Sopenharmony_cistatic const signed short xpad_abs_triggers[] = { 42562306a36Sopenharmony_ci ABS_Z, ABS_RZ, /* triggers left/right */ 42662306a36Sopenharmony_ci -1 42762306a36Sopenharmony_ci}; 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_ci/* used when the controller has extra paddle buttons */ 43062306a36Sopenharmony_cistatic const signed short xpad_btn_paddles[] = { 43162306a36Sopenharmony_ci BTN_TRIGGER_HAPPY5, BTN_TRIGGER_HAPPY6, /* paddle upper right, lower right */ 43262306a36Sopenharmony_ci BTN_TRIGGER_HAPPY7, BTN_TRIGGER_HAPPY8, /* paddle upper left, lower left */ 43362306a36Sopenharmony_ci -1 /* terminating entry */ 43462306a36Sopenharmony_ci}; 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_ci/* 43762306a36Sopenharmony_ci * Xbox 360 has a vendor-specific class, so we cannot match it with only 43862306a36Sopenharmony_ci * USB_INTERFACE_INFO (also specifically refused by USB subsystem), so we 43962306a36Sopenharmony_ci * match against vendor id as well. Wired Xbox 360 devices have protocol 1, 44062306a36Sopenharmony_ci * wireless controllers have protocol 129. 44162306a36Sopenharmony_ci */ 44262306a36Sopenharmony_ci#define XPAD_XBOX360_VENDOR_PROTOCOL(vend, pr) \ 44362306a36Sopenharmony_ci .match_flags = USB_DEVICE_ID_MATCH_VENDOR | USB_DEVICE_ID_MATCH_INT_INFO, \ 44462306a36Sopenharmony_ci .idVendor = (vend), \ 44562306a36Sopenharmony_ci .bInterfaceClass = USB_CLASS_VENDOR_SPEC, \ 44662306a36Sopenharmony_ci .bInterfaceSubClass = 93, \ 44762306a36Sopenharmony_ci .bInterfaceProtocol = (pr) 44862306a36Sopenharmony_ci#define XPAD_XBOX360_VENDOR(vend) \ 44962306a36Sopenharmony_ci { XPAD_XBOX360_VENDOR_PROTOCOL((vend), 1) }, \ 45062306a36Sopenharmony_ci { XPAD_XBOX360_VENDOR_PROTOCOL((vend), 129) } 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_ci/* The Xbox One controller uses subclass 71 and protocol 208. */ 45362306a36Sopenharmony_ci#define XPAD_XBOXONE_VENDOR_PROTOCOL(vend, pr) \ 45462306a36Sopenharmony_ci .match_flags = USB_DEVICE_ID_MATCH_VENDOR | USB_DEVICE_ID_MATCH_INT_INFO, \ 45562306a36Sopenharmony_ci .idVendor = (vend), \ 45662306a36Sopenharmony_ci .bInterfaceClass = USB_CLASS_VENDOR_SPEC, \ 45762306a36Sopenharmony_ci .bInterfaceSubClass = 71, \ 45862306a36Sopenharmony_ci .bInterfaceProtocol = (pr) 45962306a36Sopenharmony_ci#define XPAD_XBOXONE_VENDOR(vend) \ 46062306a36Sopenharmony_ci { XPAD_XBOXONE_VENDOR_PROTOCOL((vend), 208) } 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_cistatic const struct usb_device_id xpad_table[] = { 46362306a36Sopenharmony_ci { USB_INTERFACE_INFO('X', 'B', 0) }, /* Xbox USB-IF not-approved class */ 46462306a36Sopenharmony_ci XPAD_XBOX360_VENDOR(0x0079), /* GPD Win 2 controller */ 46562306a36Sopenharmony_ci XPAD_XBOX360_VENDOR(0x03eb), /* Wooting Keyboards (Legacy) */ 46662306a36Sopenharmony_ci XPAD_XBOXONE_VENDOR(0x03f0), /* HP HyperX Xbox One controllers */ 46762306a36Sopenharmony_ci XPAD_XBOX360_VENDOR(0x044f), /* Thrustmaster Xbox 360 controllers */ 46862306a36Sopenharmony_ci XPAD_XBOX360_VENDOR(0x045e), /* Microsoft Xbox 360 controllers */ 46962306a36Sopenharmony_ci XPAD_XBOXONE_VENDOR(0x045e), /* Microsoft Xbox One controllers */ 47062306a36Sopenharmony_ci XPAD_XBOX360_VENDOR(0x046d), /* Logitech Xbox 360-style controllers */ 47162306a36Sopenharmony_ci XPAD_XBOX360_VENDOR(0x056e), /* Elecom JC-U3613M */ 47262306a36Sopenharmony_ci XPAD_XBOX360_VENDOR(0x06a3), /* Saitek P3600 */ 47362306a36Sopenharmony_ci XPAD_XBOX360_VENDOR(0x0738), /* Mad Catz Xbox 360 controllers */ 47462306a36Sopenharmony_ci { USB_DEVICE(0x0738, 0x4540) }, /* Mad Catz Beat Pad */ 47562306a36Sopenharmony_ci XPAD_XBOXONE_VENDOR(0x0738), /* Mad Catz FightStick TE 2 */ 47662306a36Sopenharmony_ci XPAD_XBOX360_VENDOR(0x07ff), /* Mad Catz Gamepad */ 47762306a36Sopenharmony_ci XPAD_XBOX360_VENDOR(0x0c12), /* Zeroplus X-Box 360 controllers */ 47862306a36Sopenharmony_ci XPAD_XBOX360_VENDOR(0x0e6f), /* 0x0e6f Xbox 360 controllers */ 47962306a36Sopenharmony_ci XPAD_XBOXONE_VENDOR(0x0e6f), /* 0x0e6f Xbox One controllers */ 48062306a36Sopenharmony_ci XPAD_XBOX360_VENDOR(0x0f0d), /* Hori controllers */ 48162306a36Sopenharmony_ci XPAD_XBOXONE_VENDOR(0x0f0d), /* Hori controllers */ 48262306a36Sopenharmony_ci XPAD_XBOX360_VENDOR(0x1038), /* SteelSeries controllers */ 48362306a36Sopenharmony_ci XPAD_XBOXONE_VENDOR(0x10f5), /* Turtle Beach Controllers */ 48462306a36Sopenharmony_ci XPAD_XBOX360_VENDOR(0x11c9), /* Nacon GC100XF */ 48562306a36Sopenharmony_ci XPAD_XBOX360_VENDOR(0x11ff), /* PXN V900 */ 48662306a36Sopenharmony_ci XPAD_XBOX360_VENDOR(0x1209), /* Ardwiino Controllers */ 48762306a36Sopenharmony_ci XPAD_XBOX360_VENDOR(0x12ab), /* Xbox 360 dance pads */ 48862306a36Sopenharmony_ci XPAD_XBOX360_VENDOR(0x1430), /* RedOctane Xbox 360 controllers */ 48962306a36Sopenharmony_ci XPAD_XBOX360_VENDOR(0x146b), /* Bigben Interactive controllers */ 49062306a36Sopenharmony_ci XPAD_XBOX360_VENDOR(0x1532), /* Razer Sabertooth */ 49162306a36Sopenharmony_ci XPAD_XBOXONE_VENDOR(0x1532), /* Razer Wildcat */ 49262306a36Sopenharmony_ci XPAD_XBOX360_VENDOR(0x15e4), /* Numark Xbox 360 controllers */ 49362306a36Sopenharmony_ci XPAD_XBOX360_VENDOR(0x162e), /* Joytech Xbox 360 controllers */ 49462306a36Sopenharmony_ci XPAD_XBOX360_VENDOR(0x1689), /* Razer Onza */ 49562306a36Sopenharmony_ci XPAD_XBOX360_VENDOR(0x17ef), /* Lenovo */ 49662306a36Sopenharmony_ci XPAD_XBOX360_VENDOR(0x1949), /* Amazon controllers */ 49762306a36Sopenharmony_ci XPAD_XBOX360_VENDOR(0x1bad), /* Harmonix Rock Band guitar and drums */ 49862306a36Sopenharmony_ci XPAD_XBOX360_VENDOR(0x20d6), /* PowerA controllers */ 49962306a36Sopenharmony_ci XPAD_XBOXONE_VENDOR(0x20d6), /* PowerA controllers */ 50062306a36Sopenharmony_ci XPAD_XBOX360_VENDOR(0x24c6), /* PowerA controllers */ 50162306a36Sopenharmony_ci XPAD_XBOXONE_VENDOR(0x24c6), /* PowerA controllers */ 50262306a36Sopenharmony_ci XPAD_XBOX360_VENDOR(0x2563), /* OneXPlayer Gamepad */ 50362306a36Sopenharmony_ci XPAD_XBOX360_VENDOR(0x260d), /* Dareu H101 */ 50462306a36Sopenharmony_ci XPAD_XBOX360_VENDOR(0x2c22), /* Qanba Controllers */ 50562306a36Sopenharmony_ci XPAD_XBOX360_VENDOR(0x2dc8), /* 8BitDo Pro 2 Wired Controller */ 50662306a36Sopenharmony_ci XPAD_XBOXONE_VENDOR(0x2dc8), /* 8BitDo Pro 2 Wired Controller for Xbox */ 50762306a36Sopenharmony_ci XPAD_XBOXONE_VENDOR(0x2e24), /* Hyperkin Duke Xbox One pad */ 50862306a36Sopenharmony_ci XPAD_XBOX360_VENDOR(0x2f24), /* GameSir controllers */ 50962306a36Sopenharmony_ci XPAD_XBOX360_VENDOR(0x31e3), /* Wooting Keyboards */ 51062306a36Sopenharmony_ci XPAD_XBOX360_VENDOR(0x3285), /* Nacon GC-100 */ 51162306a36Sopenharmony_ci XPAD_XBOX360_VENDOR(0x3537), /* GameSir Controllers */ 51262306a36Sopenharmony_ci XPAD_XBOXONE_VENDOR(0x3537), /* GameSir Controllers */ 51362306a36Sopenharmony_ci { } 51462306a36Sopenharmony_ci}; 51562306a36Sopenharmony_ci 51662306a36Sopenharmony_ciMODULE_DEVICE_TABLE(usb, xpad_table); 51762306a36Sopenharmony_ci 51862306a36Sopenharmony_cistruct xboxone_init_packet { 51962306a36Sopenharmony_ci u16 idVendor; 52062306a36Sopenharmony_ci u16 idProduct; 52162306a36Sopenharmony_ci const u8 *data; 52262306a36Sopenharmony_ci u8 len; 52362306a36Sopenharmony_ci}; 52462306a36Sopenharmony_ci 52562306a36Sopenharmony_ci#define XBOXONE_INIT_PKT(_vid, _pid, _data) \ 52662306a36Sopenharmony_ci { \ 52762306a36Sopenharmony_ci .idVendor = (_vid), \ 52862306a36Sopenharmony_ci .idProduct = (_pid), \ 52962306a36Sopenharmony_ci .data = (_data), \ 53062306a36Sopenharmony_ci .len = ARRAY_SIZE(_data), \ 53162306a36Sopenharmony_ci } 53262306a36Sopenharmony_ci 53362306a36Sopenharmony_ci/* 53462306a36Sopenharmony_ci * starting with xbox one, the game input protocol is used 53562306a36Sopenharmony_ci * magic numbers are taken from 53662306a36Sopenharmony_ci * - https://github.com/xpadneo/gip-dissector/blob/main/src/gip-dissector.lua 53762306a36Sopenharmony_ci * - https://github.com/medusalix/xone/blob/master/bus/protocol.c 53862306a36Sopenharmony_ci */ 53962306a36Sopenharmony_ci#define GIP_CMD_ACK 0x01 54062306a36Sopenharmony_ci#define GIP_CMD_IDENTIFY 0x04 54162306a36Sopenharmony_ci#define GIP_CMD_POWER 0x05 54262306a36Sopenharmony_ci#define GIP_CMD_AUTHENTICATE 0x06 54362306a36Sopenharmony_ci#define GIP_CMD_VIRTUAL_KEY 0x07 54462306a36Sopenharmony_ci#define GIP_CMD_RUMBLE 0x09 54562306a36Sopenharmony_ci#define GIP_CMD_LED 0x0a 54662306a36Sopenharmony_ci#define GIP_CMD_FIRMWARE 0x0c 54762306a36Sopenharmony_ci#define GIP_CMD_INPUT 0x20 54862306a36Sopenharmony_ci 54962306a36Sopenharmony_ci#define GIP_SEQ0 0x00 55062306a36Sopenharmony_ci 55162306a36Sopenharmony_ci#define GIP_OPT_ACK 0x10 55262306a36Sopenharmony_ci#define GIP_OPT_INTERNAL 0x20 55362306a36Sopenharmony_ci 55462306a36Sopenharmony_ci/* 55562306a36Sopenharmony_ci * length of the command payload encoded with 55662306a36Sopenharmony_ci * https://en.wikipedia.org/wiki/LEB128 55762306a36Sopenharmony_ci * which is a no-op for N < 128 55862306a36Sopenharmony_ci */ 55962306a36Sopenharmony_ci#define GIP_PL_LEN(N) (N) 56062306a36Sopenharmony_ci 56162306a36Sopenharmony_ci/* 56262306a36Sopenharmony_ci * payload specific defines 56362306a36Sopenharmony_ci */ 56462306a36Sopenharmony_ci#define GIP_PWR_ON 0x00 56562306a36Sopenharmony_ci#define GIP_LED_ON 0x01 56662306a36Sopenharmony_ci 56762306a36Sopenharmony_ci#define GIP_MOTOR_R BIT(0) 56862306a36Sopenharmony_ci#define GIP_MOTOR_L BIT(1) 56962306a36Sopenharmony_ci#define GIP_MOTOR_RT BIT(2) 57062306a36Sopenharmony_ci#define GIP_MOTOR_LT BIT(3) 57162306a36Sopenharmony_ci#define GIP_MOTOR_ALL (GIP_MOTOR_R | GIP_MOTOR_L | GIP_MOTOR_RT | GIP_MOTOR_LT) 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_ci#define GIP_WIRED_INTF_DATA 0 57462306a36Sopenharmony_ci#define GIP_WIRED_INTF_AUDIO 1 57562306a36Sopenharmony_ci 57662306a36Sopenharmony_ci/* 57762306a36Sopenharmony_ci * This packet is required for all Xbox One pads with 2015 57862306a36Sopenharmony_ci * or later firmware installed (or present from the factory). 57962306a36Sopenharmony_ci */ 58062306a36Sopenharmony_cistatic const u8 xboxone_power_on[] = { 58162306a36Sopenharmony_ci GIP_CMD_POWER, GIP_OPT_INTERNAL, GIP_SEQ0, GIP_PL_LEN(1), GIP_PWR_ON 58262306a36Sopenharmony_ci}; 58362306a36Sopenharmony_ci 58462306a36Sopenharmony_ci/* 58562306a36Sopenharmony_ci * This packet is required for Xbox One S (0x045e:0x02ea) 58662306a36Sopenharmony_ci * and Xbox One Elite Series 2 (0x045e:0x0b00) pads to 58762306a36Sopenharmony_ci * initialize the controller that was previously used in 58862306a36Sopenharmony_ci * Bluetooth mode. 58962306a36Sopenharmony_ci */ 59062306a36Sopenharmony_cistatic const u8 xboxone_s_init[] = { 59162306a36Sopenharmony_ci GIP_CMD_POWER, GIP_OPT_INTERNAL, GIP_SEQ0, 0x0f, 0x06 59262306a36Sopenharmony_ci}; 59362306a36Sopenharmony_ci 59462306a36Sopenharmony_ci/* 59562306a36Sopenharmony_ci * This packet is required to get additional input data 59662306a36Sopenharmony_ci * from Xbox One Elite Series 2 (0x045e:0x0b00) pads. 59762306a36Sopenharmony_ci * We mostly do this right now to get paddle data 59862306a36Sopenharmony_ci */ 59962306a36Sopenharmony_cistatic const u8 extra_input_packet_init[] = { 60062306a36Sopenharmony_ci 0x4d, 0x10, 0x01, 0x02, 0x07, 0x00 60162306a36Sopenharmony_ci}; 60262306a36Sopenharmony_ci 60362306a36Sopenharmony_ci/* 60462306a36Sopenharmony_ci * This packet is required for the Titanfall 2 Xbox One pads 60562306a36Sopenharmony_ci * (0x0e6f:0x0165) to finish initialization and for Hori pads 60662306a36Sopenharmony_ci * (0x0f0d:0x0067) to make the analog sticks work. 60762306a36Sopenharmony_ci */ 60862306a36Sopenharmony_cistatic const u8 xboxone_hori_ack_id[] = { 60962306a36Sopenharmony_ci GIP_CMD_ACK, GIP_OPT_INTERNAL, GIP_SEQ0, GIP_PL_LEN(9), 61062306a36Sopenharmony_ci 0x00, GIP_CMD_IDENTIFY, GIP_OPT_INTERNAL, 0x3a, 0x00, 0x00, 0x00, 0x80, 0x00 61162306a36Sopenharmony_ci}; 61262306a36Sopenharmony_ci 61362306a36Sopenharmony_ci/* 61462306a36Sopenharmony_ci * This packet is required for most (all?) of the PDP pads to start 61562306a36Sopenharmony_ci * sending input reports. These pads include: (0x0e6f:0x02ab), 61662306a36Sopenharmony_ci * (0x0e6f:0x02a4), (0x0e6f:0x02a6). 61762306a36Sopenharmony_ci */ 61862306a36Sopenharmony_cistatic const u8 xboxone_pdp_led_on[] = { 61962306a36Sopenharmony_ci GIP_CMD_LED, GIP_OPT_INTERNAL, GIP_SEQ0, GIP_PL_LEN(3), 0x00, GIP_LED_ON, 0x14 62062306a36Sopenharmony_ci}; 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_ci/* 62362306a36Sopenharmony_ci * This packet is required for most (all?) of the PDP pads to start 62462306a36Sopenharmony_ci * sending input reports. These pads include: (0x0e6f:0x02ab), 62562306a36Sopenharmony_ci * (0x0e6f:0x02a4), (0x0e6f:0x02a6). 62662306a36Sopenharmony_ci */ 62762306a36Sopenharmony_cistatic const u8 xboxone_pdp_auth[] = { 62862306a36Sopenharmony_ci GIP_CMD_AUTHENTICATE, GIP_OPT_INTERNAL, GIP_SEQ0, GIP_PL_LEN(2), 0x01, 0x00 62962306a36Sopenharmony_ci}; 63062306a36Sopenharmony_ci 63162306a36Sopenharmony_ci/* 63262306a36Sopenharmony_ci * A specific rumble packet is required for some PowerA pads to start 63362306a36Sopenharmony_ci * sending input reports. One of those pads is (0x24c6:0x543a). 63462306a36Sopenharmony_ci */ 63562306a36Sopenharmony_cistatic const u8 xboxone_rumblebegin_init[] = { 63662306a36Sopenharmony_ci GIP_CMD_RUMBLE, 0x00, GIP_SEQ0, GIP_PL_LEN(9), 63762306a36Sopenharmony_ci 0x00, GIP_MOTOR_ALL, 0x00, 0x00, 0x1D, 0x1D, 0xFF, 0x00, 0x00 63862306a36Sopenharmony_ci}; 63962306a36Sopenharmony_ci 64062306a36Sopenharmony_ci/* 64162306a36Sopenharmony_ci * A rumble packet with zero FF intensity will immediately 64262306a36Sopenharmony_ci * terminate the rumbling required to init PowerA pads. 64362306a36Sopenharmony_ci * This should happen fast enough that the motors don't 64462306a36Sopenharmony_ci * spin up to enough speed to actually vibrate the gamepad. 64562306a36Sopenharmony_ci */ 64662306a36Sopenharmony_cistatic const u8 xboxone_rumbleend_init[] = { 64762306a36Sopenharmony_ci GIP_CMD_RUMBLE, 0x00, GIP_SEQ0, GIP_PL_LEN(9), 64862306a36Sopenharmony_ci 0x00, GIP_MOTOR_ALL, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 64962306a36Sopenharmony_ci}; 65062306a36Sopenharmony_ci 65162306a36Sopenharmony_ci/* 65262306a36Sopenharmony_ci * This specifies the selection of init packets that a gamepad 65362306a36Sopenharmony_ci * will be sent on init *and* the order in which they will be 65462306a36Sopenharmony_ci * sent. The correct sequence number will be added when the 65562306a36Sopenharmony_ci * packet is going to be sent. 65662306a36Sopenharmony_ci */ 65762306a36Sopenharmony_cistatic const struct xboxone_init_packet xboxone_init_packets[] = { 65862306a36Sopenharmony_ci XBOXONE_INIT_PKT(0x0e6f, 0x0165, xboxone_hori_ack_id), 65962306a36Sopenharmony_ci XBOXONE_INIT_PKT(0x0f0d, 0x0067, xboxone_hori_ack_id), 66062306a36Sopenharmony_ci XBOXONE_INIT_PKT(0x0000, 0x0000, xboxone_power_on), 66162306a36Sopenharmony_ci XBOXONE_INIT_PKT(0x045e, 0x02ea, xboxone_s_init), 66262306a36Sopenharmony_ci XBOXONE_INIT_PKT(0x045e, 0x0b00, xboxone_s_init), 66362306a36Sopenharmony_ci XBOXONE_INIT_PKT(0x045e, 0x0b00, extra_input_packet_init), 66462306a36Sopenharmony_ci XBOXONE_INIT_PKT(0x0e6f, 0x0000, xboxone_pdp_led_on), 66562306a36Sopenharmony_ci XBOXONE_INIT_PKT(0x0e6f, 0x0000, xboxone_pdp_auth), 66662306a36Sopenharmony_ci XBOXONE_INIT_PKT(0x24c6, 0x541a, xboxone_rumblebegin_init), 66762306a36Sopenharmony_ci XBOXONE_INIT_PKT(0x24c6, 0x542a, xboxone_rumblebegin_init), 66862306a36Sopenharmony_ci XBOXONE_INIT_PKT(0x24c6, 0x543a, xboxone_rumblebegin_init), 66962306a36Sopenharmony_ci XBOXONE_INIT_PKT(0x24c6, 0x541a, xboxone_rumbleend_init), 67062306a36Sopenharmony_ci XBOXONE_INIT_PKT(0x24c6, 0x542a, xboxone_rumbleend_init), 67162306a36Sopenharmony_ci XBOXONE_INIT_PKT(0x24c6, 0x543a, xboxone_rumbleend_init), 67262306a36Sopenharmony_ci}; 67362306a36Sopenharmony_ci 67462306a36Sopenharmony_cistruct xpad_output_packet { 67562306a36Sopenharmony_ci u8 data[XPAD_PKT_LEN]; 67662306a36Sopenharmony_ci u8 len; 67762306a36Sopenharmony_ci bool pending; 67862306a36Sopenharmony_ci}; 67962306a36Sopenharmony_ci 68062306a36Sopenharmony_ci#define XPAD_OUT_CMD_IDX 0 68162306a36Sopenharmony_ci#define XPAD_OUT_FF_IDX 1 68262306a36Sopenharmony_ci#define XPAD_OUT_LED_IDX (1 + IS_ENABLED(CONFIG_JOYSTICK_XPAD_FF)) 68362306a36Sopenharmony_ci#define XPAD_NUM_OUT_PACKETS (1 + \ 68462306a36Sopenharmony_ci IS_ENABLED(CONFIG_JOYSTICK_XPAD_FF) + \ 68562306a36Sopenharmony_ci IS_ENABLED(CONFIG_JOYSTICK_XPAD_LEDS)) 68662306a36Sopenharmony_ci 68762306a36Sopenharmony_cistruct usb_xpad { 68862306a36Sopenharmony_ci struct input_dev *dev; /* input device interface */ 68962306a36Sopenharmony_ci struct input_dev __rcu *x360w_dev; 69062306a36Sopenharmony_ci struct usb_device *udev; /* usb device */ 69162306a36Sopenharmony_ci struct usb_interface *intf; /* usb interface */ 69262306a36Sopenharmony_ci 69362306a36Sopenharmony_ci bool pad_present; 69462306a36Sopenharmony_ci bool input_created; 69562306a36Sopenharmony_ci 69662306a36Sopenharmony_ci struct urb *irq_in; /* urb for interrupt in report */ 69762306a36Sopenharmony_ci unsigned char *idata; /* input data */ 69862306a36Sopenharmony_ci dma_addr_t idata_dma; 69962306a36Sopenharmony_ci 70062306a36Sopenharmony_ci struct urb *irq_out; /* urb for interrupt out report */ 70162306a36Sopenharmony_ci struct usb_anchor irq_out_anchor; 70262306a36Sopenharmony_ci bool irq_out_active; /* we must not use an active URB */ 70362306a36Sopenharmony_ci u8 odata_serial; /* serial number for xbox one protocol */ 70462306a36Sopenharmony_ci unsigned char *odata; /* output data */ 70562306a36Sopenharmony_ci dma_addr_t odata_dma; 70662306a36Sopenharmony_ci spinlock_t odata_lock; 70762306a36Sopenharmony_ci 70862306a36Sopenharmony_ci struct xpad_output_packet out_packets[XPAD_NUM_OUT_PACKETS]; 70962306a36Sopenharmony_ci int last_out_packet; 71062306a36Sopenharmony_ci int init_seq; 71162306a36Sopenharmony_ci 71262306a36Sopenharmony_ci#if defined(CONFIG_JOYSTICK_XPAD_LEDS) 71362306a36Sopenharmony_ci struct xpad_led *led; 71462306a36Sopenharmony_ci#endif 71562306a36Sopenharmony_ci 71662306a36Sopenharmony_ci char phys[64]; /* physical device path */ 71762306a36Sopenharmony_ci 71862306a36Sopenharmony_ci int mapping; /* map d-pad to buttons or to axes */ 71962306a36Sopenharmony_ci int xtype; /* type of xbox device */ 72062306a36Sopenharmony_ci int packet_type; /* type of the extended packet */ 72162306a36Sopenharmony_ci int pad_nr; /* the order x360 pads were attached */ 72262306a36Sopenharmony_ci const char *name; /* name of the device */ 72362306a36Sopenharmony_ci struct work_struct work; /* init/remove device from callback */ 72462306a36Sopenharmony_ci time64_t mode_btn_down_ts; 72562306a36Sopenharmony_ci}; 72662306a36Sopenharmony_ci 72762306a36Sopenharmony_cistatic int xpad_init_input(struct usb_xpad *xpad); 72862306a36Sopenharmony_cistatic void xpad_deinit_input(struct usb_xpad *xpad); 72962306a36Sopenharmony_cistatic void xpadone_ack_mode_report(struct usb_xpad *xpad, u8 seq_num); 73062306a36Sopenharmony_cistatic void xpad360w_poweroff_controller(struct usb_xpad *xpad); 73162306a36Sopenharmony_ci 73262306a36Sopenharmony_ci/* 73362306a36Sopenharmony_ci * xpad_process_packet 73462306a36Sopenharmony_ci * 73562306a36Sopenharmony_ci * Completes a request by converting the data into events for the 73662306a36Sopenharmony_ci * input subsystem. 73762306a36Sopenharmony_ci * 73862306a36Sopenharmony_ci * The used report descriptor was taken from ITO Takayuki's website: 73962306a36Sopenharmony_ci * http://euc.jp/periphs/xbox-controller.ja.html 74062306a36Sopenharmony_ci */ 74162306a36Sopenharmony_cistatic void xpad_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char *data) 74262306a36Sopenharmony_ci{ 74362306a36Sopenharmony_ci struct input_dev *dev = xpad->dev; 74462306a36Sopenharmony_ci 74562306a36Sopenharmony_ci if (!(xpad->mapping & MAP_STICKS_TO_NULL)) { 74662306a36Sopenharmony_ci /* left stick */ 74762306a36Sopenharmony_ci input_report_abs(dev, ABS_X, 74862306a36Sopenharmony_ci (__s16) le16_to_cpup((__le16 *)(data + 12))); 74962306a36Sopenharmony_ci input_report_abs(dev, ABS_Y, 75062306a36Sopenharmony_ci ~(__s16) le16_to_cpup((__le16 *)(data + 14))); 75162306a36Sopenharmony_ci 75262306a36Sopenharmony_ci /* right stick */ 75362306a36Sopenharmony_ci input_report_abs(dev, ABS_RX, 75462306a36Sopenharmony_ci (__s16) le16_to_cpup((__le16 *)(data + 16))); 75562306a36Sopenharmony_ci input_report_abs(dev, ABS_RY, 75662306a36Sopenharmony_ci ~(__s16) le16_to_cpup((__le16 *)(data + 18))); 75762306a36Sopenharmony_ci } 75862306a36Sopenharmony_ci 75962306a36Sopenharmony_ci /* triggers left/right */ 76062306a36Sopenharmony_ci if (xpad->mapping & MAP_TRIGGERS_TO_BUTTONS) { 76162306a36Sopenharmony_ci input_report_key(dev, BTN_TL2, data[10]); 76262306a36Sopenharmony_ci input_report_key(dev, BTN_TR2, data[11]); 76362306a36Sopenharmony_ci } else { 76462306a36Sopenharmony_ci input_report_abs(dev, ABS_Z, data[10]); 76562306a36Sopenharmony_ci input_report_abs(dev, ABS_RZ, data[11]); 76662306a36Sopenharmony_ci } 76762306a36Sopenharmony_ci 76862306a36Sopenharmony_ci /* digital pad */ 76962306a36Sopenharmony_ci if (xpad->mapping & MAP_DPAD_TO_BUTTONS) { 77062306a36Sopenharmony_ci /* dpad as buttons (left, right, up, down) */ 77162306a36Sopenharmony_ci input_report_key(dev, BTN_TRIGGER_HAPPY1, data[2] & BIT(2)); 77262306a36Sopenharmony_ci input_report_key(dev, BTN_TRIGGER_HAPPY2, data[2] & BIT(3)); 77362306a36Sopenharmony_ci input_report_key(dev, BTN_TRIGGER_HAPPY3, data[2] & BIT(0)); 77462306a36Sopenharmony_ci input_report_key(dev, BTN_TRIGGER_HAPPY4, data[2] & BIT(1)); 77562306a36Sopenharmony_ci } else { 77662306a36Sopenharmony_ci input_report_abs(dev, ABS_HAT0X, 77762306a36Sopenharmony_ci !!(data[2] & 0x08) - !!(data[2] & 0x04)); 77862306a36Sopenharmony_ci input_report_abs(dev, ABS_HAT0Y, 77962306a36Sopenharmony_ci !!(data[2] & 0x02) - !!(data[2] & 0x01)); 78062306a36Sopenharmony_ci } 78162306a36Sopenharmony_ci 78262306a36Sopenharmony_ci /* start/back buttons and stick press left/right */ 78362306a36Sopenharmony_ci input_report_key(dev, BTN_START, data[2] & BIT(4)); 78462306a36Sopenharmony_ci input_report_key(dev, BTN_SELECT, data[2] & BIT(5)); 78562306a36Sopenharmony_ci input_report_key(dev, BTN_THUMBL, data[2] & BIT(6)); 78662306a36Sopenharmony_ci input_report_key(dev, BTN_THUMBR, data[2] & BIT(7)); 78762306a36Sopenharmony_ci 78862306a36Sopenharmony_ci /* "analog" buttons A, B, X, Y */ 78962306a36Sopenharmony_ci input_report_key(dev, BTN_A, data[4]); 79062306a36Sopenharmony_ci input_report_key(dev, BTN_B, data[5]); 79162306a36Sopenharmony_ci input_report_key(dev, BTN_X, data[6]); 79262306a36Sopenharmony_ci input_report_key(dev, BTN_Y, data[7]); 79362306a36Sopenharmony_ci 79462306a36Sopenharmony_ci /* "analog" buttons black, white */ 79562306a36Sopenharmony_ci input_report_key(dev, BTN_C, data[8]); 79662306a36Sopenharmony_ci input_report_key(dev, BTN_Z, data[9]); 79762306a36Sopenharmony_ci 79862306a36Sopenharmony_ci 79962306a36Sopenharmony_ci input_sync(dev); 80062306a36Sopenharmony_ci} 80162306a36Sopenharmony_ci 80262306a36Sopenharmony_ci/* 80362306a36Sopenharmony_ci * xpad360_process_packet 80462306a36Sopenharmony_ci * 80562306a36Sopenharmony_ci * Completes a request by converting the data into events for the 80662306a36Sopenharmony_ci * input subsystem. It is version for xbox 360 controller 80762306a36Sopenharmony_ci * 80862306a36Sopenharmony_ci * The used report descriptor was taken from: 80962306a36Sopenharmony_ci * http://www.free60.org/wiki/Gamepad 81062306a36Sopenharmony_ci */ 81162306a36Sopenharmony_ci 81262306a36Sopenharmony_cistatic void xpad360_process_packet(struct usb_xpad *xpad, struct input_dev *dev, 81362306a36Sopenharmony_ci u16 cmd, unsigned char *data) 81462306a36Sopenharmony_ci{ 81562306a36Sopenharmony_ci /* valid pad data */ 81662306a36Sopenharmony_ci if (data[0] != 0x00) 81762306a36Sopenharmony_ci return; 81862306a36Sopenharmony_ci 81962306a36Sopenharmony_ci /* digital pad */ 82062306a36Sopenharmony_ci if (xpad->mapping & MAP_DPAD_TO_BUTTONS) { 82162306a36Sopenharmony_ci /* dpad as buttons (left, right, up, down) */ 82262306a36Sopenharmony_ci input_report_key(dev, BTN_TRIGGER_HAPPY1, data[2] & BIT(2)); 82362306a36Sopenharmony_ci input_report_key(dev, BTN_TRIGGER_HAPPY2, data[2] & BIT(3)); 82462306a36Sopenharmony_ci input_report_key(dev, BTN_TRIGGER_HAPPY3, data[2] & BIT(0)); 82562306a36Sopenharmony_ci input_report_key(dev, BTN_TRIGGER_HAPPY4, data[2] & BIT(1)); 82662306a36Sopenharmony_ci } 82762306a36Sopenharmony_ci 82862306a36Sopenharmony_ci /* 82962306a36Sopenharmony_ci * This should be a simple else block. However historically 83062306a36Sopenharmony_ci * xbox360w has mapped DPAD to buttons while xbox360 did not. This 83162306a36Sopenharmony_ci * made no sense, but now we can not just switch back and have to 83262306a36Sopenharmony_ci * support both behaviors. 83362306a36Sopenharmony_ci */ 83462306a36Sopenharmony_ci if (!(xpad->mapping & MAP_DPAD_TO_BUTTONS) || 83562306a36Sopenharmony_ci xpad->xtype == XTYPE_XBOX360W) { 83662306a36Sopenharmony_ci input_report_abs(dev, ABS_HAT0X, 83762306a36Sopenharmony_ci !!(data[2] & 0x08) - !!(data[2] & 0x04)); 83862306a36Sopenharmony_ci input_report_abs(dev, ABS_HAT0Y, 83962306a36Sopenharmony_ci !!(data[2] & 0x02) - !!(data[2] & 0x01)); 84062306a36Sopenharmony_ci } 84162306a36Sopenharmony_ci 84262306a36Sopenharmony_ci /* start/back buttons */ 84362306a36Sopenharmony_ci input_report_key(dev, BTN_START, data[2] & BIT(4)); 84462306a36Sopenharmony_ci input_report_key(dev, BTN_SELECT, data[2] & BIT(5)); 84562306a36Sopenharmony_ci 84662306a36Sopenharmony_ci /* stick press left/right */ 84762306a36Sopenharmony_ci input_report_key(dev, BTN_THUMBL, data[2] & BIT(6)); 84862306a36Sopenharmony_ci input_report_key(dev, BTN_THUMBR, data[2] & BIT(7)); 84962306a36Sopenharmony_ci 85062306a36Sopenharmony_ci /* buttons A,B,X,Y,TL,TR and MODE */ 85162306a36Sopenharmony_ci input_report_key(dev, BTN_A, data[3] & BIT(4)); 85262306a36Sopenharmony_ci input_report_key(dev, BTN_B, data[3] & BIT(5)); 85362306a36Sopenharmony_ci input_report_key(dev, BTN_X, data[3] & BIT(6)); 85462306a36Sopenharmony_ci input_report_key(dev, BTN_Y, data[3] & BIT(7)); 85562306a36Sopenharmony_ci input_report_key(dev, BTN_TL, data[3] & BIT(0)); 85662306a36Sopenharmony_ci input_report_key(dev, BTN_TR, data[3] & BIT(1)); 85762306a36Sopenharmony_ci input_report_key(dev, BTN_MODE, data[3] & BIT(2)); 85862306a36Sopenharmony_ci 85962306a36Sopenharmony_ci if (!(xpad->mapping & MAP_STICKS_TO_NULL)) { 86062306a36Sopenharmony_ci /* left stick */ 86162306a36Sopenharmony_ci input_report_abs(dev, ABS_X, 86262306a36Sopenharmony_ci (__s16) le16_to_cpup((__le16 *)(data + 6))); 86362306a36Sopenharmony_ci input_report_abs(dev, ABS_Y, 86462306a36Sopenharmony_ci ~(__s16) le16_to_cpup((__le16 *)(data + 8))); 86562306a36Sopenharmony_ci 86662306a36Sopenharmony_ci /* right stick */ 86762306a36Sopenharmony_ci input_report_abs(dev, ABS_RX, 86862306a36Sopenharmony_ci (__s16) le16_to_cpup((__le16 *)(data + 10))); 86962306a36Sopenharmony_ci input_report_abs(dev, ABS_RY, 87062306a36Sopenharmony_ci ~(__s16) le16_to_cpup((__le16 *)(data + 12))); 87162306a36Sopenharmony_ci } 87262306a36Sopenharmony_ci 87362306a36Sopenharmony_ci /* triggers left/right */ 87462306a36Sopenharmony_ci if (xpad->mapping & MAP_TRIGGERS_TO_BUTTONS) { 87562306a36Sopenharmony_ci input_report_key(dev, BTN_TL2, data[4]); 87662306a36Sopenharmony_ci input_report_key(dev, BTN_TR2, data[5]); 87762306a36Sopenharmony_ci } else { 87862306a36Sopenharmony_ci input_report_abs(dev, ABS_Z, data[4]); 87962306a36Sopenharmony_ci input_report_abs(dev, ABS_RZ, data[5]); 88062306a36Sopenharmony_ci } 88162306a36Sopenharmony_ci 88262306a36Sopenharmony_ci input_sync(dev); 88362306a36Sopenharmony_ci 88462306a36Sopenharmony_ci /* XBOX360W controllers can't be turned off without driver assistance */ 88562306a36Sopenharmony_ci if (xpad->xtype == XTYPE_XBOX360W) { 88662306a36Sopenharmony_ci if (xpad->mode_btn_down_ts > 0 && xpad->pad_present && 88762306a36Sopenharmony_ci ((ktime_get_seconds() - xpad->mode_btn_down_ts) >= 88862306a36Sopenharmony_ci XPAD360W_POWEROFF_TIMEOUT)) { 88962306a36Sopenharmony_ci xpad360w_poweroff_controller(xpad); 89062306a36Sopenharmony_ci xpad->mode_btn_down_ts = 0; 89162306a36Sopenharmony_ci return; 89262306a36Sopenharmony_ci } 89362306a36Sopenharmony_ci 89462306a36Sopenharmony_ci /* mode button down/up */ 89562306a36Sopenharmony_ci if (data[3] & BIT(2)) 89662306a36Sopenharmony_ci xpad->mode_btn_down_ts = ktime_get_seconds(); 89762306a36Sopenharmony_ci else 89862306a36Sopenharmony_ci xpad->mode_btn_down_ts = 0; 89962306a36Sopenharmony_ci } 90062306a36Sopenharmony_ci} 90162306a36Sopenharmony_ci 90262306a36Sopenharmony_cistatic void xpad_presence_work(struct work_struct *work) 90362306a36Sopenharmony_ci{ 90462306a36Sopenharmony_ci struct usb_xpad *xpad = container_of(work, struct usb_xpad, work); 90562306a36Sopenharmony_ci int error; 90662306a36Sopenharmony_ci 90762306a36Sopenharmony_ci if (xpad->pad_present) { 90862306a36Sopenharmony_ci error = xpad_init_input(xpad); 90962306a36Sopenharmony_ci if (error) { 91062306a36Sopenharmony_ci /* complain only, not much else we can do here */ 91162306a36Sopenharmony_ci dev_err(&xpad->dev->dev, 91262306a36Sopenharmony_ci "unable to init device: %d\n", error); 91362306a36Sopenharmony_ci } else { 91462306a36Sopenharmony_ci rcu_assign_pointer(xpad->x360w_dev, xpad->dev); 91562306a36Sopenharmony_ci } 91662306a36Sopenharmony_ci } else { 91762306a36Sopenharmony_ci RCU_INIT_POINTER(xpad->x360w_dev, NULL); 91862306a36Sopenharmony_ci synchronize_rcu(); 91962306a36Sopenharmony_ci /* 92062306a36Sopenharmony_ci * Now that we are sure xpad360w_process_packet is not 92162306a36Sopenharmony_ci * using input device we can get rid of it. 92262306a36Sopenharmony_ci */ 92362306a36Sopenharmony_ci xpad_deinit_input(xpad); 92462306a36Sopenharmony_ci } 92562306a36Sopenharmony_ci} 92662306a36Sopenharmony_ci 92762306a36Sopenharmony_ci/* 92862306a36Sopenharmony_ci * xpad360w_process_packet 92962306a36Sopenharmony_ci * 93062306a36Sopenharmony_ci * Completes a request by converting the data into events for the 93162306a36Sopenharmony_ci * input subsystem. It is version for xbox 360 wireless controller. 93262306a36Sopenharmony_ci * 93362306a36Sopenharmony_ci * Byte.Bit 93462306a36Sopenharmony_ci * 00.1 - Status change: The controller or headset has connected/disconnected 93562306a36Sopenharmony_ci * Bits 01.7 and 01.6 are valid 93662306a36Sopenharmony_ci * 01.7 - Controller present 93762306a36Sopenharmony_ci * 01.6 - Headset present 93862306a36Sopenharmony_ci * 01.1 - Pad state (Bytes 4+) valid 93962306a36Sopenharmony_ci * 94062306a36Sopenharmony_ci */ 94162306a36Sopenharmony_cistatic void xpad360w_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char *data) 94262306a36Sopenharmony_ci{ 94362306a36Sopenharmony_ci struct input_dev *dev; 94462306a36Sopenharmony_ci bool present; 94562306a36Sopenharmony_ci 94662306a36Sopenharmony_ci /* Presence change */ 94762306a36Sopenharmony_ci if (data[0] & 0x08) { 94862306a36Sopenharmony_ci present = (data[1] & 0x80) != 0; 94962306a36Sopenharmony_ci 95062306a36Sopenharmony_ci if (xpad->pad_present != present) { 95162306a36Sopenharmony_ci xpad->pad_present = present; 95262306a36Sopenharmony_ci schedule_work(&xpad->work); 95362306a36Sopenharmony_ci } 95462306a36Sopenharmony_ci } 95562306a36Sopenharmony_ci 95662306a36Sopenharmony_ci /* Valid pad data */ 95762306a36Sopenharmony_ci if (data[1] != 0x1) 95862306a36Sopenharmony_ci return; 95962306a36Sopenharmony_ci 96062306a36Sopenharmony_ci rcu_read_lock(); 96162306a36Sopenharmony_ci dev = rcu_dereference(xpad->x360w_dev); 96262306a36Sopenharmony_ci if (dev) 96362306a36Sopenharmony_ci xpad360_process_packet(xpad, dev, cmd, &data[4]); 96462306a36Sopenharmony_ci rcu_read_unlock(); 96562306a36Sopenharmony_ci} 96662306a36Sopenharmony_ci 96762306a36Sopenharmony_ci/* 96862306a36Sopenharmony_ci * xpadone_process_packet 96962306a36Sopenharmony_ci * 97062306a36Sopenharmony_ci * Completes a request by converting the data into events for the 97162306a36Sopenharmony_ci * input subsystem. This version is for the Xbox One controller. 97262306a36Sopenharmony_ci * 97362306a36Sopenharmony_ci * The report format was gleaned from 97462306a36Sopenharmony_ci * https://github.com/kylelemons/xbox/blob/master/xbox.go 97562306a36Sopenharmony_ci */ 97662306a36Sopenharmony_cistatic void xpadone_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char *data) 97762306a36Sopenharmony_ci{ 97862306a36Sopenharmony_ci struct input_dev *dev = xpad->dev; 97962306a36Sopenharmony_ci bool do_sync = false; 98062306a36Sopenharmony_ci 98162306a36Sopenharmony_ci /* the xbox button has its own special report */ 98262306a36Sopenharmony_ci if (data[0] == GIP_CMD_VIRTUAL_KEY) { 98362306a36Sopenharmony_ci /* 98462306a36Sopenharmony_ci * The Xbox One S controller requires these reports to be 98562306a36Sopenharmony_ci * acked otherwise it continues sending them forever and 98662306a36Sopenharmony_ci * won't report further mode button events. 98762306a36Sopenharmony_ci */ 98862306a36Sopenharmony_ci if (data[1] == (GIP_OPT_ACK | GIP_OPT_INTERNAL)) 98962306a36Sopenharmony_ci xpadone_ack_mode_report(xpad, data[2]); 99062306a36Sopenharmony_ci 99162306a36Sopenharmony_ci input_report_key(dev, BTN_MODE, data[4] & GENMASK(1, 0)); 99262306a36Sopenharmony_ci input_sync(dev); 99362306a36Sopenharmony_ci 99462306a36Sopenharmony_ci do_sync = true; 99562306a36Sopenharmony_ci } else if (data[0] == GIP_CMD_FIRMWARE) { 99662306a36Sopenharmony_ci /* Some packet formats force us to use this separate to poll paddle inputs */ 99762306a36Sopenharmony_ci if (xpad->packet_type == PKT_XBE2_FW_5_11) { 99862306a36Sopenharmony_ci /* Mute paddles if controller is in a custom profile slot 99962306a36Sopenharmony_ci * Checked by looking at the active profile slot to 100062306a36Sopenharmony_ci * verify it's the default slot 100162306a36Sopenharmony_ci */ 100262306a36Sopenharmony_ci if (data[19] != 0) 100362306a36Sopenharmony_ci data[18] = 0; 100462306a36Sopenharmony_ci 100562306a36Sopenharmony_ci /* Elite Series 2 split packet paddle bits */ 100662306a36Sopenharmony_ci input_report_key(dev, BTN_TRIGGER_HAPPY5, data[18] & BIT(0)); 100762306a36Sopenharmony_ci input_report_key(dev, BTN_TRIGGER_HAPPY6, data[18] & BIT(1)); 100862306a36Sopenharmony_ci input_report_key(dev, BTN_TRIGGER_HAPPY7, data[18] & BIT(2)); 100962306a36Sopenharmony_ci input_report_key(dev, BTN_TRIGGER_HAPPY8, data[18] & BIT(3)); 101062306a36Sopenharmony_ci 101162306a36Sopenharmony_ci do_sync = true; 101262306a36Sopenharmony_ci } 101362306a36Sopenharmony_ci } else if (data[0] == GIP_CMD_INPUT) { /* The main valid packet type for inputs */ 101462306a36Sopenharmony_ci /* menu/view buttons */ 101562306a36Sopenharmony_ci input_report_key(dev, BTN_START, data[4] & BIT(2)); 101662306a36Sopenharmony_ci input_report_key(dev, BTN_SELECT, data[4] & BIT(3)); 101762306a36Sopenharmony_ci if (xpad->mapping & MAP_SELECT_BUTTON) 101862306a36Sopenharmony_ci input_report_key(dev, KEY_RECORD, data[22] & BIT(0)); 101962306a36Sopenharmony_ci 102062306a36Sopenharmony_ci /* buttons A,B,X,Y */ 102162306a36Sopenharmony_ci input_report_key(dev, BTN_A, data[4] & BIT(4)); 102262306a36Sopenharmony_ci input_report_key(dev, BTN_B, data[4] & BIT(5)); 102362306a36Sopenharmony_ci input_report_key(dev, BTN_X, data[4] & BIT(6)); 102462306a36Sopenharmony_ci input_report_key(dev, BTN_Y, data[4] & BIT(7)); 102562306a36Sopenharmony_ci 102662306a36Sopenharmony_ci /* digital pad */ 102762306a36Sopenharmony_ci if (xpad->mapping & MAP_DPAD_TO_BUTTONS) { 102862306a36Sopenharmony_ci /* dpad as buttons (left, right, up, down) */ 102962306a36Sopenharmony_ci input_report_key(dev, BTN_TRIGGER_HAPPY1, data[5] & BIT(2)); 103062306a36Sopenharmony_ci input_report_key(dev, BTN_TRIGGER_HAPPY2, data[5] & BIT(3)); 103162306a36Sopenharmony_ci input_report_key(dev, BTN_TRIGGER_HAPPY3, data[5] & BIT(0)); 103262306a36Sopenharmony_ci input_report_key(dev, BTN_TRIGGER_HAPPY4, data[5] & BIT(1)); 103362306a36Sopenharmony_ci } else { 103462306a36Sopenharmony_ci input_report_abs(dev, ABS_HAT0X, 103562306a36Sopenharmony_ci !!(data[5] & 0x08) - !!(data[5] & 0x04)); 103662306a36Sopenharmony_ci input_report_abs(dev, ABS_HAT0Y, 103762306a36Sopenharmony_ci !!(data[5] & 0x02) - !!(data[5] & 0x01)); 103862306a36Sopenharmony_ci } 103962306a36Sopenharmony_ci 104062306a36Sopenharmony_ci /* TL/TR */ 104162306a36Sopenharmony_ci input_report_key(dev, BTN_TL, data[5] & BIT(4)); 104262306a36Sopenharmony_ci input_report_key(dev, BTN_TR, data[5] & BIT(5)); 104362306a36Sopenharmony_ci 104462306a36Sopenharmony_ci /* stick press left/right */ 104562306a36Sopenharmony_ci input_report_key(dev, BTN_THUMBL, data[5] & BIT(6)); 104662306a36Sopenharmony_ci input_report_key(dev, BTN_THUMBR, data[5] & BIT(7)); 104762306a36Sopenharmony_ci 104862306a36Sopenharmony_ci if (!(xpad->mapping & MAP_STICKS_TO_NULL)) { 104962306a36Sopenharmony_ci /* left stick */ 105062306a36Sopenharmony_ci input_report_abs(dev, ABS_X, 105162306a36Sopenharmony_ci (__s16) le16_to_cpup((__le16 *)(data + 10))); 105262306a36Sopenharmony_ci input_report_abs(dev, ABS_Y, 105362306a36Sopenharmony_ci ~(__s16) le16_to_cpup((__le16 *)(data + 12))); 105462306a36Sopenharmony_ci 105562306a36Sopenharmony_ci /* right stick */ 105662306a36Sopenharmony_ci input_report_abs(dev, ABS_RX, 105762306a36Sopenharmony_ci (__s16) le16_to_cpup((__le16 *)(data + 14))); 105862306a36Sopenharmony_ci input_report_abs(dev, ABS_RY, 105962306a36Sopenharmony_ci ~(__s16) le16_to_cpup((__le16 *)(data + 16))); 106062306a36Sopenharmony_ci } 106162306a36Sopenharmony_ci 106262306a36Sopenharmony_ci /* triggers left/right */ 106362306a36Sopenharmony_ci if (xpad->mapping & MAP_TRIGGERS_TO_BUTTONS) { 106462306a36Sopenharmony_ci input_report_key(dev, BTN_TL2, 106562306a36Sopenharmony_ci (__u16) le16_to_cpup((__le16 *)(data + 6))); 106662306a36Sopenharmony_ci input_report_key(dev, BTN_TR2, 106762306a36Sopenharmony_ci (__u16) le16_to_cpup((__le16 *)(data + 8))); 106862306a36Sopenharmony_ci } else { 106962306a36Sopenharmony_ci input_report_abs(dev, ABS_Z, 107062306a36Sopenharmony_ci (__u16) le16_to_cpup((__le16 *)(data + 6))); 107162306a36Sopenharmony_ci input_report_abs(dev, ABS_RZ, 107262306a36Sopenharmony_ci (__u16) le16_to_cpup((__le16 *)(data + 8))); 107362306a36Sopenharmony_ci } 107462306a36Sopenharmony_ci 107562306a36Sopenharmony_ci /* Profile button has a value of 0-3, so it is reported as an axis */ 107662306a36Sopenharmony_ci if (xpad->mapping & MAP_PROFILE_BUTTON) 107762306a36Sopenharmony_ci input_report_abs(dev, ABS_PROFILE, data[34]); 107862306a36Sopenharmony_ci 107962306a36Sopenharmony_ci /* paddle handling */ 108062306a36Sopenharmony_ci /* based on SDL's SDL_hidapi_xboxone.c */ 108162306a36Sopenharmony_ci if (xpad->mapping & MAP_PADDLES) { 108262306a36Sopenharmony_ci if (xpad->packet_type == PKT_XBE1) { 108362306a36Sopenharmony_ci /* Mute paddles if controller has a custom mapping applied. 108462306a36Sopenharmony_ci * Checked by comparing the current mapping 108562306a36Sopenharmony_ci * config against the factory mapping config 108662306a36Sopenharmony_ci */ 108762306a36Sopenharmony_ci if (memcmp(&data[4], &data[18], 2) != 0) 108862306a36Sopenharmony_ci data[32] = 0; 108962306a36Sopenharmony_ci 109062306a36Sopenharmony_ci /* OG Elite Series Controller paddle bits */ 109162306a36Sopenharmony_ci input_report_key(dev, BTN_TRIGGER_HAPPY5, data[32] & BIT(1)); 109262306a36Sopenharmony_ci input_report_key(dev, BTN_TRIGGER_HAPPY6, data[32] & BIT(3)); 109362306a36Sopenharmony_ci input_report_key(dev, BTN_TRIGGER_HAPPY7, data[32] & BIT(0)); 109462306a36Sopenharmony_ci input_report_key(dev, BTN_TRIGGER_HAPPY8, data[32] & BIT(2)); 109562306a36Sopenharmony_ci } else if (xpad->packet_type == PKT_XBE2_FW_OLD) { 109662306a36Sopenharmony_ci /* Mute paddles if controller has a custom mapping applied. 109762306a36Sopenharmony_ci * Checked by comparing the current mapping 109862306a36Sopenharmony_ci * config against the factory mapping config 109962306a36Sopenharmony_ci */ 110062306a36Sopenharmony_ci if (data[19] != 0) 110162306a36Sopenharmony_ci data[18] = 0; 110262306a36Sopenharmony_ci 110362306a36Sopenharmony_ci /* Elite Series 2 4.x firmware paddle bits */ 110462306a36Sopenharmony_ci input_report_key(dev, BTN_TRIGGER_HAPPY5, data[18] & BIT(0)); 110562306a36Sopenharmony_ci input_report_key(dev, BTN_TRIGGER_HAPPY6, data[18] & BIT(1)); 110662306a36Sopenharmony_ci input_report_key(dev, BTN_TRIGGER_HAPPY7, data[18] & BIT(2)); 110762306a36Sopenharmony_ci input_report_key(dev, BTN_TRIGGER_HAPPY8, data[18] & BIT(3)); 110862306a36Sopenharmony_ci } else if (xpad->packet_type == PKT_XBE2_FW_5_EARLY) { 110962306a36Sopenharmony_ci /* Mute paddles if controller has a custom mapping applied. 111062306a36Sopenharmony_ci * Checked by comparing the current mapping 111162306a36Sopenharmony_ci * config against the factory mapping config 111262306a36Sopenharmony_ci */ 111362306a36Sopenharmony_ci if (data[23] != 0) 111462306a36Sopenharmony_ci data[22] = 0; 111562306a36Sopenharmony_ci 111662306a36Sopenharmony_ci /* Elite Series 2 5.x firmware paddle bits 111762306a36Sopenharmony_ci * (before the packet was split) 111862306a36Sopenharmony_ci */ 111962306a36Sopenharmony_ci input_report_key(dev, BTN_TRIGGER_HAPPY5, data[22] & BIT(0)); 112062306a36Sopenharmony_ci input_report_key(dev, BTN_TRIGGER_HAPPY6, data[22] & BIT(1)); 112162306a36Sopenharmony_ci input_report_key(dev, BTN_TRIGGER_HAPPY7, data[22] & BIT(2)); 112262306a36Sopenharmony_ci input_report_key(dev, BTN_TRIGGER_HAPPY8, data[22] & BIT(3)); 112362306a36Sopenharmony_ci } 112462306a36Sopenharmony_ci } 112562306a36Sopenharmony_ci 112662306a36Sopenharmony_ci do_sync = true; 112762306a36Sopenharmony_ci } 112862306a36Sopenharmony_ci 112962306a36Sopenharmony_ci if (do_sync) 113062306a36Sopenharmony_ci input_sync(dev); 113162306a36Sopenharmony_ci} 113262306a36Sopenharmony_ci 113362306a36Sopenharmony_cistatic void xpad_irq_in(struct urb *urb) 113462306a36Sopenharmony_ci{ 113562306a36Sopenharmony_ci struct usb_xpad *xpad = urb->context; 113662306a36Sopenharmony_ci struct device *dev = &xpad->intf->dev; 113762306a36Sopenharmony_ci int retval, status; 113862306a36Sopenharmony_ci 113962306a36Sopenharmony_ci status = urb->status; 114062306a36Sopenharmony_ci 114162306a36Sopenharmony_ci switch (status) { 114262306a36Sopenharmony_ci case 0: 114362306a36Sopenharmony_ci /* success */ 114462306a36Sopenharmony_ci break; 114562306a36Sopenharmony_ci case -ECONNRESET: 114662306a36Sopenharmony_ci case -ENOENT: 114762306a36Sopenharmony_ci case -ESHUTDOWN: 114862306a36Sopenharmony_ci /* this urb is terminated, clean up */ 114962306a36Sopenharmony_ci dev_dbg(dev, "%s - urb shutting down with status: %d\n", 115062306a36Sopenharmony_ci __func__, status); 115162306a36Sopenharmony_ci return; 115262306a36Sopenharmony_ci default: 115362306a36Sopenharmony_ci dev_dbg(dev, "%s - nonzero urb status received: %d\n", 115462306a36Sopenharmony_ci __func__, status); 115562306a36Sopenharmony_ci goto exit; 115662306a36Sopenharmony_ci } 115762306a36Sopenharmony_ci 115862306a36Sopenharmony_ci switch (xpad->xtype) { 115962306a36Sopenharmony_ci case XTYPE_XBOX360: 116062306a36Sopenharmony_ci xpad360_process_packet(xpad, xpad->dev, 0, xpad->idata); 116162306a36Sopenharmony_ci break; 116262306a36Sopenharmony_ci case XTYPE_XBOX360W: 116362306a36Sopenharmony_ci xpad360w_process_packet(xpad, 0, xpad->idata); 116462306a36Sopenharmony_ci break; 116562306a36Sopenharmony_ci case XTYPE_XBOXONE: 116662306a36Sopenharmony_ci xpadone_process_packet(xpad, 0, xpad->idata); 116762306a36Sopenharmony_ci break; 116862306a36Sopenharmony_ci default: 116962306a36Sopenharmony_ci xpad_process_packet(xpad, 0, xpad->idata); 117062306a36Sopenharmony_ci } 117162306a36Sopenharmony_ci 117262306a36Sopenharmony_ciexit: 117362306a36Sopenharmony_ci retval = usb_submit_urb(urb, GFP_ATOMIC); 117462306a36Sopenharmony_ci if (retval) 117562306a36Sopenharmony_ci dev_err(dev, "%s - usb_submit_urb failed with result %d\n", 117662306a36Sopenharmony_ci __func__, retval); 117762306a36Sopenharmony_ci} 117862306a36Sopenharmony_ci 117962306a36Sopenharmony_ci/* Callers must hold xpad->odata_lock spinlock */ 118062306a36Sopenharmony_cistatic bool xpad_prepare_next_init_packet(struct usb_xpad *xpad) 118162306a36Sopenharmony_ci{ 118262306a36Sopenharmony_ci const struct xboxone_init_packet *init_packet; 118362306a36Sopenharmony_ci 118462306a36Sopenharmony_ci if (xpad->xtype != XTYPE_XBOXONE) 118562306a36Sopenharmony_ci return false; 118662306a36Sopenharmony_ci 118762306a36Sopenharmony_ci /* Perform initialization sequence for Xbox One pads that require it */ 118862306a36Sopenharmony_ci while (xpad->init_seq < ARRAY_SIZE(xboxone_init_packets)) { 118962306a36Sopenharmony_ci init_packet = &xboxone_init_packets[xpad->init_seq++]; 119062306a36Sopenharmony_ci 119162306a36Sopenharmony_ci if (init_packet->idVendor != 0 && 119262306a36Sopenharmony_ci init_packet->idVendor != xpad->dev->id.vendor) 119362306a36Sopenharmony_ci continue; 119462306a36Sopenharmony_ci 119562306a36Sopenharmony_ci if (init_packet->idProduct != 0 && 119662306a36Sopenharmony_ci init_packet->idProduct != xpad->dev->id.product) 119762306a36Sopenharmony_ci continue; 119862306a36Sopenharmony_ci 119962306a36Sopenharmony_ci /* This packet applies to our device, so prepare to send it */ 120062306a36Sopenharmony_ci memcpy(xpad->odata, init_packet->data, init_packet->len); 120162306a36Sopenharmony_ci xpad->irq_out->transfer_buffer_length = init_packet->len; 120262306a36Sopenharmony_ci 120362306a36Sopenharmony_ci /* Update packet with current sequence number */ 120462306a36Sopenharmony_ci xpad->odata[2] = xpad->odata_serial++; 120562306a36Sopenharmony_ci return true; 120662306a36Sopenharmony_ci } 120762306a36Sopenharmony_ci 120862306a36Sopenharmony_ci return false; 120962306a36Sopenharmony_ci} 121062306a36Sopenharmony_ci 121162306a36Sopenharmony_ci/* Callers must hold xpad->odata_lock spinlock */ 121262306a36Sopenharmony_cistatic bool xpad_prepare_next_out_packet(struct usb_xpad *xpad) 121362306a36Sopenharmony_ci{ 121462306a36Sopenharmony_ci struct xpad_output_packet *pkt, *packet = NULL; 121562306a36Sopenharmony_ci int i; 121662306a36Sopenharmony_ci 121762306a36Sopenharmony_ci /* We may have init packets to send before we can send user commands */ 121862306a36Sopenharmony_ci if (xpad_prepare_next_init_packet(xpad)) 121962306a36Sopenharmony_ci return true; 122062306a36Sopenharmony_ci 122162306a36Sopenharmony_ci for (i = 0; i < XPAD_NUM_OUT_PACKETS; i++) { 122262306a36Sopenharmony_ci if (++xpad->last_out_packet >= XPAD_NUM_OUT_PACKETS) 122362306a36Sopenharmony_ci xpad->last_out_packet = 0; 122462306a36Sopenharmony_ci 122562306a36Sopenharmony_ci pkt = &xpad->out_packets[xpad->last_out_packet]; 122662306a36Sopenharmony_ci if (pkt->pending) { 122762306a36Sopenharmony_ci dev_dbg(&xpad->intf->dev, 122862306a36Sopenharmony_ci "%s - found pending output packet %d\n", 122962306a36Sopenharmony_ci __func__, xpad->last_out_packet); 123062306a36Sopenharmony_ci packet = pkt; 123162306a36Sopenharmony_ci break; 123262306a36Sopenharmony_ci } 123362306a36Sopenharmony_ci } 123462306a36Sopenharmony_ci 123562306a36Sopenharmony_ci if (packet) { 123662306a36Sopenharmony_ci memcpy(xpad->odata, packet->data, packet->len); 123762306a36Sopenharmony_ci xpad->irq_out->transfer_buffer_length = packet->len; 123862306a36Sopenharmony_ci packet->pending = false; 123962306a36Sopenharmony_ci return true; 124062306a36Sopenharmony_ci } 124162306a36Sopenharmony_ci 124262306a36Sopenharmony_ci return false; 124362306a36Sopenharmony_ci} 124462306a36Sopenharmony_ci 124562306a36Sopenharmony_ci/* Callers must hold xpad->odata_lock spinlock */ 124662306a36Sopenharmony_cistatic int xpad_try_sending_next_out_packet(struct usb_xpad *xpad) 124762306a36Sopenharmony_ci{ 124862306a36Sopenharmony_ci int error; 124962306a36Sopenharmony_ci 125062306a36Sopenharmony_ci if (!xpad->irq_out_active && xpad_prepare_next_out_packet(xpad)) { 125162306a36Sopenharmony_ci usb_anchor_urb(xpad->irq_out, &xpad->irq_out_anchor); 125262306a36Sopenharmony_ci error = usb_submit_urb(xpad->irq_out, GFP_ATOMIC); 125362306a36Sopenharmony_ci if (error) { 125462306a36Sopenharmony_ci dev_err(&xpad->intf->dev, 125562306a36Sopenharmony_ci "%s - usb_submit_urb failed with result %d\n", 125662306a36Sopenharmony_ci __func__, error); 125762306a36Sopenharmony_ci usb_unanchor_urb(xpad->irq_out); 125862306a36Sopenharmony_ci return -EIO; 125962306a36Sopenharmony_ci } 126062306a36Sopenharmony_ci 126162306a36Sopenharmony_ci xpad->irq_out_active = true; 126262306a36Sopenharmony_ci } 126362306a36Sopenharmony_ci 126462306a36Sopenharmony_ci return 0; 126562306a36Sopenharmony_ci} 126662306a36Sopenharmony_ci 126762306a36Sopenharmony_cistatic void xpad_irq_out(struct urb *urb) 126862306a36Sopenharmony_ci{ 126962306a36Sopenharmony_ci struct usb_xpad *xpad = urb->context; 127062306a36Sopenharmony_ci struct device *dev = &xpad->intf->dev; 127162306a36Sopenharmony_ci int status = urb->status; 127262306a36Sopenharmony_ci int error; 127362306a36Sopenharmony_ci unsigned long flags; 127462306a36Sopenharmony_ci 127562306a36Sopenharmony_ci spin_lock_irqsave(&xpad->odata_lock, flags); 127662306a36Sopenharmony_ci 127762306a36Sopenharmony_ci switch (status) { 127862306a36Sopenharmony_ci case 0: 127962306a36Sopenharmony_ci /* success */ 128062306a36Sopenharmony_ci xpad->irq_out_active = xpad_prepare_next_out_packet(xpad); 128162306a36Sopenharmony_ci break; 128262306a36Sopenharmony_ci 128362306a36Sopenharmony_ci case -ECONNRESET: 128462306a36Sopenharmony_ci case -ENOENT: 128562306a36Sopenharmony_ci case -ESHUTDOWN: 128662306a36Sopenharmony_ci /* this urb is terminated, clean up */ 128762306a36Sopenharmony_ci dev_dbg(dev, "%s - urb shutting down with status: %d\n", 128862306a36Sopenharmony_ci __func__, status); 128962306a36Sopenharmony_ci xpad->irq_out_active = false; 129062306a36Sopenharmony_ci break; 129162306a36Sopenharmony_ci 129262306a36Sopenharmony_ci default: 129362306a36Sopenharmony_ci dev_dbg(dev, "%s - nonzero urb status received: %d\n", 129462306a36Sopenharmony_ci __func__, status); 129562306a36Sopenharmony_ci break; 129662306a36Sopenharmony_ci } 129762306a36Sopenharmony_ci 129862306a36Sopenharmony_ci if (xpad->irq_out_active) { 129962306a36Sopenharmony_ci usb_anchor_urb(urb, &xpad->irq_out_anchor); 130062306a36Sopenharmony_ci error = usb_submit_urb(urb, GFP_ATOMIC); 130162306a36Sopenharmony_ci if (error) { 130262306a36Sopenharmony_ci dev_err(dev, 130362306a36Sopenharmony_ci "%s - usb_submit_urb failed with result %d\n", 130462306a36Sopenharmony_ci __func__, error); 130562306a36Sopenharmony_ci usb_unanchor_urb(urb); 130662306a36Sopenharmony_ci xpad->irq_out_active = false; 130762306a36Sopenharmony_ci } 130862306a36Sopenharmony_ci } 130962306a36Sopenharmony_ci 131062306a36Sopenharmony_ci spin_unlock_irqrestore(&xpad->odata_lock, flags); 131162306a36Sopenharmony_ci} 131262306a36Sopenharmony_ci 131362306a36Sopenharmony_cistatic int xpad_init_output(struct usb_interface *intf, struct usb_xpad *xpad, 131462306a36Sopenharmony_ci struct usb_endpoint_descriptor *ep_irq_out) 131562306a36Sopenharmony_ci{ 131662306a36Sopenharmony_ci int error; 131762306a36Sopenharmony_ci 131862306a36Sopenharmony_ci if (xpad->xtype == XTYPE_UNKNOWN) 131962306a36Sopenharmony_ci return 0; 132062306a36Sopenharmony_ci 132162306a36Sopenharmony_ci init_usb_anchor(&xpad->irq_out_anchor); 132262306a36Sopenharmony_ci 132362306a36Sopenharmony_ci xpad->odata = usb_alloc_coherent(xpad->udev, XPAD_PKT_LEN, 132462306a36Sopenharmony_ci GFP_KERNEL, &xpad->odata_dma); 132562306a36Sopenharmony_ci if (!xpad->odata) 132662306a36Sopenharmony_ci return -ENOMEM; 132762306a36Sopenharmony_ci 132862306a36Sopenharmony_ci spin_lock_init(&xpad->odata_lock); 132962306a36Sopenharmony_ci 133062306a36Sopenharmony_ci xpad->irq_out = usb_alloc_urb(0, GFP_KERNEL); 133162306a36Sopenharmony_ci if (!xpad->irq_out) { 133262306a36Sopenharmony_ci error = -ENOMEM; 133362306a36Sopenharmony_ci goto err_free_coherent; 133462306a36Sopenharmony_ci } 133562306a36Sopenharmony_ci 133662306a36Sopenharmony_ci usb_fill_int_urb(xpad->irq_out, xpad->udev, 133762306a36Sopenharmony_ci usb_sndintpipe(xpad->udev, ep_irq_out->bEndpointAddress), 133862306a36Sopenharmony_ci xpad->odata, XPAD_PKT_LEN, 133962306a36Sopenharmony_ci xpad_irq_out, xpad, ep_irq_out->bInterval); 134062306a36Sopenharmony_ci xpad->irq_out->transfer_dma = xpad->odata_dma; 134162306a36Sopenharmony_ci xpad->irq_out->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; 134262306a36Sopenharmony_ci 134362306a36Sopenharmony_ci return 0; 134462306a36Sopenharmony_ci 134562306a36Sopenharmony_cierr_free_coherent: 134662306a36Sopenharmony_ci usb_free_coherent(xpad->udev, XPAD_PKT_LEN, xpad->odata, xpad->odata_dma); 134762306a36Sopenharmony_ci return error; 134862306a36Sopenharmony_ci} 134962306a36Sopenharmony_ci 135062306a36Sopenharmony_cistatic void xpad_stop_output(struct usb_xpad *xpad) 135162306a36Sopenharmony_ci{ 135262306a36Sopenharmony_ci if (xpad->xtype != XTYPE_UNKNOWN) { 135362306a36Sopenharmony_ci if (!usb_wait_anchor_empty_timeout(&xpad->irq_out_anchor, 135462306a36Sopenharmony_ci 5000)) { 135562306a36Sopenharmony_ci dev_warn(&xpad->intf->dev, 135662306a36Sopenharmony_ci "timed out waiting for output URB to complete, killing\n"); 135762306a36Sopenharmony_ci usb_kill_anchored_urbs(&xpad->irq_out_anchor); 135862306a36Sopenharmony_ci } 135962306a36Sopenharmony_ci } 136062306a36Sopenharmony_ci} 136162306a36Sopenharmony_ci 136262306a36Sopenharmony_cistatic void xpad_deinit_output(struct usb_xpad *xpad) 136362306a36Sopenharmony_ci{ 136462306a36Sopenharmony_ci if (xpad->xtype != XTYPE_UNKNOWN) { 136562306a36Sopenharmony_ci usb_free_urb(xpad->irq_out); 136662306a36Sopenharmony_ci usb_free_coherent(xpad->udev, XPAD_PKT_LEN, 136762306a36Sopenharmony_ci xpad->odata, xpad->odata_dma); 136862306a36Sopenharmony_ci } 136962306a36Sopenharmony_ci} 137062306a36Sopenharmony_ci 137162306a36Sopenharmony_cistatic int xpad_inquiry_pad_presence(struct usb_xpad *xpad) 137262306a36Sopenharmony_ci{ 137362306a36Sopenharmony_ci struct xpad_output_packet *packet = 137462306a36Sopenharmony_ci &xpad->out_packets[XPAD_OUT_CMD_IDX]; 137562306a36Sopenharmony_ci unsigned long flags; 137662306a36Sopenharmony_ci int retval; 137762306a36Sopenharmony_ci 137862306a36Sopenharmony_ci spin_lock_irqsave(&xpad->odata_lock, flags); 137962306a36Sopenharmony_ci 138062306a36Sopenharmony_ci packet->data[0] = 0x08; 138162306a36Sopenharmony_ci packet->data[1] = 0x00; 138262306a36Sopenharmony_ci packet->data[2] = 0x0F; 138362306a36Sopenharmony_ci packet->data[3] = 0xC0; 138462306a36Sopenharmony_ci packet->data[4] = 0x00; 138562306a36Sopenharmony_ci packet->data[5] = 0x00; 138662306a36Sopenharmony_ci packet->data[6] = 0x00; 138762306a36Sopenharmony_ci packet->data[7] = 0x00; 138862306a36Sopenharmony_ci packet->data[8] = 0x00; 138962306a36Sopenharmony_ci packet->data[9] = 0x00; 139062306a36Sopenharmony_ci packet->data[10] = 0x00; 139162306a36Sopenharmony_ci packet->data[11] = 0x00; 139262306a36Sopenharmony_ci packet->len = 12; 139362306a36Sopenharmony_ci packet->pending = true; 139462306a36Sopenharmony_ci 139562306a36Sopenharmony_ci /* Reset the sequence so we send out presence first */ 139662306a36Sopenharmony_ci xpad->last_out_packet = -1; 139762306a36Sopenharmony_ci retval = xpad_try_sending_next_out_packet(xpad); 139862306a36Sopenharmony_ci 139962306a36Sopenharmony_ci spin_unlock_irqrestore(&xpad->odata_lock, flags); 140062306a36Sopenharmony_ci 140162306a36Sopenharmony_ci return retval; 140262306a36Sopenharmony_ci} 140362306a36Sopenharmony_ci 140462306a36Sopenharmony_cistatic int xpad_start_xbox_one(struct usb_xpad *xpad) 140562306a36Sopenharmony_ci{ 140662306a36Sopenharmony_ci unsigned long flags; 140762306a36Sopenharmony_ci int retval; 140862306a36Sopenharmony_ci 140962306a36Sopenharmony_ci if (usb_ifnum_to_if(xpad->udev, GIP_WIRED_INTF_AUDIO)) { 141062306a36Sopenharmony_ci /* 141162306a36Sopenharmony_ci * Explicitly disable the audio interface. This is needed 141262306a36Sopenharmony_ci * for some controllers, such as the PowerA Enhanced Wired 141362306a36Sopenharmony_ci * Controller for Series X|S (0x20d6:0x200e) to report the 141462306a36Sopenharmony_ci * guide button. 141562306a36Sopenharmony_ci */ 141662306a36Sopenharmony_ci retval = usb_set_interface(xpad->udev, 141762306a36Sopenharmony_ci GIP_WIRED_INTF_AUDIO, 0); 141862306a36Sopenharmony_ci if (retval) 141962306a36Sopenharmony_ci dev_warn(&xpad->dev->dev, 142062306a36Sopenharmony_ci "unable to disable audio interface: %d\n", 142162306a36Sopenharmony_ci retval); 142262306a36Sopenharmony_ci } 142362306a36Sopenharmony_ci 142462306a36Sopenharmony_ci spin_lock_irqsave(&xpad->odata_lock, flags); 142562306a36Sopenharmony_ci 142662306a36Sopenharmony_ci /* 142762306a36Sopenharmony_ci * Begin the init sequence by attempting to send a packet. 142862306a36Sopenharmony_ci * We will cycle through the init packet sequence before 142962306a36Sopenharmony_ci * sending any packets from the output ring. 143062306a36Sopenharmony_ci */ 143162306a36Sopenharmony_ci xpad->init_seq = 0; 143262306a36Sopenharmony_ci retval = xpad_try_sending_next_out_packet(xpad); 143362306a36Sopenharmony_ci 143462306a36Sopenharmony_ci spin_unlock_irqrestore(&xpad->odata_lock, flags); 143562306a36Sopenharmony_ci 143662306a36Sopenharmony_ci return retval; 143762306a36Sopenharmony_ci} 143862306a36Sopenharmony_ci 143962306a36Sopenharmony_cistatic void xpadone_ack_mode_report(struct usb_xpad *xpad, u8 seq_num) 144062306a36Sopenharmony_ci{ 144162306a36Sopenharmony_ci unsigned long flags; 144262306a36Sopenharmony_ci struct xpad_output_packet *packet = 144362306a36Sopenharmony_ci &xpad->out_packets[XPAD_OUT_CMD_IDX]; 144462306a36Sopenharmony_ci static const u8 mode_report_ack[] = { 144562306a36Sopenharmony_ci GIP_CMD_ACK, GIP_OPT_INTERNAL, GIP_SEQ0, GIP_PL_LEN(9), 144662306a36Sopenharmony_ci 0x00, GIP_CMD_VIRTUAL_KEY, GIP_OPT_INTERNAL, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00 144762306a36Sopenharmony_ci }; 144862306a36Sopenharmony_ci 144962306a36Sopenharmony_ci spin_lock_irqsave(&xpad->odata_lock, flags); 145062306a36Sopenharmony_ci 145162306a36Sopenharmony_ci packet->len = sizeof(mode_report_ack); 145262306a36Sopenharmony_ci memcpy(packet->data, mode_report_ack, packet->len); 145362306a36Sopenharmony_ci packet->data[2] = seq_num; 145462306a36Sopenharmony_ci packet->pending = true; 145562306a36Sopenharmony_ci 145662306a36Sopenharmony_ci /* Reset the sequence so we send out the ack now */ 145762306a36Sopenharmony_ci xpad->last_out_packet = -1; 145862306a36Sopenharmony_ci xpad_try_sending_next_out_packet(xpad); 145962306a36Sopenharmony_ci 146062306a36Sopenharmony_ci spin_unlock_irqrestore(&xpad->odata_lock, flags); 146162306a36Sopenharmony_ci} 146262306a36Sopenharmony_ci 146362306a36Sopenharmony_ci#ifdef CONFIG_JOYSTICK_XPAD_FF 146462306a36Sopenharmony_cistatic int xpad_play_effect(struct input_dev *dev, void *data, struct ff_effect *effect) 146562306a36Sopenharmony_ci{ 146662306a36Sopenharmony_ci struct usb_xpad *xpad = input_get_drvdata(dev); 146762306a36Sopenharmony_ci struct xpad_output_packet *packet = &xpad->out_packets[XPAD_OUT_FF_IDX]; 146862306a36Sopenharmony_ci __u16 strong; 146962306a36Sopenharmony_ci __u16 weak; 147062306a36Sopenharmony_ci int retval; 147162306a36Sopenharmony_ci unsigned long flags; 147262306a36Sopenharmony_ci 147362306a36Sopenharmony_ci if (effect->type != FF_RUMBLE) 147462306a36Sopenharmony_ci return 0; 147562306a36Sopenharmony_ci 147662306a36Sopenharmony_ci strong = effect->u.rumble.strong_magnitude; 147762306a36Sopenharmony_ci weak = effect->u.rumble.weak_magnitude; 147862306a36Sopenharmony_ci 147962306a36Sopenharmony_ci spin_lock_irqsave(&xpad->odata_lock, flags); 148062306a36Sopenharmony_ci 148162306a36Sopenharmony_ci switch (xpad->xtype) { 148262306a36Sopenharmony_ci case XTYPE_XBOX: 148362306a36Sopenharmony_ci packet->data[0] = 0x00; 148462306a36Sopenharmony_ci packet->data[1] = 0x06; 148562306a36Sopenharmony_ci packet->data[2] = 0x00; 148662306a36Sopenharmony_ci packet->data[3] = strong / 256; /* left actuator */ 148762306a36Sopenharmony_ci packet->data[4] = 0x00; 148862306a36Sopenharmony_ci packet->data[5] = weak / 256; /* right actuator */ 148962306a36Sopenharmony_ci packet->len = 6; 149062306a36Sopenharmony_ci packet->pending = true; 149162306a36Sopenharmony_ci break; 149262306a36Sopenharmony_ci 149362306a36Sopenharmony_ci case XTYPE_XBOX360: 149462306a36Sopenharmony_ci packet->data[0] = 0x00; 149562306a36Sopenharmony_ci packet->data[1] = 0x08; 149662306a36Sopenharmony_ci packet->data[2] = 0x00; 149762306a36Sopenharmony_ci packet->data[3] = strong / 256; /* left actuator? */ 149862306a36Sopenharmony_ci packet->data[4] = weak / 256; /* right actuator? */ 149962306a36Sopenharmony_ci packet->data[5] = 0x00; 150062306a36Sopenharmony_ci packet->data[6] = 0x00; 150162306a36Sopenharmony_ci packet->data[7] = 0x00; 150262306a36Sopenharmony_ci packet->len = 8; 150362306a36Sopenharmony_ci packet->pending = true; 150462306a36Sopenharmony_ci break; 150562306a36Sopenharmony_ci 150662306a36Sopenharmony_ci case XTYPE_XBOX360W: 150762306a36Sopenharmony_ci packet->data[0] = 0x00; 150862306a36Sopenharmony_ci packet->data[1] = 0x01; 150962306a36Sopenharmony_ci packet->data[2] = 0x0F; 151062306a36Sopenharmony_ci packet->data[3] = 0xC0; 151162306a36Sopenharmony_ci packet->data[4] = 0x00; 151262306a36Sopenharmony_ci packet->data[5] = strong / 256; 151362306a36Sopenharmony_ci packet->data[6] = weak / 256; 151462306a36Sopenharmony_ci packet->data[7] = 0x00; 151562306a36Sopenharmony_ci packet->data[8] = 0x00; 151662306a36Sopenharmony_ci packet->data[9] = 0x00; 151762306a36Sopenharmony_ci packet->data[10] = 0x00; 151862306a36Sopenharmony_ci packet->data[11] = 0x00; 151962306a36Sopenharmony_ci packet->len = 12; 152062306a36Sopenharmony_ci packet->pending = true; 152162306a36Sopenharmony_ci break; 152262306a36Sopenharmony_ci 152362306a36Sopenharmony_ci case XTYPE_XBOXONE: 152462306a36Sopenharmony_ci packet->data[0] = GIP_CMD_RUMBLE; /* activate rumble */ 152562306a36Sopenharmony_ci packet->data[1] = 0x00; 152662306a36Sopenharmony_ci packet->data[2] = xpad->odata_serial++; 152762306a36Sopenharmony_ci packet->data[3] = GIP_PL_LEN(9); 152862306a36Sopenharmony_ci packet->data[4] = 0x00; 152962306a36Sopenharmony_ci packet->data[5] = GIP_MOTOR_ALL; 153062306a36Sopenharmony_ci packet->data[6] = 0x00; /* left trigger */ 153162306a36Sopenharmony_ci packet->data[7] = 0x00; /* right trigger */ 153262306a36Sopenharmony_ci packet->data[8] = strong / 512; /* left actuator */ 153362306a36Sopenharmony_ci packet->data[9] = weak / 512; /* right actuator */ 153462306a36Sopenharmony_ci packet->data[10] = 0xFF; /* on period */ 153562306a36Sopenharmony_ci packet->data[11] = 0x00; /* off period */ 153662306a36Sopenharmony_ci packet->data[12] = 0xFF; /* repeat count */ 153762306a36Sopenharmony_ci packet->len = 13; 153862306a36Sopenharmony_ci packet->pending = true; 153962306a36Sopenharmony_ci break; 154062306a36Sopenharmony_ci 154162306a36Sopenharmony_ci default: 154262306a36Sopenharmony_ci dev_dbg(&xpad->dev->dev, 154362306a36Sopenharmony_ci "%s - rumble command sent to unsupported xpad type: %d\n", 154462306a36Sopenharmony_ci __func__, xpad->xtype); 154562306a36Sopenharmony_ci retval = -EINVAL; 154662306a36Sopenharmony_ci goto out; 154762306a36Sopenharmony_ci } 154862306a36Sopenharmony_ci 154962306a36Sopenharmony_ci retval = xpad_try_sending_next_out_packet(xpad); 155062306a36Sopenharmony_ci 155162306a36Sopenharmony_ciout: 155262306a36Sopenharmony_ci spin_unlock_irqrestore(&xpad->odata_lock, flags); 155362306a36Sopenharmony_ci return retval; 155462306a36Sopenharmony_ci} 155562306a36Sopenharmony_ci 155662306a36Sopenharmony_cistatic int xpad_init_ff(struct usb_xpad *xpad) 155762306a36Sopenharmony_ci{ 155862306a36Sopenharmony_ci if (xpad->xtype == XTYPE_UNKNOWN) 155962306a36Sopenharmony_ci return 0; 156062306a36Sopenharmony_ci 156162306a36Sopenharmony_ci input_set_capability(xpad->dev, EV_FF, FF_RUMBLE); 156262306a36Sopenharmony_ci 156362306a36Sopenharmony_ci return input_ff_create_memless(xpad->dev, NULL, xpad_play_effect); 156462306a36Sopenharmony_ci} 156562306a36Sopenharmony_ci 156662306a36Sopenharmony_ci#else 156762306a36Sopenharmony_cistatic int xpad_init_ff(struct usb_xpad *xpad) { return 0; } 156862306a36Sopenharmony_ci#endif 156962306a36Sopenharmony_ci 157062306a36Sopenharmony_ci#if defined(CONFIG_JOYSTICK_XPAD_LEDS) 157162306a36Sopenharmony_ci#include <linux/leds.h> 157262306a36Sopenharmony_ci#include <linux/idr.h> 157362306a36Sopenharmony_ci 157462306a36Sopenharmony_cistatic DEFINE_IDA(xpad_pad_seq); 157562306a36Sopenharmony_ci 157662306a36Sopenharmony_cistruct xpad_led { 157762306a36Sopenharmony_ci char name[16]; 157862306a36Sopenharmony_ci struct led_classdev led_cdev; 157962306a36Sopenharmony_ci struct usb_xpad *xpad; 158062306a36Sopenharmony_ci}; 158162306a36Sopenharmony_ci 158262306a36Sopenharmony_ci/* 158362306a36Sopenharmony_ci * set the LEDs on Xbox 360 / Wireless Controllers 158462306a36Sopenharmony_ci * @param command 158562306a36Sopenharmony_ci * 0: off 158662306a36Sopenharmony_ci * 1: all blink, then previous setting 158762306a36Sopenharmony_ci * 2: 1/top-left blink, then on 158862306a36Sopenharmony_ci * 3: 2/top-right blink, then on 158962306a36Sopenharmony_ci * 4: 3/bottom-left blink, then on 159062306a36Sopenharmony_ci * 5: 4/bottom-right blink, then on 159162306a36Sopenharmony_ci * 6: 1/top-left on 159262306a36Sopenharmony_ci * 7: 2/top-right on 159362306a36Sopenharmony_ci * 8: 3/bottom-left on 159462306a36Sopenharmony_ci * 9: 4/bottom-right on 159562306a36Sopenharmony_ci * 10: rotate 159662306a36Sopenharmony_ci * 11: blink, based on previous setting 159762306a36Sopenharmony_ci * 12: slow blink, based on previous setting 159862306a36Sopenharmony_ci * 13: rotate with two lights 159962306a36Sopenharmony_ci * 14: persistent slow all blink 160062306a36Sopenharmony_ci * 15: blink once, then previous setting 160162306a36Sopenharmony_ci */ 160262306a36Sopenharmony_cistatic void xpad_send_led_command(struct usb_xpad *xpad, int command) 160362306a36Sopenharmony_ci{ 160462306a36Sopenharmony_ci struct xpad_output_packet *packet = 160562306a36Sopenharmony_ci &xpad->out_packets[XPAD_OUT_LED_IDX]; 160662306a36Sopenharmony_ci unsigned long flags; 160762306a36Sopenharmony_ci 160862306a36Sopenharmony_ci command %= 16; 160962306a36Sopenharmony_ci 161062306a36Sopenharmony_ci spin_lock_irqsave(&xpad->odata_lock, flags); 161162306a36Sopenharmony_ci 161262306a36Sopenharmony_ci switch (xpad->xtype) { 161362306a36Sopenharmony_ci case XTYPE_XBOX360: 161462306a36Sopenharmony_ci packet->data[0] = 0x01; 161562306a36Sopenharmony_ci packet->data[1] = 0x03; 161662306a36Sopenharmony_ci packet->data[2] = command; 161762306a36Sopenharmony_ci packet->len = 3; 161862306a36Sopenharmony_ci packet->pending = true; 161962306a36Sopenharmony_ci break; 162062306a36Sopenharmony_ci 162162306a36Sopenharmony_ci case XTYPE_XBOX360W: 162262306a36Sopenharmony_ci packet->data[0] = 0x00; 162362306a36Sopenharmony_ci packet->data[1] = 0x00; 162462306a36Sopenharmony_ci packet->data[2] = 0x08; 162562306a36Sopenharmony_ci packet->data[3] = 0x40 + command; 162662306a36Sopenharmony_ci packet->data[4] = 0x00; 162762306a36Sopenharmony_ci packet->data[5] = 0x00; 162862306a36Sopenharmony_ci packet->data[6] = 0x00; 162962306a36Sopenharmony_ci packet->data[7] = 0x00; 163062306a36Sopenharmony_ci packet->data[8] = 0x00; 163162306a36Sopenharmony_ci packet->data[9] = 0x00; 163262306a36Sopenharmony_ci packet->data[10] = 0x00; 163362306a36Sopenharmony_ci packet->data[11] = 0x00; 163462306a36Sopenharmony_ci packet->len = 12; 163562306a36Sopenharmony_ci packet->pending = true; 163662306a36Sopenharmony_ci break; 163762306a36Sopenharmony_ci } 163862306a36Sopenharmony_ci 163962306a36Sopenharmony_ci xpad_try_sending_next_out_packet(xpad); 164062306a36Sopenharmony_ci 164162306a36Sopenharmony_ci spin_unlock_irqrestore(&xpad->odata_lock, flags); 164262306a36Sopenharmony_ci} 164362306a36Sopenharmony_ci 164462306a36Sopenharmony_ci/* 164562306a36Sopenharmony_ci * Light up the segment corresponding to the pad number on 164662306a36Sopenharmony_ci * Xbox 360 Controllers. 164762306a36Sopenharmony_ci */ 164862306a36Sopenharmony_cistatic void xpad_identify_controller(struct usb_xpad *xpad) 164962306a36Sopenharmony_ci{ 165062306a36Sopenharmony_ci led_set_brightness(&xpad->led->led_cdev, (xpad->pad_nr % 4) + 2); 165162306a36Sopenharmony_ci} 165262306a36Sopenharmony_ci 165362306a36Sopenharmony_cistatic void xpad_led_set(struct led_classdev *led_cdev, 165462306a36Sopenharmony_ci enum led_brightness value) 165562306a36Sopenharmony_ci{ 165662306a36Sopenharmony_ci struct xpad_led *xpad_led = container_of(led_cdev, 165762306a36Sopenharmony_ci struct xpad_led, led_cdev); 165862306a36Sopenharmony_ci 165962306a36Sopenharmony_ci xpad_send_led_command(xpad_led->xpad, value); 166062306a36Sopenharmony_ci} 166162306a36Sopenharmony_ci 166262306a36Sopenharmony_cistatic int xpad_led_probe(struct usb_xpad *xpad) 166362306a36Sopenharmony_ci{ 166462306a36Sopenharmony_ci struct xpad_led *led; 166562306a36Sopenharmony_ci struct led_classdev *led_cdev; 166662306a36Sopenharmony_ci int error; 166762306a36Sopenharmony_ci 166862306a36Sopenharmony_ci if (xpad->xtype != XTYPE_XBOX360 && xpad->xtype != XTYPE_XBOX360W) 166962306a36Sopenharmony_ci return 0; 167062306a36Sopenharmony_ci 167162306a36Sopenharmony_ci xpad->led = led = kzalloc(sizeof(struct xpad_led), GFP_KERNEL); 167262306a36Sopenharmony_ci if (!led) 167362306a36Sopenharmony_ci return -ENOMEM; 167462306a36Sopenharmony_ci 167562306a36Sopenharmony_ci xpad->pad_nr = ida_simple_get(&xpad_pad_seq, 0, 0, GFP_KERNEL); 167662306a36Sopenharmony_ci if (xpad->pad_nr < 0) { 167762306a36Sopenharmony_ci error = xpad->pad_nr; 167862306a36Sopenharmony_ci goto err_free_mem; 167962306a36Sopenharmony_ci } 168062306a36Sopenharmony_ci 168162306a36Sopenharmony_ci snprintf(led->name, sizeof(led->name), "xpad%d", xpad->pad_nr); 168262306a36Sopenharmony_ci led->xpad = xpad; 168362306a36Sopenharmony_ci 168462306a36Sopenharmony_ci led_cdev = &led->led_cdev; 168562306a36Sopenharmony_ci led_cdev->name = led->name; 168662306a36Sopenharmony_ci led_cdev->brightness_set = xpad_led_set; 168762306a36Sopenharmony_ci led_cdev->flags = LED_CORE_SUSPENDRESUME; 168862306a36Sopenharmony_ci 168962306a36Sopenharmony_ci error = led_classdev_register(&xpad->udev->dev, led_cdev); 169062306a36Sopenharmony_ci if (error) 169162306a36Sopenharmony_ci goto err_free_id; 169262306a36Sopenharmony_ci 169362306a36Sopenharmony_ci xpad_identify_controller(xpad); 169462306a36Sopenharmony_ci 169562306a36Sopenharmony_ci return 0; 169662306a36Sopenharmony_ci 169762306a36Sopenharmony_cierr_free_id: 169862306a36Sopenharmony_ci ida_simple_remove(&xpad_pad_seq, xpad->pad_nr); 169962306a36Sopenharmony_cierr_free_mem: 170062306a36Sopenharmony_ci kfree(led); 170162306a36Sopenharmony_ci xpad->led = NULL; 170262306a36Sopenharmony_ci return error; 170362306a36Sopenharmony_ci} 170462306a36Sopenharmony_ci 170562306a36Sopenharmony_cistatic void xpad_led_disconnect(struct usb_xpad *xpad) 170662306a36Sopenharmony_ci{ 170762306a36Sopenharmony_ci struct xpad_led *xpad_led = xpad->led; 170862306a36Sopenharmony_ci 170962306a36Sopenharmony_ci if (xpad_led) { 171062306a36Sopenharmony_ci led_classdev_unregister(&xpad_led->led_cdev); 171162306a36Sopenharmony_ci ida_simple_remove(&xpad_pad_seq, xpad->pad_nr); 171262306a36Sopenharmony_ci kfree(xpad_led); 171362306a36Sopenharmony_ci } 171462306a36Sopenharmony_ci} 171562306a36Sopenharmony_ci#else 171662306a36Sopenharmony_cistatic int xpad_led_probe(struct usb_xpad *xpad) { return 0; } 171762306a36Sopenharmony_cistatic void xpad_led_disconnect(struct usb_xpad *xpad) { } 171862306a36Sopenharmony_ci#endif 171962306a36Sopenharmony_ci 172062306a36Sopenharmony_cistatic int xpad_start_input(struct usb_xpad *xpad) 172162306a36Sopenharmony_ci{ 172262306a36Sopenharmony_ci int error; 172362306a36Sopenharmony_ci 172462306a36Sopenharmony_ci if (usb_submit_urb(xpad->irq_in, GFP_KERNEL)) 172562306a36Sopenharmony_ci return -EIO; 172662306a36Sopenharmony_ci 172762306a36Sopenharmony_ci if (xpad->xtype == XTYPE_XBOXONE) { 172862306a36Sopenharmony_ci error = xpad_start_xbox_one(xpad); 172962306a36Sopenharmony_ci if (error) { 173062306a36Sopenharmony_ci usb_kill_urb(xpad->irq_in); 173162306a36Sopenharmony_ci return error; 173262306a36Sopenharmony_ci } 173362306a36Sopenharmony_ci } 173462306a36Sopenharmony_ci if (xpad->xtype == XTYPE_XBOX360) { 173562306a36Sopenharmony_ci /* 173662306a36Sopenharmony_ci * Some third-party controllers Xbox 360-style controllers 173762306a36Sopenharmony_ci * require this message to finish initialization. 173862306a36Sopenharmony_ci */ 173962306a36Sopenharmony_ci u8 dummy[20]; 174062306a36Sopenharmony_ci 174162306a36Sopenharmony_ci error = usb_control_msg_recv(xpad->udev, 0, 174262306a36Sopenharmony_ci /* bRequest */ 0x01, 174362306a36Sopenharmony_ci /* bmRequestType */ 174462306a36Sopenharmony_ci USB_TYPE_VENDOR | USB_DIR_IN | 174562306a36Sopenharmony_ci USB_RECIP_INTERFACE, 174662306a36Sopenharmony_ci /* wValue */ 0x100, 174762306a36Sopenharmony_ci /* wIndex */ 0x00, 174862306a36Sopenharmony_ci dummy, sizeof(dummy), 174962306a36Sopenharmony_ci 25, GFP_KERNEL); 175062306a36Sopenharmony_ci if (error) 175162306a36Sopenharmony_ci dev_warn(&xpad->dev->dev, 175262306a36Sopenharmony_ci "unable to receive magic message: %d\n", 175362306a36Sopenharmony_ci error); 175462306a36Sopenharmony_ci } 175562306a36Sopenharmony_ci 175662306a36Sopenharmony_ci return 0; 175762306a36Sopenharmony_ci} 175862306a36Sopenharmony_ci 175962306a36Sopenharmony_cistatic void xpad_stop_input(struct usb_xpad *xpad) 176062306a36Sopenharmony_ci{ 176162306a36Sopenharmony_ci usb_kill_urb(xpad->irq_in); 176262306a36Sopenharmony_ci} 176362306a36Sopenharmony_ci 176462306a36Sopenharmony_cistatic void xpad360w_poweroff_controller(struct usb_xpad *xpad) 176562306a36Sopenharmony_ci{ 176662306a36Sopenharmony_ci unsigned long flags; 176762306a36Sopenharmony_ci struct xpad_output_packet *packet = 176862306a36Sopenharmony_ci &xpad->out_packets[XPAD_OUT_CMD_IDX]; 176962306a36Sopenharmony_ci 177062306a36Sopenharmony_ci spin_lock_irqsave(&xpad->odata_lock, flags); 177162306a36Sopenharmony_ci 177262306a36Sopenharmony_ci packet->data[0] = 0x00; 177362306a36Sopenharmony_ci packet->data[1] = 0x00; 177462306a36Sopenharmony_ci packet->data[2] = 0x08; 177562306a36Sopenharmony_ci packet->data[3] = 0xC0; 177662306a36Sopenharmony_ci packet->data[4] = 0x00; 177762306a36Sopenharmony_ci packet->data[5] = 0x00; 177862306a36Sopenharmony_ci packet->data[6] = 0x00; 177962306a36Sopenharmony_ci packet->data[7] = 0x00; 178062306a36Sopenharmony_ci packet->data[8] = 0x00; 178162306a36Sopenharmony_ci packet->data[9] = 0x00; 178262306a36Sopenharmony_ci packet->data[10] = 0x00; 178362306a36Sopenharmony_ci packet->data[11] = 0x00; 178462306a36Sopenharmony_ci packet->len = 12; 178562306a36Sopenharmony_ci packet->pending = true; 178662306a36Sopenharmony_ci 178762306a36Sopenharmony_ci /* Reset the sequence so we send out poweroff now */ 178862306a36Sopenharmony_ci xpad->last_out_packet = -1; 178962306a36Sopenharmony_ci xpad_try_sending_next_out_packet(xpad); 179062306a36Sopenharmony_ci 179162306a36Sopenharmony_ci spin_unlock_irqrestore(&xpad->odata_lock, flags); 179262306a36Sopenharmony_ci} 179362306a36Sopenharmony_ci 179462306a36Sopenharmony_cistatic int xpad360w_start_input(struct usb_xpad *xpad) 179562306a36Sopenharmony_ci{ 179662306a36Sopenharmony_ci int error; 179762306a36Sopenharmony_ci 179862306a36Sopenharmony_ci error = usb_submit_urb(xpad->irq_in, GFP_KERNEL); 179962306a36Sopenharmony_ci if (error) 180062306a36Sopenharmony_ci return -EIO; 180162306a36Sopenharmony_ci 180262306a36Sopenharmony_ci /* 180362306a36Sopenharmony_ci * Send presence packet. 180462306a36Sopenharmony_ci * This will force the controller to resend connection packets. 180562306a36Sopenharmony_ci * This is useful in the case we activate the module after the 180662306a36Sopenharmony_ci * adapter has been plugged in, as it won't automatically 180762306a36Sopenharmony_ci * send us info about the controllers. 180862306a36Sopenharmony_ci */ 180962306a36Sopenharmony_ci error = xpad_inquiry_pad_presence(xpad); 181062306a36Sopenharmony_ci if (error) { 181162306a36Sopenharmony_ci usb_kill_urb(xpad->irq_in); 181262306a36Sopenharmony_ci return error; 181362306a36Sopenharmony_ci } 181462306a36Sopenharmony_ci 181562306a36Sopenharmony_ci return 0; 181662306a36Sopenharmony_ci} 181762306a36Sopenharmony_ci 181862306a36Sopenharmony_cistatic void xpad360w_stop_input(struct usb_xpad *xpad) 181962306a36Sopenharmony_ci{ 182062306a36Sopenharmony_ci usb_kill_urb(xpad->irq_in); 182162306a36Sopenharmony_ci 182262306a36Sopenharmony_ci /* Make sure we are done with presence work if it was scheduled */ 182362306a36Sopenharmony_ci flush_work(&xpad->work); 182462306a36Sopenharmony_ci} 182562306a36Sopenharmony_ci 182662306a36Sopenharmony_cistatic int xpad_open(struct input_dev *dev) 182762306a36Sopenharmony_ci{ 182862306a36Sopenharmony_ci struct usb_xpad *xpad = input_get_drvdata(dev); 182962306a36Sopenharmony_ci 183062306a36Sopenharmony_ci return xpad_start_input(xpad); 183162306a36Sopenharmony_ci} 183262306a36Sopenharmony_ci 183362306a36Sopenharmony_cistatic void xpad_close(struct input_dev *dev) 183462306a36Sopenharmony_ci{ 183562306a36Sopenharmony_ci struct usb_xpad *xpad = input_get_drvdata(dev); 183662306a36Sopenharmony_ci 183762306a36Sopenharmony_ci xpad_stop_input(xpad); 183862306a36Sopenharmony_ci} 183962306a36Sopenharmony_ci 184062306a36Sopenharmony_cistatic void xpad_set_up_abs(struct input_dev *input_dev, signed short abs) 184162306a36Sopenharmony_ci{ 184262306a36Sopenharmony_ci struct usb_xpad *xpad = input_get_drvdata(input_dev); 184362306a36Sopenharmony_ci 184462306a36Sopenharmony_ci switch (abs) { 184562306a36Sopenharmony_ci case ABS_X: 184662306a36Sopenharmony_ci case ABS_Y: 184762306a36Sopenharmony_ci case ABS_RX: 184862306a36Sopenharmony_ci case ABS_RY: /* the two sticks */ 184962306a36Sopenharmony_ci input_set_abs_params(input_dev, abs, -32768, 32767, 16, 128); 185062306a36Sopenharmony_ci break; 185162306a36Sopenharmony_ci case ABS_Z: 185262306a36Sopenharmony_ci case ABS_RZ: /* the triggers (if mapped to axes) */ 185362306a36Sopenharmony_ci if (xpad->xtype == XTYPE_XBOXONE) 185462306a36Sopenharmony_ci input_set_abs_params(input_dev, abs, 0, 1023, 0, 0); 185562306a36Sopenharmony_ci else 185662306a36Sopenharmony_ci input_set_abs_params(input_dev, abs, 0, 255, 0, 0); 185762306a36Sopenharmony_ci break; 185862306a36Sopenharmony_ci case ABS_HAT0X: 185962306a36Sopenharmony_ci case ABS_HAT0Y: /* the d-pad (only if dpad is mapped to axes */ 186062306a36Sopenharmony_ci input_set_abs_params(input_dev, abs, -1, 1, 0, 0); 186162306a36Sopenharmony_ci break; 186262306a36Sopenharmony_ci case ABS_PROFILE: /* 4 value profile button (such as on XAC) */ 186362306a36Sopenharmony_ci input_set_abs_params(input_dev, abs, 0, 4, 0, 0); 186462306a36Sopenharmony_ci break; 186562306a36Sopenharmony_ci default: 186662306a36Sopenharmony_ci input_set_abs_params(input_dev, abs, 0, 0, 0, 0); 186762306a36Sopenharmony_ci break; 186862306a36Sopenharmony_ci } 186962306a36Sopenharmony_ci} 187062306a36Sopenharmony_ci 187162306a36Sopenharmony_cistatic void xpad_deinit_input(struct usb_xpad *xpad) 187262306a36Sopenharmony_ci{ 187362306a36Sopenharmony_ci if (xpad->input_created) { 187462306a36Sopenharmony_ci xpad->input_created = false; 187562306a36Sopenharmony_ci xpad_led_disconnect(xpad); 187662306a36Sopenharmony_ci input_unregister_device(xpad->dev); 187762306a36Sopenharmony_ci } 187862306a36Sopenharmony_ci} 187962306a36Sopenharmony_ci 188062306a36Sopenharmony_cistatic int xpad_init_input(struct usb_xpad *xpad) 188162306a36Sopenharmony_ci{ 188262306a36Sopenharmony_ci struct input_dev *input_dev; 188362306a36Sopenharmony_ci int i, error; 188462306a36Sopenharmony_ci 188562306a36Sopenharmony_ci input_dev = input_allocate_device(); 188662306a36Sopenharmony_ci if (!input_dev) 188762306a36Sopenharmony_ci return -ENOMEM; 188862306a36Sopenharmony_ci 188962306a36Sopenharmony_ci xpad->dev = input_dev; 189062306a36Sopenharmony_ci input_dev->name = xpad->name; 189162306a36Sopenharmony_ci input_dev->phys = xpad->phys; 189262306a36Sopenharmony_ci usb_to_input_id(xpad->udev, &input_dev->id); 189362306a36Sopenharmony_ci 189462306a36Sopenharmony_ci if (xpad->xtype == XTYPE_XBOX360W) { 189562306a36Sopenharmony_ci /* x360w controllers and the receiver have different ids */ 189662306a36Sopenharmony_ci input_dev->id.product = 0x02a1; 189762306a36Sopenharmony_ci } 189862306a36Sopenharmony_ci 189962306a36Sopenharmony_ci input_dev->dev.parent = &xpad->intf->dev; 190062306a36Sopenharmony_ci 190162306a36Sopenharmony_ci input_set_drvdata(input_dev, xpad); 190262306a36Sopenharmony_ci 190362306a36Sopenharmony_ci if (xpad->xtype != XTYPE_XBOX360W) { 190462306a36Sopenharmony_ci input_dev->open = xpad_open; 190562306a36Sopenharmony_ci input_dev->close = xpad_close; 190662306a36Sopenharmony_ci } 190762306a36Sopenharmony_ci 190862306a36Sopenharmony_ci if (!(xpad->mapping & MAP_STICKS_TO_NULL)) { 190962306a36Sopenharmony_ci /* set up axes */ 191062306a36Sopenharmony_ci for (i = 0; xpad_abs[i] >= 0; i++) 191162306a36Sopenharmony_ci xpad_set_up_abs(input_dev, xpad_abs[i]); 191262306a36Sopenharmony_ci } 191362306a36Sopenharmony_ci 191462306a36Sopenharmony_ci /* set up standard buttons */ 191562306a36Sopenharmony_ci for (i = 0; xpad_common_btn[i] >= 0; i++) 191662306a36Sopenharmony_ci input_set_capability(input_dev, EV_KEY, xpad_common_btn[i]); 191762306a36Sopenharmony_ci 191862306a36Sopenharmony_ci /* set up model-specific ones */ 191962306a36Sopenharmony_ci if (xpad->xtype == XTYPE_XBOX360 || xpad->xtype == XTYPE_XBOX360W || 192062306a36Sopenharmony_ci xpad->xtype == XTYPE_XBOXONE) { 192162306a36Sopenharmony_ci for (i = 0; xpad360_btn[i] >= 0; i++) 192262306a36Sopenharmony_ci input_set_capability(input_dev, EV_KEY, xpad360_btn[i]); 192362306a36Sopenharmony_ci if (xpad->mapping & MAP_SELECT_BUTTON) 192462306a36Sopenharmony_ci input_set_capability(input_dev, EV_KEY, KEY_RECORD); 192562306a36Sopenharmony_ci } else { 192662306a36Sopenharmony_ci for (i = 0; xpad_btn[i] >= 0; i++) 192762306a36Sopenharmony_ci input_set_capability(input_dev, EV_KEY, xpad_btn[i]); 192862306a36Sopenharmony_ci } 192962306a36Sopenharmony_ci 193062306a36Sopenharmony_ci if (xpad->mapping & MAP_DPAD_TO_BUTTONS) { 193162306a36Sopenharmony_ci for (i = 0; xpad_btn_pad[i] >= 0; i++) 193262306a36Sopenharmony_ci input_set_capability(input_dev, EV_KEY, 193362306a36Sopenharmony_ci xpad_btn_pad[i]); 193462306a36Sopenharmony_ci } 193562306a36Sopenharmony_ci 193662306a36Sopenharmony_ci /* set up paddles if the controller has them */ 193762306a36Sopenharmony_ci if (xpad->mapping & MAP_PADDLES) { 193862306a36Sopenharmony_ci for (i = 0; xpad_btn_paddles[i] >= 0; i++) 193962306a36Sopenharmony_ci input_set_capability(input_dev, EV_KEY, xpad_btn_paddles[i]); 194062306a36Sopenharmony_ci } 194162306a36Sopenharmony_ci 194262306a36Sopenharmony_ci /* 194362306a36Sopenharmony_ci * This should be a simple else block. However historically 194462306a36Sopenharmony_ci * xbox360w has mapped DPAD to buttons while xbox360 did not. This 194562306a36Sopenharmony_ci * made no sense, but now we can not just switch back and have to 194662306a36Sopenharmony_ci * support both behaviors. 194762306a36Sopenharmony_ci */ 194862306a36Sopenharmony_ci if (!(xpad->mapping & MAP_DPAD_TO_BUTTONS) || 194962306a36Sopenharmony_ci xpad->xtype == XTYPE_XBOX360W) { 195062306a36Sopenharmony_ci for (i = 0; xpad_abs_pad[i] >= 0; i++) 195162306a36Sopenharmony_ci xpad_set_up_abs(input_dev, xpad_abs_pad[i]); 195262306a36Sopenharmony_ci } 195362306a36Sopenharmony_ci 195462306a36Sopenharmony_ci if (xpad->mapping & MAP_TRIGGERS_TO_BUTTONS) { 195562306a36Sopenharmony_ci for (i = 0; xpad_btn_triggers[i] >= 0; i++) 195662306a36Sopenharmony_ci input_set_capability(input_dev, EV_KEY, 195762306a36Sopenharmony_ci xpad_btn_triggers[i]); 195862306a36Sopenharmony_ci } else { 195962306a36Sopenharmony_ci for (i = 0; xpad_abs_triggers[i] >= 0; i++) 196062306a36Sopenharmony_ci xpad_set_up_abs(input_dev, xpad_abs_triggers[i]); 196162306a36Sopenharmony_ci } 196262306a36Sopenharmony_ci 196362306a36Sopenharmony_ci /* setup profile button as an axis with 4 possible values */ 196462306a36Sopenharmony_ci if (xpad->mapping & MAP_PROFILE_BUTTON) 196562306a36Sopenharmony_ci xpad_set_up_abs(input_dev, ABS_PROFILE); 196662306a36Sopenharmony_ci 196762306a36Sopenharmony_ci error = xpad_init_ff(xpad); 196862306a36Sopenharmony_ci if (error) 196962306a36Sopenharmony_ci goto err_free_input; 197062306a36Sopenharmony_ci 197162306a36Sopenharmony_ci error = xpad_led_probe(xpad); 197262306a36Sopenharmony_ci if (error) 197362306a36Sopenharmony_ci goto err_destroy_ff; 197462306a36Sopenharmony_ci 197562306a36Sopenharmony_ci error = input_register_device(xpad->dev); 197662306a36Sopenharmony_ci if (error) 197762306a36Sopenharmony_ci goto err_disconnect_led; 197862306a36Sopenharmony_ci 197962306a36Sopenharmony_ci xpad->input_created = true; 198062306a36Sopenharmony_ci return 0; 198162306a36Sopenharmony_ci 198262306a36Sopenharmony_cierr_disconnect_led: 198362306a36Sopenharmony_ci xpad_led_disconnect(xpad); 198462306a36Sopenharmony_cierr_destroy_ff: 198562306a36Sopenharmony_ci input_ff_destroy(input_dev); 198662306a36Sopenharmony_cierr_free_input: 198762306a36Sopenharmony_ci input_free_device(input_dev); 198862306a36Sopenharmony_ci return error; 198962306a36Sopenharmony_ci} 199062306a36Sopenharmony_ci 199162306a36Sopenharmony_cistatic int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id) 199262306a36Sopenharmony_ci{ 199362306a36Sopenharmony_ci struct usb_device *udev = interface_to_usbdev(intf); 199462306a36Sopenharmony_ci struct usb_xpad *xpad; 199562306a36Sopenharmony_ci struct usb_endpoint_descriptor *ep_irq_in, *ep_irq_out; 199662306a36Sopenharmony_ci int i, error; 199762306a36Sopenharmony_ci 199862306a36Sopenharmony_ci if (intf->cur_altsetting->desc.bNumEndpoints != 2) 199962306a36Sopenharmony_ci return -ENODEV; 200062306a36Sopenharmony_ci 200162306a36Sopenharmony_ci for (i = 0; xpad_device[i].idVendor; i++) { 200262306a36Sopenharmony_ci if ((le16_to_cpu(udev->descriptor.idVendor) == xpad_device[i].idVendor) && 200362306a36Sopenharmony_ci (le16_to_cpu(udev->descriptor.idProduct) == xpad_device[i].idProduct)) 200462306a36Sopenharmony_ci break; 200562306a36Sopenharmony_ci } 200662306a36Sopenharmony_ci 200762306a36Sopenharmony_ci xpad = kzalloc(sizeof(struct usb_xpad), GFP_KERNEL); 200862306a36Sopenharmony_ci if (!xpad) 200962306a36Sopenharmony_ci return -ENOMEM; 201062306a36Sopenharmony_ci 201162306a36Sopenharmony_ci usb_make_path(udev, xpad->phys, sizeof(xpad->phys)); 201262306a36Sopenharmony_ci strlcat(xpad->phys, "/input0", sizeof(xpad->phys)); 201362306a36Sopenharmony_ci 201462306a36Sopenharmony_ci xpad->idata = usb_alloc_coherent(udev, XPAD_PKT_LEN, 201562306a36Sopenharmony_ci GFP_KERNEL, &xpad->idata_dma); 201662306a36Sopenharmony_ci if (!xpad->idata) { 201762306a36Sopenharmony_ci error = -ENOMEM; 201862306a36Sopenharmony_ci goto err_free_mem; 201962306a36Sopenharmony_ci } 202062306a36Sopenharmony_ci 202162306a36Sopenharmony_ci xpad->irq_in = usb_alloc_urb(0, GFP_KERNEL); 202262306a36Sopenharmony_ci if (!xpad->irq_in) { 202362306a36Sopenharmony_ci error = -ENOMEM; 202462306a36Sopenharmony_ci goto err_free_idata; 202562306a36Sopenharmony_ci } 202662306a36Sopenharmony_ci 202762306a36Sopenharmony_ci xpad->udev = udev; 202862306a36Sopenharmony_ci xpad->intf = intf; 202962306a36Sopenharmony_ci xpad->mapping = xpad_device[i].mapping; 203062306a36Sopenharmony_ci xpad->xtype = xpad_device[i].xtype; 203162306a36Sopenharmony_ci xpad->name = xpad_device[i].name; 203262306a36Sopenharmony_ci xpad->packet_type = PKT_XB; 203362306a36Sopenharmony_ci INIT_WORK(&xpad->work, xpad_presence_work); 203462306a36Sopenharmony_ci 203562306a36Sopenharmony_ci if (xpad->xtype == XTYPE_UNKNOWN) { 203662306a36Sopenharmony_ci if (intf->cur_altsetting->desc.bInterfaceClass == USB_CLASS_VENDOR_SPEC) { 203762306a36Sopenharmony_ci if (intf->cur_altsetting->desc.bInterfaceProtocol == 129) 203862306a36Sopenharmony_ci xpad->xtype = XTYPE_XBOX360W; 203962306a36Sopenharmony_ci else if (intf->cur_altsetting->desc.bInterfaceProtocol == 208) 204062306a36Sopenharmony_ci xpad->xtype = XTYPE_XBOXONE; 204162306a36Sopenharmony_ci else 204262306a36Sopenharmony_ci xpad->xtype = XTYPE_XBOX360; 204362306a36Sopenharmony_ci } else { 204462306a36Sopenharmony_ci xpad->xtype = XTYPE_XBOX; 204562306a36Sopenharmony_ci } 204662306a36Sopenharmony_ci 204762306a36Sopenharmony_ci if (dpad_to_buttons) 204862306a36Sopenharmony_ci xpad->mapping |= MAP_DPAD_TO_BUTTONS; 204962306a36Sopenharmony_ci if (triggers_to_buttons) 205062306a36Sopenharmony_ci xpad->mapping |= MAP_TRIGGERS_TO_BUTTONS; 205162306a36Sopenharmony_ci if (sticks_to_null) 205262306a36Sopenharmony_ci xpad->mapping |= MAP_STICKS_TO_NULL; 205362306a36Sopenharmony_ci } 205462306a36Sopenharmony_ci 205562306a36Sopenharmony_ci if (xpad->xtype == XTYPE_XBOXONE && 205662306a36Sopenharmony_ci intf->cur_altsetting->desc.bInterfaceNumber != GIP_WIRED_INTF_DATA) { 205762306a36Sopenharmony_ci /* 205862306a36Sopenharmony_ci * The Xbox One controller lists three interfaces all with the 205962306a36Sopenharmony_ci * same interface class, subclass and protocol. Differentiate by 206062306a36Sopenharmony_ci * interface number. 206162306a36Sopenharmony_ci */ 206262306a36Sopenharmony_ci error = -ENODEV; 206362306a36Sopenharmony_ci goto err_free_in_urb; 206462306a36Sopenharmony_ci } 206562306a36Sopenharmony_ci 206662306a36Sopenharmony_ci ep_irq_in = ep_irq_out = NULL; 206762306a36Sopenharmony_ci 206862306a36Sopenharmony_ci for (i = 0; i < 2; i++) { 206962306a36Sopenharmony_ci struct usb_endpoint_descriptor *ep = 207062306a36Sopenharmony_ci &intf->cur_altsetting->endpoint[i].desc; 207162306a36Sopenharmony_ci 207262306a36Sopenharmony_ci if (usb_endpoint_xfer_int(ep)) { 207362306a36Sopenharmony_ci if (usb_endpoint_dir_in(ep)) 207462306a36Sopenharmony_ci ep_irq_in = ep; 207562306a36Sopenharmony_ci else 207662306a36Sopenharmony_ci ep_irq_out = ep; 207762306a36Sopenharmony_ci } 207862306a36Sopenharmony_ci } 207962306a36Sopenharmony_ci 208062306a36Sopenharmony_ci if (!ep_irq_in || !ep_irq_out) { 208162306a36Sopenharmony_ci error = -ENODEV; 208262306a36Sopenharmony_ci goto err_free_in_urb; 208362306a36Sopenharmony_ci } 208462306a36Sopenharmony_ci 208562306a36Sopenharmony_ci error = xpad_init_output(intf, xpad, ep_irq_out); 208662306a36Sopenharmony_ci if (error) 208762306a36Sopenharmony_ci goto err_free_in_urb; 208862306a36Sopenharmony_ci 208962306a36Sopenharmony_ci usb_fill_int_urb(xpad->irq_in, udev, 209062306a36Sopenharmony_ci usb_rcvintpipe(udev, ep_irq_in->bEndpointAddress), 209162306a36Sopenharmony_ci xpad->idata, XPAD_PKT_LEN, xpad_irq_in, 209262306a36Sopenharmony_ci xpad, ep_irq_in->bInterval); 209362306a36Sopenharmony_ci xpad->irq_in->transfer_dma = xpad->idata_dma; 209462306a36Sopenharmony_ci xpad->irq_in->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; 209562306a36Sopenharmony_ci 209662306a36Sopenharmony_ci usb_set_intfdata(intf, xpad); 209762306a36Sopenharmony_ci 209862306a36Sopenharmony_ci /* Packet type detection */ 209962306a36Sopenharmony_ci if (le16_to_cpu(udev->descriptor.idVendor) == 0x045e) { /* Microsoft controllers */ 210062306a36Sopenharmony_ci if (le16_to_cpu(udev->descriptor.idProduct) == 0x02e3) { 210162306a36Sopenharmony_ci /* The original elite controller always uses the oldest 210262306a36Sopenharmony_ci * type of extended packet 210362306a36Sopenharmony_ci */ 210462306a36Sopenharmony_ci xpad->packet_type = PKT_XBE1; 210562306a36Sopenharmony_ci } else if (le16_to_cpu(udev->descriptor.idProduct) == 0x0b00) { 210662306a36Sopenharmony_ci /* The elite 2 controller has seen multiple packet 210762306a36Sopenharmony_ci * revisions. These are tied to specific firmware 210862306a36Sopenharmony_ci * versions 210962306a36Sopenharmony_ci */ 211062306a36Sopenharmony_ci if (le16_to_cpu(udev->descriptor.bcdDevice) < 0x0500) { 211162306a36Sopenharmony_ci /* This is the format that the Elite 2 used 211262306a36Sopenharmony_ci * prior to the BLE update 211362306a36Sopenharmony_ci */ 211462306a36Sopenharmony_ci xpad->packet_type = PKT_XBE2_FW_OLD; 211562306a36Sopenharmony_ci } else if (le16_to_cpu(udev->descriptor.bcdDevice) < 211662306a36Sopenharmony_ci 0x050b) { 211762306a36Sopenharmony_ci /* This is the format that the Elite 2 used 211862306a36Sopenharmony_ci * prior to the update that split the packet 211962306a36Sopenharmony_ci */ 212062306a36Sopenharmony_ci xpad->packet_type = PKT_XBE2_FW_5_EARLY; 212162306a36Sopenharmony_ci } else { 212262306a36Sopenharmony_ci /* The split packet format that was introduced 212362306a36Sopenharmony_ci * in firmware v5.11 212462306a36Sopenharmony_ci */ 212562306a36Sopenharmony_ci xpad->packet_type = PKT_XBE2_FW_5_11; 212662306a36Sopenharmony_ci } 212762306a36Sopenharmony_ci } 212862306a36Sopenharmony_ci } 212962306a36Sopenharmony_ci 213062306a36Sopenharmony_ci if (xpad->xtype == XTYPE_XBOX360W) { 213162306a36Sopenharmony_ci /* 213262306a36Sopenharmony_ci * Submit the int URB immediately rather than waiting for open 213362306a36Sopenharmony_ci * because we get status messages from the device whether 213462306a36Sopenharmony_ci * or not any controllers are attached. In fact, it's 213562306a36Sopenharmony_ci * exactly the message that a controller has arrived that 213662306a36Sopenharmony_ci * we're waiting for. 213762306a36Sopenharmony_ci */ 213862306a36Sopenharmony_ci error = xpad360w_start_input(xpad); 213962306a36Sopenharmony_ci if (error) 214062306a36Sopenharmony_ci goto err_deinit_output; 214162306a36Sopenharmony_ci /* 214262306a36Sopenharmony_ci * Wireless controllers require RESET_RESUME to work properly 214362306a36Sopenharmony_ci * after suspend. Ideally this quirk should be in usb core 214462306a36Sopenharmony_ci * quirk list, but we have too many vendors producing these 214562306a36Sopenharmony_ci * controllers and we'd need to maintain 2 identical lists 214662306a36Sopenharmony_ci * here in this driver and in usb core. 214762306a36Sopenharmony_ci */ 214862306a36Sopenharmony_ci udev->quirks |= USB_QUIRK_RESET_RESUME; 214962306a36Sopenharmony_ci } else { 215062306a36Sopenharmony_ci error = xpad_init_input(xpad); 215162306a36Sopenharmony_ci if (error) 215262306a36Sopenharmony_ci goto err_deinit_output; 215362306a36Sopenharmony_ci } 215462306a36Sopenharmony_ci return 0; 215562306a36Sopenharmony_ci 215662306a36Sopenharmony_cierr_deinit_output: 215762306a36Sopenharmony_ci xpad_deinit_output(xpad); 215862306a36Sopenharmony_cierr_free_in_urb: 215962306a36Sopenharmony_ci usb_free_urb(xpad->irq_in); 216062306a36Sopenharmony_cierr_free_idata: 216162306a36Sopenharmony_ci usb_free_coherent(udev, XPAD_PKT_LEN, xpad->idata, xpad->idata_dma); 216262306a36Sopenharmony_cierr_free_mem: 216362306a36Sopenharmony_ci kfree(xpad); 216462306a36Sopenharmony_ci return error; 216562306a36Sopenharmony_ci} 216662306a36Sopenharmony_ci 216762306a36Sopenharmony_cistatic void xpad_disconnect(struct usb_interface *intf) 216862306a36Sopenharmony_ci{ 216962306a36Sopenharmony_ci struct usb_xpad *xpad = usb_get_intfdata(intf); 217062306a36Sopenharmony_ci 217162306a36Sopenharmony_ci if (xpad->xtype == XTYPE_XBOX360W) 217262306a36Sopenharmony_ci xpad360w_stop_input(xpad); 217362306a36Sopenharmony_ci 217462306a36Sopenharmony_ci xpad_deinit_input(xpad); 217562306a36Sopenharmony_ci 217662306a36Sopenharmony_ci /* 217762306a36Sopenharmony_ci * Now that both input device and LED device are gone we can 217862306a36Sopenharmony_ci * stop output URB. 217962306a36Sopenharmony_ci */ 218062306a36Sopenharmony_ci xpad_stop_output(xpad); 218162306a36Sopenharmony_ci 218262306a36Sopenharmony_ci xpad_deinit_output(xpad); 218362306a36Sopenharmony_ci 218462306a36Sopenharmony_ci usb_free_urb(xpad->irq_in); 218562306a36Sopenharmony_ci usb_free_coherent(xpad->udev, XPAD_PKT_LEN, 218662306a36Sopenharmony_ci xpad->idata, xpad->idata_dma); 218762306a36Sopenharmony_ci 218862306a36Sopenharmony_ci kfree(xpad); 218962306a36Sopenharmony_ci 219062306a36Sopenharmony_ci usb_set_intfdata(intf, NULL); 219162306a36Sopenharmony_ci} 219262306a36Sopenharmony_ci 219362306a36Sopenharmony_cistatic int xpad_suspend(struct usb_interface *intf, pm_message_t message) 219462306a36Sopenharmony_ci{ 219562306a36Sopenharmony_ci struct usb_xpad *xpad = usb_get_intfdata(intf); 219662306a36Sopenharmony_ci struct input_dev *input = xpad->dev; 219762306a36Sopenharmony_ci 219862306a36Sopenharmony_ci if (xpad->xtype == XTYPE_XBOX360W) { 219962306a36Sopenharmony_ci /* 220062306a36Sopenharmony_ci * Wireless controllers always listen to input so 220162306a36Sopenharmony_ci * they are notified when controller shows up 220262306a36Sopenharmony_ci * or goes away. 220362306a36Sopenharmony_ci */ 220462306a36Sopenharmony_ci xpad360w_stop_input(xpad); 220562306a36Sopenharmony_ci 220662306a36Sopenharmony_ci /* 220762306a36Sopenharmony_ci * The wireless adapter is going off now, so the 220862306a36Sopenharmony_ci * gamepads are going to become disconnected. 220962306a36Sopenharmony_ci * Unless explicitly disabled, power them down 221062306a36Sopenharmony_ci * so they don't just sit there flashing. 221162306a36Sopenharmony_ci */ 221262306a36Sopenharmony_ci if (auto_poweroff && xpad->pad_present) 221362306a36Sopenharmony_ci xpad360w_poweroff_controller(xpad); 221462306a36Sopenharmony_ci } else { 221562306a36Sopenharmony_ci mutex_lock(&input->mutex); 221662306a36Sopenharmony_ci if (input_device_enabled(input)) 221762306a36Sopenharmony_ci xpad_stop_input(xpad); 221862306a36Sopenharmony_ci mutex_unlock(&input->mutex); 221962306a36Sopenharmony_ci } 222062306a36Sopenharmony_ci 222162306a36Sopenharmony_ci xpad_stop_output(xpad); 222262306a36Sopenharmony_ci 222362306a36Sopenharmony_ci return 0; 222462306a36Sopenharmony_ci} 222562306a36Sopenharmony_ci 222662306a36Sopenharmony_cistatic int xpad_resume(struct usb_interface *intf) 222762306a36Sopenharmony_ci{ 222862306a36Sopenharmony_ci struct usb_xpad *xpad = usb_get_intfdata(intf); 222962306a36Sopenharmony_ci struct input_dev *input = xpad->dev; 223062306a36Sopenharmony_ci int retval = 0; 223162306a36Sopenharmony_ci 223262306a36Sopenharmony_ci if (xpad->xtype == XTYPE_XBOX360W) { 223362306a36Sopenharmony_ci retval = xpad360w_start_input(xpad); 223462306a36Sopenharmony_ci } else { 223562306a36Sopenharmony_ci mutex_lock(&input->mutex); 223662306a36Sopenharmony_ci if (input_device_enabled(input)) { 223762306a36Sopenharmony_ci retval = xpad_start_input(xpad); 223862306a36Sopenharmony_ci } else if (xpad->xtype == XTYPE_XBOXONE) { 223962306a36Sopenharmony_ci /* 224062306a36Sopenharmony_ci * Even if there are no users, we'll send Xbox One pads 224162306a36Sopenharmony_ci * the startup sequence so they don't sit there and 224262306a36Sopenharmony_ci * blink until somebody opens the input device again. 224362306a36Sopenharmony_ci */ 224462306a36Sopenharmony_ci retval = xpad_start_xbox_one(xpad); 224562306a36Sopenharmony_ci } 224662306a36Sopenharmony_ci mutex_unlock(&input->mutex); 224762306a36Sopenharmony_ci } 224862306a36Sopenharmony_ci 224962306a36Sopenharmony_ci return retval; 225062306a36Sopenharmony_ci} 225162306a36Sopenharmony_ci 225262306a36Sopenharmony_cistatic struct usb_driver xpad_driver = { 225362306a36Sopenharmony_ci .name = "xpad", 225462306a36Sopenharmony_ci .probe = xpad_probe, 225562306a36Sopenharmony_ci .disconnect = xpad_disconnect, 225662306a36Sopenharmony_ci .suspend = xpad_suspend, 225762306a36Sopenharmony_ci .resume = xpad_resume, 225862306a36Sopenharmony_ci .id_table = xpad_table, 225962306a36Sopenharmony_ci}; 226062306a36Sopenharmony_ci 226162306a36Sopenharmony_cimodule_usb_driver(xpad_driver); 226262306a36Sopenharmony_ci 226362306a36Sopenharmony_ciMODULE_AUTHOR("Marko Friedemann <mfr@bmx-chemnitz.de>"); 226462306a36Sopenharmony_ciMODULE_DESCRIPTION("Xbox pad driver"); 226562306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 2266