mirror of
https://github.com/amwatson/CitraVR.git
synced 2024-09-20 03:11:40 +02:00
Merge remote-tracking branch 'upstream/master'
This commit is contained in:
commit
cba8c999e0
15 changed files with 1262 additions and 186 deletions
|
@ -10,7 +10,7 @@ plugins {
|
|||
id("org.jetbrains.kotlin.android")
|
||||
id("de.undercouch.download") version "5.5.0"
|
||||
id("kotlin-parcelize")
|
||||
kotlin("plugin.serialization") version "1.8.21"
|
||||
kotlin("plugin.serialization") version "1.9.22"
|
||||
id("androidx.navigation.safeargs.kotlin")
|
||||
}
|
||||
|
||||
|
@ -174,23 +174,23 @@ android {
|
|||
|
||||
dependencies {
|
||||
implementation("androidx.recyclerview:recyclerview:1.3.2")
|
||||
implementation("androidx.activity:activity-ktx:1.8.0")
|
||||
implementation("androidx.activity:activity-ktx:1.8.2")
|
||||
implementation("androidx.fragment:fragment-ktx:1.6.2")
|
||||
implementation("androidx.appcompat:appcompat:1.6.1")
|
||||
implementation("androidx.documentfile:documentfile:1.0.1")
|
||||
implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.1")
|
||||
implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:2.7.0")
|
||||
implementation("androidx.slidingpanelayout:slidingpanelayout:1.2.0")
|
||||
implementation("com.google.android.material:material:1.9.0")
|
||||
implementation("androidx.core:core-splashscreen:1.0.1")
|
||||
implementation("androidx.work:work-runtime:2.8.1")
|
||||
implementation("androidx.work:work-runtime:2.9.0")
|
||||
implementation("org.ini4j:ini4j:0.5.4")
|
||||
implementation("androidx.swiperefreshlayout:swiperefreshlayout:1.1.0")
|
||||
implementation("androidx.navigation:navigation-fragment-ktx:2.7.5")
|
||||
implementation("androidx.navigation:navigation-ui-ktx:2.7.5")
|
||||
implementation("androidx.navigation:navigation-fragment-ktx:2.7.6")
|
||||
implementation("androidx.navigation:navigation-ui-ktx:2.7.6")
|
||||
implementation("info.debatty:java-string-similarity:2.0.0")
|
||||
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.5.0")
|
||||
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.2")
|
||||
implementation("androidx.preference:preference-ktx:1.2.1")
|
||||
implementation("io.coil-kt:coil:2.2.2")
|
||||
implementation("io.coil-kt:coil:2.5.0")
|
||||
}
|
||||
|
||||
// Download Vulkan Validation Layers from the KhronosGroup GitHub.
|
||||
|
|
|
@ -74,6 +74,9 @@
|
|||
android:name="libopenxr_forwardloader.oculus.so"
|
||||
android:required="false" />
|
||||
|
||||
<meta-data android:name="android.game_mode_config"
|
||||
android:resource="@xml/game_mode_config" />
|
||||
|
||||
<activity
|
||||
android:name="org.citra.citra_emu.ui.main.MainActivity"
|
||||
android:configChanges="density|orientation|screenSize|keyboard|keyboardHidden|uiMode"
|
||||
|
|
7
src/android/app/src/main/res/xml/game_mode_config.xml
Normal file
7
src/android/app/src/main/res/xml/game_mode_config.xml
Normal file
|
@ -0,0 +1,7 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<game-mode-config
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:supportsBatteryGameMode="true"
|
||||
android:supportsPerformanceGameMode="true"
|
||||
android:allowGameDownscaling="false"
|
||||
android:allowGameFpsOverride="false"/>
|
|
@ -4,10 +4,10 @@
|
|||
|
||||
// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
||||
plugins {
|
||||
id("com.android.application") version "8.1.2" apply false
|
||||
id("com.android.library") version "8.1.2" apply false
|
||||
id("org.jetbrains.kotlin.android") version "1.8.21" apply false
|
||||
id("org.jetbrains.kotlin.plugin.serialization") version "1.8.21"
|
||||
id("com.android.application") version "8.2.1" apply false
|
||||
id("com.android.library") version "8.2.1" apply false
|
||||
id("org.jetbrains.kotlin.android") version "1.9.22" apply false
|
||||
id("org.jetbrains.kotlin.plugin.serialization") version "1.9.22"
|
||||
}
|
||||
|
||||
tasks.register("clean").configure {
|
||||
|
@ -19,6 +19,6 @@ buildscript {
|
|||
google()
|
||||
}
|
||||
dependencies {
|
||||
classpath("androidx.navigation:navigation-safe-args-gradle-plugin:2.7.5")
|
||||
classpath("androidx.navigation:navigation-safe-args-gradle-plugin:2.7.6")
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME
|
|||
distributionPath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.0-bin.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.2-bin.zip
|
||||
|
|
|
@ -327,6 +327,10 @@ add_library(citra_core STATIC
|
|||
hle/service/ldr_ro/cro_helper.h
|
||||
hle/service/ldr_ro/ldr_ro.cpp
|
||||
hle/service/ldr_ro/ldr_ro.h
|
||||
hle/service/mcu/mcu_hwc.cpp
|
||||
hle/service/mcu/mcu_hwc.h
|
||||
hle/service/mcu/mcu.cpp
|
||||
hle/service/mcu/mcu.h
|
||||
hle/service/mic/mic_u.cpp
|
||||
hle/service/mic/mic_u.h
|
||||
hle/service/mvd/mvd.cpp
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -18,6 +18,7 @@
|
|||
#include <boost/serialization/vector.hpp>
|
||||
#include <boost/serialization/weak_ptr.hpp>
|
||||
#include <httplib.h>
|
||||
#include "common/thread.h"
|
||||
#include "core/hle/ipc_helpers.h"
|
||||
#include "core/hle/kernel/shared_memory.h"
|
||||
#include "core/hle/service/service.h"
|
||||
|
@ -48,12 +49,25 @@ constexpr u32 TotalRequestMethods = 8;
|
|||
|
||||
enum class RequestState : u8 {
|
||||
NotStarted = 0x1, // Request has not started yet.
|
||||
InProgress = 0x5, // Request in progress, sending request over the network.
|
||||
ReadyToDownloadContent = 0x7, // Ready to download the content. (needs verification)
|
||||
ReadyToDownload = 0x8, // Ready to download?
|
||||
ConnectingToServer = 0x5, // Request in progress, connecting to server.
|
||||
SendingRequest = 0x6, // Request in progress, sending HTTP request.
|
||||
ReceivingResponse = 0x7, // Request in progress, receiving HTTP response.
|
||||
ReadyToDownloadContent = 0x8, // Ready to download the content.
|
||||
TimedOut = 0xA, // Request timed out?
|
||||
};
|
||||
|
||||
enum class PostDataEncoding : u8 {
|
||||
Auto = 0x0,
|
||||
AsciiForm = 0x1,
|
||||
MultipartForm = 0x2,
|
||||
};
|
||||
|
||||
enum class PostDataType : u8 {
|
||||
AsciiForm = 0x0,
|
||||
MultipartForm = 0x1,
|
||||
Raw = 0x2,
|
||||
};
|
||||
|
||||
enum class ClientCertID : u32 {
|
||||
Default = 0x40, // Default client cert
|
||||
};
|
||||
|
@ -197,6 +211,41 @@ public:
|
|||
friend class boost::serialization::access;
|
||||
};
|
||||
|
||||
struct Param {
|
||||
Param(const std::vector<u8>& value)
|
||||
: name(value.begin(), value.end()), value(value.begin(), value.end()){};
|
||||
Param(const std::string& name, const std::string& value) : name(name), value(value){};
|
||||
Param(const std::string& name, const std::vector<u8>& value)
|
||||
: name(name), value(value.begin(), value.end()), is_binary(true){};
|
||||
std::string name;
|
||||
std::string value;
|
||||
bool is_binary = false;
|
||||
|
||||
httplib::MultipartFormData ToMultipartForm() const {
|
||||
httplib::MultipartFormData form;
|
||||
form.name = name;
|
||||
form.content = value;
|
||||
if (is_binary) {
|
||||
form.content_type = "application/octet-stream";
|
||||
// TODO(DaniElectra): httplib doesn't support setting Content-Transfer-Encoding,
|
||||
// while the 3DS sets Content-Transfer-Encoding: binary if a binary value is set
|
||||
}
|
||||
|
||||
return form;
|
||||
}
|
||||
|
||||
private:
|
||||
template <class Archive>
|
||||
void serialize(Archive& ar, const unsigned int) {
|
||||
ar& name;
|
||||
ar& value;
|
||||
ar& is_binary;
|
||||
}
|
||||
friend class boost::serialization::access;
|
||||
};
|
||||
|
||||
using Params = std::multimap<std::string, Param>;
|
||||
|
||||
Handle handle;
|
||||
u32 session_id;
|
||||
std::string url;
|
||||
|
@ -208,8 +257,14 @@ public:
|
|||
u32 socket_buffer_size;
|
||||
std::vector<RequestHeader> headers;
|
||||
const ClCertAData* clcert_data;
|
||||
httplib::Params post_data;
|
||||
Params post_data;
|
||||
std::string post_data_raw;
|
||||
PostDataEncoding post_data_encoding = PostDataEncoding::Auto;
|
||||
PostDataType post_data_type;
|
||||
std::string multipart_boundary;
|
||||
bool force_multipart = false;
|
||||
bool chunked_request = false;
|
||||
u32 chunked_content_length;
|
||||
|
||||
std::future<void> request_future;
|
||||
std::atomic<u64> current_download_size_bytes;
|
||||
|
@ -217,12 +272,19 @@ public:
|
|||
std::size_t current_copied_data;
|
||||
bool uses_default_client_cert{};
|
||||
httplib::Response response;
|
||||
Common::Event finish_post_data;
|
||||
|
||||
void ParseAsciiPostData();
|
||||
std::string ParseMultipartFormData();
|
||||
void MakeRequest();
|
||||
void MakeRequestNonSSL(httplib::Request& request, const URLInfo& url_info,
|
||||
std::vector<Context::RequestHeader>& pending_headers);
|
||||
void MakeRequestSSL(httplib::Request& request, const URLInfo& url_info,
|
||||
std::vector<Context::RequestHeader>& pending_headers);
|
||||
bool ContentProvider(size_t offset, size_t length, httplib::DataSink& sink);
|
||||
bool ChunkedContentProvider(size_t offset, httplib::DataSink& sink);
|
||||
std::size_t HandleHeaderWrite(std::vector<Context::RequestHeader>& pending_headers,
|
||||
httplib::Stream& strm, httplib::Headers& httplib_headers);
|
||||
};
|
||||
|
||||
struct SessionData : public Kernel::SessionRequestHandler::SessionDataBase {
|
||||
|
@ -308,6 +370,16 @@ private:
|
|||
*/
|
||||
void CancelConnection(Kernel::HLERequestContext& ctx);
|
||||
|
||||
/**
|
||||
* HTTP_C::GetRequestState service function
|
||||
* Inputs:
|
||||
* 1 : Context handle
|
||||
* Outputs:
|
||||
* 1 : Result of function, 0 on success, otherwise error code
|
||||
* 2 : Request state
|
||||
*/
|
||||
void GetRequestState(Kernel::HLERequestContext& ctx);
|
||||
|
||||
/**
|
||||
* HTTP_C::GetDownloadSizeState service function
|
||||
* Inputs:
|
||||
|
@ -418,6 +490,21 @@ private:
|
|||
*/
|
||||
void AddPostDataAscii(Kernel::HLERequestContext& ctx);
|
||||
|
||||
/**
|
||||
* HTTP_C::AddPostDataBinary service function
|
||||
* Inputs:
|
||||
* 1 : Context handle
|
||||
* 2 : Form name buffer size, including null-terminator.
|
||||
* 3 : Form value buffer size
|
||||
* 4 : (FormNameSize<<14) | 0xC02
|
||||
* 5 : Form name data pointer
|
||||
* 6 : (FormValueSize<<4) | 10
|
||||
* 7 : Form value data pointer
|
||||
* Outputs:
|
||||
* 1 : Result of function, 0 on success, otherwise error code
|
||||
*/
|
||||
void AddPostDataBinary(Kernel::HLERequestContext& ctx);
|
||||
|
||||
/**
|
||||
* HTTP_C::AddPostDataRaw service function
|
||||
* Inputs:
|
||||
|
@ -430,6 +517,140 @@ private:
|
|||
*/
|
||||
void AddPostDataRaw(Kernel::HLERequestContext& ctx);
|
||||
|
||||
/**
|
||||
* HTTP_C::SetPostDataType service function
|
||||
* Inputs:
|
||||
* 1 : Context handle
|
||||
* 2 : Post data type
|
||||
* Outputs:
|
||||
* 1 : Result of function, 0 on success, otherwise error code
|
||||
*/
|
||||
void SetPostDataType(Kernel::HLERequestContext& ctx);
|
||||
|
||||
/**
|
||||
* HTTP_C::SendPostDataAscii service function
|
||||
* Inputs:
|
||||
* 1 : Context handle
|
||||
* 2 : Form name buffer size, including null-terminator.
|
||||
* 3 : Form value buffer size, including null-terminator.
|
||||
* 4 : (FormNameSize<<14) | 0xC02
|
||||
* 5 : Form name data pointer
|
||||
* 6 : (FormValueSize<<4) | 10
|
||||
* 7 : Form value data pointer
|
||||
* Outputs:
|
||||
* 1 : Result of function, 0 on success, otherwise error code
|
||||
*/
|
||||
void SendPostDataAscii(Kernel::HLERequestContext& ctx);
|
||||
|
||||
/**
|
||||
* HTTP_C::SendPostDataAsciiTimeout service function
|
||||
* Inputs:
|
||||
* 1 : Context handle
|
||||
* 2 : Form name buffer size, including null-terminator.
|
||||
* 3 : Form value buffer size, including null-terminator.
|
||||
* 4-5 : u64 nanoseconds delay
|
||||
* 6 : (FormNameSize<<14) | 0xC02
|
||||
* 7 : Form name data pointer
|
||||
* 8 : (FormValueSize<<4) | 10
|
||||
* 9 : Form value data pointer
|
||||
* Outputs:
|
||||
* 1 : Result of function, 0 on success, otherwise error code
|
||||
*/
|
||||
void SendPostDataAsciiTimeout(Kernel::HLERequestContext& ctx);
|
||||
|
||||
/**
|
||||
* SendPostDataAsciiImpl:
|
||||
* Implements SendPostDataAscii and SendPostDataAsciiTimeout service functions
|
||||
*/
|
||||
void SendPostDataAsciiImpl(Kernel::HLERequestContext& ctx, bool timeout);
|
||||
|
||||
/**
|
||||
* HTTP_C::SendPostDataBinary service function
|
||||
* Inputs:
|
||||
* 1 : Context handle
|
||||
* 2 : Form name buffer size, including null-terminator.
|
||||
* 3 : Form value buffer size
|
||||
* 4 : (FormNameSize<<14) | 0xC02
|
||||
* 5 : Form name data pointer
|
||||
* 6 : (FormValueSize<<4) | 10
|
||||
* 7 : Form value data pointer
|
||||
* Outputs:
|
||||
* 1 : Result of function, 0 on success, otherwise error code
|
||||
*/
|
||||
void SendPostDataBinary(Kernel::HLERequestContext& ctx);
|
||||
|
||||
/**
|
||||
* HTTP_C::SendPostDataBinaryTimeout service function
|
||||
* Inputs:
|
||||
* 1 : Context handle
|
||||
* 2 : Form name buffer size, including null-terminator.
|
||||
* 3 : Form value buffer size
|
||||
* 4-5 : u64 nanoseconds delay
|
||||
* 6 : (FormNameSize<<14) | 0xC02
|
||||
* 7 : Form name data pointer
|
||||
* 8 : (FormValueSize<<4) | 10
|
||||
* 9 : Form value data pointer
|
||||
* Outputs:
|
||||
* 1 : Result of function, 0 on success, otherwise error code
|
||||
*/
|
||||
void SendPostDataBinaryTimeout(Kernel::HLERequestContext& ctx);
|
||||
|
||||
/**
|
||||
* SendPostDataBinaryImpl:
|
||||
* Implements SendPostDataBinary and SendPostDataBinaryTimeout service functions
|
||||
*/
|
||||
void SendPostDataBinaryImpl(Kernel::HLERequestContext& ctx, bool timeout);
|
||||
|
||||
/**
|
||||
* HTTP_C::SendPostDataRaw service function
|
||||
* Inputs:
|
||||
* 1 : Context handle
|
||||
* 2 : Post data length
|
||||
* 3-4: (Mapped buffer) Post data
|
||||
* Outputs:
|
||||
* 1 : Result of function, 0 on success, otherwise error code
|
||||
* 2-3: (Mapped buffer) Post data
|
||||
*/
|
||||
void SendPostDataRaw(Kernel::HLERequestContext& ctx);
|
||||
|
||||
/**
|
||||
* HTTP_C::SendPostDataRawTimeout service function
|
||||
* Inputs:
|
||||
* 1 : Context handle
|
||||
* 2 : Post data length
|
||||
* 3-4: u64 nanoseconds delay
|
||||
* 5-6: (Mapped buffer) Post data
|
||||
* Outputs:
|
||||
* 1 : Result of function, 0 on success, otherwise error code
|
||||
* 2-3: (Mapped buffer) Post data
|
||||
*/
|
||||
void SendPostDataRawTimeout(Kernel::HLERequestContext& ctx);
|
||||
|
||||
/**
|
||||
* SendPostDataRawImpl:
|
||||
* Implements SendPostDataRaw and SendPostDataRawTimeout service functions
|
||||
*/
|
||||
void SendPostDataRawImpl(Kernel::HLERequestContext& ctx, bool timeout);
|
||||
|
||||
/**
|
||||
* HTTP_C::NotifyFinishSendPostData service function
|
||||
* Inputs:
|
||||
* 1 : Context handle
|
||||
* Outputs:
|
||||
* 1 : Result of function, 0 on success, otherwise error code
|
||||
*/
|
||||
void NotifyFinishSendPostData(Kernel::HLERequestContext& ctx);
|
||||
|
||||
/**
|
||||
* HTTP_C::SetPostDataEncoding service function
|
||||
* Inputs:
|
||||
* 1 : Context handle
|
||||
* 2 : Post data encoding
|
||||
* Outputs:
|
||||
* 1 : Result of function, 0 on success, otherwise error code
|
||||
*/
|
||||
void SetPostDataEncoding(Kernel::HLERequestContext& ctx);
|
||||
|
||||
/**
|
||||
* HTTP_C::GetResponseHeader service function
|
||||
* Inputs:
|
||||
|
@ -445,6 +666,28 @@ private:
|
|||
*/
|
||||
void GetResponseHeader(Kernel::HLERequestContext& ctx);
|
||||
|
||||
/**
|
||||
* HTTP_C::GetResponseHeaderTimeout service function
|
||||
* Inputs:
|
||||
* 1 : Context handle
|
||||
* 2 : Header name length
|
||||
* 3 : Return value length
|
||||
* 4-5 : u64 nanoseconds delay
|
||||
* 6-7 : (Static buffer) Header name
|
||||
* 8-9 : (Mapped buffer) Header value
|
||||
* Outputs:
|
||||
* 1 : Result of function, 0 on success, otherwise error code
|
||||
* 2 : Header value copied size
|
||||
* 3-4: (Mapped buffer) Header value
|
||||
*/
|
||||
void GetResponseHeaderTimeout(Kernel::HLERequestContext& ctx);
|
||||
|
||||
/**
|
||||
* GetResponseHeaderImpl:
|
||||
* Implements GetResponseHeader and GetResponseHeaderTimeout service functions
|
||||
*/
|
||||
void GetResponseHeaderImpl(Kernel::HLERequestContext& ctx, bool timeout);
|
||||
|
||||
/**
|
||||
* HTTP_C::GetResponseStatusCode service function
|
||||
* Inputs:
|
||||
|
@ -578,6 +821,17 @@ private:
|
|||
*/
|
||||
void SetKeepAlive(Kernel::HLERequestContext& ctx);
|
||||
|
||||
/**
|
||||
* HTTP_C::SetPostDataTypeSize service function
|
||||
* Inputs:
|
||||
* 1 : Context handle
|
||||
* 2 : Post data type
|
||||
* 3 : Content length size
|
||||
* Outputs:
|
||||
* 1 : Result of function, 0 on success, otherwise error code
|
||||
*/
|
||||
void SetPostDataTypeSize(Kernel::HLERequestContext& ctx);
|
||||
|
||||
/**
|
||||
* HTTP_C::Finalize service function
|
||||
* Outputs:
|
||||
|
|
16
src/core/hle/service/mcu/mcu.cpp
Normal file
16
src/core/hle/service/mcu/mcu.cpp
Normal file
|
@ -0,0 +1,16 @@
|
|||
// Copyright 2024 Citra Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "core/core.h"
|
||||
#include "core/hle/service/mcu/mcu.h"
|
||||
#include "core/hle/service/mcu/mcu_hwc.h"
|
||||
|
||||
namespace Service::MCU {
|
||||
|
||||
void InstallInterfaces(Core::System& system) {
|
||||
auto& service_manager = system.ServiceManager();
|
||||
std::make_shared<HWC>()->InstallAsService(service_manager);
|
||||
}
|
||||
|
||||
} // namespace Service::MCU
|
15
src/core/hle/service/mcu/mcu.h
Normal file
15
src/core/hle/service/mcu/mcu.h
Normal file
|
@ -0,0 +1,15 @@
|
|||
// Copyright 2024 Citra Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace Core {
|
||||
class System;
|
||||
}
|
||||
|
||||
namespace Service::MCU {
|
||||
|
||||
void InstallInterfaces(Core::System& system);
|
||||
|
||||
} // namespace Service::MCU
|
36
src/core/hle/service/mcu/mcu_hwc.cpp
Normal file
36
src/core/hle/service/mcu/mcu_hwc.cpp
Normal file
|
@ -0,0 +1,36 @@
|
|||
// Copyright 2024 Citra Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "common/archives.h"
|
||||
#include "core/hle/service/mcu/mcu_hwc.h"
|
||||
|
||||
SERIALIZE_EXPORT_IMPL(Service::MCU::HWC)
|
||||
|
||||
namespace Service::MCU {
|
||||
|
||||
HWC::HWC() : ServiceFramework("mcu::HWC", 1) {
|
||||
static const FunctionInfo functions[] = {
|
||||
// clang-format off
|
||||
{0x0001, nullptr, "ReadRegister"},
|
||||
{0x0002, nullptr, "WriteRegister"},
|
||||
{0x0003, nullptr, "GetInfoRegisters"},
|
||||
{0x0004, nullptr, "GetBatteryVoltage"},
|
||||
{0x0005, nullptr, "GetBatteryLevel"},
|
||||
{0x0006, nullptr, "SetPowerLEDPattern"},
|
||||
{0x0007, nullptr, "SetWifiLEDState"},
|
||||
{0x0008, nullptr, "SetCameraLEDPattern"},
|
||||
{0x0009, nullptr, "Set3DLEDState"},
|
||||
{0x000A, nullptr, "SetInfoLEDPattern"},
|
||||
{0x000B, nullptr, "GetSoundVolume"},
|
||||
{0x000C, nullptr, "SetTopScreenFlicker"},
|
||||
{0x000D, nullptr, "SetBottomScreenFlicker"},
|
||||
{0x000F, nullptr, "GetRtcTime"},
|
||||
{0x0010, nullptr, "GetMcuFwVerHigh"},
|
||||
{0x0011, nullptr, "GetMcuFwVerLow"},
|
||||
// clang-format on
|
||||
};
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
|
||||
} // namespace Service::MCU
|
21
src/core/hle/service/mcu/mcu_hwc.h
Normal file
21
src/core/hle/service/mcu/mcu_hwc.h
Normal file
|
@ -0,0 +1,21 @@
|
|||
// Copyright 2024 Citra Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/hle/service/service.h"
|
||||
|
||||
namespace Service::MCU {
|
||||
|
||||
class HWC final : public ServiceFramework<HWC> {
|
||||
public:
|
||||
explicit HWC();
|
||||
|
||||
private:
|
||||
SERVICE_SERIALIZATION_SIMPLE
|
||||
};
|
||||
|
||||
} // namespace Service::MCU
|
||||
|
||||
BOOST_CLASS_EXPORT_KEY(Service::MCU::HWC)
|
|
@ -35,6 +35,7 @@
|
|||
#include "core/hle/service/http/http_c.h"
|
||||
#include "core/hle/service/ir/ir.h"
|
||||
#include "core/hle/service/ldr_ro/ldr_ro.h"
|
||||
#include "core/hle/service/mcu/mcu.h"
|
||||
#include "core/hle/service/mic/mic_u.h"
|
||||
#include "core/hle/service/mvd/mvd.h"
|
||||
#include "core/hle/service/ndm/ndm_u.h"
|
||||
|
@ -101,7 +102,7 @@ const std::array<ServiceModuleInfo, 41> service_module_map{
|
|||
{"CDC", 0x00040130'00001802, nullptr},
|
||||
{"GPIO", 0x00040130'00001B02, nullptr},
|
||||
{"I2C", 0x00040130'00001E02, nullptr},
|
||||
{"MCU", 0x00040130'00001F02, nullptr},
|
||||
{"MCU", 0x00040130'00001F02, MCU::InstallInterfaces},
|
||||
{"MP", 0x00040130'00002A02, nullptr},
|
||||
{"PDN", 0x00040130'00002102, nullptr},
|
||||
{"SPI", 0x00040130'00002302, nullptr}}};
|
||||
|
|
|
@ -598,9 +598,10 @@ static_assert(std::is_trivially_copyable_v<CTRPollFD>,
|
|||
union CTRSockAddr {
|
||||
/// Structure to represent a raw sockaddr
|
||||
struct {
|
||||
u8 len; ///< The length of the entire structure, only the set fields count
|
||||
u8 sa_family; ///< The address family of the sockaddr
|
||||
u8 sa_data[0x1A]; ///< The extra data, this varies, depending on the address family
|
||||
u8 len; ///< The length of the entire structure, only the set fields count
|
||||
u8 sa_family; ///< The address family of the sockaddr
|
||||
std::array<u8, 0x1A>
|
||||
sa_data; ///< The extra data, this varies, depending on the address family
|
||||
} raw;
|
||||
|
||||
/// Structure to represent the 3ds' sockaddr_in structure
|
||||
|
@ -612,36 +613,57 @@ union CTRSockAddr {
|
|||
} in;
|
||||
static_assert(sizeof(CTRSockAddrIn) == 8, "Invalid CTRSockAddrIn size");
|
||||
|
||||
struct CTRSockAddrIn6 {
|
||||
u8 len; ///< The length of the entire structure
|
||||
u8 sin6_family; ///< The address family of the sockaddr_in6
|
||||
u16 sin6_port; ///< The port associated with this sockaddr_in6
|
||||
std::array<u8, 0x10> sin6_addr; ///< The actual address of the sockaddr_in6
|
||||
u32 sin6_flowinfo; ///< The flow info of the sockaddr_in6
|
||||
u32 sin6_scope_id; ///< The scope ID of the sockaddr_in6
|
||||
} in6;
|
||||
static_assert(sizeof(CTRSockAddrIn6) == 28, "Invalid CTRSockAddrIn6 size");
|
||||
|
||||
/// Convert a 3DS CTRSockAddr to a platform-specific sockaddr
|
||||
static sockaddr ToPlatform(CTRSockAddr const& ctr_addr) {
|
||||
sockaddr result;
|
||||
ASSERT_MSG(ctr_addr.raw.len == sizeof(CTRSockAddrIn),
|
||||
static std::pair<sockaddr_storage, socklen_t> ToPlatform(CTRSockAddr const& ctr_addr) {
|
||||
sockaddr_storage result{};
|
||||
socklen_t result_len = sizeof(result.ss_family);
|
||||
ASSERT_MSG(ctr_addr.raw.len == sizeof(CTRSockAddrIn) ||
|
||||
ctr_addr.raw.len == sizeof(CTRSockAddrIn6),
|
||||
"Unhandled address size (len) in CTRSockAddr::ToPlatform");
|
||||
result.sa_family = SocketDomainToPlatform(ctr_addr.raw.sa_family);
|
||||
std::memset(result.sa_data, 0, sizeof(result.sa_data));
|
||||
result.ss_family = SocketDomainToPlatform(ctr_addr.raw.sa_family);
|
||||
|
||||
// We can not guarantee ABI compatibility between platforms so we copy the fields manually
|
||||
switch (result.sa_family) {
|
||||
switch (result.ss_family) {
|
||||
case AF_INET: {
|
||||
sockaddr_in* result_in = reinterpret_cast<sockaddr_in*>(&result);
|
||||
result_in->sin_port = ctr_addr.in.sin_port;
|
||||
result_in->sin_addr.s_addr = ctr_addr.in.sin_addr;
|
||||
std::memset(result_in->sin_zero, 0, sizeof(result_in->sin_zero));
|
||||
result_len = sizeof(sockaddr_in);
|
||||
break;
|
||||
}
|
||||
case AF_INET6: {
|
||||
sockaddr_in6* result_in6 = reinterpret_cast<sockaddr_in6*>(&result);
|
||||
result_in6->sin6_port = ctr_addr.in6.sin6_port;
|
||||
memcpy(&result_in6->sin6_addr, ctr_addr.in6.sin6_addr.data(),
|
||||
sizeof(result_in6->sin6_addr));
|
||||
result_in6->sin6_flowinfo = ctr_addr.in6.sin6_flowinfo;
|
||||
result_in6->sin6_scope_id = ctr_addr.in6.sin6_scope_id;
|
||||
result_len = sizeof(sockaddr_in6);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
ASSERT_MSG(false, "Unhandled address family (sa_family) in CTRSockAddr::ToPlatform");
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
return std::make_pair(result, result_len);
|
||||
}
|
||||
|
||||
/// Convert a platform-specific sockaddr to a 3DS CTRSockAddr
|
||||
static CTRSockAddr FromPlatform(sockaddr const& addr) {
|
||||
static CTRSockAddr FromPlatform(sockaddr_storage const& addr) {
|
||||
CTRSockAddr result;
|
||||
result.raw.sa_family = static_cast<u8>(SocketDomainFromPlatform(addr.sa_family));
|
||||
result.raw.sa_family = static_cast<u8>(SocketDomainFromPlatform(addr.ss_family));
|
||||
// We can not guarantee ABI compatibility between platforms so we copy the fields manually
|
||||
switch (addr.sa_family) {
|
||||
switch (addr.ss_family) {
|
||||
case AF_INET: {
|
||||
sockaddr_in const* addr_in = reinterpret_cast<sockaddr_in const*>(&addr);
|
||||
result.raw.len = sizeof(CTRSockAddrIn);
|
||||
|
@ -649,6 +671,15 @@ union CTRSockAddr {
|
|||
result.in.sin_addr = addr_in->sin_addr.s_addr;
|
||||
break;
|
||||
}
|
||||
case AF_INET6: {
|
||||
sockaddr_in6 const* addr_in6 = reinterpret_cast<sockaddr_in6 const*>(&addr);
|
||||
result.raw.len = sizeof(CTRSockAddrIn6);
|
||||
result.in6.sin6_port = addr_in6->sin6_port;
|
||||
memcpy(result.in6.sin6_addr.data(), &addr_in6->sin6_addr, sizeof(result.in6.sin6_addr));
|
||||
result.in6.sin6_flowinfo = addr_in6->sin6_flowinfo;
|
||||
result.in6.sin6_scope_id = addr_in6->sin6_scope_id;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
ASSERT_MSG(false, "Unhandled address family (sa_family) in CTRSockAddr::ToPlatform");
|
||||
break;
|
||||
|
@ -707,7 +738,8 @@ struct CTRAddrInfo {
|
|||
.ai_family = static_cast<s32_le>(SocketDomainFromPlatform(addr.ai_family)),
|
||||
.ai_socktype = static_cast<s32_le>(SocketTypeFromPlatform(addr.ai_socktype)),
|
||||
.ai_protocol = static_cast<s32_le>(SocketProtocolFromPlatform(addr.ai_protocol)),
|
||||
.ai_addr = CTRSockAddr::FromPlatform(*addr.ai_addr),
|
||||
.ai_addr =
|
||||
CTRSockAddr::FromPlatform(*reinterpret_cast<sockaddr_storage*>(addr.ai_addr)),
|
||||
};
|
||||
ctr_addr.ai_addrlen = static_cast<s32_le>(ctr_addr.ai_addr.raw.len);
|
||||
if (addr.ai_canonname)
|
||||
|
@ -840,9 +872,9 @@ void SOC_U::Bind(Kernel::HLERequestContext& ctx) {
|
|||
CTRSockAddr ctr_sock_addr;
|
||||
std::memcpy(&ctr_sock_addr, sock_addr_buf.data(), std::min<size_t>(len, sizeof(ctr_sock_addr)));
|
||||
|
||||
sockaddr sock_addr = CTRSockAddr::ToPlatform(ctr_sock_addr);
|
||||
auto [sock_addr, sock_addr_len] = CTRSockAddr::ToPlatform(ctr_sock_addr);
|
||||
|
||||
s32 ret = ::bind(holder.socket_fd, &sock_addr, sizeof(sock_addr));
|
||||
s32 ret = ::bind(holder.socket_fd, reinterpret_cast<sockaddr*>(&sock_addr), sock_addr_len);
|
||||
|
||||
if (ret != 0)
|
||||
ret = TranslateError(GET_ERRNO);
|
||||
|
@ -937,7 +969,7 @@ void SOC_U::Accept(Kernel::HLERequestContext& ctx) {
|
|||
// Output
|
||||
s32 ret{};
|
||||
int accept_error;
|
||||
sockaddr addr;
|
||||
sockaddr_storage addr;
|
||||
};
|
||||
|
||||
auto async_data = std::make_shared<AsyncData>();
|
||||
|
@ -950,7 +982,8 @@ void SOC_U::Accept(Kernel::HLERequestContext& ctx) {
|
|||
[async_data](Kernel::HLERequestContext& ctx) {
|
||||
socklen_t addr_len = sizeof(async_data->addr);
|
||||
async_data->ret = static_cast<u32>(
|
||||
::accept(async_data->fd_info->socket_fd, &async_data->addr, &addr_len));
|
||||
::accept(async_data->fd_info->socket_fd,
|
||||
reinterpret_cast<sockaddr*>(&async_data->addr), &addr_len));
|
||||
async_data->accept_error = (async_data->ret == SOCKET_ERROR_VALUE) ? GET_ERRNO : 0;
|
||||
return 0;
|
||||
},
|
||||
|
@ -1109,10 +1142,10 @@ void SOC_U::SendToOther(Kernel::HLERequestContext& ctx) {
|
|||
CTRSockAddr ctr_dest_addr;
|
||||
std::memcpy(&ctr_dest_addr, dest_addr_buffer.data(),
|
||||
std::min<size_t>(addr_len, sizeof(ctr_dest_addr)));
|
||||
sockaddr dest_addr = CTRSockAddr::ToPlatform(ctr_dest_addr);
|
||||
ret = static_cast<s32>(::sendto(holder.socket_fd,
|
||||
reinterpret_cast<const char*>(input_buff.data()), len,
|
||||
flags, &dest_addr, sizeof(dest_addr)));
|
||||
auto [dest_addr, dest_addr_len] = CTRSockAddr::ToPlatform(ctr_dest_addr);
|
||||
ret = static_cast<s32>(
|
||||
::sendto(holder.socket_fd, reinterpret_cast<const char*>(input_buff.data()), len, flags,
|
||||
reinterpret_cast<sockaddr*>(&dest_addr), dest_addr_len));
|
||||
} else {
|
||||
ret = static_cast<s32>(::sendto(holder.socket_fd,
|
||||
reinterpret_cast<const char*>(input_buff.data()), len,
|
||||
|
@ -1159,10 +1192,10 @@ s32 SOC_U::SendToImpl(SocketHolder& holder, u32 len, u32 flags, u32 addr_len,
|
|||
CTRSockAddr ctr_dest_addr;
|
||||
std::memcpy(&ctr_dest_addr, dest_addr_buff,
|
||||
std::min<size_t>(addr_len, sizeof(ctr_dest_addr)));
|
||||
sockaddr dest_addr = CTRSockAddr::ToPlatform(ctr_dest_addr);
|
||||
ret = static_cast<s32>(::sendto(holder.socket_fd,
|
||||
reinterpret_cast<const char*>(input_buff.data()), len,
|
||||
flags, &dest_addr, sizeof(dest_addr)));
|
||||
auto [dest_addr, dest_addr_len] = CTRSockAddr::ToPlatform(ctr_dest_addr);
|
||||
ret = static_cast<s32>(
|
||||
::sendto(holder.socket_fd, reinterpret_cast<const char*>(input_buff.data()), len, flags,
|
||||
reinterpret_cast<sockaddr*>(&dest_addr), dest_addr_len));
|
||||
} else {
|
||||
ret = static_cast<s32>(::sendto(holder.socket_fd,
|
||||
reinterpret_cast<const char*>(input_buff.data()), len,
|
||||
|
@ -1294,7 +1327,7 @@ void SOC_U::RecvFromOther(Kernel::HLERequestContext& ctx) {
|
|||
|
||||
ctx.RunAsync(
|
||||
[async_data](Kernel::HLERequestContext& ctx) {
|
||||
sockaddr src_addr;
|
||||
sockaddr_storage src_addr;
|
||||
socklen_t src_addr_len = sizeof(src_addr);
|
||||
CTRSockAddr ctr_src_addr;
|
||||
// Windows, why do you have to be so special...
|
||||
|
@ -1302,10 +1335,10 @@ void SOC_U::RecvFromOther(Kernel::HLERequestContext& ctx) {
|
|||
RecvBusyWaitForEvent(*async_data->fd_info);
|
||||
}
|
||||
if (async_data->addr_len > 0) {
|
||||
async_data->ret = static_cast<s32>(
|
||||
::recvfrom(async_data->fd_info->socket_fd,
|
||||
reinterpret_cast<char*>(async_data->output_buff.data()),
|
||||
async_data->len, async_data->flags, &src_addr, &src_addr_len));
|
||||
async_data->ret = static_cast<s32>(::recvfrom(
|
||||
async_data->fd_info->socket_fd,
|
||||
reinterpret_cast<char*>(async_data->output_buff.data()), async_data->len,
|
||||
async_data->flags, reinterpret_cast<sockaddr*>(&src_addr), &src_addr_len));
|
||||
if (async_data->ret >= 0 && src_addr_len > 0) {
|
||||
ctr_src_addr = CTRSockAddr::FromPlatform(src_addr);
|
||||
std::memcpy(async_data->addr_buff.data(), &ctr_src_addr,
|
||||
|
@ -1411,7 +1444,7 @@ void SOC_U::RecvFrom(Kernel::HLERequestContext& ctx) {
|
|||
|
||||
ctx.RunAsync(
|
||||
[async_data](Kernel::HLERequestContext& ctx) {
|
||||
sockaddr src_addr;
|
||||
sockaddr_storage src_addr;
|
||||
socklen_t src_addr_len = sizeof(src_addr);
|
||||
CTRSockAddr ctr_src_addr;
|
||||
if (async_data->is_blocking) {
|
||||
|
@ -1419,10 +1452,10 @@ void SOC_U::RecvFrom(Kernel::HLERequestContext& ctx) {
|
|||
}
|
||||
if (async_data->addr_len > 0) {
|
||||
// Only get src adr if input adr available
|
||||
async_data->ret = static_cast<s32>(
|
||||
::recvfrom(async_data->fd_info->socket_fd,
|
||||
reinterpret_cast<char*>(async_data->output_buff.data()),
|
||||
async_data->len, async_data->flags, &src_addr, &src_addr_len));
|
||||
async_data->ret = static_cast<s32>(::recvfrom(
|
||||
async_data->fd_info->socket_fd,
|
||||
reinterpret_cast<char*>(async_data->output_buff.data()), async_data->len,
|
||||
async_data->flags, reinterpret_cast<sockaddr*>(&src_addr), &src_addr_len));
|
||||
if (async_data->ret >= 0 && src_addr_len > 0) {
|
||||
ctr_src_addr = CTRSockAddr::FromPlatform(src_addr);
|
||||
std::memcpy(async_data->addr_buff.data(), &ctr_src_addr,
|
||||
|
@ -1558,9 +1591,10 @@ void SOC_U::GetSockName(Kernel::HLERequestContext& ctx) {
|
|||
}
|
||||
SocketHolder& holder = socket_holder_optional->get();
|
||||
|
||||
sockaddr dest_addr;
|
||||
sockaddr_storage dest_addr;
|
||||
socklen_t dest_addr_len = sizeof(dest_addr);
|
||||
s32 ret = ::getsockname(holder.socket_fd, &dest_addr, &dest_addr_len);
|
||||
s32 ret =
|
||||
::getsockname(holder.socket_fd, reinterpret_cast<sockaddr*>(&dest_addr), &dest_addr_len);
|
||||
|
||||
CTRSockAddr ctr_dest_addr = CTRSockAddr::FromPlatform(dest_addr);
|
||||
std::vector<u8> dest_addr_buff(sizeof(ctr_dest_addr));
|
||||
|
@ -1647,10 +1681,11 @@ void SOC_U::GetHostByAddr(Kernel::HLERequestContext& ctx) {
|
|||
[[maybe_unused]] u32 out_buf_len = rp.Pop<u32>();
|
||||
auto addr = rp.PopStaticBuffer();
|
||||
|
||||
sockaddr platform_addr = CTRSockAddr::ToPlatform(*reinterpret_cast<CTRSockAddr*>(addr.data()));
|
||||
auto [platform_addr, platform_addr_len] =
|
||||
CTRSockAddr::ToPlatform(*reinterpret_cast<CTRSockAddr*>(addr.data()));
|
||||
|
||||
struct hostent* result =
|
||||
::gethostbyaddr(reinterpret_cast<char*>(&platform_addr), sizeof(platform_addr), type);
|
||||
::gethostbyaddr(reinterpret_cast<char*>(&platform_addr), platform_addr_len, type);
|
||||
|
||||
IPC::RequestBuilder rb = rp.MakeBuilder(2, 2);
|
||||
rb.Push(ResultSuccess);
|
||||
|
@ -1698,9 +1733,10 @@ void SOC_U::GetPeerName(Kernel::HLERequestContext& ctx) {
|
|||
}
|
||||
SocketHolder& holder = socket_holder_optional->get();
|
||||
|
||||
sockaddr dest_addr;
|
||||
sockaddr_storage dest_addr;
|
||||
socklen_t dest_addr_len = sizeof(dest_addr);
|
||||
const int ret = ::getpeername(holder.socket_fd, &dest_addr, &dest_addr_len);
|
||||
const int ret =
|
||||
::getpeername(holder.socket_fd, reinterpret_cast<sockaddr*>(&dest_addr), &dest_addr_len);
|
||||
|
||||
CTRSockAddr ctr_dest_addr = CTRSockAddr::FromPlatform(dest_addr);
|
||||
std::vector<u8> dest_addr_buff(sizeof(ctr_dest_addr));
|
||||
|
@ -1741,7 +1777,7 @@ void SOC_U::Connect(Kernel::HLERequestContext& ctx) {
|
|||
struct AsyncData {
|
||||
// Input
|
||||
SocketHolder* fd_info;
|
||||
sockaddr input_addr;
|
||||
std::pair<sockaddr_storage, socklen_t> input_addr;
|
||||
u32 socket_handle;
|
||||
u32 pid;
|
||||
|
||||
|
@ -1763,8 +1799,9 @@ void SOC_U::Connect(Kernel::HLERequestContext& ctx) {
|
|||
|
||||
ctx.RunAsync(
|
||||
[async_data](Kernel::HLERequestContext& ctx) {
|
||||
async_data->ret = ::connect(async_data->fd_info->socket_fd, &async_data->input_addr,
|
||||
sizeof(async_data->input_addr));
|
||||
async_data->ret = ::connect(async_data->fd_info->socket_fd,
|
||||
reinterpret_cast<sockaddr*>(&async_data->input_addr.first),
|
||||
async_data->input_addr.second);
|
||||
async_data->connect_error = (async_data->ret == SOCKET_ERROR_VALUE) ? GET_ERRNO : 0;
|
||||
return 0;
|
||||
},
|
||||
|
@ -2047,14 +2084,15 @@ void SOC_U::GetNameInfoImpl(Kernel::HLERequestContext& ctx) {
|
|||
|
||||
CTRSockAddr ctr_sa;
|
||||
std::memcpy(&ctr_sa, sa_buff.data(), socklen);
|
||||
sockaddr sa = CTRSockAddr::ToPlatform(ctr_sa);
|
||||
auto [sa, sa_len] = CTRSockAddr::ToPlatform(ctr_sa);
|
||||
|
||||
std::vector<u8> host(hostlen);
|
||||
std::vector<u8> serv(servlen);
|
||||
char* host_data = hostlen > 0 ? reinterpret_cast<char*>(host.data()) : nullptr;
|
||||
char* serv_data = servlen > 0 ? reinterpret_cast<char*>(serv.data()) : nullptr;
|
||||
|
||||
s32 ret = getnameinfo(&sa, sizeof(sa), host_data, hostlen, serv_data, servlen, flags);
|
||||
s32 ret = getnameinfo(reinterpret_cast<sockaddr*>(&sa), sa_len, host_data, hostlen, serv_data,
|
||||
servlen, flags);
|
||||
if (ret == SOCKET_ERROR_VALUE) {
|
||||
ret = TranslateError(GET_ERRNO);
|
||||
}
|
||||
|
|
|
@ -429,18 +429,20 @@ Common::ParamPackage SDLState::GetSDLControllerButtonBindByGUID(
|
|||
|
||||
#if SDL_VERSION_ATLEAST(2, 0, 6)
|
||||
{
|
||||
const SDL_ExtendedGameControllerBind extended_bind =
|
||||
controller->bindings[mapped_button];
|
||||
if (extended_bind.input.axis.axis_max < extended_bind.input.axis.axis_min) {
|
||||
params.Set("direction", "-");
|
||||
} else {
|
||||
params.Set("direction", "+");
|
||||
if (mapped_button != SDL_CONTROLLER_BUTTON_INVALID) {
|
||||
const SDL_ExtendedGameControllerBind extended_bind =
|
||||
controller->bindings[mapped_button];
|
||||
if (extended_bind.input.axis.axis_max < extended_bind.input.axis.axis_min) {
|
||||
params.Set("direction", "-");
|
||||
} else {
|
||||
params.Set("direction", "+");
|
||||
}
|
||||
params.Set("threshold", (extended_bind.input.axis.axis_min +
|
||||
(extended_bind.input.axis.axis_max -
|
||||
extended_bind.input.axis.axis_min) /
|
||||
2.0f) /
|
||||
SDL_JOYSTICK_AXIS_MAX);
|
||||
}
|
||||
params.Set(
|
||||
"threshold",
|
||||
(extended_bind.input.axis.axis_min +
|
||||
(extended_bind.input.axis.axis_max - extended_bind.input.axis.axis_min) / 2.0f) /
|
||||
SDL_JOYSTICK_AXIS_MAX);
|
||||
}
|
||||
#else
|
||||
params.Set("direction", "+"); // lacks extended_bind, so just a guess
|
||||
|
|
Loading…
Reference in a new issue