// SPDX-License-Identifier: GPL-2.0-or-later /* * Xbox gamepad driver * * Copyright (c) 2002 Marko Friedemann <[email protected]> * 2004 Oliver Schwartz <[email protected]>, * Steven Toth <[email protected]>, * Franz Lehner <[email protected]>, * Ivan Hawkes <[email protected]> * 2005 Dominic Cerquetti <[email protected]> * 2006 Adam Buchbinder <[email protected]> * 2007 Jan Kratochvil <[email protected]> * 2010 Christoph Fritz <[email protected]> * * This driver is based on: * - information from http://euc.jp/periphs/xbox-controller.ja.html * - the iForce driver drivers/char/joystick/iforce.c * - the skeleton-driver drivers/usb/usb-skeleton.c * - Xbox 360 information http://www.free60.org/wiki/Gamepad * - Xbox One information https://github.com/quantus/xbox-one-controller-protocol * * Thanks to: * - ITO Takayuki for providing essential xpad information on his website * - Vojtech Pavlik - iforce driver / input subsystem * - Greg Kroah-Hartman - usb-skeleton driver * - Xbox Linux project - extra USB IDs * - Pekka Pöyry (quantus) - Xbox One controller reverse-engineering * * TODO: * - fine tune axes (especially trigger axes) * - fix "analog" buttons (reported as digital now) * - get rumble working * - need USB IDs for other dance pads * * History: * * 2002-06-27 - 0.0.1 : first version, just said "XBOX HID controller" * * 2002-07-02 - 0.0.2 : basic working version * - all axes and 9 of the 10 buttons work (german InterAct device) * - the black button does not work * * 2002-07-14 - 0.0.3 : rework by Vojtech Pavlik * - indentation fixes * - usb + input init sequence fixes * * 2002-07-16 - 0.0.4 : minor changes, merge with Vojtech's v0.0.3 * - verified the lack of HID and report descriptors * - verified that ALL buttons WORK * - fixed d-pad to axes mapping * * 2002-07-17 - 0.0.5 : simplified d-pad handling * * 2004-10-02 - 0.0.6 : DDR pad support * - borrowed from the Xbox Linux kernel * - USB id's for commonly used dance pads are present * - 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 <linux/bits.h> #include <linux/kernel.h> #include <linux/input.h> #include <linux/rcupdate.h> #include <linux/slab.h> #include <linux/stat.h> #include <linux/module.h> #include <linux/usb/input.h> #include <linux/usb/quirks.h> #define XPAD_PKT_LEN … /* * xbox d-pads should map to buttons, as is required for DDR pads * but we map them to axes when possible to simplify things */ #define MAP_DPAD_TO_BUTTONS … #define MAP_TRIGGERS_TO_BUTTONS … #define MAP_STICKS_TO_NULL … #define MAP_SELECT_BUTTON … #define MAP_PADDLES … #define MAP_PROFILE_BUTTON … #define DANCEPAD_MAP_CONFIG … #define XTYPE_XBOX … #define XTYPE_XBOX360 … #define XTYPE_XBOX360W … #define XTYPE_XBOXONE … #define XTYPE_UNKNOWN … /* Send power-off packet to xpad360w after holding the mode button for this many * seconds */ #define XPAD360W_POWEROFF_TIMEOUT … #define PKT_XB … #define PKT_XBE1 … #define PKT_XBE2_FW_OLD … #define PKT_XBE2_FW_5_EARLY … #define PKT_XBE2_FW_5_11 … static bool dpad_to_buttons; module_param(dpad_to_buttons, bool, S_IRUGO); MODULE_PARM_DESC(…) …; static bool triggers_to_buttons; module_param(triggers_to_buttons, bool, S_IRUGO); MODULE_PARM_DESC(…) …; static bool sticks_to_null; module_param(sticks_to_null, bool, S_IRUGO); MODULE_PARM_DESC(…) …; static bool auto_poweroff = …; module_param(auto_poweroff, bool, S_IWUSR | S_IRUGO); MODULE_PARM_DESC(…) …; static const struct xpad_device { … } xpad_device[] = …; /* buttons shared with xbox and xbox360 */ static const signed short xpad_common_btn[] = …; /* original xbox controllers only */ static const signed short xpad_btn[] = …; /* used when dpad is mapped to buttons */ static const signed short xpad_btn_pad[] = …; /* used when triggers are mapped to buttons */ static const signed short xpad_btn_triggers[] = …; static const signed short xpad360_btn[] = …; static const signed short xpad_abs[] = …; /* used when dpad is mapped to axes */ static const signed short xpad_abs_pad[] = …; /* used when triggers are mapped to axes */ static const signed short xpad_abs_triggers[] = …; /* used when the controller has extra paddle buttons */ static const signed short xpad_btn_paddles[] = …; /* * 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. */ #define XPAD_XBOX360_VENDOR_PROTOCOL(vend, pr) … #define XPAD_XBOX360_VENDOR(vend) … /* The Xbox One controller uses subclass 71 and protocol 208. */ #define XPAD_XBOXONE_VENDOR_PROTOCOL(vend, pr) … #define XPAD_XBOXONE_VENDOR(vend) … static const struct usb_device_id xpad_table[] = …; MODULE_DEVICE_TABLE(usb, xpad_table); struct xboxone_init_packet { … }; #define XBOXONE_INIT_PKT(_vid, _pid, _data) … /* * starting with xbox one, the game input protocol is used * magic numbers are taken from * - https://github.com/xpadneo/gip-dissector/blob/main/src/gip-dissector.lua * - https://github.com/medusalix/xone/blob/master/bus/protocol.c */ #define GIP_CMD_ACK … #define GIP_CMD_IDENTIFY … #define GIP_CMD_POWER … #define GIP_CMD_AUTHENTICATE … #define GIP_CMD_VIRTUAL_KEY … #define GIP_CMD_RUMBLE … #define GIP_CMD_LED … #define GIP_CMD_FIRMWARE … #define GIP_CMD_INPUT … #define GIP_SEQ0 … #define GIP_OPT_ACK … #define GIP_OPT_INTERNAL … /* * length of the command payload encoded with * https://en.wikipedia.org/wiki/LEB128 * which is a no-op for N < 128 */ #define GIP_PL_LEN(N) … /* * payload specific defines */ #define GIP_PWR_ON … #define GIP_LED_ON … #define GIP_MOTOR_R … #define GIP_MOTOR_L … #define GIP_MOTOR_RT … #define GIP_MOTOR_LT … #define GIP_MOTOR_ALL … #define GIP_WIRED_INTF_DATA … #define GIP_WIRED_INTF_AUDIO … /* * This packet is required for all Xbox One pads with 2015 * or later firmware installed (or present from the factory). */ static const u8 xboxone_power_on[] = …; /* * This packet is required for Xbox One S (0x045e:0x02ea) * and Xbox One Elite Series 2 (0x045e:0x0b00) pads to * initialize the controller that was previously used in * Bluetooth mode. */ static const u8 xboxone_s_init[] = …; /* * This packet is required to get additional input data * from Xbox One Elite Series 2 (0x045e:0x0b00) pads. * We mostly do this right now to get paddle data */ static const u8 extra_input_packet_init[] = …; /* * This packet is required for the Titanfall 2 Xbox One pads * (0x0e6f:0x0165) to finish initialization and for Hori pads * (0x0f0d:0x0067) to make the analog sticks work. */ static const u8 xboxone_hori_ack_id[] = …; /* * This packet is required for most (all?) of the PDP pads to start * sending input reports. These pads include: (0x0e6f:0x02ab), * (0x0e6f:0x02a4), (0x0e6f:0x02a6). */ static const u8 xboxone_pdp_led_on[] = …; /* * This packet is required for most (all?) of the PDP pads to start * sending input reports. These pads include: (0x0e6f:0x02ab), * (0x0e6f:0x02a4), (0x0e6f:0x02a6). */ static const u8 xboxone_pdp_auth[] = …; /* * A specific rumble packet is required for some PowerA pads to start * sending input reports. One of those pads is (0x24c6:0x543a). */ static const u8 xboxone_rumblebegin_init[] = …; /* * A rumble packet with zero FF intensity will immediately * terminate the rumbling required to init PowerA pads. * This should happen fast enough that the motors don't * spin up to enough speed to actually vibrate the gamepad. */ static const u8 xboxone_rumbleend_init[] = …; /* * This specifies the selection of init packets that a gamepad * will be sent on init *and* the order in which they will be * sent. The correct sequence number will be added when the * packet is going to be sent. */ static const struct xboxone_init_packet xboxone_init_packets[] = …; struct xpad_output_packet { … }; #define XPAD_OUT_CMD_IDX … #define XPAD_OUT_FF_IDX … #define XPAD_OUT_LED_IDX … #define XPAD_NUM_OUT_PACKETS … struct usb_xpad { … }; static int xpad_init_input(struct usb_xpad *xpad); static void xpad_deinit_input(struct usb_xpad *xpad); static void xpadone_ack_mode_report(struct usb_xpad *xpad, u8 seq_num); static void xpad360w_poweroff_controller(struct usb_xpad *xpad); /* * xpad_process_packet * * Completes a request by converting the data into events for the * input subsystem. * * The used report descriptor was taken from ITO Takayuki's website: * http://euc.jp/periphs/xbox-controller.ja.html */ static void xpad_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char *data) { … } /* * xpad360_process_packet * * Completes a request by converting the data into events for the * input subsystem. It is version for xbox 360 controller * * The used report descriptor was taken from: * http://www.free60.org/wiki/Gamepad */ static void xpad360_process_packet(struct usb_xpad *xpad, struct input_dev *dev, u16 cmd, unsigned char *data) { … } static void xpad_presence_work(struct work_struct *work) { … } /* * 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) { … } /* * 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) { … } static void xpad_irq_in(struct urb *urb) { … } /* Callers must hold xpad->odata_lock spinlock */ static bool xpad_prepare_next_init_packet(struct usb_xpad *xpad) { … } /* Callers must hold xpad->odata_lock spinlock */ static bool xpad_prepare_next_out_packet(struct usb_xpad *xpad) { … } /* Callers must hold xpad->odata_lock spinlock */ static int xpad_try_sending_next_out_packet(struct usb_xpad *xpad) { … } 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) { … } static void xpad_stop_output(struct usb_xpad *xpad) { … } static void xpad_deinit_output(struct usb_xpad *xpad) { … } static int xpad_inquiry_pad_presence(struct usb_xpad *xpad) { … } static int xpad_start_xbox_one(struct usb_xpad *xpad) { … } static void xpadone_ack_mode_report(struct usb_xpad *xpad, u8 seq_num) { … } #ifdef CONFIG_JOYSTICK_XPAD_FF static int xpad_play_effect(struct input_dev *dev, void *data, struct ff_effect *effect) { … } static int xpad_init_ff(struct usb_xpad *xpad) { … } #else static int xpad_init_ff(struct usb_xpad *xpad) { return 0; } #endif #if defined(CONFIG_JOYSTICK_XPAD_LEDS) #include <linux/leds.h> #include <linux/idr.h> static DEFINE_IDA(xpad_pad_seq); struct xpad_led { … }; /* * set the LEDs on Xbox 360 / Wireless Controllers * @param command * 0: off * 1: all blink, then previous setting * 2: 1/top-left blink, then on * 3: 2/top-right blink, then on * 4: 3/bottom-left blink, then on * 5: 4/bottom-right blink, then on * 6: 1/top-left on * 7: 2/top-right on * 8: 3/bottom-left on * 9: 4/bottom-right on * 10: rotate * 11: blink, based on previous setting * 12: slow blink, based on previous setting * 13: rotate with two lights * 14: persistent slow all blink * 15: blink once, then previous setting */ static void xpad_send_led_command(struct usb_xpad *xpad, int command) { … } /* * Light up the segment corresponding to the pad number on * Xbox 360 Controllers. */ static void xpad_identify_controller(struct usb_xpad *xpad) { … } static void xpad_led_set(struct led_classdev *led_cdev, enum led_brightness value) { … } static int xpad_led_probe(struct usb_xpad *xpad) { … } static void xpad_led_disconnect(struct usb_xpad *xpad) { … } #else static int xpad_led_probe(struct usb_xpad *xpad) { return 0; } static void xpad_led_disconnect(struct usb_xpad *xpad) { } #endif static int xpad_start_input(struct usb_xpad *xpad) { … } static void xpad_stop_input(struct usb_xpad *xpad) { … } static void xpad360w_poweroff_controller(struct usb_xpad *xpad) { … } static int xpad360w_start_input(struct usb_xpad *xpad) { … } static void xpad360w_stop_input(struct usb_xpad *xpad) { … } static int xpad_open(struct input_dev *dev) { … } static void xpad_close(struct input_dev *dev) { … } static void xpad_set_up_abs(struct input_dev *input_dev, signed short abs) { … } static void xpad_deinit_input(struct usb_xpad *xpad) { … } static int xpad_init_input(struct usb_xpad *xpad) { … } static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id) { … } static void xpad_disconnect(struct usb_interface *intf) { … } static int xpad_suspend(struct usb_interface *intf, pm_message_t message) { … } static int xpad_resume(struct usb_interface *intf) { … } static struct usb_driver xpad_driver = …; module_usb_driver(…) …; MODULE_AUTHOR(…) …; MODULE_DESCRIPTION(…) …; MODULE_LICENSE(…) …;