Skip to content

Commit 5eaa115

Browse files
dynamix1337paroj
authored andcommitted
Input: xpad - add support for GHL Xbox One controller
1 parent e3cafc2 commit 5eaa115

File tree

1 file changed

+163
-3
lines changed

1 file changed

+163
-3
lines changed

xpad.c

Lines changed: 163 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -71,9 +71,15 @@
7171
#include <linux/module.h>
7272
#include <linux/usb/input.h>
7373
#include <linux/usb/quirks.h>
74+
#include <linux/timer.h>
7475

7576
#define XPAD_PKT_LEN 64
7677

78+
/* The Guitar Hero Live (GHL) Xbox One dongles require a poke
79+
* every 8 seconds.
80+
*/
81+
#define GHL_GUITAR_POKE_INTERVAL 8 /* In seconds */
82+
7783
/*
7884
* xbox d-pads should map to buttons, as is required for DDR pads
7985
* but we map them to axes when possible to simplify things
@@ -108,6 +114,7 @@
108114
#define QUIRK_360_START_PKT_1 (1 << 0)
109115
#define QUIRK_360_START_PKT_2 (1 << 1)
110116
#define QUIRK_360_START_PKT_3 (1 << 2)
117+
#define QUIRK_GHL_XBOXONE (1 << 3)
111118
#define QUIRK_360_START (QUIRK_360_START_PKT_1 | \
112119
QUIRK_360_START_PKT_2 | QUIRK_360_START_PKT_3)
113120

@@ -303,6 +310,7 @@ static const struct xpad_device {
303310
{ 0x12ab, 0x0301, "PDP AFTERGLOW AX.1", 0, XTYPE_XBOX360 },
304311
{ 0x12ab, 0x0303, "Mortal Kombat Klassic FightStick", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 },
305312
{ 0x12ab, 0x8809, "Xbox DDR dancepad", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX },
313+
{ 0x1430, 0x079B, "RedOctane GHL Controller", 0, XTYPE_XBOXONE, QUIRK_GHL_XBOXONE },
306314
{ 0x1430, 0x4748, "RedOctane Guitar Hero X-plorer", 0, XTYPE_XBOX360 },
307315
{ 0x1430, 0x8888, "TX6500+ Dance Pad (first generation)", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX },
308316
{ 0x1430, 0xf801, "RedOctane Controller", 0, XTYPE_XBOX360 },
@@ -470,6 +478,12 @@ static const signed short xpad_btn_paddles[] = {
470478
-1 /* terminating entry */
471479
};
472480

481+
/* used for GHL dpad mapping */
482+
static const struct {int x; int y; } dpad_mapping[] = {
483+
{0, -1}, {1, -1}, {1, 0}, {1, 1}, {0, 1}, {-1, 1}, {-1, 0}, {-1, -1},
484+
{0, 0}
485+
};
486+
473487
/*
474488
* Xbox 360 has a vendor-specific class, so we cannot match it with only
475489
* USB_INTERFACE_INFO (also specifically refused by USB subsystem), so we
@@ -531,6 +545,7 @@ static const struct usb_device_id xpad_table[] = {
531545
XPAD_XBOX360_VENDOR(0x1209), /* Ardwiino Controllers */
532546
XPAD_XBOX360_VENDOR(0x12ab), /* Xbox 360 dance pads */
533547
XPAD_XBOX360_VENDOR(0x1430), /* RedOctane Xbox 360 controllers */
548+
XPAD_XBOXONE_VENDOR(0x1430), /* RedOctane X-Box One controllers */
534549
XPAD_XBOX360_VENDOR(0x146b), /* Bigben Interactive controllers */
535550
XPAD_XBOX360_VENDOR(0x1532), /* Razer Sabertooth */
536551
XPAD_XBOXONE_VENDOR(0x1532), /* Razer Wildcat */
@@ -698,6 +713,11 @@ static const u8 xboxone_rumbleend_init[] = {
698713
0x00, GIP_MOTOR_ALL, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
699714
};
700715

