Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

nsyshid: add backends for cross platform USB passthrough support #950

Merged
merged 3 commits into from
Sep 18, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -232,7 +232,7 @@ jobs:
- name: "Install system dependencies"
run: |
brew update
brew install llvm@15 ninja nasm molten-vk
brew install llvm@15 ninja nasm molten-vk automake libtool

- name: "Bootstrap vcpkg"
run: |
Expand Down
2 changes: 1 addition & 1 deletion BUILD.md
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ You can skip this section if you have an Intel Mac. Every time you compile, you

### Installing dependencies

`brew install boost git cmake llvm ninja nasm molten-vk`
`brew install boost git cmake llvm ninja nasm molten-vk automake libtool`

### Build Cemu using cmake and clang
1. `git clone --recursive https://github.com/cemu-project/Cemu`
Expand Down
17 changes: 17 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,23 @@ if (WIN32)
endif()
option(ENABLE_CUBEB "Enabled cubeb backend" ON)

# usb hid backends
if (WIN32)
option(ENABLE_NSYSHID_WINDOWS_HID "Enables the native Windows HID backend for nsyshid" ON)
endif ()
# libusb and windows hid backends shouldn't be active at the same time; otherwise we'd see all devices twice!
if (NOT ENABLE_NSYSHID_WINDOWS_HID)
option(ENABLE_NSYSHID_LIBUSB "Enables the libusb backend for nsyshid" ON)
else ()
set(ENABLE_NSYSHID_LIBUSB OFF CACHE BOOL "" FORCE)
endif ()
if (ENABLE_NSYSHID_WINDOWS_HID)
add_compile_definitions(NSYSHID_ENABLE_BACKEND_WINDOWS_HID)
endif ()
if (ENABLE_NSYSHID_LIBUSB)
add_compile_definitions(NSYSHID_ENABLE_BACKEND_LIBUSB)
endif ()

option(ENABLE_WXWIDGETS "Build with wxWidgets UI (Currently required)" ON)

set(THREADS_PREFER_PTHREAD_FLAG true)
Expand Down
20 changes: 20 additions & 0 deletions cmake/Findlibusb.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# SPDX-FileCopyrightText: 2022 Andrea Pappacoda <[email protected]>
# SPDX-License-Identifier: ISC

find_package(libusb CONFIG)
if (NOT libusb_FOUND)
find_package(PkgConfig)
if (PKG_CONFIG_FOUND)
pkg_search_module(libusb IMPORTED_TARGET GLOBAL libusb-1.0 libusb)
if (libusb_FOUND)
add_library(libusb::libusb ALIAS PkgConfig::libusb)
endif ()
endif ()
endif ()

