@@ -95,7 +95,8 @@
#define XTYPE_XBOX 0
#define XTYPE_XBOX360 1
#define XTYPE_XBOX360W 2
-#define XTYPE_UNKNOWN 3
+#define XTYPE_XBOXONE 3
+#define XTYPE_UNKNOWN 4
static bool dpad_to_buttons;
module_param (dpad_to_buttons, bool , S_IRUGO);
@@ -121,6 +122,7 @@ static const struct xpad_device {
{ 0x045e , 0x0287 , " Microsoft Xbox Controller S" , 0 , XTYPE_XBOX },
{ 0x045e , 0x0289 , " Microsoft X-Box pad v2 (US)" , 0 , XTYPE_XBOX },
{ 0x045e , 0x028e , " Microsoft X-Box 360 pad" , 0 , XTYPE_XBOX360 },
+ { 0x045e , 0x02d1 , " Microsoft X-Box One pad" , 0 , XTYPE_XBOXONE },
{ 0x045e , 0x0291 , " Xbox 360 Wireless Receiver (XBOX)" , MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360W },
{ 0x045e , 0x0719 , " Xbox 360 Wireless Receiver" , MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360W },
{ 0x044f , 0x0f07 , " Thrustmaster, Inc. Controller" , 0 , XTYPE_XBOX },
@@ -231,10 +233,12 @@ static const signed short xpad_abs_triggers[] = {
-1
};
-/* Xbox 360 has a vendor-specific class, so we cannot match it with only
+/*
+ * 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
* match against vendor id as well. Wired Xbox 360 devices have protocol 1,
- * wireless controllers have protocol 129. */
+ * wireless controllers have protocol 129.
+ */
#define XPAD_XBOX360_VENDOR_PROTOCOL (vend,pr ) \
.match_flags = USB_DEVICE_ID_MATCH_VENDOR | USB_DEVICE_ID_MATCH_INT_INFO, \
.idVendor = (vend), \
@@ -245,9 +249,20 @@ static const signed short xpad_abs_triggers[] = {
{ XPAD_XBOX360_VENDOR_PROTOCOL (vend,1 ) }, \
{ XPAD_XBOX360_VENDOR_PROTOCOL (vend,129 ) }
+/* The Xbox One controller uses subclass 71 and protocol 208. */
+#define XPAD_XBOXONE_VENDOR_PROTOCOL (vend, pr ) \
+ .match_flags = USB_DEVICE_ID_MATCH_VENDOR | USB_DEVICE_ID_MATCH_INT_INFO, \
+ .idVendor = (vend), \
+ .bInterfaceClass = USB_CLASS_VENDOR_SPEC, \
+ .bInterfaceSubClass = 71 , \
+ .bInterfaceProtocol = (pr)
+#define XPAD_XBOXONE_VENDOR (vend ) \
+ { XPAD_XBOXONE_VENDOR_PROTOCOL (vend, 208 ) }
+
static struct usb_device_id xpad_table[] = {
{ USB_INTERFACE_INFO (' X' , ' B' , 0 ) }, /* X-Box USB-IF not approved class */
XPAD_XBOX360_VENDOR (0x045e ), /* Microsoft X-Box 360 controllers */
+ XPAD_XBOXONE_VENDOR (0x045e ), /* Microsoft X-Box One controllers */
XPAD_XBOX360_VENDOR (0x046d ), /* Logitech X-Box 360 style controllers */
XPAD_XBOX360_VENDOR (0x0738 ), /* Mad Catz X-Box 360 controllers */
{ USB_DEVICE (0x0738 , 0x4540 ) }, /* Mad Catz Beat Pad */
@@ -278,12 +293,10 @@ struct usb_xpad {
struct urb *bulk_out;
unsigned char *bdata;
-#if defined(CONFIG_JOYSTICK_XPAD_FF) || defined(CONFIG_JOYSTICK_XPAD_LEDS)
struct urb *irq_out; /* urb for interrupt out report */
unsigned char *odata; /* output data */
dma_addr_t odata_dma;
struct mutex odata_mutex;
-#endif
#if defined(CONFIG_JOYSTICK_XPAD_LEDS)
struct xpad_led *led;
@@ -470,6 +483,105 @@ static void xpad360w_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned cha
xpad360_process_packet (xpad, cmd, &data[4 ]);
}
+/*
+ * xpadone_process_buttons
+ *
+ * Process a button update packet from an Xbox one controller.
+ */
+static void xpadone_process_buttons (struct usb_xpad *xpad,
+ struct input_dev *dev,
+ unsigned char *data)
+{
+ /* menu/view buttons */
+ input_report_key (dev, BTN_START, data[4 ] & 0x04 );
+ input_report_key (dev, BTN_SELECT, data[4 ] & 0x08 );
+
+ /* 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 );
+
+ /* 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 );
+ } else {
+ input_report_abs (dev, ABS_HAT0X,
+ !!(data[5 ] & 0x08 ) - !!(data[5 ] & 0x04 ));
+ input_report_abs (dev, ABS_HAT0Y,
+ !!(data[5 ] & 0x02 ) - !!(data[5 ] & 0x01 ));
+ }
+
+ /* TL/TR */
+ input_report_key (dev, BTN_TL, data[5 ] & 0x10 );
+ input_report_key (dev, BTN_TR, data[5 ] & 0x20 );
+
+ /* stick press left/right */
+ input_report_key (dev, BTN_THUMBL, data[5 ] & 0x40 );
+ input_report_key (dev, BTN_THUMBR, data[5 ] & 0x80 );
+
+ if (!(xpad->mapping & MAP_STICKS_TO_NULL)) {
+ /* left stick */
+ input_report_abs (dev, ABS_X,
+ (__s16) le16_to_cpup ((__le16 *)(data + 10 )));
+ input_report_abs (dev, ABS_Y,
+ ~(__s16) le16_to_cpup ((__le16 *)(data + 12 )));
+
+ /* right stick */
+ input_report_abs (dev, ABS_RX,
+ (__s16) le16_to_cpup ((__le16 *)(data + 14 )));
+ input_report_abs (dev, ABS_RY,
+ ~(__s16) le16_to_cpup ((__le16 *)(data + 16 )));
+ }
+
+ /* triggers left/right */
+ if (xpad->mapping & MAP_TRIGGERS_TO_BUTTONS) {
+ input_report_key (dev, BTN_TL2,
+ (__u16) le16_to_cpup ((__le16 *)(data + 6 )));
+ input_report_key (dev, BTN_TR2,
+ (__u16) le16_to_cpup ((__le16 *)(data + 8 )));
+ } else {
+ input_report_abs (dev, ABS_Z,
+ (__u16) le16_to_cpup ((__le16 *)(data + 6 )));
+ input_report_abs (dev, ABS_RZ,
+ (__u16) le16_to_cpup ((__le16 *)(data + 8 )));
+ }
+
+ input_sync (dev);
+}
+
+/*
+ * xpadone_process_packet
+ *
+ * Completes a request by converting the data into events for the
+ * input subsystem. This version is for the Xbox One controller.
+ *
+ * The report format was gleaned from
+ * https://github.com/kylelemons/xbox/blob/master/xbox.go
+ */
+
+static void xpadone_process_packet (struct usb_xpad *xpad,
+ u16 cmd, unsigned char *data)
+{
+ struct input_dev *dev = xpad->dev;
+
+ switch (data[0 ]) {
+ case 0x20 :
+ xpadone_process_buttons (xpad, dev, data);
+ break ;
+
+ case 0x07 :
+ /* the xbox button has its own special report */
+ input_report_key (dev, BTN_MODE, data[4 ] & 0x01 );
+ input_sync (dev);
+ break ;
+ }
+}
+
static void xpad_irq_in (struct urb *urb)
{
struct usb_xpad *xpad = urb->context;
@@ -502,6 +614,9 @@ static void xpad_irq_in(struct urb *urb)
case XTYPE_XBOX360W:
xpad360w_process_packet (xpad, 0 , xpad->idata);
break ;
+ case XTYPE_XBOXONE:
+ xpadone_process_packet (xpad, 0 , xpad->idata);
+ break ;
default :
xpad_process_packet (xpad, 0 , xpad->idata);
}
@@ -535,7 +650,6 @@ static void xpad_bulk_out(struct urb *urb)
}
}
-#if defined(CONFIG_JOYSTICK_XPAD_FF) || defined(CONFIG_JOYSTICK_XPAD_LEDS)
static void xpad_irq_out (struct urb *urb)
{
struct usb_xpad *xpad = urb->context;
@@ -573,6 +687,7 @@ static void xpad_irq_out(struct urb *urb)
static int xpad_init_output (struct usb_interface *intf, struct usb_xpad *xpad)
{
struct usb_endpoint_descriptor *ep_irq_out;
+ int ep_irq_out_idx;
int error;
if (xpad->xtype == XTYPE_UNKNOWN)
@@ -593,7 +708,10 @@ static int xpad_init_output(struct usb_interface *intf, struct usb_xpad *xpad)
goto fail2;
}
- ep_irq_out = &intf->cur_altsetting->endpoint[1 ].desc ;
+ /* Xbox One controller has in/out endpoints swapped. */
+ ep_irq_out_idx = xpad->xtype == XTYPE_XBOXONE ? 0 : 1 ;
+ ep_irq_out = &intf->cur_altsetting->endpoint[ep_irq_out_idx].desc ;
+
usb_fill_int_urb (xpad->irq_out, xpad->udev,
usb_sndintpipe (xpad->udev, ep_irq_out->bEndpointAddress),
xpad->odata, XPAD_PKT_LEN,
@@ -621,11 +739,6 @@ static void xpad_deinit_output(struct usb_xpad *xpad)
xpad->odata, xpad->odata_dma);
}
}
-#else
-static int xpad_init_output (struct usb_interface *intf, struct usb_xpad *xpad) { return 0 ; }
-static void xpad_deinit_output (struct usb_xpad *xpad) {}
-static void xpad_stop_output (struct usb_xpad *xpad) {}
-#endif
#ifdef CONFIG_JOYSTICK_XPAD_FF
static int xpad_play_effect (struct input_dev *dev, void *data, struct ff_effect *effect)
@@ -692,7 +805,7 @@ static int xpad_play_effect(struct input_dev *dev, void *data, struct ff_effect
static int xpad_init_ff (struct usb_xpad *xpad)
{
- if (xpad->xtype == XTYPE_UNKNOWN)
+ if (xpad->xtype == XTYPE_UNKNOWN || xpad->xtype == XTYPE_XBOXONE )
return 0 ;
input_set_capability (xpad->dev, EV_FF, FF_RUMBLE);
@@ -801,6 +914,14 @@ static int xpad_open(struct input_dev *dev)
if (usb_submit_urb (xpad->irq_in, GFP_KERNEL))
return -EIO;
+ if (xpad->xtype == XTYPE_XBOXONE) {
+ /* Xbox one controller needs to be initialized. */
+ xpad->odata[0 ] = 0x05 ;
+ xpad->odata[1 ] = 0x20 ;
+ xpad->irq_out->transfer_buffer_length = 2 ;
+ return usb_submit_urb (xpad->irq_out, GFP_KERNEL);
+ }
+
return 0 ;
}
@@ -816,6 +937,7 @@ static void xpad_close(struct input_dev *dev)
static void xpad_set_up_abs (struct input_dev *input_dev, signed short abs)
{
+ struct usb_xpad *xpad = input_get_drvdata (input_dev);
set_bit (abs , input_dev->absbit);
switch (abs ) {
@@ -827,7 +949,10 @@ static void xpad_set_up_abs(struct input_dev *input_dev, signed short abs)
break ;
case ABS_Z:
case ABS_RZ: /* the triggers (if mapped to axes) */
- input_set_abs_params (input_dev, abs , 0 , 255 , 0 , 0 );
+ if (xpad->xtype == XTYPE_XBOXONE)
+ 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:
case ABS_HAT0Y: /* the d-pad (only if dpad is mapped to axes */
@@ -842,6 +967,7 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id
struct usb_xpad *xpad;
struct input_dev *input_dev;
struct usb_endpoint_descriptor *ep_irq_in;
+ int ep_irq_in_idx;
int i, error;
for (i = 0 ; xpad_device[i].idVendor ; i++) {
@@ -850,6 +976,16 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id
break ;
}
+ if (xpad_device[i].xtype == XTYPE_XBOXONE &&
+ intf->cur_altsetting->desc.bInterfaceNumber != 0 ) {
+ /*
+ * The Xbox One controller lists three interfaces all with the
+ * same interface class, subclass and protocol. Differentiate by
+ * interface number.
+ */
+ return -ENODEV;
+ }
+
xpad = kzalloc (sizeof (struct usb_xpad), GFP_KERNEL);
input_dev = input_allocate_device ();
if (!xpad || !input_dev) {
@@ -920,7 +1056,8 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id
__set_bit (xpad_common_btn[i], input_dev->keybit);
/* set up model-specific ones */
- if (xpad->xtype == XTYPE_XBOX360 || xpad->xtype == XTYPE_XBOX360W) {
+ if (xpad->xtype == XTYPE_XBOX360 || xpad->xtype == XTYPE_XBOX360W ||
+ xpad->xtype == XTYPE_XBOXONE) {
for (i = 0 ; xpad360_btn[i] >= 0 ; i++)
__set_bit (xpad360_btn[i], input_dev->keybit);
} else {
@@ -933,7 +1070,7 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id
__set_bit (xpad_btn_pad[i], input_dev->keybit);
} else {
for (i = 0 ; xpad_abs_pad[i] >= 0 ; i++)
- xpad_set_up_abs (input_dev, xpad_abs_pad[i]);
+ xpad_set_up_abs (input_dev, xpad_abs_pad[i]);
}
if (xpad->mapping & MAP_TRIGGERS_TO_BUTTONS) {
@@ -956,7 +1093,10 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id
if (error)
goto fail5;
- ep_irq_in = &intf->cur_altsetting->endpoint[0 ].desc ;
+ /* Xbox One controller has in/out endpoints swapped. */
+ ep_irq_in_idx = xpad->xtype == XTYPE_XBOXONE ? 1 : 0 ;
+ ep_irq_in = &intf->cur_altsetting->endpoint[ep_irq_in_idx].desc ;
+
usb_fill_int_urb (xpad->irq_in, udev,
usb_rcvintpipe (udev, ep_irq_in->bEndpointAddress),
xpad->idata, XPAD_PKT_LEN, xpad_irq_in,
0 comments on commit
1a48ff8