diff mbox series

[v3,3/4] HID: gamecube-adapter: add auto calibration

Message ID 20201014013023.23078-4-fx.carton91@gmail.com
State New
Headers show
Series HID: gamecube-adapter | expand

Commit Message

François-Xavier Carton Oct. 14, 2020, 1:30 a.m. UTC
The axes do not cover the full 0-255 range, with different limit values
for each axis. The minimal and maximal values are recorded for each axis
and the values are remapped from that range to 0-255.

Signed-off-by: François-Xavier Carton <fx.carton91@gmail.com>
---
 drivers/hid/hid-gamecube-adapter.c | 24 ++++++++++++++++++------
 1 file changed, 18 insertions(+), 6 deletions(-)
diff mbox series

Patch

diff --git a/drivers/hid/hid-gamecube-adapter.c b/drivers/hid/hid-gamecube-adapter.c
index d0bf09ba2762..53d372a24277 100644
--- a/drivers/hid/hid-gamecube-adapter.c
+++ b/drivers/hid/hid-gamecube-adapter.c
@@ -56,6 +56,8 @@  struct gamecube_ctrl {
 	struct input_dev __rcu *input;
 	struct gamecube_adpt *adpt;
 	enum gamecube_ctrl_flags flags;
+	u8 axis_min[6];
+	u8 axis_max[6];
 	u8 rumble;
 	struct work_struct work_connect;
 	spinlock_t flags_lock;
@@ -264,6 +266,7 @@  static void gamecube_ctrl_handle_report(struct gamecube_ctrl *ctrl, u8 *data)
 	u16 btns = data[1] << 8 | data[2];
 	u8 old_flags, new_flags = data[0];
 	unsigned long irq_flags;
+	unsigned int i;
 
 	spin_lock_irqsave(&ctrl->flags_lock, irq_flags);
 	old_flags = ctrl->flags;
@@ -271,6 +274,11 @@  static void gamecube_ctrl_handle_report(struct gamecube_ctrl *ctrl, u8 *data)
 	spin_unlock_irqrestore(&ctrl->flags_lock, irq_flags);
 
 	if ((new_flags & GC_TYPES) != (old_flags & GC_TYPES)) {
+		// Reset min/max values. The default values were obtained empirically
+		for (i = 0; i < 6; i++) {
+			ctrl->axis_min[i] = 45; // max across all axes of min values
+			ctrl->axis_max[i] = 215; // min across all axes of max values
+		}
 		schedule_work(&ctrl->work_connect);
 		return;
 	}
@@ -294,12 +302,16 @@  static void gamecube_ctrl_handle_report(struct gamecube_ctrl *ctrl, u8 *data)
 	input_report_key(dev, BTN_DPAD_RIGHT, btns & GC_BTN_DPAD_RIGHT);
 	input_report_key(dev, BTN_DPAD_DOWN, btns & GC_BTN_DPAD_DOWN);
 	input_report_key(dev, BTN_DPAD_UP, btns & GC_BTN_DPAD_UP);
-	input_report_abs(dev, ABS_X, data[3]);
-	input_report_abs(dev, ABS_Y, 255 - data[4]);
-	input_report_abs(dev, ABS_RX, data[5]);
-	input_report_abs(dev, ABS_RY, 255 - data[6]);
-	input_report_abs(dev, ABS_Z, data[7]);
-	input_report_abs(dev, ABS_RZ, data[8]);
+	for (i = 0; i < 6; i++) {
+		u8 a, b, v = data[3 + i];
+
+		a = ctrl->axis_min[i] = min(ctrl->axis_min[i], v);
+		b = ctrl->axis_max[i] = max(ctrl->axis_max[i], v);
+		v = 255U * (v - a) / (b - a);
+		if (gamecube_axes[i] == ABS_Y || gamecube_axes[i] == ABS_RY)
+			v = 255U - v;
+		input_report_abs(dev, gamecube_axes[i], v);
+	}
 	input_sync(dev);
 
 unlock: