121 lines
3.2 KiB
C++
121 lines
3.2 KiB
C++
/**
|
|
******************************************************************************
|
|
* Xenia : Xbox 360 Emulator Research Project *
|
|
******************************************************************************
|
|
* Copyright 2025 Xenia Canary. All rights reserved. *
|
|
* Released under the BSD license - see LICENSE in the root for more details. *
|
|
******************************************************************************
|
|
*/
|
|
|
|
#include "xenia/hid/skylander/skylander_hardware.h"
|
|
|
|
namespace xe {
|
|
namespace hid {
|
|
|
|
SkylanderPortalLibusb::SkylanderPortalLibusb() : SkylanderPortal() {
|
|
libusb_init(&context_);
|
|
}
|
|
|
|
SkylanderPortalLibusb::~SkylanderPortalLibusb() {
|
|
if (handle_) {
|
|
destroy_device();
|
|
}
|
|
|
|
libusb_exit(context_);
|
|
}
|
|
|
|
bool SkylanderPortalLibusb::init_device() {
|
|
if (!context_) {
|
|
return false;
|
|
}
|
|
|
|
libusb_device** devs;
|
|
ssize_t cnt = libusb_get_device_list(context_, &devs);
|
|
if (cnt < 0) {
|
|
// No device available... It might appear later.
|
|
return false;
|
|
}
|
|
|
|
bool device_found = false;
|
|
for (ssize_t i = 0; i < cnt; ++i) {
|
|
libusb_device* dev = devs[i];
|
|
|
|
struct libusb_device_descriptor desc;
|
|
if (libusb_get_device_descriptor(dev, &desc) == 0) {
|
|
// Check if this device matches the target Vendor ID and Product ID
|
|
if (desc.idVendor == portal_vendor_product_id.first &&
|
|
desc.idProduct == portal_vendor_product_id.second) {
|
|
libusb_device_handle* handle;
|
|
if (libusb_open(dev, &handle) == 0) {
|
|
libusb_claim_interface(handle, 0);
|
|
handle_ = reinterpret_cast<uintptr_t*>(handle);
|
|
device_found = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
libusb_free_device_list(devs, 0);
|
|
|
|
return device_found;
|
|
}
|
|
|
|
void SkylanderPortalLibusb::destroy_device() {
|
|
libusb_release_interface(reinterpret_cast<libusb_device_handle*>(handle_), 0);
|
|
libusb_close(reinterpret_cast<libusb_device_handle*>(handle_));
|
|
handle_ = nullptr;
|
|
}
|
|
|
|
X_STATUS SkylanderPortalLibusb::read(std::vector<uint8_t>& data) {
|
|
if (!is_initialized()) {
|
|
if (!init_device()) {
|
|
return X_ERROR_DEVICE_NOT_CONNECTED;
|
|
}
|
|
}
|
|
|
|
if (data.size() > skylander_buffer_size) {
|
|
return X_ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
const int result = libusb_interrupt_transfer(
|
|
reinterpret_cast<libusb_device_handle*>(handle_), read_endpoint,
|
|
data.data(), static_cast<int>(data.size()), nullptr, timeout);
|
|
|
|
if (result == LIBUSB_ERROR_NO_DEVICE) {
|
|
return X_ERROR_DEVICE_NOT_CONNECTED;
|
|
}
|
|
|
|
if (result < 0) {
|
|
destroy_device();
|
|
}
|
|
|
|
return X_ERROR_SUCCESS;
|
|
}
|
|
|
|
X_STATUS SkylanderPortalLibusb::write(std::vector<uint8_t>& data) {
|
|
if (!is_initialized()) {
|
|
if (!init_device()) {
|
|
return X_ERROR_DEVICE_NOT_CONNECTED;
|
|
}
|
|
}
|
|
|
|
if (data.size() > skylander_buffer_size) {
|
|
return X_ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
const int result = libusb_interrupt_transfer(
|
|
reinterpret_cast<libusb_device_handle*>(handle_), write_endpoint,
|
|
data.data(), static_cast<int>(data.size()), nullptr, timeout);
|
|
|
|
if (result == LIBUSB_ERROR_NO_DEVICE) {
|
|
return X_ERROR_DEVICE_NOT_CONNECTED;
|
|
}
|
|
|
|
if (result < 0) {
|
|
destroy_device();
|
|
}
|
|
|
|
return X_ERROR_SUCCESS;
|
|
};
|
|
|
|
} // namespace hid
|
|
} // namespace xe
|