mirror of
https://github.com/cemu-project/Cemu.git
synced 2024-11-25 18:46:55 +01:00
nsyshid: Add SetProtocol and SetReport support for libusb backend (#1243)
This commit is contained in:
parent
64b0b85ed5
commit
5209677f2f
@ -135,7 +135,7 @@ namespace nsyshid
|
|||||||
uint8* output,
|
uint8* output,
|
||||||
uint32 outputMaxLength) = 0;
|
uint32 outputMaxLength) = 0;
|
||||||
|
|
||||||
virtual bool SetProtocol(uint32 ifIndef, uint32 protocol) = 0;
|
virtual bool SetProtocol(uint8 ifIndex, uint8 protocol) = 0;
|
||||||
|
|
||||||
virtual bool SetReport(ReportMessage* message) = 0;
|
virtual bool SetReport(ReportMessage* message) = 0;
|
||||||
};
|
};
|
||||||
|
@ -230,6 +230,17 @@ namespace nsyshid::backend::libusb
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::pair<int, ConfigDescriptor> MakeConfigDescriptor(libusb_device* device, uint8 config_num)
|
||||||
|
{
|
||||||
|
libusb_config_descriptor* descriptor = nullptr;
|
||||||
|
const int ret = libusb_get_config_descriptor(device, config_num, &descriptor);
|
||||||
|
if (ret == LIBUSB_SUCCESS)
|
||||||
|
return {ret, ConfigDescriptor{descriptor, libusb_free_config_descriptor}};
|
||||||
|
|
||||||
|
return {ret, ConfigDescriptor{nullptr, [](auto) {
|
||||||
|
}}};
|
||||||
|
}
|
||||||
|
|
||||||
std::shared_ptr<Device> BackendLibusb::CheckAndCreateDevice(libusb_device* dev)
|
std::shared_ptr<Device> BackendLibusb::CheckAndCreateDevice(libusb_device* dev)
|
||||||
{
|
{
|
||||||
struct libusb_device_descriptor desc;
|
struct libusb_device_descriptor desc;
|
||||||
@ -241,6 +252,25 @@ namespace nsyshid::backend::libusb
|
|||||||
ret);
|
ret);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
std::vector<ConfigDescriptor> config_descriptors{};
|
||||||
|
for (uint8 i = 0; i < desc.bNumConfigurations; ++i)
|
||||||
|
{
|
||||||
|
auto [ret, config_descriptor] = MakeConfigDescriptor(dev, i);
|
||||||
|
if (ret != LIBUSB_SUCCESS || !config_descriptor)
|
||||||
|
{
|
||||||
|
cemuLog_log(LogType::Force, "Failed to make config descriptor {} for {:04x}:{:04x}: {}",
|
||||||
|
i, desc.idVendor, desc.idProduct, libusb_error_name(ret));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
config_descriptors.emplace_back(std::move(config_descriptor));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (desc.idVendor == 0x0e6f && desc.idProduct == 0x0241)
|
||||||
|
{
|
||||||
|
cemuLog_logDebug(LogType::Force,
|
||||||
|
"nsyshid::BackendLibusb::CheckAndCreateDevice(): lego dimensions portal detected");
|
||||||
|
}
|
||||||
auto device = std::make_shared<DeviceLibusb>(m_ctx,
|
auto device = std::make_shared<DeviceLibusb>(m_ctx,
|
||||||
desc.idVendor,
|
desc.idVendor,
|
||||||
desc.idProduct,
|
desc.idProduct,
|
||||||
@ -248,7 +278,8 @@ namespace nsyshid::backend::libusb
|
|||||||
2,
|
2,
|
||||||
0,
|
0,
|
||||||
libusb_get_bus_number(dev),
|
libusb_get_bus_number(dev),
|
||||||
libusb_get_device_address(dev));
|
libusb_get_device_address(dev),
|
||||||
|
std::move(config_descriptors));
|
||||||
// figure out device endpoints
|
// figure out device endpoints
|
||||||
if (!FindDefaultDeviceEndpoints(dev,
|
if (!FindDefaultDeviceEndpoints(dev,
|
||||||
device->m_libusbHasEndpointIn,
|
device->m_libusbHasEndpointIn,
|
||||||
@ -330,7 +361,8 @@ namespace nsyshid::backend::libusb
|
|||||||
uint8 interfaceSubClass,
|
uint8 interfaceSubClass,
|
||||||
uint8 protocol,
|
uint8 protocol,
|
||||||
uint8 libusbBusNumber,
|
uint8 libusbBusNumber,
|
||||||
uint8 libusbDeviceAddress)
|
uint8 libusbDeviceAddress,
|
||||||
|
std::vector<ConfigDescriptor> configs)
|
||||||
: Device(vendorId,
|
: Device(vendorId,
|
||||||
productId,
|
productId,
|
||||||
interfaceIndex,
|
interfaceIndex,
|
||||||
@ -346,6 +378,7 @@ namespace nsyshid::backend::libusb
|
|||||||
m_libusbHasEndpointOut(false),
|
m_libusbHasEndpointOut(false),
|
||||||
m_libusbEndpointOut(0)
|
m_libusbEndpointOut(0)
|
||||||
{
|
{
|
||||||
|
m_config_descriptors = std::move(configs);
|
||||||
}
|
}
|
||||||
|
|
||||||
DeviceLibusb::~DeviceLibusb()
|
DeviceLibusb::~DeviceLibusb()
|
||||||
@ -413,20 +446,8 @@ namespace nsyshid::backend::libusb
|
|||||||
}
|
}
|
||||||
this->m_handleInUseCounter = 0;
|
this->m_handleInUseCounter = 0;
|
||||||
}
|
}
|
||||||
if (libusb_kernel_driver_active(this->m_libusbHandle, 0) == 1)
|
|
||||||
{
|
{
|
||||||
cemuLog_logDebug(LogType::Force, "nsyshid::DeviceLibusb::open(): kernel driver active");
|
int ret = ClaimAllInterfaces(0);
|
||||||
if (libusb_detach_kernel_driver(this->m_libusbHandle, 0) == 0)
|
|
||||||
{
|
|
||||||
cemuLog_logDebug(LogType::Force, "nsyshid::DeviceLibusb::open(): kernel driver detached");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
cemuLog_logDebug(LogType::Force, "nsyshid::DeviceLibusb::open(): failed to detach kernel driver");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
{
|
|
||||||
int ret = libusb_claim_interface(this->m_libusbHandle, 0);
|
|
||||||
if (ret != 0)
|
if (ret != 0)
|
||||||
{
|
{
|
||||||
cemuLog_logDebug(LogType::Force, "nsyshid::DeviceLibusb::open(): cannot claim interface");
|
cemuLog_logDebug(LogType::Force, "nsyshid::DeviceLibusb::open(): cannot claim interface");
|
||||||
@ -680,7 +701,65 @@ namespace nsyshid::backend::libusb
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DeviceLibusb::SetProtocol(uint32 ifIndex, uint32 protocol)
|
template<typename Configs, typename Function>
|
||||||
|
static int DoForEachInterface(const Configs& configs, uint8 config_num, Function action)
|
||||||
|
{
|
||||||
|
int ret = LIBUSB_ERROR_NOT_FOUND;
|
||||||
|
if (configs.size() <= config_num || !configs[config_num])
|
||||||
|
return ret;
|
||||||
|
for (uint8 i = 0; i < configs[config_num]->bNumInterfaces; ++i)
|
||||||
|
{
|
||||||
|
ret = action(i);
|
||||||
|
if (ret < LIBUSB_SUCCESS)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int DeviceLibusb::ClaimAllInterfaces(uint8 config_num)
|
||||||
|
{
|
||||||
|
const int ret = DoForEachInterface(m_config_descriptors, config_num, [this](uint8 i) {
|
||||||
|
if (libusb_kernel_driver_active(this->m_libusbHandle, i))
|
||||||
|
{
|
||||||
|
const int ret2 = libusb_detach_kernel_driver(this->m_libusbHandle, i);
|
||||||
|
if (ret2 < LIBUSB_SUCCESS && ret2 != LIBUSB_ERROR_NOT_FOUND &&
|
||||||
|
ret2 != LIBUSB_ERROR_NOT_SUPPORTED)
|
||||||
|
{
|
||||||
|
cemuLog_log(LogType::Force, "Failed to detach kernel driver {}", libusb_error_name(ret2));
|
||||||
|
return ret2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return libusb_claim_interface(this->m_libusbHandle, i);
|
||||||
|
});
|
||||||
|
if (ret < LIBUSB_SUCCESS)
|
||||||
|
{
|
||||||
|
cemuLog_log(LogType::Force, "Failed to release all interfaces for config {}", config_num);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int DeviceLibusb::ReleaseAllInterfaces(uint8 config_num)
|
||||||
|
{
|
||||||
|
const int ret = DoForEachInterface(m_config_descriptors, config_num, [this](uint8 i) {
|
||||||
|
return libusb_release_interface(AquireHandleLock()->GetHandle(), i);
|
||||||
|
});
|
||||||
|
if (ret < LIBUSB_SUCCESS && ret != LIBUSB_ERROR_NO_DEVICE && ret != LIBUSB_ERROR_NOT_FOUND)
|
||||||
|
{
|
||||||
|
cemuLog_log(LogType::Force, "Failed to release all interfaces for config {}", config_num);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int DeviceLibusb::ReleaseAllInterfacesForCurrentConfig()
|
||||||
|
{
|
||||||
|
int config_num;
|
||||||
|
const int get_config_ret = libusb_get_configuration(AquireHandleLock()->GetHandle(), &config_num);
|
||||||
|
if (get_config_ret < LIBUSB_SUCCESS)
|
||||||
|
return get_config_ret;
|
||||||
|
return ReleaseAllInterfaces(config_num);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DeviceLibusb::SetProtocol(uint8 ifIndex, uint8 protocol)
|
||||||
{
|
{
|
||||||
auto handleLock = AquireHandleLock();
|
auto handleLock = AquireHandleLock();
|
||||||
if (!handleLock->IsValid())
|
if (!handleLock->IsValid())
|
||||||
@ -688,24 +767,18 @@ namespace nsyshid::backend::libusb
|
|||||||
cemuLog_logDebug(LogType::Force, "nsyshid::DeviceLibusb::SetProtocol(): device is not opened");
|
cemuLog_logDebug(LogType::Force, "nsyshid::DeviceLibusb::SetProtocol(): device is not opened");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
if (m_interfaceIndex != ifIndex)
|
||||||
|
m_interfaceIndex = ifIndex;
|
||||||
|
|
||||||
// ToDo: implement this
|
ReleaseAllInterfacesForCurrentConfig();
|
||||||
#if 0
|
int ret = libusb_set_configuration(AquireHandleLock()->GetHandle(), protocol);
|
||||||
// is this correct? Discarding "ifIndex" seems like a bad idea
|
if (ret == LIBUSB_SUCCESS)
|
||||||
int ret = libusb_set_configuration(handleLock->getHandle(), protocol);
|
ret = ClaimAllInterfaces(protocol);
|
||||||
if (ret == 0) {
|
|
||||||
cemuLog_logDebug(LogType::Force,
|
if (ret == LIBUSB_SUCCESS)
|
||||||
"nsyshid::DeviceLibusb::setProtocol(): success");
|
|
||||||
return true;
|
return true;
|
||||||
}
|
|
||||||
cemuLog_logDebug(LogType::Force,
|
|
||||||
"nsyshid::DeviceLibusb::setProtocol(): failed with error code: {}",
|
|
||||||
ret);
|
|
||||||
return false;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// pretend that everything is fine
|
return false;
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DeviceLibusb::SetReport(ReportMessage* message)
|
bool DeviceLibusb::SetReport(ReportMessage* message)
|
||||||
@ -717,20 +790,20 @@ namespace nsyshid::backend::libusb
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ToDo: implement this
|
int ret = libusb_control_transfer(handleLock->GetHandle(),
|
||||||
#if 0
|
LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE | LIBUSB_ENDPOINT_OUT,
|
||||||
// not sure if libusb_control_transfer() is the right candidate for this
|
LIBUSB_REQUEST_SET_CONFIGURATION,
|
||||||
int ret = libusb_control_transfer(handleLock->getHandle(),
|
512,
|
||||||
bmRequestType,
|
0,
|
||||||
bRequest,
|
message->originalData,
|
||||||
wValue,
|
message->originalLength,
|
||||||
wIndex,
|
0);
|
||||||
message->reportData,
|
|
||||||
message->length,
|
|
||||||
timeout);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// pretend that everything is fine
|
if (ret != message->originalLength)
|
||||||
|
{
|
||||||
|
cemuLog_logDebug(LogType::Force, "nsyshid::DeviceLibusb::SetReport(): Control Transfer Failed: {}", libusb_error_name(ret));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -44,6 +44,11 @@ namespace nsyshid::backend::libusb
|
|||||||
bool& endpointOutFound, uint8& endpointOut, uint16& endpointOutMaxPacketSize);
|
bool& endpointOutFound, uint8& endpointOut, uint16& endpointOutMaxPacketSize);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
using UniquePtr = std::unique_ptr<T, void (*)(T*)>;
|
||||||
|
|
||||||
|
using ConfigDescriptor = UniquePtr<libusb_config_descriptor>;
|
||||||
|
|
||||||
class DeviceLibusb : public nsyshid::Device {
|
class DeviceLibusb : public nsyshid::Device {
|
||||||
public:
|
public:
|
||||||
DeviceLibusb(libusb_context* ctx,
|
DeviceLibusb(libusb_context* ctx,
|
||||||
@ -53,7 +58,8 @@ namespace nsyshid::backend::libusb
|
|||||||
uint8 interfaceSubClass,
|
uint8 interfaceSubClass,
|
||||||
uint8 protocol,
|
uint8 protocol,
|
||||||
uint8 libusbBusNumber,
|
uint8 libusbBusNumber,
|
||||||
uint8 libusbDeviceAddress);
|
uint8 libusbDeviceAddress,
|
||||||
|
std::vector<ConfigDescriptor> configs);
|
||||||
|
|
||||||
~DeviceLibusb() override;
|
~DeviceLibusb() override;
|
||||||
|
|
||||||
@ -73,7 +79,11 @@ namespace nsyshid::backend::libusb
|
|||||||
uint8* output,
|
uint8* output,
|
||||||
uint32 outputMaxLength) override;
|
uint32 outputMaxLength) override;
|
||||||
|
|
||||||
bool SetProtocol(uint32 ifIndex, uint32 protocol) override;
|
bool SetProtocol(uint8 ifIndex, uint8 protocol) override;
|
||||||
|
|
||||||
|
int ClaimAllInterfaces(uint8 config_num);
|
||||||
|
int ReleaseAllInterfaces(uint8 config_num);
|
||||||
|
int ReleaseAllInterfacesForCurrentConfig();
|
||||||
|
|
||||||
bool SetReport(ReportMessage* message) override;
|
bool SetReport(ReportMessage* message) override;
|
||||||
|
|
||||||
@ -92,6 +102,7 @@ namespace nsyshid::backend::libusb
|
|||||||
std::atomic<sint32> m_handleInUseCounter;
|
std::atomic<sint32> m_handleInUseCounter;
|
||||||
std::condition_variable m_handleInUseCounterDecremented;
|
std::condition_variable m_handleInUseCounterDecremented;
|
||||||
libusb_device_handle* m_libusbHandle;
|
libusb_device_handle* m_libusbHandle;
|
||||||
|
std::vector<ConfigDescriptor> m_config_descriptors;
|
||||||
|
|
||||||
class HandleLock {
|
class HandleLock {
|
||||||
public:
|
public:
|
||||||
|
@ -400,7 +400,7 @@ namespace nsyshid::backend::windows
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DeviceWindowsHID::SetProtocol(uint32 ifIndef, uint32 protocol)
|
bool DeviceWindowsHID::SetProtocol(uint8 ifIndex, uint8 protocol)
|
||||||
{
|
{
|
||||||
// ToDo: implement this
|
// ToDo: implement this
|
||||||
// pretend that everything is fine
|
// pretend that everything is fine
|
||||||
|
@ -47,7 +47,7 @@ namespace nsyshid::backend::windows
|
|||||||
|
|
||||||
bool GetDescriptor(uint8 descType, uint8 descIndex, uint8 lang, uint8* output, uint32 outputMaxLength) override;
|
bool GetDescriptor(uint8 descType, uint8 descIndex, uint8 lang, uint8* output, uint32 outputMaxLength) override;
|
||||||
|
|
||||||
bool SetProtocol(uint32 ifIndef, uint32 protocol) override;
|
bool SetProtocol(uint8 ifIndex, uint8 protocol) override;
|
||||||
|
|
||||||
bool SetReport(ReportMessage* message) override;
|
bool SetReport(ReportMessage* message) override;
|
||||||
|
|
||||||
|
@ -627,7 +627,7 @@ namespace nsyshid
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SkylanderPortalDevice::SetProtocol(uint32 ifIndex, uint32 protocol)
|
bool SkylanderPortalDevice::SetProtocol(uint8 ifIndex, uint8 protocol)
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -30,7 +30,7 @@ namespace nsyshid
|
|||||||
uint8* output,
|
uint8* output,
|
||||||
uint32 outputMaxLength) override;
|
uint32 outputMaxLength) override;
|
||||||
|
|
||||||
bool SetProtocol(uint32 ifIndex, uint32 protocol) override;
|
bool SetProtocol(uint8 ifIndex, uint8 protocol) override;
|
||||||
|
|
||||||
bool SetReport(ReportMessage* message) override;
|
bool SetReport(ReportMessage* message) override;
|
||||||
|
|
||||||
|
@ -379,8 +379,8 @@ namespace nsyshid
|
|||||||
void export_HIDSetProtocol(PPCInterpreter_t* hCPU)
|
void export_HIDSetProtocol(PPCInterpreter_t* hCPU)
|
||||||
{
|
{
|
||||||
ppcDefineParamU32(hidHandle, 0); // r3
|
ppcDefineParamU32(hidHandle, 0); // r3
|
||||||
ppcDefineParamU32(ifIndex, 1); // r4
|
ppcDefineParamU8(ifIndex, 1); // r4
|
||||||
ppcDefineParamU32(protocol, 2); // r5
|
ppcDefineParamU8(protocol, 2); // r5
|
||||||
ppcDefineParamMPTR(callbackFuncMPTR, 3); // r6
|
ppcDefineParamMPTR(callbackFuncMPTR, 3); // r6
|
||||||
ppcDefineParamMPTR(callbackParamMPTR, 4); // r7
|
ppcDefineParamMPTR(callbackParamMPTR, 4); // r7
|
||||||
cemuLog_logDebug(LogType::Force, "nsyshid.HIDSetProtocol(...)");
|
cemuLog_logDebug(LogType::Force, "nsyshid.HIDSetProtocol(...)");
|
||||||
|
Loading…
Reference in New Issue
Block a user