summaryrefslogtreecommitdiff
path: root/rcm-server-rcdev.c
diff options
context:
space:
mode:
Diffstat (limited to 'rcm-server-rcdev.c')
-rw-r--r--rcm-server-rcdev.c279
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;
+}
+