Skip to content

Commit

Permalink
nsyshid: Add infrastructure and support for emulating Skylander Portal (
Browse files Browse the repository at this point in the history
  • Loading branch information
deReeperJosh authored Jun 27, 2024
1 parent f3d2083 commit 93b58ae
Show file tree
Hide file tree
Showing 19 changed files with 1,658 additions and 58 deletions.
4 changes: 4 additions & 0 deletions src/Cafe/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -457,10 +457,14 @@ add_library(CemuCafe
OS/libs/nsyshid/AttachDefaultBackends.cpp
OS/libs/nsyshid/Whitelist.cpp
OS/libs/nsyshid/Whitelist.h
OS/libs/nsyshid/BackendEmulated.cpp
OS/libs/nsyshid/BackendEmulated.h
OS/libs/nsyshid/BackendLibusb.cpp
OS/libs/nsyshid/BackendLibusb.h
OS/libs/nsyshid/BackendWindowsHID.cpp
OS/libs/nsyshid/BackendWindowsHID.h
OS/libs/nsyshid/Skylander.cpp
OS/libs/nsyshid/Skylander.h
OS/libs/nsyskbd/nsyskbd.cpp
OS/libs/nsyskbd/nsyskbd.h
OS/libs/nsysnet/nsysnet.cpp
Expand Down
9 changes: 9 additions & 0 deletions src/Cafe/OS/libs/nsyshid/AttachDefaultBackends.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#include "nsyshid.h"
#include "Backend.h"
#include "BackendEmulated.h"

#if NSYSHID_ENABLE_BACKEND_LIBUSB

Expand Down Expand Up @@ -37,5 +38,13 @@ namespace nsyshid::backend
}
}
#endif // NSYSHID_ENABLE_BACKEND_WINDOWS_HID
// add emulated backend
{
auto backendEmulated = std::make_shared<backend::emulated::BackendEmulated>();
if (backendEmulated->IsInitialisedOk())
{
AttachBackend(backendEmulated);
}
}
}
} // namespace nsyshid::backend
57 changes: 54 additions & 3 deletions src/Cafe/OS/libs/nsyshid/Backend.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,55 @@ namespace nsyshid
/* +0x12 */ uint16be maxPacketSizeTX;
} HID_t;

struct TransferCommand
{
uint8* data;
sint32 length;

TransferCommand(uint8* data, sint32 length)
: data(data), length(length)
{
}
virtual ~TransferCommand() = default;
};

struct ReadMessage final : TransferCommand
{
sint32 bytesRead;

ReadMessage(uint8* data, sint32 length, sint32 bytesRead)
: bytesRead(bytesRead), TransferCommand(data, length)
{
}
using TransferCommand::TransferCommand;
};

struct WriteMessage final : TransferCommand
{
sint32 bytesWritten;

WriteMessage(uint8* data, sint32 length, sint32 bytesWritten)
: bytesWritten(bytesWritten), TransferCommand(data, length)
{
}
using TransferCommand::TransferCommand;
};

struct ReportMessage final : TransferCommand
{
uint8* reportData;
sint32 length;
uint8* originalData;
sint32 originalLength;

ReportMessage(uint8* reportData, sint32 length, uint8* originalData, sint32 originalLength)
: reportData(reportData), length(length), originalData(originalData),
originalLength(originalLength), TransferCommand(reportData, length)
{
}
using TransferCommand::TransferCommand;
};

static_assert(offsetof(HID_t, vendorId) == 0x8, "");
static_assert(offsetof(HID_t, productId) == 0xA, "");
static_assert(offsetof(HID_t, ifIndex) == 0xC, "");
Expand Down Expand Up @@ -69,7 +118,7 @@ namespace nsyshid
ErrorTimeout,
};

virtual ReadResult Read(uint8* data, sint32 length, sint32& bytesRead) = 0;
virtual ReadResult Read(ReadMessage* message) = 0;

enum class WriteResult
{
Expand All @@ -78,7 +127,7 @@ namespace nsyshid
ErrorTimeout,
};

virtual WriteResult Write(uint8* data, sint32 length, sint32& bytesWritten) = 0;
virtual WriteResult Write(WriteMessage* message) = 0;

virtual bool GetDescriptor(uint8 descType,
uint8 descIndex,
Expand All @@ -88,7 +137,7 @@ namespace nsyshid

virtual bool SetProtocol(uint32 ifIndef, uint32 protocol) = 0;

virtual bool SetReport(uint8* reportData, sint32 length, uint8* originalData, sint32 originalLength) = 0;
virtual bool SetReport(ReportMessage* message) = 0;
};

