| summaryrefslogtreecommitdiff |
diff options
| author | Nathanael Sensfelder <SpamShield0@MultiAgentSystems.org> | 2019-12-23 15:44:19 +0100 |
|---|---|---|
| committer | Nathanael Sensfelder <SpamShield0@MultiAgentSystems.org> | 2019-12-23 15:44:19 +0100 |
| commit | 390576c3839ee7abb845e27b7267de45495e6b2f (patch) | |
| tree | c481c37c868ccc65a3476f60b17369b21a90b79b /src/device | |
| parent | 4355548f79375a62bb5e3bb5695190d48e4c0bc3 (diff) | |
Starting to turn relabsd into a proper daemon...
Diffstat (limited to 'src/device')
| -rw-r--r-- | src/device/axis/axis_name.c | 302 | ||||
| -rw-r--r-- | src/device/physical_device.c | 276 | ||||
| -rw-r--r-- | src/device/virtual_device.c | 272 |
3 files changed, 850 insertions, 0 deletions
diff --git a/src/device/axis/axis_name.c b/src/device/axis/axis_name.c new file mode 100644 index 0000000..c18a28f --- /dev/null +++ b/src/device/axis/axis_name.c @@ -0,0 +1,302 @@ +/**** LIBEVDEV ****************************************************************/ +#include <libevdev/libevdev.h> + +/**** RELABSD *****************************************************************/ +#include <relabsd/debug.h> + +#include <relabsd/util/string.h> + +#include <relabsd/device/axis.h> + +/******************************************************************************/ +/**** LOCAL FUNCTIONS *********************************************************/ +/******************************************************************************/ + +/******************************************************************************/ +/**** EXPORTED FUNCTIONS ******************************************************/ +/******************************************************************************/ +enum relabsd_axis_name relabsd_axis_parse_name +( + const char name [const restrict static 1] +) +{ + if (RELABSD_STRING_EQUALS("X", name)) + { + return RELABSD_X; + } + else if (RELABSD_STRING_EQUALS("Y", name)) + { + return RELABSD_Y; + } + else if (RELABSD_STRING_EQUALS("Z", name)) + { + return RELABSD_Z; + } + else if (RELABSD_STRING_EQUALS("RX", name)) + { + return RELABSD_RX; + } + else if (RELABSD_STRING_EQUALS("RY", name)) + { + return RELABSD_RY; + } + else if (RELABSD_STRING_EQUALS("RZ", name)) + { + return RELABSD_RZ; + } + else if (RELABSD_STRING_EQUALS("WL", name)) + { + return RELABSD_WHEEL; + } + else if (RELABSD_STRING_EQUALS("MC", name)) + { + return RELABSD_MISC; + } + + return RELABSD_UNKNOWN; +} + +const char * relabsd_axis_name_to_string (const enum relabsd_axis_name e) +{ + switch (e) + { + case RELABSD_X: + return "X"; + + case RELABSD_Y: + return "Y"; + + case RELABSD_Z: + return "Z"; + + case RELABSD_RX: + return "RX"; + + case RELABSD_RY: + return "RY"; + + case RELABSD_RZ: + return "RZ"; + + case RELABSD_WHEEL: + return "WL"; + + case RELABSD_MISC: + return "MC"; + + case RELABSD_UNKNOWN: + return "??"; + + default: + break; + } + + RELABSD_S_PROG_ERROR("relabsd_axis_to_name is missing at least 1 case."); + + return ".."; +} + +enum relabsd_axis_name relabsd_axis_name_and_evdev_abs_from_evdev_rel +( + const unsigned int rel_code, + unsigned int abs_code [const restrict static 1] +) +{ + switch (rel_code) + { + case REL_X: + *abs_code = ABS_X; + return RELABSD_X; + + case REL_Y: + *abs_code = ABS_Y; + return RELABSD_Y; + + case REL_Z: + *abs_code = ABS_Z; + return RELABSD_Z; + + case REL_RX: + *abs_code = ABS_RX; + return RELABSD_RX; + + case REL_RY: + *abs_code = ABS_RY; + return RELABSD_RY; + + case REL_RZ: + *abs_code = ABS_RZ; + return RELABSD_RZ; + + case REL_WHEEL: + *abs_code = ABS_WHEEL; + return RELABSD_WHEEL; + + case REL_MISC: + *abs_code = ABS_MISC; + return RELABSD_MISC; + + default: + return RELABSD_UNKNOWN; + } +} + +unsigned int relabsd_axis_name_to_evdev_rel (const enum relabsd_axis_name e) +{ + switch (e) + { + case RELABSD_X: + return REL_X; + + case RELABSD_Y: + return REL_Y; + + case RELABSD_Z: + return REL_Z; + + case RELABSD_RX: + return REL_RX; + + case RELABSD_RY: + return REL_RY; + + case RELABSD_RZ: + return REL_RZ; + + case RELABSD_WHEEL: + return REL_WHEEL; + + case RELABSD_MISC: + return REL_MISC; + + case RELABSD_UNKNOWN: + RELABSD_S_PROG_ERROR + ( + "relabsd_axis_name_to_evdev_rel(RELABSD_UNKNOWN) is forbidden." + ); + return REL_MAX; + + default: + break; + } + + RELABSD_S_PROG_ERROR + ( + "relabsd_axis_name_to_evdev_rel is missing at least 1 case." + ); + + return REL_MAX; +} + +unsigned int relabsd_axis_name_to_evdev_abs (const enum relabsd_axis_name e) +{ + switch (e) + { + case RELABSD_X: + return ABS_X; + + case RELABSD_Y: + return ABS_Y; + + case RELABSD_Z: + return ABS_Z; + + case RELABSD_RX: + return ABS_RX; + + case RELABSD_RY: + return ABS_RY; + + case RELABSD_RZ: + return ABS_RZ; + + case RELABSD_WHEEL: + return ABS_WHEEL; + + case RELABSD_MISC: + return ABS_MISC; + + case RELABSD_UNKNOWN: + RELABSD_S_PROG_ERROR + ( + "relabsd_axis_to_abs(RELABSD_UNKNOWN) is forbidden." + ); + return ABS_MAX; + + default: + break; + } + + RELABSD_S_PROG_ERROR("relabsd_axis_to_abs is missing at least 1 case."); + + return REL_MAX; +} + +/* + * Returns the relabsd_axis equivalent of a EV_REL/EV_ABS code. + */ +enum relabsd_axis_name relabsd_axis_name_from_evdev_rel (const unsigned int rel) +{ + switch (rel) + { + case REL_X: + return RELABSD_X; + + case REL_Y: + return RELABSD_Y; + + case REL_Z: + return RELABSD_Z; + + case REL_RX: + return RELABSD_RX; + + case REL_RY: + return RELABSD_RY; + + case REL_RZ: + return RELABSD_RZ; + + case REL_WHEEL: + return RELABSD_WHEEL; + + case REL_MISC: + return RELABSD_MISC; + + default: + return RELABSD_UNKNOWN; + } +} + +enum relabsd_axis_name relabsd_axis_name_from_evdev_abs (const unsigned int abs) +{ + switch (abs) + { + case ABS_X: + return RELABSD_X; + + case ABS_Y: + return RELABSD_Y; + + case ABS_Z: + return RELABSD_Z; + + case ABS_RX: + return RELABSD_RX; + + case ABS_RY: + return RELABSD_RY; + + case ABS_RZ: + return RELABSD_RZ; + + case ABS_WHEEL: + return RELABSD_WHEEL; + + case ABS_MISC: + return RELABSD_MISC; + + default: + return RELABSD_UNKNOWN; + } +} diff --git a/src/device/physical_device.c b/src/device/physical_device.c new file mode 100644 index 0000000..a518750 --- /dev/null +++ b/src/device/physical_device.c @@ -0,0 +1,276 @@ +#include <fcntl.h> +#include <errno.h> +#include <string.h> +#include <unistd.h> + +#include <libevdev/libevdev.h> + +#include "error.h" +#include "axis.h" +#include "config.h" + +#include "input.h" + +/* + * Ensures that the input device has enabled the EV_REL axes mentioned + * in the configuration file. + * + * Returns -1 on (fatal) error, + * 0 all configured axes are accounted for. + */ +static int check_for_axes +( + const struct libevdev * const dev, + const struct relabsd_config * const conf +) +{ + int i, device_is_valid; + unsigned int rel_code; + + device_is_valid = 1; + + for (i = RELABSD_VALID_AXES_COUNT; i --> 0;) + { + if (conf->axis[i].enabled) + { + rel_code = relabsd_axis_to_rel((enum relabsd_axis) i); + + if (!libevdev_has_event_code(dev, EV_REL, rel_code)) + { + RELABSD_FATAL + ( + "Input device has no relative %s axis, yet the configuration " + "file asks to convert it.", + relabsd_axis_to_name((enum relabsd_axis) i) + ); + + device_is_valid = 0; + } + } + } + + return (device_is_valid - 1); +} + +/* + * Ensures that the input device is compatible with the config file. + * + * Returns -1 on (fatal) error, + * 0 is the device is compatible. + */ +static int device_is_compatible +( + const struct libevdev * const dev, + const struct relabsd_config * const conf +) +{ + if (!libevdev_has_event_type(dev, EV_REL)) + { + RELABSD_S_FATAL("Input device has no relative axis."); + + return -1; + } + + if (check_for_axes(dev, conf) < 0) + { + return -1; + } + + return 0; +} + +int relabsd_physical_device_open +( + struct relabsd_physical_device * const input, + const struct relabsd_config * const conf +) +{ + RELABSD_S_DEBUG(RELABSD_DEBUG_PROGRAM_FLOW, "Opening input device..."); + + input->fd = open(conf->input_file, O_RDONLY); + + if (input->fd < 0) + { + RELABSD_FATAL + ( + "Could not open device '%s' in read only mode: %s.", + conf->input_file, + strerror(errno) + ); + + return -1; + } + + if + ( + libevdev_new_from_fd(input->fd, &(input->dev)) < 0 + ) + { + RELABSD_FATAL + ( + "libevdev could not open '%s': %s.", + conf->input_file, + strerror(errno) + ); + + close(input->fd); + + return -1; + } + + if (device_is_compatible(input->dev, conf) < 0) + { + return -1; + } + + return 0; +} + +void relabsd_physical_device_close (const struct relabsd_physical_device * const input) +{ + RELABSD_S_DEBUG(RELABSD_DEBUG_PROGRAM_FLOW, "Closing input device..."); + + libevdev_free(input->dev); + close(input->fd); +} + +int relabsd_physical_device_read +( + const struct relabsd_physical_device * const input, + unsigned int * const input_type, + unsigned int * const input_code, + int * const input_value +) +{ + int rc; + struct input_event event; + + /* + if (libevdev_has_event_pending(input->dev) == 0) + { + return -1; + } + */ + rc = + libevdev_next_event + ( + input->dev, + (LIBEVDEV_READ_FLAG_NORMAL | LIBEVDEV_READ_FLAG_BLOCKING), + &event + ); + + /* TODO: Look into LIBEVDEV_READ_STATUS_SYNC, handle it. */ + /* + if (rc == LIBEVDEV_READ_STATUS_SYNC) + { + handle_syn_dropped(input->dev); + } + else + */ + if (rc != LIBEVDEV_READ_STATUS_SUCCESS) + { + RELABSD_WARNING("[INPUT] Could not get next event: %s.", strerror(-rc)); + + return -1; + } + + RELABSD_DEBUG + ( + RELABSD_DEBUG_REAL_EVENTS, + "Valid event received: {type = %s; code = %s; value = %d}.", + libevdev_event_type_get_name(event.type), + libevdev_event_code_get_name(event.type, event.code), + event.value + ); + + *input_type = event.type; + *input_code = event.code; + *input_value = event.value; + + return 0; +} + +int relabsd_physical_device_wait_for_next_event +( + const struct relabsd_physical_device * const input, + const struct relabsd_config * const config +) +{ + int ready_fds; + const int old_errno = errno; + fd_set ready_to_read; + struct timeval curr_timeout; + + FD_ZERO(&ready_to_read); + FD_SET(input->fd, &ready_to_read); + + /* call to select may alter timeout */ + memcpy + ( + (void *) &(curr_timeout), + (const void *) &(config->timeout), + sizeof(struct timeval) + ); + + errno = 0; + + RELABSD_S_ERROR + ( + "Waiting for input to be ready..." + ); + + ready_fds = select + ( + (input->fd + 1), + &ready_to_read, + (fd_set *) NULL, + (fd_set *) NULL, + (input->timed_out) ? NULL : &(curr_timeout) + ); + + if (errno != 0) + { + RELABSD_ERROR + ( + "Unable to wait for timeout: %s (errno: %d).", + strerror(errno), + errno + ); + + if (errno == EINTR) + { + /* Signal interruption? */ + } + else + { + /* TODO: error message */ + } + + errno = old_errno; + + return -1; + } + + if (ready_fds == -1) + { + /* TODO: error message */ + + RELABSD_S_ERROR + ( + "Unable to wait for timeout, yet errno was not set to anything." + ); + + errno = old_errno; + + return -1; + } + + RELABSD_ERROR + ( + "Input is ready, ready_fds = %d", ready_fds + ); + + errno = old_errno; + + return ready_fds; +} diff --git a/src/device/virtual_device.c b/src/device/virtual_device.c new file mode 100644 index 0000000..19d1097 --- /dev/null +++ b/src/device/virtual_device.c @@ -0,0 +1,272 @@ + + +static void replace_rel_axes +( + struct relabsd_virtual_device * const dev, + const struct relabsd_config * const config +) +{ + int i; + struct input_absinfo absinfo; + unsigned int abs_code, rel_code; + + for (i = RELABSD_VALID_AXES_COUNT; i --> 0;) + { + if (config->axis[i].enabled) + { + rel_code = relabsd_axis_to_rel((enum relabsd_axis) i); + abs_code = relabsd_axis_to_abs((enum relabsd_axis) i); + + relabsd_config_get_absinfo(config, (enum relabsd_axis) i, &absinfo); + libevdev_disable_event_code(dev->dev, EV_REL, rel_code); + libevdev_enable_event_code(dev->dev, EV_ABS, abs_code, &absinfo); + } + } + +} + +static int rename_device +( + struct libevdev * const dev, + const struct relabsd_config * const config +) +{ + size_t new_name_size; + char * new_name; + const char * real_name; + + /* +2: One for the \0, one for the space between prefix and 'real_name'. */ + new_name_size = strlen(RELABSD_DEVICE_PREFIX) + 2; + + if (config->device_name == (char *) NULL) + { + /* XXX + * "The name is never NULL but it may be the empty string." + * I'm assuming that since they use the term 'string', it is \0 + * terminated. + */ + real_name = libevdev_get_name(dev); + } + else + { + real_name = config->device_name; + } + + new_name_size += strlen(real_name); + + new_name = (char *) calloc(new_name_size, sizeof(char)); + + if (new_name == (char *) NULL) + { + RELABSD_ERROR + ( + "Attempt at allocating memory to create the virtual device's name " + "failed: %s.", + strerror(errno) + ); + + /* This frees whatever came from 'libevdev_get_name'. */ + libevdev_set_name(dev, RELABSD_DEVICE_PREFIX); + + return -1; + } + + if + ( + snprintf + ( + new_name, + new_name_size, + "%s %s", + RELABSD_DEVICE_PREFIX, + real_name + ) + != ((int) (new_name_size - 1)) + ) + { + /* This makes for a great message when strerror(errno) returns SUCCESS. */ + RELABSD_ERROR + ( + "Something unexpected happened while renaming the virtual device: %s.", + strerror(errno) + ); + + /* This frees whatever came from 'libevdev_get_name'. */ + libevdev_set_name(dev, RELABSD_DEVICE_PREFIX); + + free((void *) new_name); + + return -1; + } + + /* This frees whatever came from 'libevdev_get_name'. */ + libevdev_set_name(dev, new_name); + free((void *) new_name); + + return 0; +} + +int relabsd_virtual_device_create +( + struct relabsd_virtual_device * const dev, + const struct relabsd_config * const config +) +{ + int fd; + + RELABSD_S_DEBUG(RELABSD_DEBUG_PROGRAM_FLOW, "Creating virtual device..."); + + fd = open(config->input_file, O_RDONLY); + + if (fd < 0) + { + RELABSD_FATAL + ( + "Could not open device '%s' in read only mode: %s.", + config->input_file, + strerror(errno) + ); + + return -1; + } + + if (libevdev_new_from_fd(fd, &(dev->dev)) < 0) + { + RELABSD_FATAL + ( + "libevdev could not open '%s': '%s'.", + config->input_file, + strerror(errno) + ); + + close(fd); + + return -1; + } + + if (rename_device(dev->dev, config) < 0) + { + libevdev_free(dev->dev); + close(fd); + + return -1; + } + + libevdev_enable_event_type(dev->dev, EV_ABS); + + replace_rel_axes(dev, config); + + if + ( + libevdev_uinput_create_from_device + ( + dev->dev, + /* See top of the file. */ + RELABSD_UINPUT_OPEN_MANAGED, + &(dev->uidev) + ) + < 0 + ) + { + RELABSD_FATAL("Could not create relabsd device: %s.", strerror(errno)); + + libevdev_free(dev->dev); + + close(fd); + + return -1; + } + + close(fd); + + return 0; +} + +void relabsd_virtual_device_destroy (const struct relabsd_virtual_device * const dev) +{ + RELABSD_S_DEBUG(RELABSD_DEBUG_PROGRAM_FLOW, "Destroying virtual device..."); + + libevdev_uinput_destroy(dev->uidev); + libevdev_free(dev->dev); +} + +int relabsd_virtual_device_write_evdev_event +( + const struct relabsd_virtual_device * const dev, + unsigned int const type, + unsigned int const code, + int const value +) +{ + RELABSD_DEBUG + ( + RELABSD_DEBUG_VIRTUAL_EVENTS, + "Sending event: {type = %s; code = %s; value = %d}.", + libevdev_event_type_get_name(type), + libevdev_event_code_get_name(type, code), + value + ); + + /* + * We'll also send the 'EV_SYN' events when we receive them from the input + * device. + * OPTIMIZE: prevent 'EV_SYN' from being sent if we haven't sent any new + * values. (It might not be worth it though) + */ + if (libevdev_uinput_write_event(dev->uidev, type, code, value) == 0) + { + /* FIXME: + * Why does activating the timeout trigger the EV_KEYS event to not be + * followed by EV_SYN? + */ + if (type == EV_KEY) + { + libevdev_uinput_write_event + ( + dev->uidev, + EV_SYN, + SYN_REPORT, + 0 + ); + } + + return 0; + } + + return -1; +} + +void relabsd_virtual_device_set_axes_to_zero +( + const struct relabsd_virtual_device * const dev, + const struct relabsd_config * const config +) +{ + int i; + + for (i = 0; i < RELABSD_VALID_AXES_COUNT; ++i) + { + if (config->axis[i].enabled) + { + relabsd_virtual_device_write_evdev_event + ( + dev, + EV_ABS, + relabsd_axis_to_abs((enum relabsd_axis) i), + 0 + ); + } + } + + /* + * Also send a SYN event when the axes have been modified. + */ + libevdev_uinput_write_event + ( + dev->uidev, + EV_SYN, + SYN_REPORT, + 0 + ); +} + |


