[PATCH] Input: xpad - enable & autodetect Flydigi extra buttons

matoro posted 1 patch 1 month ago
drivers/input/joystick/xpad.c | 53 ++++++++++++++++++++++++++++++++++-
1 file changed, 52 insertions(+), 1 deletion(-)
[PATCH] Input: xpad - enable & autodetect Flydigi extra buttons
Posted by matoro 1 month ago
This adds a framework for supporting additional features on devices
piggybacking an existing USB vendor/product ID but distinguishing
themselves via the idProduct field.  This is necessary because the
Flydigi Vader Pro series controllers reuse the same vendor/product ID as
orginal Microsoft Xbox 360 controllers.

The MAP_FLYDIGI_BUTTONS is a new mapping for the C, Z, and Circle face
buttons on Flydigi 360-compatible controllers.  It has been tested on
the Vader 3 Pro and Vader 4 Pro.

These controllers additionally have 4 back paddles, same as the Xbox
Elite controller, so it is included in the extra feature list.

Thanks-to: Matthew Carter <m@ahungry.com>
See: https://github.com/paroj/xpad/pull/268
Signed-off-by: Matoro Mahri <matoro_mailinglist_kernel@matoro.tk>
---
  drivers/input/joystick/xpad.c | 53 ++++++++++++++++++++++++++++++++++-
  1 file changed, 52 insertions(+), 1 deletion(-)

diff --git a/drivers/input/joystick/xpad.c b/drivers/input/joystick/xpad.c
index 2b8370ecf42a..5088a97de73e 100644
--- a/drivers/input/joystick/xpad.c
+++ b/drivers/input/joystick/xpad.c
@@ -83,6 +83,7 @@
  #define MAP_SELECT_BUTTON		(1 << 3)
  #define MAP_PADDLES			(1 << 4)
  #define MAP_PROFILE_BUTTON		(1 << 5)
+#define MAP_FLYDIGI_BUTTONS		(1 << 6)

  #define DANCEPAD_MAP_CONFIG	(MAP_DPAD_TO_BUTTONS |			\
  				MAP_TRIGGERS_TO_BUTTONS | MAP_STICKS_TO_NULL)
@@ -387,6 +388,19 @@ static const struct xpad_device {
  	{ 0x0000, 0x0000, "Generic X-Box pad", 0, XTYPE_UNKNOWN }
  };

+// A "flavor" is an aftermarket variant of an existing model supporting
+// additional features.
+static const struct xpad_flavor {
+	u16 idVendor;
+	u16 idProduct;
+	char *product;
+	u8 mapping;
+} xpad_flavor[] = {
+	{ 0x045e, 0x028e, "Flydigi VADER3", MAP_PADDLES | MAP_FLYDIGI_BUTTONS },
+	{ 0x045e, 0x028e, "Flydigi VADER4", MAP_PADDLES | MAP_FLYDIGI_BUTTONS },
+	{ 0x0000, 0x0000, NULL, 0 }
+};
+
  /* buttons shared with xbox and xbox360 */
  static const signed short xpad_common_btn[] = {
  	BTN_A, BTN_B, BTN_X, BTN_Y,			/* "analog" buttons */
@@ -444,6 +458,13 @@ static const signed short xpad_btn_paddles[] = {
  	-1						/* terminating entry */
  };

+/* used for extra buttons in addition to paddles on Flydigi Vader Pro 
series*/
+static const signed short xpad_btn_extra[] = {
+	BTN_TRIGGER_HAPPY9, BTN_TRIGGER_HAPPY10, /* C, Z face buttons */
+	BTN_TRIGGER_HAPPY11,			 /* circle */
+	-1						/* terminating entry */
+};
+
  /*
   * 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
@@ -898,6 +919,17 @@ static void xpad360_process_packet(struct usb_xpad 
*xpad, struct input_dev *dev,
  		input_report_abs(dev, ABS_RZ, data[5]);
  	}

+	/* Additional buttons for Flydigi Vader Pro series presenting as 360 pad. 
*/
+	if (xpad->mapping & MAP_FLYDIGI_BUTTONS) {
+		input_report_key(dev, BTN_TRIGGER_HAPPY9, data[19] & BIT(0));   // C
+		input_report_key(dev, BTN_TRIGGER_HAPPY10, data[19] & BIT(1));  // Z
+		input_report_key(dev, BTN_TRIGGER_HAPPY5, data[19] & BIT(3));   // 
Leftmost paddle (M2)
+		input_report_key(dev, BTN_TRIGGER_HAPPY6, data[19] & BIT(5));   // Second 
to leftmost (M4)
+		input_report_key(dev, BTN_TRIGGER_HAPPY7, data[19] & BIT(4));   // Second 
to rightmost (M3)
+		input_report_key(dev, BTN_TRIGGER_HAPPY8, data[19] & BIT(2));   // 
Rightmost paddle (M1)
+		input_report_key(dev, BTN_TRIGGER_HAPPY11, data[20] & BIT(0));  // Circle
+	}
+
  	input_sync(dev);

  	/* XBOX360W controllers can't be turned off without driver assistance */
@@ -1958,6 +1990,13 @@ static int xpad_init_input(struct usb_xpad *xpad)
  			input_set_capability(input_dev, EV_KEY, xpad_btn_paddles[i]);
  	}

+	/* set up extra face buttons if the controller has them */
+	if (xpad->mapping & MAP_FLYDIGI_BUTTONS) {
+		for (i = 0; xpad_btn_extra[i] >= 0; i++) {
+			input_set_capability(input_dev, EV_KEY, xpad_btn_extra[i]);
+		}
+	}
+
  	/*
  	 * This should be a simple else block. However historically
  	 * xbox360w has mapped DPAD to buttons while xbox360 did not. This
@@ -2012,7 +2051,7 @@ static int xpad_probe(struct usb_interface *intf, const 
struct usb_device_id *id
  	struct usb_device *udev = interface_to_usbdev(intf);
  	struct usb_xpad *xpad;
  	struct usb_endpoint_descriptor *ep_irq_in, *ep_irq_out;
-	int i, error;
+	int i, j, error;

  	if (intf->cur_altsetting->desc.bNumEndpoints != 2)
  		return -ENODEV;
@@ -2046,6 +2085,18 @@ static int xpad_probe(struct usb_interface *intf, 
const struct usb_device_id *id
  	xpad->udev = udev;
  	xpad->intf = intf;
  	xpad->mapping = xpad_device[i].mapping;
+
+	if (udev->product) {	// Only worry about extra flavors if a product string 
is present
+		for(j = 0; xpad_flavor[j].idVendor; j++) {
+			if (le16_to_cpu(udev->descriptor.idVendor) == xpad_flavor[j].idVendor &&
+			    le16_to_cpu(udev->descriptor.idProduct) == xpad_flavor[j].idProduct 
&&
+			    !strcmp(udev->product, xpad_flavor[j].product)) {
+				xpad->mapping |= xpad_flavor[j].mapping;
+				break;
+			}
+		}
+	}
+
  	xpad->xtype = xpad_device[i].xtype;
  	xpad->name = xpad_device[i].name;
  	xpad->packet_type = PKT_XB;
-- 
2.47.0