diff options
author | Brian Magnuson <bdmagnuson@gmail.com> | 2008-04-03 16:19:23 -0400 |
---|---|---|
committer | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2008-04-03 16:19:23 -0400 |
commit | 99de0912be6f384fc31c8e8e7ba0850d0d670385 (patch) | |
tree | 89b41c3879a023544d174270c0437597d3748bb8 /drivers/input | |
parent | bf8cb3141884138c2e4a2ecb56300ece6e8020a2 (diff) |
Input: xpad - add support for wireless xbox360 controllers
Signed-off-by: Brian Magnuson <bdmagnuson@gmail.com>
Signed-off-by: Anssi Hannula <anssi.hannula@gmail.com>
Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
Diffstat (limited to 'drivers/input')
-rw-r--r-- | drivers/input/joystick/xpad.c | 164 |
1 files 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 @@ | |||
92 | 92 | ||
93 | #define XTYPE_XBOX 0 | 93 | #define XTYPE_XBOX 0 |
94 | #define XTYPE_XBOX360 1 | 94 | #define XTYPE_XBOX360 1 |
95 | #define XTYPE_UNKNOWN 2 | 95 | #define XTYPE_XBOX360W 2 |
96 | #define XTYPE_UNKNOWN 3 | ||
96 | 97 | ||
97 | static int dpad_to_buttons; | 98 | static int dpad_to_buttons; |
98 | module_param(dpad_to_buttons, bool, S_IRUGO); | 99 | module_param(dpad_to_buttons, bool, S_IRUGO); |
@@ -109,6 +110,7 @@ static const struct xpad_device { | |||
109 | { 0x045e, 0x0289, "Microsoft X-Box pad v2 (US)", MAP_DPAD_TO_AXES, XTYPE_XBOX }, | 110 | { 0x045e, 0x0289, "Microsoft X-Box pad v2 (US)", MAP_DPAD_TO_AXES, XTYPE_XBOX }, |
110 | { 0x045e, 0x0285, "Microsoft X-Box pad (Japan)", MAP_DPAD_TO_AXES, XTYPE_XBOX }, | 111 | { 0x045e, 0x0285, "Microsoft X-Box pad (Japan)", MAP_DPAD_TO_AXES, XTYPE_XBOX }, |
111 | { 0x045e, 0x0287, "Microsoft Xbox Controller S", MAP_DPAD_TO_AXES, XTYPE_XBOX }, | 112 | { 0x045e, 0x0287, "Microsoft Xbox Controller S", MAP_DPAD_TO_AXES, XTYPE_XBOX }, |
113 | { 0x045e, 0x0719, "Xbox 360 Wireless Receiver", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360W }, | ||
112 | { 0x0c12, 0x8809, "RedOctane Xbox Dance Pad", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX }, | 114 | { 0x0c12, 0x8809, "RedOctane Xbox Dance Pad", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX }, |
113 | { 0x044f, 0x0f07, "Thrustmaster, Inc. Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX }, | 115 | { 0x044f, 0x0f07, "Thrustmaster, Inc. Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX }, |
114 | { 0x046d, 0xc242, "Logitech Chillstream Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX360 }, | 116 | { 0x046d, 0xc242, "Logitech Chillstream Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX360 }, |
@@ -186,22 +188,25 @@ static const signed short xpad_abs_pad[] = { | |||
186 | 188 | ||
187 | /* Xbox 360 has a vendor-specific class, so we cannot match it with only | 189 | /* Xbox 360 has a vendor-specific class, so we cannot match it with only |
188 | * USB_INTERFACE_INFO (also specifically refused by USB subsystem), so we | 190 | * USB_INTERFACE_INFO (also specifically refused by USB subsystem), so we |
189 | * match against vendor id as well. Also, some Xbox 360 devices have multiple | 191 | * match against vendor id as well. Wired Xbox 360 devices have protocol 1, |
190 | * interface protocols, we only need protocol 1. */ | 192 | * wireless controllers have protocol 129. */ |
191 | #define XPAD_XBOX360_VENDOR(vend) \ | 193 | #define XPAD_XBOX360_VENDOR_PROTOCOL(vend,pr) \ |
192 | .match_flags = USB_DEVICE_ID_MATCH_VENDOR | USB_DEVICE_ID_MATCH_INT_INFO, \ | 194 | .match_flags = USB_DEVICE_ID_MATCH_VENDOR | USB_DEVICE_ID_MATCH_INT_INFO, \ |
193 | .idVendor = (vend), \ | 195 | .idVendor = (vend), \ |
194 | .bInterfaceClass = USB_CLASS_VENDOR_SPEC, \ | 196 | .bInterfaceClass = USB_CLASS_VENDOR_SPEC, \ |
195 | .bInterfaceSubClass = 93, \ | 197 | .bInterfaceSubClass = 93, \ |
196 | .bInterfaceProtocol = 1 | 198 | .bInterfaceProtocol = (pr) |
199 | #define XPAD_XBOX360_VENDOR(vend) \ | ||
200 | { XPAD_XBOX360_VENDOR_PROTOCOL(vend,1) }, \ | ||
201 | { XPAD_XBOX360_VENDOR_PROTOCOL(vend,129) } | ||
197 | 202 | ||
198 | static struct usb_device_id xpad_table [] = { | 203 | static struct usb_device_id xpad_table [] = { |
199 | { USB_INTERFACE_INFO('X', 'B', 0) }, /* X-Box USB-IF not approved class */ | 204 | { USB_INTERFACE_INFO('X', 'B', 0) }, /* X-Box USB-IF not approved class */ |
200 | { XPAD_XBOX360_VENDOR(0x045e) }, /* Microsoft X-Box 360 controllers */ | 205 | XPAD_XBOX360_VENDOR(0x045e), /* Microsoft X-Box 360 controllers */ |
201 | { XPAD_XBOX360_VENDOR(0x046d) }, /* Logitech X-Box 360 style controllers */ | 206 | XPAD_XBOX360_VENDOR(0x046d), /* Logitech X-Box 360 style controllers */ |
202 | { XPAD_XBOX360_VENDOR(0x0738) }, /* Mad Catz X-Box 360 controllers */ | 207 | XPAD_XBOX360_VENDOR(0x0738), /* Mad Catz X-Box 360 controllers */ |
203 | { XPAD_XBOX360_VENDOR(0x0e6f) }, /* 0x0e6f X-Box 360 controllers */ | 208 | XPAD_XBOX360_VENDOR(0x0e6f), /* 0x0e6f X-Box 360 controllers */ |
204 | { XPAD_XBOX360_VENDOR(0x1430) }, /* RedOctane X-Box 360 controllers */ | 209 | XPAD_XBOX360_VENDOR(0x1430), /* RedOctane X-Box 360 controllers */ |
205 | { } | 210 | { } |
206 | }; | 211 | }; |
207 | 212 | ||
@@ -211,10 +216,15 @@ struct usb_xpad { | |||
211 | struct input_dev *dev; /* input device interface */ | 216 | struct input_dev *dev; /* input device interface */ |
212 | struct usb_device *udev; /* usb device */ | 217 | struct usb_device *udev; /* usb device */ |
213 | 218 | ||
219 | int pad_present; | ||
220 | |||
214 | struct urb *irq_in; /* urb for interrupt in report */ | 221 | struct urb *irq_in; /* urb for interrupt in report */ |
215 | unsigned char *idata; /* input data */ | 222 | unsigned char *idata; /* input data */ |
216 | dma_addr_t idata_dma; | 223 | dma_addr_t idata_dma; |
217 | 224 | ||
225 | struct urb *bulk_out; | ||
226 | unsigned char *bdata; | ||
227 | |||
218 | #if defined(CONFIG_JOYSTICK_XPAD_FF) || defined(CONFIG_JOYSTICK_XPAD_LEDS) | 228 | #if defined(CONFIG_JOYSTICK_XPAD_FF) || defined(CONFIG_JOYSTICK_XPAD_LEDS) |
219 | struct urb *irq_out; /* urb for interrupt out report */ | 229 | struct urb *irq_out; /* urb for interrupt out report */ |
220 | unsigned char *odata; /* output data */ | 230 | unsigned char *odata; /* output data */ |
@@ -359,6 +369,39 @@ static void xpad360_process_packet(struct usb_xpad *xpad, | |||
359 | input_sync(dev); | 369 | input_sync(dev); |
360 | } | 370 | } |
361 | 371 | ||
372 | /* | ||
373 | * xpad360w_process_packet | ||
374 | * | ||
375 | * Completes a request by converting the data into events for the | ||
376 | * input subsystem. It is version for xbox 360 wireless controller. | ||
377 | * | ||
378 | * Byte.Bit | ||
379 | * 00.1 - Status change: The controller or headset has connected/disconnected | ||
380 | * Bits 01.7 and 01.6 are valid | ||
381 | * 01.7 - Controller present | ||
382 | * 01.6 - Headset present | ||
383 | * 01.1 - Pad state (Bytes 4+) valid | ||
384 | * | ||
385 | */ | ||
386 | |||
387 | static void xpad360w_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char *data) | ||
388 | { | ||
389 | /* Presence change */ | ||
390 | if (data[0] & 0x08) { | ||
391 | if (data[1] & 0x80) { | ||
392 | xpad->pad_present = 1; | ||
393 | usb_submit_urb(xpad->bulk_out, GFP_ATOMIC); | ||
394 | } else | ||
395 | xpad->pad_present = 0; | ||
396 | } | ||
397 | |||
398 | /* Valid pad data */ | ||
399 | if (!(data[1] & 0x1)) | ||
400 | return; | ||
401 | |||
402 | xpad360_process_packet(xpad, cmd, &data[4]); | ||
403 | } | ||
404 | |||
362 | static void xpad_irq_in(struct urb *urb) | 405 | static void xpad_irq_in(struct urb *urb) |
363 | { | 406 | { |
364 | struct usb_xpad *xpad = urb->context; | 407 | struct usb_xpad *xpad = urb->context; |
@@ -381,10 +424,16 @@ static void xpad_irq_in(struct urb *urb) | |||
381 | goto exit; | 424 | goto exit; |
382 | } | 425 | } |
383 | 426 | ||
384 | if (xpad->xtype == XTYPE_XBOX360) | 427 | switch (xpad->xtype) { |
428 | case XTYPE_XBOX360: | ||
385 | xpad360_process_packet(xpad, 0, xpad->idata); | 429 | xpad360_process_packet(xpad, 0, xpad->idata); |
386 | else | 430 | break; |
431 | case XTYPE_XBOX360W: | ||
432 | xpad360w_process_packet(xpad, 0, xpad->idata); | ||
433 | break; | ||
434 | default: | ||
387 | xpad_process_packet(xpad, 0, xpad->idata); | 435 | xpad_process_packet(xpad, 0, xpad->idata); |
436 | } | ||
388 | 437 | ||
389 | exit: | 438 | exit: |
390 | retval = usb_submit_urb (urb, GFP_ATOMIC); | 439 | retval = usb_submit_urb (urb, GFP_ATOMIC); |
@@ -422,6 +471,23 @@ exit: | |||
422 | __FUNCTION__, retval); | 471 | __FUNCTION__, retval); |
423 | } | 472 | } |
424 | 473 | ||
474 | static void xpad_bulk_out(struct urb *urb) | ||
475 | { | ||
476 | switch (urb->status) { | ||
477 | case 0: | ||
478 | /* success */ | ||
479 | break; | ||
480 | case -ECONNRESET: | ||
481 | case -ENOENT: | ||
482 | case -ESHUTDOWN: | ||
483 | /* this urb is terminated, clean up */ | ||
484 | dbg("%s - urb shutting down with status: %d", __FUNCTION__, urb->status); | ||
485 | break; | ||
486 | default: | ||
487 | dbg("%s - nonzero urb status received: %d", __FUNCTION__, urb->status); | ||
488 | } | ||
489 | } | ||
490 | |||
425 | static int xpad_init_output(struct usb_interface *intf, struct usb_xpad *xpad) | 491 | static int xpad_init_output(struct usb_interface *intf, struct usb_xpad *xpad) |
426 | { | 492 | { |
427 | struct usb_endpoint_descriptor *ep_irq_out; | 493 | struct usb_endpoint_descriptor *ep_irq_out; |
@@ -600,6 +666,10 @@ static int xpad_open(struct input_dev *dev) | |||
600 | { | 666 | { |
601 | struct usb_xpad *xpad = input_get_drvdata(dev); | 667 | struct usb_xpad *xpad = input_get_drvdata(dev); |
602 | 668 | ||
669 | /* URB was submitted in probe */ | ||
670 | if(xpad->xtype == XTYPE_XBOX360W) | ||
671 | return 0; | ||
672 | |||
603 | xpad->irq_in->dev = xpad->udev; | 673 | xpad->irq_in->dev = xpad->udev; |
604 | if (usb_submit_urb(xpad->irq_in, GFP_KERNEL)) | 674 | if (usb_submit_urb(xpad->irq_in, GFP_KERNEL)) |
605 | return -EIO; | 675 | return -EIO; |
@@ -611,7 +681,8 @@ static void xpad_close(struct input_dev *dev) | |||
611 | { | 681 | { |
612 | struct usb_xpad *xpad = input_get_drvdata(dev); | 682 | struct usb_xpad *xpad = input_get_drvdata(dev); |
613 | 683 | ||
614 | usb_kill_urb(xpad->irq_in); | 684 | if(xpad->xtype != XTYPE_XBOX360W) |
685 | usb_kill_urb(xpad->irq_in); | ||
615 | xpad_stop_output(xpad); | 686 | xpad_stop_output(xpad); |
616 | } | 687 | } |
617 | 688 | ||
@@ -671,8 +742,15 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id | |||
671 | xpad->xtype = xpad_device[i].xtype; | 742 | xpad->xtype = xpad_device[i].xtype; |
672 | if (xpad->dpad_mapping == MAP_DPAD_UNKNOWN) | 743 | if (xpad->dpad_mapping == MAP_DPAD_UNKNOWN) |
673 | xpad->dpad_mapping = !dpad_to_buttons; | 744 | xpad->dpad_mapping = !dpad_to_buttons; |
674 | if (xpad->xtype == XTYPE_UNKNOWN) | 745 | if (xpad->xtype == XTYPE_UNKNOWN) { |
675 | xpad->xtype = (intf->cur_altsetting->desc.bInterfaceClass == USB_CLASS_VENDOR_SPEC); | 746 | if (intf->cur_altsetting->desc.bInterfaceClass == USB_CLASS_VENDOR_SPEC) { |
747 | if (intf->cur_altsetting->desc.bInterfaceProtocol == 129) | ||
748 | xpad->xtype = XTYPE_XBOX360W; | ||
749 | else | ||
750 | xpad->xtype = XTYPE_XBOX360; | ||
751 | } else | ||
752 | xpad->xtype = XTYPE_XBOX; | ||
753 | } | ||
676 | xpad->dev = input_dev; | 754 | xpad->dev = input_dev; |
677 | usb_make_path(udev, xpad->phys, sizeof(xpad->phys)); | 755 | usb_make_path(udev, xpad->phys, sizeof(xpad->phys)); |
678 | strlcat(xpad->phys, "/input0", sizeof(xpad->phys)); | 756 | 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 | |||
692 | /* set up buttons */ | 770 | /* set up buttons */ |
693 | for (i = 0; xpad_common_btn[i] >= 0; i++) | 771 | for (i = 0; xpad_common_btn[i] >= 0; i++) |
694 | set_bit(xpad_common_btn[i], input_dev->keybit); | 772 | set_bit(xpad_common_btn[i], input_dev->keybit); |
695 | if (xpad->xtype == XTYPE_XBOX360) | 773 | if ((xpad->xtype == XTYPE_XBOX360) || (xpad->xtype == XTYPE_XBOX360W)) |
696 | for (i = 0; xpad360_btn[i] >= 0; i++) | 774 | for (i = 0; xpad360_btn[i] >= 0; i++) |
697 | set_bit(xpad360_btn[i], input_dev->keybit); | 775 | set_bit(xpad360_btn[i], input_dev->keybit); |
698 | else | 776 | else |
@@ -734,8 +812,57 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id | |||
734 | goto fail4; | 812 | goto fail4; |
735 | 813 | ||
736 | usb_set_intfdata(intf, xpad); | 814 | usb_set_intfdata(intf, xpad); |
815 | |||
816 | /* | ||
817 | * Submit the int URB immediatly rather than waiting for open | ||
818 | * because we get status messages from the device whether | ||
819 | * or not any controllers are attached. In fact, it's | ||
820 | * exactly the message that a controller has arrived that | ||
821 | * we're waiting for. | ||
822 | */ | ||
823 | if (xpad->xtype == XTYPE_XBOX360W) { | ||
824 | xpad->irq_in->dev = xpad->udev; | ||
825 | error = usb_submit_urb(xpad->irq_in, GFP_KERNEL); | ||
826 | if (error) | ||
827 | goto fail4; | ||
828 | |||
829 | /* | ||
830 | * Setup the message to set the LEDs on the | ||
831 | * controller when it shows up | ||
832 | */ | ||
833 | xpad->bulk_out = usb_alloc_urb(0, GFP_KERNEL); | ||
834 | if(!xpad->bulk_out) | ||
835 | goto fail5; | ||
836 | |||
837 | xpad->bdata = kzalloc(XPAD_PKT_LEN, GFP_KERNEL); | ||
838 | if(!xpad->bdata) | ||
839 | goto fail6; | ||
840 | |||
841 | xpad->bdata[2] = 0x08; | ||
842 | switch (intf->cur_altsetting->desc.bInterfaceNumber) { | ||
843 | case 0: | ||
844 | xpad->bdata[3] = 0x42; | ||
845 | break; | ||
846 | case 2: | ||
847 | xpad->bdata[3] = 0x43; | ||
848 | break; | ||
849 | case 4: | ||
850 | xpad->bdata[3] = 0x44; | ||
851 | break; | ||
852 | case 6: | ||
853 | xpad->bdata[3] = 0x45; | ||
854 | } | ||
855 | |||
856 | ep_irq_in = &intf->cur_altsetting->endpoint[1].desc; | ||
857 | usb_fill_bulk_urb(xpad->bulk_out, udev, | ||
858 | usb_sndbulkpipe(udev, ep_irq_in->bEndpointAddress), | ||
859 | xpad->bdata, XPAD_PKT_LEN, xpad_bulk_out, xpad); | ||
860 | } | ||
861 | |||
737 | return 0; | 862 | return 0; |
738 | 863 | ||
864 | fail6: usb_free_urb(xpad->bulk_out); | ||
865 | fail5: usb_kill_urb(xpad->irq_in); | ||
739 | fail4: usb_free_urb(xpad->irq_in); | 866 | fail4: usb_free_urb(xpad->irq_in); |
740 | fail3: xpad_deinit_output(xpad); | 867 | fail3: xpad_deinit_output(xpad); |
741 | fail2: usb_buffer_free(udev, XPAD_PKT_LEN, xpad->idata, xpad->idata_dma); | 868 | 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) | |||
754 | xpad_led_disconnect(xpad); | 881 | xpad_led_disconnect(xpad); |
755 | input_unregister_device(xpad->dev); | 882 | input_unregister_device(xpad->dev); |
756 | xpad_deinit_output(xpad); | 883 | xpad_deinit_output(xpad); |
884 | if (xpad->xtype == XTYPE_XBOX360W) { | ||
885 | usb_kill_urb(xpad->bulk_out); | ||
886 | usb_free_urb(xpad->bulk_out); | ||
887 | usb_kill_urb(xpad->irq_in); | ||
888 | } | ||
757 | usb_free_urb(xpad->irq_in); | 889 | usb_free_urb(xpad->irq_in); |
758 | usb_buffer_free(xpad->udev, XPAD_PKT_LEN, | 890 | usb_buffer_free(xpad->udev, XPAD_PKT_LEN, |
759 | xpad->idata, xpad->idata_dma); | 891 | xpad->idata, xpad->idata_dma); |