mirror of
https://dev.lirent.ru/Vatrog/vm-control-io.git
synced 2026-06-18 00:26:38 +03:00
uinput: configurable device identity with fallback to built-in defaults
Add vmctl_uinput_id and an optional vmctl_config.uinput_id pointer. NULL keeps the built-in identity verbatim; a non-NULL config supplies all numeric fields literally, with the device name suffixed -A/-B for the dual-device mode.
This commit is contained in:
@@ -19,11 +19,20 @@ typedef enum {
|
||||
#define VMCTL_PTR_REL 2 /* uinput: relative mouse */
|
||||
#define VMCTL_PTR_BOTH 3 /* uinput: two devices A=abs B=rel */
|
||||
|
||||
typedef struct {
|
||||
unsigned bustype; /* HID bus type, e.g. 0x0003 (USB) */
|
||||
unsigned vendor; /* vendor id */
|
||||
unsigned product; /* product id */
|
||||
unsigned version; /* device version */
|
||||
const char* name; /* device name; library copies it */
|
||||
} vmctl_uinput_id;
|
||||
|
||||
typedef struct {
|
||||
vmctl_driver driver;
|
||||
const char* qmp_path; /* QMP unix socket; required for QMP, optional (passthrough) for UINPUT */
|
||||
const char* input_bus; /* virtio-input-host-pci bus "pci.0" for passthrough; "" = none */
|
||||
int ptr_mode; /* UINPUT VMCTL_PTR_*; 0 for QMP */
|
||||
const vmctl_uinput_id* uinput_id; /* UINPUT only; NULL = built-in defaults */
|
||||
} vmctl_config;
|
||||
|
||||
vmctl_t* vmctl_open (const vmctl_config* cfg); /* NULL on error */
|
||||
|
||||
@@ -50,7 +50,7 @@ static void emit(int fd, uint16_t type, uint16_t code, int32_t val) {
|
||||
|
||||
static void syn(int fd) { emit(fd, EV_SYN, SYN_REPORT, 0); }
|
||||
|
||||
static int uinput_create(int rel_motion, const char* name, char evdev[64]) {
|
||||
static int uinput_create(int rel_motion, const vmctl_uinput_id* id, const char* name, char evdev[64]) {
|
||||
int fd = open("/dev/uinput", O_RDWR | O_CLOEXEC);
|
||||
if (fd < 0) return -1;
|
||||
|
||||
@@ -89,10 +89,10 @@ static int uinput_create(int rel_motion, const char* name, char evdev[64]) {
|
||||
|
||||
struct uinput_setup us;
|
||||
memset(&us, 0, sizeof us);
|
||||
us.id.bustype = HWID_BUS;
|
||||
us.id.vendor = HWID_VENDOR;
|
||||
us.id.product = HWID_PRODUCT;
|
||||
us.id.version = HWID_VERSION;
|
||||
us.id.bustype = (uint16_t)id->bustype;
|
||||
us.id.vendor = (uint16_t)id->vendor;
|
||||
us.id.product = (uint16_t)id->product;
|
||||
us.id.version = (uint16_t)id->version;
|
||||
strncpy(us.name, name, sizeof us.name - 1);
|
||||
|
||||
if (ioctl(fd, UI_DEV_SETUP, &us) < 0 || ioctl(fd, UI_DEV_CREATE) < 0) {
|
||||
@@ -201,13 +201,38 @@ vmctl_t* vmctl_open_uinput_driver(const vmctl_config* cfg) {
|
||||
v->ui_fd_a = -1;
|
||||
v->ui_fd_b = -1;
|
||||
|
||||
/* HID identity: NULL config selects the built-in defaults verbatim; a
|
||||
* non-NULL config supplies all numeric fields literally (zeros included). */
|
||||
const vmctl_uinput_id DEFAULT_ID = {
|
||||
HWID_BUS, HWID_VENDOR, HWID_PRODUCT, HWID_VERSION, HWID_NAME_A
|
||||
};
|
||||
const vmctl_uinput_id* id = cfg->uinput_id ? cfg->uinput_id : &DEFAULT_ID;
|
||||
|
||||
/* Base name: caller's non-empty name, else NULL = use default A/B names. */
|
||||
const char* base = (cfg->uinput_id && cfg->uinput_id->name && cfg->uinput_id->name[0])
|
||||
? cfg->uinput_id->name : NULL;
|
||||
|
||||
/* A/B suffix is added by the library only when two devices are created
|
||||
* (VMCTL_PTR_BOTH) and only over a caller-supplied base name. */
|
||||
char name_a[UINPUT_MAX_NAME_SIZE];
|
||||
char name_b[UINPUT_MAX_NAME_SIZE];
|
||||
const char* dev_a = base ? base : HWID_NAME_A;
|
||||
const char* dev_b = HWID_NAME_B;
|
||||
if (cfg->ptr_mode == VMCTL_PTR_BOTH && base) {
|
||||
int base_max = (int)(sizeof name_a - 1 /*NUL*/ - 2 /*"-A"*/);
|
||||
snprintf(name_a, sizeof name_a, "%.*s-A", base_max, base);
|
||||
snprintf(name_b, sizeof name_b, "%.*s-B", base_max, base);
|
||||
dev_a = name_a;
|
||||
dev_b = name_b;
|
||||
}
|
||||
|
||||
char evdev_a[64], evdev_b[64];
|
||||
int rel_a = (cfg->ptr_mode == VMCTL_PTR_REL);
|
||||
v->ui_fd_a = uinput_create(rel_a, HWID_NAME_A, evdev_a);
|
||||
v->ui_fd_a = uinput_create(rel_a, id, dev_a, evdev_a);
|
||||
if (v->ui_fd_a < 0) { free(v); return NULL; }
|
||||
|
||||
if (cfg->ptr_mode == VMCTL_PTR_BOTH) {
|
||||
v->ui_fd_b = uinput_create(1, HWID_NAME_B, evdev_b);
|
||||
v->ui_fd_b = uinput_create(1, id, dev_b, evdev_b);
|
||||
if (v->ui_fd_b < 0) {
|
||||
ioctl(v->ui_fd_a, UI_DEV_DESTROY);
|
||||
close(v->ui_fd_a);
|
||||
|
||||
Reference in New Issue
Block a user