Something went wrong. Try again.
(I'm so sorry!) Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204// SPDX-License-Identifier: GPL-2.0-only/* Copyright (c) 2022 Benjamin Tissoires * * This program will morph the Microsoft Surface Dial into a mouse, * and depending on the chosen resolution enable or not the haptic feedback: * - a resolution (-r) of 3600 will report 3600 "ticks" in one full rotation * without haptic feedback * - any other resolution will report N "ticks" in a full rotation with haptic * feedback * * A good default for low resolution haptic scrolling is 72 (1 "tick" every 5 * degrees), and set to 3600 for smooth scrolling. */
#include <assert.h>#include <errno.h>#include <fcntl.h>#include <libgen.h>#include <signal.h>#include <stdbool.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <sys/resource.h>#include <unistd.h>
#include <linux/bpf.h>#include <linux/errno.h>
#include <bpf/bpf.h>#include <bpf/libbpf.h>
#include "hid_surface_dial.skel.h"
static bool running = true;
struct haptic_syscall_args { unsigned int hid; int retval;};
static void int_exit(int sig){ running = false; exit(0);}
static void usage(const char *prog){ fprintf(stderr, "%s: %s [OPTIONS] /sys/bus/hid/devices/0BUS:0VID:0PID:00ID\n\n" " OPTIONS:\n" " -r N\t set the given resolution to the device (number of ticks per 360°)\n\n", __func__, prog); fprintf(stderr, "This program will morph the Microsoft Surface Dial into a mouse,\n" "and depending on the chosen resolution enable or not the haptic feedback:\n" "- a resolution (-r) of 3600 will report 3600 'ticks' in one full rotation\n" " without haptic feedback\n" "- any other resolution will report N 'ticks' in a full rotation with haptic\n" " feedback\n" "\n" "A good default for low resolution haptic scrolling is 72 (1 'tick' every 5\n" "degrees), and set to 3600 for smooth scrolling.\n");}
static int get_hid_id(const char *path){ const char *str_id, *dir; char uevent[1024]; int fd;
memset(uevent, 0, sizeof(uevent)); snprintf(uevent, sizeof(uevent) - 1, "%s/uevent", path);
fd = open(uevent, O_RDONLY | O_NONBLOCK); if (fd < 0) return -ENOENT;
close(fd);
dir = basename((char *)path);
str_id = dir + sizeof("0003:0001:0A37."); return (int)strtol(str_id, NULL, 16);}
static int set_haptic(struct hid_surface_dial *skel, int hid_id){ struct haptic_syscall_args args = { .hid = hid_id, .retval = -1, }; int haptic_fd, err; DECLARE_LIBBPF_OPTS(bpf_test_run_opts, tattr, .ctx_in = &args, .ctx_size_in = sizeof(args), );
haptic_fd = bpf_program__fd(skel->progs.set_haptic); if (haptic_fd < 0) { fprintf(stderr, "can't locate haptic prog: %m\n"); return 1; }
err = bpf_prog_test_run_opts(haptic_fd, &tattr); if (err) { fprintf(stderr, "can't set haptic configuration to hid device %d: %m (err: %d)\n", hid_id, err); return 1; } return 0;}
int main(int argc, char **argv){ struct hid_surface_dial *skel; const char *optstr = "r:"; struct bpf_link *link; const char *sysfs_path; int err, opt, hid_id, resolution = 72;
while ((opt = getopt(argc, argv, optstr)) != -1) { switch (opt) { case 'r': { char *endp = NULL; long l = -1;
if (optarg) { l = strtol(optarg, &endp, 10); if (endp && *endp) l = -1; }
if (l < 0) { fprintf(stderr, "invalid r option %s - expecting a number\n", optarg ? optarg : ""); exit(EXIT_FAILURE); };
resolution = (int) l; break; } default: usage(basename(argv[0])); return 1; } }
if (optind == argc) { usage(basename(argv[0])); return 1; }
sysfs_path = argv[optind]; if (!sysfs_path) { perror("sysfs"); return 1; }
skel = hid_surface_dial__open(); if (!skel) { fprintf(stderr, "%s %s:%d", __func__, __FILE__, __LINE__); return -1; }
hid_id = get_hid_id(sysfs_path); if (hid_id < 0) { fprintf(stderr, "can not open HID device: %m\n"); return 1; }
skel->struct_ops.surface_dial->hid_id = hid_id;
err = hid_surface_dial__load(skel); if (err < 0) { fprintf(stderr, "can not load HID-BPF program: %m\n"); return 1; }
skel->data->resolution = resolution; skel->data->physical = (int)(resolution / 72);
link = bpf_map__attach_struct_ops(skel->maps.surface_dial); if (!link) { fprintf(stderr, "can not attach HID-BPF program: %m\n"); return 1; }
signal(SIGINT, int_exit); signal(SIGTERM, int_exit);
set_haptic(skel, hid_id);
while (running) sleep(1);
hid_surface_dial__destroy(skel);
return 0;}