diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 0000000..17be172 --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,13 @@ + \ No newline at end of file diff --git a/.github/workflows/ci-build.yml b/.github/workflows/ci-build.yml new file mode 100644 index 0000000..460600d --- /dev/null +++ b/.github/workflows/ci-build.yml @@ -0,0 +1,19 @@ +name: CI Build +on: + push: + branches: [master] + pull_request: + branches: [master] +jobs: + linux: + runs-on: ubuntu-22.04 + steps: + - name: Install Dependencies + run: | + sudo apt update + sudo apt install -y dkms + - uses: actions/checkout@v2 + - name: Build + run: | + sudo ln -s `pwd` /usr/src/xpad-0.4 + sudo dkms install -m xpad -v 0.4 diff --git a/README.md b/README.md new file mode 100644 index 0000000..68de5ac --- /dev/null +++ b/README.md @@ -0,0 +1,94 @@ +# Updated Xpad Linux Kernel Driver +Driver for the Xbox/ Xbox 360/ Xbox 360 Wireless/ Xbox One Controllers + +This driver includes the latest changes in the upstream linux kernel and additionally carries the following staging changes: + +* support for more compatible devices +* support for xbox360 class controllers, that need initialisation +* support for xbox one elite paddles +* xpad360w: power-off by long-pressing the power button + +## Xbox One Controllers +This driver is only used if you connect the controller via USB. + +**Connecting via Bluetooth** +If you get past the pairing issues, the controller will operate in the [generic-HID bluetooth profile](https://en.wikipedia.org/wiki/List_of_Bluetooth_profiles#Human_Interface_Device_Profile_(HID)). +The xpad driver will not be used. + +**Connecting via XBox One Wireless Adapter (WiFi)** +The adapter needs daemon in userspace, see: [medusalix/xow](https://github.com/medusalix/xow) +Opinion: rather get a controller that supports bluetooth. + + +# Installing +``` +sudo git clone https://github.com/paroj/xpad.git /usr/src/xpad-0.4 +sudo dkms install -m xpad -v 0.4 +``` +# Updating +``` +cd /usr/src/xpad-0.4 +sudo git fetch +sudo git checkout origin/master +sudo dkms remove -m xpad -v 0.4 --all +sudo dkms install -m xpad -v 0.4 +``` +# Removing +``` +sudo dkms remove -m xpad -v 0.4 --all +sudo rm -rf /usr/src/xpad-0.4 +``` +# Usage +This driver creates three devices for each attached gamepad + +1. /dev/input/js**N** + * example `jstest /dev/input/js0` +2. /sys/class/leds/xpad**N**/brightness + * example `echo COMMAND > /sys/class/leds/xpad0/brightness` where COMMAND is one of + * 0: off + * 1: all blink, then previous setting + * 2: 1/top-left blink, then on + * 3: 2/top-right blink, then on + * 4: 3/bottom-left blink, then on + * 5: 4/bottom-right blink, then on + * 6: 1/top-left on + * 7: 2/top-right on + * 8: 3/bottom-left on + * 9: 4/bottom-right on + * 10: rotate + * 11: blink, based on previous setting + * 12: slow blink, based on previous setting + * 13: rotate with two lights + * 14: persistent slow all blink + * 15: blink once, then previous setting +3. the generic event device + * example `fftest /dev/input/by-id/usb-*360*event*` + +# Debugging +As a regular unpriveledged user + +Setup console to display kernel log. +`dmesg --level=debug --follow` + +Open a new console and access the device with jstest. +`jstest /dev/input/jsX` + +Interact with the device and observe that data packets recieved from device are printed to kernel log. +``` +[ 3968.772128] xpad-dbg: 00000000: 20 00 b5 0e 00 00 00 00 00 00 0c 03 04 fd 6c 01 40 fe 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 3968.772135] xpad-dbg: 00000020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 3968.804137] xpad-dbg: 00000000: 20 00 b6 0e 00 00 00 00 00 00 0c 03 04 fd 6c 01 fc fd 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 3968.804145] xpad-dbg: 00000020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 3969.152120] xpad-dbg: 00000000: 20 00 b7 0e 00 00 00 00 00 00 0c 03 04 fd 6c 01 b8 fd 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 3969.152129] xpad-dbg: 00000020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +``` + +Save dmesg buffer and attach to bug report, don't forget to describe button sequences in bug report. +`dmesg --level=debug > dmesg.txt` + +Ctrl+C to close interactive console sessions when finished. + +# Sending Upstream + +1. `git format-patch --cover-letter upstream..master` +2. `git send-email --to xxx *.patch` diff --git a/stress_urb_out.sh b/stress_urb_out.sh new file mode 100755 index 0000000..2e5c235 --- /dev/null +++ b/stress_urb_out.sh @@ -0,0 +1,10 @@ +#!/bin/sh +# stress test irq_urb_out. provokes URB request dropping. +# script by Laura Abbott +# see: http://www.spinics.net/lists/linux-input/msg40477.html + +while true; do + for i in $(seq 0 5); do + echo $i > /sys/class/leds/xpad0/subsystem/xpad0/brightness + done +done diff --git a/xpad.c b/xpad.c index 4d0e581..e7439ec 100644 --- a/xpad.c +++ b/xpad.c @@ -60,7 +60,7 @@ * * Later changes can be tracked in SCM. */ - +// #define DEBUG #include #include #include @@ -69,9 +69,15 @@ #include #include #include +#include #define XPAD_PKT_LEN 64 +/* The Guitar Hero Live (GHL) Xbox One dongles require a poke + * every 8 seconds. + */ +#define GHL_GUITAR_POKE_INTERVAL 8 /* In seconds */ + /* * xbox d-pads should map to buttons, as is required for DDR pads * but we map them to axes when possible to simplify things @@ -101,6 +107,13 @@ #define PKT_XBE2_FW_5_EARLY 3 #define PKT_XBE2_FW_5_11 4 +#define QUIRK_360_START_PKT_1 (1 << 0) +#define QUIRK_360_START_PKT_2 (1 << 1) +#define QUIRK_360_START_PKT_3 (1 << 2) +#define QUIRK_GHL_XBOXONE (1 << 3) +#define QUIRK_360_START (QUIRK_360_START_PKT_1 | \ + QUIRK_360_START_PKT_2 | QUIRK_360_START_PKT_3) + static bool dpad_to_buttons; module_param(dpad_to_buttons, bool, S_IRUGO); MODULE_PARM_DESC(dpad_to_buttons, "Map D-PAD to buttons rather than axes for unknown pads"); @@ -123,7 +136,7 @@ static const struct xpad_device { char *name; u8 mapping; u8 xtype; - u8 packet_type; + u8 quirks; } xpad_device[] = { { 0x0079, 0x18d4, "GPD Win 2 X-Box Controller", 0, XTYPE_XBOX360 }, { 0x03eb, 0xff01, "Wooting One (Legacy)", 0, XTYPE_XBOX360 }, @@ -157,6 +170,7 @@ static const struct xpad_device { { 0x046d, 0xca8a, "Logitech Precision Vibration Feedback Wheel", 0, XTYPE_XBOX }, { 0x046d, 0xcaa3, "Logitech DriveFx Racing Wheel", 0, XTYPE_XBOX360 }, { 0x056e, 0x2004, "Elecom JC-U3613M", 0, XTYPE_XBOX360 }, + { 0x05ac, 0x055b, "Gamesir-G3w", 0, XTYPE_XBOX360, QUIRK_360_START }, { 0x05fd, 0x1007, "Mad Catz Controller (unverified)", 0, XTYPE_XBOX }, { 0x05fd, 0x107a, "InterAct 'PowerPad Pro' X-Box pad (Germany)", 0, XTYPE_XBOX }, { 0x05fe, 0x3030, "Chic Controller", 0, XTYPE_XBOX }, @@ -166,6 +180,7 @@ static const struct xpad_device { { 0x06a3, 0x0200, "Saitek Racing Wheel", 0, XTYPE_XBOX }, { 0x06a3, 0x0201, "Saitek Adrenalin", 0, XTYPE_XBOX }, { 0x06a3, 0xf51a, "Saitek P3600", 0, XTYPE_XBOX360 }, + { 0x0738, 0x4503, "Mad Catz Racing Wheel", 0, XTYPE_XBOXONE }, { 0x0738, 0x4506, "Mad Catz 4506 Wireless Controller", 0, XTYPE_XBOX }, { 0x0738, 0x4516, "Mad Catz Control Pad", 0, XTYPE_XBOX }, { 0x0738, 0x4520, "Mad Catz Control Pad Pro", 0, XTYPE_XBOX }, @@ -261,18 +276,21 @@ static const struct xpad_device { { 0x0f0d, 0x0067, "HORIPAD ONE", 0, XTYPE_XBOXONE }, { 0x0f0d, 0x0078, "Hori Real Arcade Pro V Kai Xbox One", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOXONE }, { 0x0f0d, 0x00c5, "Hori Fighting Commander ONE", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOXONE }, + { 0x0f0d, 0x00dc, "HORIPAD FPS for Nintendo Switch", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360, QUIRK_360_START_PKT_1 }, { 0x0f30, 0x010b, "Philips Recoil", 0, XTYPE_XBOX }, { 0x0f30, 0x0202, "Joytech Advanced Controller", 0, XTYPE_XBOX }, { 0x0f30, 0x8888, "BigBen XBMiniPad Controller", 0, XTYPE_XBOX }, { 0x102c, 0xff0c, "Joytech Wireless Advanced Controller", 0, XTYPE_XBOX }, { 0x1038, 0x1430, "SteelSeries Stratus Duo", 0, XTYPE_XBOX360 }, { 0x1038, 0x1431, "SteelSeries Stratus Duo", 0, XTYPE_XBOX360 }, + { 0x10f5, 0x7005, "Turtle Beach Recon Controller", 0, XTYPE_XBOXONE }, { 0x11c9, 0x55f0, "Nacon GC-100XF", 0, XTYPE_XBOX360 }, { 0x1209, 0x2882, "Ardwiino Controller", 0, XTYPE_XBOX360 }, { 0x12ab, 0x0004, "Honey Bee Xbox360 dancepad", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360 }, { 0x12ab, 0x0301, "PDP AFTERGLOW AX.1", 0, XTYPE_XBOX360 }, { 0x12ab, 0x0303, "Mortal Kombat Klassic FightStick", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 }, { 0x12ab, 0x8809, "Xbox DDR dancepad", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX }, + { 0x1430, 0x079B, "RedOctane GHL Controller", 0, XTYPE_XBOXONE, QUIRK_GHL_XBOXONE }, { 0x1430, 0x4748, "RedOctane Guitar Hero X-plorer", 0, XTYPE_XBOX360 }, { 0x1430, 0x8888, "TX6500+ Dance Pad (first generation)", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX }, { 0x1430, 0xf801, "RedOctane Controller", 0, XTYPE_XBOX360 }, @@ -281,6 +299,7 @@ static const struct xpad_device { { 0x1532, 0x0037, "Razer Sabertooth", 0, XTYPE_XBOX360 }, { 0x1532, 0x0a00, "Razer Atrox Arcade Stick", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOXONE }, { 0x1532, 0x0a03, "Razer Wildcat", 0, XTYPE_XBOXONE }, + { 0x1532, 0x0a29, "Razer Wolverine v2", 0, XTYPE_XBOXONE }, { 0x15e4, 0x3f00, "Power A Mini Pro Elite", 0, XTYPE_XBOX360 }, { 0x15e4, 0x3f0a, "Xbox Airflo wired controller", 0, XTYPE_XBOX360 }, { 0x15e4, 0x3f10, "Batarang Xbox 360 controller", 0, XTYPE_XBOX360 }, @@ -348,21 +367,30 @@ static const struct xpad_device { { 0x24c6, 0x550e, "Hori Real Arcade Pro V Kai 360", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 }, { 0x24c6, 0x551a, "PowerA FUSION Pro Controller", 0, XTYPE_XBOXONE }, { 0x24c6, 0x561a, "PowerA FUSION Controller", 0, XTYPE_XBOXONE }, + { 0x24c6, 0x581a, "ThrustMaster XB1 Classic Controller", 0, XTYPE_XBOXONE }, { 0x24c6, 0x5b00, "ThrustMaster Ferrari 458 Racing Wheel", 0, XTYPE_XBOX360 }, { 0x24c6, 0x5b02, "Thrustmaster, Inc. GPX Controller", 0, XTYPE_XBOX360 }, { 0x24c6, 0x5b03, "Thrustmaster Ferrari 458 Racing Wheel", 0, XTYPE_XBOX360 }, { 0x24c6, 0x5d04, "Razer Sabertooth", 0, XTYPE_XBOX360 }, { 0x24c6, 0xfafe, "Rock Candy Gamepad for Xbox 360", 0, XTYPE_XBOX360 }, { 0x2563, 0x058d, "OneXPlayer Gamepad", 0, XTYPE_XBOX360 }, - { 0x2dc8, 0x2000, "8BitDo Pro 2 Wired Controller fox Xbox", 0, XTYPE_XBOXONE }, + { 0x2dc8, 0x2000, "8BitDo Pro 2 Wired Controller for Xbox", MAP_SELECT_BUTTON, XTYPE_XBOXONE }, + { 0x2dc8, 0x3106, "8BitDo Ultimate Wireless / Pro 2 Wired Controller", 0, XTYPE_XBOX360 }, + { 0x2dc8, 0x3109, "8BitDo Ultimate Wireless Bluetooth", 0, XTYPE_XBOX360 }, + { 0x2e95, 0x0504, "SCUF Gaming Controller", MAP_SELECT_BUTTON, XTYPE_XBOXONE }, { 0x31e3, 0x1100, "Wooting One", 0, XTYPE_XBOX360 }, { 0x31e3, 0x1200, "Wooting Two", 0, XTYPE_XBOX360 }, { 0x31e3, 0x1210, "Wooting Lekker", 0, XTYPE_XBOX360 }, { 0x31e3, 0x1220, "Wooting Two HE", 0, XTYPE_XBOX360 }, + { 0x31e3, 0x1230, "Wooting Two HE (ARM)", 0, XTYPE_XBOX360 }, { 0x31e3, 0x1300, "Wooting 60HE (AVR)", 0, XTYPE_XBOX360 }, { 0x31e3, 0x1310, "Wooting 60HE (ARM)", 0, XTYPE_XBOX360 }, { 0x3285, 0x0607, "Nacon GC-100", 0, XTYPE_XBOX360 }, + { 0x3285, 0x0614, "Nacon Pro Compact", 0, XTYPE_XBOXONE }, + { 0x3537, 0x1004, "GameSir T4 Kaleid", 0, XTYPE_XBOX360 }, + { 0x3537, 0x100A, "GameSir-G7 SE", 0, XTYPE_XBOXONE }, { 0x3767, 0x0101, "Fanatec Speedster 3 Forceshock Wheel", 0, XTYPE_XBOX }, + { 0x413d, 0x2104, "Black Shark Green Ghost Gamepad", 0, XTYPE_XBOX360 }, { 0xffff, 0xffff, "Chinese-made Xbox Controller", 0, XTYPE_XBOX }, { 0x0000, 0x0000, "Generic X-Box pad", 0, XTYPE_UNKNOWN } }; @@ -424,6 +452,12 @@ static const signed short xpad_btn_paddles[] = { -1 /* terminating entry */ }; +/* used for GHL dpad mapping */ +static const struct {int x; int y; } dpad_mapping[] = { + {0, -1}, {1, -1}, {1, 0}, {1, 1}, {0, 1}, {-1, 1}, {-1, 0}, {-1, -1}, + {0, 0} +}; + /* * Xbox 360 has a vendor-specific class, so we cannot match it with only * USB_INTERFACE_INFO (also specifically refused by USB subsystem), so we @@ -470,10 +504,12 @@ static const struct usb_device_id xpad_table[] = { XPAD_XBOX360_VENDOR(0x0f0d), /* Hori Controllers */ XPAD_XBOXONE_VENDOR(0x0f0d), /* Hori Controllers */ XPAD_XBOX360_VENDOR(0x1038), /* SteelSeries Controllers */ + XPAD_XBOXONE_VENDOR(0x10f5), /* Turtle Beach */ XPAD_XBOX360_VENDOR(0x11c9), /* Nacon GC100XF */ XPAD_XBOX360_VENDOR(0x1209), /* Ardwiino Controllers */ XPAD_XBOX360_VENDOR(0x12ab), /* X-Box 360 dance pads */ XPAD_XBOX360_VENDOR(0x1430), /* RedOctane X-Box 360 controllers */ + XPAD_XBOXONE_VENDOR(0x1430), /* RedOctane X-Box One controllers */ XPAD_XBOX360_VENDOR(0x146b), /* BigBen Interactive Controllers */ XPAD_XBOX360_VENDOR(0x1532), /* Razer Sabertooth */ XPAD_XBOXONE_VENDOR(0x1532), /* Razer Wildcat */ @@ -489,10 +525,16 @@ static const struct usb_device_id xpad_table[] = { XPAD_XBOX360_VENDOR(0x2563), /* OneXPlayer Gamepad */ XPAD_XBOX360_VENDOR(0x260d), /* Dareu H101 */ XPAD_XBOXONE_VENDOR(0x2dc8), /* 8BitDo Pro 2 Wired Controller for Xbox */ + XPAD_XBOX360_VENDOR(0x2dc8), /* 8BitDo Ultimate Wireless Controller */ XPAD_XBOXONE_VENDOR(0x2e24), /* Hyperkin Duke X-Box One pad */ + XPAD_XBOXONE_VENDOR(0x2e95), /* SCUF Gaming Controller */ XPAD_XBOX360_VENDOR(0x2f24), /* GameSir Controllers */ + XPAD_XBOX360_VENDOR(0x3537), /* GameSir Controllers */ + XPAD_XBOXONE_VENDOR(0x3537), /* GameSir Controllers */ XPAD_XBOX360_VENDOR(0x31e3), /* Wooting Keyboards */ XPAD_XBOX360_VENDOR(0x3285), /* Nacon GC-100 */ + XPAD_XBOXONE_VENDOR(0x3285), /* Nacon XBOX Series S/X Controllers */ + XPAD_XBOX360_VENDOR(0x413d), /* Black Shark Green Ghost Controller */ { } }; @@ -513,13 +555,52 @@ struct xboxone_init_packet { .len = ARRAY_SIZE(_data), \ } +/* + * starting with xbox one, the game input protocol is used + * magic numbers are taken from + * - https://github.com/xpadneo/gip-dissector/blob/main/src/gip-dissector.lua + * - https://github.com/medusalix/xone/blob/master/bus/protocol.c + */ +#define GIP_CMD_ACK 0x01 +#define GIP_CMD_IDENTIFY 0x04 +#define GIP_CMD_POWER 0x05 +#define GIP_CMD_AUTHENTICATE 0x06 +#define GIP_CMD_VIRTUAL_KEY 0x07 +#define GIP_CMD_RUMBLE 0x09 +#define GIP_CMD_LED 0x0a +#define GIP_CMD_FIRMWARE 0x0c +#define GIP_CMD_INPUT 0x20 + +#define GIP_SEQ0 0x00 + +#define GIP_OPT_ACK 0x10 +#define GIP_OPT_INTERNAL 0x20 + +/* + * length of the command payload encoded with + * https://en.wikipedia.org/wiki/LEB128 + * which is a no-op for N < 128 + */ +#define GIP_PL_LEN(N) (N) + +/* + * payload specific defines + */ +#define GIP_PWR_ON 0x00 +#define GIP_LED_ON 0x01 + +#define GIP_MOTOR_R BIT(0) +#define GIP_MOTOR_L BIT(1) +#define GIP_MOTOR_RT BIT(2) +#define GIP_MOTOR_LT BIT(3) +#define GIP_MOTOR_ALL (GIP_MOTOR_R | GIP_MOTOR_L | GIP_MOTOR_RT | GIP_MOTOR_LT) /* * This packet is required for all Xbox One pads with 2015 * or later firmware installed (or present from the factory). */ -static const u8 xboxone_fw2015_init[] = { - 0x05, 0x20, 0x00, 0x01, 0x00 +static const u8 xboxone_power_on[] = { + GIP_CMD_POWER, GIP_OPT_INTERNAL, GIP_SEQ0, GIP_PL_LEN(1), GIP_PWR_ON }; /* @@ -529,7 +610,7 @@ static const u8 xboxone_fw2015_init[] = { * Bluetooth mode. */ static const u8 xboxone_s_init[] = { - 0x05, 0x20, 0x00, 0x0f, 0x06 + GIP_CMD_POWER, GIP_OPT_INTERNAL, GIP_SEQ0, 0x0f, 0x06 }; /* @@ -546,9 +627,9 @@ static const u8 extra_input_packet_init[] = { * (0x0e6f:0x0165) to finish initialization and for Hori pads * (0x0f0d:0x0067) to make the analog sticks work. */ -static const u8 xboxone_hori_init[] = { - 0x01, 0x20, 0x00, 0x09, 0x00, 0x04, 0x20, 0x3a, - 0x00, 0x00, 0x00, 0x80, 0x00 +static const u8 xboxone_hori_ack_id[] = { + GIP_CMD_ACK, GIP_OPT_INTERNAL, GIP_SEQ0, GIP_PL_LEN(9), + 0x00, GIP_CMD_IDENTIFY, GIP_OPT_INTERNAL, 0x3a, 0x00, 0x00, 0x00, 0x80, 0x00 }; /* @@ -556,8 +637,8 @@ static const u8 xboxone_hori_init[] = { * sending input reports. These pads include: (0x0e6f:0x02ab), * (0x0e6f:0x02a4), (0x0e6f:0x02a6). */ -static const u8 xboxone_pdp_init1[] = { - 0x0a, 0x20, 0x00, 0x03, 0x00, 0x01, 0x14 +static const u8 xboxone_pdp_led_on[] = { + GIP_CMD_LED, GIP_OPT_INTERNAL, GIP_SEQ0, GIP_PL_LEN(3), 0x00, GIP_LED_ON, 0x14 }; /* @@ -565,8 +646,8 @@ static const u8 xboxone_pdp_init1[] = { * sending input reports. These pads include: (0x0e6f:0x02ab), * (0x0e6f:0x02a4), (0x0e6f:0x02a6). */ -static const u8 xboxone_pdp_init2[] = { - 0x06, 0x20, 0x00, 0x02, 0x01, 0x00 +static const u8 xboxone_pdp_auth[] = { + GIP_CMD_AUTHENTICATE, GIP_OPT_INTERNAL, GIP_SEQ0, GIP_PL_LEN(2), 0x01, 0x00 }; /* @@ -574,8 +655,8 @@ static const u8 xboxone_pdp_init2[] = { * sending input reports. One of those pads is (0x24c6:0x543a). */ static const u8 xboxone_rumblebegin_init[] = { - 0x09, 0x00, 0x00, 0x09, 0x00, 0x0F, 0x00, 0x00, - 0x1D, 0x1D, 0xFF, 0x00, 0x00 + GIP_CMD_RUMBLE, 0x00, GIP_SEQ0, GIP_PL_LEN(9), + 0x00, GIP_MOTOR_ALL, 0x00, 0x00, 0x1D, 0x1D, 0xFF, 0x00, 0x00 }; /* @@ -585,8 +666,13 @@ static const u8 xboxone_rumblebegin_init[] = { * spin up to enough speed to actually vibrate the gamepad. */ static const u8 xboxone_rumbleend_init[] = { - 0x09, 0x00, 0x00, 0x09, 0x00, 0x0F, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00 + GIP_CMD_RUMBLE, 0x00, GIP_SEQ0, GIP_PL_LEN(9), + 0x00, GIP_MOTOR_ALL, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +/* GHL Xbox One magic data */ +static const char ghl_xboxone_magic_data[] = { + 0x22, 0x00, 0x00, 0x08, 0x02, 0x08, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00 }; /* @@ -596,14 +682,17 @@ static const u8 xboxone_rumbleend_init[] = { * packet is going to be sent. */ static const struct xboxone_init_packet xboxone_init_packets[] = { - XBOXONE_INIT_PKT(0x0e6f, 0x0165, xboxone_hori_init), - XBOXONE_INIT_PKT(0x0f0d, 0x0067, xboxone_hori_init), - XBOXONE_INIT_PKT(0x0000, 0x0000, xboxone_fw2015_init), + XBOXONE_INIT_PKT(0x0e6f, 0x0165, xboxone_hori_ack_id), + XBOXONE_INIT_PKT(0x0f0d, 0x0067, xboxone_hori_ack_id), + XBOXONE_INIT_PKT(0x1430, 0x079b, xboxone_hori_ack_id), + XBOXONE_INIT_PKT(0x0000, 0x0000, xboxone_power_on), XBOXONE_INIT_PKT(0x045e, 0x02ea, xboxone_s_init), XBOXONE_INIT_PKT(0x045e, 0x0b00, xboxone_s_init), XBOXONE_INIT_PKT(0x045e, 0x0b00, extra_input_packet_init), - XBOXONE_INIT_PKT(0x0e6f, 0x0000, xboxone_pdp_init1), - XBOXONE_INIT_PKT(0x0e6f, 0x0000, xboxone_pdp_init2), + XBOXONE_INIT_PKT(0x0e6f, 0x0000, xboxone_pdp_led_on), + XBOXONE_INIT_PKT(0x1430, 0x079b, xboxone_pdp_led_on), + XBOXONE_INIT_PKT(0x0e6f, 0x0000, xboxone_pdp_auth), + XBOXONE_INIT_PKT(0x1430, 0x079b, xboxone_pdp_auth), XBOXONE_INIT_PKT(0x24c6, 0x541a, xboxone_rumblebegin_init), XBOXONE_INIT_PKT(0x24c6, 0x542a, xboxone_rumblebegin_init), XBOXONE_INIT_PKT(0x24c6, 0x543a, xboxone_rumblebegin_init), @@ -660,9 +749,13 @@ struct usb_xpad { int xtype; /* type of xbox device */ int packet_type; /* type of the extended packet */ int pad_nr; /* the order x360 pads were attached */ + int quirks; const char *name; /* name of the device */ struct work_struct work; /* init/remove device from callback */ + struct delayed_work poweroff_work; /* work struct for poweroff on mode long press */ time64_t mode_btn_down_ts; + struct urb *ghl_urb; /* URB for GHL Xbox One magic data */ + struct timer_list ghl_poke_timer; /* Timer for periodic poke of GHL magic data */ }; static int xpad_init_input(struct usb_xpad *xpad); @@ -670,6 +763,63 @@ static void xpad_deinit_input(struct usb_xpad *xpad); static void xpadone_ack_mode_report(struct usb_xpad *xpad, u8 seq_num); static void xpad360w_poweroff_controller(struct usb_xpad *xpad); +/* + * ghl_magic_poke_cb + * + * Call back function that resets the timer for the next magic data poke. + */ +static void ghl_magic_poke_cb(struct urb *urb) +{ + struct usb_xpad *xpad = urb->context; + + if (urb->status < 0) + pr_warn("URB transfer failed.\n"); + + mod_timer(&xpad->ghl_poke_timer, jiffies + GHL_GUITAR_POKE_INTERVAL*HZ); +} + +/* + * ghl_magic_poke + * + * Submits the GHL magic_data URB. + */ +static void ghl_magic_poke(struct timer_list *t) +{ + int ret; + struct usb_xpad *xpad = from_timer(xpad, t, ghl_poke_timer); + + ret = usb_submit_urb(xpad->ghl_urb, GFP_ATOMIC); + if (ret < 0) + pr_warn("URB transfer failed.\n"); +} + +/* + * ghl_init_urb + * + * Prepares the interrupt URB for GHL magic_data. + */ +static int ghl_init_urb(struct usb_xpad *xpad, struct usb_device *usbdev, + const char ghl_magic_data[], u16 poke_size, struct usb_endpoint_descriptor *ep_irq_out) +{ + u8 *databuf; + unsigned int pipe; + + pipe = usb_sndintpipe(usbdev, ep_irq_out->bEndpointAddress); + + databuf = devm_kzalloc(&xpad->udev->dev, poke_size, GFP_ATOMIC); + if (databuf == NULL) + return -ENOMEM; + + memcpy(databuf, ghl_magic_data, poke_size); + + usb_fill_int_urb( + xpad->ghl_urb, usbdev, pipe, + databuf, poke_size, + ghl_magic_poke_cb, xpad, ep_irq_out->bInterval); + + return 0; +} + /* * xpad_process_packet * @@ -709,10 +859,10 @@ static void xpad_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char *d /* digital pad */ if (xpad->mapping & MAP_DPAD_TO_BUTTONS) { /* dpad as buttons (left, right, up, down) */ - input_report_key(dev, BTN_TRIGGER_HAPPY1, data[2] & 0x04); - input_report_key(dev, BTN_TRIGGER_HAPPY2, data[2] & 0x08); - input_report_key(dev, BTN_TRIGGER_HAPPY3, data[2] & 0x01); - input_report_key(dev, BTN_TRIGGER_HAPPY4, data[2] & 0x02); + input_report_key(dev, BTN_TRIGGER_HAPPY1, data[2] & BIT(2)); + input_report_key(dev, BTN_TRIGGER_HAPPY2, data[2] & BIT(3)); + input_report_key(dev, BTN_TRIGGER_HAPPY3, data[2] & BIT(0)); + input_report_key(dev, BTN_TRIGGER_HAPPY4, data[2] & BIT(1)); } else { input_report_abs(dev, ABS_HAT0X, !!(data[2] & 0x08) - !!(data[2] & 0x04)); @@ -721,10 +871,10 @@ static void xpad_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char *d } /* start/back buttons and stick press left/right */ - input_report_key(dev, BTN_START, data[2] & 0x10); - input_report_key(dev, BTN_SELECT, data[2] & 0x20); - input_report_key(dev, BTN_THUMBL, data[2] & 0x40); - input_report_key(dev, BTN_THUMBR, data[2] & 0x80); + input_report_key(dev, BTN_START, data[2] & BIT(4)); + input_report_key(dev, BTN_SELECT, data[2] & BIT(5)); + input_report_key(dev, BTN_THUMBL, data[2] & BIT(6)); + input_report_key(dev, BTN_THUMBR, data[2] & BIT(7)); /* "analog" buttons A, B, X, Y */ input_report_key(dev, BTN_A, data[4]); @@ -759,10 +909,10 @@ static void xpad360_process_packet(struct usb_xpad *xpad, struct input_dev *dev, /* digital pad */ if (xpad->mapping & MAP_DPAD_TO_BUTTONS) { /* dpad as buttons (left, right, up, down) */ - input_report_key(dev, BTN_TRIGGER_HAPPY1, data[2] & 0x04); - input_report_key(dev, BTN_TRIGGER_HAPPY2, data[2] & 0x08); - input_report_key(dev, BTN_TRIGGER_HAPPY3, data[2] & 0x01); - input_report_key(dev, BTN_TRIGGER_HAPPY4, data[2] & 0x02); + input_report_key(dev, BTN_TRIGGER_HAPPY1, data[2] & BIT(2)); + input_report_key(dev, BTN_TRIGGER_HAPPY2, data[2] & BIT(3)); + input_report_key(dev, BTN_TRIGGER_HAPPY3, data[2] & BIT(0)); + input_report_key(dev, BTN_TRIGGER_HAPPY4, data[2] & BIT(1)); } /* @@ -780,21 +930,21 @@ static void xpad360_process_packet(struct usb_xpad *xpad, struct input_dev *dev, } /* start/back buttons */ - input_report_key(dev, BTN_START, data[2] & 0x10); - input_report_key(dev, BTN_SELECT, data[2] & 0x20); + input_report_key(dev, BTN_START, data[2] & BIT(4)); + input_report_key(dev, BTN_SELECT, data[2] & BIT(5)); /* stick press left/right */ - input_report_key(dev, BTN_THUMBL, data[2] & 0x40); - input_report_key(dev, BTN_THUMBR, data[2] & 0x80); + input_report_key(dev, BTN_THUMBL, data[2] & BIT(6)); + input_report_key(dev, BTN_THUMBR, data[2] & BIT(7)); /* buttons A,B,X,Y,TL,TR and MODE */ - input_report_key(dev, BTN_A, data[3] & 0x10); - input_report_key(dev, BTN_B, data[3] & 0x20); - input_report_key(dev, BTN_X, data[3] & 0x40); - input_report_key(dev, BTN_Y, data[3] & 0x80); - input_report_key(dev, BTN_TL, data[3] & 0x01); - input_report_key(dev, BTN_TR, data[3] & 0x02); - input_report_key(dev, BTN_MODE, data[3] & 0x04); + input_report_key(dev, BTN_A, data[3] & BIT(4)); + input_report_key(dev, BTN_B, data[3] & BIT(5)); + input_report_key(dev, BTN_X, data[3] & BIT(6)); + input_report_key(dev, BTN_Y, data[3] & BIT(7)); + input_report_key(dev, BTN_TL, data[3] & BIT(0)); + input_report_key(dev, BTN_TR, data[3] & BIT(1)); + input_report_key(dev, BTN_MODE, data[3] & BIT(2)); if (!(xpad->mapping & MAP_STICKS_TO_NULL)) { /* left stick */ @@ -823,20 +973,29 @@ static void xpad360_process_packet(struct usb_xpad *xpad, struct input_dev *dev, /* XBOX360W controllers can't be turned off without driver assistance */ if (xpad->xtype == XTYPE_XBOX360W) { - if (xpad->mode_btn_down_ts > 0 && xpad->pad_present && - ((ktime_get_seconds() - xpad->mode_btn_down_ts) >= - XPAD360W_POWEROFF_TIMEOUT)) { - xpad360w_poweroff_controller(xpad); - xpad->mode_btn_down_ts = 0; - return; + if (data[3] & BIT(2)) { + if (xpad->mode_btn_down_ts == 0) + xpad->mode_btn_down_ts = ktime_get_seconds(); + schedule_delayed_work(&xpad->poweroff_work, msecs_to_jiffies(0)); + } else { + xpad->mode_btn_down_ts = 0; } + } +} - /* mode button down/up */ - if (data[3] & 0x04) - xpad->mode_btn_down_ts = ktime_get_seconds(); - else - xpad->mode_btn_down_ts = 0; +static void xpad360w_poweroff_work(struct work_struct *work) { + struct usb_xpad *xpad = container_of(to_delayed_work(work), struct usb_xpad, poweroff_work); + + if (xpad->mode_btn_down_ts == 0) + return; + + if ((ktime_get_seconds() - xpad->mode_btn_down_ts) >= XPAD360W_POWEROFF_TIMEOUT) { + xpad360w_poweroff_controller(xpad); + xpad->mode_btn_down_ts = 0; + return; } + + schedule_delayed_work(&xpad->poweroff_work, msecs_to_jiffies(200)); } static void xpad_presence_work(struct work_struct *work) @@ -917,21 +1076,22 @@ static void xpadone_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char { struct input_dev *dev = xpad->dev; bool do_sync = false; + int dpad_value; /* the xbox button has its own special report */ - if (data[0] == 0X07) { + if (data[0] == GIP_CMD_VIRTUAL_KEY) { /* * The Xbox One S controller requires these reports to be * acked otherwise it continues sending them forever and * won't report further mode button events. */ - if (data[1] == 0x30) + if (data[1] == (GIP_OPT_ACK | GIP_OPT_INTERNAL)) xpadone_ack_mode_report(xpad, data[2]); - input_report_key(dev, BTN_MODE, data[4] & 0x01); + input_report_key(dev, BTN_MODE, data[4] & BIT(0)); do_sync = true; - } else if (data[0] == 0X0C) { + } else if (data[0] == GIP_CMD_FIRMWARE) { /* Some packet formats force us to use this separate to poll paddle inputs */ if (xpad->packet_type == PKT_XBE2_FW_5_11) { /* Mute paddles if controller is in a custom profile slot @@ -942,33 +1102,33 @@ static void xpadone_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char data[18] = 0; /* Elite Series 2 split packet paddle bits */ - input_report_key(dev, BTN_TRIGGER_HAPPY5, data[18] & 0x01); - input_report_key(dev, BTN_TRIGGER_HAPPY6, data[18] & 0x02); - input_report_key(dev, BTN_TRIGGER_HAPPY7, data[18] & 0x04); - input_report_key(dev, BTN_TRIGGER_HAPPY8, data[18] & 0x08); + input_report_key(dev, BTN_TRIGGER_HAPPY5, data[18] & BIT(0)); + input_report_key(dev, BTN_TRIGGER_HAPPY6, data[18] & BIT(1)); + input_report_key(dev, BTN_TRIGGER_HAPPY7, data[18] & BIT(2)); + input_report_key(dev, BTN_TRIGGER_HAPPY8, data[18] & BIT(3)); do_sync = true; } - } else if (data[0] == 0X20) { /* The main valid packet type for inputs */ + } else if (data[0] == GIP_CMD_INPUT) { /* The main valid packet type for inputs */ /* menu/view buttons */ - input_report_key(dev, BTN_START, data[4] & 0x04); - input_report_key(dev, BTN_SELECT, data[4] & 0x08); + input_report_key(dev, BTN_START, data[4] & BIT(2)); + input_report_key(dev, BTN_SELECT, data[4] & BIT(3)); if (xpad->mapping & MAP_SELECT_BUTTON) - input_report_key(dev, KEY_RECORD, data[22] & 0x01); + input_report_key(dev, KEY_RECORD, data[22] & BIT(0) || /* 8BitDo: */ data[18] & BIT(0)); /* buttons A,B,X,Y */ - input_report_key(dev, BTN_A, data[4] & 0x10); - input_report_key(dev, BTN_B, data[4] & 0x20); - input_report_key(dev, BTN_X, data[4] & 0x40); - input_report_key(dev, BTN_Y, data[4] & 0x80); + input_report_key(dev, BTN_A, data[4] & BIT(4)); + input_report_key(dev, BTN_B, data[4] & BIT(5)); + input_report_key(dev, BTN_X, data[4] & BIT(6)); + input_report_key(dev, BTN_Y, data[4] & BIT(7)); /* digital pad */ if (xpad->mapping & MAP_DPAD_TO_BUTTONS) { /* dpad as buttons (left, right, up, down) */ - input_report_key(dev, BTN_TRIGGER_HAPPY1, data[5] & 0x04); - input_report_key(dev, BTN_TRIGGER_HAPPY2, data[5] & 0x08); - input_report_key(dev, BTN_TRIGGER_HAPPY3, data[5] & 0x01); - input_report_key(dev, BTN_TRIGGER_HAPPY4, data[5] & 0x02); + input_report_key(dev, BTN_TRIGGER_HAPPY1, data[5] & BIT(2)); + input_report_key(dev, BTN_TRIGGER_HAPPY2, data[5] & BIT(3)); + input_report_key(dev, BTN_TRIGGER_HAPPY3, data[5] & BIT(0)); + input_report_key(dev, BTN_TRIGGER_HAPPY4, data[5] & BIT(1)); } else { input_report_abs(dev, ABS_HAT0X, !!(data[5] & 0x08) - !!(data[5] & 0x04)); @@ -977,12 +1137,12 @@ static void xpadone_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char } /* TL/TR */ - input_report_key(dev, BTN_TL, data[5] & 0x10); - input_report_key(dev, BTN_TR, data[5] & 0x20); + input_report_key(dev, BTN_TL, data[5] & BIT(4)); + input_report_key(dev, BTN_TR, data[5] & BIT(5)); /* stick press left/right */ - input_report_key(dev, BTN_THUMBL, data[5] & 0x40); - input_report_key(dev, BTN_THUMBR, data[5] & 0x80); + input_report_key(dev, BTN_THUMBL, data[5] & BIT(6)); + input_report_key(dev, BTN_THUMBR, data[5] & BIT(7)); if (!(xpad->mapping & MAP_STICKS_TO_NULL)) { /* left stick */ @@ -1023,10 +1183,10 @@ static void xpadone_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char data[32] = 0; /* OG Elite Series Controller paddle bits */ - input_report_key(dev, BTN_TRIGGER_HAPPY5, data[32] & 0x02); - input_report_key(dev, BTN_TRIGGER_HAPPY6, data[32] & 0x08); - input_report_key(dev, BTN_TRIGGER_HAPPY7, data[32] & 0x01); - input_report_key(dev, BTN_TRIGGER_HAPPY8, data[32] & 0x04); + input_report_key(dev, BTN_TRIGGER_HAPPY5, data[32] & BIT(1)); + input_report_key(dev, BTN_TRIGGER_HAPPY6, data[32] & BIT(3)); + input_report_key(dev, BTN_TRIGGER_HAPPY7, data[32] & BIT(0)); + input_report_key(dev, BTN_TRIGGER_HAPPY8, data[32] & BIT(2)); } else if (xpad->packet_type == PKT_XBE2_FW_OLD) { /* Mute paddles if controller has a custom mapping applied. * Checked by comparing the current mapping @@ -1036,10 +1196,10 @@ static void xpadone_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char data[18] = 0; /* Elite Series 2 4.x firmware paddle bits */ - input_report_key(dev, BTN_TRIGGER_HAPPY5, data[18] & 0x01); - input_report_key(dev, BTN_TRIGGER_HAPPY6, data[18] & 0x02); - input_report_key(dev, BTN_TRIGGER_HAPPY7, data[18] & 0x04); - input_report_key(dev, BTN_TRIGGER_HAPPY8, data[18] & 0x08); + input_report_key(dev, BTN_TRIGGER_HAPPY5, data[18] & BIT(0)); + input_report_key(dev, BTN_TRIGGER_HAPPY6, data[18] & BIT(1)); + input_report_key(dev, BTN_TRIGGER_HAPPY7, data[18] & BIT(2)); + input_report_key(dev, BTN_TRIGGER_HAPPY8, data[18] & BIT(3)); } else if (xpad->packet_type == PKT_XBE2_FW_5_EARLY) { /* Mute paddles if controller has a custom mapping applied. * Checked by comparing the current mapping @@ -1051,13 +1211,55 @@ static void xpadone_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char /* Elite Series 2 5.x firmware paddle bits * (before the packet was split) */ - input_report_key(dev, BTN_TRIGGER_HAPPY5, data[22] & 0x01); - input_report_key(dev, BTN_TRIGGER_HAPPY6, data[22] & 0x02); - input_report_key(dev, BTN_TRIGGER_HAPPY7, data[22] & 0x04); - input_report_key(dev, BTN_TRIGGER_HAPPY8, data[22] & 0x08); + input_report_key(dev, BTN_TRIGGER_HAPPY5, data[22] & BIT(0)); + input_report_key(dev, BTN_TRIGGER_HAPPY6, data[22] & BIT(1)); + input_report_key(dev, BTN_TRIGGER_HAPPY7, data[22] & BIT(2)); + input_report_key(dev, BTN_TRIGGER_HAPPY8, data[22] & BIT(3)); } } + do_sync = true; + + } else if (data[0] == 0X21) { /* The main valid packet type for GHL inputs */ + /* Mapping chosen to be coherent with GHL dongles of other consoles */ + + /* The 6 fret buttons */ + input_report_key(dev, BTN_B, data[4] & BIT(1)); + input_report_key(dev, BTN_X, data[4] & BIT(2)); + input_report_key(dev, BTN_Y, data[4] & BIT(3)); + input_report_key(dev, BTN_A, data[4] & BIT(0)); + input_report_key(dev, BTN_TL, data[4] & BIT(4)); + input_report_key(dev, BTN_TR, data[4] & BIT(5)); + + /* D-pad */ + dpad_value = data[6] & 0xF; + if (dpad_value > 7) + dpad_value = 8; + + input_report_abs(dev, ABS_HAT0X, dpad_mapping[dpad_value].x); + input_report_abs(dev, ABS_HAT0Y, dpad_mapping[dpad_value].y); + + /* Strum bar */ + input_report_abs(dev, ABS_Y, ((data[8] - 0x80) << 9)); + + /* Tilt Sensor */ + input_report_abs(dev, ABS_Z, ((data[9] - 0x80) << 9)); + + /* Whammy bar */ + input_report_abs(dev, ABS_RZ, ((data[10] - 0x80) << 9)); + + /* Power Button */ + input_report_key(dev, BTN_THUMBR, data[5] & BIT(4)); + + /* GHTV button */ + input_report_key(dev, BTN_START, data[5] & BIT(2)); + + /* Hero Power button */ + input_report_key(dev, BTN_MODE, data[5] & BIT(0)); + + /* Pause button */ + input_report_key(dev, BTN_THUMBL, data[5] & BIT(1)); + do_sync = true; } @@ -1090,6 +1292,13 @@ static void xpad_irq_in(struct urb *urb) goto exit; } +#if defined(DEBUG_VERBOSE) + /* If you set rowsize to larger than 32 it defaults to 16? + * Otherwise I would set it to XPAD_PKT_LEN V + */ + print_hex_dump(KERN_DEBUG, "xpad-dbg: ", DUMP_PREFIX_OFFSET, 32, 1, xpad->idata, XPAD_PKT_LEN, 0); +#endif + switch (xpad->xtype) { case XTYPE_XBOX360: xpad360_process_packet(xpad, xpad->dev, 0, xpad->idata); @@ -1356,14 +1565,106 @@ static int xpad_start_xbox_one(struct usb_xpad *xpad) return retval; } +static int xpad_start_xbox_360(struct usb_xpad *xpad) +{ + int status; + + char *data = kzalloc(20, GFP_KERNEL); + + int TIMEOUT = 100; + + /* + this init sequence is needed for the gamesir g3w controller + and for shanwan controllers in xpad mode. + Unfortunately, in this mode they identify as 0x045e, 0x028e, so we + have to inspect the manufacturer string. + Sending this sequence to other controllers will break initialization. + */ + bool is_shanwan = xpad->udev->manufacturer && strcasecmp("shanwan", xpad->udev->manufacturer) == 0; + if (!(xpad->quirks & QUIRK_360_START) && !is_shanwan) { + status = 0; + goto err_free_ctrl_data; + } + + if ((xpad->quirks & QUIRK_360_START_PKT_1) || is_shanwan) { + status = usb_control_msg(xpad->udev, + usb_rcvctrlpipe(xpad->udev, 0), + 0x1, 0xc1, + cpu_to_le16(0x100), cpu_to_le16(0x0), data, cpu_to_le16(20), + TIMEOUT); + +#ifdef DEBUG + dev_dbg(&xpad->intf->dev, + "%s - control message 1 returned %d\n", __func__, status); +#endif + + if (status < 0) { + goto err_free_ctrl_data; + } +#ifdef DEBUG + else { + print_hex_dump(KERN_DEBUG, "xpad-dbg: ", DUMP_PREFIX_OFFSET, 32, 1, data, 20, 0); + } +#endif + } + + if ((xpad->quirks & QUIRK_360_START_PKT_2) || is_shanwan) { + status = usb_control_msg(xpad->udev, + usb_rcvctrlpipe(xpad->udev, 0), + 0x1, 0xc1, + cpu_to_le16(0x0), cpu_to_le16(0x0), data, cpu_to_le16(8), + TIMEOUT); +#ifdef DEBUG + dev_dbg(&xpad->intf->dev, + "%s - control message 2 returned %d\n", __func__, status); +#endif + + if (status < 0) { + goto err_free_ctrl_data; + } +#ifdef DEBUG + else { + print_hex_dump(KERN_DEBUG, "xpad-dbg: ", DUMP_PREFIX_OFFSET, 32, 1, data, 8, 0); + } +#endif + } + + if ((xpad->quirks & QUIRK_360_START_PKT_3) || is_shanwan) { + status = usb_control_msg(xpad->udev, + usb_rcvctrlpipe(xpad->udev, 0), + 0x1, 0xc0, + cpu_to_le16(0x0), cpu_to_le16(0x0), data, cpu_to_le16(4), + TIMEOUT); +#ifdef DEBUG + dev_dbg(&xpad->intf->dev, + "%s - control message 3 returned %d\n", __func__, status); +#endif + + if (status < 0) { + goto err_free_ctrl_data; + } +#ifdef DEBUG + else { + print_hex_dump(KERN_DEBUG, "xpad-dbg: ", DUMP_PREFIX_OFFSET, 32, 1, data, 4, 0); + } +#endif + } + + status = 0; + +err_free_ctrl_data: + kfree(data); + return status; +} + static void xpadone_ack_mode_report(struct usb_xpad *xpad, u8 seq_num) { unsigned long flags; struct xpad_output_packet *packet = &xpad->out_packets[XPAD_OUT_CMD_IDX]; static const u8 mode_report_ack[] = { - 0x01, 0x20, 0x00, 0x09, 0x00, 0x07, 0x20, 0x02, - 0x00, 0x00, 0x00, 0x00, 0x00 + GIP_CMD_ACK, GIP_OPT_INTERNAL, GIP_SEQ0, GIP_PL_LEN(9), + 0x00, GIP_CMD_VIRTUAL_KEY, GIP_OPT_INTERNAL, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00 }; spin_lock_irqsave(&xpad->odata_lock, flags); @@ -1441,14 +1742,14 @@ static int xpad_play_effect(struct input_dev *dev, void *data, struct ff_effect break; case XTYPE_XBOXONE: - packet->data[0] = 0x09; /* activate rumble */ + packet->data[0] = GIP_CMD_RUMBLE; /* activate rumble */ packet->data[1] = 0x00; packet->data[2] = xpad->odata_serial++; - packet->data[3] = 0x09; + packet->data[3] = GIP_PL_LEN(9); packet->data[4] = 0x00; - packet->data[5] = 0x0F; - packet->data[6] = 0x00; - packet->data[7] = 0x00; + packet->data[5] = GIP_MOTOR_ALL; + packet->data[6] = 0x00; /* left trigger */ + packet->data[7] = 0x00; /* right trigger */ packet->data[8] = strong / 512; /* left actuator */ packet->data[9] = weak / 512; /* right actuator */ packet->data[10] = 0xFF; /* on period */ @@ -1641,6 +1942,12 @@ static int xpad_start_input(struct usb_xpad *xpad) { int error; + if (xpad->xtype == XTYPE_XBOX360) { + error = xpad_start_xbox_360(xpad); + if (error) + return error; + } + if (usb_submit_urb(xpad->irq_in, GFP_KERNEL)) return -EIO; @@ -1711,6 +2018,8 @@ static int xpad360w_start_input(struct usb_xpad *xpad) return error; } + INIT_DELAYED_WORK(&xpad->poweroff_work, xpad360w_poweroff_work); + return 0; } @@ -1720,6 +2029,7 @@ static void xpad360w_stop_input(struct usb_xpad *xpad) /* Make sure we are done with presence work if it was scheduled */ flush_work(&xpad->work); + flush_delayed_work(&xpad->poweroff_work); } static int xpad_open(struct input_dev *dev) @@ -1743,15 +2053,29 @@ static void xpad_set_up_abs(struct input_dev *input_dev, signed short abs) switch (abs) { case ABS_X: case ABS_Y: + /* GHL Strum bar */ + if ((xpad->xtype == XTYPE_XBOXONE) && (xpad->quirks & QUIRK_GHL_XBOXONE)) { + input_set_abs_params(input_dev, abs, -32767, 32767, 0, 0); + break; + } case ABS_RX: case ABS_RY: /* the two sticks */ input_set_abs_params(input_dev, abs, -32768, 32767, 16, 128); break; case ABS_Z: + /* GHL Tilt sensor */ + if ((xpad->xtype == XTYPE_XBOXONE) && (xpad->quirks & QUIRK_GHL_XBOXONE)) { + input_set_abs_params(input_dev, abs, -32767, 32767, 0, 0); + break; + } case ABS_RZ: /* the triggers (if mapped to axes) */ - if (xpad->xtype == XTYPE_XBOXONE) - input_set_abs_params(input_dev, abs, 0, 1023, 0, 0); - else + if (xpad->xtype == XTYPE_XBOXONE) { + /* GHL Whammy bar */ + if (xpad->quirks & QUIRK_GHL_XBOXONE) + input_set_abs_params(input_dev, abs, -32767, 32767, 0, 0); + else + input_set_abs_params(input_dev, abs, 0, 1023, 0, 0); + } else input_set_abs_params(input_dev, abs, 0, 255, 0, 0); break; case ABS_HAT0X: @@ -1921,6 +2245,7 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id xpad->mapping = xpad_device[i].mapping; xpad->xtype = xpad_device[i].xtype; xpad->name = xpad_device[i].name; + xpad->quirks = xpad_device[i].quirks; xpad->packet_type = PKT_XB; INIT_WORK(&xpad->work, xpad_presence_work); @@ -2043,6 +2368,21 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id if (error) goto err_deinit_output; } + + if (xpad->quirks & QUIRK_GHL_XBOXONE) { + + xpad->ghl_urb = usb_alloc_urb(0, GFP_ATOMIC); + if (!xpad->ghl_urb) + return -ENOMEM; + + error = ghl_init_urb(xpad, udev, ghl_xboxone_magic_data, ARRAY_SIZE(ghl_xboxone_magic_data), ep_irq_out); + + if (error) + return error; + + timer_setup(&xpad->ghl_poke_timer, ghl_magic_poke, 0); + mod_timer(&xpad->ghl_poke_timer, jiffies + GHL_GUITAR_POKE_INTERVAL*HZ); + } return 0; err_deinit_output: @@ -2074,6 +2414,12 @@ static void xpad_disconnect(struct usb_interface *intf) xpad_deinit_output(xpad); usb_free_urb(xpad->irq_in); + + if (xpad->quirks & QUIRK_GHL_XBOXONE) { + usb_free_urb(xpad->ghl_urb); + del_timer_sync(&xpad->ghl_poke_timer); + } + usb_free_coherent(xpad->udev, XPAD_PKT_LEN, xpad->idata, xpad->idata_dma);