#define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include #include #include #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; }