From 05d62f943cd92949bf72beb9c27367e122c8e1e4 Mon Sep 17 00:00:00 2001 From: cathery Date: Sun, 16 Feb 2020 22:53:58 +0300 Subject: [PATCH] sysmodule: implement usb and controller handler modules (not working) --- .vscode/c_cpp_properties.json | 2 +- .vscode/settings.json | 7 +- .../Sysmodule/source/controller_handler.cpp | 73 +++++++ source/Sysmodule/source/controller_handler.h | 18 ++ source/Sysmodule/source/main.cpp | 36 +++- source/Sysmodule/source/usb_module.cpp | 200 ++++++++++++++++++ source/Sysmodule/source/usb_module.h | 11 + 7 files changed, 340 insertions(+), 7 deletions(-) create mode 100644 source/Sysmodule/source/controller_handler.cpp create mode 100644 source/Sysmodule/source/controller_handler.h create mode 100644 source/Sysmodule/source/usb_module.cpp create mode 100644 source/Sysmodule/source/usb_module.h diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json index 90773ea..5ddbb52 100644 --- a/.vscode/c_cpp_properties.json +++ b/.vscode/c_cpp_properties.json @@ -3,7 +3,7 @@ { "name": "AArch64 libnx", "includePath": [ - "${DEVKITPRO}/devkitA64/lib/gcc/aarch64-none-elf/*/include/", + "${DEVKITPRO}/devkitA64/lib/gcc/aarch64-none-elf/**", "${DEVKITPRO}/devkitA64/aarch64-none-elf/include/", "${DEVKITPRO}/portlibs/switch/include/", "${DEVKITPRO}/libnx/include/", diff --git a/.vscode/settings.json b/.vscode/settings.json index adbb2e0..c9a7570 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -49,7 +49,12 @@ "thread": "cpp", "bit": "cpp", "cinttypes": "cpp", - "variant": "cpp" + "variant": "cpp", + "condition_variable": "cpp", + "map": "cpp", + "set": "cpp", + "mutex": "cpp", + "shared_mutex": "cpp" }, "C_Cpp.dimInactiveRegions": true } \ No newline at end of file diff --git a/source/Sysmodule/source/controller_handler.cpp b/source/Sysmodule/source/controller_handler.cpp new file mode 100644 index 0000000..2b13c13 --- /dev/null +++ b/source/Sysmodule/source/controller_handler.cpp @@ -0,0 +1,73 @@ +#include "switch.h" +#include "controller_handler.h" +#include "SwitchHDLHandler.h" +#include "SwitchAbstractedPadHandler.h" +#include +#include + +#include "log.h" + +namespace syscon::handler +{ + namespace + { + constexpr size_t MaxControllerHandlersSize = 10; + std::vector> controllerHandlers; + bool UseAbstractedPad; + } + + bool IsAtControllerLimit() + { + return controllerHandlers.size() >= MaxControllerHandlersSize; + } + + Result Insert(std::unique_ptr &&controllerPtr) + { + WriteToLog("Inserting controller"); + std::unique_ptr switchHandler; + if (UseAbstractedPad) + { + switchHandler = std::make_unique(std::move(controllerPtr)); + WriteToLog("Inserting as abstracted pad"); + } + else + { + switchHandler = std::make_unique(std::move(controllerPtr)); + WriteToLog("Inserting as HDLs"); + } + + Result rc = switchHandler->Initialize(); + if (R_SUCCEEDED(rc)) + controllerHandlers.push_back(std::move(switchHandler)); + + WriteToLog("Controller result: 0x%x", rc); + return rc; + } + + std::vector>& Get() + { + return controllerHandlers; + } + /* + void Remove(std::function func) + { + std::remove_if(controllerHandlers.begin(), controllerHandlers.end(), func); + } + */ + + void Initialize() + { + UseAbstractedPad = hosversionBetween(5, 7); + controllerHandlers.reserve(MaxControllerHandlersSize); + } + + void Reset() + { + controllerHandlers.clear(); + } + + void Exit() + { + Reset(); + } +} \ No newline at end of file diff --git a/source/Sysmodule/source/controller_handler.h b/source/Sysmodule/source/controller_handler.h new file mode 100644 index 0000000..ebd73b9 --- /dev/null +++ b/source/Sysmodule/source/controller_handler.h @@ -0,0 +1,18 @@ +#pragma once + +#include "ControllerHelpers.h" +#include "SwitchVirtualGamepadHandler.h" + +namespace syscon::handler +{ + bool IsAtControllerLimit(); + + Result Insert(std::unique_ptr &&controllerPtr); + std::vector>& Get(); + + //void Remove(void Remove(bool (*func)(std::unique_ptr a)));; + + void Initialize(); + void Reset(); + void Exit(); +} \ No newline at end of file diff --git a/source/Sysmodule/source/main.cpp b/source/Sysmodule/source/main.cpp index ad02106..7610a96 100644 --- a/source/Sysmodule/source/main.cpp +++ b/source/Sysmodule/source/main.cpp @@ -3,12 +3,17 @@ #include "mainLoop.h" #include +#include "usb_module.h" +#include "controller_handler.h" + +#define APP_VERSION "0.6.0" + // libnx fake heap initialization extern "C" { u32 __nx_applet_type = AppletType_None; - #define INNER_HEAP_SIZE 0x40 * ams::os::MemoryPageSize + #define INNER_HEAP_SIZE 0x40'000 size_t nx_inner_heap_size = INNER_HEAP_SIZE; char nx_inner_heap[INNER_HEAP_SIZE]; @@ -21,6 +26,14 @@ extern "C" fake_heap_start = nx_inner_heap; fake_heap_end = nx_inner_heap + nx_inner_heap_size; } + + // Exception handling + alignas(16) u8 __nx_exception_stack[ams::os::MemoryPageSize]; + u64 __nx_exception_stack_size = sizeof(__nx_exception_stack); + void __libnx_exception_handler(ThreadExceptionDump *ctx) + { + ams::CrashHandler(ctx); + } } // libstratosphere variables @@ -37,14 +50,15 @@ extern "C" void __appInit(void) ams::sm::DoWithSession([] { R_ASSERT(timeInitialize()); - R_ASSERT(fsInitialize()); - R_ASSERT(fsdevMountSdmc()); R_ASSERT(hiddbgInitialize()); - if (hosversionAtLeast(7, 0, 0)) + if (ams::hos::GetVersion() >= ams::hos::Version_700) R_ASSERT(hiddbgAttachHdlsWorkBuffer()); R_ASSERT(usbHsInitialize()); R_ASSERT(pscmInitialize()); + R_ASSERT(fsInitialize()); }); + + R_ASSERT(fsdevMountSdmc()); } extern "C" void __appExit(void) @@ -58,7 +72,19 @@ extern "C" void __appExit(void) timeExit(); } +using namespace syscon; + int main(int argc, char *argv[]) { - return mainLoop(); + WriteToLog("\n\nNew sysmodule session started on version " APP_VERSION); + handler::Initialize(); + usb::Initialize(); + + while (true) + { + svcSleepThread(1e+8L); + } + + usb::Exit(); + handler::Exit(); } diff --git a/source/Sysmodule/source/usb_module.cpp b/source/Sysmodule/source/usb_module.cpp new file mode 100644 index 0000000..6ef1b66 --- /dev/null +++ b/source/Sysmodule/source/usb_module.cpp @@ -0,0 +1,200 @@ +#include "switch.h" +#include "usb_module.h" +#include "controller_handler.h" + + +#include "SwitchUSBDevice.h" +#include "ControllerHelpers.h" +#include "log.h" + +namespace syscon::usb +{ + namespace + { + constexpr u8 CatchAllEventIndex = 2; + constexpr u8 Dualshock3EventIndex = 0; + constexpr u8 Dualshock4EventIndex = 1; + + + constexpr size_t MaxUsbHsInterfacesSize = 16; + + void UsbEventThreadFunc(void *arg); + void UsbInterfaceChangeThreadFunc(void *arg); + + ams::os::StaticThread<0x2'000> g_usb_event_thread(&UsbEventThreadFunc, nullptr, 0x3F); + ams::os::StaticThread<0x1'000> g_usb_interface_change_thread(&UsbInterfaceChangeThreadFunc, nullptr, 0x3F); + + //TODO: Implement UsbInterfaceChangeThreadFunc + + Event g_usbCatchAllEvent; + Event g_usbDualshock3Event; + Event g_usbDualshock4Event; + UsbHsInterface interfaces[MaxUsbHsInterfacesSize]; + + s32 QueryInterfaces(u8 iclass, u8 isubclass, u8 iprotocol); + s32 QueryVendorProduct(uint16_t vendor_id, uint16_t product_id); + + void UsbEventThreadFunc(void *arg) + { + WriteToLog("Starting USB Event Thread!"); + while (R_SUCCEEDED(eventWait(&g_usbCatchAllEvent, UINT64_MAX))) + { + WriteToLog("Event got caught!"); + if (handler::IsAtControllerLimit()) + continue; + WriteToLog("Querying interfaces now"); + s32 total_entries; + if ((total_entries = QueryInterfaces(USB_CLASS_VENDOR_SPEC, 93, 1)) != 0) + handler::Insert(std::make_unique(std::make_unique(interfaces, total_entries))); + + else if ((total_entries = QueryInterfaces(USB_CLASS_VENDOR_SPEC, 93, 129)) != 0) + for (int i = 0; i != total_entries; ++i) + handler::Insert(std::make_unique(std::make_unique(interfaces + i, 1))); + + else if ((total_entries = QueryInterfaces(0x58, 0x42, 0x00)) != 0) + handler::Insert(std::make_unique(std::make_unique(interfaces, total_entries))); + + else if ((total_entries = QueryInterfaces(USB_CLASS_VENDOR_SPEC, 71, 208)) != 0) + handler::Insert(std::make_unique(std::make_unique(interfaces, total_entries))); + + else if ((total_entries = QueryVendorProduct(VENDOR_SONY, PRODUCT_DUALSHOCK3)) != 0) + handler::Insert(std::make_unique(std::make_unique(interfaces, total_entries))); + + else if ((total_entries = QueryVendorProduct(VENDOR_SONY, PRODUCT_DUALSHOCK4_2X)) != 0) + handler::Insert(std::make_unique(std::make_unique(interfaces, total_entries))); + } + } + + void UsbInterfaceChangeThreadFunc(void *arg) + { + WriteToLog("Starting USB Interface Change Thread!"); + while (R_SUCCEEDED(eventWait(usbHsGetInterfaceStateChangeEvent(), UINT64_MAX))) + { + s32 total_entries; + //WriteToLog("Interface state was changed"); + eventClear(usbHsGetInterfaceStateChangeEvent()); + if (R_SUCCEEDED(usbHsQueryAcquiredInterfaces(interfaces, sizeof(interfaces), &total_entries))) + { + for (auto it = handler::Get().begin(); it != handler::Get().end(); ++it) + { + bool found_flag = false; + + for (auto &&ptr : (*it)->GetController()->GetDevice()->GetInterfaces()) + { + //We check if a device was removed by comparing the controller's interfaces and the currently acquired interfaces + //If we didn't find a single matching interface ID, we consider a controller removed + for (int i = 0; i != total_entries; ++i) + { + if (interfaces[i].inf.ID == static_cast(ptr.get())->GetID()) + { + found_flag = true; + break; + } + } + } + + if (!found_flag) + { + //WriteToLog("Erasing controller! %i", (*it)->GetController()->GetType()); + handler::Get().erase(it--); + //WriteToLog("Controller erased!"); + } + } + } + } + } + + s32 QueryInterfaces(u8 iclass, u8 isubclass, u8 iprotocol) + { + UsbHsInterfaceFilter filter { + .Flags = UsbHsInterfaceFilterFlags_bInterfaceClass | UsbHsInterfaceFilterFlags_bInterfaceSubClass | UsbHsInterfaceFilterFlags_bInterfaceProtocol, + .bInterfaceClass = iclass, + .bInterfaceSubClass = isubclass, + .bInterfaceProtocol = iprotocol, + }; + s32 out_entries = 0; + usbHsQueryAvailableInterfaces(&filter, interfaces, sizeof(interfaces), &out_entries); + return out_entries; + } + + s32 QueryVendorProduct(uint16_t vendor_id, uint16_t product_id) + { + UsbHsInterfaceFilter filter { + .Flags = UsbHsInterfaceFilterFlags_idVendor | UsbHsInterfaceFilterFlags_idProduct, + .idVendor = vendor_id, + .idProduct = product_id, + }; + s32 out_entries = 0; + usbHsQueryAvailableInterfaces(&filter, interfaces, sizeof(interfaces), &out_entries); + return out_entries; + } + + Result CreateCatchAllAvailableEvent() + { + constexpr UsbHsInterfaceFilter filter { + .Flags = UsbHsInterfaceFilterFlags_bcdDevice_Min, + .bcdDevice_Min = 0, + }; + return usbHsCreateInterfaceAvailableEvent(&g_usbCatchAllEvent, true, CatchAllEventIndex, &filter); + } + + Result CreateDualshock3AvailableEvent() + { + constexpr UsbHsInterfaceFilter filter { + .Flags = UsbHsInterfaceFilterFlags_idVendor | UsbHsInterfaceFilterFlags_idProduct, + .idVendor = VENDOR_SONY, + .idProduct = PRODUCT_DUALSHOCK3, + }; + return usbHsCreateInterfaceAvailableEvent(&g_usbDualshock3Event, true, Dualshock3EventIndex, &filter); + } + + Result CreateDualshock4AvailableEvent() + { + constexpr UsbHsInterfaceFilter filter { + .Flags = UsbHsInterfaceFilterFlags_idVendor | UsbHsInterfaceFilterFlags_idProduct, + .idVendor = VENDOR_SONY, + .idProduct = PRODUCT_DUALSHOCK4_2X, + }; + return usbHsCreateInterfaceAvailableEvent(&g_usbDualshock4Event, true, Dualshock4EventIndex, &filter); + } + } + + + void Initialize() + { + R_ASSERT(Enable()); + } + + void Exit() + { + Disable(); + } + + Result Enable() + { + R_TRY(CreateCatchAllAvailableEvent()); + R_TRY(CreateDualshock3AvailableEvent()); + R_TRY(CreateDualshock4AvailableEvent()); + + R_TRY(g_usb_event_thread.Start().GetValue()); + //R_TRY(g_usb_interface_change_thread.Start().GetValue()); + + return 0; + } + + void Disable() + { + usbHsDestroyInterfaceAvailableEvent(&g_usbCatchAllEvent, CatchAllEventIndex); + usbHsDestroyInterfaceAvailableEvent(&g_usbDualshock3Event, Dualshock3EventIndex); + usbHsDestroyInterfaceAvailableEvent(&g_usbDualshock4Event, Dualshock4EventIndex); + + //TODO: test this without the cancel + g_usb_event_thread.CancelSynchronization(); + g_usb_interface_change_thread.CancelSynchronization(); + + g_usb_event_thread.Join(); + g_usb_interface_change_thread.Join(); + + handler::Reset(); + } +} \ No newline at end of file diff --git a/source/Sysmodule/source/usb_module.h b/source/Sysmodule/source/usb_module.h new file mode 100644 index 0000000..7296950 --- /dev/null +++ b/source/Sysmodule/source/usb_module.h @@ -0,0 +1,11 @@ +#pragma once +#include + +namespace syscon::usb { + + void Initialize(); + void Exit(); + + Result Enable(); + void Disable(); +} \ No newline at end of file