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",
|
||||
"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/",
|
||||
|
7
.vscode/settings.json
vendored
7
.vscode/settings.json
vendored
@ -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
|
||||
}
|
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 <stratosphere.hpp>
|
||||
|
||||
#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();
|
||||
}
|
||||
|
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