/* * Azeron Linux Configuration Library - Device Communication * Copyright (C) 2024 Azeron Linux Project * * SPDX-License-Identifier: MIT */ #include "azeron.h" #include "internal.h" #include #include /* 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"; } }