276 lines
8.6 KiB
Nix
276 lines
8.6 KiB
Nix
# NixOS module for maccel mouse acceleration driver
|
|
{
|
|
config,
|
|
lib,
|
|
pkgs,
|
|
...
|
|
}:
|
|
with lib; let
|
|
cfg = config.hardware.maccel;
|
|
|
|
# Extract version from PKGBUILD
|
|
pkgbuildContent = builtins.readFile ./PKGBUILD;
|
|
kernelModuleVersion = builtins.head (builtins.match ".*pkgver=([^[:space:]]+).*" pkgbuildContent);
|
|
|
|
# Extract version from cli/Cargo.toml
|
|
cliCargoToml = builtins.fromTOML (builtins.readFile ./cli/Cargo.toml);
|
|
cliVersion = cliCargoToml.package.version;
|
|
|
|
# Convert float to fixed-point integer (64-bit, 32 fractional bits)
|
|
fixedPointScale = 4294967296; # 2^32
|
|
toFixedPoint = value: builtins.floor (value * fixedPointScale + 0.5);
|
|
|
|
# Mode enum mapping (from driver/accel/mode.h)
|
|
modeMap = {
|
|
linear = 0;
|
|
natural = 1;
|
|
synchronous = 2;
|
|
no_accel = 3;
|
|
};
|
|
|
|
# Parameter mapping (from driver/params.h)
|
|
parameterMap = {
|
|
# Common parameters
|
|
SENS_MULT = cfg.parameters.sensMultiplier;
|
|
YX_RATIO = cfg.parameters.yxRatio;
|
|
INPUT_DPI = cfg.parameters.inputDpi;
|
|
ANGLE_ROTATION = cfg.parameters.angleRotation;
|
|
MODE = cfg.parameters.mode;
|
|
|
|
# Linear mode parameters
|
|
ACCEL = cfg.parameters.acceleration;
|
|
OFFSET = cfg.parameters.offset;
|
|
OUTPUT_CAP = cfg.parameters.outputCap;
|
|
|
|
# Natural mode parameters
|
|
DECAY_RATE = cfg.parameters.decayRate;
|
|
LIMIT = cfg.parameters.limit;
|
|
|
|
# Synchronous mode parameters
|
|
GAMMA = cfg.parameters.gamma;
|
|
SMOOTH = cfg.parameters.smooth;
|
|
MOTIVITY = cfg.parameters.motivity;
|
|
SYNC_SPEED = cfg.parameters.syncSpeed;
|
|
};
|
|
|
|
# Generate modprobe parameter string
|
|
kernelModuleParams = let
|
|
validParams = filterAttrs (_: v: v != null) parameterMap;
|
|
formatParam = name: value:
|
|
if name == "MODE"
|
|
then "${name}=${toString (modeMap.${value})}"
|
|
else "${name}=${toString (toFixedPoint value)}";
|
|
in
|
|
concatStringsSep " " (mapAttrsToList formatParam validParams);
|
|
|
|
# Build kernel module
|
|
maccel-kernel-module = config.boot.kernelPackages.callPackage ({
|
|
lib,
|
|
stdenv,
|
|
kernel,
|
|
}:
|
|
stdenv.mkDerivation rec {
|
|
pname = "maccel-dkms";
|
|
version = kernelModuleVersion;
|
|
|
|
src = ./.;
|
|
|
|
nativeBuildInputs = kernel.moduleBuildDependencies;
|
|
|
|
makeFlags =
|
|
[
|
|
"KVER=${kernel.modDirVersion}"
|
|
"KDIR=${kernel.dev}/lib/modules/${kernel.modDirVersion}/build"
|
|
"DRIVER_CFLAGS=-DFIXEDPT_BITS=64"
|
|
]
|
|
++ optionals cfg.debug ["DRIVER_CFLAGS+=-g -DDEBUG"];
|
|
|
|
preBuild = "cd driver";
|
|
|
|
installPhase = ''
|
|
mkdir -p $out/lib/modules/${kernel.modDirVersion}/kernel/drivers/usb
|
|
cp maccel.ko $out/lib/modules/${kernel.modDirVersion}/kernel/drivers/usb/
|
|
'';
|
|
|
|
meta = with lib; {
|
|
description = "Mouse acceleration driver and kernel module for Linux.";
|
|
homepage = "https://www.maccel.org/";
|
|
license = licenses.gpl2Plus;
|
|
platforms = platforms.linux;
|
|
};
|
|
}) {};
|
|
|
|
# Optional CLI tools
|
|
maccel-cli = pkgs.rustPlatform.buildRustPackage rec {
|
|
pname = "maccel-cli";
|
|
version = cliVersion;
|
|
|
|
src = ./.;
|
|
|
|
cargoLock.lockFile = "${src}/Cargo.lock";
|
|
|
|
cargoBuildFlags = ["--bin" "maccel"];
|
|
|
|
meta = with lib; {
|
|
description = "CLI and TUI tools for configuring maccel.";
|
|
homepage = "https://www.maccel.org/";
|
|
license = licenses.gpl2Plus;
|
|
platforms = platforms.linux;
|
|
};
|
|
};
|
|
in {
|
|
options.hardware.maccel = {
|
|
enable = mkEnableOption "Enable maccel mouse acceleration driver (kernel module). Parameters must be configured via `hardware.maccel.parameters`.";
|
|
|
|
debug = mkOption {
|
|
type = types.bool;
|
|
default = false;
|
|
description = "Enable debug build of the kernel module.";
|
|
};
|
|
|
|
enableCli = mkOption {
|
|
type = types.bool;
|
|
default = false;
|
|
description = "Install CLI and TUI tools for real-time parameter tuning. You may add your user to the `maccel` group using `users.groups.maccel.members = [\"your_username\"];` to run maccel CLI/TUI without sudo. Note: Changes made via CLI/TUI are temporary and do not persist across reboots. Use this to discover optimal parameter values, then apply them permanently via `hardware.maccel.parameters`.";
|
|
};
|
|
|
|
parameters = {
|
|
# Common parameters
|
|
sensMultiplier = mkOption {
|
|
type = types.nullOr types.float;
|
|
default = null;
|
|
description = "Sensitivity multiplier applied after acceleration calculation.";
|
|
};
|
|
|
|
yxRatio = mkOption {
|
|
type = types.nullOr types.float;
|
|
default = null;
|
|
description = "Y/X ratio - factor by which Y-axis sensitivity is multiplied.";
|
|
};
|
|
|
|
inputDpi = mkOption {
|
|
type =
|
|
types.nullOr (types.addCheck types.float (x: x > 0.0)
|
|
// {description = "positive float";});
|
|
default = null;
|
|
description = "DPI of the mouse, used to normalize effective DPI. Must be positive.";
|
|
};
|
|
|
|
angleRotation = mkOption {
|
|
type = types.nullOr types.float;
|
|
default = null;
|
|
description = "Apply rotation in degrees to mouse movement input.";
|
|
};
|
|
|
|
mode = mkOption {
|
|
type = types.nullOr (types.enum ["linear" "natural" "synchronous" "no_accel"]);
|
|
default = null;
|
|
description = "Acceleration mode.";
|
|
};
|
|
|
|
# Linear mode parameters
|
|
acceleration = mkOption {
|
|
type = types.nullOr types.float;
|
|
default = null;
|
|
description = "Linear acceleration factor.";
|
|
};
|
|
|
|
offset = mkOption {
|
|
type =
|
|
types.nullOr (types.addCheck types.float (x: x >= 0.0)
|
|
// {description = "non-negative float";});
|
|
default = null;
|
|
description = "Input speed past which to allow acceleration. Cannot be negative.";
|
|
};
|
|
|
|
outputCap = mkOption {
|
|
type = types.nullOr types.float;
|
|
default = null;
|
|
description = "Maximum sensitivity multiplier cap.";
|
|
};
|
|
|
|
# Natural mode parameters
|
|
decayRate = mkOption {
|
|
type =
|
|
types.nullOr (types.addCheck types.float (x: x > 0.0)
|
|
// {description = "positive float";});
|
|
default = null;
|
|
description = "Decay rate of the Natural acceleration curve. Must be positive.";
|
|
};
|
|
|
|
limit = mkOption {
|
|
type =
|
|
types.nullOr (types.addCheck types.float (x: x >= 1.0)
|
|
// {description = "float >= 1.0";});
|
|
default = null;
|
|
description = "Limit of the Natural acceleration curve. Cannot be less than 1.";
|
|
};
|
|
|
|
# Synchronous mode parameters
|
|
gamma = mkOption {
|
|
type =
|
|
types.nullOr (types.addCheck types.float (x: x > 0.0)
|
|
// {description = "positive float";});
|
|
default = null;
|
|
description = "Controls how fast you get from low to fast around the midpoint. Must be positive.";
|
|
};
|
|
|
|
smooth = mkOption {
|
|
type =
|
|
types.nullOr (types.addCheck types.float (x: x >= 0.0 && x <= 1.0)
|
|
// {description = "float between 0.0 and 1.0";});
|
|
default = null;
|
|
description = "Controls the suddenness of the sensitivity increase. Must be between 0 and 1.";
|
|
};
|
|
|
|
motivity = mkOption {
|
|
type =
|
|
types.nullOr (types.addCheck types.float (x: x > 1.0)
|
|
// {description = "float > 1.0";});
|
|
default = null;
|
|
description = "Sets max sensitivity while setting min to 1/motivity. Must be greater than 1.";
|
|
};
|
|
|
|
syncSpeed = mkOption {
|
|
type =
|
|
types.nullOr (types.addCheck types.float (x: x > 0.0)
|
|
// {description = "positive float";});
|
|
default = null;
|
|
description = "Sets the middle sensitivity between min and max sensitivity. Must be positive.";
|
|
};
|
|
};
|
|
};
|
|
|
|
config = mkIf cfg.enable {
|
|
# Add kernel module
|
|
boot.extraModulePackages = [maccel-kernel-module];
|
|
|
|
# Load module with parameters
|
|
boot.kernelModules = ["maccel"];
|
|
boot.extraModprobeConfig = mkIf (kernelModuleParams != "") ''
|
|
options maccel ${kernelModuleParams}
|
|
'';
|
|
|
|
# Create maccel group
|
|
users.groups.maccel = {};
|
|
|
|
# Install CLI tools if requested
|
|
environment.systemPackages = mkIf cfg.enableCli [maccel-cli];
|
|
|
|
# Create reset scripts directory
|
|
systemd.tmpfiles.rules = mkIf cfg.enableCli [
|
|
"d /var/opt/maccel/resets 0775 root maccel"
|
|
];
|
|
|
|
# Add udev rules
|
|
services.udev.extraRules = mkIf cfg.enableCli ''
|
|
# Set sysfs parameter permissions
|
|
ACTION=="add", SUBSYSTEM=="module", DEVPATH=="/module/maccel", \
|
|
RUN+="${pkgs.coreutils}/bin/chgrp -R maccel /sys/module/maccel/parameters"
|
|
# Set /dev/maccel character device permissions
|
|
ACTION=="add", KERNEL=="maccel", \
|
|
GROUP="maccel", MODE="0640"
|
|
'';
|
|
};
|
|
}
|