| 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; +} | 