716+
/* GHL Xbox One magic data */
717+
static const char ghl_xboxone_magic_data[] = {
718+
0x22, 0x00, 0x00, 0x08, 0x02, 0x08, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00
719+
};
720+
701721
/*
702722
* This specifies the selection of init packets that a gamepad
703723
* will be sent on init *and* the order in which they will be
@@ -707,13 +727,16 @@ static const u8 xboxone_rumbleend_init[] = {
707727
static const struct xboxone_init_packet xboxone_init_packets[] = {
708728
XBOXONE_INIT_PKT(0x0e6f, 0x0165, xboxone_hori_ack_id),
709729
XBOXONE_INIT_PKT(0x0f0d, 0x0067, xboxone_hori_ack_id),
730+
XBOXONE_INIT_PKT(0x1430, 0x079b, xboxone_hori_ack_id),
710731
XBOXONE_INIT_PKT(0x0000, 0x0000, xboxone_power_on),
711732
XBOXONE_INIT_PKT(0x045e, 0x02ea, xboxone_s_init),
712733
XBOXONE_INIT_PKT(0x045e, 0x0b00, xboxone_s_init),
713734
XBOXONE_INIT_PKT(0x045e, 0x0b00, extra_input_packet_init),
714735
XBOXONE_INIT_PKT(0x0e6f, 0x0000, xboxone_pdp_led_on),
736+
XBOXONE_INIT_PKT(0x1430, 0x079b, xboxone_pdp_led_on),
715737
XBOXONE_INIT_PKT(0x20d6, 0xa01a, xboxone_pdp_led_on),
716738
XBOXONE_INIT_PKT(0x0e6f, 0x0000, xboxone_pdp_auth),
739+
XBOXONE_INIT_PKT(0x1430, 0x079b, xboxone_pdp_auth),
717740
XBOXONE_INIT_PKT(0x20d6, 0xa01a, xboxone_pdp_auth),
718741
XBOXONE_INIT_PKT(0x24c6, 0x541a, xboxone_rumblebegin_init),
719742
XBOXONE_INIT_PKT(0x24c6, 0x542a, xboxone_rumblebegin_init),
@@ -776,13 +799,72 @@ struct usb_xpad {
776799
struct work_struct work; /* init/remove device from callback */
777800
struct delayed_work poweroff_work; /* work struct for poweroff on mode long press */
778801
time64_t mode_btn_down_ts;
802+
struct urb *ghl_urb; /* URB for GHL Xbox One magic data */
803+
struct timer_list ghl_poke_timer; /* Timer for periodic poke of GHL magic data */
779804
};
780805

781806
static int xpad_init_input(struct usb_xpad *xpad);
782807
static void xpad_deinit_input(struct usb_xpad *xpad);
783808
static void xpadone_ack_mode_report(struct usb_xpad *xpad, u8 seq_num);
784809
static void xpad360w_poweroff_controller(struct usb_xpad *xpad);
785810

811+
/*
812+
* ghl_magic_poke_cb
813+
*
814+
* Call back function that resets the timer for the next magic data poke.
815+
*/
816+
static void ghl_magic_poke_cb(struct urb *urb)
817+
{
818+
struct usb_xpad *xpad = urb->context;
819+
820+
if (urb->status < 0)
821+
pr_warn("URB transfer failed.\n");
822+
823+
mod_timer(&xpad->ghl_poke_timer, jiffies + GHL_GUITAR_POKE_INTERVAL*HZ);
824+
}
825+
826+
/*
827+
* ghl_magic_poke
828+
*
829+
* Submits the GHL magic_data URB.
830+
*/
831+
static void ghl_magic_poke(struct timer_list *t)
832+
{
833+
int ret;
834+
struct usb_xpad *xpad = from_timer(xpad, t, ghl_poke_timer);
835+
836+
ret = usb_submit_urb(xpad->ghl_urb, GFP_ATOMIC);
837+
if (ret < 0)
838+
pr_warn("URB transfer failed.\n");
839+
}
840+
841+
/*
842+
* ghl_init_urb
843+
*
844+
* Prepares the interrupt URB for GHL magic_data.
845+
*/
846+
static int ghl_init_urb(struct usb_xpad *xpad, struct usb_device *usbdev,
847+
const char ghl_magic_data[], u16 poke_size, struct usb_endpoint_descriptor *ep_irq_out)
848+
{
849+
u8 *databuf;
850+
unsigned int pipe;
851+
852+
pipe = usb_sndintpipe(usbdev, ep_irq_out->bEndpointAddress);
853+
854+
databuf = devm_kzalloc(&xpad->udev->dev, poke_size, GFP_ATOMIC);
855+
if (databuf == NULL)
856+
return -ENOMEM;
857+
858+
memcpy(databuf, ghl_magic_data, poke_size);
859+
860+
usb_fill_int_urb(
861+
xpad->ghl_urb, usbdev, pipe,
862+
databuf, poke_size,
863+
ghl_magic_poke_cb, xpad, ep_irq_out->bInterval);
864+
865+
return 0;
866+
}
867+
786868
/*
787869
* xpad_process_packet
788870
*
@@ -1040,6 +1122,7 @@ static void xpadone_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char
10401122
{
10411123
struct input_dev *dev = xpad->dev;
10421124
bool do_sync = false;
1125+
int dpad_value;
10431126

10441127
/* the xbox button has its own special report */
10451128
if (data[0] == GIP_CMD_VIRTUAL_KEY) {
@@ -1186,6 +1269,48 @@ static void xpadone_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char
11861269
}
11871270
}
11881271

