All of lore.kernel.org
 help / color / mirror / Atom feed
From: Vicki Pfau <vi@endrift.com>
To: Dmitry Torokhov <dmitry.torokhov@gmail.com>, linux-input@vger.kernel.org
Cc: Vicki Pfau <vi@endrift.com>
Subject: [PATCH v3 10/10] Input: xbox_gip - Add flight stick support
Date: Mon,  9 Mar 2026 22:20:04 -0700	[thread overview]
Message-ID: <20260310052017.1289494-11-vi@endrift.com> (raw)
In-Reply-To: <20260310052017.1289494-1-vi@endrift.com>

This adds preliminary flight stick support, with a few caveats:

- Flight sticks support up to 64 extra buttons. This only exposes the first
  50, as there isn't any good place to map the remainder.
- Flight sticks support up to 12 extra axes. This picks a fairly abritrary
  mapping for them, as there's again no good place to map them.

Flight sticks also have addressible LEDs, but I don't have a device that
supports them so I can't test them yet.

Signed-off-by: Vicki Pfau <vi@endrift.com>
---
 drivers/input/joystick/gip/Makefile           |   2 +-
 drivers/input/joystick/gip/gip-core.c         |   4 +-
 drivers/input/joystick/gip/gip-flight-stick.c | 179 ++++++++++++++++++
 drivers/input/joystick/gip/gip.h              |   1 +
 4 files changed, 184 insertions(+), 2 deletions(-)
 create mode 100644 drivers/input/joystick/gip/gip-flight-stick.c

diff --git a/drivers/input/joystick/gip/Makefile b/drivers/input/joystick/gip/Makefile
index db6c9079c7e18..4de873f77a020 100644
--- a/drivers/input/joystick/gip/Makefile
+++ b/drivers/input/joystick/gip/Makefile
@@ -1,3 +1,3 @@
 # SPDX-License-Identifier: GPL-2.0-or-later
 obj-$(CONFIG_JOYSTICK_XBOX_GIP)	+= xbox-gip.o
-xbox-gip-y := gip-arcade-stick.o gip-core.o gip-drivers.o gip-wheel.o
+xbox-gip-y := gip-arcade-stick.o gip-core.o gip-drivers.o gip-flight-stick.o gip-wheel.o
diff --git a/drivers/input/joystick/gip/gip-core.c b/drivers/input/joystick/gip/gip-core.c
index 773d7705b7be8..17e2be5cd2444 100644
--- a/drivers/input/joystick/gip/gip-core.c
+++ b/drivers/input/joystick/gip/gip-core.c
@@ -11,9 +11,10 @@
  * - Sending fragmented messages
  * - Raw character device
  * - Wheel force feedback
- * - Flight stick support
  * - More arcade stick testing
  * - Arcade stick extra buttons
+ * - More flight stick testing
+ * - Flight stick LEDs
  * - Split into driver-per-attachment GIP-as-a-bus approach drivers
  *
  * This driver is based on the Microsoft GIP spec at:
@@ -319,6 +320,7 @@ static const struct gip_driver* base_drivers[] = {
 	&gip_driver_arcade_stick,
 	&gip_driver_trueforce_wheel,
 	&gip_driver_wheel,
+	&gip_driver_flight_stick,
 	NULL /* Sentinel */
 };
 
