113 lines
2.6 KiB
C
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;
|
|
}
|
|
}
|