Initial commit
This commit is contained in:
218
libazeron/device.c
Normal file
218
libazeron/device.c
Normal file
@@ -0,0 +1,218 @@
|
||||
/*
|
||||
* Azeron Linux Configuration Library - Device Communication
|
||||
* Copyright (C) 2024 Azeron Linux Project
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include "azeron.h"
|
||||
#include "internal.h"
|
||||
#include <libusb-1.0/libusb.h>
|
||||
#include <string.h>
|
||||
|
||||
/* Claim device interfaces */
|
||||
int azeron_device_claim(struct azeron_device *device)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (!device || !device->handle) {
|
||||
return AZERON_ERROR_INVALID_PARAM;
|
||||
}
|
||||
|
||||
if (device->claimed) {
|
||||
return AZERON_SUCCESS;
|
||||
}
|
||||
|
||||
pthread_mutex_lock(&device->mutex);
|
||||
|
||||
/* Claim all interfaces - the device has 5 interfaces (0-4) */
|
||||
for (int i = 0; i <= 4; i++) {
|
||||
ret = libusb_claim_interface(device->handle, i);
|
||||
if (ret < 0) {
|
||||
AZERON_ERROR("Failed to claim interface %d: %s", i, azeron_usb_error_string(ret));
|
||||
|
||||
/* Release already claimed interfaces */
|
||||
for (int j = 0; j < i; j++) {
|
||||
libusb_release_interface(device->handle, j);
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&device->mutex);
|
||||
return azeron_libusb_to_azeron_error(ret);
|
||||
}
|
||||
}
|
||||
|
||||
device->claimed = true;
|
||||
pthread_mutex_unlock(&device->mutex);
|
||||
|
||||
AZERON_LOG("Device interfaces claimed");
|
||||
|
||||
return AZERON_SUCCESS;
|
||||
}
|
||||
|
||||
/* Release device interfaces */
|
||||
int azeron_device_release(struct azeron_device *device)
|
||||
{
|
||||
int ret;
|
||||
int overall_ret = AZERON_SUCCESS;
|
||||
|
||||
if (!device || !device->handle) {
|
||||
return AZERON_ERROR_INVALID_PARAM;
|
||||
}
|
||||
|
||||
if (!device->claimed) {
|
||||
return AZERON_SUCCESS;
|
||||
}
|
||||
|
||||
pthread_mutex_lock(&device->mutex);
|
||||
|
||||
/* Release all interfaces */
|
||||
for (int i = 0; i <= 4; i++) {
|
||||
ret = libusb_release_interface(device->handle, i);
|
||||
if (ret < 0) {
|
||||
AZERON_ERROR("Failed to release interface %d: %s", i, azeron_usb_error_string(ret));
|
||||
overall_ret = azeron_libusb_to_azeron_error(ret);
|
||||
}
|
||||
}
|
||||
|
||||
device->claimed = false;
|
||||
pthread_mutex_unlock(&device->mutex);
|
||||
|
||||
AZERON_LOG("Device interfaces released");
|
||||
|
||||
return overall_ret;
|
||||
}
|
||||
|
||||
/* Read data from endpoint */
|
||||
int azeron_device_read(struct azeron_device *device, uint8_t endpoint, uint8_t *data, size_t size, int timeout)
|
||||
{
|
||||
int transferred;
|
||||
int ret;
|
||||
|
||||
if (!device || !device->handle || !data) {
|
||||
return AZERON_ERROR_INVALID_PARAM;
|
||||
}
|
||||
|
||||
if (!device->claimed) {
|
||||
ret = azeron_device_claim(device);
|
||||
if (ret != AZERON_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
pthread_mutex_lock(&device->mutex);
|
||||
|
||||
ret = libusb_interrupt_transfer(device->handle, endpoint, data, size, &transferred, timeout);
|
||||
|
||||
pthread_mutex_unlock(&device->mutex);
|
||||
|
||||
if (ret < 0) {
|
||||
AZERON_ERROR("Failed to read from endpoint 0x%02x: %s", endpoint, azeron_usb_error_string(ret));
|
||||
return azeron_libusb_to_azeron_error(ret);
|
||||
}
|
||||
|
||||
AZERON_LOG("Read %d bytes from endpoint 0x%02x", transferred, endpoint);
|
||||
|
||||
return transferred;
|
||||
}
|
||||
|
||||
/* Write data to endpoint */
|
||||
int azeron_device_write(struct azeron_device *device, uint8_t endpoint, const uint8_t *data, size_t size, int timeout)
|
||||
{
|
||||
int transferred;
|
||||
int ret;
|
||||
|
||||
if (!device || !device->handle || !data) {
|
||||
return AZERON_ERROR_INVALID_PARAM;
|
||||
}
|
||||
|
||||
if (!device->claimed) {
|
||||
ret = azeron_device_claim(device);
|
||||
if (ret != AZERON_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
pthread_mutex_lock(&device->mutex);
|
||||
|
||||
ret = libusb_interrupt_transfer(device->handle, endpoint, (uint8_t *)data, size, &transferred, timeout);
|
||||
|
||||
pthread_mutex_unlock(&device->mutex);
|
||||
|
||||
if (ret < 0) {
|
||||
AZERON_ERROR("Failed to write to endpoint 0x%02x: %s", endpoint, azeron_usb_error_string(ret));
|
||||
return azeron_libusb_to_azeron_error(ret);
|
||||
}
|
||||
|
||||
AZERON_LOG("Wrote %d bytes to endpoint 0x%02x", transferred, endpoint);
|
||||
|
||||
return transferred;
|
||||
}
|
||||
|
||||
/* Perform control transfer */
|
||||
int azeron_device_control_transfer(struct azeron_device *device, uint8_t request_type, uint8_t request,
|
||||
uint16_t value, uint16_t index, uint8_t *data, size_t size, int timeout)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (!device || !device->handle) {
|
||||
return AZERON_ERROR_INVALID_PARAM;
|
||||
}
|
||||
|
||||
if (!device->claimed) {
|
||||
ret = azeron_device_claim(device);
|
||||
if (ret != AZERON_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
pthread_mutex_lock(&device->mutex);
|
||||
|
||||
ret = libusb_control_transfer(device->handle, request_type, request, value, index, data, size, timeout);
|
||||
|
||||
pthread_mutex_unlock(&device->mutex);
|
||||
|
||||
if (ret < 0) {
|
||||
AZERON_ERROR("Control transfer failed: %s", azeron_usb_error_string(ret));
|
||||
return azeron_libusb_to_azeron_error(ret);
|
||||
}
|
||||
|
||||
AZERON_LOG("Control transfer: %d bytes transferred", ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Get button type string */
|
||||
const char *azeron_button_type_string(enum azeron_button_type type)
|
||||
{
|
||||
switch (type) {
|
||||
case AZERON_BTN_KEYBOARD:
|
||||
return "keyboard";
|
||||
case AZERON_BTN_MOUSE:
|
||||
return "mouse";
|
||||
case AZERON_BTN_GAMEPAD:
|
||||
return "gamepad";
|
||||
case AZERON_BTN_MACRO:
|
||||
return "macro";
|
||||
case AZERON_BTN_LAYER_SWITCH:
|
||||
return "layer_switch";
|
||||
default:
|
||||
return "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
/* Get stick mode string */
|
||||
const char *azeron_stick_mode_string(enum azeron_stick_mode mode)
|
||||
{
|
||||
switch (mode) {
|
||||
case AZERON_STICK_ANALOG:
|
||||
return "analog";
|
||||
case AZERON_STICK_DIGITAL_4:
|
||||
return "digital_4";
|
||||
case AZERON_STICK_DIGITAL_8:
|
||||
return "digital_8";
|
||||
case AZERON_STICK_MOUSE:
|
||||
return "mouse";
|
||||
default:
|
||||
return "unknown";
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user