class Backend {
Expand Down Expand Up @@ -121,6 +170,8 @@ namespace nsyshid

std::shared_ptr<Device> FindDevice(std::function<bool(const std::shared_ptr<Device>&)> isWantedDevice);

bool FindDeviceById(uint16 vendorId, uint16 productId);

bool IsDeviceWhitelisted(uint16 vendorId, uint16 productId);

// called from OnAttach() - attach devices that your backend can see here
Expand Down
29 changes: 29 additions & 0 deletions src/Cafe/OS/libs/nsyshid/BackendEmulated.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#include "BackendEmulated.h"
#include "Skylander.h"
#include "config/CemuConfig.h"

namespace nsyshid::backend::emulated
{
BackendEmulated::BackendEmulated()
{
cemuLog_logDebug(LogType::Force, "nsyshid::BackendEmulated: emulated backend initialised");
}

BackendEmulated::~BackendEmulated() = default;

bool BackendEmulated::IsInitialisedOk()
{
return true;
}

void BackendEmulated::AttachVisibleDevices()
{
if (GetConfig().emulated_usb_devices.emulate_skylander_portal && !FindDeviceById(0x1430, 0x0150))
{
cemuLog_logDebug(LogType::Force, "Attaching Emulated Portal");
// Add Skylander Portal
auto device = std::make_shared<SkylanderPortalDevice>();
AttachDevice(device);
}
}
} // namespace nsyshid::backend::emulated
16 changes: 16 additions & 0 deletions src/Cafe/OS/libs/nsyshid/BackendEmulated.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#include "nsyshid.h"
#include "Backend.h"

namespace nsyshid::backend::emulated
{
class BackendEmulated : public nsyshid::Backend {
public:
BackendEmulated();
~BackendEmulated();

bool IsInitialisedOk() override;

protected:
void AttachVisibleDevices() override;
};
} // namespace nsyshid::backend::emulated
36 changes: 15 additions & 21 deletions src/Cafe/OS/libs/nsyshid/BackendLibusb.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -241,11 +241,6 @@ namespace nsyshid::backend::libusb
ret);
return nullptr;
}
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,
desc.idVendor,
desc.idProduct,
Expand Down Expand Up @@ -471,7 +466,7 @@ namespace nsyshid::backend::libusb
return m_libusbHandle != nullptr && m_handleInUseCounter >= 0;
}

Device::ReadResult DeviceLibusb::Read(uint8* data, sint32 length, sint32& bytesRead)
Device::ReadResult DeviceLibusb::Read(ReadMessage* message)
{
auto handleLock = AquireHandleLock();
if (!handleLock->IsValid())
Expand All @@ -488,8 +483,8 @@ namespace nsyshid::backend::libusb
{
ret = libusb_bulk_transfer(handleLock->GetHandle(),
this->m_libusbEndpointIn,
data,
length,
message->data,
message->length,
&actualLength,
timeout);
}
Expand All @@ -500,8 +495,8 @@ namespace nsyshid::backend::libusb
// success
cemuLog_logDebug(LogType::Force, "nsyshid::DeviceLibusb::read(): read {} of {} bytes",
actualLength,
length);
bytesRead = actualLength;
message->length);
message->bytesRead = actualLength;
return ReadResult::Success;
}
cemuLog_logDebug(LogType::Force,
Expand All @@ -510,7 +505,7 @@ namespace nsyshid::backend::libusb
return ReadResult::Error;
}

Device::WriteResult DeviceLibusb::Write(uint8* data, sint32 length, sint32& bytesWritten)
Device::WriteResult DeviceLibusb::Write(WriteMessage* message)
{
auto handleLock = AquireHandleLock();
if (!handleLock->IsValid())
Expand All @@ -520,23 +515,23 @@ namespace nsyshid::backend::libusb
return WriteResult::Error;
}

bytesWritten = 0;
message->bytesWritten = 0;
int actualLength = 0;
int ret = libusb_bulk_transfer(handleLock->GetHandle(),
this->m_libusbEndpointOut,
data,
length,
message->data,
message->length,
&actualLength,
0);

if (ret == 0)
{
// success
bytesWritten = actualLength;
message->bytesWritten = actualLength;
cemuLog_logDebug(LogType::Force,
"nsyshid::DeviceLibusb::write(): wrote {} of {} bytes",
bytesWritten,
length);
message->bytesWritten,
message->length);
return WriteResult::Success;
}
cemuLog_logDebug(LogType::Force,
Expand Down Expand Up @@ -713,8 +708,7 @@ namespace nsyshid::backend::libusb
return true;
}

bool DeviceLibusb::SetReport(uint8* reportData, sint32 length, uint8* originalData,
sint32 originalLength)
bool DeviceLibusb::SetReport(ReportMessage* message)
{
auto handleLock = AquireHandleLock();
if (!handleLock->IsValid())
Expand All @@ -731,8 +725,8 @@ namespace nsyshid::backend::libusb
bRequest,
wValue,
wIndex,
reportData,
length,
message->reportData,
message->length,
timeout);
#endif

Expand Down
6 changes: 3 additions & 3 deletions src/Cafe/OS/libs/nsyshid/BackendLibusb.h
Original file line number Diff line number Diff line change
Expand Up @@ -63,9 +63,9 @@ namespace nsyshid::backend::libusb

bool IsOpened() override;