diff --git a/drivers/input/joystick/gip/gip-flight-stick.c b/drivers/input/joystick/gip/gip-flight-stick.c
new file mode 100644
index 0000000000000..c2b913a012d0e
--- /dev/null
+++ b/drivers/input/joystick/gip/gip-flight-stick.c
@@ -0,0 +1,179 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Drivers for GIP flight stick devices
+ *
+ * Copyright (c) 2025 Valve Software
+ *
+ * This driver is based on the Microsoft GIP spec at:
+ * https://aka.ms/gipdocs
+ * https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-gipusb/e7c90904-5e21-426e-b9ad-d82adeee0dbc
+ */
+#include "gip.h"
+
+/* FlightStick vendor messages */
+#define GIP_CMD_DEVICE_CAPABILITIES	0x00
+#define GIP_CMD_LED_CAPABILITIES	0x01
+#define GIP_CMD_SET_LED_STATE		0x02
+
+/*
+ * The spec defines up to 64 extra buttons and 12 extra axes, but there's
+ * currently no good way to map all of them. For now, let's leave it as a much
+ * smaller number.and add more when we get a better way.
+ */
+#define MAX_GIP_FLIGHT_STICK_BUTTONS 10
+#define MAX_GIP_FLIGHT_STICK_AXES 1
+
+struct gip_flight_stick_capabilities_response {
+	uint8_t extra_button_count;
+	uint8_t extra_axis_count;
+	uint8_t led_count;
+	uint8_t max_global_led_gain;
+};
+
+static const unsigned int gip_flight_stick_extra_buttons[] = {
+	BTN_0,
+	BTN_1,
+	BTN_2,
+	BTN_3,
+	BTN_4,
+	BTN_5,
+	BTN_6,
+	BTN_7,
+	BTN_8,
+	BTN_9,
+};
+
+static const unsigned int gip_flight_stick_extra_axes[] = {
+	ABS_RUDDER,
+};
+
+static int gip_flight_stick_init(struct gip_attachment *attachment)
+{
+	int rc = gip_send_vendor_message(attachment, GIP_CMD_DEVICE_CAPABILITIES, 0, NULL, 0);
+
+	if (rc < 0)
+		return rc;
+
+	return GIP_INIT_NO_INPUT;
+}
+
+static int gip_setup_flight_stick_input(struct gip_attachment *attachment, struct input_dev* input)
+{
+	int i;
+	int rc = gip_driver_navigation.setup_input(attachment, input);
+
+	if (rc)
+		return rc;
+
+	input_set_capability(input, EV_KEY, BTN_TOP);
+	input_set_capability(input, EV_KEY, BTN_TOP2);
+	for (i = 0; i < attachment->extra_buttons && i < MAX_GIP_FLIGHT_STICK_BUTTONS; i++)
+		input_set_capability(input, EV_KEY, BTN_0 + i);
+	if (attachment->extra_buttons > MAX_GIP_FLIGHT_STICK_BUTTONS)
+		dev_info(GIP_DEV(attachment),
+			"Device has too many extra buttons, %i through %i ignored\n",
+			MAX_GIP_FLIGHT_STICK_BUTTONS,
+			attachment->extra_buttons + 1);
+	input_set_abs_params(input, ABS_X, -32768, 32767, 0, 0);
+	input_set_abs_params(input, ABS_Y, -32768, 32767, 0, 0);
+	input_set_abs_params(input, ABS_Z, -32768, 32767, 0, 0);
+	input_set_abs_params(input, ABS_THROTTLE, 0, 65535, 0, 0);
+	for (i = 0; i < attachment->extra_axes && i < MAX_GIP_FLIGHT_STICK_AXES; i++)
+		input_set_abs_params(input, gip_flight_stick_extra_axes[i], 0, 65535, 0, 0);
+
+	return 0;
+}
+
+static int gip_handle_flight_stick_report(struct gip_attachment *attachment,
+	struct input_dev *input, const uint8_t *bytes, int num_bytes)
+{
+	int32_t axis;
+	int rc = gip_driver_navigation.handle_input_report(attachment, input, bytes, num_bytes);
+	int i;
+
+	if (rc)
+		return rc;
+
+	if (num_bytes < 19)
+		return -EINVAL;
+
+	/* Fire 1 and 2 */
+	input_report_key(input, BTN_TOP, bytes[2] & BIT(0));
+	input_report_key(input, BTN_TOP2, bytes[2] & BIT(1));
+
+	for (i = 0; i < attachment->extra_buttons && i < MAX_GIP_FLIGHT_STICK_BUTTONS; i++) {
+		input_report_key(input, gip_flight_stick_extra_buttons[i],
+			bytes[i / 8 + 3] & BIT(i));
+	}
+
+	/*
+	 * Roll, pitch and yaw are signed. Throttle and any
+	 * extra axes are unsigned. All values are full-range.
+	 */
+	axis = bytes[11];
+	axis |= bytes[12] << 8;
+	input_report_abs(input, ABS_X, (int16_t) axis);
+
+	axis = bytes[13];
+	axis |= bytes[14] << 8;
+	input_report_abs(input, ABS_Y, (int16_t) axis);
+
+	axis = bytes[15];
+	axis |= bytes[16] << 8;
+	input_report_abs(input, ABS_Z, (int16_t) axis);
+
+	axis = bytes[17];
+	axis |= bytes[18] << 8;
+	input_report_abs(input, ABS_THROTTLE, axis);
+
+	for (i = 0; i < attachment->extra_axes && i < MAX_GIP_FLIGHT_STICK_AXES; i++) {
+		if (20 + i * 2 >= num_bytes)
+			break;
+
+		axis = bytes[19 + i * 2];
+		axis |= bytes[20 + i * 2] << 8;
+		input_report_abs(input, gip_flight_stick_extra_axes[i], axis);
+	}
+
+	return 0;
+}
+
+static int gip_handle_flight_stick_cmd_device_capabilities(struct gip_attachment *attachment,
+	const struct gip_header *header, const uint8_t *bytes, int num_bytes)
+{
+	const struct gip_flight_stick_capabilities_response *response =
+		(const struct gip_flight_stick_capabilities_response*)bytes;
+	struct input_dev *input;
+
+	rcu_read_lock();
+	input = rcu_dereference(attachment->input);
+	rcu_read_unlock();
+	if (input)
+		return 0;
+
+	if (num_bytes < 4)
+		return -EINVAL;
+
+	attachment->extra_axes = min(response->extra_axis_count, MAX_GIP_FLIGHT_STICK_AXES);
+	attachment->extra_buttons = min(response->extra_button_count, MAX_GIP_FLIGHT_STICK_BUTTONS);
+	return gip_setup_input_device(attachment);
+}
+
+const struct gip_driver gip_driver_flight_stick = {
+	.types = (const char* const[]) {
+		"Windows.Xbox.Input.FlightStick",
+		"Microsoft.Xbox.Input.FlightStick",
+		NULL
+	},
+	.guid = GUID_INIT(0x03f1a011, 0xefe9, 0x4cc1, 0x96, 0x9c,
+		0x38, 0xdc, 0x55, 0xf4, 0x04, 0xd0),
+
+	.probe = NULL,
+	.remove = NULL,
+	.init = gip_flight_stick_init,
+	.setup_input = gip_setup_flight_stick_input,
+	.handle_input_report = gip_handle_flight_stick_report,
+	.vendor_handlers = {
+		[GIP_CMD_DEVICE_CAPABILITIES] = gip_handle_flight_stick_cmd_device_capabilities,
+	},
+};
diff --git a/drivers/input/joystick/gip/gip.h b/drivers/input/joystick/gip/gip.h
index 3b5cab96dc0b7..6d70a69d99a39 100644
--- a/drivers/input/joystick/gip/gip.h
+++ b/drivers/input/joystick/gip/gip.h
@@ -323,4 +323,5 @@ extern const struct gip_driver gip_driver_gamepad;
 extern const struct gip_driver gip_driver_arcade_stick;
 extern const struct gip_driver gip_driver_wheel;
 extern const struct gip_driver gip_driver_trueforce_wheel;