1272+
do_sync = true;
1273+
1274+
} else if (data[0] == 0X21) { /* The main valid packet type for GHL inputs */
1275+
/* Mapping chosen to be coherent with GHL dongles of other consoles */
1276+
1277+
/* The 6 fret buttons */
1278+
input_report_key(dev, BTN_B, data[4] & BIT(1));
1279+
input_report_key(dev, BTN_X, data[4] & BIT(2));
1280+
input_report_key(dev, BTN_Y, data[4] & BIT(3));
1281+
input_report_key(dev, BTN_A, data[4] & BIT(0));
1282+
input_report_key(dev, BTN_TL, data[4] & BIT(4));
1283+
input_report_key(dev, BTN_TR, data[4] & BIT(5));
1284+
1285+
/* D-pad */
1286+
dpad_value = data[6] & 0xF;
1287+
if (dpad_value > 7)
1288+
dpad_value = 8;
1289+
1290+
input_report_abs(dev, ABS_HAT0X, dpad_mapping[dpad_value].x);
1291+
input_report_abs(dev, ABS_HAT0Y, dpad_mapping[dpad_value].y);
1292+
1293+
/* Strum bar */
1294+
input_report_abs(dev, ABS_Y, ((data[8] - 0x80) << 9));
1295+
1296+
/* Tilt Sensor */
1297+
input_report_abs(dev, ABS_Z, ((data[9] - 0x80) << 9));
1298+
1299+
/* Whammy bar */
1300+
input_report_abs(dev, ABS_RZ, ((data[10] - 0x80) << 9));
1301+
1302+
/* Power Button */
1303+
input_report_key(dev, BTN_THUMBR, data[5] & BIT(4));
1304+
1305+
/* GHTV button */
1306+
input_report_key(dev, BTN_START, data[5] & BIT(2));
1307+
1308+
/* Hero Power button */
1309+
input_report_key(dev, BTN_MODE, data[5] & BIT(0));
1310+
1311+
/* Pause button */
1312+
input_report_key(dev, BTN_THUMBL, data[5] & BIT(1));
1313+
11891314
do_sync = true;
11901315
}
11911316

@@ -1985,15 +2110,29 @@ static void xpad_set_up_abs(struct input_dev *input_dev, signed short abs)
19852110
switch (abs) {
19862111
case ABS_X:
19872112
case ABS_Y:
2113+
/* GHL Strum bar */
2114+
if ((xpad->xtype == XTYPE_XBOXONE) && (xpad->quirks & QUIRK_GHL_XBOXONE)) {
2115+
input_set_abs_params(input_dev, abs, -32767, 32767, 0, 0);
2116+
break;
2117+
}
19882118
case ABS_RX:
19892119
case ABS_RY: /* the two sticks */
19902120
input_set_abs_params(input_dev, abs, -32768, 32767, 16, 128);
19912121
break;
19922122
case ABS_Z:
2123+
/* GHL Tilt sensor */
2124+
if ((xpad->xtype == XTYPE_XBOXONE) && (xpad->quirks & QUIRK_GHL_XBOXONE)) {
2125+
input_set_abs_params(input_dev, abs, -32767, 32767, 0, 0);
2126+
break;
2127+
}
19932128
case ABS_RZ: /* the triggers (if mapped to axes) */
1994-
if (xpad->xtype == XTYPE_XBOXONE)
1995-
input_set_abs_params(input_dev, abs, 0, 1023, 0, 0);
1996-
else
2129+
if (xpad->xtype == XTYPE_XBOXONE) {
2130+
/* GHL Whammy bar */
2131+
if (xpad->quirks & QUIRK_GHL_XBOXONE)
2132+
input_set_abs_params(input_dev, abs, -32767, 32767, 0, 0);
2133+
else
2134+
input_set_abs_params(input_dev, abs, 0, 1023, 0, 0);
2135+
} else
19972136
input_set_abs_params(input_dev, abs, 0, 255, 0, 0);
19982137
break;
19992138
case ABS_HAT0X:
@@ -2293,6 +2432,21 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id
22932432
if (error)
22942433
goto err_deinit_output;
22952434
}
2435+
2436+
if (xpad->quirks & QUIRK_GHL_XBOXONE) {
2437+
2438+
xpad->ghl_urb = usb_alloc_urb(0, GFP_ATOMIC);
2439+
if (!xpad->ghl_urb)
2440+
return -ENOMEM;
2441+
2442+
error = ghl_init_urb(xpad, udev, ghl_xboxone_magic_data, ARRAY_SIZE(ghl_xboxone_magic_data), ep_irq_out);
2443+
2444+
if (error)
2445+
return error;
2446+
2447+
timer_setup(&xpad->ghl_poke_timer, ghl_magic_poke, 0);
2448+
mod_timer(&xpad->ghl_poke_timer, jiffies + GHL_GUITAR_POKE_INTERVAL*HZ);
2449+
}
22962450
return 0;
22972451

22982452
err_deinit_output:
@@ -2324,6 +2478,12 @@ static void xpad_disconnect(struct usb_interface *intf)
23242478
xpad_deinit_output(xpad);
23252479

23262480
usb_free_urb(xpad->irq_in);
2481+
2482+
if (xpad->quirks & QUIRK_GHL_XBOXONE) {
2483+
usb_free_urb(xpad->ghl_urb);
2484+
del_timer_sync(&xpad->ghl_poke_timer);
2485+
}
2486+
23272487
usb_free_coherent(xpad->udev, XPAD_PKT_LEN,
23282488
xpad->idata, xpad->idata_dma);
23292489

0 commit comments

Comments
 (0)