| summaryrefslogtreecommitdiff |
diff options
Diffstat (limited to 'src/device/physical_device.c')
| -rw-r--r-- | src/device/physical_device.c | 276 |
1 files changed, 276 insertions, 0 deletions
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; +} |


