nsyshid: Make Libusb the Windows backend (#1471)

This commit is contained in:
Joshua de Reeper 2025-01-12 13:33:24 +00:00 committed by GitHub
parent 8dd809d725
commit 0a59085021
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
15 changed files with 412 additions and 773 deletions

View file

@ -1,7 +1,5 @@
#include "BackendLibusb.h"
#if NSYSHID_ENABLE_BACKEND_LIBUSB
namespace nsyshid::backend::libusb
{
BackendLibusb::BackendLibusb()
@ -16,7 +14,7 @@ namespace nsyshid::backend::libusb
{
m_ctx = nullptr;
cemuLog_logDebug(LogType::Force, "nsyshid::BackendLibusb: failed to initialize libusb, return code: {}",
m_initReturnCode);
m_initReturnCode);
return;
}
@ -35,8 +33,8 @@ namespace nsyshid::backend::libusb
if (ret != LIBUSB_SUCCESS)
{
cemuLog_logDebug(LogType::Force,
"nsyshid::BackendLibusb: failed to register hotplug callback with return code {}",
ret);
"nsyshid::BackendLibusb: failed to register hotplug callback with return code {}",
ret);
}
else
{
@ -53,8 +51,8 @@ namespace nsyshid::backend::libusb
if (ret != 0)
{
cemuLog_logDebug(LogType::Force,
"nsyshid::BackendLibusb: hotplug thread: error handling events: {}",
ret);
"nsyshid::BackendLibusb: hotplug thread: error handling events: {}",
ret);
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
}
}
@ -139,8 +137,8 @@ namespace nsyshid::backend::libusb
case LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED:
{
cemuLog_logDebug(LogType::Force, "nsyshid::BackendLibusb::OnHotplug(): device arrived: {:04x}:{:04x}",
desc.idVendor,
desc.idProduct);
desc.idVendor,
desc.idProduct);
auto device = CheckAndCreateDevice(dev);
if (device != nullptr)
{
@ -167,8 +165,8 @@ namespace nsyshid::backend::libusb
case LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT:
{
cemuLog_logDebug(LogType::Force, "nsyshid::BackendLibusb::OnHotplug(): device left: {:04x}:{:04x}",
desc.idVendor,
desc.idProduct);
desc.idVendor,
desc.idProduct);
auto device = FindLibusbDevice(dev);
if (device != nullptr)
{
@ -204,7 +202,7 @@ namespace nsyshid::backend::libusb
if (ret < 0)
{
cemuLog_logDebug(LogType::Force,
"nsyshid::BackendLibusb::FindLibusbDevice(): failed to get device descriptor");
"nsyshid::BackendLibusb::FindLibusbDevice(): failed to get device descriptor");
return nullptr;
}
uint8 busNumber = libusb_get_bus_number(dev);
@ -269,7 +267,7 @@ namespace nsyshid::backend::libusb
if (desc.idVendor == 0x0e6f && desc.idProduct == 0x0241)
{
cemuLog_logDebug(LogType::Force,
"nsyshid::BackendLibusb::CheckAndCreateDevice(): lego dimensions portal detected");
"nsyshid::BackendLibusb::CheckAndCreateDevice(): lego dimensions portal detected");
}
auto device = std::make_shared<DeviceLibusb>(m_ctx,
desc.idVendor,
@ -446,12 +444,13 @@ namespace nsyshid::backend::libusb
}
this->m_handleInUseCounter = 0;
}
int ret = ClaimAllInterfaces(0);
if (ret != 0)
{
int ret = ClaimAllInterfaces(0);
if (ret != 0)
{
cemuLog_logDebug(LogType::Force, "nsyshid::DeviceLibusb::open(): cannot claim interface");
}
cemuLog_log(LogType::Force, "nsyshid::DeviceLibusb::open(): cannot claim interface for config 0");
return false;
}
}
@ -475,7 +474,7 @@ namespace nsyshid::backend::libusb
{
m_handleInUseCounterDecremented.wait(lock);
}
libusb_release_interface(handle, 0);
ReleaseAllInterfacesForCurrentConfig();
libusb_close(handle);
m_handleInUseCounter = -1;
m_handleInUseCounterDecremented.notify_all();
@ -493,21 +492,26 @@ namespace nsyshid::backend::libusb
if (!handleLock->IsValid())
{
cemuLog_logDebug(LogType::Force,
"nsyshid::DeviceLibusb::read(): cannot read from a non-opened device\n");
"nsyshid::DeviceLibusb::read(): cannot read from a non-opened device\n");
return ReadResult::Error;
}
for (int i = 0; i < m_config_descriptors.size(); i++)
{
ClaimAllInterfaces(i);
}
const unsigned int timeout = 50;
int actualLength = 0;
int ret = 0;
do
{
ret = libusb_bulk_transfer(handleLock->GetHandle(),
this->m_libusbEndpointIn,
message->data,
message->length,
&actualLength,
timeout);
ret = libusb_interrupt_transfer(handleLock->GetHandle(),
this->m_libusbEndpointIn,
message->data,
message->length,
&actualLength,
timeout);
}
while (ret == LIBUSB_ERROR_TIMEOUT && actualLength == 0 && IsOpened());
@ -521,8 +525,8 @@ namespace nsyshid::backend::libusb
return ReadResult::Success;
}
cemuLog_logDebug(LogType::Force,
"nsyshid::DeviceLibusb::read(): failed with error code: {}",
ret);
"nsyshid::DeviceLibusb::read(): failed at endpoint 0x{:02x} with error message: {}", this->m_libusbEndpointIn,
libusb_error_name(ret));
return ReadResult::Error;
}
@ -532,18 +536,23 @@ namespace nsyshid::backend::libusb
if (!handleLock->IsValid())
{
cemuLog_logDebug(LogType::Force,
"nsyshid::DeviceLibusb::write(): cannot write to a non-opened device\n");
"nsyshid::DeviceLibusb::write(): cannot write to a non-opened device\n");
return WriteResult::Error;
}
for (int i = 0; i < m_config_descriptors.size(); i++)
{
ClaimAllInterfaces(i);
}
message->bytesWritten = 0;
int actualLength = 0;
int ret = libusb_bulk_transfer(handleLock->GetHandle(),
this->m_libusbEndpointOut,
message->data,
message->length,
&actualLength,
0);
int ret = libusb_interrupt_transfer(handleLock->GetHandle(),
this->m_libusbEndpointOut,
message->data,
message->length,
&actualLength,
0);
if (ret == 0)
{
@ -556,14 +565,14 @@ namespace nsyshid::backend::libusb
return WriteResult::Success;
}
cemuLog_logDebug(LogType::Force,
"nsyshid::DeviceLibusb::write(): failed with error code: {}",
ret);
"nsyshid::DeviceLibusb::write(): failed with error code: {}",
ret);
return WriteResult::Error;
}
bool DeviceLibusb::GetDescriptor(uint8 descType,
uint8 descIndex,
uint8 lang,
uint16 lang,
uint8* output,
uint32 outputMaxLength)
{
@ -579,7 +588,6 @@ namespace nsyshid::backend::libusb
struct libusb_config_descriptor* conf = nullptr;
libusb_device* dev = libusb_get_device(handleLock->GetHandle());
int ret = libusb_get_active_config_descriptor(dev, &conf);
if (ret == 0)
{
std::vector<uint8> configurationDescriptor(conf->wTotalLength);
@ -656,7 +664,6 @@ namespace nsyshid::backend::libusb
extraReadPointer += bLength;
}
}
for (int endpointIndex = 0; endpointIndex < altsetting.bNumEndpoints; endpointIndex++)
{
// endpoint descriptor
@ -681,24 +688,61 @@ namespace nsyshid::backend::libusb
uint32 bytesWritten = currentWritePtr - &configurationDescriptor[0];
libusb_free_config_descriptor(conf);
cemu_assert_debug(bytesWritten <= conf->wTotalLength);
memcpy(output, &configurationDescriptor[0],
std::min<uint32>(outputMaxLength, bytesWritten));
return true;
}
else
{
cemuLog_logDebug(LogType::Force,
"nsyshid::DeviceLibusb::getDescriptor(): failed to get config descriptor with error code: {}",
ret);
return false;
}
}
else
{
cemu_assert_unimplemented();
uint16 wValue = uint16(descType) << 8 | uint16(descIndex);
// HID Get_Descriptor requests are handled via libusb_control_transfer
int ret = libusb_control_transfer(handleLock->GetHandle(),
LIBUSB_REQUEST_TYPE_STANDARD | LIBUSB_ENDPOINT_IN,
LIBUSB_REQUEST_GET_DESCRIPTOR,
wValue,
lang,
output,
outputMaxLength,
0);
if (ret != outputMaxLength)
{
cemuLog_logDebug(LogType::Force, "nsyshid::DeviceLibusb::GetDescriptor(): Control Transfer Failed: {}", libusb_error_name(ret));
return false;
}
}
return false;
return true;
}
bool DeviceLibusb::SetIdle(uint8 ifIndex,
uint8 reportId,
uint8 duration)
{
auto handleLock = AquireHandleLock();
if (!handleLock->IsValid())
{
cemuLog_log(LogType::Force, "nsyshid::DeviceLibusb::SetIdle(): device is not opened");
return false;
}
uint16 wValue = uint16(duration) << 8 | uint16(reportId);
// HID Set_Idle requests are handled via libusb_control_transfer
int ret = libusb_control_transfer(handleLock->GetHandle(),
LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE | LIBUSB_ENDPOINT_OUT,
HID_CLASS_SET_IDLE, // Defined in HID Class Specific Requests (7.2)
wValue,
ifIndex,
nullptr,
0,
0);
if (ret != 0)
{
cemuLog_logDebug(LogType::Force, "nsyshid::DeviceLibusb::SetIdle(): Control Transfer Failed: {}", libusb_error_name(ret));
return false;
}
return true;
}
template<typename Configs, typename Function>
@ -767,18 +811,22 @@ namespace nsyshid::backend::libusb
cemuLog_logDebug(LogType::Force, "nsyshid::DeviceLibusb::SetProtocol(): device is not opened");
return false;
}
if (m_interfaceIndex != ifIndex)
m_interfaceIndex = ifIndex;
ReleaseAllInterfacesForCurrentConfig();
int ret = libusb_set_configuration(AquireHandleLock()->GetHandle(), protocol);
if (ret == LIBUSB_SUCCESS)
ret = ClaimAllInterfaces(protocol);
int ret = libusb_control_transfer(handleLock->GetHandle(),
LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE | LIBUSB_ENDPOINT_OUT,
HID_CLASS_SET_PROTOCOL, // Defined in HID Class Specific Requests (7.2)
protocol,
ifIndex,
nullptr,
0,
0);
if (ret == LIBUSB_SUCCESS)
return true;
return false;
if (ret != 0)
{
cemuLog_logDebug(LogType::Force, "nsyshid::DeviceLibusb::SetProtocol(): Control Transfer Failed: {}", libusb_error_name(ret));
return false;
}
return true;
}
bool DeviceLibusb::SetReport(ReportMessage* message)
@ -790,18 +838,20 @@ namespace nsyshid::backend::libusb
return false;
}
uint16 wValue = uint16(message->reportType) << 8 | uint16(message->reportId);
int ret = libusb_control_transfer(handleLock->GetHandle(),
LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE | LIBUSB_ENDPOINT_OUT,
LIBUSB_REQUEST_SET_CONFIGURATION,
512,
0,
message->originalData,
message->originalLength,
HID_CLASS_SET_REPORT, // Defined in HID Class Specific Requests (7.2)
wValue,
m_interfaceIndex,
message->data,
uint16(message->length & 0xFFFF),
0);
if (ret != message->originalLength)
if (ret != message->length)
{
cemuLog_logDebug(LogType::Force, "nsyshid::DeviceLibusb::SetReport(): Control Transfer Failed: {}", libusb_error_name(ret));
cemuLog_logDebug(LogType::Force, "nsyshid::DeviceLibusb::SetReport(): Control Transfer Failed at interface {} : {}", m_interfaceIndex, libusb_error_name(ret));
return false;
}
return true;
@ -854,5 +904,3 @@ namespace nsyshid::backend::libusb
return m_handle;
}
} // namespace nsyshid::backend::libusb
#endif // NSYSHID_ENABLE_BACKEND_LIBUSB