Skip to content

Commit 0270e37

Browse files
authored
Input: xpad - add support for GHL Xbox One controller
1 parent 5d67940 commit 0270e37

File tree

1 file changed

+165
-5
lines changed

1 file changed

+165
-5
lines changed

xpad.c

Lines changed: 165 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -69,9 +69,15 @@
6969
#include <linux/module.h>
7070
#include <linux/usb/input.h>
7171
#include <linux/usb/quirks.h>
72+
#include <linux/timer.h>
7273

7374
#define XPAD_PKT_LEN 64
7475

76+
/* The Guitar Hero Live (GHL) Xbox One dongles require a poke
77+
* every 8 seconds.
78+
*/
79+
#define GHL_GUITAR_POKE_INTERVAL 8 /* In seconds */
80+
7581
/*
7682
* xbox d-pads should map to buttons, as is required for DDR pads
7783
* but we map them to axes when possible to simplify things
@@ -104,6 +110,7 @@
104110
#define QUIRK_360_START_PKT_1 (1 << 0)
105111
#define QUIRK_360_START_PKT_2 (1 << 1)
106112
#define QUIRK_360_START_PKT_3 (1 << 2)
113+
#define QUIRK_GHL_XBOXONE (1 << 3)
107114
#define QUIRK_360_START (QUIRK_360_START_PKT_1 | \
108115
QUIRK_360_START_PKT_2 | QUIRK_360_START_PKT_3)
109116

@@ -281,6 +288,7 @@ static const struct xpad_device {
281288
{ 0x12ab, 0x0301, "PDP AFTERGLOW AX.1", 0, XTYPE_XBOX360 },
282289
{ 0x12ab, 0x0303, "Mortal Kombat Klassic FightStick", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 },
283290
{ 0x12ab, 0x8809, "Xbox DDR dancepad", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX },
291+
{ 0x1430, 0x079B, "RedOctane GHL Controller", 0, XTYPE_XBOXONE, QUIRK_GHL_XBOXONE },
284292
{ 0x1430, 0x4748, "RedOctane Guitar Hero X-plorer", 0, XTYPE_XBOX360 },
285293
{ 0x1430, 0x8888, "TX6500+ Dance Pad (first generation)", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX },
286294
{ 0x1430, 0xf801, "RedOctane Controller", 0, XTYPE_XBOX360 },
@@ -432,6 +440,12 @@ static const signed short xpad_btn_paddles[] = {
432440
-1 /* terminating entry */
433441
};
434442

