1c0abf9e6Sopenharmony_ci// SPDX-License-Identifier: MIT 2c0abf9e6Sopenharmony_ci/* 3c0abf9e6Sopenharmony_ci * Copyright © 2013 Red Hat, Inc. 4c0abf9e6Sopenharmony_ci */ 5c0abf9e6Sopenharmony_ci 6c0abf9e6Sopenharmony_ci#include "config.h" 7c0abf9e6Sopenharmony_ci#include <fcntl.h> 8c0abf9e6Sopenharmony_ci#include <poll.h> 9c0abf9e6Sopenharmony_ci#include <unistd.h> 10c0abf9e6Sopenharmony_ci#include <string.h> 11c0abf9e6Sopenharmony_ci#include <stdio.h> 12c0abf9e6Sopenharmony_ci#include <errno.h> 13c0abf9e6Sopenharmony_ci#include <linux/uinput.h> 14c0abf9e6Sopenharmony_ci#include <dirent.h> 15c0abf9e6Sopenharmony_ci 16c0abf9e6Sopenharmony_ci#include <libevdev/libevdev.h> 17c0abf9e6Sopenharmony_ci#include <libevdev/libevdev-int.h> 18c0abf9e6Sopenharmony_ci#include <libevdev/libevdev-util.h> 19c0abf9e6Sopenharmony_ci#include <libevdev/libevdev-uinput.h> 20c0abf9e6Sopenharmony_ci 21c0abf9e6Sopenharmony_ci#include "test-common-uinput.h" 22c0abf9e6Sopenharmony_ci 23c0abf9e6Sopenharmony_ci#define SYS_INPUT_DIR "/sys/class/input" 24c0abf9e6Sopenharmony_ci#define DEV_INPUT_DIR "/dev/input/" 25c0abf9e6Sopenharmony_ci 26c0abf9e6Sopenharmony_cistruct uinput_device 27c0abf9e6Sopenharmony_ci{ 28c0abf9e6Sopenharmony_ci struct libevdev *d; /* lazy, it has all the accessors */ 29c0abf9e6Sopenharmony_ci struct libevdev_uinput *uidev; 30c0abf9e6Sopenharmony_ci int dev_fd; /* open fd to the devnode */ 31c0abf9e6Sopenharmony_ci int uinput_fd; 32c0abf9e6Sopenharmony_ci}; 33c0abf9e6Sopenharmony_ci 34c0abf9e6Sopenharmony_cistruct uinput_device* 35c0abf9e6Sopenharmony_ciuinput_device_new(const char *name) 36c0abf9e6Sopenharmony_ci{ 37c0abf9e6Sopenharmony_ci struct uinput_device *dev; 38c0abf9e6Sopenharmony_ci 39c0abf9e6Sopenharmony_ci dev = calloc(1, sizeof(*dev)); 40c0abf9e6Sopenharmony_ci if (!dev) 41c0abf9e6Sopenharmony_ci return NULL; 42c0abf9e6Sopenharmony_ci 43c0abf9e6Sopenharmony_ci dev->d = libevdev_new(); 44c0abf9e6Sopenharmony_ci dev->dev_fd = -1; 45c0abf9e6Sopenharmony_ci dev->uinput_fd = -1; 46c0abf9e6Sopenharmony_ci 47c0abf9e6Sopenharmony_ci if (name) 48c0abf9e6Sopenharmony_ci libevdev_set_name(dev->d, name); 49c0abf9e6Sopenharmony_ci 50c0abf9e6Sopenharmony_ci return dev; 51c0abf9e6Sopenharmony_ci} 52c0abf9e6Sopenharmony_ci 53c0abf9e6Sopenharmony_ciint 54c0abf9e6Sopenharmony_ciuinput_device_new_with_events_v(struct uinput_device **d, const char *name, const struct input_id *id, va_list args) 55c0abf9e6Sopenharmony_ci{ 56c0abf9e6Sopenharmony_ci int rc; 57c0abf9e6Sopenharmony_ci struct uinput_device *dev; 58c0abf9e6Sopenharmony_ci 59c0abf9e6Sopenharmony_ci dev = uinput_device_new(name); 60c0abf9e6Sopenharmony_ci if (!dev) 61c0abf9e6Sopenharmony_ci return -ENOMEM; 62c0abf9e6Sopenharmony_ci if (id != DEFAULT_IDS) 63c0abf9e6Sopenharmony_ci uinput_device_set_ids(dev, id); 64c0abf9e6Sopenharmony_ci 65c0abf9e6Sopenharmony_ci rc = uinput_device_set_event_bits_v(dev, args); 66c0abf9e6Sopenharmony_ci 67c0abf9e6Sopenharmony_ci if (rc == 0) 68c0abf9e6Sopenharmony_ci rc = uinput_device_create(dev); 69c0abf9e6Sopenharmony_ci 70c0abf9e6Sopenharmony_ci if (rc != 0) { 71c0abf9e6Sopenharmony_ci uinput_device_free(dev); 72c0abf9e6Sopenharmony_ci dev = NULL; 73c0abf9e6Sopenharmony_ci } else 74c0abf9e6Sopenharmony_ci *d = dev; 75c0abf9e6Sopenharmony_ci 76c0abf9e6Sopenharmony_ci return rc; 77c0abf9e6Sopenharmony_ci} 78c0abf9e6Sopenharmony_ci 79c0abf9e6Sopenharmony_ciint 80c0abf9e6Sopenharmony_ciuinput_device_new_with_events(struct uinput_device **d, const char *name, const struct input_id *id, ...) 81c0abf9e6Sopenharmony_ci{ 82c0abf9e6Sopenharmony_ci int rc; 83c0abf9e6Sopenharmony_ci va_list args; 84c0abf9e6Sopenharmony_ci 85c0abf9e6Sopenharmony_ci va_start(args, id); 86c0abf9e6Sopenharmony_ci rc = uinput_device_new_with_events_v(d, name, id, args); 87c0abf9e6Sopenharmony_ci va_end(args); 88c0abf9e6Sopenharmony_ci 89c0abf9e6Sopenharmony_ci return rc; 90c0abf9e6Sopenharmony_ci} 91c0abf9e6Sopenharmony_ci 92c0abf9e6Sopenharmony_civoid 93c0abf9e6Sopenharmony_ciuinput_device_free(struct uinput_device *dev) 94c0abf9e6Sopenharmony_ci{ 95c0abf9e6Sopenharmony_ci if (!dev) 96c0abf9e6Sopenharmony_ci return; 97c0abf9e6Sopenharmony_ci 98c0abf9e6Sopenharmony_ci if (dev->uinput_fd != -1) { 99c0abf9e6Sopenharmony_ci (void)ioctl(dev->uinput_fd, UI_DEV_DESTROY, NULL); 100c0abf9e6Sopenharmony_ci close(dev->uinput_fd); 101c0abf9e6Sopenharmony_ci } 102c0abf9e6Sopenharmony_ci if (dev->dev_fd != -1) 103c0abf9e6Sopenharmony_ci close(dev->dev_fd); 104c0abf9e6Sopenharmony_ci libevdev_free(dev->d); 105c0abf9e6Sopenharmony_ci libevdev_uinput_destroy(dev->uidev); 106c0abf9e6Sopenharmony_ci free(dev); 107c0abf9e6Sopenharmony_ci} 108c0abf9e6Sopenharmony_ci 109c0abf9e6Sopenharmony_ciint 110c0abf9e6Sopenharmony_ciuinput_device_get_fd(const struct uinput_device *dev) 111c0abf9e6Sopenharmony_ci{ 112c0abf9e6Sopenharmony_ci return dev->dev_fd; 113c0abf9e6Sopenharmony_ci} 114c0abf9e6Sopenharmony_ci 115c0abf9e6Sopenharmony_ciconst char* 116c0abf9e6Sopenharmony_ciuinput_device_get_devnode(const struct uinput_device *dev) 117c0abf9e6Sopenharmony_ci{ 118c0abf9e6Sopenharmony_ci return libevdev_uinput_get_devnode(dev->uidev); 119c0abf9e6Sopenharmony_ci} 120c0abf9e6Sopenharmony_ci 121c0abf9e6Sopenharmony_ciint 122c0abf9e6Sopenharmony_ciuinput_device_create(struct uinput_device* d) 123c0abf9e6Sopenharmony_ci{ 124c0abf9e6Sopenharmony_ci int rc; 125c0abf9e6Sopenharmony_ci int fd; 126c0abf9e6Sopenharmony_ci const char *devnode; 127c0abf9e6Sopenharmony_ci 128c0abf9e6Sopenharmony_ci fd = open("/dev/uinput", O_RDWR); 129c0abf9e6Sopenharmony_ci if (fd < 0) 130c0abf9e6Sopenharmony_ci goto error; 131c0abf9e6Sopenharmony_ci 132c0abf9e6Sopenharmony_ci d->uinput_fd = fd; 133c0abf9e6Sopenharmony_ci 134c0abf9e6Sopenharmony_ci rc = libevdev_uinput_create_from_device(d->d, fd, &d->uidev); 135c0abf9e6Sopenharmony_ci if (rc != 0) 136c0abf9e6Sopenharmony_ci goto error; 137c0abf9e6Sopenharmony_ci 138c0abf9e6Sopenharmony_ci devnode = libevdev_uinput_get_devnode(d->uidev); 139c0abf9e6Sopenharmony_ci if (devnode == NULL) 140c0abf9e6Sopenharmony_ci goto error; 141c0abf9e6Sopenharmony_ci 142c0abf9e6Sopenharmony_ci d->dev_fd = open(devnode, O_RDWR); 143c0abf9e6Sopenharmony_ci if (d->dev_fd == -1) 144c0abf9e6Sopenharmony_ci goto error; 145c0abf9e6Sopenharmony_ci 146c0abf9e6Sopenharmony_ci /* write abs resolution now */ 147c0abf9e6Sopenharmony_ci if (libevdev_has_event_type(d->d, EV_ABS)) { 148c0abf9e6Sopenharmony_ci int code; 149c0abf9e6Sopenharmony_ci for (code = 0; code < ABS_CNT; code++) { 150c0abf9e6Sopenharmony_ci const struct input_absinfo *abs; 151c0abf9e6Sopenharmony_ci 152c0abf9e6Sopenharmony_ci /* can't change slots */ 153c0abf9e6Sopenharmony_ci if (code == ABS_MT_SLOT) 154c0abf9e6Sopenharmony_ci continue; 155c0abf9e6Sopenharmony_ci 156c0abf9e6Sopenharmony_ci abs = libevdev_get_abs_info(d->d, code); 157c0abf9e6Sopenharmony_ci if (!abs) 158c0abf9e6Sopenharmony_ci continue; 159c0abf9e6Sopenharmony_ci 160c0abf9e6Sopenharmony_ci rc = ioctl(d->dev_fd, EVIOCSABS(code), abs); 161c0abf9e6Sopenharmony_ci if (rc < 0) { 162c0abf9e6Sopenharmony_ci printf("error %s for code %d\n", strerror(-rc), code); 163c0abf9e6Sopenharmony_ci goto error; 164c0abf9e6Sopenharmony_ci } 165c0abf9e6Sopenharmony_ci } 166c0abf9e6Sopenharmony_ci } 167c0abf9e6Sopenharmony_ci 168c0abf9e6Sopenharmony_ci return 0; 169c0abf9e6Sopenharmony_ci 170c0abf9e6Sopenharmony_cierror: 171c0abf9e6Sopenharmony_ci if (d->dev_fd != -1) 172c0abf9e6Sopenharmony_ci close(d->dev_fd); 173c0abf9e6Sopenharmony_ci if (d->uinput_fd != -1) 174c0abf9e6Sopenharmony_ci close(d->uinput_fd); 175c0abf9e6Sopenharmony_ci return -errno; 176c0abf9e6Sopenharmony_ci 177c0abf9e6Sopenharmony_ci} 178c0abf9e6Sopenharmony_ci 179c0abf9e6Sopenharmony_ciint uinput_device_set_name(struct uinput_device *dev, const char *name) 180c0abf9e6Sopenharmony_ci{ 181c0abf9e6Sopenharmony_ci libevdev_set_name(dev->d, name); 182c0abf9e6Sopenharmony_ci return 0; 183c0abf9e6Sopenharmony_ci} 184c0abf9e6Sopenharmony_ci 185c0abf9e6Sopenharmony_ciint uinput_device_set_ids(struct uinput_device *dev, const struct input_id *ids) 186c0abf9e6Sopenharmony_ci{ 187c0abf9e6Sopenharmony_ci libevdev_set_id_product(dev->d, ids->product); 188c0abf9e6Sopenharmony_ci libevdev_set_id_vendor(dev->d, ids->vendor); 189c0abf9e6Sopenharmony_ci libevdev_set_id_bustype(dev->d, ids->bustype); 190c0abf9e6Sopenharmony_ci libevdev_set_id_version(dev->d, ids->version); 191c0abf9e6Sopenharmony_ci return 0; 192c0abf9e6Sopenharmony_ci} 193c0abf9e6Sopenharmony_ci 194c0abf9e6Sopenharmony_ciint 195c0abf9e6Sopenharmony_ciuinput_device_set_bit(struct uinput_device* dev, unsigned int bit) 196c0abf9e6Sopenharmony_ci{ 197c0abf9e6Sopenharmony_ci return libevdev_enable_event_type(dev->d, bit); 198c0abf9e6Sopenharmony_ci} 199c0abf9e6Sopenharmony_ci 200c0abf9e6Sopenharmony_ciint 201c0abf9e6Sopenharmony_ciuinput_device_set_prop(struct uinput_device *dev, unsigned int prop) 202c0abf9e6Sopenharmony_ci{ 203c0abf9e6Sopenharmony_ci return libevdev_enable_property(dev->d, prop); 204c0abf9e6Sopenharmony_ci} 205c0abf9e6Sopenharmony_ci 206c0abf9e6Sopenharmony_ciint 207c0abf9e6Sopenharmony_ciuinput_device_set_event_bit(struct uinput_device* dev, unsigned int type, unsigned int code) 208c0abf9e6Sopenharmony_ci{ 209c0abf9e6Sopenharmony_ci return libevdev_enable_event_code(dev->d, type, code, NULL); 210c0abf9e6Sopenharmony_ci} 211c0abf9e6Sopenharmony_ci 212c0abf9e6Sopenharmony_ciint 213c0abf9e6Sopenharmony_ciuinput_device_set_event_bits_v(struct uinput_device *dev, va_list args) 214c0abf9e6Sopenharmony_ci{ 215c0abf9e6Sopenharmony_ci int type, code; 216c0abf9e6Sopenharmony_ci int rc = 0; 217c0abf9e6Sopenharmony_ci 218c0abf9e6Sopenharmony_ci do { 219c0abf9e6Sopenharmony_ci type = va_arg(args, int); 220c0abf9e6Sopenharmony_ci if (type == -1) 221c0abf9e6Sopenharmony_ci break; 222c0abf9e6Sopenharmony_ci code = va_arg(args, int); 223c0abf9e6Sopenharmony_ci if (code == -1) 224c0abf9e6Sopenharmony_ci break; 225c0abf9e6Sopenharmony_ci rc = libevdev_enable_event_code(dev->d, type, code, NULL); 226c0abf9e6Sopenharmony_ci } while (rc == 0); 227c0abf9e6Sopenharmony_ci 228c0abf9e6Sopenharmony_ci return rc; 229c0abf9e6Sopenharmony_ci} 230c0abf9e6Sopenharmony_ci 231c0abf9e6Sopenharmony_ciint 232c0abf9e6Sopenharmony_ciuinput_device_set_event_bits(struct uinput_device *dev, ...) 233c0abf9e6Sopenharmony_ci{ 234c0abf9e6Sopenharmony_ci int rc; 235c0abf9e6Sopenharmony_ci va_list args; 236c0abf9e6Sopenharmony_ci va_start(args, dev); 237c0abf9e6Sopenharmony_ci rc = uinput_device_set_event_bits_v(dev, args); 238c0abf9e6Sopenharmony_ci va_end(args); 239c0abf9e6Sopenharmony_ci 240c0abf9e6Sopenharmony_ci return rc; 241c0abf9e6Sopenharmony_ci} 242c0abf9e6Sopenharmony_ci 243c0abf9e6Sopenharmony_ciint 244c0abf9e6Sopenharmony_ciuinput_device_set_abs_bit(struct uinput_device* dev, unsigned int code, const struct input_absinfo *absinfo) 245c0abf9e6Sopenharmony_ci{ 246c0abf9e6Sopenharmony_ci return libevdev_enable_event_code(dev->d, EV_ABS, code, absinfo); 247c0abf9e6Sopenharmony_ci} 248c0abf9e6Sopenharmony_ci 249c0abf9e6Sopenharmony_ciint 250c0abf9e6Sopenharmony_ciuinput_device_event(const struct uinput_device *dev, unsigned int type, unsigned int code, int value) 251c0abf9e6Sopenharmony_ci{ 252c0abf9e6Sopenharmony_ci return libevdev_uinput_write_event(dev->uidev, type, code, value); 253c0abf9e6Sopenharmony_ci} 254c0abf9e6Sopenharmony_ci 255c0abf9e6Sopenharmony_ciint uinput_device_event_multiple_v(const struct uinput_device* dev, va_list args) 256c0abf9e6Sopenharmony_ci{ 257c0abf9e6Sopenharmony_ci int type, code, value; 258c0abf9e6Sopenharmony_ci int rc = 0; 259c0abf9e6Sopenharmony_ci 260c0abf9e6Sopenharmony_ci do { 261c0abf9e6Sopenharmony_ci type = va_arg(args, int); 262c0abf9e6Sopenharmony_ci if (type == -1) 263c0abf9e6Sopenharmony_ci break; 264c0abf9e6Sopenharmony_ci code = va_arg(args, int); 265c0abf9e6Sopenharmony_ci if (code == -1) 266c0abf9e6Sopenharmony_ci break; 267c0abf9e6Sopenharmony_ci value = va_arg(args, int); 268c0abf9e6Sopenharmony_ci rc = uinput_device_event(dev, type, code, value); 269c0abf9e6Sopenharmony_ci } while (rc == 0); 270c0abf9e6Sopenharmony_ci 271c0abf9e6Sopenharmony_ci return rc; 272c0abf9e6Sopenharmony_ci} 273c0abf9e6Sopenharmony_ci 274c0abf9e6Sopenharmony_ciint uinput_device_event_multiple(const struct uinput_device* dev, ...) 275c0abf9e6Sopenharmony_ci{ 276c0abf9e6Sopenharmony_ci int rc; 277c0abf9e6Sopenharmony_ci va_list args; 278c0abf9e6Sopenharmony_ci va_start(args, dev); 279c0abf9e6Sopenharmony_ci rc = uinput_device_event_multiple_v(dev, args); 280c0abf9e6Sopenharmony_ci va_end(args); 281c0abf9e6Sopenharmony_ci return rc; 282c0abf9e6Sopenharmony_ci} 283