Skip to content

Commit a0d7274

Browse files
dynamix1337paroj
authored andcommitted
Input: xpad - add support for GHL Xbox One controller
1 parent 3470f9f commit a0d7274

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

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

483+
/* used for GHL dpad mapping */
484+
static const struct {int x; int y; } dpad_mapping[] = {
485+
{0, -1}, {1, -1}, {1, 0}, {1, 1}, {0, 1}, {-1, 1}, {-1, 0}, {-1, -1},
486+
{0, 0}
487+
};
488+
475489
/*
476490
* Xbox 360 has a vendor-specific class, so we cannot match it with only
477491
* USB_INTERFACE_INFO (also specifically refused by USB subsystem), so we
@@ -533,6 +547,7 @@ static const struct usb_device_id xpad_table[] = {
533547
XPAD_XBOX360_VENDOR(0x1209), /* Ardwiino Controllers */
534548
XPAD_XBOX360_VENDOR(0x12ab), /* Xbox 360 dance pads */
535549
XPAD_XBOX360_VENDOR(0x1430), /* RedOctane Xbox 360 controllers */
550+
XPAD_XBOXONE_VENDOR(0x1430), /* RedOctane X-Box One controllers */
536551
XPAD_XBOX360_VENDOR(0x146b), /* Bigben Interactive controllers */
537552
XPAD_XBOX360_VENDOR(0x1532), /* Razer Sabertooth */
538553
XPAD_XBOXONE_VENDOR(0x1532), /* Razer Wildcat */
@@ -701,6 +716,11 @@ static const u8 xboxone_rumbleend_init[] = {
701716
0x00, GIP_MOTOR_ALL, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
702717
};
703718

719+
/* GHL Xbox One magic data */
720+
static const char ghl_xboxone_magic_data[] = {
721+
0x22, 0x00, 0x00, 0x08, 0x02, 0x08, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00
722+
};
723+
704724
/*
705725
* This specifies the selection of init packets that a gamepad
706726
* will be sent on init *and* the order in which they will be
@@ -710,13 +730,16 @@ static const u8 xboxone_rumbleend_init[] = {
710730
static const struct xboxone_init_packet xboxone_init_packets[] = {
711731
XBOXONE_INIT_PKT(0x0e6f, 0x0165, xboxone_hori_ack_id),
712732
XBOXONE_INIT_PKT(0x0f0d, 0x0067, xboxone_hori_ack_id),
733+
XBOXONE_INIT_PKT(0x1430, 0x079b, xboxone_hori_ack_id),
713734
XBOXONE_INIT_PKT(0x0000, 0x0000, xboxone_power_on),
714735
XBOXONE_INIT_PKT(0x045e, 0x02ea, xboxone_s_init),
715736
XBOXONE_INIT_PKT(0x045e, 0x0b00, xboxone_s_init),
716737
XBOXONE_INIT_PKT(0x045e, 0x0b00, extra_input_packet_init),
717738
XBOXONE_INIT_PKT(0x0e6f, 0x0000, xboxone_pdp_led_on),
739+
XBOXONE_INIT_PKT(0x1430, 0x079b, xboxone_pdp_led_on),
718740
XBOXONE_INIT_PKT(0x20d6, 0xa01a, xboxone_pdp_led_on),
719741
XBOXONE_INIT_PKT(0x0e6f, 0x0000, xboxone_pdp_auth),
742+
XBOXONE_INIT_PKT(0x1430, 0x079b, xboxone_pdp_auth),
720743
XBOXONE_INIT_PKT(0x20d6, 0xa01a, xboxone_pdp_auth),
721744
XBOXONE_INIT_PKT(0x24c6, 0x541a, xboxone_rumblebegin_init),
722745
XBOXONE_INIT_PKT(0x24c6, 0x542a, xboxone_rumblebegin_init),
@@ -779,13 +802,72 @@ struct usb_xpad {
779802
struct work_struct work; /* init/remove device from callback */
780803
struct delayed_work poweroff_work; /* work struct for poweroff on mode long press */
781804
time64_t mode_btn_down_ts;
805+
struct urb *ghl_urb; /* URB for GHL Xbox One magic data */
806+
struct timer_list ghl_poke_timer; /* Timer for periodic poke of GHL magic data */
782807
};
783808