443+
/* used for GHL dpad mapping */
444+
static const struct {int x; int y; } dpad_mapping[] = {
445+
{0, -1}, {1, -1}, {1, 0}, {1, 1}, {0, 1}, {-1, 1}, {-1, 0}, {-1, -1},
446+
{0, 0}
447+
};
448+
435449
/*
436450
* Xbox 360 has a vendor-specific class, so we cannot match it with only
437451
* USB_INTERFACE_INFO (also specifically refused by USB subsystem), so we
@@ -482,6 +496,7 @@ static const struct usb_device_id xpad_table[] = {
482496
XPAD_XBOX360_VENDOR(0x1209), /* Ardwiino Controllers */
483497
XPAD_XBOX360_VENDOR(0x12ab), /* X-Box 360 dance pads */
484498
XPAD_XBOX360_VENDOR(0x1430), /* RedOctane X-Box 360 controllers */
499+
XPAD_XBOXONE_VENDOR(0x1430), /* RedOctane X-Box One controllers */
485500
XPAD_XBOX360_VENDOR(0x146b), /* BigBen Interactive Controllers */
486501
XPAD_XBOX360_VENDOR(0x1532), /* Razer Sabertooth */
487502
XPAD_XBOXONE_VENDOR(0x1532), /* Razer Wildcat */
@@ -594,7 +609,7 @@ static const u8 extra_input_packet_init[] = {
594609
* (0x0f0d:0x0067) to make the analog sticks work.
595610
*/
596611
static const u8 xboxone_hori_ack_id[] = {
597-
GIP_CMD_ACK, GIP_OPT_INTERNAL, GIP_SEQ0, GIP_PL_LEN(9),
612+
GIP_CMD_ACK, GIP_OPT_INTERNAL, GIP_SEQ0, GIP_PL_LEN(9),
598613
0x00, GIP_CMD_IDENTIFY, GIP_OPT_INTERNAL, 0x3a, 0x00, 0x00, 0x00, 0x80, 0x00
599614
};
600615

@@ -636,6 +651,11 @@ static const u8 xboxone_rumbleend_init[] = {
636651
0x00, GIP_MOTOR_ALL, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
637652
};
638653

654+
/* GHL Xbox One magic data */
655+
static const char ghl_xboxone_magic_data[] = {
656+
0x22, 0x00, 0x00, 0x08, 0x02, 0x08, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00
657+
};
658+
639659
/*
640660
* This specifies the selection of init packets that a gamepad
641661
* will be sent on init *and* the order in which they will be
@@ -645,12 +665,15 @@ static const u8 xboxone_rumbleend_init[] = {
645665
static const struct xboxone_init_packet xboxone_init_packets[] = {
646666
XBOXONE_INIT_PKT(0x0e6f, 0x0165, xboxone_hori_ack_id),
647667
XBOXONE_INIT_PKT(0x0f0d, 0x0067, xboxone_hori_ack_id),
668+
XBOXONE_INIT_PKT(0x1430, 0x079b, xboxone_hori_ack_id),
648669
XBOXONE_INIT_PKT(0x0000, 0x0000, xboxone_power_on),
649670
XBOXONE_INIT_PKT(0x045e, 0x02ea, xboxone_s_init),
650671
XBOXONE_INIT_PKT(0x045e, 0x0b00, xboxone_s_init),
651672
XBOXONE_INIT_PKT(0x045e, 0x0b00, extra_input_packet_init),
652673
XBOXONE_INIT_PKT(0x0e6f, 0x0000, xboxone_pdp_led_on),
674+
XBOXONE_INIT_PKT(0x1430, 0x079b, xboxone_pdp_led_on),
653675
XBOXONE_INIT_PKT(0x0e6f, 0x0000, xboxone_pdp_auth),
676+
XBOXONE_INIT_PKT(0x1430, 0x079b, xboxone_pdp_auth),
654677
XBOXONE_INIT_PKT(0x24c6, 0x541a, xboxone_rumblebegin_init),
655678
XBOXONE_INIT_PKT(0x24c6, 0x542a, xboxone_rumblebegin_init),
656679
XBOXONE_INIT_PKT(0x24c6, 0x543a, xboxone_rumblebegin_init),
@@ -712,13 +735,72 @@ struct usb_xpad {
712735
struct work_struct work; /* init/remove device from callback */
713736
struct delayed_work poweroff_work; /* work struct for poweroff on mode long press */
714737
time64_t mode_btn_down_ts;
738+
struct urb *ghl_urb; /* URB for GHL Xbox One magic data */
739+
struct timer_list ghl_poke_timer; /* Timer for periodic poke of GHL magic data */
715740
};
716741

717742
static int xpad_init_input(struct usb_xpad *xpad);
718743
static void xpad_deinit_input(struct usb_xpad *xpad);
719744
static void xpadone_ack_mode_report(struct usb_xpad *xpad, u8 seq_num);
720745
static void xpad360w_poweroff_controller(struct usb_xpad *xpad);
721746

