From 8a0f83eacc1bb8899094b17483de95ddf2d8fcc6 Mon Sep 17 00:00:00 2001 From: Anssi Hannula Date: Thu, 3 Apr 2008 16:17:52 -0400 Subject: [PATCH 1/9] Input: xpad - match xbox 360 devices with interface info Match Xbox 360 controllers using the interface info, i.e. interface class 255 (Vendor specific), subclass 93 and protocol 1, instead of specifying the device ids individually. As the class is vendor-specific, we have to still match against vendor id as well, though. Signed-off-by: Anssi Hannula Signed-off-by: Dmitry Torokhov --- drivers/input/joystick/xpad.c | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/drivers/input/joystick/xpad.c b/drivers/input/joystick/xpad.c index 0380597249bb..8804ad30dae2 100644 --- a/drivers/input/joystick/xpad.c +++ b/drivers/input/joystick/xpad.c @@ -91,6 +91,7 @@ #define XTYPE_XBOX 0 #define XTYPE_XBOX360 1 +#define XTYPE_UNKNOWN 2 static int dpad_to_buttons; module_param(dpad_to_buttons, bool, S_IRUGO); @@ -138,7 +139,7 @@ static const struct xpad_device { { 0x1430, 0x8888, "TX6500+ Dance Pad (first generation)", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX }, { 0x045e, 0x028e, "Microsoft X-Box 360 pad", MAP_DPAD_TO_AXES, XTYPE_XBOX360 }, { 0xffff, 0xffff, "Chinese-made Xbox Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX }, - { 0x0000, 0x0000, "Generic X-Box pad", MAP_DPAD_UNKNOWN, XTYPE_XBOX } + { 0x0000, 0x0000, "Generic X-Box pad", MAP_DPAD_UNKNOWN, XTYPE_UNKNOWN } }; static const signed short xpad_btn[] = { @@ -173,12 +174,20 @@ static const signed short xpad_abs_pad[] = { -1 /* terminating entry */ }; -/* Xbox 360 has a vendor-specific (sub)class, so we cannot match it with only - * USB_INTERFACE_INFO, more to that this device has 4 InterfaceProtocols, - * but we need only one of them. */ +/* 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. Also, some Xbox 360 devices have multiple + * interface protocols, we only need protocol 1. */ +#define XPAD_XBOX360_VENDOR(vend) \ + .match_flags = USB_DEVICE_ID_MATCH_VENDOR | USB_DEVICE_ID_MATCH_INT_INFO, \ + .idVendor = (vend), \ + .bInterfaceClass = USB_CLASS_VENDOR_SPEC, \ + .bInterfaceSubClass = 93, \ + .bInterfaceProtocol = 1 + static struct usb_device_id xpad_table [] = { { USB_INTERFACE_INFO('X', 'B', 0) }, /* X-Box USB-IF not approved class */ - { USB_DEVICE_INTERFACE_PROTOCOL(0x045e, 0x028e, 1) }, /* X-Box 360 controller */ + { XPAD_XBOX360_VENDOR(0x045e) }, /* Microsoft X-Box 360 controllers */ { } }; @@ -645,6 +654,8 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id xpad->xtype = xpad_device[i].xtype; if (xpad->dpad_mapping == MAP_DPAD_UNKNOWN) xpad->dpad_mapping = dpad_to_buttons; + if (xpad->xtype == XTYPE_UNKNOWN) + xpad->xtype = (intf->cur_altsetting->desc.bInterfaceClass == USB_CLASS_VENDOR_SPEC); xpad->dev = input_dev; usb_make_path(udev, xpad->phys, sizeof(xpad->phys)); strlcat(xpad->phys, "/input0", sizeof(xpad->phys)); From a0979923d7c34c9c60d0ee8a533f9502dcfbd42b Mon Sep 17 00:00:00 2001 From: Anssi Hannula Date: Thu, 3 Apr 2008 16:18:10 -0400 Subject: [PATCH 2/9] Input: xpad - fix dpad handling of unknown devices For devices not specifically listed in xpad.c, xpad->dpad_mapping is initially set to MAP_DPAD_UNKNOWN. In xpad_probe() it gets changed to either MAP_DPAD_TO_BUTTONS or MAP_DPAD_TO_AXES, depending on the module parameter dpad_to_buttons. However, MAP_DPAD_UNKNOWN is defined as -1, while the field is u8. This results in actual value of 255, causing the MAP_DPAD_UNKNOWN check in xpad_probe() to fail. Fix that by defining MAP_DPAD_UNKNOWN as 2 instead. Also, setting module parameter dpad_to_buttons to 1 should obviously map dpad to buttons, while the default behaviour (0) should be to map dpad to axes. However, dpad_to_buttons is directly assigned to xpad->dpad_mapping, and as MAP_DPAD_TO_BUTTONS is 0, the actual behaviour is reversed. Fix that by negating dpad_to_buttons in assignment. Signed-off-by: Anssi Hannula Signed-off-by: Dmitry Torokhov --- drivers/input/joystick/xpad.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/input/joystick/xpad.c b/drivers/input/joystick/xpad.c index 8804ad30dae2..6288c4f6e3a3 100644 --- a/drivers/input/joystick/xpad.c +++ b/drivers/input/joystick/xpad.c @@ -87,7 +87,7 @@ but we map them to axes when possible to simplify things */ #define MAP_DPAD_TO_BUTTONS 0 #define MAP_DPAD_TO_AXES 1 -#define MAP_DPAD_UNKNOWN -1 +#define MAP_DPAD_UNKNOWN 2 #define XTYPE_XBOX 0 #define XTYPE_XBOX360 1 @@ -653,7 +653,7 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id xpad->dpad_mapping = xpad_device[i].dpad_mapping; xpad->xtype = xpad_device[i].xtype; if (xpad->dpad_mapping == MAP_DPAD_UNKNOWN) - xpad->dpad_mapping = dpad_to_buttons; + xpad->dpad_mapping = !dpad_to_buttons; if (xpad->xtype == XTYPE_UNKNOWN) xpad->xtype = (intf->cur_altsetting->desc.bInterfaceClass == USB_CLASS_VENDOR_SPEC); xpad->dev = input_dev; From 97f09cb53da583cefc1ce2930de8f64b52cfc54b Mon Sep 17 00:00:00 2001 From: Anssi Hannula Date: Thu, 3 Apr 2008 16:18:23 -0400 Subject: [PATCH 3/9] Input: xpad - fix inverted Y and RY axes The commit ae91d10aab2762f81733e9194cb56eff99c8d808 inverted Y and RY axes on xbox360 so that up is positive and down is negative. This is wrong, as axes on game controllers have up as negative per convention. Also, even xpad itself reports HAT0X with up as negative. Fix that by inverting them again. Also, according to http://bugzilla.kernel.org/show_bug.cgi?id=10337 the original xbox controllers also have the Y and RY axes inverted. Fix that by inverting them as well. Cc: Brian Magnuson Signed-off-by: Anssi Hannula Signed-off-by: Dmitry Torokhov --- drivers/input/joystick/xpad.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/input/joystick/xpad.c b/drivers/input/joystick/xpad.c index 6288c4f6e3a3..316d98755440 100644 --- a/drivers/input/joystick/xpad.c +++ b/drivers/input/joystick/xpad.c @@ -236,13 +236,13 @@ static void xpad_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char *d input_report_abs(dev, ABS_X, (__s16) le16_to_cpup((__le16 *)(data + 12))); input_report_abs(dev, ABS_Y, - (__s16) le16_to_cpup((__le16 *)(data + 14))); + ~(__s16) le16_to_cpup((__le16 *)(data + 14))); /* right stick */ input_report_abs(dev, ABS_RX, (__s16) le16_to_cpup((__le16 *)(data + 16))); input_report_abs(dev, ABS_RY, - (__s16) le16_to_cpup((__le16 *)(data + 18))); + ~(__s16) le16_to_cpup((__le16 *)(data + 18))); /* triggers left/right */ input_report_abs(dev, ABS_Z, data[10]); @@ -330,13 +330,13 @@ static void xpad360_process_packet(struct usb_xpad *xpad, input_report_abs(dev, ABS_X, (__s16) le16_to_cpup((__le16 *)(data + 6))); input_report_abs(dev, ABS_Y, - (__s16) le16_to_cpup((__le16 *)(data + 8))); + ~(__s16) le16_to_cpup((__le16 *)(data + 8))); /* right stick */ input_report_abs(dev, ABS_RX, (__s16) le16_to_cpup((__le16 *)(data + 10))); input_report_abs(dev, ABS_RY, - (__s16) le16_to_cpup((__le16 *)(data + 12))); + ~(__s16) le16_to_cpup((__le16 *)(data + 12))); /* triggers left/right */ input_report_abs(dev, ABS_Z, data[4]); From 8a7ae2a890852b133342a6d72f84b0dac1bc8e8e Mon Sep 17 00:00:00 2001 From: Anssi Hannula Date: Thu, 3 Apr 2008 16:18:35 -0400 Subject: [PATCH 4/9] Input: xpad - add more xbox 360 controller ids Add Mad Catz and 0x0e6f xbox360 controllers which are already found in xpad_device[] table in xpad.c into the vendor id list. Also add Logitech into the vendor list for Logitech Chillstream gamepads. Also add the RedOctane Guitar Hero X-plorer. Signed-off-by: Anssi Hannula Signed-off-by: Dmitry Torokhov --- drivers/input/joystick/xpad.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/input/joystick/xpad.c b/drivers/input/joystick/xpad.c index 316d98755440..89524954ab46 100644 --- a/drivers/input/joystick/xpad.c +++ b/drivers/input/joystick/xpad.c @@ -110,6 +110,7 @@ static const struct xpad_device { { 0x045e, 0x0287, "Microsoft Xbox Controller S", MAP_DPAD_TO_AXES, XTYPE_XBOX }, { 0x0c12, 0x8809, "RedOctane Xbox Dance Pad", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX }, { 0x044f, 0x0f07, "Thrustmaster, Inc. Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX }, + { 0x046d, 0xc242, "Logitech Chillstream Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX360 }, { 0x046d, 0xca84, "Logitech Xbox Cordless Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX }, { 0x046d, 0xca88, "Logitech Compact Controller for Xbox", MAP_DPAD_TO_AXES, XTYPE_XBOX }, { 0x05fd, 0x1007, "Mad Catz Controller (unverified)", MAP_DPAD_TO_AXES, XTYPE_XBOX }, @@ -136,6 +137,7 @@ static const struct xpad_device { { 0x0f30, 0x8888, "BigBen XBMiniPad Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX }, { 0x102c, 0xff0c, "Joytech Wireless Advanced Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX }, { 0x12ab, 0x8809, "Xbox DDR dancepad", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX }, + { 0x1430, 0x4748, "RedOctane Guitar Hero X-plorer", MAP_DPAD_TO_AXES, XTYPE_XBOX360 }, { 0x1430, 0x8888, "TX6500+ Dance Pad (first generation)", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX }, { 0x045e, 0x028e, "Microsoft X-Box 360 pad", MAP_DPAD_TO_AXES, XTYPE_XBOX360 }, { 0xffff, 0xffff, "Chinese-made Xbox Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX }, @@ -188,6 +190,10 @@ static const signed short xpad_abs_pad[] = { 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_XBOX360_VENDOR(0x046d) }, /* Logitech X-Box 360 style controllers */ + { XPAD_XBOX360_VENDOR(0x0738) }, /* Mad Catz X-Box 360 controllers */ + { XPAD_XBOX360_VENDOR(0x0e6f) }, /* 0x0e6f X-Box 360 controllers */ + { XPAD_XBOX360_VENDOR(0x1430) }, /* RedOctane X-Box 360 controllers */ { } }; From fc55e95214f1e8384e48cff88279d16507fa5358 Mon Sep 17 00:00:00 2001 From: Anssi Hannula Date: Thu, 3 Apr 2008 16:18:44 -0400 Subject: [PATCH 5/9] Input: xpad - do not report nonexistent buttons for xbox360 The buttons BTN_C and BTN_Z are only used in the original xbox controller, not in xbox360 controller. Therefore only add them to keybit when the controller is a non-360 one. Signed-off-by: Anssi Hannula Signed-off-by: Dmitry Torokhov --- drivers/input/joystick/xpad.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/drivers/input/joystick/xpad.c b/drivers/input/joystick/xpad.c index 89524954ab46..b48f7051bf30 100644 --- a/drivers/input/joystick/xpad.c +++ b/drivers/input/joystick/xpad.c @@ -144,12 +144,19 @@ static const struct xpad_device { { 0x0000, 0x0000, "Generic X-Box pad", MAP_DPAD_UNKNOWN, XTYPE_UNKNOWN } }; -static const signed short xpad_btn[] = { - BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, /* "analog" buttons */ +/* buttons shared with xbox and xbox360 */ +static const signed short xpad_common_btn[] = { + BTN_A, BTN_B, BTN_X, BTN_Y, /* "analog" buttons */ BTN_START, BTN_BACK, BTN_THUMBL, BTN_THUMBR, /* start/back/sticks */ -1 /* terminating entry */ }; +/* original xbox controllers only */ +static const signed short xpad_btn[] = { + BTN_C, BTN_Z, /* "analog" buttons */ + -1 /* terminating entry */ +}; + /* only used if MAP_DPAD_TO_BUTTONS */ static const signed short xpad_btn_pad[] = { BTN_LEFT, BTN_RIGHT, /* d-pad left, right */ @@ -679,11 +686,14 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); /* set up buttons */ - for (i = 0; xpad_btn[i] >= 0; i++) - set_bit(xpad_btn[i], input_dev->keybit); + for (i = 0; xpad_common_btn[i] >= 0; i++) + set_bit(xpad_common_btn[i], input_dev->keybit); if (xpad->xtype == XTYPE_XBOX360) for (i = 0; xpad360_btn[i] >= 0; i++) set_bit(xpad360_btn[i], input_dev->keybit); + else + for (i = 0; xpad_btn[i] >= 0; i++) + set_bit(xpad_btn[i], input_dev->keybit); if (xpad->dpad_mapping == MAP_DPAD_TO_BUTTONS) for (i = 0; xpad_btn_pad[i] >= 0; i++) set_bit(xpad_btn_pad[i], input_dev->keybit); From cfbe20106fa00e89c1fb2c74dbff0ba80e0e539d Mon Sep 17 00:00:00 2001 From: Anssi Hannula Date: Thu, 3 Apr 2008 16:18:57 -0400 Subject: [PATCH 6/9] Input: xpad - enable force feedback on xbox 360 controllers only Commit 4994cd8dadcf9d484ab3ec19f3c7c7a4e5353c1c introduced a regression which causes xpad to report force feedback cababilities for non-360 controllers too, even while there is no actual support for those. Fix that by adding a check for XTYPE_XBOX360 to xpad_init_ff(). Signed-off-by: Anssi Hannula Signed-off-by: Dmitry Torokhov --- drivers/input/joystick/xpad.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/input/joystick/xpad.c b/drivers/input/joystick/xpad.c index b48f7051bf30..fd801135eebb 100644 --- a/drivers/input/joystick/xpad.c +++ b/drivers/input/joystick/xpad.c @@ -499,6 +499,9 @@ static int xpad_play_effect(struct input_dev *dev, void *data, static int xpad_init_ff(struct usb_xpad *xpad) { + if (xpad->xtype != XTYPE_XBOX360) + return 0; + input_set_capability(xpad->dev, EV_FF, FF_RUMBLE); return input_ff_create_memless(xpad->dev, NULL, xpad_play_effect); From bf8cb3141884138c2e4a2ecb56300ece6e8020a2 Mon Sep 17 00:00:00 2001 From: Anssi Hannula Date: Thu, 3 Apr 2008 16:19:10 -0400 Subject: [PATCH 7/9] Input: xpad - drop obsolete driver versioning The driver version numbers and changelog have not been updated in a long while to reflect actual changes. Remove the version number and add a notice that later changes can be tracked in SCM. Signed-off-by: Anssi Hannula Signed-off-by: Dmitry Torokhov --- drivers/input/joystick/xpad.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/input/joystick/xpad.c b/drivers/input/joystick/xpad.c index fd801135eebb..7188eec53cc6 100644 --- a/drivers/input/joystick/xpad.c +++ b/drivers/input/joystick/xpad.c @@ -1,5 +1,5 @@ /* - * X-Box gamepad - v0.0.6 + * X-Box gamepad driver * * Copyright (c) 2002 Marko Friedemann * 2004 Oliver Schwartz , @@ -68,6 +68,8 @@ * - dance pads will map D-PAD to buttons, not axes * - pass the module paramater 'dpad_to_buttons' to force * the D-PAD to map to buttons if your pad is not detected + * + * Later changes can be tracked in SCM. */ #include @@ -77,7 +79,6 @@ #include #include -#define DRIVER_VERSION "v0.0.6" #define DRIVER_AUTHOR "Marko Friedemann " #define DRIVER_DESC "X-Box pad driver" @@ -771,7 +772,7 @@ static int __init usb_xpad_init(void) { int result = usb_register(&xpad_driver); if (result == 0) - info(DRIVER_DESC ":" DRIVER_VERSION); + info(DRIVER_DESC); return result; } From 99de0912be6f384fc31c8e8e7ba0850d0d670385 Mon Sep 17 00:00:00 2001 From: Brian Magnuson Date: Thu, 3 Apr 2008 16:19:23 -0400 Subject: [PATCH 8/9] Input: xpad - add support for wireless xbox360 controllers Signed-off-by: Brian Magnuson Signed-off-by: Anssi Hannula Signed-off-by: Dmitry Torokhov --- drivers/input/joystick/xpad.c | 164 ++++++++++++++++++++++++++++++---- 1 file changed, 148 insertions(+), 16 deletions(-) diff --git a/drivers/input/joystick/xpad.c b/drivers/input/joystick/xpad.c index 7188eec53cc6..ebf8303d6f56 100644 --- a/drivers/input/joystick/xpad.c +++ b/drivers/input/joystick/xpad.c @@ -92,7 +92,8 @@ #define XTYPE_XBOX 0 #define XTYPE_XBOX360 1 -#define XTYPE_UNKNOWN 2 +#define XTYPE_XBOX360W 2 +#define XTYPE_UNKNOWN 3 static int dpad_to_buttons; module_param(dpad_to_buttons, bool, S_IRUGO); @@ -109,6 +110,7 @@ static const struct xpad_device { { 0x045e, 0x0289, "Microsoft X-Box pad v2 (US)", MAP_DPAD_TO_AXES, XTYPE_XBOX }, { 0x045e, 0x0285, "Microsoft X-Box pad (Japan)", MAP_DPAD_TO_AXES, XTYPE_XBOX }, { 0x045e, 0x0287, "Microsoft Xbox Controller S", MAP_DPAD_TO_AXES, XTYPE_XBOX }, + { 0x045e, 0x0719, "Xbox 360 Wireless Receiver", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360W }, { 0x0c12, 0x8809, "RedOctane Xbox Dance Pad", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX }, { 0x044f, 0x0f07, "Thrustmaster, Inc. Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX }, { 0x046d, 0xc242, "Logitech Chillstream Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX360 }, @@ -186,22 +188,25 @@ static const signed short xpad_abs_pad[] = { /* 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. Also, some Xbox 360 devices have multiple - * interface protocols, we only need protocol 1. */ -#define XPAD_XBOX360_VENDOR(vend) \ + * match against vendor id as well. Wired Xbox 360 devices have protocol 1, + * 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), \ .bInterfaceClass = USB_CLASS_VENDOR_SPEC, \ .bInterfaceSubClass = 93, \ - .bInterfaceProtocol = 1 + .bInterfaceProtocol = (pr) +#define XPAD_XBOX360_VENDOR(vend) \ + { XPAD_XBOX360_VENDOR_PROTOCOL(vend,1) }, \ + { XPAD_XBOX360_VENDOR_PROTOCOL(vend,129) } 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_XBOX360_VENDOR(0x046d) }, /* Logitech X-Box 360 style controllers */ - { XPAD_XBOX360_VENDOR(0x0738) }, /* Mad Catz X-Box 360 controllers */ - { XPAD_XBOX360_VENDOR(0x0e6f) }, /* 0x0e6f X-Box 360 controllers */ - { XPAD_XBOX360_VENDOR(0x1430) }, /* RedOctane X-Box 360 controllers */ + XPAD_XBOX360_VENDOR(0x045e), /* Microsoft X-Box 360 controllers */ + XPAD_XBOX360_VENDOR(0x046d), /* Logitech X-Box 360 style controllers */ + XPAD_XBOX360_VENDOR(0x0738), /* Mad Catz X-Box 360 controllers */ + XPAD_XBOX360_VENDOR(0x0e6f), /* 0x0e6f X-Box 360 controllers */ + XPAD_XBOX360_VENDOR(0x1430), /* RedOctane X-Box 360 controllers */ { } }; @@ -211,10 +216,15 @@ struct usb_xpad { struct input_dev *dev; /* input device interface */ struct usb_device *udev; /* usb device */ + int pad_present; + struct urb *irq_in; /* urb for interrupt in report */ unsigned char *idata; /* input data */ dma_addr_t idata_dma; + 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 */ @@ -359,6 +369,39 @@ static void xpad360_process_packet(struct usb_xpad *xpad, input_sync(dev); } +/* + * xpad360w_process_packet + * + * Completes a request by converting the data into events for the + * input subsystem. It is version for xbox 360 wireless controller. + * + * Byte.Bit + * 00.1 - Status change: The controller or headset has connected/disconnected + * Bits 01.7 and 01.6 are valid + * 01.7 - Controller present + * 01.6 - Headset present + * 01.1 - Pad state (Bytes 4+) valid + * + */ + +static void xpad360w_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char *data) +{ + /* Presence change */ + if (data[0] & 0x08) { + if (data[1] & 0x80) { + xpad->pad_present = 1; + usb_submit_urb(xpad->bulk_out, GFP_ATOMIC); + } else + xpad->pad_present = 0; + } + + /* Valid pad data */ + if (!(data[1] & 0x1)) + return; + + xpad360_process_packet(xpad, cmd, &data[4]); +} + static void xpad_irq_in(struct urb *urb) { struct usb_xpad *xpad = urb->context; @@ -381,10 +424,16 @@ static void xpad_irq_in(struct urb *urb) goto exit; } - if (xpad->xtype == XTYPE_XBOX360) + switch (xpad->xtype) { + case XTYPE_XBOX360: xpad360_process_packet(xpad, 0, xpad->idata); - else + break; + case XTYPE_XBOX360W: + xpad360w_process_packet(xpad, 0, xpad->idata); + break; + default: xpad_process_packet(xpad, 0, xpad->idata); + } exit: retval = usb_submit_urb (urb, GFP_ATOMIC); @@ -422,6 +471,23 @@ exit: __FUNCTION__, retval); } +static void xpad_bulk_out(struct urb *urb) +{ + switch (urb->status) { + case 0: + /* success */ + break; + case -ECONNRESET: + case -ENOENT: + case -ESHUTDOWN: + /* this urb is terminated, clean up */ + dbg("%s - urb shutting down with status: %d", __FUNCTION__, urb->status); + break; + default: + dbg("%s - nonzero urb status received: %d", __FUNCTION__, urb->status); + } +} + static int xpad_init_output(struct usb_interface *intf, struct usb_xpad *xpad) { struct usb_endpoint_descriptor *ep_irq_out; @@ -600,6 +666,10 @@ static int xpad_open(struct input_dev *dev) { struct usb_xpad *xpad = input_get_drvdata(dev); + /* URB was submitted in probe */ + if(xpad->xtype == XTYPE_XBOX360W) + return 0; + xpad->irq_in->dev = xpad->udev; if (usb_submit_urb(xpad->irq_in, GFP_KERNEL)) return -EIO; @@ -611,7 +681,8 @@ static void xpad_close(struct input_dev *dev) { struct usb_xpad *xpad = input_get_drvdata(dev); - usb_kill_urb(xpad->irq_in); + if(xpad->xtype != XTYPE_XBOX360W) + usb_kill_urb(xpad->irq_in); xpad_stop_output(xpad); } @@ -671,8 +742,15 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id xpad->xtype = xpad_device[i].xtype; if (xpad->dpad_mapping == MAP_DPAD_UNKNOWN) xpad->dpad_mapping = !dpad_to_buttons; - if (xpad->xtype == XTYPE_UNKNOWN) - xpad->xtype = (intf->cur_altsetting->desc.bInterfaceClass == USB_CLASS_VENDOR_SPEC); + if (xpad->xtype == XTYPE_UNKNOWN) { + if (intf->cur_altsetting->desc.bInterfaceClass == USB_CLASS_VENDOR_SPEC) { + if (intf->cur_altsetting->desc.bInterfaceProtocol == 129) + xpad->xtype = XTYPE_XBOX360W; + else + xpad->xtype = XTYPE_XBOX360; + } else + xpad->xtype = XTYPE_XBOX; + } xpad->dev = input_dev; usb_make_path(udev, xpad->phys, sizeof(xpad->phys)); strlcat(xpad->phys, "/input0", sizeof(xpad->phys)); @@ -692,7 +770,7 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id /* set up buttons */ for (i = 0; xpad_common_btn[i] >= 0; i++) set_bit(xpad_common_btn[i], input_dev->keybit); - if (xpad->xtype == XTYPE_XBOX360) + if ((xpad->xtype == XTYPE_XBOX360) || (xpad->xtype == XTYPE_XBOX360W)) for (i = 0; xpad360_btn[i] >= 0; i++) set_bit(xpad360_btn[i], input_dev->keybit); else @@ -734,8 +812,57 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id goto fail4; usb_set_intfdata(intf, xpad); + + /* + * Submit the int URB immediatly rather than waiting for open + * because we get status messages from the device whether + * or not any controllers are attached. In fact, it's + * exactly the message that a controller has arrived that + * we're waiting for. + */ + if (xpad->xtype == XTYPE_XBOX360W) { + xpad->irq_in->dev = xpad->udev; + error = usb_submit_urb(xpad->irq_in, GFP_KERNEL); + if (error) + goto fail4; + + /* + * Setup the message to set the LEDs on the + * controller when it shows up + */ + xpad->bulk_out = usb_alloc_urb(0, GFP_KERNEL); + if(!xpad->bulk_out) + goto fail5; + + xpad->bdata = kzalloc(XPAD_PKT_LEN, GFP_KERNEL); + if(!xpad->bdata) + goto fail6; + + xpad->bdata[2] = 0x08; + switch (intf->cur_altsetting->desc.bInterfaceNumber) { + case 0: + xpad->bdata[3] = 0x42; + break; + case 2: + xpad->bdata[3] = 0x43; + break; + case 4: + xpad->bdata[3] = 0x44; + break; + case 6: + xpad->bdata[3] = 0x45; + } + + ep_irq_in = &intf->cur_altsetting->endpoint[1].desc; + usb_fill_bulk_urb(xpad->bulk_out, udev, + usb_sndbulkpipe(udev, ep_irq_in->bEndpointAddress), + xpad->bdata, XPAD_PKT_LEN, xpad_bulk_out, xpad); + } + return 0; + fail6: usb_free_urb(xpad->bulk_out); + fail5: usb_kill_urb(xpad->irq_in); fail4: usb_free_urb(xpad->irq_in); fail3: xpad_deinit_output(xpad); fail2: usb_buffer_free(udev, XPAD_PKT_LEN, xpad->idata, xpad->idata_dma); @@ -754,6 +881,11 @@ static void xpad_disconnect(struct usb_interface *intf) xpad_led_disconnect(xpad); input_unregister_device(xpad->dev); xpad_deinit_output(xpad); + if (xpad->xtype == XTYPE_XBOX360W) { + usb_kill_urb(xpad->bulk_out); + usb_free_urb(xpad->bulk_out); + usb_kill_urb(xpad->irq_in); + } usb_free_urb(xpad->irq_in); usb_buffer_free(xpad->udev, XPAD_PKT_LEN, xpad->idata, xpad->idata_dma); From 6eae9b0acdb6f03ed87ef882760e0ef8f440dc1a Mon Sep 17 00:00:00 2001 From: Oliver Neukum Date: Thu, 3 Apr 2008 16:19:33 -0400 Subject: [PATCH 9/9] Input: xpad - don't use GFP_ATOMIC GFP_ATOMIC should not be used when GFP_KERNEL can be used. Signed-off-by: Oliver Neukum Signed-off-by: Dmitry Torokhov --- drivers/input/joystick/xpad.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/input/joystick/xpad.c b/drivers/input/joystick/xpad.c index ebf8303d6f56..d4d289e75dc2 100644 --- a/drivers/input/joystick/xpad.c +++ b/drivers/input/joystick/xpad.c @@ -497,7 +497,7 @@ static int xpad_init_output(struct usb_interface *intf, struct usb_xpad *xpad) return 0; xpad->odata = usb_buffer_alloc(xpad->udev, XPAD_PKT_LEN, - GFP_ATOMIC, &xpad->odata_dma ); + GFP_KERNEL, &xpad->odata_dma); if (!xpad->odata) goto fail1; @@ -729,7 +729,7 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id goto fail1; xpad->idata = usb_buffer_alloc(udev, XPAD_PKT_LEN, - GFP_ATOMIC, &xpad->idata_dma); + GFP_KERNEL, &xpad->idata_dma); if (!xpad->idata) goto fail1;