From 3565e20cf20b8f7932dd7e5ca9667b5e2101fb85 Mon Sep 17 00:00:00 2001 From: Daniel Tobias Date: Tue, 10 May 2016 00:31:56 +1000 Subject: [PATCH 01/21] xpad: print received packets if DEBUG_VERBOSE Signed-off-by: Daniel Tobias --- xpad.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/xpad.c b/xpad.c index 4d0e581..5bd52c7 100644 --- a/xpad.c +++ b/xpad.c @@ -1090,6 +1090,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); From e0f001b6a3e8f24faef53e7a9accd56b35de4ab2 Mon Sep 17 00:00:00 2001 From: Pavel Rojtberg Date: Sun, 5 Jul 2015 15:41:30 +0200 Subject: [PATCH 02/21] add code to enable debug outputs --- xpad.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xpad.c b/xpad.c index 5bd52c7..3d19dca 100644 --- a/xpad.c +++ b/xpad.c @@ -60,7 +60,7 @@ * * Later changes can be tracked in SCM. */ - +// #define DEBUG #include #include #include From 75e79d8c899e11d027a541916bfd360d979acd70 Mon Sep 17 00:00:00 2001 From: Pavel Rojtberg Date: Wed, 24 Jun 2015 12:47:17 +0200 Subject: [PATCH 03/21] add README.md Signed-off-by: Daniel Tobias Signed-off-by: Jonathan Signed-off-by: Matt Sturgeon --- README.md | 94 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 94 insertions(+) create mode 100644 README.md 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` From 876f4397ea8b2d86380eafd700f2698088582c1a Mon Sep 17 00:00:00 2001 From: Pavel Rojtberg Date: Sun, 27 Sep 2015 23:57:46 +0200 Subject: [PATCH 04/21] add stress_urb_out.sh --- stress_urb_out.sh | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100755 stress_urb_out.sh 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 From 78d2f924d99dc6035dd9ab355c83f6fa0c79b99e Mon Sep 17 00:00:00 2001 From: Pavel Rojtberg Date: Sun, 8 Dec 2019 13:44:36 +0100 Subject: [PATCH 05/21] add PR template --- .github/pull_request_template.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 .github/pull_request_template.md 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 From 6fd35f2fe01eca86666c52b54ce056d2f30fa73e Mon Sep 17 00:00:00 2001 From: Pavel Rojtberg Date: Mon, 5 Sep 2022 18:35:42 +0200 Subject: [PATCH 06/21] add CI build --- .github/workflows/ci-build.yml | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 .github/workflows/ci-build.yml 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 From 61b4e97a58ae8ddd81c385d6a04268a22d7b3bde Mon Sep 17 00:00:00 2001 From: Giuseppe Bilotta Date: Sun, 15 Aug 2021 01:47:17 +0200 Subject: [PATCH 07/21] Input: xpad - initialize 360 controllers Many knockoff brands emulating the XBOX 360 controller do not properly send data unless configured correctly. Examples include the Gamesir G3w and the Fantech GP11 Shooter. Protocol inspection of communication with other operating systems reveals a sequence of control messages that can be used to initialize the controllers sufficiently to send proper data. Some of these controllers only require one and may break with further, some may require all three. This change adds a quirks field that allows specifying these initialization packets. Note that it also removes an unused field from the controller type table. Signed-off-by: Darvin Delgado Signed-off-by: Vicki Pfau --- xpad.c | 110 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 109 insertions(+), 1 deletion(-) diff --git a/xpad.c b/xpad.c index 3d19dca..6fe1212 100644 --- a/xpad.c +++ b/xpad.c @@ -101,6 +101,12 @@ #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_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 +129,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 +163,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 }, @@ -261,6 +268,7 @@ 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 }, @@ -660,6 +668,7 @@ 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 */ time64_t mode_btn_down_ts; @@ -1363,6 +1372,98 @@ 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 = 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; @@ -1648,6 +1749,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; @@ -1928,6 +2035,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); From 1b1391aea9ffbab325ea2ffd35cffb1ec5d4518c Mon Sep 17 00:00:00 2001 From: Pavel Rojtberg Date: Fri, 9 Sep 2022 00:08:54 +0200 Subject: [PATCH 08/21] Input: xpad - refactor using BIT() macro --- xpad.c | 112 ++++++++++++++++++++++++++++----------------------------- 1 file changed, 56 insertions(+), 56 deletions(-) diff --git a/xpad.c b/xpad.c index 6fe1212..4c150dc 100644 --- a/xpad.c +++ b/xpad.c @@ -718,10 +718,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)); @@ -730,10 +730,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]); @@ -768,10 +768,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)); } /* @@ -789,21 +789,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 */ @@ -841,7 +841,7 @@ static void xpad360_process_packet(struct usb_xpad *xpad, struct input_dev *dev, } /* mode button down/up */ - if (data[3] & 0x04) + if (data[3] & BIT(2)) xpad->mode_btn_down_ts = ktime_get_seconds(); else xpad->mode_btn_down_ts = 0; @@ -937,7 +937,7 @@ static void xpadone_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char if (data[1] == 0x30) 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) { @@ -951,33 +951,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 */ /* 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)); /* 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)); @@ -986,12 +986,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 */ @@ -1032,10 +1032,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 @@ -1045,10 +1045,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 @@ -1060,10 +1060,10 @@ 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)); } } From 2c087f90bb85799df02400f6f10ccdca70e02c6e Mon Sep 17 00:00:00 2001 From: Pavel Rojtberg Date: Fri, 9 Sep 2022 19:36:53 +0200 Subject: [PATCH 09/21] Input: xpad - decipher xpadone packages with GIP defines only renames, no functional changes - even though some of the packets we send are suspicious. However, I dont have the hardware to verify they are truly superflous. --- xpad.c | 99 ++++++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 69 insertions(+), 30 deletions(-) diff --git a/xpad.c b/xpad.c index 4c150dc..1ecaf9d 100644 --- a/xpad.c +++ b/xpad.c @@ -521,13 +521,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 }; /* @@ -537,7 +576,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 }; /* @@ -554,9 +593,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 }; /* @@ -564,8 +603,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 }; /* @@ -573,8 +612,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 }; /* @@ -582,8 +621,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 }; /* @@ -593,8 +632,8 @@ static const u8 xboxone_rumblebegin_init[] = { * spin up to enough speed to actually vibrate the gamepad. */ static const u8 xboxone_rumbleend_init[] = { - 0x09, 0x00, 0x00, 0x09, 0x00, 0x0F, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00 + GIP_CMD_RUMBLE, 0x00, GIP_SEQ0, GIP_PL_LEN(9), + 0x00, GIP_MOTOR_ALL, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; /* @@ -604,14 +643,14 @@ static const u8 xboxone_rumbleend_init[] = { * packet is going to be sent. */ static const struct xboxone_init_packet xboxone_init_packets[] = { - XBOXONE_INIT_PKT(0x0e6f, 0x0165, xboxone_hori_init), - XBOXONE_INIT_PKT(0x0f0d, 0x0067, xboxone_hori_init), - XBOXONE_INIT_PKT(0x0000, 0x0000, xboxone_fw2015_init), + XBOXONE_INIT_PKT(0x0e6f, 0x0165, xboxone_hori_ack_id), + XBOXONE_INIT_PKT(0x0f0d, 0x0067, xboxone_hori_ack_id), + XBOXONE_INIT_PKT(0x0000, 0x0000, xboxone_power_on), XBOXONE_INIT_PKT(0x045e, 0x02ea, xboxone_s_init), XBOXONE_INIT_PKT(0x045e, 0x0b00, xboxone_s_init), XBOXONE_INIT_PKT(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(0x0e6f, 0x0000, xboxone_pdp_auth), XBOXONE_INIT_PKT(0x24c6, 0x541a, xboxone_rumblebegin_init), XBOXONE_INIT_PKT(0x24c6, 0x542a, xboxone_rumblebegin_init), XBOXONE_INIT_PKT(0x24c6, 0x543a, xboxone_rumblebegin_init), @@ -928,19 +967,19 @@ static void xpadone_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char bool do_sync = false; /* the xbox button has its own special report */ - if (data[0] == 0X07) { + if (data[0] == GIP_CMD_VIRTUAL_KEY) { /* * The Xbox One S controller requires these reports to be * acked otherwise it continues sending them forever and * won't report further mode button events. */ - if (data[1] == 0x30) + if (data[1] == (GIP_OPT_ACK | GIP_OPT_INTERNAL)) xpadone_ack_mode_report(xpad, data[2]); input_report_key(dev, BTN_MODE, data[4] & 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 @@ -958,7 +997,7 @@ static void xpadone_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char 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] & BIT(2)); input_report_key(dev, BTN_SELECT, data[4] & BIT(3)); @@ -1470,8 +1509,8 @@ static void xpadone_ack_mode_report(struct usb_xpad *xpad, u8 seq_num) struct xpad_output_packet *packet = &xpad->out_packets[XPAD_OUT_CMD_IDX]; static const u8 mode_report_ack[] = { - 0x01, 0x20, 0x00, 0x09, 0x00, 0x07, 0x20, 0x02, - 0x00, 0x00, 0x00, 0x00, 0x00 + GIP_CMD_ACK, GIP_OPT_INTERNAL, GIP_SEQ0, GIP_PL_LEN(9), + 0x00, GIP_CMD_VIRTUAL_KEY, GIP_OPT_INTERNAL, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00 }; spin_lock_irqsave(&xpad->odata_lock, flags); @@ -1549,14 +1588,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 */ From 5d6794045292c532cd6a42eb85574fc96db05062 Mon Sep 17 00:00:00 2001 From: Davide Garberi Date: Sat, 22 Oct 2022 17:49:16 +0200 Subject: [PATCH 10/21] input: xpad - Switch to workqueue for xpad360w button poweroff This allows to turn off the pad without having to release the Xbox (mode) button Signed-off-by: Davide Garberi --- xpad.c | 35 ++++++++++++++++++++++++----------- 1 file changed, 24 insertions(+), 11 deletions(-) diff --git a/xpad.c b/xpad.c index 1ecaf9d..25e2a4e 100644 --- a/xpad.c +++ b/xpad.c @@ -710,6 +710,7 @@ struct usb_xpad { 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; }; @@ -871,20 +872,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] & BIT(2)) - 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) @@ -1864,6 +1874,8 @@ static int xpad360w_start_input(struct usb_xpad *xpad) return error; } + INIT_DELAYED_WORK(&xpad->poweroff_work, xpad360w_poweroff_work); + return 0; } @@ -1873,6 +1885,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) From 0270e3759fccdd2887553fa4fd2cd07844b29f49 Mon Sep 17 00:00:00 2001 From: Daniel Nguyen <56515021+dynamix1337@users.noreply.github.com> Date: Sat, 22 Oct 2022 11:54:44 -0400 Subject: [PATCH 11/21] Input: xpad - add support for GHL Xbox One controller --- xpad.c | 170 +++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 165 insertions(+), 5 deletions(-) diff --git a/xpad.c b/xpad.c index 25e2a4e..25108a2 100644 --- a/xpad.c +++ b/xpad.c @@ -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 @@ -104,6 +110,7 @@ #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) @@ -281,6 +288,7 @@ static const struct xpad_device { { 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 }, @@ -432,6 +440,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 @@ -482,6 +496,7 @@ static const struct usb_device_id xpad_table[] = { 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 */ @@ -594,7 +609,7 @@ static const u8 extra_input_packet_init[] = { * (0x0f0d:0x0067) to make the analog sticks work. */ static const u8 xboxone_hori_ack_id[] = { - GIP_CMD_ACK, GIP_OPT_INTERNAL, GIP_SEQ0, GIP_PL_LEN(9), + 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 }; @@ -636,6 +651,11 @@ static const u8 xboxone_rumbleend_init[] = { 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 +}; + /* * This specifies the selection of init packets that a gamepad * will be sent on init *and* the order in which they will be @@ -645,12 +665,15 @@ static const u8 xboxone_rumbleend_init[] = { static const struct xboxone_init_packet xboxone_init_packets[] = { 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_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), @@ -712,6 +735,8 @@ struct usb_xpad { 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); @@ -719,6 +744,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 * @@ -975,6 +1057,7 @@ 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] == GIP_CMD_VIRTUAL_KEY) { @@ -1116,6 +1199,48 @@ static void xpadone_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char } } + 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; } @@ -1519,7 +1644,7 @@ static void xpadone_ack_mode_report(struct usb_xpad *xpad, u8 seq_num) struct xpad_output_packet *packet = &xpad->out_packets[XPAD_OUT_CMD_IDX]; static const u8 mode_report_ack[] = { - GIP_CMD_ACK, GIP_OPT_INTERNAL, GIP_SEQ0, GIP_PL_LEN(9), + 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 }; @@ -1909,15 +2034,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: @@ -2210,6 +2349,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: @@ -2241,6 +2395,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); From dbe7e0903d3cf4ebea60bd40bbaad72598c92b62 Mon Sep 17 00:00:00 2001 From: Eldad Zack Date: Thu, 20 Oct 2022 18:48:51 +0200 Subject: [PATCH 12/21] xbox 360: fix null pointer dereference when manufacturer is null This occurs with MSI GC20 on Ubuntu 22.04.1 LTS. Signed-off-by: Eldad Zack --- xpad.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xpad.c b/xpad.c index 25108a2..d61afde 100644 --- a/xpad.c +++ b/xpad.c @@ -1561,7 +1561,7 @@ static int xpad_start_xbox_360(struct usb_xpad *xpad) have to inspect the manufacturer string. Sending this sequence to other controllers will break initialization. */ - bool is_shanwan = strcasecmp("shanwan", xpad->udev->manufacturer) == 0; + 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; From 1821d2822783e8c24733b05138e06d9a9f4d309d Mon Sep 17 00:00:00 2001 From: Josh Cotton Date: Mon, 14 Nov 2022 07:57:40 -0800 Subject: [PATCH 13/21] Input: xpad - add support for 8BitDo Ultimate Wireless controller dongle Signed-off-by: Josh Cotton --- xpad.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/xpad.c b/xpad.c index d61afde..6efc96a 100644 --- a/xpad.c +++ b/xpad.c @@ -371,6 +371,7 @@ static const struct xpad_device { { 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, 0x3106, "8BitDo Ultimate Wireless Controller", 0, XTYPE_XBOX360 }, { 0x31e3, 0x1100, "Wooting One", 0, XTYPE_XBOX360 }, { 0x31e3, 0x1200, "Wooting Two", 0, XTYPE_XBOX360 }, { 0x31e3, 0x1210, "Wooting Lekker", 0, XTYPE_XBOX360 }, @@ -512,6 +513,7 @@ 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_XBOX360_VENDOR(0x2f24), /* GameSir Controllers */ XPAD_XBOX360_VENDOR(0x31e3), /* Wooting Keyboards */ From 4a64f5caefb2e571d90240f9b1a2bbe1a8950a74 Mon Sep 17 00:00:00 2001 From: Leonardo Brondani Schenkel Date: Wed, 4 Jan 2023 16:58:49 +0100 Subject: [PATCH 14/21] Improve name of 8BitDo controller 2dc8:3106 8BitDo Pro 2 Wired Controller shares the same USB identifier (2dc8:3106) as a different device, so amend name to reflect that and reduce confusion as the user might think the controller was misdetected. I have personally tested it and I can confirm that Pro 2 Wired will also not work in XTYPE_XBOXONE mode (buton presses won't register), therefore XTYPE_XBOX360 remains appropriate. Signed-off-by: Leonardo Brondani Schenkel --- xpad.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xpad.c b/xpad.c index 6efc96a..78e9221 100644 --- a/xpad.c +++ b/xpad.c @@ -371,7 +371,7 @@ static const struct xpad_device { { 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, 0x3106, "8BitDo Ultimate Wireless Controller", 0, XTYPE_XBOX360 }, + { 0x2dc8, 0x3106, "8BitDo Ultimate Wireless / Pro 2 Wired Controller", 0, XTYPE_XBOX360 }, { 0x31e3, 0x1100, "Wooting One", 0, XTYPE_XBOX360 }, { 0x31e3, 0x1200, "Wooting Two", 0, XTYPE_XBOX360 }, { 0x31e3, 0x1210, "Wooting Lekker", 0, XTYPE_XBOX360 }, From 1bdf0926376e9a256d32619122e755923de1dd0a Mon Sep 17 00:00:00 2001 From: Thijs Reus Date: Sat, 26 Nov 2022 19:34:13 +0100 Subject: [PATCH 15/21] Added Turtle Beach Recon support (from the diff from https://www.spinics.net/lists/linux-input/msg75512.html) --- xpad.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/xpad.c b/xpad.c index 78e9221..fd207c9 100644 --- a/xpad.c +++ b/xpad.c @@ -180,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 }, @@ -282,6 +283,7 @@ static const struct xpad_device { { 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 }, @@ -297,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 }, @@ -364,6 +367,7 @@ 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 }, @@ -379,6 +383,7 @@ static const struct xpad_device { { 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 }, { 0x3767, 0x0101, "Fanatec Speedster 3 Forceshock Wheel", 0, XTYPE_XBOX }, { 0xffff, 0xffff, "Chinese-made Xbox Controller", 0, XTYPE_XBOX }, { 0x0000, 0x0000, "Generic X-Box pad", 0, XTYPE_UNKNOWN } @@ -493,6 +498,7 @@ 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 */ @@ -518,6 +524,7 @@ static const struct usb_device_id xpad_table[] = { XPAD_XBOX360_VENDOR(0x2f24), /* 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 */ { } }; From 904be143d75818e672a8f4fa346ebf5362332bac Mon Sep 17 00:00:00 2001 From: Leonardo Brondani Schenkel Date: Mon, 9 Jan 2023 17:44:39 +0100 Subject: [PATCH 16/21] Support KEY_RECORD for 8BitDo Pro 2...for Xbox This controller is a "Series S|X": it has the "share" button below the big Xbox button. However, it reports the status of that button in a different offset than the official controller. The button is still recognized by official Microsoft driver in Windows, so it looks like that both offsets are used in the wild. Signed-off-by: Leonardo Brondani Schenkel --- xpad.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/xpad.c b/xpad.c index fd207c9..c38a36f 100644 --- a/xpad.c +++ b/xpad.c @@ -374,7 +374,7 @@ static const struct xpad_device { { 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 }, { 0x31e3, 0x1100, "Wooting One", 0, XTYPE_XBOX360 }, { 0x31e3, 0x1200, "Wooting Two", 0, XTYPE_XBOX360 }, @@ -1104,7 +1104,7 @@ static void xpadone_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char input_report_key(dev, BTN_START, data[4] & BIT(2)); input_report_key(dev, BTN_SELECT, data[4] & BIT(3)); if (xpad->mapping & MAP_SELECT_BUTTON) - input_report_key(dev, KEY_RECORD, data[22] & BIT(0)); + 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] & BIT(4)); From 51af0649c2926e8992b70ca1bb506db949c6d8d9 Mon Sep 17 00:00:00 2001 From: jdarn <109807817+jdarn@users.noreply.github.com> Date: Wed, 12 Apr 2023 18:57:01 -0400 Subject: [PATCH 17/21] Input: xpad - add support for 8BitDo Ultimate bluetooth/hall effect variant --- xpad.c | 1 + 1 file changed, 1 insertion(+) diff --git a/xpad.c b/xpad.c index c38a36f..674e101 100644 --- a/xpad.c +++ b/xpad.c @@ -376,6 +376,7 @@ static const struct xpad_device { { 0x2563, 0x058d, "OneXPlayer Gamepad", 0, XTYPE_XBOX360 }, { 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 }, { 0x31e3, 0x1100, "Wooting One", 0, XTYPE_XBOX360 }, { 0x31e3, 0x1200, "Wooting Two", 0, XTYPE_XBOX360 }, { 0x31e3, 0x1210, "Wooting Lekker", 0, XTYPE_XBOX360 }, From 889871ead9a762f5b1b92adc1aa3681423a30948 Mon Sep 17 00:00:00 2001 From: Jack Greiner Date: Wed, 28 Jun 2023 00:06:11 -0400 Subject: [PATCH 18/21] Input: xpad - add support for wooting two he (arm) Signed-off-by: Jack Greiner --- xpad.c | 1 + 1 file changed, 1 insertion(+) diff --git a/xpad.c b/xpad.c index 674e101..28c8bd1 100644 --- a/xpad.c +++ b/xpad.c @@ -381,6 +381,7 @@ static const struct xpad_device { { 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 }, From eddb513e04697348fd7ad6961c6d5cfaa7467998 Mon Sep 17 00:00:00 2001 From: Jocelyne Jones Date: Sun, 2 Jul 2023 21:03:05 +0100 Subject: [PATCH 19/21] Input: xpad - add support for SCUF Instinct --- xpad.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/xpad.c b/xpad.c index 28c8bd1..40f657e 100644 --- a/xpad.c +++ b/xpad.c @@ -377,6 +377,7 @@ static const struct xpad_device { { 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 }, @@ -523,6 +524,7 @@ static const struct usb_device_id xpad_table[] = { 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(0x31e3), /* Wooting Keyboards */ XPAD_XBOX360_VENDOR(0x3285), /* Nacon GC-100 */ From 3a215825f981643d164aa4e10fd2ab584fd9987c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20G=C3=B6rgens?= Date: Thu, 23 Nov 2023 00:11:40 +0100 Subject: [PATCH 20/21] feat: add Black Shark Green Ghost controller support --- xpad.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/xpad.c b/xpad.c index 40f657e..43985dd 100644 --- a/xpad.c +++ b/xpad.c @@ -388,6 +388,7 @@ static const struct xpad_device { { 0x3285, 0x0607, "Nacon GC-100", 0, XTYPE_XBOX360 }, { 0x3285, 0x0614, "Nacon Pro Compact", 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 } }; @@ -529,6 +530,7 @@ static const struct usb_device_id xpad_table[] = { 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 */ { } }; From ae0917a5ea3fe682b68b3d6c972c1fd417480250 Mon Sep 17 00:00:00 2001 From: Igor Demyanov Date: Tue, 19 Nov 2024 20:42:16 +0300 Subject: [PATCH 21/21] Support GameSir T4 Kaleid & GameSir-G7 SE --- xpad.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/xpad.c b/xpad.c index 43985dd..e7439ec 100644 --- a/xpad.c +++ b/xpad.c @@ -387,6 +387,8 @@ static const struct xpad_device { { 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 }, @@ -527,6 +529,8 @@ static const struct usb_device_id xpad_table[] = { 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 */