1
0
mirror of https://github.com/cathery/sys-con.git synced 2024-07-03 02:18:43 +00:00

sysmodule: implement usb and controller handler modules (not working)

This commit is contained in:
cathery 2020-02-16 22:53:58 +03:00
parent d5cd9b7b0d
commit 05d62f943c
7 changed files with 340 additions and 7 deletions

View File

@ -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/",

View File

@ -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
}

View 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();
}
}

View 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();
}

View File

@ -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();
}

View 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();
}
}

View File

@ -0,0 +1,11 @@
#pragma once
#include <stratosphere.hpp>
namespace syscon::usb {
void Initialize();
void Exit();
Result Enable();
void Disable();
}