Files
Xenia-Canary/src/xenia/hid/skylander/skylander_hardware.cc
Gliniak 7298536d46 [HID] Added support for Xbox 360 Skylanders Portal
- This requires Zadig for installation of WinUSB driver for portal
2025-04-14 21:44:49 +02:00

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