747+
/*
748+
* ghl_magic_poke_cb
749+
*
750+
* Call back function that resets the timer for the next magic data poke.
751+
*/
752+
static void ghl_magic_poke_cb(struct urb *urb)
753+
{
754+
struct usb_xpad *xpad = urb->context;
755+
756+
if (urb->status < 0)
757+
pr_warn("URB transfer failed.\n");
758+
759+
mod_timer(&xpad->ghl_poke_timer, jiffies + GHL_GUITAR_POKE_INTERVAL*HZ);
760+
}
761+
762+
/*
763+
* ghl_magic_poke
764+
*
765+
* Submits the GHL magic_data URB.
766+
*/
767+
static void ghl_magic_poke(struct timer_list *t)
768+
{
769+
int ret;
770+
struct usb_xpad *xpad = from_timer(xpad, t, ghl_poke_timer);
771+
772+
ret = usb_submit_urb(xpad->ghl_urb, GFP_ATOMIC);
773+
if (ret < 0)
774+
pr_warn("URB transfer failed.\n");
775+
}
776+
777+
/*
778+
* ghl_init_urb
779+
*
780+
* Prepares the interrupt URB for GHL magic_data.
781+
*/
782+
static int ghl_init_urb(struct usb_xpad *xpad, struct usb_device *usbdev,
783+
const char ghl_magic_data[], u16 poke_size, struct usb_endpoint_descriptor *ep_irq_out)
784+
{
785+
u8 *databuf;
786+
unsigned int pipe;
787+
788+
pipe = usb_sndintpipe(usbdev, ep_irq_out->bEndpointAddress);
789+
790+
databuf = devm_kzalloc(&xpad->udev->dev, poke_size, GFP_ATOMIC);
791+
if (databuf == NULL)
792+
return -ENOMEM;
793+
794+
memcpy(databuf, ghl_magic_data, poke_size);
795+
796+
usb_fill_int_urb(
797+
xpad->ghl_urb, usbdev, pipe,
798+
databuf, poke_size,
799+
ghl_magic_poke_cb, xpad, ep_irq_out->bInterval);
800+
801+
return 0;
802+
}
803+
722804
/*
723805
* xpad_process_packet
724806
*
@@ -975,6 +1057,7 @@ static void xpadone_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char
9751057
{
9761058
struct input_dev *dev = xpad->dev;
9771059
bool do_sync = false;
1060+
int dpad_value;
9781061

9791062
/* the xbox button has its own special report */
9801063
if (data[0] == GIP_CMD_VIRTUAL_KEY) {
@@ -1116,6 +1199,48 @@ static void xpadone_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char
11161199
}
11171200
}
11181201

1202+
do_sync = true;
1203+
1204+
} else if (data[0] == 0X21) { /* The main valid packet type for GHL inputs */
1205+
/* Mapping chosen to be coherent with GHL dongles of other consoles */
1206+
1207+
/* The 6 fret buttons */
1208+
input_report_key(dev, BTN_B, data[4] & BIT(1));
1209+
input_report_key(dev, BTN_X, data[4] & BIT(2));
1210+
input_report_key(dev, BTN_Y, data[4] & BIT(3));
1211+
input_report_key(dev, BTN_A, data[4] & BIT(0));
1212+
input_report_key(dev, BTN_TL, data[4] & BIT(4));
1213+
input_report_key(dev, BTN_TR, data[4] & BIT(5));
1214+
1215+
/* D-pad */
1216+
dpad_value = data[6] & 0xF;
1217+
if (dpad_value > 7)
1218+
dpad_value = 8;
1219+
1220+
input_report_abs(dev, ABS_HAT0X, dpad_mapping[dpad_value].x);
1221+
input_report_abs(dev, ABS_HAT0Y, dpad_mapping[dpad_value].y);
1222+
1223+
/* Strum bar */
1224+
input_report_abs(dev, ABS_Y, ((data[8] - 0x80) << 9));
1225+
1226+
/* Tilt Sensor */
1227+
input_report_abs(dev, ABS_Z, ((data[9] - 0x80) << 9));
1228+
1229+
/* Whammy bar */
1230+
input_report_abs(dev, ABS_RZ, ((data[10] - 0x80) << 9));
1231+
1232+
/* Power Button */
1233+
input_report_key(dev, BTN_THUMBR, data[5] & BIT(4));
1234+
1235+
/* GHTV button */
1236+
input_report_key(dev, BTN_START, data[5] & BIT(2));
1237+
1238+
/* Hero Power button */
1239+
input_report_key(dev, BTN_MODE, data[5] & BIT(0));
1240+
1241+
/* Pause button */
1242+
input_report_key(dev, BTN_THUMBL, data[5] & BIT(1));
1243+
11191244
do_sync = true;
11201245
}
11211246

