mirror of
https://github.com/cathery/sys-con.git
synced 2024-10-02 20:52:02 +00:00
sysmodule: implement usb and controller handler modules (not working)
This commit is contained in:
parent
d5cd9b7b0d
commit
05d62f943c
2
.vscode/c_cpp_properties.json
vendored
2
.vscode/c_cpp_properties.json
vendored
@ -3,7 +3,7 @@
|
|||||||
{
|
{
|
||||||
"name": "AArch64 libnx",
|
"name": "AArch64 libnx",
|
||||||
"includePath": [
|
"includePath": [
|
||||||
"${DEVKITPRO}/devkitA64/lib/gcc/aarch64-none-elf/*/include/",
|
"${DEVKITPRO}/devkitA64/lib/gcc/aarch64-none-elf/**",
|
||||||
"${DEVKITPRO}/devkitA64/aarch64-none-elf/include/",
|
"${DEVKITPRO}/devkitA64/aarch64-none-elf/include/",
|
||||||
"${DEVKITPRO}/portlibs/switch/include/",
|
"${DEVKITPRO}/portlibs/switch/include/",
|
||||||
"${DEVKITPRO}/libnx/include/",
|
"${DEVKITPRO}/libnx/include/",
|
||||||
|
7
.vscode/settings.json
vendored
7
.vscode/settings.json
vendored
@ -49,7 +49,12 @@
|
|||||||
"thread": "cpp",
|
"thread": "cpp",
|
||||||
"bit": "cpp",
|
"bit": "cpp",
|
||||||
"cinttypes": "cpp",
|
"cinttypes": "cpp",
|
||||||
"variant": "cpp"
|
"variant": "cpp",
|
||||||
|
"condition_variable": "cpp",
|
||||||
|
"map": "cpp",
|
||||||
|
"set": "cpp",
|
||||||
|
"mutex": "cpp",
|
||||||
|
"shared_mutex": "cpp"
|
||||||
},
|
},
|
||||||
"C_Cpp.dimInactiveRegions": true
|
"C_Cpp.dimInactiveRegions": true
|
||||||
}
|
}
|
73
source/Sysmodule/source/controller_handler.cpp
Normal file
73
source/Sysmodule/source/controller_handler.cpp
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
#include "switch.h"
|
||||||
|
#include "controller_handler.h"
|
||||||
|
#include "SwitchHDLHandler.h"
|
||||||
|
#include "SwitchAbstractedPadHandler.h"
|
||||||
|
#include <algorithm>
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
|
#include "log.h"
|
||||||
|
|
||||||
|
namespace syscon::handler
|
||||||
|
{
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
constexpr size_t MaxControllerHandlersSize = 10;
|
||||||
|
std::vector<std::unique_ptr<SwitchVirtualGamepadHandler>> controllerHandlers;
|
||||||
|
bool UseAbstractedPad;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsAtControllerLimit()
|
||||||
|
{
|
||||||
|
return controllerHandlers.size() >= MaxControllerHandlersSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result Insert(std::unique_ptr<IController> &&controllerPtr)
|
||||||
|
{
|
||||||
|
WriteToLog("Inserting controller");
|
||||||
|
std::unique_ptr<SwitchVirtualGamepadHandler> switchHandler;
|
||||||
|
if (UseAbstractedPad)
|
||||||
|
{
|
||||||
|
switchHandler = std::make_unique<SwitchAbstractedPadHandler>(std::move(controllerPtr));
|
||||||
|
WriteToLog("Inserting as abstracted pad");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
switchHandler = std::make_unique<SwitchHDLHandler>(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<std::unique_ptr<SwitchVirtualGamepadHandler>>& 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();
|
||||||
|
}
|
||||||
|
}
|
18
source/Sysmodule/source/controller_handler.h
Normal file
18
source/Sysmodule/source/controller_handler.h
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "ControllerHelpers.h"
|
||||||
|
#include "SwitchVirtualGamepadHandler.h"
|
||||||
|
|
||||||
|
namespace syscon::handler
|
||||||
|
{
|
||||||
|
bool IsAtControllerLimit();
|
||||||
|
|
||||||
|
Result Insert(std::unique_ptr<IController> &&controllerPtr);
|
||||||
|
std::vector<std::unique_ptr<SwitchVirtualGamepadHandler>>& Get();
|
||||||
|
|
||||||
|
//void Remove(void Remove(bool (*func)(std::unique_ptr<SwitchVirtualGamepadHandler> a)));;
|
||||||
|
|
||||||
|
void Initialize();
|
||||||
|
void Reset();
|
||||||
|
void Exit();
|
||||||
|
}
|
@ -3,12 +3,17 @@
|
|||||||
#include "mainLoop.h"
|
#include "mainLoop.h"
|
||||||
#include <stratosphere.hpp>
|
#include <stratosphere.hpp>
|
||||||
|
|
||||||
|
#include "usb_module.h"
|
||||||
|
#include "controller_handler.h"
|
||||||
|
|
||||||
|
#define APP_VERSION "0.6.0"
|
||||||
|
|
||||||
// libnx fake heap initialization
|
// libnx fake heap initialization
|
||||||
extern "C"
|
extern "C"
|
||||||
{
|
{
|
||||||
u32 __nx_applet_type = AppletType_None;
|
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;
|
size_t nx_inner_heap_size = INNER_HEAP_SIZE;
|
||||||
char nx_inner_heap[INNER_HEAP_SIZE];
|
char nx_inner_heap[INNER_HEAP_SIZE];
|
||||||
|
|
||||||
@ -21,6 +26,14 @@ extern "C"
|
|||||||
fake_heap_start = nx_inner_heap;
|
fake_heap_start = nx_inner_heap;
|
||||||
fake_heap_end = nx_inner_heap + nx_inner_heap_size;
|
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
|
// libstratosphere variables
|
||||||
@ -37,14 +50,15 @@ extern "C" void __appInit(void)
|
|||||||
ams::sm::DoWithSession([]
|
ams::sm::DoWithSession([]
|
||||||
{
|
{
|
||||||
R_ASSERT(timeInitialize());
|
R_ASSERT(timeInitialize());
|
||||||
R_ASSERT(fsInitialize());
|
|
||||||
R_ASSERT(fsdevMountSdmc());
|
|
||||||
R_ASSERT(hiddbgInitialize());
|
R_ASSERT(hiddbgInitialize());
|
||||||
if (hosversionAtLeast(7, 0, 0))
|
if (ams::hos::GetVersion() >= ams::hos::Version_700)
|
||||||
R_ASSERT(hiddbgAttachHdlsWorkBuffer());
|
R_ASSERT(hiddbgAttachHdlsWorkBuffer());
|
||||||
R_ASSERT(usbHsInitialize());
|
R_ASSERT(usbHsInitialize());
|
||||||
R_ASSERT(pscmInitialize());
|
R_ASSERT(pscmInitialize());
|
||||||
|
R_ASSERT(fsInitialize());
|
||||||
});
|
});
|
||||||
|
|
||||||
|
R_ASSERT(fsdevMountSdmc());
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" void __appExit(void)
|
extern "C" void __appExit(void)
|
||||||
@ -58,7 +72,19 @@ extern "C" void __appExit(void)
|
|||||||
timeExit();
|
timeExit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
using namespace syscon;
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
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();
|
||||||
}
|
}
|
||||||
|
200
source/Sysmodule/source/usb_module.cpp
Normal file
200
source/Sysmodule/source/usb_module.cpp
Normal file
@ -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<Xbox360Controller>(std::make_unique<SwitchUSBDevice>(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<Xbox360WirelessController>(std::make_unique<SwitchUSBDevice>(interfaces + i, 1)));
|
||||||
|
|
||||||
|
else if ((total_entries = QueryInterfaces(0x58, 0x42, 0x00)) != 0)
|
||||||
|
handler::Insert(std::make_unique<XboxController>(std::make_unique<SwitchUSBDevice>(interfaces, total_entries)));
|
||||||
|
|
||||||
|
else if ((total_entries = QueryInterfaces(USB_CLASS_VENDOR_SPEC, 71, 208)) != 0)
|
||||||
|
handler::Insert(std::make_unique<XboxOneController>(std::make_unique<SwitchUSBDevice>(interfaces, total_entries)));
|
||||||
|
|
||||||
|
else if ((total_entries = QueryVendorProduct(VENDOR_SONY, PRODUCT_DUALSHOCK3)) != 0)
|
||||||
|
handler::Insert(std::make_unique<Dualshock3Controller>(std::make_unique<SwitchUSBDevice>(interfaces, total_entries)));
|
||||||
|
|
||||||
|
else if ((total_entries = QueryVendorProduct(VENDOR_SONY, PRODUCT_DUALSHOCK4_2X)) != 0)
|
||||||
|
handler::Insert(std::make_unique<Dualshock4Controller>(std::make_unique<SwitchUSBDevice>(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<SwitchUSBInterface *>(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();
|
||||||
|
}
|
||||||
|
}
|
11
source/Sysmodule/source/usb_module.h
Normal file
11
source/Sysmodule/source/usb_module.h
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <stratosphere.hpp>
|
||||||
|
|
||||||
|
namespace syscon::usb {
|
||||||
|
|
||||||
|
void Initialize();
|
||||||
|
void Exit();
|
||||||
|
|
||||||
|
Result Enable();
|
||||||
|
void Disable();
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user