784809
static int xpad_init_input(struct usb_xpad *xpad);
785810
static void xpad_deinit_input(struct usb_xpad *xpad);
786811
static void xpadone_ack_mode_report(struct usb_xpad *xpad, u8 seq_num);
787812
static void xpad360w_poweroff_controller(struct usb_xpad *xpad);
788813

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

10471130
/* the xbox button has its own special report */
10481131
if (data[0] == GIP_CMD_VIRTUAL_KEY) {
@@ -1189,6 +1272,48 @@ static void xpadone_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char
11891272
}
11901273
}
11911274

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

@@ -2018,15 +2143,29 @@ static void xpad_set_up_abs(struct input_dev *input_dev, signed short abs)
20182143
switch (abs) {
20192144
case ABS_X:
20202145
case ABS_Y:
2146+
/* GHL Strum bar */
2147+
if ((xpad->xtype == XTYPE_XBOXONE) && (xpad->quirks & QUIRK_GHL_XBOXONE)) {
2148+
input_set_abs_params(input_dev, abs, -32767, 32767, 0, 0);
2149+
break;
2150+
}
20212151
case ABS_RX:
20222152
case ABS_RY: /* the two sticks */
20232153
input_set_abs_params(input_dev, abs, -32768, 32767, 16, 128);
20242154
break;
20252155
case ABS_Z:
2156+
/* GHL Tilt sensor */
2157+
if ((xpad->xtype == XTYPE_XBOXONE) && (xpad->quirks & QUIRK_GHL_XBOXONE)) {
2158+
input_set_abs_params(input_dev, abs, -32767, 32767, 0, 0);
2159+
break;
2160+
}
20262161
case ABS_RZ: /* the triggers (if mapped to axes) */
2027-
if (xpad->xtype == XTYPE_XBOXONE)
2028-
input_set_abs_params(input_dev, abs, 0, 1023, 0, 0);
2029-
else
2162+
if (xpad->xtype == XTYPE_XBOXONE) {
2163+
/* GHL Whammy bar */
2164+
if (xpad->quirks & QUIRK_GHL_XBOXONE)
2165+
input_set_abs_params(input_dev, abs, -32767, 32767, 0, 0);
2166+
else
2167+
input_set_abs_params(input_dev, abs, 0, 1023, 0, 0);
2168+
} else
20302169
input_set_abs_params(input_dev, abs, 0, 255, 0, 0);
20312170
break;
20322171
case ABS_HAT0X:
@@ -2326,6 +2465,21 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id
23262465
if (error)
23272466
goto err_deinit_output;
23282467
}
2468+
2469+
if (xpad->quirks & QUIRK_GHL_XBOXONE) {
2470+
2471+
xpad->ghl_urb = usb_alloc_urb(0, GFP_ATOMIC);
2472+
if (!xpad->ghl_urb)
2473+
return -ENOMEM;
2474+
2475+
error = ghl_init_urb(xpad, udev, ghl_xboxone_magic_data, ARRAY_SIZE(ghl_xboxone_magic_data), ep_irq_out);
2476+
2477+
if (error)
2478+
return error;
2479+
2480+
timer_setup(&xpad->ghl_poke_timer, ghl_magic_poke, 0);
2481+
mod_timer(&xpad->ghl_poke_timer, jiffies + GHL_GUITAR_POKE_INTERVAL*HZ);
2482+
}
23292483
return 0;
23302484

23312485
err_deinit_output:
@@ -2357,6 +2511,12 @@ static void xpad_disconnect(struct usb_interface *intf)
23572511
xpad_deinit_output(xpad);
23582512

23592513
usb_free_urb(xpad->irq_in);
2514+
2515+
if (xpad->quirks & QUIRK_GHL_XBOXONE) {
2516+
usb_free_urb(xpad->ghl_urb);
2517+
del_timer_sync(&xpad->ghl_poke_timer);
2518+
}
2519+
23602520
usb_free_coherent(xpad->udev, XPAD_PKT_LEN,
23612521
xpad->idata, xpad->idata_dma);
23622522

0 commit comments

Comments
 (0)