linux/drivers/input/joystick/xpad.c

// 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();