find_package_handle_standard_args(libusb
REQUIRED_VARS
libusb_LINK_LIBRARIES
libusb_FOUND
VERSION_VAR libusb_VERSION
)
19 changes: 19 additions & 0 deletions src/Cafe/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -434,6 +434,14 @@ add_library(CemuCafe
OS/libs/nn_uds/nn_uds.h
OS/libs/nsyshid/nsyshid.cpp
OS/libs/nsyshid/nsyshid.h
OS/libs/nsyshid/Backend.h
OS/libs/nsyshid/AttachDefaultBackends.cpp
OS/libs/nsyshid/Whitelist.cpp
OS/libs/nsyshid/Whitelist.h
OS/libs/nsyshid/BackendLibusb.cpp
OS/libs/nsyshid/BackendLibusb.h
OS/libs/nsyshid/BackendWindowsHID.cpp
OS/libs/nsyshid/BackendWindowsHID.h
OS/libs/nsyskbd/nsyskbd.cpp
OS/libs/nsyskbd/nsyskbd.h
OS/libs/nsysnet/nsysnet.cpp
Expand Down Expand Up @@ -524,6 +532,17 @@ if (ENABLE_WAYLAND)
target_link_libraries(CemuCafe PUBLIC Wayland::Client)
endif()

if (ENABLE_NSYSHID_LIBUSB)
if (ENABLE_VCPKG)
find_package(libusb CONFIG REQUIRED)
target_include_directories(CemuCafe PRIVATE ${LIBUSB_INCLUDE_DIRS})
target_link_libraries(CemuCafe PRIVATE ${LIBUSB_LIBRARIES})
else ()
find_package(libusb MODULE REQUIRED)
target_link_libraries(CemuCafe PRIVATE libusb::libusb)
endif ()
endif ()

if (ENABLE_WXWIDGETS)
target_link_libraries(CemuCafe PRIVATE wx::base wx::core)
endif()
Expand Down
41 changes: 41 additions & 0 deletions src/Cafe/OS/libs/nsyshid/AttachDefaultBackends.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
#include "nsyshid.h"
#include "Backend.h"

#if NSYSHID_ENABLE_BACKEND_LIBUSB

#include "BackendLibusb.h"

#endif

#if NSYSHID_ENABLE_BACKEND_WINDOWS_HID

#include "BackendWindowsHID.h"

#endif

namespace nsyshid::backend
{
void AttachDefaultBackends()
{
#if NSYSHID_ENABLE_BACKEND_LIBUSB
// add libusb backend
{
auto backendLibusb = std::make_shared<backend::libusb::BackendLibusb>();
if (backendLibusb->IsInitialisedOk())
{
AttachBackend(backendLibusb);
}
}
#endif // NSYSHID_ENABLE_BACKEND_LIBUSB
#if NSYSHID_ENABLE_BACKEND_WINDOWS_HID
// add windows hid backend
{
auto backendWindowsHID = std::make_shared<backend::windows::BackendWindowsHID>();
if (backendWindowsHID->IsInitialisedOk())
{
AttachBackend(backendWindowsHID);
}
}
#endif // NSYSHID_ENABLE_BACKEND_WINDOWS_HID
}
} // namespace nsyshid::backend
141 changes: 141 additions & 0 deletions src/Cafe/OS/libs/nsyshid/Backend.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
#ifndef CEMU_NSYSHID_BACKEND_H
#define CEMU_NSYSHID_BACKEND_H

#include <list>
#include <memory>
#include <mutex>

#include "Common/precompiled.h"

namespace nsyshid
{
typedef struct
{
/* +0x00 */ uint32be handle;
/* +0x04 */ uint32 ukn04;
/* +0x08 */ uint16 vendorId; // little-endian ?
/* +0x0A */ uint16 productId; // little-endian ?
/* +0x0C */ uint8 ifIndex;
/* +0x0D */ uint8 subClass;
/* +0x0E */ uint8 protocol;
/* +0x0F */ uint8 paddingGuessed0F;
/* +0x10 */ uint16be maxPacketSizeRX;
/* +0x12 */ uint16be maxPacketSizeTX;
} HID_t;

static_assert(offsetof(HID_t, vendorId) == 0x8, "");
static_assert(offsetof(HID_t, productId) == 0xA, "");
static_assert(offsetof(HID_t, ifIndex) == 0xC, "");
static_assert(offsetof(HID_t, protocol) == 0xE, "");

class Device {
public:
Device() = delete;

Device(uint16 vendorId,
uint16 productId,
uint8 interfaceIndex,
uint8 interfaceSubClass,
uint8 protocol);

Device(const Device& device) = delete;

Device& operator=(const Device& device) = delete;

virtual ~Device() = default;

HID_t* m_hid; // this info is passed to applications and must remain intact

uint16 m_vendorId;
uint16 m_productId;
uint8 m_interfaceIndex;
uint8 m_interfaceSubClass;
uint8 m_protocol;
uint16 m_maxPacketSizeRX;
uint16 m_maxPacketSizeTX;

virtual void AssignHID(HID_t* hid);

virtual bool Open() = 0;

virtual void Close() = 0;

virtual bool IsOpened() = 0;

enum class ReadResult
{
Success,
Error,
ErrorTimeout,
};

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

enum class WriteResult
{
Success,
Error,
ErrorTimeout,
};

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

virtual bool GetDescriptor(uint8 descType,
uint8 descIndex,
uint8 lang,
uint8* output,
uint32 outputMaxLength) = 0;

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

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

class Backend {
public:
Backend();

Backend(const Backend& backend) = delete;

Backend& operator=(const Backend& backend) = delete;

virtual ~Backend() = default;

void DetachAllDevices();

// called from nsyshid when this backend is attached - do not call this yourself!
void OnAttach();

// called from nsyshid when this backend is detached - do not call this yourself!
void OnDetach();

bool IsBackendAttached();

virtual bool IsInitialisedOk() = 0;

protected:
// try to attach a device - only works if this backend is attached
bool AttachDevice(const std::shared_ptr<Device>& device);

void DetachDevice(const std::shared_ptr<Device>& device);

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

bool IsDeviceWhitelisted(uint16 vendorId, uint16 productId);

// called from OnAttach() - attach devices that your backend can see here
virtual void AttachVisibleDevices() = 0;

private:
std::list<std::shared_ptr<Device>> m_devices;
std::recursive_mutex m_devicesMutex;
bool m_isAttached;
};

namespace backend
{
void AttachDefaultBackends();
}
} // namespace nsyshid

#endif // CEMU_NSYSHID_BACKEND_H
Loading