From b96150b51068b47ac7dc94b708d725a86a4d3305 Mon Sep 17 00:00:00 2001 From: AndyFilter Date: Fri, 1 May 2026 11:51:51 +0200 Subject: [PATCH 01/11] Driver: very early prototype of per-device configuration support --- driver/accel.h | 25 +++++++ driver/driver.c | 184 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 209 insertions(+) diff --git a/driver/accel.h b/driver/accel.h index 3166115..413f1cc 100644 --- a/driver/accel.h +++ b/driver/accel.h @@ -1,6 +1,31 @@ #ifndef _ACCEL_H #define _ACCEL_H +#include + +#include "accel_modes.h" +#include "FixedMath/Fixed64.h" int accelerate(int *x, int *y); +struct accel_params { + char acceleration_mode; + FP_LONG input_cap; + FP_LONG sensitivity; + FP_LONG ratio_yx; + FP_LONG output_cap; + FP_LONG offset; + FP_LONG prescale; + FP_LONG acceleration; + FP_LONG exponent; + FP_LONG midpoint; + FP_LONG motivity; + bool use_smoothing; + unsigned long lut_size; + char lut_data[MAX_LUT_BUF_LEN]; + char cc_data_aggregate[MAX_LUT_BUF_LEN]; + FP_LONG rotation_angle; + FP_LONG angle_snap_threshold; + FP_LONG angle_snap_angle; +}; + #endif /* _ACCEL_H */ diff --git a/driver/driver.c b/driver/driver.c index 042b449..fe90b64 100644 --- a/driver/driver.c +++ b/driver/driver.c @@ -18,9 +18,72 @@ #define __cleanup_events 1 #endif +static ssize_t mouse_param_show(struct device *dev, struct device_attribute *attr, char *buf); +static ssize_t mouse_param_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count); + +#define FILE_PERMISSIONS (0660) + +// Manual definition since we aren't using the default _show naming convention +static struct device_attribute dev_attr_acceleration_mode = __ATTR(acceleration_mode, FILE_PERMISSIONS, mouse_param_show, mouse_param_store); + +static struct device_attribute dev_attr_input_cap = __ATTR(input_cap, FILE_PERMISSIONS, mouse_param_show, mouse_param_store); +static struct device_attribute dev_attr_sensitivity = __ATTR(sensitivity, FILE_PERMISSIONS, mouse_param_show, mouse_param_store); +static struct device_attribute dev_attr_ratio_yx = __ATTR(ratio_yx, FILE_PERMISSIONS, mouse_param_show, mouse_param_store); +static struct device_attribute dev_attr_output_cap = __ATTR(output_cap, FILE_PERMISSIONS, mouse_param_show, mouse_param_store); +static struct device_attribute dev_attr_offset = __ATTR(offset, FILE_PERMISSIONS, mouse_param_show, mouse_param_store); +static struct device_attribute dev_attr_prescale = __ATTR(prescale, FILE_PERMISSIONS, mouse_param_show, mouse_param_store); +static struct device_attribute dev_attr_acceleration = __ATTR(acceleration, FILE_PERMISSIONS, mouse_param_show, mouse_param_store); +static struct device_attribute dev_attr_exponent = __ATTR(exponent, FILE_PERMISSIONS, mouse_param_show, mouse_param_store); +static struct device_attribute dev_attr_midpoint = __ATTR(midpoint, FILE_PERMISSIONS, mouse_param_show, mouse_param_store); +static struct device_attribute dev_attr_motivity = __ATTR(motivity, FILE_PERMISSIONS, mouse_param_show, mouse_param_store); +static struct device_attribute dev_attr_use_smoothing = __ATTR(use_smoothing, FILE_PERMISSIONS, mouse_param_show, mouse_param_store); + +static struct device_attribute dev_attr_lut_size = __ATTR(lut_size, FILE_PERMISSIONS, mouse_param_show, mouse_param_store); +static struct device_attribute dev_attr_lut_data = __ATTR(lut_data, FILE_PERMISSIONS, mouse_param_show, mouse_param_store); + +static struct device_attribute dev_attr_cc_data_aggregate = __ATTR(cc_data_aggregate, FILE_PERMISSIONS, mouse_param_show, mouse_param_store); + +static struct device_attribute dev_attr_rotation_angle = __ATTR(rotation_angle, FILE_PERMISSIONS, mouse_param_show, mouse_param_store); +static struct device_attribute dev_attr_angle_snap_threshold = __ATTR(angle_snap_threshold, FILE_PERMISSIONS, mouse_param_show, mouse_param_store); +static struct device_attribute dev_attr_angle_snap_angle = __ATTR(angle_snap_angle, FILE_PERMISSIONS, mouse_param_show, mouse_param_store); + + +static struct attribute *mouse_attrs[] = { + &dev_attr_acceleration_mode.attr, + &dev_attr_input_cap.attr, + &dev_attr_ratio_yx.attr, + &dev_attr_output_cap.attr, + &dev_attr_offset.attr, + &dev_attr_prescale.attr, + &dev_attr_acceleration.attr, + &dev_attr_sensitivity.attr, + &dev_attr_exponent.attr, + &dev_attr_midpoint.attr, + &dev_attr_motivity.attr, + &dev_attr_use_smoothing.attr, + &dev_attr_lut_size.attr, + &dev_attr_lut_data.attr, + &dev_attr_cc_data_aggregate.attr, + &dev_attr_rotation_angle.attr, + &dev_attr_angle_snap_threshold.attr, + &dev_attr_angle_snap_angle.attr, + NULL, +}; + +static const struct attribute_group mouse_attr_group = { + .name = "accel_config", + .attrs = mouse_attrs, +}; + +static const struct attribute_group *mouse_groups[] = { + &mouse_attr_group, + NULL, +}; + struct mouse_state { int x; int y; + struct accel_params *params; }; #if __cleanup_events @@ -69,6 +132,8 @@ static void driver_events(struct input_handle *handle, const struct input_value if (x == NONE_EVENT_VALUE && y == NONE_EVENT_VALUE) goto unchanged_return; + // Get the accel params + struct accel_params *params = state->params; error = accelerate(&x, &y); /* Reset state */ state->x = NONE_EVENT_VALUE; @@ -198,6 +263,7 @@ static int input_register_handle_head(struct input_handle *handle) { static int driver_connect(struct input_handler *handler, struct input_dev *dev, const struct input_device_id *id) { struct input_handle *handle; struct mouse_state *state; + struct accel_params *accel_config; int error; handle = kzalloc(sizeof(struct input_handle), GFP_KERNEL); @@ -210,6 +276,22 @@ static int driver_connect(struct input_handler *handler, struct input_dev *dev, return -ENOMEM; } + accel_config = kzalloc(sizeof(struct accel_params), GFP_KERNEL); + if (!accel_config) { + kfree(handle); + kfree(state); + return -ENOMEM; + } + state->params = accel_config; + + input_set_drvdata(dev, state); + + error = sysfs_create_group(&dev->dev.kobj, &mouse_attr_group); + if (error) { + pr_err("Failed to create sysfs group: %d\n", error); + goto err_free_mem; + } + state->x = NONE_EVENT_VALUE; state->y = NONE_EVENT_VALUE; @@ -246,7 +328,9 @@ static int driver_connect(struct input_handler *handler, struct input_dev *dev, static void driver_disconnect(struct input_handle *handle) { input_close_device(handle); input_unregister_handle(handle); + kfree(((struct mouse_state*)handle->private)->params); kfree(handle->private); + sysfs_remove_group(&handle->dev->dev.kobj, &mouse_attr_group); kfree(handle); } @@ -269,6 +353,106 @@ struct input_handler driver_handler = { .match = driver_match }; +static ssize_t mouse_param_show(struct device *dev, struct device_attribute *attr, char *buf) { + struct input_dev *idev = to_input_dev(dev); + struct mouse_state *state = input_get_drvdata(idev); + if (!state) return -ENODEV; + + struct accel_params *params = state->params; + + if (attr == &dev_attr_acceleration_mode) + return sysfs_emit(buf, "%d\n", params->acceleration_mode); + if (attr == &dev_attr_input_cap) + return sysfs_emit(buf, "%lld\n", params->input_cap); + if (attr == &dev_attr_ratio_yx) + return sysfs_emit(buf, "%lld\n", params->ratio_yx); + if (attr == &dev_attr_output_cap) + return sysfs_emit(buf, "%lld\n", params->output_cap); + if (attr == &dev_attr_offset) + return sysfs_emit(buf, "%lld\n", params->offset); + if (attr == &dev_attr_prescale) + return sysfs_emit(buf, "%lld\n", params->prescale); + if (attr == &dev_attr_acceleration) + return sysfs_emit(buf, "%lld\n", params->acceleration); + if (attr == &dev_attr_sensitivity) + return sysfs_emit(buf, "%lld\n", params->sensitivity); + if (attr == &dev_attr_exponent) + return sysfs_emit(buf, "%lld\n", params->exponent); + if (attr == &dev_attr_midpoint) + return sysfs_emit(buf, "%lld\n", params->midpoint); + if (attr == &dev_attr_motivity) + return sysfs_emit(buf, "%lld\n", params->motivity); + if (attr == &dev_attr_use_smoothing) + return sysfs_emit(buf, "%d\n", params->use_smoothing); + if (attr == &dev_attr_lut_size) + return sysfs_emit(buf, "%lu\n", params->lut_size); + if (attr == &dev_attr_lut_data) + return sysfs_emit(buf, "%s\n", params->lut_data); + if (attr == &dev_attr_cc_data_aggregate) + return sysfs_emit(buf, "%s\n", params->cc_data_aggregate); + if (attr == &dev_attr_rotation_angle) + return sysfs_emit(buf, "%lld\n", params->rotation_angle); + if (attr == &dev_attr_angle_snap_threshold) + return sysfs_emit(buf, "%lld\n", params->angle_snap_threshold); + if (attr == &dev_attr_angle_snap_angle) + return sysfs_emit(buf, "%lld\n", params->angle_snap_angle); + return -EINVAL; +} + +static ssize_t mouse_param_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { + struct input_dev *idev = to_input_dev(dev); + struct mouse_state *state = input_get_drvdata(idev); + if (!state) return -ENODEV; + + struct accel_params *data = state->params; + long long val; + int ret; + + ret = kstrtoll(buf, 10, &val); + if (ret) return ret; + + if (attr == &dev_attr_acceleration_mode) + data->acceleration_mode = val; + else if (attr == &dev_attr_input_cap) + data->input_cap = val; + else if (attr == &dev_attr_ratio_yx) + data->ratio_yx = val; + else if (attr == &dev_attr_output_cap) + data->output_cap = val; + else if (attr == &dev_attr_offset) + data->offset = val; + else if (attr == &dev_attr_prescale) + data->prescale = val; + else if (attr == &dev_attr_acceleration) + data->acceleration = val; + else if (attr == &dev_attr_sensitivity) + data->sensitivity = val; + else if (attr == &dev_attr_exponent) + data->exponent = val; + else if (attr == &dev_attr_midpoint) + data->midpoint = val; + else if (attr == &dev_attr_motivity) + data->motivity = val; + else if (attr == &dev_attr_use_smoothing) + data->use_smoothing = val; + else if (attr == &dev_attr_lut_size) + data->lut_size = val; + else if (attr == &dev_attr_lut_data) { + // Call the parser + } + else if (attr == &dev_attr_cc_data_aggregate) { + // nop + } + else if (attr == &dev_attr_rotation_angle) + data->rotation_angle = val; + else if (attr == &dev_attr_angle_snap_threshold) + data->angle_snap_threshold = val; + else if (attr == &dev_attr_angle_snap_angle) + data->angle_snap_angle = val; + + return count; +} + static int __init yeetmouse_init(void) { return input_register_handler(&driver_handler); } From 8215e8240cb1c0f783c36663a6be125c6c6ecb83 Mon Sep 17 00:00:00 2001 From: Salman Abuhaimed Date: Fri, 1 May 2026 20:59:25 +0300 Subject: [PATCH 02/11] ignore clangd files --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index 0ca27cd..1754002 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,8 @@ *.kate-swp *.zst *.out +.cache +compile_commands.json .directory Module.symvers modules.order From 185398de1ed12c7f3d2b3bd7dda45c4f9b6dc0c5 Mon Sep 17 00:00:00 2001 From: Salman Abuhaimed Date: Fri, 1 May 2026 20:59:25 +0300 Subject: [PATCH 03/11] WIP: add per-device config --- driver/FixedMath/FixedUtil.h | 1 + driver/accel.c | 161 +++------- driver/accel.h | 20 +- driver/accel_modes.c | 565 +++++++++++++++++------------------ driver/accel_modes.h | 71 +---- driver/driver.c | 349 +++++++++++++++------- shared_definitions.h | 55 ++++ 7 files changed, 654 insertions(+), 568 deletions(-) diff --git a/driver/FixedMath/FixedUtil.h b/driver/FixedMath/FixedUtil.h index 9499c82..d3267d5 100644 --- a/driver/FixedMath/FixedUtil.h +++ b/driver/FixedMath/FixedUtil.h @@ -34,6 +34,7 @@ // Include numeric types #include +#include // If FP_ASSERT is not custom-defined, then use the standard one //#ifndef FP_ASSERT diff --git a/driver/accel.c b/driver/accel.c index 10dbe14..31ba949 100644 --- a/driver/accel.c +++ b/driver/accel.c @@ -1,13 +1,11 @@ // SPDX-License-Identifier: GPL-2.0-or-later #include "accel.h" -#include "util.h" #include #include #include #include //strlen #include "FixedMath/Fixed64.h" -#include "../shared_definitions.h" #include "accel_modes.h" #include "defaults.h" @@ -99,81 +97,14 @@ struct ModesConstants modesConst = { .sin_a = 0, .cos_a = 0, .as_cos = 0, .as_sin = 0, .as_half_threshold = 0, .current_func_at_0 = FP64_1 }; -static ktime_t g_next_update = 0; -INLINE void update_params(ktime_t now) -{ - if(!g_update) return; - if(now < g_next_update) return; - g_update = 0; - g_next_update = now + 1000000000ll; //Next update is allowed after 1s of delay - - modesConst.is_init = false; - - PARAM_UPDATE(InputCap); - PARAM_UPDATE(Sensitivity); - PARAM_UPDATE(RatioYX); - PARAM_UPDATE(Acceleration); - PARAM_UPDATE(OutputCap); - PARAM_UPDATE(Offset); - PARAM_UPDATE(Exponent); - PARAM_UPDATE(Midpoint); - PARAM_UPDATE(PreScale); - PARAM_UPDATE(Motivity); - PARAM_UPDATE(RotationAngle); - PARAM_UPDATE(AngleSnap_Threshold); - PARAM_UPDATE(AngleSnap_Angle); - g_LutSize = PARAM_UPDATE_UL(LutSize); - g_AccelerationMode = PARAM_UPDATE_UL(AccelerationMode); - if(g_LutSize > MAX_LUT_ARRAY_SIZE) - g_LutSize = MAX_LUT_ARRAY_SIZE; - // LutDataBuf get auto updated, we don't need to do anything, just extract the data - // Populate the g_LutData with the data in the buffer - char* p = g_param_LutDataBuf; - int i = 0; - for(; i < g_LutSize*2 && *p; i++) { - FP_LONG val; - p += FP64_FromString(p, &val) + 1; // + 1 to skip the ';' or ',' - // The format for the driver side is very strict tho, so don't edit it by hand pls. - ((i % 2 == 0) ? g_LutData_x : g_LutData_y)[i/2] = val; - - // Debug stuff (you know it didn't work the first time (nor the 10th time... (that's at least 10 'blue screens'))) - //char buf[25]; - //FP64_ToString(val, buf, 4); - //printk("YeetMouse: Converted %s, next char is: %i\n", buf, *p); - } - - // Did not work correctly - if(i % 2 == 1) - g_LutSize = 0; - - // Sanity check - if(g_LutSize <= 1 && (g_AccelerationMode == AccelMode_Lut || g_AccelerationMode == AccelMode_CustomCurve)) - g_AccelerationMode = AccelMode_Current; - - if ((g_AccelerationMode == AccelMode_Lut || g_AccelerationMode == AccelMode_CustomCurve) && - (g_LutData_x[g_LutSize-1] == g_LutData_x[g_LutSize-2] && g_LutData_y[g_LutSize-1] == g_LutData_y[g_LutSize-2])) - g_AccelerationMode = AccelMode_Current; - - // Angle snap threshold should be in range [0, PI) - if(g_AngleSnap_Threshold >= FP64_PI || g_AngleSnap_Threshold < 0) { - g_AngleSnap_Threshold = 0; - } - - update_constants(); -} - // Acceleration happens here -int accelerate(int *x, int *y) +int accelerate(const struct accel_params * params, struct accel_runtime *rt, const struct ModesConstants *constants, int *x, int *y) { FP_LONG delta_x, delta_y, ms, speed; //static long buffer_x = 0; //static long buffer_y = 0; - //Static float assignment should happen at compile-time and thus should be safe here. However, avoid non-static assignment of floats outside kernel_fpu_begin()/kernel_fpu_end() - static FP_LONG carry_x = 0; - static FP_LONG carry_y = 0; //static FP_LONG carry_whl = 0; static FP_LONG last_ms = One; - static ktime_t last; ktime_t now; int status = 0; @@ -187,7 +118,7 @@ int accelerate(int *x, int *y) //Calculate frametime now = ktime_get(); // ns - long long dt = (now - last); + long long dt = (now - rt->last); //int frac = dt % 10000; // We can't just store milliseconds as this would lose a lot of precision (nano -> mili, that's 10^-6 difference). // But we have only Q16.16 bits of precision, meaning 16 bits for the fractional part of the number (it's constant!). @@ -198,7 +129,7 @@ int accelerate(int *x, int *y) /// THE ABOVE NO LONGER HOLDS, AS I'VE MOVED (AGAIN), THIS TIME TO 64bit FIXED POINT MATH //ms = FP64_FromInt(dt / 10000ll) + FP64_Div(FP64_FromInt(frac), fp64_10000); // NOT MILLISECONDS, its ms * 100 ms = FP64_DivPrecise(FP64_FromInt(dt), FP64_FromInt(1000000)); - last = now; + rt->last = now; //if(ms < 1) ms = last_ms; //Sometimes, urbs appear bunched -> Beyond µs resolution so the timing reading is plain wrong. Fallback to last known valid frametime // Editor node: I have no idea, what this line above really does, but commenting it out solves all my problems // with incorrect data. It seems that it tries to fix a problem that doesn't exist, or doesn't exist on my @@ -209,12 +140,12 @@ int accelerate(int *x, int *y) last_ms = ms; // Update acceleration parameters periodically - update_params(now); + // update_params(params, now); // Apply Pre-Scale - if (g_PreScale != FP64_1) { - delta_x = FP64_Mul(delta_x, g_PreScale); - delta_y = FP64_Mul(delta_y, g_PreScale); + if (params->prescale != FP64_1) { + delta_x = FP64_Mul(delta_x, params->prescale); + delta_y = FP64_Mul(delta_y, params->prescale); } // Calculate velocity @@ -222,79 +153,79 @@ int accelerate(int *x, int *y) speed = FP64_DivPrecise(speed, ms); // Apply speedcap - if (g_InputCap > 0) { - //if(speed >= g_InputCap) { - if (FP64_Sub(speed, g_InputCap) > 0) { - speed = g_InputCap; + if (params->input_cap > 0) { + //if(speed >= params->input_cap) { + if (FP64_Sub(speed, params->input_cap) > 0) { + speed = params->input_cap; } } - speed = FP64_Sub(speed, g_Offset); + speed = FP64_Sub(speed, params->offset); // Apply Rotation before everything else to keep the precision - if(g_RotationAngle != 0) { - FP_LONG new_delta_x = FP64_Mul(delta_x, modesConst.cos_a) - FP64_Mul(delta_y, modesConst.sin_a); - delta_y = FP64_Mul(delta_x, modesConst.sin_a) + FP64_Mul(delta_y, modesConst.cos_a); + if(params->rotation_angle != 0) { + FP_LONG new_delta_x = FP64_Mul(delta_x, constants->cos_a) - FP64_Mul(delta_y, constants->sin_a); + delta_y = FP64_Mul(delta_x, constants->sin_a) + FP64_Mul(delta_y, constants->cos_a); delta_x = new_delta_x; } static_assert(AccelMode_Count == 10, "Wrong AccelMode count!"); // Apply acceleration if movement is over offset if (speed > 0) { - switch (g_AccelerationMode) { + switch (params->acceleration_mode) { case AccelMode_Linear: - speed = accel_linear(speed); + speed = accel_linear(constants, params->acceleration, params->use_smoothing, speed); break; case AccelMode_Power: - speed = accel_power(speed); + speed = accel_power(constants, params->midpoint, params->acceleration, params->exponent, params->use_smoothing, speed); break; case AccelMode_Classic: - speed = accel_classic(speed); + speed = accel_classic(constants, params->acceleration, params->use_smoothing, speed); break; case AccelMode_Motivity: - speed = accel_motivity(speed); + speed = accel_motivity(constants, params->midpoint, speed); break; case AccelMode_Synchronous: - speed = accel_synchronous(speed); + speed = accel_synchronous(constants, params->acceleration, params->use_smoothing, speed); break; case AccelMode_Natural: - speed = accel_natural(speed); + speed = accel_natural(constants, params->midpoint, params->use_smoothing, speed); break; case AccelMode_Jump: - speed = accel_jump(speed); + speed = accel_jump(constants, params->midpoint, params->use_smoothing, speed); break; case AccelMode_Lut: case AccelMode_CustomCurve: - speed = accel_lut(speed); + speed = accel_lut(params->lut_pairs, params->lut_data_x, params->lut_data_y, speed); break; default: speed = FP64_1; break; } } else { - speed = modesConst.current_func_at_0; + speed = constants->current_func_at_0; } // Actually apply accelerated sensitivity, allow post-scaling and apply carry from previous round // Like RawAccel, sensitivity will be a final multiplier: - if (g_RatioYX == FP64_1) { - if(g_Sensitivity != FP64_1) - speed = FP64_Mul(speed, g_Sensitivity); + if (params->ratio_yx == FP64_1) { + if(params->sensitivity != FP64_1) + speed = FP64_Mul(speed, params->sensitivity); // Apply Output Limit - if(g_OutputCap > 0) - speed = FP64_Min(g_OutputCap, speed); + if(params->output_cap > 0) + speed = FP64_Min(params->output_cap, speed); // Apply acceleration delta_x = FP64_Mul(delta_x, speed); delta_y = FP64_Mul(delta_y, speed); } else { - speed = FP64_Mul(speed, g_Sensitivity); - FP_LONG speed_Y = FP64_Mul(speed, g_RatioYX); + speed = FP64_Mul(speed, params->sensitivity); + FP_LONG speed_Y = FP64_Mul(speed, params->ratio_yx); // Apply Output Limit - if(g_OutputCap > 0) { - speed = FP64_Min(g_OutputCap, speed); - speed_Y = FP64_Min(g_OutputCap, speed_Y); + if(params->output_cap > 0) { + speed = FP64_Min(params->output_cap, speed); + speed_Y = FP64_Min(params->output_cap, speed_Y); } // Apply acceleration @@ -303,36 +234,36 @@ int accelerate(int *x, int *y) } // Angle Snapping - if(modesConst.as_half_threshold != 0) { + if(constants->as_half_threshold != 0) { FP_LONG delta_mag = FP64_Sqrt(FP64_Add(FP64_Mul(delta_x, delta_x), FP64_Mul(delta_y, delta_y))); if (delta_mag != 0) { FP_LONG current_angle = FP64_Atan2(delta_y, delta_x); - FP_LONG angle_diff = FP64_Sub(g_AngleSnap_Angle, current_angle); + FP_LONG angle_diff = FP64_Sub(params->angle_snap_angle, current_angle); FP_LONG angle_diff_quarter = FP64_PI_2 - FP64_Abs(angle_diff); int sign = FP64_Sign(angle_diff_quarter); angle_diff_quarter = FP64_Abs(angle_diff_quarter) - FP64_PI_2; - if (FP64_Abs(angle_diff_quarter) <= modesConst.as_half_threshold) { - delta_x = FP64_Mul(modesConst.as_cos, delta_mag) * sign; - delta_y = FP64_Mul(modesConst.as_sin, delta_mag) * sign; + if (FP64_Abs(angle_diff_quarter) <= constants->as_half_threshold) { + delta_x = FP64_Mul(constants->as_cos, delta_mag) * sign; + delta_y = FP64_Mul(constants->as_sin, delta_mag) * sign; } } } - delta_x = FP64_Add(delta_x, carry_x); - delta_y = FP64_Add(delta_y, carry_y); + delta_x = FP64_Add(delta_x, rt->carry_x); + delta_y = FP64_Add(delta_y, rt->carry_y); // I don't do wheel, sorry - //delta_whl *= g_ScrollsPerTick/3.0f; + //delta_whl *= params->scrolls_per_tick/3.0f; //Cast back to int *x = FP64_RoundToInt(delta_x); *y = FP64_RoundToInt(delta_y); //Save carry for next round - carry_x = FP64_Sub(delta_x, FP64_FromInt(*x)); - carry_y = FP64_Sub(delta_y, FP64_FromInt(*y)); + rt->carry_x = FP64_Sub(delta_x, FP64_FromInt(*x)); + rt->carry_y = FP64_Sub(delta_y, FP64_FromInt(*y)); //carry_whl = delta_whl - *wheel; // Used to very roughly estimate the performance, and 0.1% lows @@ -363,4 +294,4 @@ unsigned long atoul(const char *str) { } return result; -} \ No newline at end of file +} diff --git a/driver/accel.h b/driver/accel.h index 413f1cc..9f521ce 100644 --- a/driver/accel.h +++ b/driver/accel.h @@ -1,13 +1,22 @@ #ifndef _ACCEL_H #define _ACCEL_H #include +#include -#include "accel_modes.h" #include "FixedMath/Fixed64.h" +#include "../shared_definitions.h" -int accelerate(int *x, int *y); +#define MAX_LUT_ARRAY_SIZE 128 +#define MAX_LUT_BUF_LEN 4096 + +struct accel_runtime { + FP_LONG carry_x, carry_y; + FP_LONG last_ms; + ktime_t last; +}; struct accel_params { + struct rcu_head rcu; char acceleration_mode; FP_LONG input_cap; FP_LONG sensitivity; @@ -20,12 +29,15 @@ struct accel_params { FP_LONG midpoint; FP_LONG motivity; bool use_smoothing; - unsigned long lut_size; - char lut_data[MAX_LUT_BUF_LEN]; + unsigned long lut_pairs; + FP_LONG lut_data_x[MAX_LUT_ARRAY_SIZE]; + FP_LONG lut_data_y[MAX_LUT_ARRAY_SIZE]; char cc_data_aggregate[MAX_LUT_BUF_LEN]; FP_LONG rotation_angle; FP_LONG angle_snap_threshold; FP_LONG angle_snap_angle; }; +int accelerate(const struct accel_params * params, struct accel_runtime *rt, const struct ModesConstants *constants, int *x, int *y); + #endif /* _ACCEL_H */ diff --git a/driver/accel_modes.c b/driver/accel_modes.c index 96f897d..d220727 100644 --- a/driver/accel_modes.c +++ b/driver/accel_modes.c @@ -1,61 +1,137 @@ #include "accel_modes.h" -#include "../shared_definitions.h" #include "FixedMath/Fixed64.h" #include "FixedMath/FixedUtil.h" +#include "accel.h" #define EXP_ARG_THRESHOLD 16ll -static bool synchronous_build_lut(void); -static bool s_sync_lut_ready = false; +static FP_LONG synchronous_legacy(const struct ModesConstants *constants, FP_LONG acceleration, FP_LONG x) { + if (constants->useClamp) { + FP_LONG L = FP64_Mul(constants->gammaConst, FP64_Sub(FP64_Log(x), constants->logSync)); + if (L < FP64_1) return constants->minSens; + if (L > -FP64_1) return constants->maxSens; + return FP64_Exp(FP64_Mul(L, constants->logMot)); + } + + if (x == acceleration) { + return FP64_1; + } + + FP_LONG delta = FP64_Sub(FP64_Log(x), constants->logSync); + FP_LONG M = FP64_Mul(constants->gammaConst, FP64_Abs(delta)); + FP_LONG T = FP64_Tanh(FP64_Pow(M, constants->sharpness)); + FP_LONG exponent = FP64_Pow(T, constants->sharpnessRecip); + if (delta < 0) { + exponent = -exponent; + } + return FP64_Exp(FP64_Mul(exponent, constants->logMot)); +} + +// Helper: build LUT for smoothing/gain mode +static bool synchronous_build_lut(struct ModesConstants *constants, FP_LONG acceleration) { + // x_start = 2^SYNC_START + constants->x_start = FP64_Scalbn(FP64_1, SYNC_START); + + FP_LONG sum = 0; + FP_LONG prev_x = 0; + + int idx = 0; + + // integrate sync_legacy in small steps using the same 2-point midpoint rule + for (int e = 0; e < (SYNC_STOP - SYNC_START); ++e) { + // expScale = 2^(e + SYNC_START) / SYNC_NUM + FP_LONG expScale = FP64_DivPrecise(FP64_Scalbn(FP64_1, e + SYNC_START), FP64_FromInt(SYNC_NUM)); + + for (int i = 0; i < SYNC_NUM; ++i) { + // b = (i + SYNC_NUM) * expScale [sweeps from 2^(e+SYNC_START) .. 2^(e+1+SYNC_START)] + FP_LONG b = FP64_Mul(FP64_FromInt(i + SYNC_NUM), expScale); + + // integrate from a -> b in two equal partitions + FP_LONG interval = FP64_DivPrecise(FP64_Sub(b, prev_x), FP64_FromInt(2)); + for (int p = 1; p <= 2; ++p) { + // xi = a + p*interval + FP_LONG xi = FP64_Add(prev_x, FP64_Mul(FP64_FromInt(p), interval)); + // sum += sync_legacy(xi) * interval + sum = FP64_Add(sum, FP64_Mul(synchronous_legacy(constants, acceleration, xi), interval)); + } + + prev_x = b; + + constants->data[idx++] = sum; + } + } + + // final point at 2^SYNC_STOP + { + FP_LONG b = FP64_Scalbn(FP64_1, SYNC_STOP); + FP_LONG interval = FP64_DivPrecise(FP64_Sub(b, prev_x), FP64_FromInt(2)); + for (int p = 1; p <= 2; ++p) { + FP_LONG xi = FP64_Add(prev_x, FP64_Mul(FP64_FromInt(p), interval)); + sum = FP64_Add(sum, FP64_Mul(synchronous_legacy(constants, acceleration, xi), interval)); + } + prev_x = b; + + if (idx < SYNC_CAPACITY) { + constants->data[idx] = sum; // last element + } + } + + constants->lut_ready = true; + return true; +} // Recalculate new modes constants -void update_constants(void) { +void update_constants(struct accel_params *params, struct ModesConstants *constants) { // General - modesConst.accel_sub_1 = FP64_Sub(g_Acceleration, FP64_1); - modesConst.exp_sub_1 = FP64_Sub(g_Exponent, FP64_1); - modesConst.cap_x = 0; - modesConst.cap_y = 0; - modesConst.gain_constant = 0; - modesConst.sign = FP64_1; + constants->accel_sub_1 = FP64_Sub(params->acceleration, FP64_1); + constants->exp_sub_1 = FP64_Sub(params->exponent, FP64_1); + constants->cap_x = 0; + constants->cap_y = 0; + constants->gain_constant = 0; + constants->sign = FP64_1; // Synchronous - if (g_AccelerationMode == AccelMode_Synchronous) { - if (g_Motivity <= FP64_1) { + if (params->acceleration_mode == AccelMode_Synchronous) { + if (params->motivity <= FP64_1) { printk("YeetMouse: Error: Acceleration mode 'Synchronous' is not supported for motivity 1.\n"); - g_Acceleration = 0; - g_AccelerationMode = AccelMode_Current; + params->acceleration = 0; + params->acceleration_mode = AccelMode_Current; } else { - modesConst.logMot = FP64_Log(g_Motivity); - modesConst.gammaConst = FP64_DivPrecise(g_Exponent, modesConst.logMot); - modesConst.logSync = FP64_Log(g_Acceleration); + constants->logMot = FP64_Log(params->motivity); + constants->gammaConst = FP64_DivPrecise(params->exponent, constants->logMot); + constants->logSync = FP64_Log(params->acceleration); // sharpness = (midpoint == 0) ? 16.0 : (0.5 / midpoint) - modesConst.sharpness = (g_Midpoint == 0) + constants->sharpness = (params->midpoint == 0) ? FP64_FromInt(16) - : FP64_DivPrecise(FP64_0_5, g_Midpoint); + : FP64_DivPrecise(FP64_0_5, params->midpoint); + + constants->sharpnessRecip = FP64_DivPrecise(FP64_1, constants->sharpness); + constants->useClamp = (constants->sharpness >= FP64_FromInt(16)); - modesConst.sharpnessRecip = FP64_DivPrecise(FP64_1, modesConst.sharpness); - modesConst.useClamp = (modesConst.sharpness >= FP64_FromInt(16)); + constants->minSens = FP64_DivPrecise(FP64_1, params->motivity); + constants->maxSens = params->motivity; - modesConst.minSens = FP64_DivPrecise(FP64_1, g_Motivity); - modesConst.maxSens = g_Motivity; + constants->lut_ready = false; + } - s_sync_lut_ready = false; + if (params->use_smoothing) { + synchronous_build_lut(constants, params->acceleration); } } // Linear - if (g_AccelerationMode == AccelMode_Linear) { - if (g_Acceleration == 0) { + if (params->acceleration_mode == AccelMode_Linear) { + if (params->acceleration == 0) { printk("YeetMouse: Error: Acceleration mode 'Linear' is not supported for acceleration 0.\n"); - g_Acceleration = 0; - g_AccelerationMode = AccelMode_Current; + params->acceleration = 0; + params->acceleration_mode = AccelMode_Current; } - else if (g_UseSmoothing) { + else if (params->use_smoothing) { FP_LONG sign = FP64_1; - FP_LONG cap_y = FP64_Sub(g_Midpoint, FP64_1); + FP_LONG cap_y = FP64_Sub(params->midpoint, FP64_1); FP_LONG cap_x = FP64_FromInt(0); FP_LONG constant = FP64_FromInt(0); if (cap_y != 0) { @@ -63,26 +139,26 @@ void update_constants(void) { cap_y = FP64_Mul(cap_y, Neg1); sign = Neg1; } - cap_x = FP64_DivPrecise(FP64_DivPrecise(cap_y, FP64_FromInt(2)), g_Acceleration); + cap_x = FP64_DivPrecise(FP64_DivPrecise(cap_y, FP64_FromInt(2)), params->acceleration); } constant = FP64_DivPrecise(FP64_Mul(FP64_Mul(cap_y, Neg1), cap_x), FP64_FromInt(2)); - modesConst.cap_x = cap_x; - modesConst.cap_y = cap_y; - modesConst.gain_constant = constant; - modesConst.sign = sign; + constants->cap_x = cap_x; + constants->cap_y = cap_y; + constants->gain_constant = constant; + constants->sign = sign; } } // Classic - if (g_AccelerationMode == AccelMode_Classic) { - if (g_UseSmoothing && (g_Exponent == 0 || modesConst.exp_sub_1 == 0)) { + if (params->acceleration_mode == AccelMode_Classic) { + if (params->use_smoothing && (params->exponent == 0 || constants->exp_sub_1 == 0)) { printk("YeetMouse: Error: Acceleration mode 'Classic' is not supported for exponent 0 or 1 while using the the smooth cap.\n"); - g_Acceleration = 0; - g_AccelerationMode = AccelMode_Current; + params->acceleration = 0; + params->acceleration_mode = AccelMode_Current; } else { - if (g_UseSmoothing) { + if (params->use_smoothing) { FP_LONG sign = FP64_1; - FP_LONG cap_y = FP64_Sub(g_Midpoint, FP64_1); + FP_LONG cap_y = FP64_Sub(params->midpoint, FP64_1); FP_LONG cap_x = FP64_FromInt(0); FP_LONG constant = FP64_FromInt(0); if (cap_y != 0) { @@ -90,140 +166,140 @@ void update_constants(void) { cap_y = FP64_Mul(cap_y, Neg1); sign = Neg1; } - cap_x = FP64_DivPrecise(FP64_Pow(FP64_DivPrecise(cap_y, g_Exponent), - FP64_DivPrecise(FP64_1, modesConst.exp_sub_1)), g_Acceleration); + cap_x = FP64_DivPrecise(FP64_Pow(FP64_DivPrecise(cap_y, params->exponent), + FP64_DivPrecise(FP64_1, constants->exp_sub_1)), params->acceleration); } - FP_LONG factor = FP64_DivPrecise(FP64_Sub(g_Exponent, FP64_1), g_Exponent); + FP_LONG factor = FP64_DivPrecise(FP64_Sub(params->exponent, FP64_1), params->exponent); constant = FP64_Mul(cap_y, cap_x); constant = FP64_Mul(factor, constant); constant = FP64_Mul(constant, Neg1); - modesConst.cap_x = cap_x; - modesConst.cap_y = cap_y; - modesConst.gain_constant = constant; - modesConst.sign = sign; + constants->cap_x = cap_x; + constants->cap_y = cap_y; + constants->gain_constant = constant; + constants->sign = sign; } } } // Natural - if (g_AccelerationMode == AccelMode_Natural) { - if (modesConst.exp_sub_1 == 0 || g_Exponent == FP64_1) { + if (params->acceleration_mode == AccelMode_Natural) { + if (constants->exp_sub_1 == 0 || params->exponent == FP64_1) { printk("YeetMouse: Error: Acceleration mode 'Natural' is not supported for exponent 1.\n"); - g_Acceleration = 0; - g_AccelerationMode = AccelMode_Current; + params->acceleration = 0; + params->acceleration_mode = AccelMode_Current; } - if (g_Acceleration == 0) { + if (params->acceleration == 0) { printk("YeetMouse: Error: Acceleration mode 'Natural' is not supported for acceleration 0.\n"); - g_Acceleration = 0; - g_AccelerationMode = AccelMode_Current; + params->acceleration = 0; + params->acceleration_mode = AccelMode_Current; } else { - modesConst.auxiliar_accel = FP64_DivPrecise(g_Acceleration, FP64_Abs(modesConst.exp_sub_1)); - modesConst.auxiliar_constant = FP64_DivPrecise(-modesConst.exp_sub_1, modesConst.auxiliar_accel); + constants->auxiliar_accel = FP64_DivPrecise(params->acceleration, FP64_Abs(constants->exp_sub_1)); + constants->auxiliar_constant = FP64_DivPrecise(-constants->exp_sub_1, constants->auxiliar_accel); } } // Jump - if (g_AccelerationMode == AccelMode_Jump) { - if (g_Midpoint == 0) { + if (params->acceleration_mode == AccelMode_Jump) { + if (params->midpoint == 0) { printk("YeetMouse: Error: Acceleration mode 'Jump' is not supported for midpoint 0.\n"); - g_Midpoint = FP64_1; - g_Acceleration = 0; - g_AccelerationMode = AccelMode_Current; + params->midpoint = FP64_1; + params->acceleration = 0; + params->acceleration_mode = AccelMode_Current; } else { - FP_LONG smooth_inv = FP64_Mul(g_Exponent, g_Midpoint); + FP_LONG smooth_inv = FP64_Mul(params->exponent, params->midpoint); if (smooth_inv < FP64_1) - modesConst.r = 0; + constants->r = 0; else - modesConst.r = FP64_DivPrecise(Pi2, smooth_inv); + constants->r = FP64_DivPrecise(Pi2, smooth_inv); - FP_LONG r_times_m = FP64_Mul(modesConst.r, g_Midpoint); + FP_LONG r_times_m = FP64_Mul(constants->r, params->midpoint); - if (modesConst.r == 0) { - modesConst.C0 = FP64_1; + if (constants->r == 0) { + constants->C0 = FP64_1; } // Safely exponentiate without overflow (ln(1+exp(x)) when x -> 'inf' = ln(exp(x)) = x. (in practice works for x >= 8)) else if (r_times_m < (EXP_ARG_THRESHOLD << FP64_Shift)) - modesConst.C0 = FP64_Mul(modesConst.accel_sub_1, FP64_DivPrecise(FP64_Log(FP64_Add(FP64_1, FP64_Exp(r_times_m))), modesConst.r)); + constants->C0 = FP64_Mul(constants->accel_sub_1, FP64_DivPrecise(FP64_Log(FP64_Add(FP64_1, FP64_Exp(r_times_m))), constants->r)); else - modesConst.C0 = FP64_Mul(modesConst.accel_sub_1, FP64_DivPrecise(r_times_m, modesConst.r)); + constants->C0 = FP64_Mul(constants->accel_sub_1, FP64_DivPrecise(r_times_m, constants->r)); } } // Power - if (g_AccelerationMode == AccelMode_Power) { - if (g_Exponent == 0 || g_Exponent == -FP64_1 || g_Acceleration == 0) { + if (params->acceleration_mode == AccelMode_Power) { + if (params->exponent == 0 || params->exponent == -FP64_1 || params->acceleration == 0) { printk("YeetMouse: Error: Acceleration mode 'Power' is not supported for exponent 0 or -1 or acceleration 0.\n"); - g_Acceleration = 0; - g_AccelerationMode = AccelMode_Current; + params->acceleration = 0; + params->acceleration_mode = AccelMode_Current; } - else if (g_Midpoint == 0 && !g_UseSmoothing) { - modesConst.offset_x = 0; - modesConst.power_constant = 0; + else if (params->midpoint == 0 && !params->use_smoothing) { + constants->offset_x = 0; + constants->power_constant = 0; } - else if ((g_Midpoint >= g_Motivity) && g_UseSmoothing) { + else if ((params->midpoint >= params->motivity) && params->use_smoothing) { printk("YeetMouse: Error: Acceleration mode 'Power' is not supported for output offsets higher than the smooth cap.\n"); - g_Acceleration = 0; - g_AccelerationMode = AccelMode_Current; + params->acceleration = 0; + params->acceleration_mode = AccelMode_Current; } - else if (FP64_DivPrecise(g_Midpoint, FP64_Mul(g_Acceleration, g_Exponent)) > FP64_100) { // 100 here is completely arbitrary + else if (FP64_DivPrecise(params->midpoint, FP64_Mul(params->acceleration, params->exponent)) > FP64_100) { // 100 here is completely arbitrary printk("YeetMouse: Error: Invalid parameters for the 'Power' mode.\n"); - g_Acceleration = 0; - g_AccelerationMode = AccelMode_Current; + params->acceleration = 0; + params->acceleration_mode = AccelMode_Current; } else { - // modesConst.offset_x = FP64_DivPrecise(FP64_Pow(FP64_DivPrecise(g_Midpoint, FP64_Add(g_Exponent, FP64_ONE)), - // FP64_DivPrecise(FP64_ONE, g_Exponent)), g_Acceleration); - // modesConst.power_constant = FP64_DivPrecise(FP64_Mul(modesConst.offset_x, FP64_Mul(g_Midpoint, g_Exponent)), FP64_Add(g_Exponent, FP64_ONE)); - - FP_LONG exponent_plus_one = FP64_Add(g_Exponent, FP64_1); - if (g_Midpoint == 0) { - modesConst.offset_x = 0; - modesConst.power_constant = 0; + // constants->offset_x = FP64_DivPrecise(FP64_Pow(FP64_DivPrecise(params->midpoint, FP64_Add(params->exponent, FP64_ONE)), + // FP64_DivPrecise(FP64_ONE, params->exponent)), params->acceleration); + // constants->power_constant = FP64_DivPrecise(FP64_Mul(constants->offset_x, FP64_Mul(params->midpoint, params->exponent)), FP64_Add(params->exponent, FP64_ONE)); + + FP_LONG exponent_plus_one = FP64_Add(params->exponent, FP64_1); + if (params->midpoint == 0) { + constants->offset_x = 0; + constants->power_constant = 0; } else { - FP_LONG one_over_exponent = FP64_DivPrecise(FP64_1, g_Exponent); - FP_LONG base_value = FP64_DivPrecise(g_Midpoint, exponent_plus_one); + FP_LONG one_over_exponent = FP64_DivPrecise(FP64_1, params->exponent); + FP_LONG base_value = FP64_DivPrecise(params->midpoint, exponent_plus_one); FP_LONG pow_result = FP64_Pow(base_value, one_over_exponent); - modesConst.offset_x = FP64_DivPrecise(pow_result, g_Acceleration); + constants->offset_x = FP64_DivPrecise(pow_result, params->acceleration); - FP_LONG intermediate = FP64_Mul(modesConst.offset_x, FP64_Mul(g_Midpoint, g_Exponent)); - modesConst.power_constant = FP64_DivPrecise(intermediate, exponent_plus_one); + FP_LONG intermediate = FP64_Mul(constants->offset_x, FP64_Mul(params->midpoint, params->exponent)); + constants->power_constant = FP64_DivPrecise(intermediate, exponent_plus_one); } - if (g_UseSmoothing) { - FP_LONG cap_y = g_Motivity; + if (params->use_smoothing) { + FP_LONG cap_y = params->motivity; FP_LONG cap_x = FP64_FromInt(0); if (cap_y > FP64_FromInt(0)) { cap_x = FP64_DivPrecise( FP64_Pow( FP64_DivPrecise(cap_y, exponent_plus_one), - FP64_DivPrecise(FP64_1, g_Exponent)), - g_Acceleration); + FP64_DivPrecise(FP64_1, params->exponent)), + params->acceleration); } - FP_LONG constant = FP64_Mul(g_Acceleration, cap_x); - constant = FP64_Pow(constant, g_Exponent); + FP_LONG constant = FP64_Mul(params->acceleration, cap_x); + constant = FP64_Pow(constant, params->exponent); constant = FP64_Mul(constant, cap_x); - constant = FP64_Add(constant, modesConst.power_constant); + constant = FP64_Add(constant, constants->power_constant); constant = FP64_Sub(constant, FP64_Mul(cap_x, cap_y)); - modesConst.cap_x = cap_x; - modesConst.cap_y = cap_y; - modesConst.gain_constant = constant; + constants->cap_x = cap_x; + constants->cap_y = cap_y; + constants->gain_constant = constant; } } } // Lut (Validation) - if (g_AccelerationMode == AccelMode_Lut || g_AccelerationMode == AccelMode_CustomCurve) { - if (g_LutSize <= 1 || g_LutData_x[g_LutSize-1] == g_LutData_x[g_LutSize-2]) - g_AccelerationMode = AccelMode_Current; + if (params->acceleration_mode == AccelMode_Lut || params->acceleration_mode == AccelMode_CustomCurve) { + if (params->lut_pairs <= 1 || params->lut_data_x[params->lut_pairs-1] == params->lut_data_x[params->lut_pairs-2]) + params->acceleration_mode = AccelMode_Current; // Check if LUT_x is sorted - for (int i = 1; i < g_LutSize; i++) { - if (g_LutData_x[i - 1] > g_LutData_x[i]) { - g_AccelerationMode = AccelMode_Current; + for (int i = 1; i < params->lut_pairs; i++) { + if (params->lut_data_x[i - 1] > params->lut_data_x[i]) { + params->acceleration_mode = AccelMode_Current; printk("YeetMouse: Error: Acceleration mode 'LUT' is not supported for unsorted LUT_x.\n"); break; } @@ -231,135 +307,49 @@ void update_constants(void) { } static_assert(AccelMode_Count == 10, "Wrong AccelMode count!"); - switch (g_AccelerationMode) { + switch (params->acceleration_mode) { case AccelMode_Linear: - modesConst.current_func_at_0 = accel_linear(FP64_0_01); + constants->current_func_at_0 = accel_linear(constants, params->acceleration, params->use_smoothing, FP64_0_01); break; case AccelMode_Power: - modesConst.current_func_at_0 = accel_power(FP64_0_01); + constants->current_func_at_0 = accel_power(constants, params->midpoint, params->acceleration, params->exponent, params->use_smoothing, FP64_0_01); break; case AccelMode_Classic: - modesConst.current_func_at_0 = accel_classic(FP64_0_01); + constants->current_func_at_0 = accel_classic(constants, params->acceleration, params->use_smoothing, FP64_0_01); break; case AccelMode_Motivity: - modesConst.current_func_at_0 = accel_motivity(FP64_0_01); + constants->current_func_at_0 = accel_motivity(constants, params->midpoint, FP64_0_01); break; case AccelMode_Synchronous: - modesConst.current_func_at_0 = accel_synchronous(FP64_0_01); - synchronous_build_lut(); + constants->current_func_at_0 = accel_synchronous(constants, params->acceleration, params->use_smoothing, FP64_0_01); break; case AccelMode_Natural: - modesConst.current_func_at_0 = accel_natural(FP64_0_01); + constants->current_func_at_0 = accel_natural(constants, params->midpoint, params->use_smoothing, FP64_0_01); break; case AccelMode_Jump: - modesConst.current_func_at_0 = accel_jump(FP64_0_01); + constants->current_func_at_0 = accel_jump(constants, params->midpoint, params->use_smoothing, FP64_0_01); break; case AccelMode_Lut: case AccelMode_CustomCurve: - modesConst.current_func_at_0 = accel_lut(FP64_0_01); + constants->current_func_at_0 = accel_lut(params->lut_pairs, params->lut_data_x, params->lut_data_y, FP64_0_01); break; default: - modesConst.current_func_at_0 = FP64_1; + constants->current_func_at_0 = FP64_1; break; } // Rotation (precalculate the trig. functions) - modesConst.sin_a = FP64_Sin(g_RotationAngle); - modesConst.cos_a = FP64_Cos(g_RotationAngle); + constants->sin_a = FP64_Sin(params->rotation_angle); + constants->cos_a = FP64_Cos(params->rotation_angle); - modesConst.as_cos = FP64_Cos(g_AngleSnap_Angle); - modesConst.as_sin = FP64_Sin(g_AngleSnap_Angle); - modesConst.as_half_threshold = FP64_DivPrecise(g_AngleSnap_Threshold, 2ll << FP64_Shift); + constants->as_cos = FP64_Cos(params->angle_snap_angle); + constants->as_sin = FP64_Sin(params->angle_snap_angle); + constants->as_half_threshold = FP64_DivPrecise(params->angle_snap_threshold, 2ll << FP64_Shift); - modesConst.is_init = 1; + constants->is_init = 1; } -#define SYNC_START (-3) -#define SYNC_STOP (9) -#define SYNC_NUM (8) -#define SYNC_CAPACITY ((SYNC_STOP - SYNC_START) * SYNC_NUM + 1) - -// Local LUT storage for synchronous smoothing -static struct { - FP_LONG x_start; // 2^SYNC_START - FP_LONG data[SYNC_CAPACITY]; // monotonic over x -} s_sync_lut; - -static FP_LONG synchronous_legacy(FP_LONG x) { - if (modesConst.useClamp) { - FP_LONG L = FP64_Mul(modesConst.gammaConst, FP64_Sub(FP64_Log(x), modesConst.logSync)); - if (L < FP64_1) return modesConst.minSens; - if (L > -FP64_1) return modesConst.maxSens; - return FP64_Exp(FP64_Mul(L, modesConst.logMot)); - } - - if (x == g_Acceleration) { - return FP64_1; - } - - FP_LONG delta = FP64_Sub(FP64_Log(x), modesConst.logSync); - FP_LONG M = FP64_Mul(modesConst.gammaConst, FP64_Abs(delta)); - FP_LONG T = FP64_Tanh(FP64_Pow(M, modesConst.sharpness)); - FP_LONG exponent = FP64_Pow(T, modesConst.sharpnessRecip); - if (delta < 0) { - exponent = -exponent; - } - return FP64_Exp(FP64_Mul(exponent, modesConst.logMot)); -} - -// Helper: build LUT for smoothing/gain mode -static bool synchronous_build_lut(void) { - // x_start = 2^SYNC_START - s_sync_lut.x_start = FP64_Scalbn(FP64_1, SYNC_START); - - FP_LONG sum = 0; - FP_LONG prev_x = 0; - - int idx = 0; - - // integrate sync_legacy in small steps using the same 2-point midpoint rule - for (int e = 0; e < (SYNC_STOP - SYNC_START); ++e) { - // expScale = 2^(e + SYNC_START) / SYNC_NUM - FP_LONG expScale = FP64_DivPrecise(FP64_Scalbn(FP64_1, e + SYNC_START), FP64_FromInt(SYNC_NUM)); - - for (int i = 0; i < SYNC_NUM; ++i) { - // b = (i + SYNC_NUM) * expScale [sweeps from 2^(e+SYNC_START) .. 2^(e+1+SYNC_START)] - FP_LONG b = FP64_Mul(FP64_FromInt(i + SYNC_NUM), expScale); - - // integrate from a -> b in two equal partitions - FP_LONG interval = FP64_DivPrecise(FP64_Sub(b, prev_x), FP64_FromInt(2)); - for (int p = 1; p <= 2; ++p) { - // xi = a + p*interval - FP_LONG xi = FP64_Add(prev_x, FP64_Mul(FP64_FromInt(p), interval)); - // sum += sync_legacy(xi) * interval - sum = FP64_Add(sum, FP64_Mul(synchronous_legacy(xi), interval)); - } - - prev_x = b; - - s_sync_lut.data[idx++] = sum; - } - } - - // final point at 2^SYNC_STOP - { - FP_LONG b = FP64_Scalbn(FP64_1, SYNC_STOP); - FP_LONG interval = FP64_DivPrecise(FP64_Sub(b, prev_x), FP64_FromInt(2)); - for (int p = 1; p <= 2; ++p) { - FP_LONG xi = FP64_Add(prev_x, FP64_Mul(FP64_FromInt(p), interval)); - sum = FP64_Add(sum, FP64_Mul(synchronous_legacy(xi), interval)); - } - prev_x = b; - - if (idx < SYNC_CAPACITY) { - s_sync_lut.data[idx] = sum; // last element - } - } - s_sync_lut_ready = true; - return true; -} - -static FP_LONG synchronous_eval(FP_LONG x) { +static FP_LONG synchronous_eval(const struct ModesConstants *constants, FP_LONG x) { // Find octave index: e = floor(log2(x)), clamped int e = FP64_Ilogb(x); if (e < SYNC_START) e = SYNC_START; @@ -382,55 +372,55 @@ static FP_LONG synchronous_eval(FP_LONG x) { // t = fractional part in [0,1) FP_LONG t = FP64_Sub(idxF, FP64_FromInt(idx)); - FP_LONG y = FP64_Lerp(s_sync_lut.data[idx], s_sync_lut.data[idx + 1], t); + FP_LONG y = FP64_Lerp(constants->data[idx], constants->data[idx + 1], t); return FP64_DivPrecise(y, x); } - FP_LONG y = s_sync_lut.data[0]; - return FP64_DivPrecise(y, s_sync_lut.x_start); + FP_LONG y = constants->data[0]; + return FP64_DivPrecise(y, constants->x_start); } -FP_LONG accel_linear(FP_LONG speed) { - if (g_UseSmoothing) { - if (speed < modesConst.cap_x) { - speed = FP64_Mul(modesConst.sign, FP64_Mul(speed, g_Acceleration)); +FP_LONG accel_linear(const struct ModesConstants *constants, FP_LONG acceleration, bool use_smoothing, FP_LONG speed) { + if (use_smoothing) { + if (speed < constants->cap_x) { + speed = FP64_Mul(constants->sign, FP64_Mul(speed, acceleration)); } else { - speed = FP64_Mul(modesConst.sign, FP64_Add(FP64_DivPrecise(modesConst.gain_constant, speed), modesConst.cap_y)); + speed = FP64_Mul(constants->sign, FP64_Add(FP64_DivPrecise(constants->gain_constant, speed), constants->cap_y)); } } else { - speed = FP64_Mul(speed, g_Acceleration); + speed = FP64_Mul(speed, acceleration); } return FP64_Add(FP64_1, speed); } -FP_LONG accel_power(FP_LONG speed) { - if (speed <= modesConst.offset_x) - speed = g_Midpoint; +FP_LONG accel_power(const struct ModesConstants *constants, FP_LONG midpoint, FP_LONG acceleration, FP_LONG exponent, bool use_smoothing, FP_LONG speed) { + if (speed <= constants->offset_x) + speed = midpoint; else { - if (g_UseSmoothing) { - if (speed < modesConst.cap_x) { - if (modesConst.power_constant == 0) - speed = FP64_PowFast(FP64_Mul(speed, g_Acceleration), g_Exponent); + if (use_smoothing) { + if (speed < constants->cap_x) { + if (constants->power_constant == 0) + speed = FP64_PowFast(FP64_Mul(speed, acceleration), exponent); else - speed = FP64_Add(FP64_PowFast(FP64_Mul(speed, g_Acceleration), g_Exponent), FP64_DivPrecise(modesConst.power_constant, speed)); + speed = FP64_Add(FP64_PowFast(FP64_Mul(speed, acceleration), exponent), FP64_DivPrecise(constants->power_constant, speed)); } else { - if (modesConst.cap_x == FP64_FromInt(0)) { - speed = modesConst.cap_y; + if (constants->cap_x == FP64_FromInt(0)) { + speed = constants->cap_y; } else { - speed = FP64_Add(FP64_DivPrecise(modesConst.gain_constant, speed), modesConst.cap_y); + speed = FP64_Add(FP64_DivPrecise(constants->gain_constant, speed), constants->cap_y); } } } else { - if (modesConst.power_constant == 0) - speed = FP64_PowFast(FP64_Mul(speed, g_Acceleration), g_Exponent); + if (constants->power_constant == 0) + speed = FP64_PowFast(FP64_Mul(speed, acceleration), exponent); else - speed = FP64_Add(FP64_PowFast(FP64_Mul(speed, g_Acceleration), g_Exponent), FP64_DivPrecise(modesConst.power_constant, speed)); + speed = FP64_Add(FP64_PowFast(FP64_Mul(speed, acceleration), exponent), FP64_DivPrecise(constants->power_constant, speed)); } } return speed; } -FP_LONG accel_classic(FP_LONG speed) { +FP_LONG accel_classic(const struct ModesConstants *constants, FP_LONG acceleration, bool use_smoothing, FP_LONG speed) { // (Speed * Acceleration) ^ (Exponent - 1) + 1 // Same as above just without adding the one //speed *= g_Acceleration; @@ -439,20 +429,20 @@ FP_LONG accel_classic(FP_LONG speed) { // FIXED-POINT: FP_LONG accel_classic_result = speed; - accel_classic_result = FP64_Mul(accel_classic_result, g_Acceleration); - accel_classic_result = FP64_PowFast(accel_classic_result, modesConst.exp_sub_1); + accel_classic_result = FP64_Mul(accel_classic_result, acceleration); + accel_classic_result = FP64_PowFast(accel_classic_result, constants->exp_sub_1); // if Use Smooth Cap is on, we proceed to calculate the transition // point and the function that provides the smooth cap - if (g_UseSmoothing) { + if (use_smoothing) { // we setup the y cap - if (speed < modesConst.cap_x) { - accel_classic_result = FP64_Mul(modesConst.sign, accel_classic_result); + if (speed < constants->cap_x) { + accel_classic_result = FP64_Mul(constants->sign, accel_classic_result); speed = FP64_Add(accel_classic_result, FP64_1); } else { - speed = FP64_Add(FP64_Mul(modesConst.sign, - FP64_Add(FP64_DivPrecise(modesConst.gain_constant, speed), - modesConst.cap_y)), FP64_1); + speed = FP64_Add(FP64_Mul(constants->sign, + FP64_Add(FP64_DivPrecise(constants->gain_constant, speed), + constants->cap_y)), FP64_1); } } else speed = FP64_Add(accel_classic_result, FP64_1); @@ -460,7 +450,7 @@ FP_LONG accel_classic(FP_LONG speed) { return speed; } -FP_LONG accel_motivity(FP_LONG speed) { +FP_LONG accel_motivity(const struct ModesConstants *constants, FP_LONG midpoint, FP_LONG speed) { // Acceleration / ( 1 + e ^ (midpoint - x)) //product = g_Midpoint-speed; //motivity = e; @@ -469,31 +459,28 @@ FP_LONG accel_motivity(FP_LONG speed) { //speed = motivity; // FIXED-POINT: - FP_LONG exp = FP64_ExpFast(FP64_Sub(g_Midpoint, speed)); - speed = FP64_Add(FP64_1, FP64_DivPrecise(modesConst.accel_sub_1, FP64_Add(FP64_1, exp))); + FP_LONG exp = FP64_ExpFast(FP64_Sub(midpoint, speed)); + speed = FP64_Add(FP64_1, FP64_DivPrecise(constants->accel_sub_1, FP64_Add(FP64_1, exp))); return speed; } -FP_LONG accel_synchronous(FP_LONG speed) { +FP_LONG accel_synchronous(const struct ModesConstants *constants, FP_LONG acceleration, bool use_smoothing, FP_LONG speed) { // Defensive: ensure speed > 0 for log-domain math; you can clamp differently if your file already does. if (speed <= 0) { return FP64_1; } FP_LONG val; - if (g_UseSmoothing) { - if (!s_sync_lut_ready) { // This should be skipped 100% (except the first time) of the time by the branch predictor - synchronous_build_lut(); - } - val = synchronous_eval(speed); + if (use_smoothing && constants->lut_ready) { + val = synchronous_eval(constants, speed); } else { - val = synchronous_legacy(speed); + val = synchronous_legacy(constants, acceleration, speed); } return val; } -FP_LONG accel_jump(FP_LONG speed) { +FP_LONG accel_jump(const struct ModesConstants *constants, FP_LONG midpoint, bool use_smoothing, FP_LONG speed) { // r = 2pi/(k*midpoint), where k is the smoothness factor (stored inside g_Exponent) // Jump: Acceleration / (1 + exp(r(midpoint - x))) + 1 // Smooth: Integral of the above divided by x pretty much @@ -501,51 +488,51 @@ FP_LONG accel_jump(FP_LONG speed) { if (speed <= 0) return FP64_1; - FP_LONG exp_arg = FP64_Mul(modesConst.r, FP64_Sub(g_Midpoint, speed)); + FP_LONG exp_arg = FP64_Mul(constants->r, FP64_Sub(midpoint, speed)); FP_LONG D = FP64_Exp(exp_arg); - if(g_UseSmoothing) { // smooth - if (modesConst.r != 0) { + if(use_smoothing) { // smooth + if (constants->r != 0) { FP_LONG natural_log = exp_arg > (EXP_ARG_THRESHOLD << FP64_Shift) ? exp_arg : FP64_Log(FP64_Add(FP64_1, D)); - FP_LONG integral = FP64_Mul(modesConst.accel_sub_1, FP64_Add(speed, FP64_DivPrecise(natural_log, modesConst.r))); + FP_LONG integral = FP64_Mul(constants->accel_sub_1, FP64_Add(speed, FP64_DivPrecise(natural_log, constants->r))); // Not really an integral - speed = FP64_Add(FP64_DivPrecise(FP64_Sub(integral, modesConst.C0), speed), FP64_1); + speed = FP64_Add(FP64_DivPrecise(FP64_Sub(integral, constants->C0), speed), FP64_1); } - else if (speed <= g_Midpoint) + else if (speed <= midpoint) speed = FP64_1; else - speed = FP64_Add(FP64_DivPrecise(FP64_Mul(modesConst.accel_sub_1, FP64_Sub(speed, g_Midpoint)), speed), FP64_1); + speed = FP64_Add(FP64_DivPrecise(FP64_Mul(constants->accel_sub_1, FP64_Sub(speed, midpoint)), speed), FP64_1); } else { - if (modesConst.r != 0) - speed = FP64_Add(FP64_DivPrecise(modesConst.accel_sub_1, FP64_Add(FP64_1, D)), FP64_1); - else if (speed <= g_Midpoint) + if (constants->r != 0) + speed = FP64_Add(FP64_DivPrecise(constants->accel_sub_1, FP64_Add(FP64_1, D)), FP64_1); + else if (speed <= midpoint) speed = FP64_1; else - speed = FP64_Add(modesConst.accel_sub_1, FP64_1); + speed = FP64_Add(constants->accel_sub_1, FP64_1); } return speed; } -FP_LONG accel_natural(FP_LONG speed) { - if (speed <= g_Midpoint) { +FP_LONG accel_natural(const struct ModesConstants *constants, FP_LONG midpoint, bool use_smoothing, FP_LONG speed) { + if (speed <= midpoint) { speed = FP64_1; } else { - FP_LONG n_offset_x = FP64_Sub(g_Midpoint, speed); - FP_LONG decay = FP64_Exp(FP64_Mul(modesConst.auxiliar_accel, n_offset_x)); + FP_LONG n_offset_x = FP64_Sub(midpoint, speed); + FP_LONG decay = FP64_Exp(FP64_Mul(constants->auxiliar_accel, n_offset_x)); - if (g_UseSmoothing) { + if (use_smoothing) { FP_LONG decay_auxiliaraccel = - FP64_DivPrecise(decay, modesConst.auxiliar_accel); + FP64_DivPrecise(decay, constants->auxiliar_accel); FP_LONG numerator = FP64_Add( - FP64_Mul(modesConst.exp_sub_1, FP64_Sub(decay_auxiliaraccel, n_offset_x)), - modesConst.auxiliar_constant); + FP64_Mul(constants->exp_sub_1, FP64_Sub(decay_auxiliaraccel, n_offset_x)), + constants->auxiliar_constant); speed = FP64_Add(FP64_DivPrecise(numerator, speed), FP64_1); } else { speed = FP64_Add( - FP64_Mul(modesConst.exp_sub_1, (FP64_Sub( - FP64_1, FP64_DivPrecise(FP64_Sub(g_Midpoint, FP64_Mul(decay, n_offset_x)), speed)))), + FP64_Mul(constants->exp_sub_1, (FP64_Sub( + FP64_1, FP64_DivPrecise(FP64_Sub(midpoint, FP64_Mul(decay, n_offset_x)), speed)))), FP64_1); } } @@ -557,17 +544,17 @@ FP_LONG accel_natural(FP_LONG speed) { #define MIN(a,b) (((a)<(b))?(a):(b)) #endif -FP_LONG accel_lut(FP_LONG speed) { +FP_LONG accel_lut(unsigned long lut_pairs, const FP_LONG lut_data_x[MAX_LUT_ARRAY_SIZE], const FP_LONG lut_data_y[MAX_LUT_ARRAY_SIZE], FP_LONG speed) { // Assumes the size and values are valid. Please don't change LUT parameters by hand. - if(speed < g_LutData_x[0]) // Check if the speed is below the first given point - speed = g_LutData_y[0]; + if(speed < lut_data_x[0]) // Check if the speed is below the first given point + speed = lut_data_y[0]; else { - int l = 0, r = g_LutSize - 1, best_point = r, iter = 0; // We REALLY don't want an infinity loop in kernel + int l = 0, r = lut_pairs - 1, best_point = r, iter = 0; // We REALLY don't want an infinity loop in kernel while (l <= r && iter < 10) { int mid = (r + l) / 2; - if (speed > g_LutData_x[mid]) { + if (speed > lut_data_x[mid]) { l = mid + 1; } else { best_point = mid; @@ -577,14 +564,14 @@ FP_LONG accel_lut(FP_LONG speed) { iter++; } - int index = MIN(best_point-1, g_LutSize-2); + int index = MIN(best_point-1, lut_pairs-2); - FP_LONG p = g_LutData_y[index]; - FP_LONG p1 = g_LutData_y[index + 1]; + FP_LONG p = lut_data_y[index]; + FP_LONG p1 = lut_data_y[index + 1]; // denominator should not possibly ever be equal to 0 here... (we all know how this will end) - FP_LONG frac = FP64_DivPrecise(speed - g_LutData_x[index], - g_LutData_x[index + 1] - g_LutData_x[index]); + FP_LONG frac = FP64_DivPrecise(speed - lut_data_x[index], + lut_data_x[index + 1] - lut_data_x[index]); speed = FP64_Lerp(p, p1, frac); } diff --git a/driver/accel_modes.h b/driver/accel_modes.h index 799ef69..c893ff6 100644 --- a/driver/accel_modes.h +++ b/driver/accel_modes.h @@ -10,59 +10,10 @@ extern "C" { #endif #include #include "FixedMath/Fixed64.h" +#include "accel.h" +#include "../shared_definitions.h" -#define MAX_LUT_ARRAY_SIZE 128 -#define MAX_LUT_BUF_LEN 4096 - -struct ModesConstants { - bool is_init; - - // General - FP_LONG accel_sub_1; - FP_LONG exp_sub_1; - FP_LONG current_func_at_0; - - // Synchronous (legacy) - FP_LONG logMot; - FP_LONG gammaConst; - FP_LONG logSync; - FP_LONG sharpness; - FP_LONG sharpnessRecip; - bool useClamp; - FP_LONG minSens; - FP_LONG maxSens; - - // Classic - FP_LONG sign; - FP_LONG gain_constant; - FP_LONG cap_x; - FP_LONG cap_y; - - // Jump - FP_LONG C0; // the "integral" evaluated at 0 - FP_LONG r; // basically a smoothness factor - - // Power - FP_LONG offset_x; - FP_LONG power_constant; - - // Natural - FP_LONG auxiliar_accel; - FP_LONG auxiliar_constant; - - // Rotation - FP_LONG sin_a, cos_a; - - // Angle Snapping - FP_LONG as_sin, as_cos; - FP_LONG as_half_threshold; -}; - -extern FP_LONG g_Sensitivity, g_RatioYX, g_OutputCap, g_InputCap, g_Offset, g_PreScale, g_Acceleration, g_Exponent, - g_Midpoint, g_Motivity, g_RotationAngle, g_AngleSnap_Angle, g_AngleSnap_Threshold, g_LutData_x[], g_LutData_y[]; -extern char g_AccelerationMode, g_UseSmoothing; extern unsigned long g_LutSize; -extern struct ModesConstants modesConst; static const FP_LONG FP64_PI = C0NST_FP64_FromDouble(3.14159); static const FP_LONG FP64_PI_2 = C0NST_FP64_FromDouble(1.57079); static const FP_LONG FP64_PI_4 = C0NST_FP64_FromDouble(0.78539); @@ -75,16 +26,16 @@ static const FP_LONG FP64_100 = 100ll << FP64_Shift; static const FP_LONG FP64_1000 = 1000ll << FP64_Shift; static const FP_LONG FP64_10000 = 10000ll << FP64_Shift; -void update_constants(void); +void update_constants(struct accel_params *params, struct ModesConstants *constants); -FP_LONG accel_linear(FP_LONG speed); -FP_LONG accel_power(FP_LONG speed); -FP_LONG accel_classic(FP_LONG speed); -FP_LONG accel_motivity(FP_LONG speed); -FP_LONG accel_synchronous(FP_LONG speed); -FP_LONG accel_natural(FP_LONG speed); -FP_LONG accel_jump(FP_LONG speed); -FP_LONG accel_lut(FP_LONG speed); +FP_LONG accel_linear(const struct ModesConstants *constants, FP_LONG acceleration, bool use_smoothing, FP_LONG speed); +FP_LONG accel_power(const struct ModesConstants *constants, FP_LONG midpoint, FP_LONG acceleration, FP_LONG exponent, bool use_smoothing, FP_LONG speed); +FP_LONG accel_classic(const struct ModesConstants *constants, FP_LONG acceleration, bool use_smoothing, FP_LONG speed); +FP_LONG accel_motivity(const struct ModesConstants *constants, FP_LONG midpoint, FP_LONG speed); +FP_LONG accel_synchronous(const struct ModesConstants *constants, FP_LONG acceleration, bool use_smoothing, FP_LONG speed); +FP_LONG accel_natural(const struct ModesConstants *constants, FP_LONG midpoint, bool use_smoothing, FP_LONG speed); +FP_LONG accel_jump(const struct ModesConstants *constants, FP_LONG midpoint, bool use_smoothing, FP_LONG speed); +FP_LONG accel_lut(unsigned long lut_pairs, const FP_LONG lut_data_x[MAX_LUT_ARRAY_SIZE], const FP_LONG lut_data_y[MAX_LUT_ARRAY_SIZE], FP_LONG speed); #ifdef __cplusplus } diff --git a/driver/driver.c b/driver/driver.c index fe90b64..e9b9fb0 100644 --- a/driver/driver.c +++ b/driver/driver.c @@ -1,5 +1,13 @@ +#include "FixedMath/Fixed64.h" #include "accel.h" -#include "util.h" +#include "../shared_definitions.h" +#include "accel_modes.h" +#include "asm-generic/errno-base.h" +#include "linux/device.h" +#include "linux/device/class.h" +#include "linux/input.h" +#include "linux/mutex.h" +#include "linux/printk.h" #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include @@ -38,7 +46,6 @@ static struct device_attribute dev_attr_midpoint = __ATTR(midpoint, FILE static struct device_attribute dev_attr_motivity = __ATTR(motivity, FILE_PERMISSIONS, mouse_param_show, mouse_param_store); static struct device_attribute dev_attr_use_smoothing = __ATTR(use_smoothing, FILE_PERMISSIONS, mouse_param_show, mouse_param_store); -static struct device_attribute dev_attr_lut_size = __ATTR(lut_size, FILE_PERMISSIONS, mouse_param_show, mouse_param_store); static struct device_attribute dev_attr_lut_data = __ATTR(lut_data, FILE_PERMISSIONS, mouse_param_show, mouse_param_store); static struct device_attribute dev_attr_cc_data_aggregate = __ATTR(cc_data_aggregate, FILE_PERMISSIONS, mouse_param_show, mouse_param_store); @@ -61,7 +68,6 @@ static struct attribute *mouse_attrs[] = { &dev_attr_midpoint.attr, &dev_attr_motivity.attr, &dev_attr_use_smoothing.attr, - &dev_attr_lut_size.attr, &dev_attr_lut_data.attr, &dev_attr_cc_data_aggregate.attr, &dev_attr_rotation_angle.attr, @@ -70,12 +76,14 @@ static struct attribute *mouse_attrs[] = { NULL, }; +static struct class *yeetmouse_class; + static const struct attribute_group mouse_attr_group = { .name = "accel_config", .attrs = mouse_attrs, }; -static const struct attribute_group *mouse_groups[] = { +static const struct attribute_group *mouse_attr_groups[] = { &mouse_attr_group, NULL, }; @@ -83,7 +91,11 @@ static const struct attribute_group *mouse_groups[] = { struct mouse_state { int x; int y; - struct accel_params *params; + struct accel_runtime rt; + struct ModesConstants modes_consts; + struct accel_params __rcu *params; + struct mutex writer; + struct device *class_dev; }; #if __cleanup_events @@ -132,9 +144,13 @@ static void driver_events(struct input_handle *handle, const struct input_value if (x == NONE_EVENT_VALUE && y == NONE_EVENT_VALUE) goto unchanged_return; - // Get the accel params - struct accel_params *params = state->params; - error = accelerate(&x, &y); + struct accel_params *params; + + rcu_read_lock(); + params = rcu_dereference(state->params); + error = accelerate(params, &state->rt, &state->modes_consts, &x, &y); + rcu_read_unlock(); + /* Reset state */ state->x = NONE_EVENT_VALUE; state->y = NONE_EVENT_VALUE; @@ -260,77 +276,108 @@ static int input_register_handle_head(struct input_handle *handle) { return 0; } -static int driver_connect(struct input_handler *handler, struct input_dev *dev, const struct input_device_id *id) { +static int driver_connect(struct input_handler *handler, struct input_dev *dev, + const struct input_device_id *id) +{ struct input_handle *handle; - struct mouse_state *state; + struct mouse_state *state; struct accel_params *accel_config; int error; - handle = kzalloc(sizeof(struct input_handle), GFP_KERNEL); + handle = kzalloc(sizeof(*handle), GFP_KERNEL); if (!handle) return -ENOMEM; - state = kzalloc(sizeof(struct mouse_state), GFP_KERNEL); + state = kzalloc(sizeof(*state), GFP_KERNEL); if (!state) { - kfree(handle); - return -ENOMEM; + error = -ENOMEM; + goto err_free_handle; } + mutex_init(&state->writer); - accel_config = kzalloc(sizeof(struct accel_params), GFP_KERNEL); + accel_config = kzalloc(sizeof(*accel_config), GFP_KERNEL); if (!accel_config) { - kfree(handle); - kfree(state); - return -ENOMEM; + error = -ENOMEM; + goto err_free_state; } - state->params = accel_config; - input_set_drvdata(dev, state); + accel_config->acceleration_mode = 1; + accel_config->sensitivity = FP64_1; + accel_config->prescale = FP64_1; + accel_config->acceleration = FP64_1; + accel_config->ratio_yx = FP64_1; - error = sysfs_create_group(&dev->dev.kobj, &mouse_attr_group); - if (error) { - pr_err("Failed to create sysfs group: %d\n", error); - goto err_free_mem; - } + state->modes_consts.current_func_at_0 = FP64_1; + update_constants(accel_config, &state->modes_consts); + + rcu_assign_pointer(state->params, accel_config); state->x = NONE_EVENT_VALUE; state->y = NONE_EVENT_VALUE; + input_set_drvdata(dev, state); + + char safe_name[64]; + strscpy(safe_name, dev->name, sizeof(safe_name)); + // Replace spaces with underscores + for (char *p = safe_name; *p; p++) + if (*p == ' ') *p = '_'; + + state->class_dev = device_create_with_groups(yeetmouse_class, &dev->dev, + MKDEV(0, 0), state, + mouse_attr_groups, + "%s", safe_name); + + if (IS_ERR(state->class_dev)) { + error = PTR_ERR(state->class_dev); + goto err_clear_drvdata; + } + handle->private = state; - handle->dev = input_get_device(dev); + handle->dev = input_get_device(dev); handle->handler = handler; - handle->name = "yeetmouse"; + handle->name = "yeetmouse"; - /* WARN: Instead of `input_register_handle` we use a customized version of it here. - * This prepends the handler (like a filter) instead of appending it, making - * it take precedence over any other input handler that'll be added. */ error = input_register_handle_head(handle); if (error) - goto err_free_mem; + goto err_put_dev; error = input_open_device(handle); if (error) goto err_unregister_handle; - pr_info("connecting to device: %s (%s at %s)", dev_name(&dev->dev), dev->name ?: "unknown", - dev->phys ?: "unknown"); + pr_info("connecting to device: %s (%s at %s)", + dev_name(&dev->dev), dev->name ?: "unknown", dev->phys ?: "unknown"); return 0; err_unregister_handle: input_unregister_handle(handle); - -err_free_mem: - kfree(handle->private); +err_put_dev: + input_put_device(handle->dev); + device_unregister(state->class_dev); +err_clear_drvdata: + input_set_drvdata(dev, NULL); + kfree(accel_config); +err_free_state: + mutex_destroy(&state->writer); + kfree(state); +err_free_handle: kfree(handle); return error; } static void driver_disconnect(struct input_handle *handle) { + struct mouse_state *state = handle->private; + + device_unregister(state->class_dev); input_close_device(handle); input_unregister_handle(handle); - kfree(((struct mouse_state*)handle->private)->params); - kfree(handle->private); - sysfs_remove_group(&handle->dev->dev.kobj, &mouse_attr_group); + input_put_device(handle->dev); + + kfree_rcu(state->params, rcu); + mutex_destroy(&state->writer); + kfree(state); kfree(handle); } @@ -358,107 +405,209 @@ static ssize_t mouse_param_show(struct device *dev, struct device_attribute *att struct mouse_state *state = input_get_drvdata(idev); if (!state) return -ENODEV; - struct accel_params *params = state->params; + int ret; - if (attr == &dev_attr_acceleration_mode) - return sysfs_emit(buf, "%d\n", params->acceleration_mode); - if (attr == &dev_attr_input_cap) - return sysfs_emit(buf, "%lld\n", params->input_cap); - if (attr == &dev_attr_ratio_yx) - return sysfs_emit(buf, "%lld\n", params->ratio_yx); - if (attr == &dev_attr_output_cap) - return sysfs_emit(buf, "%lld\n", params->output_cap); - if (attr == &dev_attr_offset) - return sysfs_emit(buf, "%lld\n", params->offset); - if (attr == &dev_attr_prescale) - return sysfs_emit(buf, "%lld\n", params->prescale); - if (attr == &dev_attr_acceleration) - return sysfs_emit(buf, "%lld\n", params->acceleration); - if (attr == &dev_attr_sensitivity) - return sysfs_emit(buf, "%lld\n", params->sensitivity); - if (attr == &dev_attr_exponent) - return sysfs_emit(buf, "%lld\n", params->exponent); - if (attr == &dev_attr_midpoint) - return sysfs_emit(buf, "%lld\n", params->midpoint); - if (attr == &dev_attr_motivity) - return sysfs_emit(buf, "%lld\n", params->motivity); - if (attr == &dev_attr_use_smoothing) - return sysfs_emit(buf, "%d\n", params->use_smoothing); - if (attr == &dev_attr_lut_size) - return sysfs_emit(buf, "%lu\n", params->lut_size); - if (attr == &dev_attr_lut_data) - return sysfs_emit(buf, "%s\n", params->lut_data); - if (attr == &dev_attr_cc_data_aggregate) - return sysfs_emit(buf, "%s\n", params->cc_data_aggregate); - if (attr == &dev_attr_rotation_angle) - return sysfs_emit(buf, "%lld\n", params->rotation_angle); - if (attr == &dev_attr_angle_snap_threshold) - return sysfs_emit(buf, "%lld\n", params->angle_snap_threshold); - if (attr == &dev_attr_angle_snap_angle) - return sysfs_emit(buf, "%lld\n", params->angle_snap_angle); - return -EINVAL; + struct accel_params *params; + + rcu_read_lock(); + params = rcu_dereference(state->params); + // TODO + + if (attr == &dev_attr_acceleration_mode) { + ret = sysfs_emit(buf, "%d\n", params->acceleration_mode); + } else if (attr == &dev_attr_input_cap) { + ret = sysfs_emit(buf, "%lld\n", params->input_cap); + } else if (attr == &dev_attr_ratio_yx) { + ret = sysfs_emit(buf, "%lld\n", params->ratio_yx); + } else if (attr == &dev_attr_output_cap) { + ret = sysfs_emit(buf, "%lld\n", params->output_cap); + } else if (attr == &dev_attr_offset) { + ret = sysfs_emit(buf, "%lld\n", params->offset); + } else if (attr == &dev_attr_prescale) { + ret = sysfs_emit(buf, "%lld\n", params->prescale); + } else if (attr == &dev_attr_acceleration) { + ret = sysfs_emit(buf, "%lld\n", params->acceleration); + } else if (attr == &dev_attr_sensitivity) { + ret = sysfs_emit(buf, "%lld\n", params->sensitivity); + } else if (attr == &dev_attr_exponent) { + ret = sysfs_emit(buf, "%lld\n", params->exponent); + } else if (attr == &dev_attr_midpoint) { + ret = sysfs_emit(buf, "%lld\n", params->midpoint); + } else if (attr == &dev_attr_motivity) { + ret = sysfs_emit(buf, "%lld\n", params->motivity); + } else if (attr == &dev_attr_use_smoothing) { + ret = sysfs_emit(buf, "%d\n", params->use_smoothing); + } else if (attr == &dev_attr_lut_data) { + ret = sysfs_emit(buf, "%s\n", "TODO"); + // ret = sysfs_emit(buf, "%s\n", params->lut_data); + } else if (attr == &dev_attr_cc_data_aggregate) { + ret = sysfs_emit(buf, "%s\n", params->cc_data_aggregate); + } else if (attr == &dev_attr_rotation_angle) { + ret = sysfs_emit(buf, "%lld\n", params->rotation_angle); + } else if (attr == &dev_attr_angle_snap_threshold) { + ret = sysfs_emit(buf, "%lld\n", params->angle_snap_threshold); + } else if (attr == &dev_attr_angle_snap_angle) { + ret = sysfs_emit(buf, "%lld\n", params->angle_snap_angle); + } else { + ret = -EINVAL; + } + + rcu_read_unlock(); + + return ret; +} + +static int parse_lut_data(const char *buf, int count, struct accel_params* params) { + const char *p = buf; + const char *end = buf + count; + const size_t lut_max = ARRAY_SIZE(params->lut_data_x); // x and y are same size + int i = 0; + + while (p < end && *p && i < 2 * lut_max) { + FP_LONG val; + int consumed = FP64_FromString(p, &val); + + if (consumed <= 0 || consumed > (end - p)) + return -EINVAL; + + ((i % 2 == 0) ? params->lut_data_x + : params->lut_data_y)[i / 2] = val; + i++; + p += consumed; + + if (p == end) // buffer is empty + break; + if (*p == ';' || *p == ',') { + p++; + continue; + } + if (*p == '\0' || *p == '\n') + break; + + return -EINVAL; // unexpected separator + } + + // enforce that pairs are complete + if (i % 2 != 0) + return -EINVAL; + + params->lut_pairs = i / 2; + + return 0; +} + +static void validate_config(struct accel_params *cfg) +{ + if (cfg->lut_pairs <= 1 && + (cfg->acceleration_mode == AccelMode_Lut || + cfg->acceleration_mode == AccelMode_CustomCurve)) + cfg->acceleration_mode = AccelMode_Current; + + if (cfg->angle_snap_threshold >= FP64_PI || + cfg->angle_snap_threshold < 0) + cfg->angle_snap_threshold = 0; } static ssize_t mouse_param_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { + int ret; struct input_dev *idev = to_input_dev(dev); struct mouse_state *state = input_get_drvdata(idev); if (!state) return -ENODEV; - struct accel_params *data = state->params; + struct accel_params *new_config; + struct accel_params *old_config; + + new_config = kzalloc(sizeof(struct accel_params), GFP_KERNEL); + if (!new_config) { + return -ENOMEM; + } + + mutex_lock(&state->writer); + + old_config = rcu_dereference_protected(state->params, + lockdep_is_held(&state->writer)); + *new_config = *old_config; + long long val; - int ret; - ret = kstrtoll(buf, 10, &val); - if (ret) return ret; + if (attr != &dev_attr_lut_data && attr != &dev_attr_cc_data_aggregate) { + ret = kstrtoll(buf, 10, &val); + if (ret) + goto err_unlock; + } if (attr == &dev_attr_acceleration_mode) - data->acceleration_mode = val; + new_config->acceleration_mode = val; else if (attr == &dev_attr_input_cap) - data->input_cap = val; + new_config->input_cap = val; else if (attr == &dev_attr_ratio_yx) - data->ratio_yx = val; + new_config->ratio_yx = val; else if (attr == &dev_attr_output_cap) - data->output_cap = val; + new_config->output_cap = val; else if (attr == &dev_attr_offset) - data->offset = val; + new_config->offset = val; else if (attr == &dev_attr_prescale) - data->prescale = val; - else if (attr == &dev_attr_acceleration) - data->acceleration = val; + new_config->prescale = val; + else if (attr == &dev_attr_acceleration) { + new_config->acceleration = FP64_FromInt(val); + } else if (attr == &dev_attr_sensitivity) - data->sensitivity = val; + new_config->sensitivity = val; else if (attr == &dev_attr_exponent) - data->exponent = val; + new_config->exponent = val; else if (attr == &dev_attr_midpoint) - data->midpoint = val; + new_config->midpoint = val; else if (attr == &dev_attr_motivity) - data->motivity = val; + new_config->motivity = val; else if (attr == &dev_attr_use_smoothing) - data->use_smoothing = val; - else if (attr == &dev_attr_lut_size) - data->lut_size = val; + new_config->use_smoothing = val; else if (attr == &dev_attr_lut_data) { - // Call the parser + int res = parse_lut_data(buf, count, new_config); + if (res < 0) { + ret = res; + goto err_unlock; + } } else if (attr == &dev_attr_cc_data_aggregate) { // nop } else if (attr == &dev_attr_rotation_angle) - data->rotation_angle = val; + new_config->rotation_angle = val; else if (attr == &dev_attr_angle_snap_threshold) - data->angle_snap_threshold = val; + new_config->angle_snap_threshold = val; else if (attr == &dev_attr_angle_snap_angle) - data->angle_snap_angle = val; + new_config->angle_snap_angle = val; + + validate_config(new_config); + + // FIXME: modes_consts should also be protected by RCU + update_constants(new_config, &state->modes_consts); + + rcu_assign_pointer(state->params, new_config); + + mutex_unlock(&state->writer); + + kfree_rcu(old_config, rcu); return count; + +err_unlock: + mutex_unlock(&state->writer); + kfree(new_config); + return ret; } static int __init yeetmouse_init(void) { + yeetmouse_class = class_create("yeetmouse"); + if (IS_ERR(yeetmouse_class)) + return PTR_ERR(yeetmouse_class); + return input_register_handler(&driver_handler); } static void __exit yeetmouse_exit(void) { input_unregister_handler(&driver_handler); + class_destroy(yeetmouse_class); } MODULE_DESCRIPTION("USB HID input handler applying mouse acceleration (Yeetmouse)"); diff --git a/shared_definitions.h b/shared_definitions.h index 65d69ce..79282f1 100644 --- a/shared_definitions.h +++ b/shared_definitions.h @@ -2,6 +2,13 @@ #ifndef SHARED_DEFINITIONS_H #define SHARED_DEFINITIONS_H +#include +#include "driver/FixedMath/Fixed64.h" + +#define SYNC_START (-3) +#define SYNC_STOP (9) +#define SYNC_NUM (8) +#define SYNC_CAPACITY ((SYNC_STOP - SYNC_START) * SYNC_NUM + 1) enum AccelMode { AccelMode_Current = 0, // Mainly used in GUI, denotes lack of a curve on the driver side @@ -17,4 +24,52 @@ enum AccelMode { AccelMode_Count, }; +struct ModesConstants { + bool is_init; + + // General + FP_LONG accel_sub_1; + FP_LONG exp_sub_1; + FP_LONG current_func_at_0; + + // Synchronous (legacy) + FP_LONG logMot; + FP_LONG gammaConst; + FP_LONG logSync; + FP_LONG sharpness; + FP_LONG sharpnessRecip; + bool useClamp; + FP_LONG minSens; + FP_LONG maxSens; + + // Classic + FP_LONG sign; + FP_LONG gain_constant; + FP_LONG cap_x; + FP_LONG cap_y; + + // Jump + FP_LONG C0; // the "integral" evaluated at 0 + FP_LONG r; // basically a smoothness factor + + // Power + FP_LONG offset_x; + FP_LONG power_constant; + + // Natural + FP_LONG auxiliar_accel; + FP_LONG auxiliar_constant; + + // Rotation + FP_LONG sin_a, cos_a; + + // Angle Snapping + FP_LONG as_sin, as_cos; + FP_LONG as_half_threshold; + + bool lut_ready; // whether the synchronous smoothing LUT below is built + FP_LONG x_start; // 2^SYNC_START + FP_LONG data[SYNC_CAPACITY]; // monotonic over x +}; + #endif From 82a5336aee014b9e4e0de3360be1d23c07ca7458 Mon Sep 17 00:00:00 2001 From: Salman Abuhaimed Date: Thu, 23 Jul 2026 00:11:23 +0300 Subject: [PATCH 04/11] parse acceleration from and to string for store and show --- driver/driver.c | 136 ++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 115 insertions(+), 21 deletions(-) diff --git a/driver/driver.c b/driver/driver.c index e9b9fb0..e3769c3 100644 --- a/driver/driver.c +++ b/driver/driver.c @@ -426,7 +426,9 @@ static ssize_t mouse_param_show(struct device *dev, struct device_attribute *att } else if (attr == &dev_attr_prescale) { ret = sysfs_emit(buf, "%lld\n", params->prescale); } else if (attr == &dev_attr_acceleration) { - ret = sysfs_emit(buf, "%lld\n", params->acceleration); + char output[64]; + FP64_ToString(params->acceleration, output, 2); + ret = sysfs_emit(buf, "%s\n", output); } else if (attr == &dev_attr_sensitivity) { ret = sysfs_emit(buf, "%lld\n", params->sensitivity); } else if (attr == &dev_attr_exponent) { @@ -528,39 +530,110 @@ static ssize_t mouse_param_store(struct device *dev, struct device_attribute *at lockdep_is_held(&state->writer)); *new_config = *old_config; - long long val; - - if (attr != &dev_attr_lut_data && attr != &dev_attr_cc_data_aggregate) { + if (attr == &dev_attr_acceleration_mode) { + long long val; ret = kstrtoll(buf, 10, &val); - if (ret) + if (ret) { goto err_unlock; - } + } - if (attr == &dev_attr_acceleration_mode) new_config->acceleration_mode = val; - else if (attr == &dev_attr_input_cap) + } + else if (attr == &dev_attr_input_cap) { + long long val; + ret = kstrtoll(buf, 10, &val); + if (ret) { + goto err_unlock; + } + new_config->input_cap = val; - else if (attr == &dev_attr_ratio_yx) + } + else if (attr == &dev_attr_ratio_yx) { + long long val; + ret = kstrtoll(buf, 10, &val); + if (ret) { + goto err_unlock; + } + new_config->ratio_yx = val; - else if (attr == &dev_attr_output_cap) + } + else if (attr == &dev_attr_output_cap) { + long long val; + ret = kstrtoll(buf, 10, &val); + if (ret) { + goto err_unlock; + } + new_config->output_cap = val; - else if (attr == &dev_attr_offset) + } + else if (attr == &dev_attr_offset) { + long long val; + ret = kstrtoll(buf, 10, &val); + if (ret) { + goto err_unlock; + } + new_config->offset = val; - else if (attr == &dev_attr_prescale) + } + else if (attr == &dev_attr_prescale) { + long long val; + ret = kstrtoll(buf, 10, &val); + if (ret) { + goto err_unlock; + } + new_config->prescale = val; + } else if (attr == &dev_attr_acceleration) { - new_config->acceleration = FP64_FromInt(val); + FP_LONG val; + FP64_FromString(buf, &val); + new_config->acceleration = val; } - else if (attr == &dev_attr_sensitivity) + else if (attr == &dev_attr_sensitivity) { + long long val; + ret = kstrtoll(buf, 10, &val); + if (ret) { + goto err_unlock; + } + new_config->sensitivity = val; - else if (attr == &dev_attr_exponent) + } + else if (attr == &dev_attr_exponent) { + long long val; + ret = kstrtoll(buf, 10, &val); + if (ret) { + goto err_unlock; + } + new_config->exponent = val; - else if (attr == &dev_attr_midpoint) + } + else if (attr == &dev_attr_midpoint) { + long long val; + ret = kstrtoll(buf, 10, &val); + if (ret) { + goto err_unlock; + } + new_config->midpoint = val; - else if (attr == &dev_attr_motivity) + } + else if (attr == &dev_attr_motivity) { + long long val; + ret = kstrtoll(buf, 10, &val); + if (ret) { + goto err_unlock; + } + new_config->motivity = val; - else if (attr == &dev_attr_use_smoothing) + } + else if (attr == &dev_attr_use_smoothing) { + long long val; + ret = kstrtoll(buf, 10, &val); + if (ret) { + goto err_unlock; + } + new_config->use_smoothing = val; + } else if (attr == &dev_attr_lut_data) { int res = parse_lut_data(buf, count, new_config); if (res < 0) { @@ -571,12 +644,33 @@ static ssize_t mouse_param_store(struct device *dev, struct device_attribute *at else if (attr == &dev_attr_cc_data_aggregate) { // nop } - else if (attr == &dev_attr_rotation_angle) + else if (attr == &dev_attr_rotation_angle) { + long long val; + ret = kstrtoll(buf, 10, &val); + if (ret) { + goto err_unlock; + } + new_config->rotation_angle = val; - else if (attr == &dev_attr_angle_snap_threshold) + } + else if (attr == &dev_attr_angle_snap_threshold) { + long long val; + ret = kstrtoll(buf, 10, &val); + if (ret) { + goto err_unlock; + } + new_config->angle_snap_threshold = val; - else if (attr == &dev_attr_angle_snap_angle) + } + else if (attr == &dev_attr_angle_snap_angle) { + long long val; + ret = kstrtoll(buf, 10, &val); + if (ret) { + goto err_unlock; + } + new_config->angle_snap_angle = val; + } validate_config(new_config); From b869f51de7b334bb26c1597943eb5b8597dff74b Mon Sep 17 00:00:00 2001 From: AndyFilter Date: Sat, 25 Jul 2026 22:38:17 +0200 Subject: [PATCH 05/11] Clean up driver headers and move ModesConstants to accel.h --- driver/FixedMath/Fixed64.h | 2 +- driver/FixedMath/FixedUtil.h | 2 -- driver/accel.h | 50 +++++++++++++++++++++++++++++++++-- driver/accel_modes.h | 1 - shared_definitions.h | 51 ------------------------------------ tests/config.h | 6 +++++ 6 files changed, 55 insertions(+), 57 deletions(-) diff --git a/driver/FixedMath/Fixed64.h b/driver/FixedMath/Fixed64.h index b8238e5..38091a7 100644 --- a/driver/FixedMath/Fixed64.h +++ b/driver/FixedMath/Fixed64.h @@ -33,8 +33,8 @@ // Include numeric types #include -#include "FixedUtil.h" #include +#include "FixedUtil.h" // If FP_ASSERT is not custom-defined, then use the standard one diff --git a/driver/FixedMath/FixedUtil.h b/driver/FixedMath/FixedUtil.h index d3267d5..64f2995 100644 --- a/driver/FixedMath/FixedUtil.h +++ b/driver/FixedMath/FixedUtil.h @@ -34,8 +34,6 @@ // Include numeric types #include -#include - // If FP_ASSERT is not custom-defined, then use the standard one //#ifndef FP_ASSERT //# include diff --git a/driver/accel.h b/driver/accel.h index 9f521ce..744f64e 100644 --- a/driver/accel.h +++ b/driver/accel.h @@ -1,7 +1,5 @@ #ifndef _ACCEL_H #define _ACCEL_H -#include -#include #include "FixedMath/Fixed64.h" #include "../shared_definitions.h" @@ -38,6 +36,54 @@ struct accel_params { FP_LONG angle_snap_angle; }; +struct ModesConstants { + bool is_init; + + // General + FP_LONG accel_sub_1; + FP_LONG exp_sub_1; + FP_LONG current_func_at_0; + + // Synchronous (legacy) + FP_LONG logMot; + FP_LONG gammaConst; + FP_LONG logSync; + FP_LONG sharpness; + FP_LONG sharpnessRecip; + bool useClamp; + FP_LONG minSens; + FP_LONG maxSens; + + // Classic + FP_LONG sign; + FP_LONG gain_constant; + FP_LONG cap_x; + FP_LONG cap_y; + + // Jump + FP_LONG C0; // the "integral" evaluated at 0 + FP_LONG r; // basically a smoothness factor + + // Power + FP_LONG offset_x; + FP_LONG power_constant; + + // Natural + FP_LONG auxiliar_accel; + FP_LONG auxiliar_constant; + + // Rotation + FP_LONG sin_a, cos_a; + + // Angle Snapping + FP_LONG as_sin, as_cos; + FP_LONG as_half_threshold; + + bool lut_ready; // whether the synchronous smoothing LUT below is built + FP_LONG x_start; // 2^SYNC_START + FP_LONG data[SYNC_CAPACITY]; // monotonic over x +}; + int accelerate(const struct accel_params * params, struct accel_runtime *rt, const struct ModesConstants *constants, int *x, int *y); #endif /* _ACCEL_H */ diff --git a/driver/accel_modes.h b/driver/accel_modes.h index c893ff6..1fb25dd 100644 --- a/driver/accel_modes.h +++ b/driver/accel_modes.h @@ -11,7 +11,6 @@ extern "C" { #include #include "FixedMath/Fixed64.h" #include "accel.h" -#include "../shared_definitions.h" extern unsigned long g_LutSize; static const FP_LONG FP64_PI = C0NST_FP64_FromDouble(3.14159); diff --git a/shared_definitions.h b/shared_definitions.h index 79282f1..951f317 100644 --- a/shared_definitions.h +++ b/shared_definitions.h @@ -2,8 +2,6 @@ #ifndef SHARED_DEFINITIONS_H #define SHARED_DEFINITIONS_H -#include -#include "driver/FixedMath/Fixed64.h" #define SYNC_START (-3) #define SYNC_STOP (9) @@ -23,53 +21,4 @@ enum AccelMode { AccelMode_CustomCurve = 9, AccelMode_Count, }; - -struct ModesConstants { - bool is_init; - - // General - FP_LONG accel_sub_1; - FP_LONG exp_sub_1; - FP_LONG current_func_at_0; - - // Synchronous (legacy) - FP_LONG logMot; - FP_LONG gammaConst; - FP_LONG logSync; - FP_LONG sharpness; - FP_LONG sharpnessRecip; - bool useClamp; - FP_LONG minSens; - FP_LONG maxSens; - - // Classic - FP_LONG sign; - FP_LONG gain_constant; - FP_LONG cap_x; - FP_LONG cap_y; - - // Jump - FP_LONG C0; // the "integral" evaluated at 0 - FP_LONG r; // basically a smoothness factor - - // Power - FP_LONG offset_x; - FP_LONG power_constant; - - // Natural - FP_LONG auxiliar_accel; - FP_LONG auxiliar_constant; - - // Rotation - FP_LONG sin_a, cos_a; - - // Angle Snapping - FP_LONG as_sin, as_cos; - FP_LONG as_half_threshold; - - bool lut_ready; // whether the synchronous smoothing LUT below is built - FP_LONG x_start; // 2^SYNC_START - FP_LONG data[SYNC_CAPACITY]; // monotonic over x -}; - #endif diff --git a/tests/config.h b/tests/config.h index 7b6536b..0c25562 100644 --- a/tests/config.h +++ b/tests/config.h @@ -15,6 +15,12 @@ extern "C" { #include #include #define printk printf +#define ktime_t signed long long +struct callback_head { + struct callback_head *next; + void (*func)(struct callback_head *head); +} __attribute__((aligned(sizeof(void *)))); +#define rcu_head callback_head #include static float FP64_ToFloat(FP_LONG v) { From 91d4ba5b69c75e712ac940381d595af28eae1441 Mon Sep 17 00:00:00 2001 From: Salman Abuhaimed Date: Fri, 24 Jul 2026 01:30:57 +0300 Subject: [PATCH 06/11] add per-device selection to GUI --- driver/accel.c | 6 - driver/driver.c | 7 + gui/DriverHelper.cpp | 280 ++++++++++++++++-------------------- gui/DriverHelper.h | 45 ++++-- gui/main.cpp | 140 +++++++++++++----- tools/yeetmousectl/main.cpp | 72 ++++++++-- 6 files changed, 330 insertions(+), 220 deletions(-) diff --git a/driver/accel.c b/driver/accel.c index 31ba949..c6f4eac 100644 --- a/driver/accel.c +++ b/driver/accel.c @@ -91,12 +91,6 @@ unsigned long atoul(const char *str); #define PARAM_UPDATE(param) (FP64_FromString(g_param_##param, &g_##param)) #define PARAM_UPDATE_UL(param) (atoul(g_param_##param)) -// Aggregate values that don't change with speed to save on calculations done every irq -struct ModesConstants modesConst = { - .is_init = false, .C0 = 0, .r = 0, .auxiliar_accel = 0, .auxiliar_constant = 0, .accel_sub_1 = 0, .exp_sub_1 = 0, - .sin_a = 0, .cos_a = 0, .as_cos = 0, .as_sin = 0, .as_half_threshold = 0, .current_func_at_0 = FP64_1 -}; - // Acceleration happens here int accelerate(const struct accel_params * params, struct accel_runtime *rt, const struct ModesConstants *constants, int *x, int *y) { diff --git a/driver/driver.c b/driver/driver.c index e3769c3..ca75abd 100644 --- a/driver/driver.c +++ b/driver/driver.c @@ -643,6 +643,13 @@ static ssize_t mouse_param_store(struct device *dev, struct device_attribute *at } else if (attr == &dev_attr_cc_data_aggregate) { // nop + // // The driver never interprets the curve, it only hands it back to the GUI, + // // which sends the sampled result along as a LUT + // if (strscpy(new_config->cc_data_aggregate, buf, + // sizeof(new_config->cc_data_aggregate)) < 0) { + // ret = -E2BIG; + // goto err_unlock; + // } } else if (attr == &dev_attr_rotation_angle) { long long val; diff --git a/gui/DriverHelper.cpp b/gui/DriverHelper.cpp index c4f9c9e..6e883f2 100644 --- a/gui/DriverHelper.cpp +++ b/gui/DriverHelper.cpp @@ -4,180 +4,157 @@ #include #include #include +#include #include #include #include #include +#include #include #include #include template -static bool GetParameterTy(const std::string ¶m_name, Ty &value) { +static bool GetParameterTy(const std::string &path, Ty &value) { try { using namespace std; - ifstream file(YEETMOUSE_PARAMS_DIR + param_name); + ifstream file(path); - if (file.bad()) + if (!(file >> value)) { + fprintf(stderr, "Error when reading parameter %s (%s)\n", path.c_str(), strerror(errno)); return false; + } - file >> value; - file.close(); return true; } catch (std::exception &ex) { - fprintf(stderr, "Error when reading parameter %s (%s)\n", param_name.c_str(), ex.what()); + fprintf(stderr, "Error when reading parameter %s (%s)\n", path.c_str(), ex.what()); return false; } } -static bool GetParameterTy(const std::string ¶m_name, std::string &value) { +static bool GetParameterTy(const std::string &path, std::string &value) { try { using namespace std; - ifstream file(YEETMOUSE_PARAMS_DIR + param_name); + ifstream file(path); - if (file.bad() || file.fail()) + if (!file.is_open()) { + fprintf(stderr, "Error when reading parameter %s (%s)\n", path.c_str(), strerror(errno)); return false; + } std::stringstream ss; ss << file.rdbuf(); value = ss.str(); - file.close(); return true; } catch (std::exception &ex) { - fprintf(stderr, "Error when reading parameter %s (%s)\n", param_name.c_str(), ex.what()); + fprintf(stderr, "Error when reading parameter %s (%s)\n", path.c_str(), ex.what()); return false; } } template -bool SetParameterTy(const std::string ¶m_name, Ty value) { +static bool SetParameterTy(const std::string &path, Ty value) { try { using namespace std; - ofstream file(YEETMOUSE_PARAMS_DIR + param_name); - - if (file.bad()) - return false; + ofstream file(path); + // The driver rejects malformed values, which only shows up when the stream is flushed file << value; file.close(); + + if (file.fail()) { + fprintf(stderr, "Error when saving parameter %s (%s)\n", path.c_str(), strerror(errno)); + return false; + } + return true; } catch (std::exception &ex) { - fprintf(stderr, "Error when saving parameter %s (%s)\n", param_name.c_str(), ex.what()); + fprintf(stderr, "Error when saving parameter %s (%s)\n", path.c_str(), ex.what()); return false; } } namespace DriverHelper { - bool GetParameterF(const std::string ¶m_name, float &value) { - return GetParameterTy(param_name, value); - } - - bool GetParameterI(const std::string ¶m_name, int &value) { - return GetParameterTy(param_name, value); - } - - bool GetParameterB(const std::string ¶m_name, bool &value) { - int temp = 0; - bool res = GetParameterTy(param_name, temp); - value = temp == 1; - return res; - } - - bool GetParameterS(const std::string ¶m_name, std::string &value) { - return GetParameterTy(param_name, value); - } - - bool CleanParameters(int &fixed_num) { + std::vector DiscoverDevices() { namespace fs = std::filesystem; - for (const auto &entry: fs::directory_iterator(YEETMOUSE_PARAMS_DIR)) { - std::string str; - std::ifstream t(entry.path()); - if (!t.is_open() || t.bad() || t.fail()) - return false; - std::stringstream buffer; - buffer << t.rdbuf(); - str = buffer.str(); - //printf("param at %s = %s\n", entry.path().c_str(), str.c_str()); - - //std::streampos size = t.tellg(); - //std::cout << "pos = " << size << std::endl; - //t.clear(); - //t.seekp(0); - // I assume this is enough to not leave behind some parts of the old values if the new ones are shorter - t.close(); - - try { - // Integer written with FP64_Shift - if (size_t bracket_pos = str.find('('), ll_pos = str.find("ll"); - str.find("<< 32") != std::string::npos && bracket_pos != std::string::npos && ll_pos != - std::string::npos) { - fixed_num++; - std::ofstream o(entry.path()); - if (!o.is_open() || o.bad() || o.fail()) - return false; - std::string int_str = str.substr(bracket_pos + 1, ll_pos - bracket_pos - 1); - //printf("Clean param: %s\n", int_str.c_str()); - o.write(int_str.c_str(), int_str.size()); - o.close(); - } else if (ll_pos != std::string::npos) { - // Floating point represented as a long long - fixed_num++; - size_t start_offset = bracket_pos == std::string::npos ? 0 : (bracket_pos + 1); - std::ofstream o(entry.path()); - if (!o.is_open() || o.bad() || o.fail()) - return false; - std::string int_str = str.substr(start_offset, ll_pos - start_offset); - FP_LONG fp_val = std::stoll(int_str); - char buf[24]; - FP64_ToString(fp_val, buf, 6); - //printf("Clean param: %s, which is %s\n", int_str.c_str(), buf); - o.write(buf, strlen(buf)); - o.close(); - } else { - // Anything else is either 0 or not meant to be a floating point - //printf("Wrong format \\;\n"); - } - } catch (const std::exception &ex) { - fprintf(stderr, "Error parsing parameter %s!\n", entry.path().filename().c_str()); - return false; + std::vector devices; + std::error_code ec; + + // The class directory only exists while the driver is loaded + fs::directory_iterator it(YEETMOUSE_CLASS_DIR, fs::directory_options::skip_permission_denied, ec); + if (ec) + return devices; + + for (const auto &entry: it) { + // Every entry is a symlink to the input device, holding the parameter group + auto params_dir = entry.path() / YEETMOUSE_DEVICE_PARAMS_SUBDIR; + if (!fs::is_directory(params_dir, ec)) + continue; + + Device device; + device.sysfs_name = entry.path().filename().string(); + device.params_dir = params_dir.string() + "/"; + + // The driver had to mangle the name to use it as a directory, so read the original one back + std::ifstream name_file(entry.path() / "device" / "name"); + if (!std::getline(name_file, device.name) || device.name.empty()) { + device.name = device.sysfs_name; + std::replace(device.name.begin(), device.name.end(), '_', ' '); } + + // Every parameter of a device shares the same permissions, so one of them is enough to test + const std::string probe = device.params_dir + "acceleration_mode"; + device.readable = access(probe.c_str(), R_OK) == 0; + device.writable = access(probe.c_str(), W_OK) == 0; + + devices.push_back(std::move(device)); } - // Save the new (clean) parameters. Nothing should change, it just looks nicer. - SaveParameters(); + // Keep the order stable, the directory iteration order isn't + std::sort(devices.begin(), devices.end(), + [](const Device &a, const Device &b) { return a.name < b.name; }); - return true; + return devices; } - bool SaveParameters() { - return SetParameterTy("update", 1); + bool GetParameterF(const std::string ¶ms_dir, const std::string ¶m_name, float &value) { + return GetParameterTy(params_dir + param_name, value); } - bool SavePersistentParameters() { - return std::system("pkexec /usr/bin/yeetmousectl save /etc/yeetmouse.conf") == 0; + bool GetParameterI(const std::string ¶ms_dir, const std::string ¶m_name, int &value) { + return GetParameterTy(params_dir + param_name, value); } - bool WriteParameterF(const std::string ¶m_name, float value) { - return SetParameterTy(param_name, value); + bool GetParameterB(const std::string ¶ms_dir, const std::string ¶m_name, bool &value) { + int temp = 0; + bool res = GetParameterTy(params_dir + param_name, temp); + value = temp == 1; + return res; } - bool WriteParameterI(const std::string ¶m_name, float value) { - return SetParameterTy(param_name, value); + bool GetParameterS(const std::string ¶ms_dir, const std::string ¶m_name, std::string &value) { + return GetParameterTy(params_dir + param_name, value); + } + + bool SavePersistentParameters(const Device &device) { + // Device names come straight out of the USB descriptors, so quote them before handing + // the name to a shell + std::string quoted_name = "'"; + for (char c: device.sysfs_name) + quoted_name += (c == '\'') ? "'\\''" : std::string(1, c); + quoted_name += "'"; + + const std::string cmd = "pkexec /usr/bin/yeetmousectl save /etc/yeetmouse.conf " + quoted_name; + return std::system(cmd.c_str()) == 0; } bool ValidateDirectory() { namespace fs = std::filesystem; - try { - auto dir = fs::directory_entry(YEETMOUSE_PARAMS_DIR); - if (!dir.exists()) - return false; - } catch (std::exception &ex) { - return false; - } + std::error_code ec; - return true; + return fs::is_directory(YEETMOUSE_CLASS_DIR, ec); } size_t ParseUserLutData(char *szUser_data, double *out_x, double *out_y, size_t out_size) { @@ -304,38 +281,38 @@ namespace DriverHelper { return idx / 2; } - bool ParseAllParameters(Parameters ¶ms, char *lutUserData) { + bool ParseAllParameters(const std::string ¶ms_dir, Parameters ¶ms, char *lutUserData) { bool res = true; - - res &= GetParameterF("Sensitivity", params.sens); - res &= GetParameterF("RatioYX", params.ratioYX); - res &= GetParameterF("OutputCap", params.outCap); - res &= GetParameterF("InputCap", params.inCap); - res &= GetParameterF("Offset", params.offset); - res &= GetParameterF("Acceleration", params.accel); - res &= GetParameterF("Exponent", params.exponent); - res &= GetParameterF("Midpoint", params.midpoint); - res &= GetParameterF("Motivity", params.motivity); - res &= GetParameterF("PreScale", params.preScale); + + res &= GetParameterF(params_dir, "sensitivity", params.sens); + res &= GetParameterF(params_dir, "ratio_yx", params.ratioYX); + res &= GetParameterF(params_dir, "output_cap", params.outCap); + res &= GetParameterF(params_dir, "input_cap", params.inCap); + res &= GetParameterF(params_dir, "offset", params.offset); + res &= GetParameterF(params_dir, "acceleration", params.accel); + res &= GetParameterF(params_dir, "exponent", params.exponent); + res &= GetParameterF(params_dir, "midpoint", params.midpoint); + res &= GetParameterF(params_dir, "motivity", params.motivity); + res &= GetParameterF(params_dir, "prescale", params.preScale); int accelMode{}; - res &= GetParameterI("AccelerationMode", accelMode); + res &= GetParameterI(params_dir, "acceleration_mode", accelMode); params.accelMode = static_cast(accelMode); - res &= GetParameterB("UseSmoothing", params.useSmoothing); - res &= GetParameterI("LutSize", params.lutSize); - res &= GetParameterF("RotationAngle", params.rotation); + res &= GetParameterB(params_dir, "use_smoothing", params.useSmoothing); + res &= GetParameterF(params_dir, "rotation_angle", params.rotation); params.rotation /= DEG2RAD; - res &= GetParameterF("AngleSnap_Threshold", params.asThreshold); + res &= GetParameterF(params_dir, "angle_snap_threshold", params.asThreshold); params.asThreshold /= DEG2RAD; - res &= GetParameterF("AngleSnap_Angle", params.asAngle); + res &= GetParameterF(params_dir, "angle_snap_angle", params.asAngle); params.asAngle /= DEG2RAD; std::string Lut_dataBuf; - res &= GetParameterS("LutDataBuf", Lut_dataBuf); + res &= GetParameterS(params_dir, "lut_data", Lut_dataBuf); Lut_dataBuf.copy(lutUserData, MAX_LUT_BUF_LEN-1, 0); - ParseDriverLutData(Lut_dataBuf.c_str(), params.lutDataX, params.lutDataY); + // The driver only stores the pairs themselves, the count comes back out of the data + params.lutSize = ParseDriverLutData(Lut_dataBuf.c_str(), params.lutDataX, params.lutDataY); // Load custom curve data Lut_dataBuf.clear(); - if (res &= GetParameterS("_CustomCurveDataAggregate", Lut_dataBuf)) { + if (res &= GetParameterS(params_dir, "cc_data_aggregate", Lut_dataBuf)) { CustomCurve dummy_curve; if (!dummy_curve.ImportCustomCurve(Lut_dataBuf) && params.accelMode == AccelMode_CustomCurve) { fprintf(stderr, "Could not load custom curve data\n"); @@ -352,7 +329,7 @@ namespace DriverHelper { return res; } - std::string EncodeLutData(double *data_x, double *data_y, size_t size, bool strict_format) { + std::string EncodeLutData(const double *data_x, const double *data_y, size_t size, bool strict_format) { std::stringstream res; res << std::setprecision(LUT_EXPORT_PRECISION); @@ -371,49 +348,44 @@ namespace DriverHelper { // midpoint(midpoint), scrollAccel(scrollAccel), // accelMode(accelMode) {} -bool Parameters::SaveAll(bool auto_update) { +bool Parameters::SaveAll(const std::string ¶ms_dir) const { bool res = true; // LUT auto encodedLutData = DriverHelper::EncodeLutData(lutDataX, lutDataY, lutSize); if (!encodedLutData.empty() && encodedLutData.size() < MAX_LUT_BUF_LEN) { - res &= SetParameterTy("LutSize", lutSize); - //res &= SetParameterTy("LutStride", LUT_stride); - //printf("encoded: %s, size: %zu, stride: %i\n", encoded.c_str(), LUT_size, LUT_stride); - res &= SetParameterTy("LutDataBuf", encodedLutData); + res &= SetParameterTy(params_dir + "lut_data", encodedLutData); } else if (accelMode == AccelMode_Lut || accelMode == AccelMode_CustomCurve) return false; // Custom Curve auto encodedCCData = customCurve.ExportCustomCurve(); if (!encodedCCData.empty() && encodedCCData.size() < MAX_LUT_BUF_LEN) { - res &= SetParameterTy("_CustomCurveDataAggregate", encodedCCData); + res &= SetParameterTy(params_dir + "cc_data_aggregate", encodedCCData); } else if (accelMode == AccelMode_CustomCurve) return false; // General - res &= SetParameterTy("Sensitivity", sens); - res &= SetParameterTy("RatioYX", useAnisotropy ? ratioYX : 1); - res &= SetParameterTy("OutputCap", outCap); - res &= SetParameterTy("InputCap", inCap); - res &= SetParameterTy("Offset", offset); - res &= SetParameterTy("RotationAngle", rotation * DEG2RAD); - res &= SetParameterTy("AngleSnap_Threshold", asThreshold * DEG2RAD); - res &= SetParameterTy("AngleSnap_Angle", asAngle * DEG2RAD); + res &= SetParameterTy(params_dir + "sensitivity", sens); + res &= SetParameterTy(params_dir + "ratio_yx", useAnisotropy ? ratioYX : 1); + res &= SetParameterTy(params_dir + "output_cap", outCap); + res &= SetParameterTy(params_dir + "input_cap", inCap); + res &= SetParameterTy(params_dir + "offset", offset); + res &= SetParameterTy(params_dir + "rotation_angle", rotation * DEG2RAD); + res &= SetParameterTy(params_dir + "angle_snap_threshold", asThreshold * DEG2RAD); + res &= SetParameterTy(params_dir + "angle_snap_angle", asAngle * DEG2RAD); // Specific - res &= SetParameterTy("Acceleration", accel); - res &= SetParameterTy("Exponent", exponent); - res &= SetParameterTy("Midpoint", midpoint); - res &= SetParameterTy("Motivity", motivity); - res &= SetParameterTy("PreScale", preScale); - res &= SetParameterTy("UseSmoothing", useSmoothing); - - res &= SetParameterTy("AccelerationMode", accelMode); - - if (res && auto_update) - res &= DriverHelper::SaveParameters(); + res &= SetParameterTy(params_dir + "acceleration", accel); + res &= SetParameterTy(params_dir + "exponent", exponent); + res &= SetParameterTy(params_dir + "midpoint", midpoint); + res &= SetParameterTy(params_dir + "motivity", motivity); + res &= SetParameterTy(params_dir + "prescale", preScale); + res &= SetParameterTy(params_dir + "use_smoothing", useSmoothing); + + // Written last, the driver falls back to the current mode if the curve it needs is missing + res &= SetParameterTy(params_dir + "acceleration_mode", accelMode); return res; } diff --git a/gui/DriverHelper.h b/gui/DriverHelper.h index 228fb68..de91d68 100644 --- a/gui/DriverHelper.h +++ b/gui/DriverHelper.h @@ -3,6 +3,7 @@ #include #include +#include #include #include @@ -11,6 +12,9 @@ #define YEETMOUSE_PARAMS_DIR "/sys/module/yeetmouse/parameters/" +#define YEETMOUSE_CLASS_DIR "/sys/class/yeetmouse/" +#define YEETMOUSE_DEVICE_PARAMS_SUBDIR "accel_config" + #define MAX_LUT_ARRAY_SIZE 128 // THIS NEEDS TO BE THE SAME AS IN THE DRIVER CODE #define MAX_LUT_BUF_LEN 4096 #define LUT_EXPORT_PRECISION 5 // Decimal points precision for exporting a LUT @@ -19,34 +23,44 @@ struct Parameters; +struct Device { + std::string sysfs_name; // Directory name under YEETMOUSE_CLASS_DIR (device name with spaces replaced by '_') + std::string name; // Name as reported by the input device, meant to be displayed to the user + std::string params_dir; // Absolute path of the device's parameter directory (with a trailing '/') + bool readable = false; // Whether the parameters can be read (requires the 'yeetmouse' group) + bool writable = false; // Whether the parameters can be written to +}; + namespace DriverHelper { - bool GetParameterF(const std::string ¶m_name, float &value); - bool GetParameterI(const std::string ¶m_name, int &value); - bool GetParameterB(const std::string ¶m_name, bool &value); - bool GetParameterS(const std::string ¶m_name, std::string &value); + /// Lists every mouse the driver is currently attached to, sorted by name. + /// Returns an empty vector when the driver isn't loaded. + std::vector DiscoverDevices(); - bool WriteParameterF(const std::string ¶m_name, float value); - bool WriteParameterI(const std::string ¶m_name, float value); + /// Every parameter is read from and written to `params_dir` of the device it belongs to. + /// The driver applies a parameter as soon as it is written, no separate update is needed. + bool GetParameterF(const std::string ¶ms_dir, const std::string ¶m_name, float &value); + bool GetParameterI(const std::string ¶ms_dir, const std::string ¶m_name, int &value); + bool GetParameterB(const std::string ¶ms_dir, const std::string ¶m_name, bool &value); + bool GetParameterS(const std::string ¶ms_dir, const std::string ¶m_name, std::string &value); - bool SaveParameters(); + bool WriteParameterF(const std::string ¶ms_dir, const std::string ¶m_name, float value); + bool WriteParameterI(const std::string ¶ms_dir, const std::string ¶m_name, float value); - bool SavePersistentParameters(); + /// Stores the driver configuration of `device` in /etc/yeetmouse.conf, asks for root privileges + bool SavePersistentParameters(const Device &device); bool ValidateDirectory(); - /// Converts the ugly FP64 representation of user parameters to nice floating point values - bool CleanParameters(int &fixed_num); - /// Returns the number of parsed values size_t ParseUserLutData(char *user_data, double *out_x, double *out_y, size_t out_size); /// Returns the number of parsed values size_t ParseDriverLutData(const char *user_data, double *out_x, double *out_y); - /// Reads all driver parameters - bool ParseAllParameters(Parameters& params, char *lutUserData); + /// Reads all parameters of a single device + bool ParseAllParameters(const std::string ¶ms_dir, Parameters& params, char *lutUserData); - std::string EncodeLutData(double *data_x, double *data_y, size_t size, bool strict_format = true); + std::string EncodeLutData(const double *data_x, const double *data_y, size_t size, bool strict_format = true); } // DriverHelper inline std::string AccelMode2String(AccelMode mode) { @@ -223,7 +237,8 @@ struct Parameters { //Parameters(float sens, float sensCap, float speedCap, float offset, float accel, float exponent, float midpoint, // float scrollAccel, int accelMode); - bool SaveAll(bool auto_update = true); + /// Writes every parameter to a single device, applied by the driver as they are written + bool SaveAll(const std::string ¶ms_dir) const; }; #endif //YEETMOUSE_DRIVERHELPER_H diff --git a/gui/main.cpp b/gui/main.cpp index 1d09b03..02ad7c0 100644 --- a/gui/main.cpp +++ b/gui/main.cpp @@ -9,6 +9,7 @@ #include "ConfigHelper.h" #include #include +#include #include #include #include @@ -43,13 +44,24 @@ bool has_privilege = false; static char LUT_user_data[MAX_LUT_BUF_LEN]; +Device active_device; // The device every parameter below is read from and written to + void ResetParameters(); void ApplyImportedParameters(Parameters cur_params[NUM_MODES], const Parameters& imported_params); void DroppedFilesCallback(GLFWwindow* window, int path_count, const char* paths[]); +static bool SelectDevice(const Device &device); + +/// Re-reads the device list and returns the index the selection should move to. Mice come and go +/// while the GUI is running, so the active device is looked up by name instead of by index. +static int RefreshDevices(std::vector &devices) { + devices = DriverHelper::DiscoverDevices(); -#define RefreshDevices() {devices = DriverHelper::DiscoverDevices(); \ - if(selected_device >= devices.size()) \ - selected_device = devices.size() - 1;} + for (int i = 0; i < (int) devices.size(); i++) + if (devices[i].sysfs_name == active_device.sysfs_name) + return i; + + return devices.empty() ? -1 : 0; +} static int OnGui() { using namespace std::chrono; @@ -122,11 +134,70 @@ static int OnGui() { /* ---------------------------- LEFT MODES WINDOW ---------------------------- */ ImGui::SetNextWindowSizeConstraints({220, 0}, {FLT_MAX, FLT_MAX}); ImGui::PushStyleColor(ImGuiCol_FrameBg, ImVec4(0.1f, 0.1f, 0.1f, 1.0f)); - if (ImGui::BeginChild("Modes", ImVec2(220, 0), ImGuiChildFlags_FrameStyle)) { + if (ImGui::BeginChild("Devices and modes", ImVec2(220, 0), ImGuiChildFlags_FrameStyle)) { ImGui::PopStyleColor(); ImGui::Spacing(); ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, {12, 12}); ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, {12, 12}); + + static int selected_device = -1; + static std::vector devices; + // Enabling a device per se isn't supported by the driver yet, so this is only a GUI state for now. + // Keyed by the sysfs name, so it survives devices being (un)plugged. + static std::map enabled_devices; + static steady_clock::time_point last_devices_refresh; + + // Scanning sysfs every frame would be wasteful + if (steady_clock::now() - last_devices_refresh >= 1s) { + selected_device = RefreshDevices(devices); + last_devices_refresh = steady_clock::now(); + + if (selected_device < 0) + has_privilege = false; + else if (devices[selected_device].sysfs_name != active_device.sysfs_name) + SelectDevice(devices[selected_device]); // Our device is gone, follow the driver + else + has_privilege = devices[selected_device].writable; + } + + // Device selection + ImGui::SeparatorText("Device"); + ImGui::SetNextItemWidth(-1); + ImGui::BeginDisabled(devices.empty()); + if (ImGui::BeginCombo("##Select device", + selected_device >= 0 ? devices[selected_device].name.c_str() : "No devices found")) { + for (int i = 0; i < (int) devices.size(); i++) { + const Device &device = devices[i]; + bool is_selected = (i == selected_device); + // Devices are inserted as enabled, the checkbox keeps its address stable afterwards + bool &is_enabled = enabled_devices.try_emplace(device.sysfs_name, true).first->second; + ImGui::PushID(i); + + ImGui::PopStyleVar(); // Pop the style to avoid huge checkboxes + ImGui::Checkbox("##Device_Checkbox", &is_enabled); + ImGui::SameLine(); + ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, {12, 12}); + + ImGui::BeginDisabled(!is_enabled || !device.writable); + + if (ImGui::Selectable(device.name.c_str(), is_selected) && !is_selected) { + selected_device = i; + SelectDevice(device); + } + if (is_selected) + ImGui::SetItemDefaultFocus(); + + ImGui::EndDisabled(); + + if (!device.writable && ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled)) + ImGui::SetTooltip("Missing permissions to configure this device"); + + ImGui::PopID(); + } + ImGui::EndCombo(); + } + ImGui::EndDisabled(); + ImGui::SeparatorText("Mode Selection"); for (int i = 1; i < NUM_MODES; i++) { const char *accel = AccelModes[i]; @@ -1130,7 +1201,8 @@ static int OnGui() { !functions[selected_mode].isValid); if (ImGui::Button("Apply", {avail.x / 3 - (ImGui::GetStyle().ItemSpacing.x * 2), -1})) { - params[selected_mode].SaveAll(); + if (!params[selected_mode].SaveAll(active_device.params_dir)) + fprintf(stderr, "Failed to apply the parameters to %s\n", active_device.name.c_str()); functions[0] = functions[selected_mode]; params[0] = params[selected_mode]; used_mode = selected_mode; @@ -1143,11 +1215,13 @@ static int OnGui() { ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImColor::HSV(0.3, 0.7, 0.8).Value); ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImColor::HSV(0.3, 0.67, 0.83).Value); if (ImGui::Button("Apply + Save", {-1, -1})) { - params[selected_mode].SaveAll(false); - if (!DriverHelper::SavePersistentParameters()) + // The driver applies each parameter as it is written, so the config file is dumped + // back out of the device afterwards + if (!params[selected_mode].SaveAll(active_device.params_dir)) + fprintf(stderr, "Failed to apply the parameters to %s\n", active_device.name.c_str()); + if (!DriverHelper::SavePersistentParameters(active_device)) fprintf(stderr, "Failed to save parameters in /etc/yeetmouse.conf\n"); else { - DriverHelper::SaveParameters(); functions[0] = functions[selected_mode]; params[0] = params[selected_mode]; used_mode = selected_mode; @@ -1187,6 +1261,24 @@ static int OnGui() { Parameters start_params; +static bool SelectDevice(const Device &device) { + active_device = device; + has_privilege = device.writable; + + if (!DriverHelper::ParseAllParameters(device.params_dir, start_params, LUT_user_data)) { + fprintf(stderr, "Could not read the parameters of %s\n", device.name.c_str()); + was_initialized = false; + return false; + } + + used_mode = start_params.accelMode; + selected_mode = static_cast(start_params.accelMode % NUM_MODES); + was_initialized = true; + + ResetParameters(); + return true; +} + void ResetParameters(void) { for (int mode = 0; mode < NUM_MODES; mode++) { params[mode] = start_params; @@ -1280,16 +1372,6 @@ int main() { ImGui::GetIO().IniFilename = nullptr; - std::ifstream driver_update_file(YEETMOUSE_PARAMS_DIR "update"); - if (!driver_update_file.is_open()) { - fprintf(stderr, "You are not added to the 'yeetmouse' group, re-login before using the GUI!\n"); - has_privilege = false; - //return 1; - } else - has_privilege = true; - - driver_update_file.close(); - if (!DriverHelper::ValidateDirectory()) { fprintf(stderr, "YeetMouse directory doesnt exist!\nInstall the driver first, or check the parameters path.\n"); @@ -1299,22 +1381,14 @@ int main() { // Register file drag and drop glfwSetDropCallback(GUI::window, DroppedFilesCallback); - int fixed_num = 0; - if (!DriverHelper::CleanParameters(fixed_num) && fixed_num != 0 && !has_privilege) { - fprintf(stderr, "Could not setup driver params\n"); - } else { - // Read driver parameters to a dummy aggregate - DriverHelper::ParseAllParameters(start_params, LUT_user_data); - - used_mode = start_params.accelMode; - - selected_mode = static_cast(start_params.accelMode % NUM_MODES); - - was_initialized = true; - } - + auto devices = DriverHelper::DiscoverDevices(); + if (devices.empty()) + fprintf(stderr, "The driver is loaded, but is not attached to any mouse\n"); + else if (!SelectDevice(devices.front())) + fprintf(stderr, "You are not added to the 'yeetmouse' group, re-login before using the GUI!\n"); - ResetParameters(); + if (!was_initialized) + ResetParameters(); while (true) { diff --git a/tools/yeetmousectl/main.cpp b/tools/yeetmousectl/main.cpp index b87d4ad..691fea8 100644 --- a/tools/yeetmousectl/main.cpp +++ b/tools/yeetmousectl/main.cpp @@ -1,12 +1,28 @@ #include #include #include +#include // GUI helpers #include "../../gui/ConfigHelper.h" #include "../../gui/DriverHelper.h" -static int ApplyConfig(const std::string &file) { +/// Every device the driver is attached to, or just the named one +static std::vector SelectDevices(const char *name) { + auto devices = DriverHelper::DiscoverDevices(); + + if (!name) + return devices; + + for (const auto &device: devices) + if (device.sysfs_name == name || device.name == name) + return {device}; + + std::cerr << "No such device: " << name << std::endl; + return {}; +} + +static int ApplyConfig(const std::string &file, const char *device_name) { std::ifstream stream(file); if (!stream.is_open()) { @@ -26,19 +42,42 @@ static int ApplyConfig(const std::string &file) { Parameters params = *parsed; - params.SaveAll(); + const auto devices = SelectDevices(device_name); + if (devices.empty()) { + std::cerr << "No device to apply the configuration to." << std::endl; + return 1; + } - std::cout << "Configuration applied." << std::endl; + // Without a device given, the config is the same for every mouse + int failed = 0; + for (const auto &device: devices) { + if (!params.SaveAll(device.params_dir)) { + std::cerr << "Failed to apply the configuration to " << device.name << std::endl; + failed++; + } + } + + if (failed == (int) devices.size()) + return 1; + + std::cout << "Configuration applied to " << devices.size() - failed << " device(s)." << std::endl; return 0; } -static std::string DumpDriver() { +static std::string DumpDriver(const char *device_name) { Parameters params{}; char LUT_user_data[MAX_LUT_BUF_LEN]; - DriverHelper::ParseAllParameters(params, LUT_user_data); + const auto devices = SelectDevices(device_name); + if (devices.empty()) { + std::cerr << "No device to read the configuration from." << std::endl; + return {}; + } + + if (!DriverHelper::ParseAllParameters(devices.front().params_dir, params, LUT_user_data)) + return {}; return ConfigHelper::ExportPlainText(params, false); } @@ -47,9 +86,12 @@ int main(int argc, char **argv) { if (argc < 2) { std::cout << "Usage:\n" - " yeetmousectl apply \n" - " yeetmousectl dump\n" - " yeetmousectl save \n"; + " yeetmousectl apply [device]\n" + " yeetmousectl dump [device]\n" + " yeetmousectl save [device]\n" + "\n" + "Devices are named as under /sys/class/yeetmouse. Without one, `apply` covers\n" + "every mouse the driver is attached to and `dump`/`save` read the first one.\n"; return 0; } @@ -62,14 +104,15 @@ int main(int argc, char **argv) { return 2; } - return ApplyConfig(argv[2]); + return ApplyConfig(argv[2], argc > 3 ? argv[3] : nullptr); } if (cmd == "dump") { - if (const auto dump_str = DumpDriver(); dump_str.length() < 2) { + const auto dump_str = DumpDriver(argc > 2 ? argv[2] : nullptr); + if (dump_str.length() < 2) { return 4; } - std::cout << DumpDriver(); + std::cout << dump_str; return 0; } @@ -79,13 +122,18 @@ int main(int argc, char **argv) { return 2; } + const auto dump_str = DumpDriver(argc > 3 ? argv[3] : nullptr); + if (dump_str.length() < 2) { + return 4; + } + std::ofstream out(argv[2]); if (!out.is_open()) { std::cerr << "Failed to open file\n"; return 3; } - out << DumpDriver();; + out << dump_str; return 0; } From 122460ceb05fee838725c633169f53075023d389 Mon Sep 17 00:00:00 2001 From: Salman Abuhaimed Date: Sat, 22 Aug 2026 21:18:26 +0300 Subject: [PATCH 07/11] use defaults.h --- driver/driver.c | 29 ++++++++++++++++++++++++----- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/driver/driver.c b/driver/driver.c index ca75abd..b2ccf0d 100644 --- a/driver/driver.c +++ b/driver/driver.c @@ -2,6 +2,8 @@ #include "accel.h" #include "../shared_definitions.h" #include "accel_modes.h" +#include "defaults.h" +#include "linux/stringify.h" #include "asm-generic/errno-base.h" #include "linux/device.h" #include "linux/device/class.h" @@ -31,6 +33,13 @@ static ssize_t mouse_param_store(struct device *dev, struct device_attribute *at #define FILE_PERMISSIONS (0660) +/* defaults.h holds plain decimal literals, so that userspace can share the same file */ +#define DEFAULT_FP64(name) ({ \ + FP_LONG __value = 0; \ + FP64_FromString(__stringify(name), &__value); \ + __value; \ +}) + // Manual definition since we aren't using the default _show naming convention static struct device_attribute dev_attr_acceleration_mode = __ATTR(acceleration_mode, FILE_PERMISSIONS, mouse_param_show, mouse_param_store); @@ -301,11 +310,21 @@ static int driver_connect(struct input_handler *handler, struct input_dev *dev, goto err_free_state; } - accel_config->acceleration_mode = 1; - accel_config->sensitivity = FP64_1; - accel_config->prescale = FP64_1; - accel_config->acceleration = FP64_1; - accel_config->ratio_yx = FP64_1; + accel_config->acceleration_mode = ACCELERATION_MODE; + accel_config->sensitivity = DEFAULT_FP64(SENSITIVITY); + accel_config->ratio_yx = DEFAULT_FP64(RATIO_YX); + accel_config->output_cap = DEFAULT_FP64(OUTPUT_CAP); + accel_config->input_cap = DEFAULT_FP64(INPUT_CAP); + accel_config->offset = DEFAULT_FP64(OFFSET); + accel_config->prescale = DEFAULT_FP64(PRESCALE); + accel_config->acceleration = DEFAULT_FP64(ACCELERATION); + accel_config->midpoint = DEFAULT_FP64(MIDPOINT); + accel_config->motivity = DEFAULT_FP64(MOTIVITY); + accel_config->exponent = DEFAULT_FP64(EXPONENT); + accel_config->use_smoothing = USE_SMOOTHING; + accel_config->rotation_angle = DEFAULT_FP64(ROTATION_ANGLE); + accel_config->angle_snap_threshold = DEFAULT_FP64(ANGLE_SNAPPING_THRESHOLD); + accel_config->angle_snap_angle = DEFAULT_FP64(ANGLE_SNAPPING_ANGLE); state->modes_consts.current_func_at_0 = FP64_1; update_constants(accel_config, &state->modes_consts); From 1b2f794126afff332fd03f2df319c6edc4e40ce1 Mon Sep 17 00:00:00 2001 From: Salman Abuhaimed Date: Sat, 22 Aug 2026 21:18:26 +0300 Subject: [PATCH 08/11] move parameter parsing and emiting to functions --- driver/driver.c | 176 ++++++++++++++++++++++-------------------------- 1 file changed, 81 insertions(+), 95 deletions(-) diff --git a/driver/driver.c b/driver/driver.c index b2ccf0d..33fcbbc 100644 --- a/driver/driver.c +++ b/driver/driver.c @@ -419,6 +419,44 @@ struct input_handler driver_handler = { .match = driver_match }; +#define PARAM_DECIMALS (6) + +static ssize_t emit_fp64(char *buf, FP_LONG value) { + char output[32]; + + FP64_ToString(value, output, PARAM_DECIMALS); + return sysfs_emit(buf, "%s\n", output); +} + +static ssize_t emit_lut_data(char *buf, const struct accel_params *params) { + char value[32]; + unsigned long i; + int len = 0; + + for (i = 0; i < params->lut_pairs; i++) { + /* Leave room for the longest pair we could still append */ + if (len > PAGE_SIZE - 2 * sizeof(value)) + break; + + FP64_ToString(params->lut_data_x[i], value, PARAM_DECIMALS); + len += sysfs_emit_at(buf, len, "%s,", value); + FP64_ToString(params->lut_data_y[i], value, PARAM_DECIMALS); + len += sysfs_emit_at(buf, len, "%s;", value); + } + + return len + sysfs_emit_at(buf, len, "\n"); +} + +static int parse_fp64(const char *buf, FP_LONG *out) { + FP_LONG value; + + if (FP64_FromString(buf, &value) <= 0) + return -EINVAL; + + *out = value; + return 0; +} + static ssize_t mouse_param_show(struct device *dev, struct device_attribute *attr, char *buf) { struct input_dev *idev = to_input_dev(dev); struct mouse_state *state = input_get_drvdata(idev); @@ -430,45 +468,41 @@ static ssize_t mouse_param_show(struct device *dev, struct device_attribute *att rcu_read_lock(); params = rcu_dereference(state->params); - // TODO if (attr == &dev_attr_acceleration_mode) { ret = sysfs_emit(buf, "%d\n", params->acceleration_mode); } else if (attr == &dev_attr_input_cap) { - ret = sysfs_emit(buf, "%lld\n", params->input_cap); + ret = emit_fp64(buf, params->input_cap); } else if (attr == &dev_attr_ratio_yx) { - ret = sysfs_emit(buf, "%lld\n", params->ratio_yx); + ret = emit_fp64(buf, params->ratio_yx); } else if (attr == &dev_attr_output_cap) { - ret = sysfs_emit(buf, "%lld\n", params->output_cap); + ret = emit_fp64(buf, params->output_cap); } else if (attr == &dev_attr_offset) { - ret = sysfs_emit(buf, "%lld\n", params->offset); + ret = emit_fp64(buf, params->offset); } else if (attr == &dev_attr_prescale) { - ret = sysfs_emit(buf, "%lld\n", params->prescale); + ret = emit_fp64(buf, params->prescale); } else if (attr == &dev_attr_acceleration) { - char output[64]; - FP64_ToString(params->acceleration, output, 2); - ret = sysfs_emit(buf, "%s\n", output); + ret = emit_fp64(buf, params->acceleration); } else if (attr == &dev_attr_sensitivity) { - ret = sysfs_emit(buf, "%lld\n", params->sensitivity); + ret = emit_fp64(buf, params->sensitivity); } else if (attr == &dev_attr_exponent) { - ret = sysfs_emit(buf, "%lld\n", params->exponent); + ret = emit_fp64(buf, params->exponent); } else if (attr == &dev_attr_midpoint) { - ret = sysfs_emit(buf, "%lld\n", params->midpoint); + ret = emit_fp64(buf, params->midpoint); } else if (attr == &dev_attr_motivity) { - ret = sysfs_emit(buf, "%lld\n", params->motivity); + ret = emit_fp64(buf, params->motivity); } else if (attr == &dev_attr_use_smoothing) { ret = sysfs_emit(buf, "%d\n", params->use_smoothing); } else if (attr == &dev_attr_lut_data) { - ret = sysfs_emit(buf, "%s\n", "TODO"); - // ret = sysfs_emit(buf, "%s\n", params->lut_data); + ret = emit_lut_data(buf, params); } else if (attr == &dev_attr_cc_data_aggregate) { ret = sysfs_emit(buf, "%s\n", params->cc_data_aggregate); } else if (attr == &dev_attr_rotation_angle) { - ret = sysfs_emit(buf, "%lld\n", params->rotation_angle); + ret = emit_fp64(buf, params->rotation_angle); } else if (attr == &dev_attr_angle_snap_threshold) { - ret = sysfs_emit(buf, "%lld\n", params->angle_snap_threshold); + ret = emit_fp64(buf, params->angle_snap_threshold); } else if (attr == &dev_attr_angle_snap_angle) { - ret = sysfs_emit(buf, "%lld\n", params->angle_snap_angle); + ret = emit_fp64(buf, params->angle_snap_angle); } else { ret = -EINVAL; } @@ -559,94 +593,58 @@ static ssize_t mouse_param_store(struct device *dev, struct device_attribute *at new_config->acceleration_mode = val; } else if (attr == &dev_attr_input_cap) { - long long val; - ret = kstrtoll(buf, 10, &val); - if (ret) { + ret = parse_fp64(buf, &new_config->input_cap); + if (ret) goto err_unlock; - } - - new_config->input_cap = val; } else if (attr == &dev_attr_ratio_yx) { - long long val; - ret = kstrtoll(buf, 10, &val); - if (ret) { + ret = parse_fp64(buf, &new_config->ratio_yx); + if (ret) goto err_unlock; - } - - new_config->ratio_yx = val; } else if (attr == &dev_attr_output_cap) { - long long val; - ret = kstrtoll(buf, 10, &val); - if (ret) { + ret = parse_fp64(buf, &new_config->output_cap); + if (ret) goto err_unlock; - } - - new_config->output_cap = val; } else if (attr == &dev_attr_offset) { - long long val; - ret = kstrtoll(buf, 10, &val); - if (ret) { + ret = parse_fp64(buf, &new_config->offset); + if (ret) goto err_unlock; - } - - new_config->offset = val; } else if (attr == &dev_attr_prescale) { - long long val; - ret = kstrtoll(buf, 10, &val); - if (ret) { + ret = parse_fp64(buf, &new_config->prescale); + if (ret) goto err_unlock; - } - - new_config->prescale = val; } else if (attr == &dev_attr_acceleration) { - FP_LONG val; - FP64_FromString(buf, &val); - new_config->acceleration = val; + ret = parse_fp64(buf, &new_config->acceleration); + if (ret) + goto err_unlock; } else if (attr == &dev_attr_sensitivity) { - long long val; - ret = kstrtoll(buf, 10, &val); - if (ret) { + ret = parse_fp64(buf, &new_config->sensitivity); + if (ret) goto err_unlock; - } - - new_config->sensitivity = val; } else if (attr == &dev_attr_exponent) { - long long val; - ret = kstrtoll(buf, 10, &val); - if (ret) { + ret = parse_fp64(buf, &new_config->exponent); + if (ret) goto err_unlock; - } - - new_config->exponent = val; } else if (attr == &dev_attr_midpoint) { - long long val; - ret = kstrtoll(buf, 10, &val); - if (ret) { + ret = parse_fp64(buf, &new_config->midpoint); + if (ret) goto err_unlock; - } - - new_config->midpoint = val; } else if (attr == &dev_attr_motivity) { - long long val; - ret = kstrtoll(buf, 10, &val); - if (ret) { + ret = parse_fp64(buf, &new_config->motivity); + if (ret) goto err_unlock; - } - - new_config->motivity = val; } else if (attr == &dev_attr_use_smoothing) { - long long val; - ret = kstrtoll(buf, 10, &val); + bool val; + ret = kstrtobool(buf, &val); if (ret) { goto err_unlock; } @@ -671,31 +669,19 @@ static ssize_t mouse_param_store(struct device *dev, struct device_attribute *at // } } else if (attr == &dev_attr_rotation_angle) { - long long val; - ret = kstrtoll(buf, 10, &val); - if (ret) { + ret = parse_fp64(buf, &new_config->rotation_angle); + if (ret) goto err_unlock; - } - - new_config->rotation_angle = val; } else if (attr == &dev_attr_angle_snap_threshold) { - long long val; - ret = kstrtoll(buf, 10, &val); - if (ret) { + ret = parse_fp64(buf, &new_config->angle_snap_threshold); + if (ret) goto err_unlock; - } - - new_config->angle_snap_threshold = val; } else if (attr == &dev_attr_angle_snap_angle) { - long long val; - ret = kstrtoll(buf, 10, &val); - if (ret) { + ret = parse_fp64(buf, &new_config->angle_snap_angle); + if (ret) goto err_unlock; - } - - new_config->angle_snap_angle = val; } validate_config(new_config); From 21ca4d8cd32ce9fcbd2ba3dfdcbda35163e0f0b8 Mon Sep 17 00:00:00 2001 From: Salman Abuhaimed Date: Sat, 22 Aug 2026 22:07:21 +0300 Subject: [PATCH 09/11] remove legacy module parameters --- driver/accel.c | 95 -------------------------------------------- driver/accel_modes.h | 1 - gui/DriverHelper.h | 3 +- 3 files changed, 1 insertion(+), 98 deletions(-) diff --git a/driver/accel.c b/driver/accel.c index c6f4eac..7064ca9 100644 --- a/driver/accel.c +++ b/driver/accel.c @@ -4,93 +4,14 @@ #include #include #include -#include //strlen #include "FixedMath/Fixed64.h" #include "accel_modes.h" -#include "defaults.h" MODULE_AUTHOR("Christopher Williams "); //Original idea of this module MODULE_AUTHOR("Klaus Zipfel "); //Current maintainer MODULE_AUTHOR("Maciej Grzęda "); // Current maintainer // Sorry if you have issues with compilation because of this silly character in my family name lol <3 -//Converts a preprocessor define's value in "config.h" to a string - Suspect this to change in future version without a "config.h" -#define _s(x) #x -#define s(x) _s(x) - -// Convenient helper for float based parameters -#define PARAM_F(param, default, desc) \ - FP_LONG g_##param = C0NST_FP64_FromDouble(default); \ - char* g_param_##param = s(default); \ - module_param_named(param, g_param_##param, charp, 0660); \ - MODULE_PARM_DESC(param, desc); - -#define PARAM(param, default, desc) \ - char g_##param = default; \ - module_param_named(param, g_##param, byte, 0660); \ - MODULE_PARM_DESC(param, desc); - -#define PARAM_BYTE(param, default, desc) \ - char g_##param = (char)default; \ - char* g_param_##param = s(default); \ - module_param_named(param, g_param_##param, charp, 0660); \ - MODULE_PARM_DESC(param, desc); - -#define PARAM_ARR(param, default, desc) \ - char g_param_##param[MAX_LUT_BUF_LEN] = s(default); \ - module_param_string(param, g_param_##param, MAX_LUT_BUF_LEN, 0660); \ - MODULE_PARM_DESC(param, desc); - -#define PARAM_UL(param, default, desc) \ - unsigned long g_##param = (unsigned long)default; \ - char* g_param_##param = s(default); \ - module_param_named(param, g_param_##param, charp, 0660); \ - MODULE_PARM_DESC(param, desc); - -// ########## Kernel module parameters - -// Simple module parameters (instant update) -PARAM(update, 1, "Triggers an update of the acceleration parameters below"); - -// Triggered update (same as Acceleration parameters) -PARAM_BYTE(AccelerationMode, ACCELERATION_MODE, "Sets the algorithm to be used for acceleration"); - -// Acceleration parameters (type pchar. Converted to float via "update_params" triggered by /sys/module/yeetmouse/parameters/update) -PARAM_F(InputCap, INPUT_CAP, "Limit the maximum pointer speed before applying acceleration."); -PARAM_F(Sensitivity, SENSITIVITY, "Mouse base sensitivity, or X axis sensitivity if the anisotropy is on."); // Sensitivity for X axis only if sens != sens_y (anisotropy is on), otherwise sensitivity for both axes -PARAM_F(RatioYX, RATIO_YX, "Mouse base sensitivity on the Y axis."); // Used only when anisotropy is on -PARAM_F(OutputCap, OUTPUT_CAP, "Cap maximum sensitivity."); -PARAM_F(Offset, OFFSET, "Mouse acceleration shift."); -PARAM_F(PreScale, PRESCALE, "Parameter to adjust for the DPI"); - -PARAM_F(Acceleration, ACCELERATION, "Mouse acceleration sensitivity."); -PARAM_F(Exponent, EXPONENT, "Exponent for algorithms that use it"); -PARAM_F(Midpoint, MIDPOINT, "Midpoint for sigmoid function, Output Offset for Power mode"); -PARAM_F(Motivity, MOTIVITY, "Expresses how much change will occur for the Motivity (and Synchronous) function"); -PARAM (UseSmoothing, USE_SMOOTHING, "Whether to smooth out functions (doesn't apply to all)"); -//PARAM_F(ScrollsPerTick, SCROLLS_PER_TICK, "Amount of lines to scroll per scroll-wheel tick."); - -PARAM_UL(LutSize, LUT_SIZE, "LUT data array size"); -PARAM_ARR(LutDataBuf, LUT_DATA, "Data of the LUT stored in a human form"); // g_LutDataBuf should not be used! - -PARAM_ARR(_CustomCurveDataAggregate, CC_DATA_AGGREGATE, "Stores the Custom Curve data, SHOULD NOT BE USED ON THE DRIVER SIDE"); - -PARAM_F(RotationAngle, ROTATION_ANGLE, "Amount of clockwise rotation (in radians)"); -PARAM_F(AngleSnap_Threshold, ANGLE_SNAPPING_THRESHOLD, "Rotation value at which angle snapping is triggered (in radians)"); -PARAM_F(AngleSnap_Angle, ANGLE_SNAPPING_ANGLE, "Amount of clockwise rotation for angle snapping (in radians)"); - -FP_LONG g_LutData_x[MAX_LUT_ARRAY_SIZE]; // Array to store the x-values of the LUT data -FP_LONG g_LutData_y[MAX_LUT_ARRAY_SIZE]; // Array to store the y-values of the LUT data - -// Converts given string to a unsigned long -unsigned long atoul(const char *str); - -// Updates the acceleration parameters. This is purposely done with a delay! -// First, to not hammer too much the logic in "accelerate()", which is called VERY OFTEN! -// Second, to fight possible cheating. However, this can be OFC changed, since we are OSS... -#define PARAM_UPDATE(param) (FP64_FromString(g_param_##param, &g_##param)) -#define PARAM_UPDATE_UL(param) (atoul(g_param_##param)) - // Acceleration happens here int accelerate(const struct accel_params * params, struct accel_runtime *rt, const struct ModesConstants *constants, int *x, int *y) { @@ -133,9 +54,6 @@ int accelerate(const struct accel_params * params, struct accel_runtime *rt, con //if(ms > 100) ms = 100; //Original InterAccel has 200 here. RawAccel rounds to 100. So do we. last_ms = ms; - // Update acceleration parameters periodically - // update_params(params, now); - // Apply Pre-Scale if (params->prescale != FP64_1) { delta_x = FP64_Mul(delta_x, params->prescale); @@ -276,16 +194,3 @@ int accelerate(const struct accel_params * params, struct accel_runtime *rt, con return status; } - -unsigned long atoul(const char *str) { - unsigned long result = 0; - int i = 0; - - // Iterate through the string, converting each digit to an integer - while (str[i] >= '0' && str[i] <= '9') { - result = result * 10 + (str[i] - '0'); - i++; - } - - return result; -} diff --git a/driver/accel_modes.h b/driver/accel_modes.h index 1fb25dd..9ae7016 100644 --- a/driver/accel_modes.h +++ b/driver/accel_modes.h @@ -12,7 +12,6 @@ extern "C" { #include "FixedMath/Fixed64.h" #include "accel.h" -extern unsigned long g_LutSize; static const FP_LONG FP64_PI = C0NST_FP64_FromDouble(3.14159); static const FP_LONG FP64_PI_2 = C0NST_FP64_FromDouble(1.57079); static const FP_LONG FP64_PI_4 = C0NST_FP64_FromDouble(0.78539); diff --git a/gui/DriverHelper.h b/gui/DriverHelper.h index de91d68..f229b80 100644 --- a/gui/DriverHelper.h +++ b/gui/DriverHelper.h @@ -10,8 +10,7 @@ #include "CustomCurve.h" #include "../shared_definitions.h" -#define YEETMOUSE_PARAMS_DIR "/sys/module/yeetmouse/parameters/" - +// Every mouse the driver attached to gets its own directory here, holding an `accel_config` group #define YEETMOUSE_CLASS_DIR "/sys/class/yeetmouse/" #define YEETMOUSE_DEVICE_PARAMS_SUBDIR "accel_config" From 344b3d7e0482a109b465e593969a4f86cda7953b Mon Sep 17 00:00:00 2001 From: Salman Abuhaimed Date: Sat, 22 Aug 2026 22:11:39 +0300 Subject: [PATCH 10/11] pass param struct to accel functions --- driver/accel.c | 16 ++++---- driver/accel_modes.c | 96 ++++++++++++++++++++++---------------------- driver/accel_modes.h | 16 ++++---- 3 files changed, 64 insertions(+), 64 deletions(-) diff --git a/driver/accel.c b/driver/accel.c index 7064ca9..32155c1 100644 --- a/driver/accel.c +++ b/driver/accel.c @@ -86,28 +86,28 @@ int accelerate(const struct accel_params * params, struct accel_runtime *rt, con if (speed > 0) { switch (params->acceleration_mode) { case AccelMode_Linear: - speed = accel_linear(constants, params->acceleration, params->use_smoothing, speed); + speed = accel_linear(constants, params, speed); break; case AccelMode_Power: - speed = accel_power(constants, params->midpoint, params->acceleration, params->exponent, params->use_smoothing, speed); + speed = accel_power(constants, params, speed); break; case AccelMode_Classic: - speed = accel_classic(constants, params->acceleration, params->use_smoothing, speed); + speed = accel_classic(constants, params, speed); break; case AccelMode_Motivity: - speed = accel_motivity(constants, params->midpoint, speed); + speed = accel_motivity(constants, params, speed); break; case AccelMode_Synchronous: - speed = accel_synchronous(constants, params->acceleration, params->use_smoothing, speed); + speed = accel_synchronous(constants, params, speed); break; case AccelMode_Natural: - speed = accel_natural(constants, params->midpoint, params->use_smoothing, speed); + speed = accel_natural(constants, params, speed); break; case AccelMode_Jump: - speed = accel_jump(constants, params->midpoint, params->use_smoothing, speed); + speed = accel_jump(constants, params, speed); break; case AccelMode_Lut: case AccelMode_CustomCurve: - speed = accel_lut(params->lut_pairs, params->lut_data_x, params->lut_data_y, speed); + speed = accel_lut(params, speed); break; default: speed = FP64_1; diff --git a/driver/accel_modes.c b/driver/accel_modes.c index d220727..f4c6147 100644 --- a/driver/accel_modes.c +++ b/driver/accel_modes.c @@ -309,28 +309,28 @@ void update_constants(struct accel_params *params, struct ModesConstants *consta static_assert(AccelMode_Count == 10, "Wrong AccelMode count!"); switch (params->acceleration_mode) { case AccelMode_Linear: - constants->current_func_at_0 = accel_linear(constants, params->acceleration, params->use_smoothing, FP64_0_01); + constants->current_func_at_0 = accel_linear(constants, params, FP64_0_01); break; case AccelMode_Power: - constants->current_func_at_0 = accel_power(constants, params->midpoint, params->acceleration, params->exponent, params->use_smoothing, FP64_0_01); + constants->current_func_at_0 = accel_power(constants, params, FP64_0_01); break; case AccelMode_Classic: - constants->current_func_at_0 = accel_classic(constants, params->acceleration, params->use_smoothing, FP64_0_01); + constants->current_func_at_0 = accel_classic(constants, params, FP64_0_01); break; case AccelMode_Motivity: - constants->current_func_at_0 = accel_motivity(constants, params->midpoint, FP64_0_01); + constants->current_func_at_0 = accel_motivity(constants, params, FP64_0_01); break; case AccelMode_Synchronous: - constants->current_func_at_0 = accel_synchronous(constants, params->acceleration, params->use_smoothing, FP64_0_01); + constants->current_func_at_0 = accel_synchronous(constants, params, FP64_0_01); break; case AccelMode_Natural: - constants->current_func_at_0 = accel_natural(constants, params->midpoint, params->use_smoothing, FP64_0_01); + constants->current_func_at_0 = accel_natural(constants, params, FP64_0_01); break; case AccelMode_Jump: - constants->current_func_at_0 = accel_jump(constants, params->midpoint, params->use_smoothing, FP64_0_01); + constants->current_func_at_0 = accel_jump(constants, params, FP64_0_01); break; case AccelMode_Lut: case AccelMode_CustomCurve: - constants->current_func_at_0 = accel_lut(params->lut_pairs, params->lut_data_x, params->lut_data_y, FP64_0_01); + constants->current_func_at_0 = accel_lut(params, FP64_0_01); break; default: constants->current_func_at_0 = FP64_1; @@ -380,29 +380,29 @@ static FP_LONG synchronous_eval(const struct ModesConstants *constants, FP_LONG return FP64_DivPrecise(y, constants->x_start); } -FP_LONG accel_linear(const struct ModesConstants *constants, FP_LONG acceleration, bool use_smoothing, FP_LONG speed) { - if (use_smoothing) { +FP_LONG accel_linear(const struct ModesConstants *constants, const struct accel_params *params, FP_LONG speed) { + if (params->use_smoothing) { if (speed < constants->cap_x) { - speed = FP64_Mul(constants->sign, FP64_Mul(speed, acceleration)); + speed = FP64_Mul(constants->sign, FP64_Mul(speed, params->acceleration)); } else { speed = FP64_Mul(constants->sign, FP64_Add(FP64_DivPrecise(constants->gain_constant, speed), constants->cap_y)); } } else { - speed = FP64_Mul(speed, acceleration); + speed = FP64_Mul(speed, params->acceleration); } return FP64_Add(FP64_1, speed); } -FP_LONG accel_power(const struct ModesConstants *constants, FP_LONG midpoint, FP_LONG acceleration, FP_LONG exponent, bool use_smoothing, FP_LONG speed) { +FP_LONG accel_power(const struct ModesConstants *constants, const struct accel_params *params, FP_LONG speed) { if (speed <= constants->offset_x) - speed = midpoint; + speed = params->midpoint; else { - if (use_smoothing) { + if (params->use_smoothing) { if (speed < constants->cap_x) { if (constants->power_constant == 0) - speed = FP64_PowFast(FP64_Mul(speed, acceleration), exponent); + speed = FP64_PowFast(FP64_Mul(speed, params->acceleration), params->exponent); else - speed = FP64_Add(FP64_PowFast(FP64_Mul(speed, acceleration), exponent), FP64_DivPrecise(constants->power_constant, speed)); + speed = FP64_Add(FP64_PowFast(FP64_Mul(speed, params->acceleration), params->exponent), FP64_DivPrecise(constants->power_constant, speed)); } else { if (constants->cap_x == FP64_FromInt(0)) { speed = constants->cap_y; @@ -412,15 +412,15 @@ FP_LONG accel_power(const struct ModesConstants *constants, FP_LONG midpoint, FP } } else { if (constants->power_constant == 0) - speed = FP64_PowFast(FP64_Mul(speed, acceleration), exponent); + speed = FP64_PowFast(FP64_Mul(speed, params->acceleration), params->exponent); else - speed = FP64_Add(FP64_PowFast(FP64_Mul(speed, acceleration), exponent), FP64_DivPrecise(constants->power_constant, speed)); + speed = FP64_Add(FP64_PowFast(FP64_Mul(speed, params->acceleration), params->exponent), FP64_DivPrecise(constants->power_constant, speed)); } } return speed; } -FP_LONG accel_classic(const struct ModesConstants *constants, FP_LONG acceleration, bool use_smoothing, FP_LONG speed) { +FP_LONG accel_classic(const struct ModesConstants *constants, const struct accel_params *params, FP_LONG speed) { // (Speed * Acceleration) ^ (Exponent - 1) + 1 // Same as above just without adding the one //speed *= g_Acceleration; @@ -429,12 +429,12 @@ FP_LONG accel_classic(const struct ModesConstants *constants, FP_LONG accelerati // FIXED-POINT: FP_LONG accel_classic_result = speed; - accel_classic_result = FP64_Mul(accel_classic_result, acceleration); + accel_classic_result = FP64_Mul(accel_classic_result, params->acceleration); accel_classic_result = FP64_PowFast(accel_classic_result, constants->exp_sub_1); // if Use Smooth Cap is on, we proceed to calculate the transition // point and the function that provides the smooth cap - if (use_smoothing) { + if (params->use_smoothing) { // we setup the y cap if (speed < constants->cap_x) { accel_classic_result = FP64_Mul(constants->sign, accel_classic_result); @@ -450,7 +450,7 @@ FP_LONG accel_classic(const struct ModesConstants *constants, FP_LONG accelerati return speed; } -FP_LONG accel_motivity(const struct ModesConstants *constants, FP_LONG midpoint, FP_LONG speed) { +FP_LONG accel_motivity(const struct ModesConstants *constants, const struct accel_params *params, FP_LONG speed) { // Acceleration / ( 1 + e ^ (midpoint - x)) //product = g_Midpoint-speed; //motivity = e; @@ -459,28 +459,28 @@ FP_LONG accel_motivity(const struct ModesConstants *constants, FP_LONG midpoint, //speed = motivity; // FIXED-POINT: - FP_LONG exp = FP64_ExpFast(FP64_Sub(midpoint, speed)); + FP_LONG exp = FP64_ExpFast(FP64_Sub(params->midpoint, speed)); speed = FP64_Add(FP64_1, FP64_DivPrecise(constants->accel_sub_1, FP64_Add(FP64_1, exp))); return speed; } -FP_LONG accel_synchronous(const struct ModesConstants *constants, FP_LONG acceleration, bool use_smoothing, FP_LONG speed) { +FP_LONG accel_synchronous(const struct ModesConstants *constants, const struct accel_params *params, FP_LONG speed) { // Defensive: ensure speed > 0 for log-domain math; you can clamp differently if your file already does. if (speed <= 0) { return FP64_1; } FP_LONG val; - if (use_smoothing && constants->lut_ready) { + if (params->use_smoothing && constants->lut_ready) { val = synchronous_eval(constants, speed); } else { - val = synchronous_legacy(constants, acceleration, speed); + val = synchronous_legacy(constants, params->acceleration, speed); } return val; } -FP_LONG accel_jump(const struct ModesConstants *constants, FP_LONG midpoint, bool use_smoothing, FP_LONG speed) { +FP_LONG accel_jump(const struct ModesConstants *constants, const struct accel_params *params, FP_LONG speed) { // r = 2pi/(k*midpoint), where k is the smoothness factor (stored inside g_Exponent) // Jump: Acceleration / (1 + exp(r(midpoint - x))) + 1 // Smooth: Integral of the above divided by x pretty much @@ -488,25 +488,25 @@ FP_LONG accel_jump(const struct ModesConstants *constants, FP_LONG midpoint, boo if (speed <= 0) return FP64_1; - FP_LONG exp_arg = FP64_Mul(constants->r, FP64_Sub(midpoint, speed)); + FP_LONG exp_arg = FP64_Mul(constants->r, FP64_Sub(params->midpoint, speed)); FP_LONG D = FP64_Exp(exp_arg); - if(use_smoothing) { // smooth + if(params->use_smoothing) { // smooth if (constants->r != 0) { FP_LONG natural_log = exp_arg > (EXP_ARG_THRESHOLD << FP64_Shift) ? exp_arg : FP64_Log(FP64_Add(FP64_1, D)); FP_LONG integral = FP64_Mul(constants->accel_sub_1, FP64_Add(speed, FP64_DivPrecise(natural_log, constants->r))); // Not really an integral speed = FP64_Add(FP64_DivPrecise(FP64_Sub(integral, constants->C0), speed), FP64_1); } - else if (speed <= midpoint) + else if (speed <= params->midpoint) speed = FP64_1; else - speed = FP64_Add(FP64_DivPrecise(FP64_Mul(constants->accel_sub_1, FP64_Sub(speed, midpoint)), speed), FP64_1); + speed = FP64_Add(FP64_DivPrecise(FP64_Mul(constants->accel_sub_1, FP64_Sub(speed, params->midpoint)), speed), FP64_1); } else { if (constants->r != 0) speed = FP64_Add(FP64_DivPrecise(constants->accel_sub_1, FP64_Add(FP64_1, D)), FP64_1); - else if (speed <= midpoint) + else if (speed <= params->midpoint) speed = FP64_1; else speed = FP64_Add(constants->accel_sub_1, FP64_1); @@ -515,14 +515,14 @@ FP_LONG accel_jump(const struct ModesConstants *constants, FP_LONG midpoint, boo return speed; } -FP_LONG accel_natural(const struct ModesConstants *constants, FP_LONG midpoint, bool use_smoothing, FP_LONG speed) { - if (speed <= midpoint) { +FP_LONG accel_natural(const struct ModesConstants *constants, const struct accel_params *params, FP_LONG speed) { + if (speed <= params->midpoint) { speed = FP64_1; } else { - FP_LONG n_offset_x = FP64_Sub(midpoint, speed); + FP_LONG n_offset_x = FP64_Sub(params->midpoint, speed); FP_LONG decay = FP64_Exp(FP64_Mul(constants->auxiliar_accel, n_offset_x)); - if (use_smoothing) { + if (params->use_smoothing) { FP_LONG decay_auxiliaraccel = FP64_DivPrecise(decay, constants->auxiliar_accel); FP_LONG numerator = FP64_Add( @@ -532,7 +532,7 @@ FP_LONG accel_natural(const struct ModesConstants *constants, FP_LONG midpoint, } else { speed = FP64_Add( FP64_Mul(constants->exp_sub_1, (FP64_Sub( - FP64_1, FP64_DivPrecise(FP64_Sub(midpoint, FP64_Mul(decay, n_offset_x)), speed)))), + FP64_1, FP64_DivPrecise(FP64_Sub(params->midpoint, FP64_Mul(decay, n_offset_x)), speed)))), FP64_1); } } @@ -544,17 +544,17 @@ FP_LONG accel_natural(const struct ModesConstants *constants, FP_LONG midpoint, #define MIN(a,b) (((a)<(b))?(a):(b)) #endif -FP_LONG accel_lut(unsigned long lut_pairs, const FP_LONG lut_data_x[MAX_LUT_ARRAY_SIZE], const FP_LONG lut_data_y[MAX_LUT_ARRAY_SIZE], FP_LONG speed) { +FP_LONG accel_lut(const struct accel_params *params, FP_LONG speed) { // Assumes the size and values are valid. Please don't change LUT parameters by hand. - if(speed < lut_data_x[0]) // Check if the speed is below the first given point - speed = lut_data_y[0]; + if(speed < params->lut_data_x[0]) // Check if the speed is below the first given point + speed = params->lut_data_y[0]; else { - int l = 0, r = lut_pairs - 1, best_point = r, iter = 0; // We REALLY don't want an infinity loop in kernel + int l = 0, r = params->lut_pairs - 1, best_point = r, iter = 0; // We REALLY don't want an infinity loop in kernel while (l <= r && iter < 10) { int mid = (r + l) / 2; - if (speed > lut_data_x[mid]) { + if (speed > params->lut_data_x[mid]) { l = mid + 1; } else { best_point = mid; @@ -564,14 +564,14 @@ FP_LONG accel_lut(unsigned long lut_pairs, const FP_LONG lut_data_x[MAX_LUT_ARRA iter++; } - int index = MIN(best_point-1, lut_pairs-2); + int index = MIN(best_point-1, params->lut_pairs-2); - FP_LONG p = lut_data_y[index]; - FP_LONG p1 = lut_data_y[index + 1]; + FP_LONG p = params->lut_data_y[index]; + FP_LONG p1 = params->lut_data_y[index + 1]; // denominator should not possibly ever be equal to 0 here... (we all know how this will end) - FP_LONG frac = FP64_DivPrecise(speed - lut_data_x[index], - lut_data_x[index + 1] - lut_data_x[index]); + FP_LONG frac = FP64_DivPrecise(speed - params->lut_data_x[index], + params->lut_data_x[index + 1] - params->lut_data_x[index]); speed = FP64_Lerp(p, p1, frac); } diff --git a/driver/accel_modes.h b/driver/accel_modes.h index 9ae7016..f8b96fd 100644 --- a/driver/accel_modes.h +++ b/driver/accel_modes.h @@ -26,14 +26,14 @@ static const FP_LONG FP64_10000 = 10000ll << FP64_Shift; void update_constants(struct accel_params *params, struct ModesConstants *constants); -FP_LONG accel_linear(const struct ModesConstants *constants, FP_LONG acceleration, bool use_smoothing, FP_LONG speed); -FP_LONG accel_power(const struct ModesConstants *constants, FP_LONG midpoint, FP_LONG acceleration, FP_LONG exponent, bool use_smoothing, FP_LONG speed); -FP_LONG accel_classic(const struct ModesConstants *constants, FP_LONG acceleration, bool use_smoothing, FP_LONG speed); -FP_LONG accel_motivity(const struct ModesConstants *constants, FP_LONG midpoint, FP_LONG speed); -FP_LONG accel_synchronous(const struct ModesConstants *constants, FP_LONG acceleration, bool use_smoothing, FP_LONG speed); -FP_LONG accel_natural(const struct ModesConstants *constants, FP_LONG midpoint, bool use_smoothing, FP_LONG speed); -FP_LONG accel_jump(const struct ModesConstants *constants, FP_LONG midpoint, bool use_smoothing, FP_LONG speed); -FP_LONG accel_lut(unsigned long lut_pairs, const FP_LONG lut_data_x[MAX_LUT_ARRAY_SIZE], const FP_LONG lut_data_y[MAX_LUT_ARRAY_SIZE], FP_LONG speed); +FP_LONG accel_linear(const struct ModesConstants *constants, const struct accel_params *params, FP_LONG speed); +FP_LONG accel_power(const struct ModesConstants *constants, const struct accel_params *params, FP_LONG speed); +FP_LONG accel_classic(const struct ModesConstants *constants, const struct accel_params *params, FP_LONG speed); +FP_LONG accel_motivity(const struct ModesConstants *constants, const struct accel_params *params, FP_LONG speed); +FP_LONG accel_synchronous(const struct ModesConstants *constants, const struct accel_params *params, FP_LONG speed); +FP_LONG accel_natural(const struct ModesConstants *constants, const struct accel_params *params, FP_LONG speed); +FP_LONG accel_jump(const struct ModesConstants *constants, const struct accel_params *params, FP_LONG speed); +FP_LONG accel_lut(const struct accel_params *params, FP_LONG speed); #ifdef __cplusplus } From a3ba8c693712bb893156cf1c8dfd9aa5b73fefa3 Mon Sep 17 00:00:00 2001 From: AndyFilter Date: Sun, 23 Aug 2026 13:21:29 +0200 Subject: [PATCH 11/11] Update Test Suite to reflect the structure changes --- tests/TestManager.cpp | 149 ++++++++++++++++++++---------------------- 1 file changed, 70 insertions(+), 79 deletions(-) diff --git a/tests/TestManager.cpp b/tests/TestManager.cpp index 8f20b02..dd161e1 100644 --- a/tests/TestManager.cpp +++ b/tests/TestManager.cpp @@ -4,32 +4,28 @@ #include "driver/accel_modes.h" // "Private" values only visible to the accel_modes -FP_LONG g_Sensitivity = FP64_1, g_RatioYX = FP64_1, g_OutputCap = 0, g_InputCap = 0, g_Offset = 0, g_PreScale = FP64_1, g_Acceleration = 0, g_Exponent - = 0, g_Midpoint = 0, g_Motivity = 0, g_RotationAngle = 0, g_AngleSnap_Angle = 0, g_AngleSnap_Threshold = - 0, g_LutData_x[256], g_LutData_y[256]; -char g_AccelerationMode = 0, g_UseSmoothing = 0; -unsigned long g_LutSize = 0; +accel_params accelParams; ModesConstants modesConst; static CachedFunction function; // Ignores speedY (for now?) FP_LONG ApplyGlobalPostParameters(FP_LONG speed) { FP_LONG speed_Y = FP64_1; - if (g_RatioYX == FP64_1) { - if(g_Sensitivity != FP64_1) - speed = FP64_Mul(speed, g_Sensitivity); + if (accelParams.ratio_yx == FP64_1) { + if(accelParams.sensitivity != FP64_1) + speed = FP64_Mul(speed, accelParams.sensitivity); // Apply Output Limit - if(g_OutputCap > 0) - speed = FP64_Min(g_OutputCap, speed); + if(accelParams.output_cap > 0) + speed = FP64_Min(accelParams.output_cap, speed); } else { - speed = FP64_Mul(speed, g_Sensitivity); - speed_Y = FP64_Mul(speed, g_RatioYX); + speed = FP64_Mul(speed, accelParams.sensitivity); + speed_Y = FP64_Mul(speed, accelParams.ratio_yx); // Apply Output Limit - if(g_OutputCap > 0) { - speed = FP64_Min(g_OutputCap, speed); - speed_Y = FP64_Min(g_OutputCap, speed_Y); + if(accelParams.output_cap > 0) { + speed = FP64_Min(accelParams.output_cap, speed); + speed_Y = FP64_Min(accelParams.output_cap, speed_Y); } } @@ -37,7 +33,7 @@ FP_LONG ApplyGlobalPostParameters(FP_LONG speed) { } FP_LONG ApplyGlobalPreParameters(FP_LONG speed) { - return FP64_Mul(speed, g_PreScale); + return FP64_Mul(speed, accelParams.prescale); } // TestManager & TestManager::GetInstance() { @@ -47,18 +43,18 @@ FP_LONG ApplyGlobalPreParameters(FP_LONG speed) { void TestManager::Initialize() { function.params = new Parameters; - function.params->sens = FP64_ToFloat(g_Sensitivity); - function.params->ratioYX = FP64_ToFloat(g_RatioYX); - function.params->accelMode = static_cast(g_AccelerationMode); - function.params->preScale = FP64_ToFloat(g_PreScale); - function.params->accel = FP64_ToFloat(g_Acceleration); - function.params->exponent = FP64_ToFloat(g_Exponent); - function.params->midpoint = FP64_ToFloat(g_Midpoint); - function.params->offset = FP64_ToFloat(g_Offset); - function.params->useSmoothing = g_UseSmoothing; - function.params->rotation = FP64_ToFloat(g_RotationAngle); - function.params->asAngle = FP64_ToFloat(g_AngleSnap_Angle); - function.params->asThreshold = FP64_ToFloat(g_AngleSnap_Threshold); + function.params->sens = FP64_ToFloat(accelParams.sensitivity); + function.params->ratioYX = FP64_ToFloat(accelParams.ratio_yx); + function.params->accelMode = static_cast(accelParams.acceleration_mode); + function.params->preScale = FP64_ToFloat(accelParams.prescale); + function.params->accel = FP64_ToFloat(accelParams.acceleration); + function.params->exponent = FP64_ToFloat(accelParams.exponent); + function.params->midpoint = FP64_ToFloat(accelParams.midpoint); + function.params->offset = FP64_ToFloat(accelParams.offset); + function.params->useSmoothing = accelParams.use_smoothing; + function.params->rotation = FP64_ToFloat(accelParams.rotation_angle); + function.params->asAngle = FP64_ToFloat(accelParams.angle_snap_angle); + function.params->asThreshold = FP64_ToFloat(accelParams.angle_snap_threshold); function.params->inCap = 0; function.params->outCap = 0; function.PreCacheConstants(); @@ -69,7 +65,7 @@ FP_LONG TestManager::AccelLinear(FP_LONG x, FP_LONG acceleration, FP_LONG midpoi SetUseSmoothing(gain); SetMidpoint(midpoint); UpdateModesConstants(); - return ApplyGlobalPostParameters(accel_linear(ApplyGlobalPreParameters(x))); + return ApplyGlobalPostParameters(accel_linear(&modesConst, &accelParams, ApplyGlobalPreParameters(x))); } FP_LONG TestManager::AccelPower(FP_LONG x, FP_LONG acceleration, FP_LONG exponent, FP_LONG midpoint, FP_LONG motivity, @@ -80,7 +76,7 @@ FP_LONG TestManager::AccelPower(FP_LONG x, FP_LONG acceleration, FP_LONG exponen SetMotivity(motivity); SetUseSmoothing(gain); UpdateModesConstants(); - return ApplyGlobalPostParameters(accel_power(ApplyGlobalPreParameters(x))); + return ApplyGlobalPostParameters(accel_power(&modesConst, &accelParams, ApplyGlobalPreParameters(x))); } FP_LONG TestManager::AccelClassic(FP_LONG x, FP_LONG acceleration, FP_LONG exponent, FP_LONG midpoint, bool gain) { @@ -89,7 +85,7 @@ FP_LONG TestManager::AccelClassic(FP_LONG x, FP_LONG acceleration, FP_LONG expon SetMidpoint(midpoint); SetUseSmoothing(gain); UpdateModesConstants(); - return ApplyGlobalPostParameters(accel_classic(ApplyGlobalPreParameters(x))); + return ApplyGlobalPostParameters(accel_classic(&modesConst, &accelParams, ApplyGlobalPreParameters(x))); } FP_LONG TestManager::AccelMotivity(FP_LONG x, FP_LONG acceleration, FP_LONG exponent, FP_LONG midpoint) { @@ -97,7 +93,7 @@ FP_LONG TestManager::AccelMotivity(FP_LONG x, FP_LONG acceleration, FP_LONG expo SetExponent(exponent); SetMidpoint(midpoint); UpdateModesConstants(); - return ApplyGlobalPostParameters(accel_motivity(ApplyGlobalPreParameters(x))); + return ApplyGlobalPostParameters(accel_motivity(&modesConst, &accelParams, ApplyGlobalPreParameters(x))); } FP_LONG TestManager::AccelSynchronous(FP_LONG x, FP_LONG sync_speed, FP_LONG gamma, FP_LONG smoothness, @@ -108,7 +104,7 @@ FP_LONG TestManager::AccelSynchronous(FP_LONG x, FP_LONG sync_speed, FP_LONG gam SetMotivity(motivity); SetUseSmoothing(gain); UpdateModesConstants(); - return ApplyGlobalPostParameters(accel_synchronous(ApplyGlobalPreParameters(x))); + return ApplyGlobalPostParameters(accel_synchronous(&modesConst, &accelParams, ApplyGlobalPreParameters(x))); } FP_LONG TestManager::AccelJump(FP_LONG x, FP_LONG acceleration, FP_LONG exponent, FP_LONG midpoint, bool gain) { @@ -117,7 +113,7 @@ FP_LONG TestManager::AccelJump(FP_LONG x, FP_LONG acceleration, FP_LONG exponent SetMidpoint(midpoint); SetUseSmoothing(gain); UpdateModesConstants(); - return ApplyGlobalPostParameters(accel_jump(ApplyGlobalPreParameters(x))); + return ApplyGlobalPostParameters(accel_jump(&modesConst, &accelParams, ApplyGlobalPreParameters(x))); } FP_LONG TestManager::AccelLUT(FP_LONG x, FP_LONG values_x[], FP_LONG values_y[], unsigned long count) { @@ -125,11 +121,11 @@ FP_LONG TestManager::AccelLUT(FP_LONG x, FP_LONG values_x[], FP_LONG values_y[], SetLutData_x(values_x, count); SetLutData_y(values_y, count); UpdateModesConstants(); - return ApplyGlobalPostParameters(accel_lut(ApplyGlobalPreParameters(x))); + return ApplyGlobalPostParameters(accel_lut(&accelParams, ApplyGlobalPreParameters(x))); } FP_LONG TestManager::AccelLUT(FP_LONG x) { - return ApplyGlobalPostParameters(accel_lut(ApplyGlobalPreParameters(x))); + return ApplyGlobalPostParameters(accel_lut(&accelParams, ApplyGlobalPreParameters(x))); } FP_LONG TestManager::AccelLinear(float x, float acceleration, float midpoint, bool gain) { @@ -181,31 +177,31 @@ FP_LONG TestManager::AccelLUT(float x) { } FP_LONG TestManager::AccelLinear(float x) { - return ApplyGlobalPostParameters(accel_linear(ApplyGlobalPreParameters(FP64_FromFloat(x)))); + return ApplyGlobalPostParameters(accel_linear(&modesConst, &accelParams, ApplyGlobalPreParameters(FP64_FromFloat(x)))); } FP_LONG TestManager::AccelPower(float x) { - return ApplyGlobalPostParameters(accel_power(ApplyGlobalPreParameters(FP64_FromFloat(x)))); + return ApplyGlobalPostParameters(accel_power(&modesConst, &accelParams, ApplyGlobalPreParameters(FP64_FromFloat(x)))); } FP_LONG TestManager::AccelClassic(float x) { - return ApplyGlobalPostParameters(accel_classic(ApplyGlobalPreParameters(FP64_FromFloat(x)))); + return ApplyGlobalPostParameters(accel_classic(&modesConst, &accelParams, ApplyGlobalPreParameters(FP64_FromFloat(x)))); } FP_LONG TestManager::AccelMotivity(float x) { - return ApplyGlobalPostParameters(accel_motivity(ApplyGlobalPreParameters(FP64_FromFloat(x)))); + return ApplyGlobalPostParameters(accel_motivity(&modesConst, &accelParams, ApplyGlobalPreParameters(FP64_FromFloat(x)))); } FP_LONG TestManager::AccelSynchronous(float x) { - return ApplyGlobalPostParameters(accel_synchronous(ApplyGlobalPreParameters(FP64_FromFloat(x)))); + return ApplyGlobalPostParameters(accel_synchronous(&modesConst, &accelParams, ApplyGlobalPreParameters(FP64_FromFloat(x)))); } FP_LONG TestManager::AccelNatural(float x) { - return ApplyGlobalPostParameters(accel_natural(ApplyGlobalPreParameters(FP64_FromFloat(x)))); + return ApplyGlobalPostParameters(accel_natural(&modesConst, &accelParams, ApplyGlobalPreParameters(FP64_FromFloat(x)))); } FP_LONG TestManager::AccelJump(float x) { - return ApplyGlobalPostParameters(accel_jump(ApplyGlobalPreParameters(FP64_FromFloat(x)))); + return ApplyGlobalPostParameters(accel_jump(&modesConst, &accelParams, ApplyGlobalPreParameters(FP64_FromFloat(x)))); } ModesConstants &TestManager::GetModesConstants() { @@ -213,12 +209,12 @@ ModesConstants &TestManager::GetModesConstants() { } void TestManager::UpdateModesConstants() { - update_constants(); + update_constants(&accelParams, &modesConst); function.PreCacheConstants(); } bool TestManager::ValidateConstants() { - if (g_AccelerationMode == AccelMode_Current) + if (accelParams.acceleration_mode == AccelMode_Current) return false; // switch (g_AccelerationMode) { @@ -244,95 +240,90 @@ bool TestManager::ValidateFunctionGUI() { } void TestManager::SetAccelMode(AccelMode mode) { - g_AccelerationMode = mode; - function.params->accelMode = static_cast(g_AccelerationMode); -} - -void TestManager::SetUseSmoothing(char useSmoothing) { - g_UseSmoothing = useSmoothing; - function.params->useSmoothing = g_UseSmoothing; + accelParams.acceleration_mode = mode; + function.params->accelMode = mode; } void TestManager::SetAcceleration(FP_LONG acceleration) { - g_Acceleration = acceleration; - function.params->accel = FP64_ToFloat(g_Acceleration); + accelParams.acceleration = acceleration; + function.params->accel = FP64_ToFloat(acceleration); } void TestManager::SetExponent(FP_LONG exponent) { - g_Exponent = exponent; - function.params->exponent = FP64_ToFloat(g_Exponent); + accelParams.exponent = exponent; + function.params->exponent = FP64_ToFloat(exponent); } void TestManager::SetMidpoint(FP_LONG midpoint) { - g_Midpoint = midpoint; - function.params->midpoint = FP64_ToFloat(g_Midpoint); + accelParams.midpoint = midpoint; + function.params->midpoint = FP64_ToFloat(midpoint); } void TestManager::SetMotivity(FP_LONG motivity) { - g_Motivity = motivity; - function.params->motivity = FP64_ToFloat(g_Motivity); + accelParams.motivity = motivity; + function.params->motivity = FP64_ToFloat(motivity); } void TestManager::SetSensitivity(FP_LONG sensitivity) { - g_Sensitivity = sensitivity; + accelParams.sensitivity = sensitivity; function.params->sens = FP64_ToFloat(sensitivity); } void TestManager::SetSensitivityY(FP_LONG sensitivityY) { - g_RatioYX = sensitivityY; + accelParams.ratio_yx = sensitivityY; function.params->ratioYX = FP64_ToFloat(sensitivityY); } void TestManager::SetOutCap(FP_LONG outCap) { - g_OutputCap = outCap; + accelParams.output_cap = outCap; function.params->outCap = FP64_ToFloat(outCap); } void TestManager::SetInCap(FP_LONG inCap) { - g_InputCap = inCap; + accelParams.input_cap = inCap; function.params->inCap = FP64_ToFloat(inCap); } void TestManager::SetOffset(FP_LONG offset) { - g_Offset = offset; + accelParams.offset = offset; function.params->offset = FP64_ToFloat(offset); } void TestManager::SetPreScale(FP_LONG preScale) { - g_PreScale = preScale; + accelParams.prescale = preScale; function.params->preScale = FP64_ToFloat(preScale); } void TestManager::SetRotationAngle(FP_LONG rotationAngle) { - g_RotationAngle = rotationAngle; - function.params->rotation = FP64_ToFloat(g_RotationAngle); + accelParams.rotation_angle = rotationAngle; + function.params->rotation = FP64_ToFloat(rotationAngle); } void TestManager::SetAngleSnap_Angle(FP_LONG angleSnap_Angle) { - g_AngleSnap_Angle = angleSnap_Angle; - function.params->asAngle = FP64_ToFloat(g_AngleSnap_Angle); + accelParams.angle_snap_angle = angleSnap_Angle; + function.params->asAngle = FP64_ToFloat(angleSnap_Angle); } void TestManager::SetAngleSnap_Threshold(FP_LONG angleSnap_Threshold) { - g_AngleSnap_Threshold = angleSnap_Threshold; - function.params->asThreshold = FP64_ToFloat(g_AngleSnap_Threshold); + accelParams.angle_snap_threshold = angleSnap_Threshold; + function.params->asThreshold = FP64_ToFloat(angleSnap_Threshold); } void TestManager::SetUseSmoothing(bool useSmoothing) { - g_UseSmoothing = useSmoothing ? 1 : 0; - function.params->useSmoothing = g_UseSmoothing; + accelParams.use_smoothing = useSmoothing; + function.params->useSmoothing = useSmoothing; } void TestManager::SetLutSize(unsigned long lutSize) { - g_LutSize = lutSize; - function.params->lutSize = g_LutSize; + accelParams.lut_pairs = lutSize; + function.params->lutSize = lutSize; } void TestManager::SetLutData_x(FP_LONG values[], unsigned long count) { SetLutSize(count); for (unsigned long i = 0; i < count; i++) { - g_LutData_x[i] = values[i]; + accelParams.lut_data_x[i] = values[i]; function.params->lutDataX[i] = FP64_ToFloat(values[i]); } } @@ -341,7 +332,7 @@ void TestManager::SetLutData_y(FP_LONG values[], unsigned long count) { SetLutSize(count); for (unsigned long i = 0; i < count; i++) { - g_LutData_y[i] = values[i]; + accelParams.lut_data_y[i] = values[i]; function.params->lutDataY[i] = FP64_ToFloat(values[i]); } } @@ -417,6 +408,6 @@ void TestManager::SetLutData(float values_x[], float values_y[], unsigned long c } float TestManager::EvalFloatFunc(float x) { - function.params->accelMode = static_cast(g_AccelerationMode); + function.params->accelMode = static_cast(accelParams.acceleration_mode); return function.EvalFuncAt(x); }