+extern const struct gip_driver gip_driver_flight_stick;
 #endif
-- 
2.53.0


  parent reply	other threads:[~2026-03-10  5:20 UTC|newest]

Thread overview: 13+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-03-10  5:19 [PATCH v3 00/10] Input: xbox_gip - Add new driver for Xbox GIP Vicki Pfau
2026-03-10  5:19 ` [PATCH v3 01/10] " Vicki Pfau
2026-03-11  0:41   ` Vicki Pfau
2026-03-10  5:19 ` [PATCH v3 02/10] Input: xpad - Remove Xbox One support Vicki Pfau
2026-03-10  5:19 ` [PATCH v3 03/10] Input: xbox_gip - Add controllable LED support Vicki Pfau
2026-03-10  5:19 ` [PATCH v3 04/10] Input: xbox_gip - Add HID relaying Vicki Pfau
2026-03-10  5:19 ` [PATCH v3 05/10] Input: xbox_gip - Add battery support Vicki Pfau
2026-03-10  5:20 ` [PATCH v3 06/10] Input: xbox_gip - Add arcade stick support Vicki Pfau
2026-03-10  5:20 ` [PATCH v3 07/10] Input: Add ABS_CLUTCH, HANDBRAKE, and SHIFTER Vicki Pfau
2026-03-10  5:20 ` [PATCH v3 08/10] HID: Map more automobile simulation inputs Vicki Pfau
2026-03-10  5:20 ` [PATCH v3 09/10] Input: xbox_gip - Add wheel support Vicki Pfau
2026-03-10  5:20 ` Vicki Pfau [this message]
2026-03-10  5:23   ` [PATCH v3 10/10] Input: xbox_gip - Add flight stick support Vicki Pfau

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260310052017.1289494-11-vi@endrift.com \
    --to=vi@endrift.com \
    --cc=dmitry.torokhov@gmail.com \
    --cc=linux-input@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.