/** * Copyright (c) 2025 favewa * SPDX-License-Identifier: BSD-3-Clause */ #include "ratazana.h" #include #include #include #include #include #include #include #include #include static constexpr int HID_OPEN_FLAGS = O_RDONLY | O_NONBLOCK; static ratazana_result_t query_hidraw_info(int fd, const char *path, ratazana_hid_device_t *info) { struct hidraw_devinfo devinfo = {0}; if (ioctl(fd, HIDIOCGRAWINFO, &devinfo) < 0) return close(fd), RATAZANA_ERROR_IO; char name[256] = {0}; if (ioctl(fd, HIDIOCGRAWNAME(sizeof(name)), name) < 0) strncpy(name, "Unknown Device", sizeof(name) - 1); *info = (ratazana_hid_device_t){ .vendor_id = devinfo.vendor, .product_id = devinfo.product, .bus_type = devinfo.bustype, }; strncpy(info->path, path, sizeof(info->path) - 1); strncpy(info->name, name, sizeof(info->name) - 1); return close(fd), RATAZANA_OK; } ratazana_result_t ratazana_hid_enumerate(ratazana_hid_device_t *out, ratazana_device_matcher_t match) { if (!out) return RATAZANA_ERROR_INVALID_ARG; DIR *dir = opendir("/dev"); if (dir == nullptr) return RATAZANA_ERROR_IO; struct dirent *entry; ratazana_result_t result = RATAZANA_ERROR_NOT_FOUND; while ((entry = readdir(dir)) != nullptr) { if (strncmp(entry->d_name, "hidraw", 6) != 0) continue; char path[256]; snprintf(path, sizeof(path), "/dev/%s", entry->d_name); int fd = open(path, HID_OPEN_FLAGS); if (fd < 0) continue; ratazana_hid_device_t info = {0}; ratazana_result_t query_result = query_hidraw_info(fd, path, &info); close(fd); if (query_result) continue; if (match == nullptr || match(&info)) return (*out = info), closedir(dir), RATAZANA_OK; } return closedir(dir), result; } ratazana_result_t ratazana_device_open(ratazana_device_t *restrict dev, const char *restrict path, uint8_t device_index) { if (!dev || !path) return RATAZANA_ERROR_INVALID_ARG; dev->fd = open(path, O_RDWR); if (dev->fd < 0) { perror("Failed to open device"); if (errno == EACCES) { fprintf(stderr, "Hint: You may need root privileges or udev rules " "to access this device\n"); return RATAZANA_ERROR_ACCESS; } return RATAZANA_ERROR_IO; } strncpy(dev->path, path, sizeof(dev->path) - 1); dev->idx = device_index; printf("Device opened: %s [idx=0x%02X]\n", path, device_index); return RATAZANA_OK; } void ratazana_device_close(ratazana_device_t *dev) { if (dev != nullptr && dev->fd >= 0) { close(dev->fd); dev->fd = -1; } }