diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 4497b50799db..5a64a10b06da 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1680,6 +1680,8 @@ static void hid_process_report(struct hid_device *hid, unsigned int a; struct hid_field_entry *entry; struct hid_field *field; + struct input_dev *fastmouse_dev = NULL; + /* first retrieve all incoming values in data */ for (a = 0; a < report->maxfield; a++) @@ -1692,6 +1694,10 @@ static void hid_process_report(struct hid_device *hid, list) { field = entry->field; + if (hid->type == HID_TYPE_USBMOUSE && field->hidinput) { + fastmouse_dev = field->hidinput->input; + } + if (field->flags & HID_MAIN_ITEM_VARIABLE) hid_process_event(hid, field, @@ -1721,6 +1727,13 @@ static void hid_process_report(struct hid_device *hid, hid_input_array_field(hid, field, interrupt); } } + + + if (fastmouse_dev) { + fastmouse_input_emit(fastmouse_dev); + } + + } /* diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c index 9d80635a91eb..56e1bb7b7023 100644 --- a/drivers/hid/hid-input.c +++ b/drivers/hid/hid-input.c @@ -14,6 +14,7 @@ */ #include +#include #include #include @@ -1505,6 +1506,150 @@ static void hid_report_set_tool(struct hid_report *report, struct input_dev *inp report->tool = new_tool; } +struct fastmouse_state { + int division; + long frame_x, frame_y; + long accum_x, accum_y; + int rise, run; + /* TODO + int polling_rate; + long accel; + */ +}; +static struct fastmouse_state fastmouse = { + .division = 1, + .frame_x = 0, + .frame_y = 0, + .accum_x = 0, + .accum_y = 0, + .rise = 0, + .run = INT_MAX, + /* TODO + .polling_rate = 4000, + .accel = 1, + */ +}; + +static int set_division(const char *val, const struct kernel_param *kp) { + const int ret = kstrtoint(val, 0, &fastmouse.division); + if (ret != 0 || fastmouse.division <= 0) { + return -EINVAL; + } + return ret; +} +static const struct kernel_param_ops division_ops = { + .set = set_division, + .get = param_get_int, +}; +module_param_cb(division, &division_ops, &fastmouse.division, 0664); +MODULE_PARM_DESC(division, "Mouse movement division amount (default: 1)"); + +static int set_rise(const char *val, const struct kernel_param *kp) { + const int ret = kstrtoint(val, 0, &fastmouse.rise); + if (ret != 0) { + return -EINVAL; + } + return ret; +} +static const struct kernel_param_ops rise_ops = { + .set = set_rise, + .get = param_get_int, +}; +module_param_cb(rise, &rise_ops, &fastmouse.rise, 0664); +MODULE_PARM_DESC(rise, "Mouse movement rise amount (default: 0)"); + +static int set_run(const char *val, const struct kernel_param *kp) { + const int ret = kstrtoint(val, 0, &fastmouse.run); + if (ret != 0) { + return -EINVAL; + } + return ret; +} +static const struct kernel_param_ops run_ops = { + .set = set_run, + .get = param_get_int, +}; +module_param_cb(run, &run_ops, &fastmouse.run, 0664); +MODULE_PARM_DESC(run, "Mouse movement run amount (default: INT_MAX)"); + +/* TODO +static int set_polling_rate(const char *val, const struct kernel_param *kp) { + const int ret = kstrtoint(val, 0, &fastmouse.polling_rate); + if (ret != 0) { + return -EINVAL; + } + return ret; +} +static const struct kernel_param_ops poll_ops = { + .set = set_polling_rate, + .get = param_get_int, +}; +module_param_cb(polling_rate, &poll_ops, &fastmouse.polling_rate, 0664); +MODULE_PARM_DESC(polling_rate, "Mouse polling rate (default: 4000)"); + +static int set_accel(const char *val, const struct kernel_param *kp) { + const int ret = kstrtol(val, 0, &fastmouse.accel); + if (ret != 0) { + return -EINVAL; + } + return ret; +} +static const struct kernel_param_ops accel_ops = { + .set = set_accel, + .get = param_get_int, +}; +module_param_cb(acceleration, &accel_ops, &fastmouse.accel, 0664); +MODULE_PARM_DESC(acceleration, "Mouse acceleration (default: 1)"); +*/ + +static void input_event_fastmouse_log( + struct input_dev *input, + const unsigned int type, + const unsigned int code, + __s32 value) { + fastmouse.frame_x += (code == REL_X) * value; + fastmouse.frame_y += (code == REL_Y) * value; +} + +/* TODO (for accel) +static unsigned __int128 i128_sqrt(const unsigned __int128 v) { + unsigned __int128 left = 0; + unsigned __int128 right = v; + while (left < right) { + const unsigned __int128 mid = left + ((right - left) / 2); + if (mid >= ~(u64)0 || mid * mid > v) { + right = mid; + } else if (mid * mid == v) { + return mid; + } else { + left = mid + 1; + } + } + return left != 0 ? left - 1 : 0; +} +*/ + +void fastmouse_input_emit(struct input_dev *input) { + const long rise = fastmouse.rise / fastmouse.division; + const long run = fastmouse.run / fastmouse.division; + + fastmouse.accum_x += fastmouse.frame_x * run - fastmouse.frame_y * rise; + fastmouse.accum_y += fastmouse.frame_x * rise + fastmouse.frame_y * run; + + const long emit_x = fastmouse.accum_x / INT_MAX; + if (emit_x != 0) { + input_event(input, EV_REL, REL_X, emit_x); + } + const long emit_y = fastmouse.accum_y / INT_MAX; + if (emit_y != 0) { + input_event(input, EV_REL, REL_Y, emit_y); + } + fastmouse.accum_x %= INT_MAX; + fastmouse.accum_y %= INT_MAX; + + fastmouse.frame_x = fastmouse.frame_y = 0; +} + void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct hid_usage *usage, __s32 value) { struct input_dev *input; @@ -1713,7 +1858,12 @@ void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct (!test_bit(usage->code, input->key)) == value) input_event(input, EV_MSC, MSC_SCAN, usage->hid); - input_event(input, usage->type, usage->code, value); + if (hid->type == HID_TYPE_USBMOUSE && usage->type == EV_REL) { + input_event_fastmouse_log(input, usage->type, usage->code, value); + } else { + input_event(input, usage->type, usage->code, value); + } + if ((field->flags & HID_MAIN_ITEM_RELATIVE) && usage->type == EV_KEY && value) { diff --git a/include/linux/hid.h b/include/linux/hid.h index cdc0dc13c87f..8321d637b112 100644 --- a/include/linux/hid.h +++ b/include/linux/hid.h @@ -940,6 +940,7 @@ extern void hid_unregister_driver(struct hid_driver *); module_driver(__hid_driver, hid_register_driver, \ hid_unregister_driver) +extern void fastmouse_input_emit(struct input_dev *input); extern void hidinput_hid_event(struct hid_device *, struct hid_field *, struct hid_usage *, __s32); extern void hidinput_report_event(struct hid_device *hid, struct hid_report *report); extern int hidinput_connect(struct hid_device *hid, unsigned int force);