ratazana/hidraw.c
2025-11-10 04:53:37 -03:00

113 lines
2.6 KiB
C

/**
* Copyright (c) 2025 favewa
* SPDX-License-Identifier: BSD-3-Clause
*/
#include "ratazana.h"
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <stddef.h>
#include <linux/hidraw.h>
#include <sys/ioctl.h>
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;
}
}