diff options
Diffstat (limited to 'rcm-server-rcdev.c')
-rw-r--r-- | rcm-server-rcdev.c | 279 |
1 files changed, 279 insertions, 0 deletions
diff --git a/rcm-server-rcdev.c b/rcm-server-rcdev.c new file mode 100644 index 0000000..82fa8ed --- /dev/null +++ b/rcm-server-rcdev.c @@ -0,0 +1,279 @@ +#define _GNU_SOURCE +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <stdbool.h> +#include <stdint.h> +#include <inttypes.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <sys/ioctl.h> +#include <string.h> +#include <errno.h> + +#include "utils.h" +#include "shared.h" +#include "rcm-server-main.h" +#include "rcm-server-keymap.h" +#include "rcm-server-lirc.h" +#include "rcm-server-evdev.h" +#include "rcm-server-rcdev.h" + +struct rc_event { + uint16_t type; + uint16_t code; + uint32_t val; +} __attribute__((packed)); + +/* rc_event.type value */ +#define RC_DEBUG 0x0 +#define RC_CORE 0x1 +#define RC_KEY 0x2 +#define RC_IR 0x3 + +/* RC_CORE codes */ +#define RC_CORE_DROPPED 0x0 + +/* RC_KEY codes */ +#define RC_KEY_REPEAT 0x0 +#define RC_KEY_PROTOCOL 0x1 +#define RC_KEY_SCANCODE 0x2 +#define RC_KEY_SCANCODE_PART 0x3 +#define RC_KEY_TOGGLE 0x4 + +/* RC_IR codes */ +#define RC_IR_SPACE 0x0 +#define RC_IR_PULSE 0x1 +#define RC_IR_START 0x2 +#define RC_IR_STOP 0x3 +#define RC_IR_RESET 0x4 +#define RC_IR_CARRIER 0x5 +#define RC_IR_DUTY_CYCLE 0x6 + +static int +rcdev_read(sd_event_source *s, int fd, uint32_t revents, void *userdata) +{ + struct rc_device *rcdev = userdata; + + if (fd != rcdev->rcdev_fd) + fprintf(stderr, "rcdev fd mismatch: %i != %i\n", rcdev->rcdev_fd, fd); + + if (revents & EPOLLHUP) { + fprintf(stderr, "rcdev connection closed!\n"); + rcdev_close(rcdev); + return 0; + } + + if (!(revents & EPOLLIN)) { + fprintf(stderr, "unexpected rcdev event: %" PRIu32 "\n", revents); + return 0; + } + + while (true) { + struct rc_event ev; + ssize_t r; + + r = read(rcdev->rcdev_fd, &ev, sizeof(ev)); + if (r < 0) { + fprintf(stderr, "rcdev read failed: %s\n", strerror(errno)); + break; + } + + if (r != sizeof(ev)) { + fprintf(stderr, "rcdev read failed, got %zi bytes, expected %zu\n", r, sizeof(ev)); + break; + } + + printf("rcdev event - type "); + switch (ev.type) { + case RC_DEBUG: + printf("RC_DEBUG; code 0x%0" PRIx16 "; val 0x%0" PRIx32 "\n", + ev.code, ev.val); + break; + + case RC_CORE: + printf("RC_CORE; code "); + if (ev.code == RC_CORE_DROPPED) + printf("RC_CORE_DROPPED"); + else + printf("UNKNOWN (0x%0" PRIx16 ")", ev.code); + printf("; val 0x%0" PRIx32 "\n", ev.val); + break; + + case RC_KEY: + printf("RC_KEY; code "); + switch (ev.code) { + case RC_KEY_REPEAT: + printf("RC_KEY_REPEAT"); + break; + case RC_KEY_PROTOCOL: + printf("RC_KEY_PROTOCOL"); + break; + case RC_KEY_SCANCODE: + printf("RC_KEY_SCANCODE"); + break; + case RC_KEY_SCANCODE_PART: + printf("RC_KEY_SCANCODE_PART"); + break; + case RC_KEY_TOGGLE: + printf("RC_KEY_TOGGLE"); + break; + default: + printf("UNKNOWN (0x%0" PRIx16 ")", ev.code); + break; + } + printf("; val 0x%0" PRIx32 "\n", ev.val); + break; + + case RC_IR: + printf("RC_IR; code "); + switch (ev.code) { + case RC_IR_SPACE: + printf("RC_IR_SPACE"); + break; + case RC_IR_PULSE: + printf("RC_IR_PULSE"); + break; + case RC_IR_START: + printf("RC_IR_START"); + break; + case RC_IR_STOP: + printf("RC_IR_STOP"); + break; + case RC_IR_RESET: + printf("RC_IR_RESET"); + break; + case RC_IR_CARRIER: + printf("RC_IR_CARRIER"); + break; + case RC_IR_DUTY_CYCLE: + printf("RC_IR_DUTY_CYCLE"); + break; + default: + printf("UNKNOWN (0x%0" PRIx16 ")", ev.code); + break; + } + printf("; val 0x%0" PRIx32 "\n", ev.val); + break; + + default: + printf("type UNKNOWN (0x%0" PRIx16 "); code 0x%0" PRIx16 "; val 0x%0" PRIx32 "\n", + ev.type, ev.code, ev.val); + break; + } + } + + return 0; +} + +struct rc_device * +rcdev_create(struct manager *mgr, const char *name) +{ + struct rc_device *rcdev; + + if (!name) + return NULL; + + rcdev = malloc(sizeof(*rcdev)); + if (!rcdev) { + fprintf(stderr, "malloc failed: %m\n"); + return NULL; + } + + if (asprintf(&rcdev->path, "/org/gnome/RemoteControlManager/%s", name) < 0) { + fprintf(stderr, "asprintf failed: %m\n"); + free(rcdev); + return NULL; + } + + list_init(&rcdev->keymaps); + rcdev->mgr = mgr; + rcdev->name = rcdev->path + strlen("/org/gnome/RemoteControlManager/"); + rcdev->rcdev_fd = -1; + rcdev->evdev_fd = -1; + rcdev->lirc_fd = -1; + rcdev->error = NULL; + rcdev->input_name = NULL; + rcdev->driver_name = NULL; + rcdev->keymap_name = NULL; + + if (keymaps_load(rcdev) < 0) { + fprintf(stderr, "failed to load keymaps: %m\n"); + rcdev_free(rcdev); + return NULL; + } + + return rcdev; +} + +void +rcdev_free(struct rc_device *rcdev) +{ + if (!rcdev) + return; + + list_del(&rcdev->list); + lirc_close(rcdev); + evdev_close(rcdev); + rcdev_close(rcdev); + + free(rcdev->path); + free(rcdev->input_name); + free(rcdev->driver_name); + free(rcdev->keymap_name); + + while (!list_empty(&rcdev->keymaps)) { + struct keymap *keymap = list_first_entry(&rcdev->keymaps, typeof(*keymap), list); + list_del(&keymap->list); + free(keymap->name); + free(keymap); + } + + free(rcdev); +} + +int +rcdev_setup(struct rc_device *rcdev, const char *path) +{ + int r; + + if (!rcdev) + return -EINVAL; + + if (rcdev->rcdev_fd >= 0) { + printf("Multiple rcdev devices!?\n"); + return 0; + } + + rcdev->rcdev_fd = open(path, O_RDONLY | O_NONBLOCK); + if (rcdev->rcdev_fd < 0) { + printf("Failed to open rcdev device %s: %s\n", path, strerror(errno)); + return -errno; + } + + if (sd_event_add_io(rcdev->mgr->event, &rcdev->rcdev_ev, + rcdev->rcdev_fd, EPOLLIN, rcdev_read, rcdev) < 0) { + printf("Failed to add event source for rcdev device %s: %s\n", + path, strerror(errno)); + r = -errno; + rcdev_close(rcdev); + return r; + } + + return 0; +} + +void +rcdev_close(struct rc_device *rcdev) +{ + if (!rcdev) + return; + + if (rcdev->rcdev_fd < 0) + return; + + close(rcdev->rcdev_fd); + rcdev->rcdev_fd = -1; +} + |