#define _GNU_SOURCE #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-evdev.h" #include "rcm-server-lirc.h" #include "rcm-server-rcdev.h" #include "rcm-server-udev.h" static void udev_device_remove(struct manager *mgr, struct udev_device *udev) { const char *name; struct rc_device *rcdev; name = udev_device_get_sysname(udev); printf("Asked to remove device %s\n", name); list_for_each_entry(rcdev, &mgr->rc_devs, list) { if (strcmp(rcdev->name, name)) continue; sd_bus_emit_object_removed(mgr->bus, rcdev->path); rcdev_free(rcdev); mgr->num_rc_devs--; break; } } static void udev_device_add(struct manager *mgr, struct udev_device *udev) { const char *name; const char *tmpstr; struct rc_device *rcdev; struct udev_enumerate *enumerate; struct udev_list_entry *devices, *dev_list_entry; int r; name = udev_device_get_sysname(udev); if (!name) return; rcdev = rcdev_create(mgr, name); if (!rcdev) return; enumerate = udev_enumerate_new(mgr->udev); udev_enumerate_add_match_parent(enumerate, udev); udev_enumerate_add_match_sysname(enumerate, "event*"); udev_enumerate_add_match_sysname(enumerate, "lirc*"); udev_enumerate_scan_devices(enumerate); devices = udev_enumerate_get_list_entry(enumerate); udev_list_entry_foreach(dev_list_entry, devices) { const char *path; struct udev_device *udev_dev; const char *devnode; const char *subsys; path = udev_list_entry_get_name(dev_list_entry); if (!path) { printf("Failed to get udev name\n"); continue; } udev_dev = udev_device_new_from_syspath(mgr->udev, path); if (!udev_dev) { printf("Failed to create udev device\n"); continue; } devnode = udev_device_get_devnode(udev_dev); if (!devnode) { printf("Failed to determine udev_dev devnode\n"); goto next; } subsys = udev_device_get_subsystem(udev_dev); if (!subsys) { printf("Failed to determine udev_dev subsystem\n"); goto next; } if (!strcmp(subsys, "input")) { r = evdev_setup(rcdev, devnode); if (r < 0) { printf("Failed to setup evdev: %s\n", devnode); rcdev->error = "Error: Failed to setup evdev"; goto next; } } else if (!strcmp(subsys, "lirc")) { r = lirc_setup(rcdev, devnode); if (r < 0) { printf("Failed to setup lirc: %s\n", devnode); rcdev->error = "Error: Failed to setup lirc"; goto next; } } else { printf("Unknown subsystem, ignored %s\n", devnode); goto next; } next: udev_device_unref(udev_dev); } udev_enumerate_unref(enumerate); tmpstr = udev_device_get_devnode(udev); if (tmpstr) { r = rcdev_setup(rcdev, tmpstr); if (r < 0) { printf("Failed to setup rcdev: %s\n", tmpstr); rcdev->error = "Error: Failed to setup rcdev"; } } tmpstr = udev_device_get_sysattr_value(udev, "uevent"); if (tmpstr) { char tmp[strlen(tmpstr) + 1]; char *token; strcpy(tmp, tmpstr); for (token = strtok(tmp, "\n"); token; token = strtok(NULL, "\n")) { if (!strncmp(token, "DRV_NAME=", strlen("DRV_NAME="))) rcdev->driver_name = strdup(token + strlen("DRV_NAME=")); else if (!strncmp(token, "NAME=", strlen("NAME="))) rcdev->keymap_name = strdup(token + strlen("NAME=")); else if (!strncmp(token, "DEVNAME=", strlen("DEVNAME="))) continue; else if (!strncmp(token, "MAJOR=", strlen("MAJOR="))) continue; else if (!strncmp(token, "MINOR=", strlen("MINOR="))) continue; else printf("Unused uevent: %s\n", token); } } printf("Adding Device Object\n"); printf("\tPath : %s\n", udev_device_get_syspath(udev)); printf("\tNode : %s\n", udev_device_get_devnode(udev)); printf("\tSubsystem : %s\n", udev_device_get_subsystem(udev)); printf("\tDevtype : %s\n", udev_device_get_devtype(udev)); printf("\tAction : %s\n", udev_device_get_action(udev)); printf("\tName : %s\n", rcdev->name); printf("\tInput name: %s\n", rcdev->input_name); printf("\tDriver : %s\n", rcdev->driver_name); printf("\tKernel map: %s\n", rcdev->keymap_name); printf("\trcdev fd : %i\n", rcdev->rcdev_fd); printf("\tevdev fd : %i\n", rcdev->evdev_fd); printf("\tLIRC fd : %i\n", rcdev->lirc_fd); printf("\tDBUS path : %s\n", rcdev->path); printf("\tProtocols : %s\n", udev_device_get_sysattr_value(udev, "protocols")); list_add(&rcdev->list, &mgr->rc_devs); mgr->num_rc_devs++; sd_bus_emit_object_added(mgr->bus, rcdev->path); } static int udev_read(sd_event_source *s, int fd, uint32_t revents, void *userdata) { struct manager *mgr = userdata; struct udev_device *udev_dev; if (revents & EPOLLHUP) { fprintf(stderr, "udev connection closed!\n"); return 0; } if (!(revents & EPOLLIN)) { fprintf(stderr, "unexpected udev event: %" PRIu32 "\n", revents); return 0; } while ((udev_dev = udev_monitor_receive_device(mgr->udev_mon))) { printf("Read device: %s\n", udev_device_get_syspath(udev_dev)); if (!strcmp(udev_device_get_action(udev_dev), "add")) udev_device_add(mgr, udev_dev); else if (!strcmp(udev_device_get_action(udev_dev), "remove")) udev_device_remove(mgr, udev_dev); udev_device_unref(udev_dev); } return 1; } int udev_setup(struct manager *mgr) { struct udev_enumerate *enumerate; struct udev_list_entry *devices, *dev_list_entry; struct udev_device *udev_dev; mgr->udev = udev_new(); if (!mgr->udev) return -ENOMEM; mgr->udev_mon = udev_monitor_new_from_netlink(mgr->udev, "udev"); udev_monitor_filter_add_match_subsystem_devtype(mgr->udev_mon, "rc", NULL); udev_monitor_enable_receiving(mgr->udev_mon); enumerate = udev_enumerate_new(mgr->udev); udev_enumerate_add_match_subsystem(enumerate, "rc"); udev_enumerate_scan_devices(enumerate); devices = udev_enumerate_get_list_entry(enumerate); udev_list_entry_foreach(dev_list_entry, devices) { const char *path; path = udev_list_entry_get_name(dev_list_entry); if (!path) { printf("Failed to get udev name\n"); continue; } udev_dev = udev_device_new_from_syspath(mgr->udev, path); if (!udev_dev) { printf("Failed to create udev device\n"); continue; } udev_device_add(mgr, udev_dev); udev_device_unref(udev_dev); } udev_enumerate_unref(enumerate); return sd_event_add_io(mgr->event, &mgr->udev_ev, udev_monitor_get_fd(mgr->udev_mon), EPOLLIN, udev_read, mgr); } void udev_close(struct manager *mgr) { if (!mgr) return; udev_monitor_unref(mgr->udev_mon); udev_unref(mgr->udev); }