@@ -1519,7 +1644,7 @@ static void xpadone_ack_mode_report(struct usb_xpad *xpad, u8 seq_num)
15191644
struct xpad_output_packet *packet =
15201645
&xpad->out_packets[XPAD_OUT_CMD_IDX];
15211646
static const u8 mode_report_ack[] = {
1522-
GIP_CMD_ACK, GIP_OPT_INTERNAL, GIP_SEQ0, GIP_PL_LEN(9),
1647+
GIP_CMD_ACK, GIP_OPT_INTERNAL, GIP_SEQ0, GIP_PL_LEN(9),
15231648
0x00, GIP_CMD_VIRTUAL_KEY, GIP_OPT_INTERNAL, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00
15241649
};
15251650

@@ -1909,15 +2034,29 @@ static void xpad_set_up_abs(struct input_dev *input_dev, signed short abs)
19092034
switch (abs) {
19102035
case ABS_X:
19112036
case ABS_Y:
2037+
/* GHL Strum bar */
2038+
if ((xpad->xtype == XTYPE_XBOXONE) && (xpad->quirks & QUIRK_GHL_XBOXONE)) {
2039+
input_set_abs_params(input_dev, abs, -32767, 32767, 0, 0);
2040+
break;
2041+
}
19122042
case ABS_RX:
19132043
case ABS_RY: /* the two sticks */
19142044
input_set_abs_params(input_dev, abs, -32768, 32767, 16, 128);
19152045
break;
19162046
case ABS_Z:
2047+
/* GHL Tilt sensor */
2048+
if ((xpad->xtype == XTYPE_XBOXONE) && (xpad->quirks & QUIRK_GHL_XBOXONE)) {
2049+
input_set_abs_params(input_dev, abs, -32767, 32767, 0, 0);
2050+
break;
2051+
}
19172052
case ABS_RZ: /* the triggers (if mapped to axes) */
1918-
if (xpad->xtype == XTYPE_XBOXONE)
1919-
input_set_abs_params(input_dev, abs, 0, 1023, 0, 0);
1920-
else
2053+
if (xpad->xtype == XTYPE_XBOXONE) {
2054+
/* GHL Whammy bar */
2055+
if (xpad->quirks & QUIRK_GHL_XBOXONE)
2056+
input_set_abs_params(input_dev, abs, -32767, 32767, 0, 0);
2057+
else
2058+
input_set_abs_params(input_dev, abs, 0, 1023, 0, 0);
2059+
} else
19212060
input_set_abs_params(input_dev, abs, 0, 255, 0, 0);
19222061
break;
19232062
case ABS_HAT0X:
@@ -2210,6 +2349,21 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id
22102349
if (error)
22112350
goto err_deinit_output;
22122351
}
2352+
2353+
if (xpad->quirks & QUIRK_GHL_XBOXONE) {
2354+
2355+
xpad->ghl_urb = usb_alloc_urb(0, GFP_ATOMIC);
2356+
if (!xpad->ghl_urb)
2357+
return -ENOMEM;
2358+
2359+
error = ghl_init_urb(xpad, udev, ghl_xboxone_magic_data, ARRAY_SIZE(ghl_xboxone_magic_data), ep_irq_out);
2360+
2361+
if (error)
2362+
return error;
2363+
2364+
timer_setup(&xpad->ghl_poke_timer, ghl_magic_poke, 0);
2365+
mod_timer(&xpad->ghl_poke_timer, jiffies + GHL_GUITAR_POKE_INTERVAL*HZ);
2366+
}
22132367
return 0;
22142368

22152369
err_deinit_output:
@@ -2241,6 +2395,12 @@ static void xpad_disconnect(struct usb_interface *intf)
22412395
xpad_deinit_output(xpad);
22422396

22432397
usb_free_urb(xpad->irq_in);
2398+
2399+
if (xpad->quirks & QUIRK_GHL_XBOXONE) {
2400+
usb_free_urb(xpad->ghl_urb);
2401+
del_timer_sync(&xpad->ghl_poke_timer);
2402+
}
2403+
22442404
usb_free_coherent(xpad->udev, XPAD_PKT_LEN,
22452405
xpad->idata, xpad->idata_dma);
22462406

0 commit comments

Comments
 (0)