Skip to content

Commit 8a6548c

Browse files
Oblomovparoj
authored andcommitted
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 <[email protected]> Signed-off-by: Vicki Pfau <[email protected]>
1 parent e79082e commit 8a6548c

File tree

1 file changed

+108
-0
lines changed

1 file changed

+108
-0
lines changed

xpad.c

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,12 @@
105105
#define PKT_XBE2_FW_5_EARLY 3
106106
#define PKT_XBE2_FW_5_11 4
107107

108+
#define QUIRK_360_START_PKT_1 (1 << 0)
109+
#define QUIRK_360_START_PKT_2 (1 << 1)
110+
#define QUIRK_360_START_PKT_3 (1 << 2)
111+
#define QUIRK_360_START (QUIRK_360_START_PKT_1 | \
112+
QUIRK_360_START_PKT_2 | QUIRK_360_START_PKT_3)
113+
108114
static bool dpad_to_buttons;
109115
module_param(dpad_to_buttons, bool, S_IRUGO);
110116
MODULE_PARM_DESC(dpad_to_buttons, "Map D-PAD to buttons rather than axes for unknown pads");
@@ -127,6 +133,7 @@ static const struct xpad_device {
127133
char *name;
128134
u8 mapping;
129135
u8 xtype;
136+
u8 quirks;
130137
} xpad_device[] = {
131138
/* Please keep this list sorted by vendor and product ID. */
132139
{ 0x0079, 0x18d4, "GPD Win 2 X-Box Controller", 0, XTYPE_XBOX360 },
@@ -168,6 +175,7 @@ static const struct xpad_device {
168175
{ 0x046d, 0xca8a, "Logitech Precision Vibration Feedback Wheel", 0, XTYPE_XBOX },
169176
{ 0x046d, 0xcaa3, "Logitech DriveFx Racing Wheel", 0, XTYPE_XBOX360 },
170177
{ 0x056e, 0x2004, "Elecom JC-U3613M", 0, XTYPE_XBOX360 },
178+
{ 0x05ac, 0x055b, "Gamesir-G3w", 0, XTYPE_XBOX360, QUIRK_360_START },
171179
{ 0x05fd, 0x1007, "Mad Catz Controller (unverified)", 0, XTYPE_XBOX },
172180
{ 0x05fd, 0x107a, "InterAct 'PowerPad Pro' X-Box pad (Germany)", 0, XTYPE_XBOX },
173181
{ 0x05fe, 0x3030, "Chic Controller", 0, XTYPE_XBOX },
@@ -755,6 +763,7 @@ struct usb_xpad {
755763
int xtype; /* type of xbox device */
756764
int packet_type; /* type of the extended packet */
757765
int pad_nr; /* the order x360 pads were attached */
766+
int quirks;
758767
const char *name; /* name of the device */
759768
struct work_struct work; /* init/remove device from callback */
760769
struct delayed_work poweroff_work; /* work struct for poweroff on mode long press */
@@ -1489,6 +1498,98 @@ static int xpad_start_xbox_one(struct usb_xpad *xpad)
14891498
return retval;
14901499
}
14911500

1501+
static int xpad_start_xbox_360(struct usb_xpad *xpad)
1502+
{
1503+
int status;
1504+
1505+
char *data = kzalloc(20, GFP_KERNEL);
1506+
1507+
int TIMEOUT = 100;
1508+
1509+
/*
1510+
this init sequence is needed for the gamesir g3w controller
1511+
and for shanwan controllers in xpad mode.
1512+
Unfortunately, in this mode they identify as 0x045e, 0x028e, so we
1513+
have to inspect the manufacturer string.
1514+
Sending this sequence to other controllers will break initialization.
1515+
*/
1516+
bool is_shanwan = xpad->udev->manufacturer && strcasecmp("shanwan", xpad->udev->manufacturer) == 0;
1517+
if (!(xpad->quirks & QUIRK_360_START) && !is_shanwan) {
1518+
status = 0;
1519+
goto err_free_ctrl_data;
1520+
}
1521+
1522+
if ((xpad->quirks & QUIRK_360_START_PKT_1) || is_shanwan) {
1523+
status = usb_control_msg(xpad->udev,
1524+
usb_rcvctrlpipe(xpad->udev, 0),
1525+
0x1, 0xc1,
1526+
cpu_to_le16(0x100), cpu_to_le16(0x0), data, cpu_to_le16(20),
1527+
TIMEOUT);
1528+
1529+
#ifdef DEBUG
1530+
dev_dbg(&xpad->intf->dev,
1531+
"%s - control message 1 returned %d\n", __func__, status);
1532+
#endif
1533+
1534+
if (status < 0) {
1535+
goto err_free_ctrl_data;
1536+
}
1537+
#ifdef DEBUG
1538+
else {
1539+
print_hex_dump(KERN_DEBUG, "xpad-dbg: ", DUMP_PREFIX_OFFSET, 32, 1, data, 20, 0);
1540+
}
1541+
#endif
1542+
}
1543+
1544+
if ((xpad->quirks & QUIRK_360_START_PKT_2) || is_shanwan) {
1545+
status = usb_control_msg(xpad->udev,
1546+
usb_rcvctrlpipe(xpad->udev, 0),
1547+
0x1, 0xc1,
1548+
cpu_to_le16(0x0), cpu_to_le16(0x0), data, cpu_to_le16(8),
1549+
TIMEOUT);
1550+
#ifdef DEBUG
1551+
dev_dbg(&xpad->intf->dev,
1552+
"%s - control message 2 returned %d\n", __func__, status);
1553+
#endif
1554+
1555+
if (status < 0) {
1556+
goto err_free_ctrl_data;
1557+
}
1558+
#ifdef DEBUG
1559+
else {
1560+
print_hex_dump(KERN_DEBUG, "xpad-dbg: ", DUMP_PREFIX_OFFSET, 32, 1, data, 8, 0);
1561+
}
1562+
#endif
1563+
}
1564+
1565+
if ((xpad->quirks & QUIRK_360_START_PKT_3) || is_shanwan) {
1566+
status = usb_control_msg(xpad->udev,
1567+
usb_rcvctrlpipe(xpad->udev, 0),
1568+
0x1, 0xc0,
1569+
cpu_to_le16(0x0), cpu_to_le16(0x0), data, cpu_to_le16(4),
1570+
TIMEOUT);
1571+
#ifdef DEBUG
1572+
dev_dbg(&xpad->intf->dev,
1573+
"%s - control message 3 returned %d\n", __func__, status);
1574+
#endif
1575+
1576+
if (status < 0) {
1577+
goto err_free_ctrl_data;
1578+
}
1579+
#ifdef DEBUG
1580+
else {
1581+
print_hex_dump(KERN_DEBUG, "xpad-dbg: ", DUMP_PREFIX_OFFSET, 32, 1, data, 4, 0);
1582+
}
1583+
#endif
1584+
}
1585+
1586+
status = 0;
1587+
1588+
err_free_ctrl_data:
1589+
kfree(data);
1590+
return status;
1591+
}
1592+
14921593
static void xpadone_ack_mode_report(struct usb_xpad *xpad, u8 seq_num)
14931594
{
14941595
unsigned long flags;
@@ -1774,6 +1875,12 @@ static int xpad_start_input(struct usb_xpad *xpad)
17741875
{
17751876
int error;
17761877

1878+
if (xpad->xtype == XTYPE_XBOX360) {
1879+
error = xpad_start_xbox_360(xpad);
1880+
if (error)
1881+
return error;
1882+
}
1883+
17771884
if (usb_submit_urb(xpad->irq_in, GFP_KERNEL))
17781885
return -EIO;
17791886

@@ -2085,6 +2192,7 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id
20852192
xpad->mapping = xpad_device[i].mapping;
20862193
xpad->xtype = xpad_device[i].xtype;
20872194
xpad->name = xpad_device[i].name;
2195+
xpad->quirks = xpad_device[i].quirks;
20882196
xpad->packet_type = PKT_XB;
20892197
INIT_WORK(&xpad->work, xpad_presence_work);
20902198

0 commit comments

Comments
 (0)