ReadResult Read(uint8* data, sint32 length, sint32& bytesRead) override;
ReadResult Read(ReadMessage* message) override;

WriteResult Write(uint8* data, sint32 length, sint32& bytesWritten) override;
WriteResult Write(WriteMessage* message) override;

bool GetDescriptor(uint8 descType,
uint8 descIndex,
Expand All @@ -75,7 +75,7 @@ namespace nsyshid::backend::libusb

bool SetProtocol(uint32 ifIndex, uint32 protocol) override;

bool SetReport(uint8* reportData, sint32 length, uint8* originalData, sint32 originalLength) override;
bool SetReport(ReportMessage* message) override;

uint8 m_libusbBusNumber;
uint8 m_libusbDeviceAddress;
Expand Down
34 changes: 17 additions & 17 deletions src/Cafe/OS/libs/nsyshid/BackendWindowsHID.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -196,20 +196,20 @@ namespace nsyshid::backend::windows
return m_hFile != INVALID_HANDLE_VALUE;
}

Device::ReadResult DeviceWindowsHID::Read(uint8* data, sint32 length, sint32& bytesRead)
Device::ReadResult DeviceWindowsHID::Read(ReadMessage* message)
{
bytesRead = 0;
message->bytesRead = 0;
DWORD bt;
OVERLAPPED ovlp = {0};
ovlp.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);

uint8* tempBuffer = (uint8*)malloc(length + 1);
uint8* tempBuffer = (uint8*)malloc(message->length + 1);
sint32 transferLength = 0; // minus report byte

_debugPrintHex("HID_READ_BEFORE", data, length);
_debugPrintHex("HID_READ_BEFORE", message->data, message->length);

cemuLog_logDebug(LogType::Force, "HidRead Begin (Length 0x{:08x})", length);
BOOL readResult = ReadFile(this->m_hFile, tempBuffer, length + 1, &bt, &ovlp);
cemuLog_logDebug(LogType::Force, "HidRead Begin (Length 0x{:08x})", message->length);
BOOL readResult = ReadFile(this->m_hFile, tempBuffer, message->length + 1, &bt, &ovlp);
if (readResult != FALSE)
{
// sometimes we get the result immediately
Expand Down Expand Up @@ -247,7 +247,7 @@ namespace nsyshid::backend::windows
ReadResult result = ReadResult::Success;
if (bt != 0)
{
memcpy(data, tempBuffer + 1, transferLength);
memcpy(message->data, tempBuffer + 1, transferLength);
sint32 hidReadLength = transferLength;

char debugOutput[1024] = {0};
Expand All @@ -257,7 +257,7 @@ namespace nsyshid::backend::windows
}
cemuLog_logDebug(LogType::Force, "HIDRead data: {}", debugOutput);

bytesRead = transferLength;
message->bytesRead = transferLength;
result = ReadResult::Success;
}
else
Expand All @@ -270,19 +270,19 @@ namespace nsyshid::backend::windows
return result;
}

Device::WriteResult DeviceWindowsHID::Write(uint8* data, sint32 length, sint32& bytesWritten)
Device::WriteResult DeviceWindowsHID::Write(WriteMessage* message)
{
bytesWritten = 0;
message->bytesWritten = 0;
DWORD bt;
OVERLAPPED ovlp = {0};
ovlp.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);

uint8* tempBuffer = (uint8*)malloc(length + 1);
memcpy(tempBuffer + 1, data, length);
uint8* tempBuffer = (uint8*)malloc(message->length + 1);
memcpy(tempBuffer + 1, message->data, message->length);
tempBuffer[0] = 0; // report byte?

cemuLog_logDebug(LogType::Force, "HidWrite Begin (Length 0x{:08x})", length);
BOOL writeResult = WriteFile(this->m_hFile, tempBuffer, length + 1, &bt, &ovlp);
cemuLog_logDebug(LogType::Force, "HidWrite Begin (Length 0x{:08x})", message->length);
BOOL writeResult = WriteFile(this->m_hFile, tempBuffer, message->length + 1, &bt, &ovlp);
if (writeResult != FALSE)
{
// sometimes we get the result immediately
Expand Down Expand Up @@ -314,7 +314,7 @@ namespace nsyshid::backend::windows

if (bt != 0)
{
bytesWritten = length;
message->bytesWritten = message->length;
return WriteResult::Success;
}
return WriteResult::Error;
Expand Down Expand Up @@ -407,12 +407,12 @@ namespace nsyshid::backend::windows
return true;
}

bool DeviceWindowsHID::SetReport(uint8* reportData, sint32 length, uint8* originalData, sint32 originalLength)
bool DeviceWindowsHID::SetReport(ReportMessage* message)
{
sint32 retryCount = 0;
while (true)
{
BOOL r = HidD_SetOutputReport(this->m_hFile, reportData, length);
BOOL r = HidD_SetOutputReport(this->m_hFile, message->reportData, message->length);
if (r != FALSE)
break;
Sleep(20); // retry
Expand Down
Loading

0 comments on commit 93b58ae

Please sign in to comment.