Compare commits
19 Commits
android-24
...
android-24
Author | SHA1 | Date | |
---|---|---|---|
26ff2f6008 | |||
c41e38e94a | |||
85347b6458 | |||
8e75ebd166 | |||
25c25c7a88 | |||
fff2c30600 | |||
95d96cfe66 | |||
f75fceb3c0 | |||
3511d5552a | |||
f27bdce70f | |||
85fd2bcb82 | |||
836592c447 | |||
fbc1b61bff | |||
26e028808a | |||
2053ff96fc | |||
9ce43ee677 | |||
7cfb51e5e7 | |||
2c357c929c | |||
482e203d5c |
@ -2,9 +2,9 @@
|
|||||||
|----|----|----|----|----|
|
|----|----|----|----|----|
|
||||||
| [12461](https://github.com/yuzu-emu/yuzu//pull/12461) | [`acc26667b`](https://github.com/yuzu-emu/yuzu//pull/12461/files) | Rework Nvdec and VIC to fix out-of-order videos, and speed up decoding. | [Kelebek1](https://github.com/Kelebek1/) | Yes |
|
| [12461](https://github.com/yuzu-emu/yuzu//pull/12461) | [`acc26667b`](https://github.com/yuzu-emu/yuzu//pull/12461/files) | Rework Nvdec and VIC to fix out-of-order videos, and speed up decoding. | [Kelebek1](https://github.com/Kelebek1/) | Yes |
|
||||||
| [12749](https://github.com/yuzu-emu/yuzu//pull/12749) | [`aad4b0d6f`](https://github.com/yuzu-emu/yuzu//pull/12749/files) | general: workarounds for SMMU syncing issues | [liamwhite](https://github.com/liamwhite/) | Yes |
|
| [12749](https://github.com/yuzu-emu/yuzu//pull/12749) | [`aad4b0d6f`](https://github.com/yuzu-emu/yuzu//pull/12749/files) | general: workarounds for SMMU syncing issues | [liamwhite](https://github.com/liamwhite/) | Yes |
|
||||||
| [12975](https://github.com/yuzu-emu/yuzu//pull/12975) | [`9ce43ee67`](https://github.com/yuzu-emu/yuzu//pull/12975/files) | Texture Cache: Fix untracking on GPU remap | [FernandoS27](https://github.com/FernandoS27/) | Yes |
|
|
||||||
| [12993](https://github.com/yuzu-emu/yuzu//pull/12993) | [`bca698a17`](https://github.com/yuzu-emu/yuzu//pull/12993/files) | am: rewrite part 1 | [liamwhite](https://github.com/liamwhite/) | Yes |
|
| [12993](https://github.com/yuzu-emu/yuzu//pull/12993) | [`bca698a17`](https://github.com/yuzu-emu/yuzu//pull/12993/files) | am: rewrite part 1 | [liamwhite](https://github.com/liamwhite/) | Yes |
|
||||||
| [12998](https://github.com/yuzu-emu/yuzu//pull/12998) | [`836592c44`](https://github.com/yuzu-emu/yuzu//pull/12998/files) | android: Swap confirmation buttons for delete save data dialog | [t895](https://github.com/t895/) | Yes |
|
| [13000](https://github.com/yuzu-emu/yuzu//pull/13000) | [`461eaca7e`](https://github.com/yuzu-emu/yuzu//pull/13000/files) | device_memory_manager: skip unregistered interfaces on invalidate | [liamwhite](https://github.com/liamwhite/) | Yes |
|
||||||
|
| [13007](https://github.com/yuzu-emu/yuzu//pull/13007) | [`3c823254f`](https://github.com/yuzu-emu/yuzu//pull/13007/files) | android: Expose FSR slider and add vertical alignment setting | [t895](https://github.com/t895/) | Yes |
|
||||||
|
|
||||||
|
|
||||||
End of merge log. You can find the original README.md below the break.
|
End of merge log. You can find the original README.md below the break.
|
||||||
|
@ -24,7 +24,9 @@ enum class IntSetting(override val key: String) : AbstractIntSetting {
|
|||||||
THEME_MODE("theme_mode"),
|
THEME_MODE("theme_mode"),
|
||||||
OVERLAY_SCALE("control_scale"),
|
OVERLAY_SCALE("control_scale"),
|
||||||
OVERLAY_OPACITY("control_opacity"),
|
OVERLAY_OPACITY("control_opacity"),
|
||||||
LOCK_DRAWER("lock_drawer");
|
LOCK_DRAWER("lock_drawer"),
|
||||||
|
VERTICAL_ALIGNMENT("vertical_alignment"),
|
||||||
|
FSR_SHARPENING_SLIDER("fsr_sharpening_slider");
|
||||||
|
|
||||||
override fun getInt(needsGlobal: Boolean): Int = NativeConfig.getInt(key, needsGlobal)
|
override fun getInt(needsGlobal: Boolean): Int = NativeConfig.getInt(key, needsGlobal)
|
||||||
|
|
||||||
|
@ -93,4 +93,15 @@ object Settings {
|
|||||||
entries.firstOrNull { it.int == int } ?: Unspecified
|
entries.firstOrNull { it.int == int } ?: Unspecified
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum class EmulationVerticalAlignment(val int: Int) {
|
||||||
|
Top(1),
|
||||||
|
Center(0),
|
||||||
|
Bottom(2);
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
fun from(int: Int): EmulationVerticalAlignment =
|
||||||
|
entries.firstOrNull { it.int == int } ?: Center
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -188,6 +188,16 @@ abstract class SettingsItem(
|
|||||||
R.array.rendererScalingFilterValues
|
R.array.rendererScalingFilterValues
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
put(
|
||||||
|
SliderSetting(
|
||||||
|
IntSetting.FSR_SHARPENING_SLIDER,
|
||||||
|
R.string.fsr_sharpness,
|
||||||
|
R.string.fsr_sharpness_description,
|
||||||
|
0,
|
||||||
|
100,
|
||||||
|
"%"
|
||||||
|
)
|
||||||
|
)
|
||||||
put(
|
put(
|
||||||
SingleChoiceSetting(
|
SingleChoiceSetting(
|
||||||
IntSetting.RENDERER_ANTI_ALIASING,
|
IntSetting.RENDERER_ANTI_ALIASING,
|
||||||
@ -215,6 +225,15 @@ abstract class SettingsItem(
|
|||||||
R.array.rendererAspectRatioValues
|
R.array.rendererAspectRatioValues
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
put(
|
||||||
|
SingleChoiceSetting(
|
||||||
|
IntSetting.VERTICAL_ALIGNMENT,
|
||||||
|
R.string.vertical_alignment,
|
||||||
|
0,
|
||||||
|
R.array.verticalAlignmentEntries,
|
||||||
|
R.array.verticalAlignmentValues
|
||||||
|
)
|
||||||
|
)
|
||||||
put(
|
put(
|
||||||
SwitchSetting(
|
SwitchSetting(
|
||||||
BooleanSetting.RENDERER_USE_DISK_SHADER_CACHE,
|
BooleanSetting.RENDERER_USE_DISK_SHADER_CACHE,
|
||||||
|
@ -143,10 +143,12 @@ class SettingsFragmentPresenter(
|
|||||||
add(IntSetting.RENDERER_RESOLUTION.key)
|
add(IntSetting.RENDERER_RESOLUTION.key)
|
||||||
add(IntSetting.RENDERER_VSYNC.key)
|
add(IntSetting.RENDERER_VSYNC.key)
|
||||||
add(IntSetting.RENDERER_SCALING_FILTER.key)
|
add(IntSetting.RENDERER_SCALING_FILTER.key)
|
||||||
|
add(IntSetting.FSR_SHARPENING_SLIDER.key)
|
||||||
add(IntSetting.RENDERER_ANTI_ALIASING.key)
|
add(IntSetting.RENDERER_ANTI_ALIASING.key)
|
||||||
add(IntSetting.MAX_ANISOTROPY.key)
|
add(IntSetting.MAX_ANISOTROPY.key)
|
||||||
add(IntSetting.RENDERER_SCREEN_LAYOUT.key)
|
add(IntSetting.RENDERER_SCREEN_LAYOUT.key)
|
||||||
add(IntSetting.RENDERER_ASPECT_RATIO.key)
|
add(IntSetting.RENDERER_ASPECT_RATIO.key)
|
||||||
|
add(IntSetting.VERTICAL_ALIGNMENT.key)
|
||||||
add(BooleanSetting.PICTURE_IN_PICTURE.key)
|
add(BooleanSetting.PICTURE_IN_PICTURE.key)
|
||||||
add(BooleanSetting.RENDERER_USE_DISK_SHADER_CACHE.key)
|
add(BooleanSetting.RENDERER_USE_DISK_SHADER_CACHE.key)
|
||||||
add(BooleanSetting.RENDERER_FORCE_MAX_CLOCK.key)
|
add(BooleanSetting.RENDERER_FORCE_MAX_CLOCK.key)
|
||||||
|
@ -15,7 +15,9 @@ import android.os.Handler
|
|||||||
import android.os.Looper
|
import android.os.Looper
|
||||||
import android.os.PowerManager
|
import android.os.PowerManager
|
||||||
import android.os.SystemClock
|
import android.os.SystemClock
|
||||||
|
import android.util.Rational
|
||||||
import android.view.*
|
import android.view.*
|
||||||
|
import android.widget.FrameLayout
|
||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import androidx.activity.OnBackPressedCallback
|
import androidx.activity.OnBackPressedCallback
|
||||||
@ -24,6 +26,7 @@ import androidx.core.content.res.ResourcesCompat
|
|||||||
import androidx.core.graphics.Insets
|
import androidx.core.graphics.Insets
|
||||||
import androidx.core.view.ViewCompat
|
import androidx.core.view.ViewCompat
|
||||||
import androidx.core.view.WindowInsetsCompat
|
import androidx.core.view.WindowInsetsCompat
|
||||||
|
import androidx.core.view.updateLayoutParams
|
||||||
import androidx.core.view.updatePadding
|
import androidx.core.view.updatePadding
|
||||||
import androidx.drawerlayout.widget.DrawerLayout
|
import androidx.drawerlayout.widget.DrawerLayout
|
||||||
import androidx.drawerlayout.widget.DrawerLayout.DrawerListener
|
import androidx.drawerlayout.widget.DrawerLayout.DrawerListener
|
||||||
@ -52,6 +55,7 @@ import org.yuzu.yuzu_emu.features.settings.model.BooleanSetting
|
|||||||
import org.yuzu.yuzu_emu.features.settings.model.IntSetting
|
import org.yuzu.yuzu_emu.features.settings.model.IntSetting
|
||||||
import org.yuzu.yuzu_emu.features.settings.model.Settings
|
import org.yuzu.yuzu_emu.features.settings.model.Settings
|
||||||
import org.yuzu.yuzu_emu.features.settings.model.Settings.EmulationOrientation
|
import org.yuzu.yuzu_emu.features.settings.model.Settings.EmulationOrientation
|
||||||
|
import org.yuzu.yuzu_emu.features.settings.model.Settings.EmulationVerticalAlignment
|
||||||
import org.yuzu.yuzu_emu.features.settings.utils.SettingsFile
|
import org.yuzu.yuzu_emu.features.settings.utils.SettingsFile
|
||||||
import org.yuzu.yuzu_emu.model.DriverViewModel
|
import org.yuzu.yuzu_emu.model.DriverViewModel
|
||||||
import org.yuzu.yuzu_emu.model.Game
|
import org.yuzu.yuzu_emu.model.Game
|
||||||
@ -617,7 +621,46 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun updateScreenLayout() {
|
private fun updateScreenLayout() {
|
||||||
binding.surfaceEmulation.setAspectRatio(null)
|
val verticalAlignment =
|
||||||
|
EmulationVerticalAlignment.from(IntSetting.VERTICAL_ALIGNMENT.getInt())
|
||||||
|
val aspectRatio = when (IntSetting.RENDERER_ASPECT_RATIO.getInt()) {
|
||||||
|
0 -> Rational(16, 9)
|
||||||
|
1 -> Rational(4, 3)
|
||||||
|
2 -> Rational(21, 9)
|
||||||
|
3 -> Rational(16, 10)
|
||||||
|
else -> null // Best fit
|
||||||
|
}
|
||||||
|
when (verticalAlignment) {
|
||||||
|
EmulationVerticalAlignment.Top -> {
|
||||||
|
binding.surfaceEmulation.setAspectRatio(aspectRatio)
|
||||||
|
val params = FrameLayout.LayoutParams(
|
||||||
|
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||||
|
ViewGroup.LayoutParams.WRAP_CONTENT
|
||||||
|
)
|
||||||
|
params.gravity = Gravity.TOP or Gravity.CENTER_HORIZONTAL
|
||||||
|
binding.surfaceEmulation.layoutParams = params
|
||||||
|
}
|
||||||
|
|
||||||
|
EmulationVerticalAlignment.Center -> {
|
||||||
|
binding.surfaceEmulation.setAspectRatio(null)
|
||||||
|
binding.surfaceEmulation.updateLayoutParams {
|
||||||
|
width = ViewGroup.LayoutParams.MATCH_PARENT
|
||||||
|
height = ViewGroup.LayoutParams.MATCH_PARENT
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
EmulationVerticalAlignment.Bottom -> {
|
||||||
|
binding.surfaceEmulation.setAspectRatio(aspectRatio)
|
||||||
|
val params =
|
||||||
|
FrameLayout.LayoutParams(
|
||||||
|
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||||
|
ViewGroup.LayoutParams.WRAP_CONTENT
|
||||||
|
)
|
||||||
|
params.gravity = Gravity.BOTTOM or Gravity.CENTER_HORIZONTAL
|
||||||
|
binding.surfaceEmulation.layoutParams = params
|
||||||
|
}
|
||||||
|
}
|
||||||
|
emulationState.updateSurface()
|
||||||
emulationActivity?.buildPictureInPictureParams()
|
emulationActivity?.buildPictureInPictureParams()
|
||||||
updateOrientation()
|
updateOrientation()
|
||||||
}
|
}
|
||||||
|
@ -38,6 +38,13 @@ struct Values {
|
|||||||
Settings::Specialization::Default,
|
Settings::Specialization::Default,
|
||||||
true,
|
true,
|
||||||
true};
|
true};
|
||||||
|
Settings::Setting<s32> vertical_alignment{linkage,
|
||||||
|
0,
|
||||||
|
"vertical_alignment",
|
||||||
|
Settings::Category::Android,
|
||||||
|
Settings::Specialization::Default,
|
||||||
|
true,
|
||||||
|
true};
|
||||||
|
|
||||||
Settings::SwitchableSetting<std::string, false> driver_path{linkage, "", "driver_path",
|
Settings::SwitchableSetting<std::string, false> driver_path{linkage, "", "driver_path",
|
||||||
Settings::Category::GpuDriver};
|
Settings::Category::GpuDriver};
|
||||||
|
@ -292,4 +292,15 @@
|
|||||||
<item>5</item>
|
<item>5</item>
|
||||||
</integer-array>
|
</integer-array>
|
||||||
|
|
||||||
|
<string-array name="verticalAlignmentEntries">
|
||||||
|
<item>@string/top</item>
|
||||||
|
<item>@string/center</item>
|
||||||
|
<item>@string/bottom</item>
|
||||||
|
</string-array>
|
||||||
|
<integer-array name="verticalAlignmentValues">
|
||||||
|
<item>1</item>
|
||||||
|
<item>0</item>
|
||||||
|
<item>2</item>
|
||||||
|
</integer-array>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
|
@ -226,6 +226,8 @@
|
|||||||
<string name="renderer_screen_layout">Orientation</string>
|
<string name="renderer_screen_layout">Orientation</string>
|
||||||
<string name="renderer_aspect_ratio">Aspect ratio</string>
|
<string name="renderer_aspect_ratio">Aspect ratio</string>
|
||||||
<string name="renderer_scaling_filter">Window adapting filter</string>
|
<string name="renderer_scaling_filter">Window adapting filter</string>
|
||||||
|
<string name="fsr_sharpness">FSR sharpness</string>
|
||||||
|
<string name="fsr_sharpness_description">Determines how sharpened the image will look while using FSR\'s dynamic contrast</string>
|
||||||
<string name="renderer_anti_aliasing">Anti-aliasing method</string>
|
<string name="renderer_anti_aliasing">Anti-aliasing method</string>
|
||||||
<string name="renderer_force_max_clock">Force maximum clocks (Adreno only)</string>
|
<string name="renderer_force_max_clock">Force maximum clocks (Adreno only)</string>
|
||||||
<string name="renderer_force_max_clock_description">Forces the GPU to run at the maximum possible clocks (thermal constraints will still be applied).</string>
|
<string name="renderer_force_max_clock_description">Forces the GPU to run at the maximum possible clocks (thermal constraints will still be applied).</string>
|
||||||
@ -558,6 +560,12 @@
|
|||||||
<string name="mute">Mute</string>
|
<string name="mute">Mute</string>
|
||||||
<string name="unmute">Unmute</string>
|
<string name="unmute">Unmute</string>
|
||||||
|
|
||||||
|
<!-- Emulation vertical alignment -->
|
||||||
|
<string name="vertical_alignment">Vertical alignment</string>
|
||||||
|
<string name="top">Top</string>
|
||||||
|
<string name="center">Center</string>
|
||||||
|
<string name="bottom">Bottom</string>
|
||||||
|
|
||||||
<!-- Licenses screen strings -->
|
<!-- Licenses screen strings -->
|
||||||
<string name="licenses">Licenses</string>
|
<string name="licenses">Licenses</string>
|
||||||
<string name="license_fidelityfx_fsr" translatable="false">FidelityFX-FSR</string>
|
<string name="license_fidelityfx_fsr" translatable="false">FidelityFX-FSR</string>
|
||||||
|
@ -666,6 +666,18 @@ add_library(core STATIC
|
|||||||
hle/service/ldn/ldn.h
|
hle/service/ldn/ldn.h
|
||||||
hle/service/ldn/ldn_results.h
|
hle/service/ldn/ldn_results.h
|
||||||
hle/service/ldn/ldn_types.h
|
hle/service/ldn/ldn_types.h
|
||||||
|
hle/service/ldn/monitor_service.cpp
|
||||||
|
hle/service/ldn/monitor_service.h
|
||||||
|
hle/service/ldn/sf_monitor_service.cpp
|
||||||
|
hle/service/ldn/sf_monitor_service.h
|
||||||
|
hle/service/ldn/sf_service.cpp
|
||||||
|
hle/service/ldn/sf_service.h
|
||||||
|
hle/service/ldn/sf_service_monitor.cpp
|
||||||
|
hle/service/ldn/sf_service_monitor.h
|
||||||
|
hle/service/ldn/system_local_communication_service.cpp
|
||||||
|
hle/service/ldn/system_local_communication_service.h
|
||||||
|
hle/service/ldn/user_local_communication_service.cpp
|
||||||
|
hle/service/ldn/user_local_communication_service.h
|
||||||
hle/service/ldr/ldr.cpp
|
hle/service/ldr/ldr.cpp
|
||||||
hle/service/ldr/ldr.h
|
hle/service/ldr/ldr.h
|
||||||
hle/service/lm/lm.cpp
|
hle/service/lm/lm.cpp
|
||||||
|
@ -522,13 +522,17 @@ void DeviceMemoryManager<Traits>::UpdatePagesCachedCount(DAddr addr, size_t size
|
|||||||
auto* memory_device_inter = registered_processes[asid.id];
|
auto* memory_device_inter = registered_processes[asid.id];
|
||||||
const auto release_pending = [&] {
|
const auto release_pending = [&] {
|
||||||
if (uncache_bytes > 0) {
|
if (uncache_bytes > 0) {
|
||||||
MarkRegionCaching(memory_device_inter, uncache_begin << Memory::YUZU_PAGEBITS,
|
if (memory_device_inter != nullptr) {
|
||||||
uncache_bytes, false);
|
MarkRegionCaching(memory_device_inter, uncache_begin << Memory::YUZU_PAGEBITS,
|
||||||
|
uncache_bytes, false);
|
||||||
|
}
|
||||||
uncache_bytes = 0;
|
uncache_bytes = 0;
|
||||||
}
|
}
|
||||||
if (cache_bytes > 0) {
|
if (cache_bytes > 0) {
|
||||||
MarkRegionCaching(memory_device_inter, cache_begin << Memory::YUZU_PAGEBITS,
|
if (memory_device_inter != nullptr) {
|
||||||
cache_bytes, true);
|
MarkRegionCaching(memory_device_inter, cache_begin << Memory::YUZU_PAGEBITS,
|
||||||
|
cache_bytes, true);
|
||||||
|
}
|
||||||
cache_bytes = 0;
|
cache_bytes = 0;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -85,15 +85,14 @@ Result LANDiscovery::GetNetworkInfo(NetworkInfo& out_network) const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Result LANDiscovery::GetNetworkInfo(NetworkInfo& out_network,
|
Result LANDiscovery::GetNetworkInfo(NetworkInfo& out_network,
|
||||||
std::vector<NodeLatestUpdate>& out_updates,
|
std::span<NodeLatestUpdate> out_updates) {
|
||||||
std::size_t buffer_count) {
|
if (out_updates.size() > NodeCountMax) {
|
||||||
if (buffer_count > NodeCountMax) {
|
|
||||||
return ResultInvalidBufferCount;
|
return ResultInvalidBufferCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (state == State::AccessPointCreated || state == State::StationConnected) {
|
if (state == State::AccessPointCreated || state == State::StationConnected) {
|
||||||
std::memcpy(&out_network, &network_info, sizeof(network_info));
|
std::memcpy(&out_network, &network_info, sizeof(network_info));
|
||||||
for (std::size_t i = 0; i < buffer_count; i++) {
|
for (std::size_t i = 0; i < out_updates.size(); i++) {
|
||||||
out_updates[i].state_change = node_changes[i].state_change;
|
out_updates[i].state_change = node_changes[i].state_change;
|
||||||
node_changes[i].state_change = NodeStateChange::None;
|
node_changes[i].state_change = NodeStateChange::None;
|
||||||
}
|
}
|
||||||
@ -107,15 +106,8 @@ DisconnectReason LANDiscovery::GetDisconnectReason() const {
|
|||||||
return disconnect_reason;
|
return disconnect_reason;
|
||||||
}
|
}
|
||||||
|
|
||||||
Result LANDiscovery::Scan(std::vector<NetworkInfo>& networks, u16& count,
|
Result LANDiscovery::Scan(std::span<NetworkInfo> out_networks, s16& out_count,
|
||||||
const ScanFilter& filter) {
|
const ScanFilter& filter) {
|
||||||
if (!IsFlagSet(filter.flag, ScanFilterFlag::NetworkType) ||
|
|
||||||
filter.network_type <= NetworkType::All) {
|
|
||||||
if (!IsFlagSet(filter.flag, ScanFilterFlag::Ssid) && filter.ssid.length >= SsidLengthMax) {
|
|
||||||
return ResultBadInput;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
{
|
||||||
std::scoped_lock lock{packet_mutex};
|
std::scoped_lock lock{packet_mutex};
|
||||||
scan_results.clear();
|
scan_results.clear();
|
||||||
@ -128,7 +120,7 @@ Result LANDiscovery::Scan(std::vector<NetworkInfo>& networks, u16& count,
|
|||||||
|
|
||||||
std::scoped_lock lock{packet_mutex};
|
std::scoped_lock lock{packet_mutex};
|
||||||
for (const auto& [key, info] : scan_results) {
|
for (const auto& [key, info] : scan_results) {
|
||||||
if (count >= networks.size()) {
|
if (out_count >= static_cast<s16>(out_networks.size())) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -159,7 +151,7 @@ Result LANDiscovery::Scan(std::vector<NetworkInfo>& networks, u16& count,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
networks[count++] = info;
|
out_networks[out_count++] = info;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ResultSuccess;
|
return ResultSuccess;
|
||||||
|
@ -54,11 +54,10 @@ public:
|
|||||||
void SetState(State new_state);
|
void SetState(State new_state);
|
||||||
|
|
||||||
Result GetNetworkInfo(NetworkInfo& out_network) const;
|
Result GetNetworkInfo(NetworkInfo& out_network) const;
|
||||||
Result GetNetworkInfo(NetworkInfo& out_network, std::vector<NodeLatestUpdate>& out_updates,
|
Result GetNetworkInfo(NetworkInfo& out_network, std::span<NodeLatestUpdate> out_updates);
|
||||||
std::size_t buffer_count);
|
|
||||||
|
|
||||||
DisconnectReason GetDisconnectReason() const;
|
DisconnectReason GetDisconnectReason() const;
|
||||||
Result Scan(std::vector<NetworkInfo>& networks, u16& count, const ScanFilter& filter);
|
Result Scan(std::span<NetworkInfo> out_networks, s16& out_count, const ScanFilter& filter);
|
||||||
Result SetAdvertiseData(std::span<const u8> data);
|
Result SetAdvertiseData(std::span<const u8> data);
|
||||||
|
|
||||||
Result OpenAccessPoint();
|
Result OpenAccessPoint();
|
||||||
|
@ -1,36 +1,24 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
#include "core/core.h"
|
#include "core/core.h"
|
||||||
#include "core/hle/service/ldn/lan_discovery.h"
|
#include "core/hle/service/cmif_serialization.h"
|
||||||
#include "core/hle/service/ldn/ldn.h"
|
#include "core/hle/service/ldn/ldn.h"
|
||||||
#include "core/hle/service/ldn/ldn_results.h"
|
#include "core/hle/service/ldn/monitor_service.h"
|
||||||
#include "core/hle/service/ldn/ldn_types.h"
|
#include "core/hle/service/ldn/sf_monitor_service.h"
|
||||||
#include "core/hle/service/server_manager.h"
|
#include "core/hle/service/ldn/sf_service.h"
|
||||||
#include "core/internal_network/network.h"
|
#include "core/hle/service/ldn/sf_service_monitor.h"
|
||||||
#include "core/internal_network/network_interface.h"
|
#include "core/hle/service/ldn/system_local_communication_service.h"
|
||||||
#include "network/network.h"
|
#include "core/hle/service/ldn/user_local_communication_service.h"
|
||||||
|
|
||||||
// This is defined by synchapi.h and conflicts with ServiceContext::CreateEvent
|
|
||||||
#undef CreateEvent
|
|
||||||
|
|
||||||
namespace Service::LDN {
|
namespace Service::LDN {
|
||||||
|
|
||||||
class IMonitorService final : public ServiceFramework<IMonitorService> {
|
class IMonitorServiceCreator final : public ServiceFramework<IMonitorServiceCreator> {
|
||||||
public:
|
public:
|
||||||
explicit IMonitorService(Core::System& system_) : ServiceFramework{system_, "IMonitorService"} {
|
explicit IMonitorServiceCreator(Core::System& system_) : ServiceFramework{system_, "ldn:m"} {
|
||||||
// clang-format off
|
// clang-format off
|
||||||
static const FunctionInfo functions[] = {
|
static const FunctionInfo functions[] = {
|
||||||
{0, &IMonitorService::GetStateForMonitor, "GetStateForMonitor"},
|
{0, C<&IMonitorServiceCreator::CreateMonitorService>, "CreateMonitorService"}
|
||||||
{1, nullptr, "GetNetworkInfoForMonitor"},
|
|
||||||
{2, nullptr, "GetIpv4AddressForMonitor"},
|
|
||||||
{3, nullptr, "GetDisconnectReasonForMonitor"},
|
|
||||||
{4, nullptr, "GetSecurityParameterForMonitor"},
|
|
||||||
{5, nullptr, "GetNetworkConfigForMonitor"},
|
|
||||||
{100, &IMonitorService::InitializeMonitor, "InitializeMonitor"},
|
|
||||||
{101, nullptr, "FinalizeMonitor"},
|
|
||||||
};
|
};
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
||||||
@ -38,84 +26,20 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void GetStateForMonitor(HLERequestContext& ctx) {
|
Result CreateMonitorService(OutInterface<IMonitorService> out_interface) {
|
||||||
LOG_INFO(Service_LDN, "called");
|
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 3};
|
|
||||||
rb.Push(ResultSuccess);
|
|
||||||
rb.PushEnum(state);
|
|
||||||
}
|
|
||||||
|
|
||||||
void InitializeMonitor(HLERequestContext& ctx) {
|
|
||||||
LOG_INFO(Service_LDN, "called");
|
|
||||||
|
|
||||||
state = State::Initialized;
|
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
|
||||||
rb.Push(ResultSuccess);
|
|
||||||
}
|
|
||||||
|
|
||||||
State state{State::None};
|
|
||||||
};
|
|
||||||
|
|
||||||
class LDNM final : public ServiceFramework<LDNM> {
|
|
||||||
public:
|
|
||||||
explicit LDNM(Core::System& system_) : ServiceFramework{system_, "ldn:m"} {
|
|
||||||
// clang-format off
|
|
||||||
static const FunctionInfo functions[] = {
|
|
||||||
{0, &LDNM::CreateMonitorService, "CreateMonitorService"}
|
|
||||||
};
|
|
||||||
// clang-format on
|
|
||||||
|
|
||||||
RegisterHandlers(functions);
|
|
||||||
}
|
|
||||||
|
|
||||||
void CreateMonitorService(HLERequestContext& ctx) {
|
|
||||||
LOG_DEBUG(Service_LDN, "called");
|
LOG_DEBUG(Service_LDN, "called");
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
*out_interface = std::make_shared<IMonitorService>(system);
|
||||||
rb.Push(ResultSuccess);
|
R_SUCCEED();
|
||||||
rb.PushIpcInterface<IMonitorService>(system);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class ISystemLocalCommunicationService final
|
class ISystemServiceCreator final : public ServiceFramework<ISystemServiceCreator> {
|
||||||
: public ServiceFramework<ISystemLocalCommunicationService> {
|
|
||||||
public:
|
public:
|
||||||
explicit ISystemLocalCommunicationService(Core::System& system_)
|
explicit ISystemServiceCreator(Core::System& system_) : ServiceFramework{system_, "ldn:s"} {
|
||||||
: ServiceFramework{system_, "ISystemLocalCommunicationService"} {
|
|
||||||
// clang-format off
|
// clang-format off
|
||||||
static const FunctionInfo functions[] = {
|
static const FunctionInfo functions[] = {
|
||||||
{0, nullptr, "GetState"},
|
{0, C<&ISystemServiceCreator::CreateSystemLocalCommunicationService>, "CreateSystemLocalCommunicationService"},
|
||||||
{1, nullptr, "GetNetworkInfo"},
|
|
||||||
{2, nullptr, "GetIpv4Address"},
|
|
||||||
{3, nullptr, "GetDisconnectReason"},
|
|
||||||
{4, nullptr, "GetSecurityParameter"},
|
|
||||||
{5, nullptr, "GetNetworkConfig"},
|
|
||||||
{100, nullptr, "AttachStateChangeEvent"},
|
|
||||||
{101, nullptr, "GetNetworkInfoLatestUpdate"},
|
|
||||||
{102, nullptr, "Scan"},
|
|
||||||
{103, nullptr, "ScanPrivate"},
|
|
||||||
{104, nullptr, "SetWirelessControllerRestriction"},
|
|
||||||
{200, nullptr, "OpenAccessPoint"},
|
|
||||||
{201, nullptr, "CloseAccessPoint"},
|
|
||||||
{202, nullptr, "CreateNetwork"},
|
|
||||||
{203, nullptr, "CreateNetworkPrivate"},
|
|
||||||
{204, nullptr, "DestroyNetwork"},
|
|
||||||
{205, nullptr, "Reject"},
|
|
||||||
{206, nullptr, "SetAdvertiseData"},
|
|
||||||
{207, nullptr, "SetStationAcceptPolicy"},
|
|
||||||
{208, nullptr, "AddAcceptFilterEntry"},
|
|
||||||
{209, nullptr, "ClearAcceptFilter"},
|
|
||||||
{300, nullptr, "OpenStation"},
|
|
||||||
{301, nullptr, "CloseStation"},
|
|
||||||
{302, nullptr, "Connect"},
|
|
||||||
{303, nullptr, "ConnectPrivate"},
|
|
||||||
{304, nullptr, "Disconnect"},
|
|
||||||
{400, nullptr, "InitializeSystem"},
|
|
||||||
{401, nullptr, "FinalizeSystem"},
|
|
||||||
{402, nullptr, "SetOperationMode"},
|
|
||||||
{403, &ISystemLocalCommunicationService::InitializeSystem2, "InitializeSystem2"},
|
|
||||||
};
|
};
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
||||||
@ -123,651 +47,78 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void InitializeSystem2(HLERequestContext& ctx) {
|
Result CreateSystemLocalCommunicationService(
|
||||||
LOG_WARNING(Service_LDN, "(STUBBED) called");
|
OutInterface<ISystemLocalCommunicationService> out_interface) {
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
|
||||||
rb.Push(ResultSuccess);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class IUserLocalCommunicationService final
|
|
||||||
: public ServiceFramework<IUserLocalCommunicationService> {
|
|
||||||
public:
|
|
||||||
explicit IUserLocalCommunicationService(Core::System& system_)
|
|
||||||
: ServiceFramework{system_, "IUserLocalCommunicationService"},
|
|
||||||
service_context{system, "IUserLocalCommunicationService"},
|
|
||||||
room_network{system_.GetRoomNetwork()}, lan_discovery{room_network} {
|
|
||||||
// clang-format off
|
|
||||||
static const FunctionInfo functions[] = {
|
|
||||||
{0, &IUserLocalCommunicationService::GetState, "GetState"},
|
|
||||||
{1, &IUserLocalCommunicationService::GetNetworkInfo, "GetNetworkInfo"},
|
|
||||||
{2, &IUserLocalCommunicationService::GetIpv4Address, "GetIpv4Address"},
|
|
||||||
{3, &IUserLocalCommunicationService::GetDisconnectReason, "GetDisconnectReason"},
|
|
||||||
{4, &IUserLocalCommunicationService::GetSecurityParameter, "GetSecurityParameter"},
|
|
||||||
{5, &IUserLocalCommunicationService::GetNetworkConfig, "GetNetworkConfig"},
|
|
||||||
{100, &IUserLocalCommunicationService::AttachStateChangeEvent, "AttachStateChangeEvent"},
|
|
||||||
{101, &IUserLocalCommunicationService::GetNetworkInfoLatestUpdate, "GetNetworkInfoLatestUpdate"},
|
|
||||||
{102, &IUserLocalCommunicationService::Scan, "Scan"},
|
|
||||||
{103, &IUserLocalCommunicationService::ScanPrivate, "ScanPrivate"},
|
|
||||||
{104, &IUserLocalCommunicationService::SetWirelessControllerRestriction, "SetWirelessControllerRestriction"},
|
|
||||||
{200, &IUserLocalCommunicationService::OpenAccessPoint, "OpenAccessPoint"},
|
|
||||||
{201, &IUserLocalCommunicationService::CloseAccessPoint, "CloseAccessPoint"},
|
|
||||||
{202, &IUserLocalCommunicationService::CreateNetwork, "CreateNetwork"},
|
|
||||||
{203, &IUserLocalCommunicationService::CreateNetworkPrivate, "CreateNetworkPrivate"},
|
|
||||||
{204, &IUserLocalCommunicationService::DestroyNetwork, "DestroyNetwork"},
|
|
||||||
{205, nullptr, "Reject"},
|
|
||||||
{206, &IUserLocalCommunicationService::SetAdvertiseData, "SetAdvertiseData"},
|
|
||||||
{207, &IUserLocalCommunicationService::SetStationAcceptPolicy, "SetStationAcceptPolicy"},
|
|
||||||
{208, &IUserLocalCommunicationService::AddAcceptFilterEntry, "AddAcceptFilterEntry"},
|
|
||||||
{209, nullptr, "ClearAcceptFilter"},
|
|
||||||
{300, &IUserLocalCommunicationService::OpenStation, "OpenStation"},
|
|
||||||
{301, &IUserLocalCommunicationService::CloseStation, "CloseStation"},
|
|
||||||
{302, &IUserLocalCommunicationService::Connect, "Connect"},
|
|
||||||
{303, nullptr, "ConnectPrivate"},
|
|
||||||
{304, &IUserLocalCommunicationService::Disconnect, "Disconnect"},
|
|
||||||
{400, &IUserLocalCommunicationService::Initialize, "Initialize"},
|
|
||||||
{401, &IUserLocalCommunicationService::Finalize, "Finalize"},
|
|
||||||
{402, &IUserLocalCommunicationService::Initialize2, "Initialize2"},
|
|
||||||
};
|
|
||||||
// clang-format on
|
|
||||||
|
|
||||||
RegisterHandlers(functions);
|
|
||||||
|
|
||||||
state_change_event =
|
|
||||||
service_context.CreateEvent("IUserLocalCommunicationService:StateChangeEvent");
|
|
||||||
}
|
|
||||||
|
|
||||||
~IUserLocalCommunicationService() {
|
|
||||||
if (is_initialized) {
|
|
||||||
if (auto room_member = room_network.GetRoomMember().lock()) {
|
|
||||||
room_member->Unbind(ldn_packet_received);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
service_context.CloseEvent(state_change_event);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Callback to parse and handle a received LDN packet.
|
|
||||||
void OnLDNPacketReceived(const Network::LDNPacket& packet) {
|
|
||||||
lan_discovery.ReceivePacket(packet);
|
|
||||||
}
|
|
||||||
|
|
||||||
void OnEventFired() {
|
|
||||||
state_change_event->Signal();
|
|
||||||
}
|
|
||||||
|
|
||||||
void GetState(HLERequestContext& ctx) {
|
|
||||||
State state = State::Error;
|
|
||||||
|
|
||||||
if (is_initialized) {
|
|
||||||
state = lan_discovery.GetState();
|
|
||||||
}
|
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 3};
|
|
||||||
rb.Push(ResultSuccess);
|
|
||||||
rb.PushEnum(state);
|
|
||||||
}
|
|
||||||
|
|
||||||
void GetNetworkInfo(HLERequestContext& ctx) {
|
|
||||||
const auto write_buffer_size = ctx.GetWriteBufferSize();
|
|
||||||
|
|
||||||
if (write_buffer_size != sizeof(NetworkInfo)) {
|
|
||||||
LOG_ERROR(Service_LDN, "Invalid buffer size {}", write_buffer_size);
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
|
||||||
rb.Push(ResultBadInput);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
NetworkInfo network_info{};
|
|
||||||
const auto rc = lan_discovery.GetNetworkInfo(network_info);
|
|
||||||
if (rc.IsError()) {
|
|
||||||
LOG_ERROR(Service_LDN, "NetworkInfo is not valid {}", rc.raw);
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
|
||||||
rb.Push(rc);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx.WriteBuffer<NetworkInfo>(network_info);
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
|
||||||
rb.Push(ResultSuccess);
|
|
||||||
}
|
|
||||||
|
|
||||||
void GetIpv4Address(HLERequestContext& ctx) {
|
|
||||||
const auto network_interface = Network::GetSelectedNetworkInterface();
|
|
||||||
|
|
||||||
if (!network_interface) {
|
|
||||||
LOG_ERROR(Service_LDN, "No network interface available");
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
|
||||||
rb.Push(ResultNoIpAddress);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ipv4Address current_address{Network::TranslateIPv4(network_interface->ip_address)};
|
|
||||||
Ipv4Address subnet_mask{Network::TranslateIPv4(network_interface->subnet_mask)};
|
|
||||||
|
|
||||||
// When we're connected to a room, spoof the hosts IP address
|
|
||||||
if (auto room_member = room_network.GetRoomMember().lock()) {
|
|
||||||
if (room_member->IsConnected()) {
|
|
||||||
current_address = room_member->GetFakeIpAddress();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::reverse(std::begin(current_address), std::end(current_address)); // ntohl
|
|
||||||
std::reverse(std::begin(subnet_mask), std::end(subnet_mask)); // ntohl
|
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 4};
|
|
||||||
rb.Push(ResultSuccess);
|
|
||||||
rb.PushRaw(current_address);
|
|
||||||
rb.PushRaw(subnet_mask);
|
|
||||||
}
|
|
||||||
|
|
||||||
void GetDisconnectReason(HLERequestContext& ctx) {
|
|
||||||
IPC::ResponseBuilder rb{ctx, 3};
|
|
||||||
rb.Push(ResultSuccess);
|
|
||||||
rb.PushEnum(lan_discovery.GetDisconnectReason());
|
|
||||||
}
|
|
||||||
|
|
||||||
void GetSecurityParameter(HLERequestContext& ctx) {
|
|
||||||
SecurityParameter security_parameter{};
|
|
||||||
NetworkInfo info{};
|
|
||||||
const Result rc = lan_discovery.GetNetworkInfo(info);
|
|
||||||
|
|
||||||
if (rc.IsError()) {
|
|
||||||
LOG_ERROR(Service_LDN, "NetworkInfo is not valid {}", rc.raw);
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
|
||||||
rb.Push(rc);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
security_parameter.session_id = info.network_id.session_id;
|
|
||||||
std::memcpy(security_parameter.data.data(), info.ldn.security_parameter.data(),
|
|
||||||
sizeof(SecurityParameter::data));
|
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 10};
|
|
||||||
rb.Push(rc);
|
|
||||||
rb.PushRaw<SecurityParameter>(security_parameter);
|
|
||||||
}
|
|
||||||
|
|
||||||
void GetNetworkConfig(HLERequestContext& ctx) {
|
|
||||||
NetworkConfig config{};
|
|
||||||
NetworkInfo info{};
|
|
||||||
const Result rc = lan_discovery.GetNetworkInfo(info);
|
|
||||||
|
|
||||||
if (rc.IsError()) {
|
|
||||||
LOG_ERROR(Service_LDN, "NetworkConfig is not valid {}", rc.raw);
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
|
||||||
rb.Push(rc);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
config.intent_id = info.network_id.intent_id;
|
|
||||||
config.channel = info.common.channel;
|
|
||||||
config.node_count_max = info.ldn.node_count_max;
|
|
||||||
config.local_communication_version = info.ldn.nodes[0].local_communication_version;
|
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 10};
|
|
||||||
rb.Push(rc);
|
|
||||||
rb.PushRaw<NetworkConfig>(config);
|
|
||||||
}
|
|
||||||
|
|
||||||
void AttachStateChangeEvent(HLERequestContext& ctx) {
|
|
||||||
LOG_INFO(Service_LDN, "called");
|
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2, 1};
|
|
||||||
rb.Push(ResultSuccess);
|
|
||||||
rb.PushCopyObjects(state_change_event->GetReadableEvent());
|
|
||||||
}
|
|
||||||
|
|
||||||
void GetNetworkInfoLatestUpdate(HLERequestContext& ctx) {
|
|
||||||
const std::size_t network_buffer_size = ctx.GetWriteBufferSize(0);
|
|
||||||
const std::size_t node_buffer_count = ctx.GetWriteBufferNumElements<NodeLatestUpdate>(1);
|
|
||||||
|
|
||||||
if (node_buffer_count == 0 || network_buffer_size != sizeof(NetworkInfo)) {
|
|
||||||
LOG_ERROR(Service_LDN, "Invalid buffer, size = {}, count = {}", network_buffer_size,
|
|
||||||
node_buffer_count);
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
|
||||||
rb.Push(ResultBadInput);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
NetworkInfo info{};
|
|
||||||
std::vector<NodeLatestUpdate> latest_update(node_buffer_count);
|
|
||||||
|
|
||||||
const auto rc = lan_discovery.GetNetworkInfo(info, latest_update, latest_update.size());
|
|
||||||
if (rc.IsError()) {
|
|
||||||
LOG_ERROR(Service_LDN, "NetworkInfo is not valid {}", rc.raw);
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
|
||||||
rb.Push(rc);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx.WriteBuffer(info, 0);
|
|
||||||
ctx.WriteBuffer(latest_update, 1);
|
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
|
||||||
rb.Push(ResultSuccess);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Scan(HLERequestContext& ctx) {
|
|
||||||
ScanImpl(ctx);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ScanPrivate(HLERequestContext& ctx) {
|
|
||||||
ScanImpl(ctx, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ScanImpl(HLERequestContext& ctx, bool is_private = false) {
|
|
||||||
IPC::RequestParser rp{ctx};
|
|
||||||
const auto channel{rp.PopEnum<WifiChannel>()};
|
|
||||||
const auto scan_filter{rp.PopRaw<ScanFilter>()};
|
|
||||||
|
|
||||||
const std::size_t network_info_size = ctx.GetWriteBufferNumElements<NetworkInfo>();
|
|
||||||
|
|
||||||
if (network_info_size == 0) {
|
|
||||||
LOG_ERROR(Service_LDN, "Invalid buffer size {}", network_info_size);
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
|
||||||
rb.Push(ResultBadInput);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
u16 count = 0;
|
|
||||||
std::vector<NetworkInfo> network_infos(network_info_size);
|
|
||||||
Result rc = lan_discovery.Scan(network_infos, count, scan_filter);
|
|
||||||
|
|
||||||
LOG_INFO(Service_LDN,
|
|
||||||
"called, channel={}, filter_scan_flag={}, filter_network_type={}, is_private={}",
|
|
||||||
channel, scan_filter.flag, scan_filter.network_type, is_private);
|
|
||||||
|
|
||||||
ctx.WriteBuffer(network_infos);
|
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 3};
|
|
||||||
rb.Push(rc);
|
|
||||||
rb.Push<u32>(count);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetWirelessControllerRestriction(HLERequestContext& ctx) {
|
|
||||||
LOG_WARNING(Service_LDN, "(STUBBED) called");
|
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
|
||||||
rb.Push(ResultSuccess);
|
|
||||||
}
|
|
||||||
|
|
||||||
void OpenAccessPoint(HLERequestContext& ctx) {
|
|
||||||
LOG_INFO(Service_LDN, "called");
|
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
|
||||||
rb.Push(lan_discovery.OpenAccessPoint());
|
|
||||||
}
|
|
||||||
|
|
||||||
void CloseAccessPoint(HLERequestContext& ctx) {
|
|
||||||
LOG_INFO(Service_LDN, "called");
|
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
|
||||||
rb.Push(lan_discovery.CloseAccessPoint());
|
|
||||||
}
|
|
||||||
|
|
||||||
void CreateNetwork(HLERequestContext& ctx) {
|
|
||||||
LOG_INFO(Service_LDN, "called");
|
|
||||||
|
|
||||||
CreateNetworkImpl(ctx);
|
|
||||||
}
|
|
||||||
|
|
||||||
void CreateNetworkPrivate(HLERequestContext& ctx) {
|
|
||||||
LOG_INFO(Service_LDN, "called");
|
|
||||||
|
|
||||||
CreateNetworkImpl(ctx, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
void CreateNetworkImpl(HLERequestContext& ctx, bool is_private = false) {
|
|
||||||
IPC::RequestParser rp{ctx};
|
|
||||||
|
|
||||||
const auto security_config{rp.PopRaw<SecurityConfig>()};
|
|
||||||
[[maybe_unused]] const auto security_parameter{is_private ? rp.PopRaw<SecurityParameter>()
|
|
||||||
: SecurityParameter{}};
|
|
||||||
const auto user_config{rp.PopRaw<UserConfig>()};
|
|
||||||
rp.Pop<u32>(); // Padding
|
|
||||||
const auto network_Config{rp.PopRaw<NetworkConfig>()};
|
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
|
||||||
rb.Push(lan_discovery.CreateNetwork(security_config, user_config, network_Config));
|
|
||||||
}
|
|
||||||
|
|
||||||
void DestroyNetwork(HLERequestContext& ctx) {
|
|
||||||
LOG_INFO(Service_LDN, "called");
|
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
|
||||||
rb.Push(lan_discovery.DestroyNetwork());
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetAdvertiseData(HLERequestContext& ctx) {
|
|
||||||
const auto read_buffer = ctx.ReadBuffer();
|
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
|
||||||
rb.Push(lan_discovery.SetAdvertiseData(read_buffer));
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetStationAcceptPolicy(HLERequestContext& ctx) {
|
|
||||||
LOG_WARNING(Service_LDN, "(STUBBED) called");
|
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
|
||||||
rb.Push(ResultSuccess);
|
|
||||||
}
|
|
||||||
|
|
||||||
void AddAcceptFilterEntry(HLERequestContext& ctx) {
|
|
||||||
LOG_WARNING(Service_LDN, "(STUBBED) called");
|
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
|
||||||
rb.Push(ResultSuccess);
|
|
||||||
}
|
|
||||||
|
|
||||||
void OpenStation(HLERequestContext& ctx) {
|
|
||||||
LOG_INFO(Service_LDN, "called");
|
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
|
||||||
rb.Push(lan_discovery.OpenStation());
|
|
||||||
}
|
|
||||||
|
|
||||||
void CloseStation(HLERequestContext& ctx) {
|
|
||||||
LOG_INFO(Service_LDN, "called");
|
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
|
||||||
rb.Push(lan_discovery.CloseStation());
|
|
||||||
}
|
|
||||||
|
|
||||||
void Connect(HLERequestContext& ctx) {
|
|
||||||
IPC::RequestParser rp{ctx};
|
|
||||||
struct Parameters {
|
|
||||||
SecurityConfig security_config;
|
|
||||||
UserConfig user_config;
|
|
||||||
u32 local_communication_version;
|
|
||||||
u32 option;
|
|
||||||
};
|
|
||||||
static_assert(sizeof(Parameters) == 0x7C, "Parameters has incorrect size.");
|
|
||||||
|
|
||||||
const auto parameters{rp.PopRaw<Parameters>()};
|
|
||||||
|
|
||||||
LOG_INFO(Service_LDN,
|
|
||||||
"called, passphrase_size={}, security_mode={}, "
|
|
||||||
"local_communication_version={}",
|
|
||||||
parameters.security_config.passphrase_size,
|
|
||||||
parameters.security_config.security_mode, parameters.local_communication_version);
|
|
||||||
|
|
||||||
const auto read_buffer = ctx.ReadBuffer();
|
|
||||||
if (read_buffer.size() != sizeof(NetworkInfo)) {
|
|
||||||
LOG_ERROR(Frontend, "NetworkInfo doesn't match read_buffer size!");
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
|
||||||
rb.Push(ResultBadInput);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
NetworkInfo network_info{};
|
|
||||||
std::memcpy(&network_info, read_buffer.data(), read_buffer.size());
|
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
|
||||||
rb.Push(lan_discovery.Connect(network_info, parameters.user_config,
|
|
||||||
static_cast<u16>(parameters.local_communication_version)));
|
|
||||||
}
|
|
||||||
|
|
||||||
void Disconnect(HLERequestContext& ctx) {
|
|
||||||
LOG_INFO(Service_LDN, "called");
|
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
|
||||||
rb.Push(lan_discovery.Disconnect());
|
|
||||||
}
|
|
||||||
|
|
||||||
void Initialize(HLERequestContext& ctx) {
|
|
||||||
const auto rc = InitializeImpl(ctx);
|
|
||||||
if (rc.IsError()) {
|
|
||||||
LOG_ERROR(Service_LDN, "Network isn't initialized, rc={}", rc.raw);
|
|
||||||
}
|
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
|
||||||
rb.Push(rc);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Finalize(HLERequestContext& ctx) {
|
|
||||||
if (auto room_member = room_network.GetRoomMember().lock()) {
|
|
||||||
room_member->Unbind(ldn_packet_received);
|
|
||||||
}
|
|
||||||
|
|
||||||
is_initialized = false;
|
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
|
||||||
rb.Push(lan_discovery.Finalize());
|
|
||||||
}
|
|
||||||
|
|
||||||
void Initialize2(HLERequestContext& ctx) {
|
|
||||||
const auto rc = InitializeImpl(ctx);
|
|
||||||
if (rc.IsError()) {
|
|
||||||
LOG_ERROR(Service_LDN, "Network isn't initialized, rc={}", rc.raw);
|
|
||||||
}
|
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
|
||||||
rb.Push(rc);
|
|
||||||
}
|
|
||||||
|
|
||||||
Result InitializeImpl(HLERequestContext& ctx) {
|
|
||||||
const auto network_interface = Network::GetSelectedNetworkInterface();
|
|
||||||
if (!network_interface) {
|
|
||||||
LOG_ERROR(Service_LDN, "No network interface is set");
|
|
||||||
return ResultAirplaneModeEnabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (auto room_member = room_network.GetRoomMember().lock()) {
|
|
||||||
ldn_packet_received = room_member->BindOnLdnPacketReceived(
|
|
||||||
[this](const Network::LDNPacket& packet) { OnLDNPacketReceived(packet); });
|
|
||||||
} else {
|
|
||||||
LOG_ERROR(Service_LDN, "Couldn't bind callback!");
|
|
||||||
return ResultAirplaneModeEnabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
lan_discovery.Initialize([&]() { OnEventFired(); });
|
|
||||||
is_initialized = true;
|
|
||||||
return ResultSuccess;
|
|
||||||
}
|
|
||||||
|
|
||||||
KernelHelpers::ServiceContext service_context;
|
|
||||||
Kernel::KEvent* state_change_event;
|
|
||||||
Network::RoomNetwork& room_network;
|
|
||||||
LANDiscovery lan_discovery;
|
|
||||||
|
|
||||||
// Callback identifier for the OnLDNPacketReceived event.
|
|
||||||
Network::RoomMember::CallbackHandle<Network::LDNPacket> ldn_packet_received;
|
|
||||||
|
|
||||||
bool is_initialized{};
|
|
||||||
};
|
|
||||||
|
|
||||||
class LDNS final : public ServiceFramework<LDNS> {
|
|
||||||
public:
|
|
||||||
explicit LDNS(Core::System& system_) : ServiceFramework{system_, "ldn:s"} {
|
|
||||||
// clang-format off
|
|
||||||
static const FunctionInfo functions[] = {
|
|
||||||
{0, &LDNS::CreateSystemLocalCommunicationService, "CreateSystemLocalCommunicationService"},
|
|
||||||
};
|
|
||||||
// clang-format on
|
|
||||||
|
|
||||||
RegisterHandlers(functions);
|
|
||||||
}
|
|
||||||
|
|
||||||
void CreateSystemLocalCommunicationService(HLERequestContext& ctx) {
|
|
||||||
LOG_DEBUG(Service_LDN, "called");
|
LOG_DEBUG(Service_LDN, "called");
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
*out_interface = std::make_shared<ISystemLocalCommunicationService>(system);
|
||||||
rb.Push(ResultSuccess);
|
R_SUCCEED();
|
||||||
rb.PushIpcInterface<ISystemLocalCommunicationService>(system);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class LDNU final : public ServiceFramework<LDNU> {
|
class IUserServiceCreator final : public ServiceFramework<IUserServiceCreator> {
|
||||||
public:
|
public:
|
||||||
explicit LDNU(Core::System& system_) : ServiceFramework{system_, "ldn:u"} {
|
explicit IUserServiceCreator(Core::System& system_) : ServiceFramework{system_, "ldn:u"} {
|
||||||
// clang-format off
|
// clang-format off
|
||||||
static const FunctionInfo functions[] = {
|
static const FunctionInfo functions[] = {
|
||||||
{0, &LDNU::CreateUserLocalCommunicationService, "CreateUserLocalCommunicationService"},
|
{0, C<&IUserServiceCreator::CreateUserLocalCommunicationService>, "CreateUserLocalCommunicationService"},
|
||||||
};
|
};
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
||||||
RegisterHandlers(functions);
|
RegisterHandlers(functions);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CreateUserLocalCommunicationService(HLERequestContext& ctx) {
|
private:
|
||||||
|
Result CreateUserLocalCommunicationService(
|
||||||
|
OutInterface<IUserLocalCommunicationService> out_interface) {
|
||||||
LOG_DEBUG(Service_LDN, "called");
|
LOG_DEBUG(Service_LDN, "called");
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
*out_interface = std::make_shared<IUserLocalCommunicationService>(system);
|
||||||
rb.Push(ResultSuccess);
|
R_SUCCEED();
|
||||||
rb.PushIpcInterface<IUserLocalCommunicationService>(system);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class INetworkService final : public ServiceFramework<INetworkService> {
|
class ISfServiceCreator final : public ServiceFramework<ISfServiceCreator> {
|
||||||
public:
|
public:
|
||||||
explicit INetworkService(Core::System& system_) : ServiceFramework{system_, "INetworkService"} {
|
explicit ISfServiceCreator(Core::System& system_, bool is_system_, const char* name_)
|
||||||
|
: ServiceFramework{system_, name_}, is_system{is_system_} {
|
||||||
// clang-format off
|
// clang-format off
|
||||||
static const FunctionInfo functions[] = {
|
static const FunctionInfo functions[] = {
|
||||||
{0, nullptr, "Initialize"},
|
{0, C<&ISfServiceCreator::CreateNetworkService>, "CreateNetworkService"},
|
||||||
{256, nullptr, "AttachNetworkInterfaceStateChangeEvent"},
|
{8, C<&ISfServiceCreator::CreateNetworkServiceMonitor>, "CreateNetworkServiceMonitor"},
|
||||||
{264, nullptr, "GetNetworkInterfaceLastError"},
|
|
||||||
{272, nullptr, "GetRole"},
|
|
||||||
{280, nullptr, "GetAdvertiseData"},
|
|
||||||
{288, nullptr, "GetGroupInfo"},
|
|
||||||
{296, nullptr, "GetGroupInfo2"},
|
|
||||||
{304, nullptr, "GetGroupOwner"},
|
|
||||||
{312, nullptr, "GetIpConfig"},
|
|
||||||
{320, nullptr, "GetLinkLevel"},
|
|
||||||
{512, nullptr, "Scan"},
|
|
||||||
{768, nullptr, "CreateGroup"},
|
|
||||||
{776, nullptr, "DestroyGroup"},
|
|
||||||
{784, nullptr, "SetAdvertiseData"},
|
|
||||||
{1536, nullptr, "SendToOtherGroup"},
|
|
||||||
{1544, nullptr, "RecvFromOtherGroup"},
|
|
||||||
{1552, nullptr, "AddAcceptableGroupId"},
|
|
||||||
{1560, nullptr, "ClearAcceptableGroupId"},
|
|
||||||
};
|
|
||||||
// clang-format on
|
|
||||||
|
|
||||||
RegisterHandlers(functions);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class INetworkServiceMonitor final : public ServiceFramework<INetworkServiceMonitor> {
|
|
||||||
public:
|
|
||||||
explicit INetworkServiceMonitor(Core::System& system_)
|
|
||||||
: ServiceFramework{system_, "INetworkServiceMonitor"} {
|
|
||||||
// clang-format off
|
|
||||||
static const FunctionInfo functions[] = {
|
|
||||||
{0, &INetworkServiceMonitor::Initialize, "Initialize"},
|
|
||||||
{256, nullptr, "AttachNetworkInterfaceStateChangeEvent"},
|
|
||||||
{264, nullptr, "GetNetworkInterfaceLastError"},
|
|
||||||
{272, nullptr, "GetRole"},
|
|
||||||
{280, nullptr, "GetAdvertiseData"},
|
|
||||||
{281, nullptr, "GetAdvertiseData2"},
|
|
||||||
{288, nullptr, "GetGroupInfo"},
|
|
||||||
{296, nullptr, "GetGroupInfo2"},
|
|
||||||
{304, nullptr, "GetGroupOwner"},
|
|
||||||
{312, nullptr, "GetIpConfig"},
|
|
||||||
{320, nullptr, "GetLinkLevel"},
|
|
||||||
{328, nullptr, "AttachJoinEvent"},
|
|
||||||
{336, nullptr, "GetMembers"},
|
|
||||||
};
|
};
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
||||||
RegisterHandlers(functions);
|
RegisterHandlers(functions);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Initialize(HLERequestContext& ctx) {
|
private:
|
||||||
LOG_WARNING(Service_LDN, "(STUBBED) called");
|
Result CreateNetworkService(OutInterface<ISfService> out_interface, u32 input,
|
||||||
|
u64 reserved_input) {
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
|
||||||
rb.Push(ResultDisabled);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class LP2PAPP final : public ServiceFramework<LP2PAPP> {
|
|
||||||
public:
|
|
||||||
explicit LP2PAPP(Core::System& system_) : ServiceFramework{system_, "lp2p:app"} {
|
|
||||||
// clang-format off
|
|
||||||
static const FunctionInfo functions[] = {
|
|
||||||
{0, &LP2PAPP::CreateMonitorService, "CreateNetworkService"},
|
|
||||||
{8, &LP2PAPP::CreateMonitorService, "CreateNetworkServiceMonitor"},
|
|
||||||
};
|
|
||||||
// clang-format on
|
|
||||||
|
|
||||||
RegisterHandlers(functions);
|
|
||||||
}
|
|
||||||
|
|
||||||
void CreateNetworkervice(HLERequestContext& ctx) {
|
|
||||||
IPC::RequestParser rp{ctx};
|
|
||||||
const u64 reserved_input = rp.Pop<u64>();
|
|
||||||
const u32 input = rp.Pop<u32>();
|
|
||||||
|
|
||||||
LOG_WARNING(Service_LDN, "(STUBBED) called reserved_input={} input={}", reserved_input,
|
LOG_WARNING(Service_LDN, "(STUBBED) called reserved_input={} input={}", reserved_input,
|
||||||
input);
|
input);
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
*out_interface = std::make_shared<ISfService>(system);
|
||||||
rb.Push(ResultSuccess);
|
R_SUCCEED();
|
||||||
rb.PushIpcInterface<INetworkService>(system);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CreateMonitorService(HLERequestContext& ctx) {
|
Result CreateNetworkServiceMonitor(OutInterface<ISfServiceMonitor> out_interface,
|
||||||
IPC::RequestParser rp{ctx};
|
u64 reserved_input) {
|
||||||
const u64 reserved_input = rp.Pop<u64>();
|
|
||||||
|
|
||||||
LOG_WARNING(Service_LDN, "(STUBBED) called reserved_input={}", reserved_input);
|
LOG_WARNING(Service_LDN, "(STUBBED) called reserved_input={}", reserved_input);
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
*out_interface = std::make_shared<ISfServiceMonitor>(system);
|
||||||
rb.Push(ResultSuccess);
|
R_SUCCEED();
|
||||||
rb.PushIpcInterface<INetworkServiceMonitor>(system);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool is_system{};
|
||||||
};
|
};
|
||||||
|
|
||||||
class LP2PSYS final : public ServiceFramework<LP2PSYS> {
|
class ISfMonitorServiceCreator final : public ServiceFramework<ISfMonitorServiceCreator> {
|
||||||
public:
|
public:
|
||||||
explicit LP2PSYS(Core::System& system_) : ServiceFramework{system_, "lp2p:sys"} {
|
explicit ISfMonitorServiceCreator(Core::System& system_) : ServiceFramework{system_, "lp2p:m"} {
|
||||||
// clang-format off
|
// clang-format off
|
||||||
static const FunctionInfo functions[] = {
|
static const FunctionInfo functions[] = {
|
||||||
{0, &LP2PSYS::CreateMonitorService, "CreateNetworkService"},
|
{0, C<&ISfMonitorServiceCreator::CreateMonitorService>, "CreateMonitorService"},
|
||||||
{8, &LP2PSYS::CreateMonitorService, "CreateNetworkServiceMonitor"},
|
|
||||||
};
|
|
||||||
// clang-format on
|
|
||||||
|
|
||||||
RegisterHandlers(functions);
|
|
||||||
}
|
|
||||||
|
|
||||||
void CreateNetworkervice(HLERequestContext& ctx) {
|
|
||||||
IPC::RequestParser rp{ctx};
|
|
||||||
const u64 reserved_input = rp.Pop<u64>();
|
|
||||||
const u32 input = rp.Pop<u32>();
|
|
||||||
|
|
||||||
LOG_WARNING(Service_LDN, "(STUBBED) called reserved_input={} input={}", reserved_input,
|
|
||||||
input);
|
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
|
||||||
rb.Push(ResultSuccess);
|
|
||||||
rb.PushIpcInterface<INetworkService>(system);
|
|
||||||
}
|
|
||||||
|
|
||||||
void CreateMonitorService(HLERequestContext& ctx) {
|
|
||||||
IPC::RequestParser rp{ctx};
|
|
||||||
const u64 reserved_input = rp.Pop<u64>();
|
|
||||||
|
|
||||||
LOG_WARNING(Service_LDN, "(STUBBED) called reserved_input={}", reserved_input);
|
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
|
||||||
rb.Push(ResultSuccess);
|
|
||||||
rb.PushIpcInterface<INetworkServiceMonitor>(system);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class ISfMonitorService final : public ServiceFramework<ISfMonitorService> {
|
|
||||||
public:
|
|
||||||
explicit ISfMonitorService(Core::System& system_)
|
|
||||||
: ServiceFramework{system_, "ISfMonitorService"} {
|
|
||||||
// clang-format off
|
|
||||||
static const FunctionInfo functions[] = {
|
|
||||||
{0, &ISfMonitorService::Initialize, "Initialize"},
|
|
||||||
{288, &ISfMonitorService::GetGroupInfo, "GetGroupInfo"},
|
|
||||||
{320, nullptr, "GetLinkLevel"},
|
|
||||||
};
|
};
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
||||||
@ -775,64 +126,27 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void Initialize(HLERequestContext& ctx) {
|
Result CreateMonitorService(OutInterface<ISfMonitorService> out_interface, u64 reserved_input) {
|
||||||
LOG_WARNING(Service_LDN, "(STUBBED) called");
|
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 3};
|
|
||||||
rb.Push(ResultSuccess);
|
|
||||||
rb.Push(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void GetGroupInfo(HLERequestContext& ctx) {
|
|
||||||
LOG_WARNING(Service_LDN, "(STUBBED) called");
|
|
||||||
|
|
||||||
struct GroupInfo {
|
|
||||||
std::array<u8, 0x200> info;
|
|
||||||
};
|
|
||||||
|
|
||||||
GroupInfo group_info{};
|
|
||||||
|
|
||||||
ctx.WriteBuffer(group_info);
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
|
||||||
rb.Push(ResultSuccess);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class LP2PM final : public ServiceFramework<LP2PM> {
|
|
||||||
public:
|
|
||||||
explicit LP2PM(Core::System& system_) : ServiceFramework{system_, "lp2p:m"} {
|
|
||||||
// clang-format off
|
|
||||||
static const FunctionInfo functions[] = {
|
|
||||||
{0, &LP2PM::CreateMonitorService, "CreateMonitorService"},
|
|
||||||
};
|
|
||||||
// clang-format on
|
|
||||||
|
|
||||||
RegisterHandlers(functions);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
void CreateMonitorService(HLERequestContext& ctx) {
|
|
||||||
IPC::RequestParser rp{ctx};
|
|
||||||
const u64 reserved_input = rp.Pop<u64>();
|
|
||||||
|
|
||||||
LOG_INFO(Service_LDN, "called, reserved_input={}", reserved_input);
|
LOG_INFO(Service_LDN, "called, reserved_input={}", reserved_input);
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
*out_interface = std::make_shared<ISfMonitorService>(system);
|
||||||
rb.Push(ResultSuccess);
|
R_SUCCEED();
|
||||||
rb.PushIpcInterface<ISfMonitorService>(system);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
void LoopProcess(Core::System& system) {
|
void LoopProcess(Core::System& system) {
|
||||||
auto server_manager = std::make_unique<ServerManager>(system);
|
auto server_manager = std::make_unique<ServerManager>(system);
|
||||||
|
|
||||||
server_manager->RegisterNamedService("ldn:m", std::make_shared<LDNM>(system));
|
server_manager->RegisterNamedService("ldn:m", std::make_shared<IMonitorServiceCreator>(system));
|
||||||
server_manager->RegisterNamedService("ldn:s", std::make_shared<LDNS>(system));
|
server_manager->RegisterNamedService("ldn:s", std::make_shared<ISystemServiceCreator>(system));
|
||||||
server_manager->RegisterNamedService("ldn:u", std::make_shared<LDNU>(system));
|
server_manager->RegisterNamedService("ldn:u", std::make_shared<IUserServiceCreator>(system));
|
||||||
|
|
||||||
server_manager->RegisterNamedService("lp2p:app", std::make_shared<LP2PAPP>(system));
|
server_manager->RegisterNamedService(
|
||||||
server_manager->RegisterNamedService("lp2p:sys", std::make_shared<LP2PSYS>(system));
|
"lp2p:app", std::make_shared<ISfServiceCreator>(system, false, "lp2p:app"));
|
||||||
server_manager->RegisterNamedService("lp2p:m", std::make_shared<LP2PM>(system));
|
server_manager->RegisterNamedService(
|
||||||
|
"lp2p:sys", std::make_shared<ISfServiceCreator>(system, true, "lp2p:sys"));
|
||||||
|
server_manager->RegisterNamedService("lp2p:m",
|
||||||
|
std::make_shared<ISfMonitorServiceCreator>(system));
|
||||||
|
|
||||||
ServerManager::RunServer(std::move(server_manager));
|
ServerManager::RunServer(std::move(server_manager));
|
||||||
}
|
}
|
||||||
|
@ -3,12 +3,6 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "core/hle/kernel/k_event.h"
|
|
||||||
#include "core/hle/result.h"
|
|
||||||
#include "core/hle/service/ipc_helpers.h"
|
|
||||||
#include "core/hle/service/kernel_helpers.h"
|
|
||||||
#include "core/hle/service/sm/sm.h"
|
|
||||||
|
|
||||||
namespace Core {
|
namespace Core {
|
||||||
class System;
|
class System;
|
||||||
}
|
}
|
||||||
|
@ -123,6 +123,18 @@ enum class NodeStatus : u8 {
|
|||||||
Connected,
|
Connected,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum class WirelessControllerRestriction : u32 {
|
||||||
|
None,
|
||||||
|
Default,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ConnectOption {
|
||||||
|
union {
|
||||||
|
u32 raw;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
static_assert(sizeof(ConnectOption) == 0x4, "ConnectOption is an invalid size");
|
||||||
|
|
||||||
struct NodeLatestUpdate {
|
struct NodeLatestUpdate {
|
||||||
NodeStateChange state_change;
|
NodeStateChange state_change;
|
||||||
INSERT_PADDING_BYTES(0x7); // Unknown
|
INSERT_PADDING_BYTES(0x7); // Unknown
|
||||||
@ -139,9 +151,9 @@ static_assert(sizeof(SessionId) == 0x10, "SessionId is an invalid size");
|
|||||||
|
|
||||||
struct IntentId {
|
struct IntentId {
|
||||||
u64 local_communication_id;
|
u64 local_communication_id;
|
||||||
INSERT_PADDING_BYTES(0x2); // Reserved
|
INSERT_PADDING_BYTES_NOINIT(0x2); // Reserved
|
||||||
u16 scene_id;
|
u16 scene_id;
|
||||||
INSERT_PADDING_BYTES(0x4); // Reserved
|
INSERT_PADDING_BYTES_NOINIT(0x4); // Reserved
|
||||||
};
|
};
|
||||||
static_assert(sizeof(IntentId) == 0x10, "IntentId is an invalid size");
|
static_assert(sizeof(IntentId) == 0x10, "IntentId is an invalid size");
|
||||||
|
|
||||||
@ -152,13 +164,14 @@ struct NetworkId {
|
|||||||
static_assert(sizeof(NetworkId) == 0x20, "NetworkId is an invalid size");
|
static_assert(sizeof(NetworkId) == 0x20, "NetworkId is an invalid size");
|
||||||
|
|
||||||
struct Ssid {
|
struct Ssid {
|
||||||
u8 length{};
|
u8 length;
|
||||||
std::array<char, SsidLengthMax + 1> raw{};
|
std::array<char, SsidLengthMax + 1> raw;
|
||||||
|
|
||||||
Ssid() = default;
|
Ssid() = default;
|
||||||
|
|
||||||
constexpr explicit Ssid(std::string_view data) {
|
constexpr explicit Ssid(std::string_view data) {
|
||||||
length = static_cast<u8>(std::min(data.size(), SsidLengthMax));
|
length = static_cast<u8>(std::min(data.size(), SsidLengthMax));
|
||||||
|
raw = {};
|
||||||
data.copy(raw.data(), length);
|
data.copy(raw.data(), length);
|
||||||
raw[length] = 0;
|
raw[length] = 0;
|
||||||
}
|
}
|
||||||
@ -181,7 +194,7 @@ using Ipv4Address = std::array<u8, 4>;
|
|||||||
static_assert(sizeof(Ipv4Address) == 0x4, "Ipv4Address is an invalid size");
|
static_assert(sizeof(Ipv4Address) == 0x4, "Ipv4Address is an invalid size");
|
||||||
|
|
||||||
struct MacAddress {
|
struct MacAddress {
|
||||||
std::array<u8, 6> raw{};
|
std::array<u8, 6> raw;
|
||||||
|
|
||||||
friend bool operator==(const MacAddress& lhs, const MacAddress& rhs) = default;
|
friend bool operator==(const MacAddress& lhs, const MacAddress& rhs) = default;
|
||||||
};
|
};
|
||||||
@ -211,7 +224,7 @@ struct CommonNetworkInfo {
|
|||||||
WifiChannel channel;
|
WifiChannel channel;
|
||||||
LinkLevel link_level;
|
LinkLevel link_level;
|
||||||
PackedNetworkType network_type;
|
PackedNetworkType network_type;
|
||||||
INSERT_PADDING_BYTES(0x4);
|
INSERT_PADDING_BYTES_NOINIT(0x4);
|
||||||
};
|
};
|
||||||
static_assert(sizeof(CommonNetworkInfo) == 0x30, "CommonNetworkInfo is an invalid size");
|
static_assert(sizeof(CommonNetworkInfo) == 0x30, "CommonNetworkInfo is an invalid size");
|
||||||
|
|
||||||
@ -221,9 +234,9 @@ struct NodeInfo {
|
|||||||
s8 node_id;
|
s8 node_id;
|
||||||
u8 is_connected;
|
u8 is_connected;
|
||||||
std::array<u8, UserNameBytesMax + 1> user_name;
|
std::array<u8, UserNameBytesMax + 1> user_name;
|
||||||
INSERT_PADDING_BYTES(0x1); // Reserved
|
INSERT_PADDING_BYTES_NOINIT(0x1); // Reserved
|
||||||
s16 local_communication_version;
|
s16 local_communication_version;
|
||||||
INSERT_PADDING_BYTES(0x10); // Reserved
|
INSERT_PADDING_BYTES_NOINIT(0x10); // Reserved
|
||||||
};
|
};
|
||||||
static_assert(sizeof(NodeInfo) == 0x40, "NodeInfo is an invalid size");
|
static_assert(sizeof(NodeInfo) == 0x40, "NodeInfo is an invalid size");
|
||||||
|
|
||||||
@ -232,14 +245,14 @@ struct LdnNetworkInfo {
|
|||||||
SecurityMode security_mode;
|
SecurityMode security_mode;
|
||||||
AcceptPolicy station_accept_policy;
|
AcceptPolicy station_accept_policy;
|
||||||
u8 has_action_frame;
|
u8 has_action_frame;
|
||||||
INSERT_PADDING_BYTES(0x2); // Padding
|
INSERT_PADDING_BYTES_NOINIT(0x2); // Padding
|
||||||
u8 node_count_max;
|
u8 node_count_max;
|
||||||
u8 node_count;
|
u8 node_count;
|
||||||
std::array<NodeInfo, NodeCountMax> nodes;
|
std::array<NodeInfo, NodeCountMax> nodes;
|
||||||
INSERT_PADDING_BYTES(0x2); // Reserved
|
INSERT_PADDING_BYTES_NOINIT(0x2); // Reserved
|
||||||
u16 advertise_data_size;
|
u16 advertise_data_size;
|
||||||
std::array<u8, AdvertiseDataSizeMax> advertise_data;
|
std::array<u8, AdvertiseDataSizeMax> advertise_data;
|
||||||
INSERT_PADDING_BYTES(0x8C); // Reserved
|
INSERT_PADDING_BYTES_NOINIT(0x8C); // Reserved
|
||||||
u64 random_authentication_id;
|
u64 random_authentication_id;
|
||||||
};
|
};
|
||||||
static_assert(sizeof(LdnNetworkInfo) == 0x430, "LdnNetworkInfo is an invalid size");
|
static_assert(sizeof(LdnNetworkInfo) == 0x430, "LdnNetworkInfo is an invalid size");
|
||||||
@ -250,6 +263,7 @@ struct NetworkInfo {
|
|||||||
LdnNetworkInfo ldn;
|
LdnNetworkInfo ldn;
|
||||||
};
|
};
|
||||||
static_assert(sizeof(NetworkInfo) == 0x480, "NetworkInfo is an invalid size");
|
static_assert(sizeof(NetworkInfo) == 0x480, "NetworkInfo is an invalid size");
|
||||||
|
static_assert(std::is_trivial_v<NetworkInfo>, "NetworkInfo type must be trivially copyable.");
|
||||||
|
|
||||||
struct SecurityConfig {
|
struct SecurityConfig {
|
||||||
SecurityMode security_mode;
|
SecurityMode security_mode;
|
||||||
@ -303,4 +317,36 @@ struct AddressList {
|
|||||||
};
|
};
|
||||||
static_assert(sizeof(AddressList) == 0x60, "AddressList is an invalid size");
|
static_assert(sizeof(AddressList) == 0x60, "AddressList is an invalid size");
|
||||||
|
|
||||||
|
struct GroupInfo {
|
||||||
|
std::array<u8, 0x200> info;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct CreateNetworkConfig {
|
||||||
|
SecurityConfig security_config;
|
||||||
|
UserConfig user_config;
|
||||||
|
INSERT_PADDING_BYTES(0x4);
|
||||||
|
NetworkConfig network_config;
|
||||||
|
};
|
||||||
|
static_assert(sizeof(CreateNetworkConfig) == 0x98, "CreateNetworkConfig is an invalid size");
|
||||||
|
|
||||||
|
#pragma pack(push, 4)
|
||||||
|
struct CreateNetworkConfigPrivate {
|
||||||
|
SecurityConfig security_config;
|
||||||
|
SecurityParameter security_parameter;
|
||||||
|
UserConfig user_config;
|
||||||
|
INSERT_PADDING_BYTES(0x4);
|
||||||
|
NetworkConfig network_config;
|
||||||
|
};
|
||||||
|
#pragma pack(pop)
|
||||||
|
static_assert(sizeof(CreateNetworkConfigPrivate) == 0xB8,
|
||||||
|
"CreateNetworkConfigPrivate is an invalid size");
|
||||||
|
|
||||||
|
struct ConnectNetworkData {
|
||||||
|
SecurityConfig security_config;
|
||||||
|
UserConfig user_config;
|
||||||
|
s32 local_communication_version;
|
||||||
|
ConnectOption option;
|
||||||
|
};
|
||||||
|
static_assert(sizeof(ConnectNetworkData) == 0x7c, "ConnectNetworkData is an invalid size");
|
||||||
|
|
||||||
} // namespace Service::LDN
|
} // namespace Service::LDN
|
||||||
|
43
src/core/hle/service/ldn/monitor_service.cpp
Normal file
43
src/core/hle/service/ldn/monitor_service.cpp
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
#include "core/hle/service/cmif_serialization.h"
|
||||||
|
#include "core/hle/service/ldn/monitor_service.h"
|
||||||
|
|
||||||
|
namespace Service::LDN {
|
||||||
|
|
||||||
|
IMonitorService::IMonitorService(Core::System& system_)
|
||||||
|
: ServiceFramework{system_, "IMonitorService"} {
|
||||||
|
// clang-format off
|
||||||
|
static const FunctionInfo functions[] = {
|
||||||
|
{0, C<&IMonitorService::GetStateForMonitor>, "GetStateForMonitor"},
|
||||||
|
{1, nullptr, "GetNetworkInfoForMonitor"},
|
||||||
|
{2, nullptr, "GetIpv4AddressForMonitor"},
|
||||||
|
{3, nullptr, "GetDisconnectReasonForMonitor"},
|
||||||
|
{4, nullptr, "GetSecurityParameterForMonitor"},
|
||||||
|
{5, nullptr, "GetNetworkConfigForMonitor"},
|
||||||
|
{100, C<&IMonitorService::InitializeMonitor>, "InitializeMonitor"},
|
||||||
|
{101, nullptr, "FinalizeMonitor"},
|
||||||
|
};
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
|
RegisterHandlers(functions);
|
||||||
|
}
|
||||||
|
|
||||||
|
IMonitorService::~IMonitorService() = default;
|
||||||
|
|
||||||
|
Result IMonitorService::GetStateForMonitor(Out<State> out_state) {
|
||||||
|
LOG_INFO(Service_LDN, "called");
|
||||||
|
|
||||||
|
*out_state = state;
|
||||||
|
R_SUCCEED();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result IMonitorService::InitializeMonitor() {
|
||||||
|
LOG_INFO(Service_LDN, "called");
|
||||||
|
|
||||||
|
state = State::Initialized;
|
||||||
|
R_SUCCEED();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Service::LDN
|
28
src/core/hle/service/ldn/monitor_service.h
Normal file
28
src/core/hle/service/ldn/monitor_service.h
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "core/hle/service/cmif_types.h"
|
||||||
|
#include "core/hle/service/ldn/ldn_types.h"
|
||||||
|
#include "core/hle/service/service.h"
|
||||||
|
|
||||||
|
namespace Core {
|
||||||
|
class System;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Service::LDN {
|
||||||
|
|
||||||
|
class IMonitorService final : public ServiceFramework<IMonitorService> {
|
||||||
|
public:
|
||||||
|
explicit IMonitorService(Core::System& system_);
|
||||||
|
~IMonitorService() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
Result GetStateForMonitor(Out<State> out_state);
|
||||||
|
Result InitializeMonitor();
|
||||||
|
|
||||||
|
State state{State::None};
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Service::LDN
|
40
src/core/hle/service/ldn/sf_monitor_service.cpp
Normal file
40
src/core/hle/service/ldn/sf_monitor_service.cpp
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
#include "core/hle/service/cmif_serialization.h"
|
||||||
|
#include "core/hle/service/ldn/ldn_types.h"
|
||||||
|
#include "core/hle/service/ldn/sf_monitor_service.h"
|
||||||
|
|
||||||
|
namespace Service::LDN {
|
||||||
|
|
||||||
|
ISfMonitorService::ISfMonitorService(Core::System& system_)
|
||||||
|
: ServiceFramework{system_, "ISfMonitorService"} {
|
||||||
|
// clang-format off
|
||||||
|
static const FunctionInfo functions[] = {
|
||||||
|
{0, C<&ISfMonitorService::Initialize>, "Initialize"},
|
||||||
|
{288, C<&ISfMonitorService::GetGroupInfo>, "GetGroupInfo"},
|
||||||
|
{320, nullptr, "GetLinkLevel"},
|
||||||
|
};
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
|
RegisterHandlers(functions);
|
||||||
|
}
|
||||||
|
|
||||||
|
ISfMonitorService::~ISfMonitorService() = default;
|
||||||
|
|
||||||
|
Result ISfMonitorService::Initialize(Out<u32> out_value) {
|
||||||
|
LOG_WARNING(Service_LDN, "(STUBBED) called");
|
||||||
|
|
||||||
|
*out_value = 0;
|
||||||
|
R_SUCCEED();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result ISfMonitorService::GetGroupInfo(
|
||||||
|
OutLargeData<GroupInfo, BufferAttr_HipcAutoSelect> out_group_info) {
|
||||||
|
LOG_WARNING(Service_LDN, "(STUBBED) called");
|
||||||
|
|
||||||
|
*out_group_info = GroupInfo{};
|
||||||
|
R_SUCCEED();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Service::LDN
|
26
src/core/hle/service/ldn/sf_monitor_service.h
Normal file
26
src/core/hle/service/ldn/sf_monitor_service.h
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "core/hle/service/cmif_types.h"
|
||||||
|
#include "core/hle/service/service.h"
|
||||||
|
|
||||||
|
namespace Core {
|
||||||
|
class System;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Service::LDN {
|
||||||
|
struct GroupInfo;
|
||||||
|
|
||||||
|
class ISfMonitorService final : public ServiceFramework<ISfMonitorService> {
|
||||||
|
public:
|
||||||
|
explicit ISfMonitorService(Core::System& system_);
|
||||||
|
~ISfMonitorService() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
Result Initialize(Out<u32> out_value);
|
||||||
|
Result GetGroupInfo(OutLargeData<GroupInfo, BufferAttr_HipcAutoSelect> out_group_info);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Service::LDN
|
37
src/core/hle/service/ldn/sf_service.cpp
Normal file
37
src/core/hle/service/ldn/sf_service.cpp
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
#include "core/hle/service/ldn/sf_service.h"
|
||||||
|
|
||||||
|
namespace Service::LDN {
|
||||||
|
|
||||||
|
ISfService::ISfService(Core::System& system_) : ServiceFramework{system_, "ISfService"} {
|
||||||
|
// clang-format off
|
||||||
|
static const FunctionInfo functions[] = {
|
||||||
|
{0, nullptr, "Initialize"},
|
||||||
|
{256, nullptr, "AttachNetworkInterfaceStateChangeEvent"},
|
||||||
|
{264, nullptr, "GetNetworkInterfaceLastError"},
|
||||||
|
{272, nullptr, "GetRole"},
|
||||||
|
{280, nullptr, "GetAdvertiseData"},
|
||||||
|
{288, nullptr, "GetGroupInfo"},
|
||||||
|
{296, nullptr, "GetGroupInfo2"},
|
||||||
|
{304, nullptr, "GetGroupOwner"},
|
||||||
|
{312, nullptr, "GetIpConfig"},
|
||||||
|
{320, nullptr, "GetLinkLevel"},
|
||||||
|
{512, nullptr, "Scan"},
|
||||||
|
{768, nullptr, "CreateGroup"},
|
||||||
|
{776, nullptr, "DestroyGroup"},
|
||||||
|
{784, nullptr, "SetAdvertiseData"},
|
||||||
|
{1536, nullptr, "SendToOtherGroup"},
|
||||||
|
{1544, nullptr, "RecvFromOtherGroup"},
|
||||||
|
{1552, nullptr, "AddAcceptableGroupId"},
|
||||||
|
{1560, nullptr, "ClearAcceptableGroupId"},
|
||||||
|
};
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
|
RegisterHandlers(functions);
|
||||||
|
}
|
||||||
|
|
||||||
|
ISfService::~ISfService() = default;
|
||||||
|
|
||||||
|
} // namespace Service::LDN
|
21
src/core/hle/service/ldn/sf_service.h
Normal file
21
src/core/hle/service/ldn/sf_service.h
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "core/hle/service/cmif_types.h"
|
||||||
|
#include "core/hle/service/service.h"
|
||||||
|
|
||||||
|
namespace Core {
|
||||||
|
class System;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Service::LDN {
|
||||||
|
|
||||||
|
class ISfService final : public ServiceFramework<ISfService> {
|
||||||
|
public:
|
||||||
|
explicit ISfService(Core::System& system_);
|
||||||
|
~ISfService() override;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Service::LDN
|
50
src/core/hle/service/ldn/sf_service_monitor.cpp
Normal file
50
src/core/hle/service/ldn/sf_service_monitor.cpp
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
#include "core/hle/service/cmif_serialization.h"
|
||||||
|
#include "core/hle/service/ldn/ldn_types.h"
|
||||||
|
#include "core/hle/service/ldn/sf_service_monitor.h"
|
||||||
|
|
||||||
|
namespace Service::LDN {
|
||||||
|
|
||||||
|
ISfServiceMonitor::ISfServiceMonitor(Core::System& system_)
|
||||||
|
: ServiceFramework{system_, "ISfServiceMonitor"} {
|
||||||
|
// clang-format off
|
||||||
|
static const FunctionInfo functions[] = {
|
||||||
|
{0, C<&ISfServiceMonitor::Initialize>, "Initialize"},
|
||||||
|
{256, nullptr, "AttachNetworkInterfaceStateChangeEvent"},
|
||||||
|
{264, nullptr, "GetNetworkInterfaceLastError"},
|
||||||
|
{272, nullptr, "GetRole"},
|
||||||
|
{280, nullptr, "GetAdvertiseData"},
|
||||||
|
{281, nullptr, "GetAdvertiseData2"},
|
||||||
|
{288, C<&ISfServiceMonitor::GetGroupInfo>, "GetGroupInfo"},
|
||||||
|
{296, nullptr, "GetGroupInfo2"},
|
||||||
|
{304, nullptr, "GetGroupOwner"},
|
||||||
|
{312, nullptr, "GetIpConfig"},
|
||||||
|
{320, nullptr, "GetLinkLevel"},
|
||||||
|
{328, nullptr, "AttachJoinEvent"},
|
||||||
|
{336, nullptr, "GetMembers"},
|
||||||
|
};
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
|
RegisterHandlers(functions);
|
||||||
|
}
|
||||||
|
|
||||||
|
ISfServiceMonitor::~ISfServiceMonitor() = default;
|
||||||
|
|
||||||
|
Result ISfServiceMonitor::Initialize(Out<u32> out_value) {
|
||||||
|
LOG_WARNING(Service_LDN, "(STUBBED) called");
|
||||||
|
|
||||||
|
*out_value = 0;
|
||||||
|
R_SUCCEED();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result ISfServiceMonitor::GetGroupInfo(
|
||||||
|
OutLargeData<GroupInfo, BufferAttr_HipcAutoSelect> out_group_info) {
|
||||||
|
LOG_WARNING(Service_LDN, "(STUBBED) called");
|
||||||
|
|
||||||
|
*out_group_info = GroupInfo{};
|
||||||
|
R_SUCCEED();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Service::LDN
|
26
src/core/hle/service/ldn/sf_service_monitor.h
Normal file
26
src/core/hle/service/ldn/sf_service_monitor.h
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "core/hle/service/cmif_types.h"
|
||||||
|
#include "core/hle/service/service.h"
|
||||||
|
|
||||||
|
namespace Core {
|
||||||
|
class System;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Service::LDN {
|
||||||
|
struct GroupInfo;
|
||||||
|
|
||||||
|
class ISfServiceMonitor final : public ServiceFramework<ISfServiceMonitor> {
|
||||||
|
public:
|
||||||
|
explicit ISfServiceMonitor(Core::System& system_);
|
||||||
|
~ISfServiceMonitor() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
Result Initialize(Out<u32> out_value);
|
||||||
|
Result GetGroupInfo(OutLargeData<GroupInfo, BufferAttr_HipcAutoSelect> out_group_info);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Service::LDN
|
@ -0,0 +1,56 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
#include "core/hle/service/cmif_serialization.h"
|
||||||
|
#include "core/hle/service/ldn/system_local_communication_service.h"
|
||||||
|
|
||||||
|
namespace Service::LDN {
|
||||||
|
|
||||||
|
ISystemLocalCommunicationService::ISystemLocalCommunicationService(Core::System& system_)
|
||||||
|
: ServiceFramework{system_, "ISystemLocalCommunicationService"} {
|
||||||
|
// clang-format off
|
||||||
|
static const FunctionInfo functions[] = {
|
||||||
|
{0, nullptr, "GetState"},
|
||||||
|
{1, nullptr, "GetNetworkInfo"},
|
||||||
|
{2, nullptr, "GetIpv4Address"},
|
||||||
|
{3, nullptr, "GetDisconnectReason"},
|
||||||
|
{4, nullptr, "GetSecurityParameter"},
|
||||||
|
{5, nullptr, "GetNetworkConfig"},
|
||||||
|
{100, nullptr, "AttachStateChangeEvent"},
|
||||||
|
{101, nullptr, "GetNetworkInfoLatestUpdate"},
|
||||||
|
{102, nullptr, "Scan"},
|
||||||
|
{103, nullptr, "ScanPrivate"},
|
||||||
|
{104, nullptr, "SetWirelessControllerRestriction"},
|
||||||
|
{200, nullptr, "OpenAccessPoint"},
|
||||||
|
{201, nullptr, "CloseAccessPoint"},
|
||||||
|
{202, nullptr, "CreateNetwork"},
|
||||||
|
{203, nullptr, "CreateNetworkPrivate"},
|
||||||
|
{204, nullptr, "DestroyNetwork"},
|
||||||
|
{205, nullptr, "Reject"},
|
||||||
|
{206, nullptr, "SetAdvertiseData"},
|
||||||
|
{207, nullptr, "SetStationAcceptPolicy"},
|
||||||
|
{208, nullptr, "AddAcceptFilterEntry"},
|
||||||
|
{209, nullptr, "ClearAcceptFilter"},
|
||||||
|
{300, nullptr, "OpenStation"},
|
||||||
|
{301, nullptr, "CloseStation"},
|
||||||
|
{302, nullptr, "Connect"},
|
||||||
|
{303, nullptr, "ConnectPrivate"},
|
||||||
|
{304, nullptr, "Disconnect"},
|
||||||
|
{400, nullptr, "InitializeSystem"},
|
||||||
|
{401, nullptr, "FinalizeSystem"},
|
||||||
|
{402, nullptr, "SetOperationMode"},
|
||||||
|
{403, C<&ISystemLocalCommunicationService::InitializeSystem2>, "InitializeSystem2"},
|
||||||
|
};
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
|
RegisterHandlers(functions);
|
||||||
|
}
|
||||||
|
|
||||||
|
ISystemLocalCommunicationService::~ISystemLocalCommunicationService() = default;
|
||||||
|
|
||||||
|
Result ISystemLocalCommunicationService::InitializeSystem2() {
|
||||||
|
LOG_WARNING(Service_LDN, "(STUBBED) called");
|
||||||
|
R_SUCCEED();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Service::LDN
|
@ -0,0 +1,25 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "core/hle/service/cmif_types.h"
|
||||||
|
#include "core/hle/service/service.h"
|
||||||
|
|
||||||
|
namespace Core {
|
||||||
|
class System;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Service::LDN {
|
||||||
|
|
||||||
|
class ISystemLocalCommunicationService final
|
||||||
|
: public ServiceFramework<ISystemLocalCommunicationService> {
|
||||||
|
public:
|
||||||
|
explicit ISystemLocalCommunicationService(Core::System& system_);
|
||||||
|
~ISystemLocalCommunicationService() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
Result InitializeSystem2();
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Service::LDN
|
320
src/core/hle/service/ldn/user_local_communication_service.cpp
Normal file
320
src/core/hle/service/ldn/user_local_communication_service.cpp
Normal file
@ -0,0 +1,320 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
#include "core/core.h"
|
||||||
|
#include "core/hle/kernel/k_event.h"
|
||||||
|
#include "core/hle/service/cmif_serialization.h"
|
||||||
|
#include "core/hle/service/ldn/ldn_results.h"
|
||||||
|
#include "core/hle/service/ldn/ldn_types.h"
|
||||||
|
#include "core/hle/service/ldn/user_local_communication_service.h"
|
||||||
|
#include "core/hle/service/server_manager.h"
|
||||||
|
#include "core/internal_network/network.h"
|
||||||
|
#include "core/internal_network/network_interface.h"
|
||||||
|
#include "network/network.h"
|
||||||
|
|
||||||
|
// This is defined by synchapi.h and conflicts with ServiceContext::CreateEvent
|
||||||
|
#undef CreateEvent
|
||||||
|
|
||||||
|
namespace Service::LDN {
|
||||||
|
|
||||||
|
IUserLocalCommunicationService::IUserLocalCommunicationService(Core::System& system_)
|
||||||
|
: ServiceFramework{system_, "IUserLocalCommunicationService"},
|
||||||
|
service_context{system, "IUserLocalCommunicationService"},
|
||||||
|
room_network{system_.GetRoomNetwork()}, lan_discovery{room_network} {
|
||||||
|
// clang-format off
|
||||||
|
static const FunctionInfo functions[] = {
|
||||||
|
{0, C<&IUserLocalCommunicationService::GetState>, "GetState"},
|
||||||
|
{1, C<&IUserLocalCommunicationService::GetNetworkInfo>, "GetNetworkInfo"},
|
||||||
|
{2, C<&IUserLocalCommunicationService::GetIpv4Address>, "GetIpv4Address"},
|
||||||
|
{3, C<&IUserLocalCommunicationService::GetDisconnectReason>, "GetDisconnectReason"},
|
||||||
|
{4, C<&IUserLocalCommunicationService::GetSecurityParameter>, "GetSecurityParameter"},
|
||||||
|
{5, C<&IUserLocalCommunicationService::GetNetworkConfig>, "GetNetworkConfig"},
|
||||||
|
{100, C<&IUserLocalCommunicationService::AttachStateChangeEvent>, "AttachStateChangeEvent"},
|
||||||
|
{101, C<&IUserLocalCommunicationService::GetNetworkInfoLatestUpdate>, "GetNetworkInfoLatestUpdate"},
|
||||||
|
{102, C<&IUserLocalCommunicationService::Scan>, "Scan"},
|
||||||
|
{103, C<&IUserLocalCommunicationService::ScanPrivate>, "ScanPrivate"},
|
||||||
|
{104, C<&IUserLocalCommunicationService::SetWirelessControllerRestriction>, "SetWirelessControllerRestriction"},
|
||||||
|
{200, C<&IUserLocalCommunicationService::OpenAccessPoint>, "OpenAccessPoint"},
|
||||||
|
{201, C<&IUserLocalCommunicationService::CloseAccessPoint>, "CloseAccessPoint"},
|
||||||
|
{202, C<&IUserLocalCommunicationService::CreateNetwork>, "CreateNetwork"},
|
||||||
|
{203, C<&IUserLocalCommunicationService::CreateNetworkPrivate>, "CreateNetworkPrivate"},
|
||||||
|
{204, C<&IUserLocalCommunicationService::DestroyNetwork>, "DestroyNetwork"},
|
||||||
|
{205, nullptr, "Reject"},
|
||||||
|
{206, C<&IUserLocalCommunicationService::SetAdvertiseData>, "SetAdvertiseData"},
|
||||||
|
{207, C<&IUserLocalCommunicationService::SetStationAcceptPolicy>, "SetStationAcceptPolicy"},
|
||||||
|
{208, C<&IUserLocalCommunicationService::AddAcceptFilterEntry>, "AddAcceptFilterEntry"},
|
||||||
|
{209, nullptr, "ClearAcceptFilter"},
|
||||||
|
{300, C<&IUserLocalCommunicationService::OpenStation>, "OpenStation"},
|
||||||
|
{301, C<&IUserLocalCommunicationService::CloseStation>, "CloseStation"},
|
||||||
|
{302, C<&IUserLocalCommunicationService::Connect>, "Connect"},
|
||||||
|
{303, nullptr, "ConnectPrivate"},
|
||||||
|
{304, C<&IUserLocalCommunicationService::Disconnect>, "Disconnect"},
|
||||||
|
{400, C<&IUserLocalCommunicationService::Initialize>, "Initialize"},
|
||||||
|
{401, C<&IUserLocalCommunicationService::Finalize>, "Finalize"},
|
||||||
|
{402, C<&IUserLocalCommunicationService::Initialize2>, "Initialize2"},
|
||||||
|
};
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
|
RegisterHandlers(functions);
|
||||||
|
|
||||||
|
state_change_event =
|
||||||
|
service_context.CreateEvent("IUserLocalCommunicationService:StateChangeEvent");
|
||||||
|
}
|
||||||
|
|
||||||
|
IUserLocalCommunicationService::~IUserLocalCommunicationService() {
|
||||||
|
if (is_initialized) {
|
||||||
|
if (auto room_member = room_network.GetRoomMember().lock()) {
|
||||||
|
room_member->Unbind(ldn_packet_received);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
service_context.CloseEvent(state_change_event);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result IUserLocalCommunicationService::GetState(Out<State> out_state) {
|
||||||
|
*out_state = State::Error;
|
||||||
|
|
||||||
|
if (is_initialized) {
|
||||||
|
*out_state = lan_discovery.GetState();
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG_INFO(Service_LDN, "called, state={}", *out_state);
|
||||||
|
|
||||||
|
R_SUCCEED();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result IUserLocalCommunicationService::GetNetworkInfo(
|
||||||
|
OutLargeData<NetworkInfo, BufferAttr_HipcPointer> out_network_info) {
|
||||||
|
LOG_INFO(Service_LDN, "called");
|
||||||
|
|
||||||
|
R_RETURN(lan_discovery.GetNetworkInfo(*out_network_info));
|
||||||
|
}
|
||||||
|
|
||||||
|
Result IUserLocalCommunicationService::GetIpv4Address(Out<Ipv4Address> out_current_address,
|
||||||
|
Out<Ipv4Address> out_subnet_mask) {
|
||||||
|
LOG_INFO(Service_LDN, "called");
|
||||||
|
const auto network_interface = Network::GetSelectedNetworkInterface();
|
||||||
|
|
||||||
|
R_UNLESS(network_interface.has_value(), ResultNoIpAddress);
|
||||||
|
|
||||||
|
*out_current_address = {Network::TranslateIPv4(network_interface->ip_address)};
|
||||||
|
*out_subnet_mask = {Network::TranslateIPv4(network_interface->subnet_mask)};
|
||||||
|
|
||||||
|
// When we're connected to a room, spoof the hosts IP address
|
||||||
|
if (auto room_member = room_network.GetRoomMember().lock()) {
|
||||||
|
if (room_member->IsConnected()) {
|
||||||
|
*out_current_address = room_member->GetFakeIpAddress();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::reverse(std::begin(*out_current_address), std::end(*out_current_address)); // ntohl
|
||||||
|
std::reverse(std::begin(*out_subnet_mask), std::end(*out_subnet_mask)); // ntohl
|
||||||
|
R_SUCCEED();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result IUserLocalCommunicationService::GetDisconnectReason(
|
||||||
|
Out<DisconnectReason> out_disconnect_reason) {
|
||||||
|
LOG_INFO(Service_LDN, "called");
|
||||||
|
|
||||||
|
*out_disconnect_reason = lan_discovery.GetDisconnectReason();
|
||||||
|
R_SUCCEED();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result IUserLocalCommunicationService::GetSecurityParameter(
|
||||||
|
Out<SecurityParameter> out_security_parameter) {
|
||||||
|
LOG_INFO(Service_LDN, "called");
|
||||||
|
|
||||||
|
NetworkInfo info{};
|
||||||
|
R_TRY(lan_discovery.GetNetworkInfo(info));
|
||||||
|
|
||||||
|
out_security_parameter->session_id = info.network_id.session_id;
|
||||||
|
std::memcpy(out_security_parameter->data.data(), info.ldn.security_parameter.data(),
|
||||||
|
sizeof(SecurityParameter::data));
|
||||||
|
R_SUCCEED();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result IUserLocalCommunicationService::GetNetworkConfig(Out<NetworkConfig> out_network_config) {
|
||||||
|
LOG_INFO(Service_LDN, "called");
|
||||||
|
|
||||||
|
NetworkInfo info{};
|
||||||
|
R_TRY(lan_discovery.GetNetworkInfo(info));
|
||||||
|
|
||||||
|
out_network_config->intent_id = info.network_id.intent_id;
|
||||||
|
out_network_config->channel = info.common.channel;
|
||||||
|
out_network_config->node_count_max = info.ldn.node_count_max;
|
||||||
|
out_network_config->local_communication_version = info.ldn.nodes[0].local_communication_version;
|
||||||
|
R_SUCCEED();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result IUserLocalCommunicationService::AttachStateChangeEvent(
|
||||||
|
OutCopyHandle<Kernel::KReadableEvent> out_event) {
|
||||||
|
LOG_INFO(Service_LDN, "called");
|
||||||
|
|
||||||
|
*out_event = &state_change_event->GetReadableEvent();
|
||||||
|
R_SUCCEED();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result IUserLocalCommunicationService::GetNetworkInfoLatestUpdate(
|
||||||
|
OutLargeData<NetworkInfo, BufferAttr_HipcPointer> out_network_info,
|
||||||
|
OutArray<NodeLatestUpdate, BufferAttr_HipcPointer> out_node_latest_update) {
|
||||||
|
LOG_INFO(Service_LDN, "called");
|
||||||
|
|
||||||
|
R_UNLESS(!out_node_latest_update.empty(), ResultBadInput);
|
||||||
|
|
||||||
|
R_RETURN(lan_discovery.GetNetworkInfo(*out_network_info, out_node_latest_update));
|
||||||
|
}
|
||||||
|
|
||||||
|
Result IUserLocalCommunicationService::Scan(
|
||||||
|
Out<s16> network_count, WifiChannel channel, const ScanFilter& scan_filter,
|
||||||
|
OutArray<NetworkInfo, BufferAttr_HipcAutoSelect> out_network_info) {
|
||||||
|
LOG_INFO(Service_LDN, "called, channel={}, filter_scan_flag={}, filter_network_type={}",
|
||||||
|
channel, scan_filter.flag, scan_filter.network_type);
|
||||||
|
|
||||||
|
R_UNLESS(!out_network_info.empty(), ResultBadInput);
|
||||||
|
R_RETURN(lan_discovery.Scan(out_network_info, *network_count, scan_filter));
|
||||||
|
}
|
||||||
|
|
||||||
|
Result IUserLocalCommunicationService::ScanPrivate(
|
||||||
|
Out<s16> network_count, WifiChannel channel, const ScanFilter& scan_filter,
|
||||||
|
OutArray<NetworkInfo, BufferAttr_HipcAutoSelect> out_network_info) {
|
||||||
|
LOG_INFO(Service_LDN, "called, channel={}, filter_scan_flag={}, filter_network_type={}",
|
||||||
|
channel, scan_filter.flag, scan_filter.network_type);
|
||||||
|
|
||||||
|
R_UNLESS(out_network_info.empty(), ResultBadInput);
|
||||||
|
R_RETURN(lan_discovery.Scan(out_network_info, *network_count, scan_filter));
|
||||||
|
}
|
||||||
|
|
||||||
|
Result IUserLocalCommunicationService::SetWirelessControllerRestriction(
|
||||||
|
WirelessControllerRestriction wireless_restriction) {
|
||||||
|
LOG_WARNING(Service_LDN, "(STUBBED) called");
|
||||||
|
R_SUCCEED();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result IUserLocalCommunicationService::OpenAccessPoint() {
|
||||||
|
LOG_INFO(Service_LDN, "called");
|
||||||
|
|
||||||
|
R_RETURN(lan_discovery.OpenAccessPoint());
|
||||||
|
}
|
||||||
|
|
||||||
|
Result IUserLocalCommunicationService::CloseAccessPoint() {
|
||||||
|
LOG_INFO(Service_LDN, "called");
|
||||||
|
|
||||||
|
R_RETURN(lan_discovery.CloseAccessPoint());
|
||||||
|
}
|
||||||
|
|
||||||
|
Result IUserLocalCommunicationService::CreateNetwork(const CreateNetworkConfig& create_config) {
|
||||||
|
LOG_INFO(Service_LDN, "called");
|
||||||
|
|
||||||
|
R_RETURN(lan_discovery.CreateNetwork(create_config.security_config, create_config.user_config,
|
||||||
|
create_config.network_config));
|
||||||
|
}
|
||||||
|
|
||||||
|
Result IUserLocalCommunicationService::CreateNetworkPrivate(
|
||||||
|
const CreateNetworkConfigPrivate& create_config,
|
||||||
|
InArray<AddressEntry, BufferAttr_HipcPointer> address_list) {
|
||||||
|
LOG_INFO(Service_LDN, "called");
|
||||||
|
|
||||||
|
R_RETURN(lan_discovery.CreateNetwork(create_config.security_config, create_config.user_config,
|
||||||
|
create_config.network_config));
|
||||||
|
}
|
||||||
|
|
||||||
|
Result IUserLocalCommunicationService::DestroyNetwork() {
|
||||||
|
LOG_INFO(Service_LDN, "called");
|
||||||
|
|
||||||
|
R_RETURN(lan_discovery.DestroyNetwork());
|
||||||
|
}
|
||||||
|
|
||||||
|
Result IUserLocalCommunicationService::SetAdvertiseData(
|
||||||
|
InBuffer<BufferAttr_HipcAutoSelect> buffer_data) {
|
||||||
|
LOG_INFO(Service_LDN, "called");
|
||||||
|
|
||||||
|
R_RETURN(lan_discovery.SetAdvertiseData(buffer_data));
|
||||||
|
}
|
||||||
|
|
||||||
|
Result IUserLocalCommunicationService::SetStationAcceptPolicy(AcceptPolicy accept_policy) {
|
||||||
|
LOG_WARNING(Service_LDN, "(STUBBED) called");
|
||||||
|
R_SUCCEED();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result IUserLocalCommunicationService::AddAcceptFilterEntry(MacAddress mac_address) {
|
||||||
|
LOG_WARNING(Service_LDN, "(STUBBED) called");
|
||||||
|
R_SUCCEED();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result IUserLocalCommunicationService::OpenStation() {
|
||||||
|
LOG_INFO(Service_LDN, "called");
|
||||||
|
|
||||||
|
R_RETURN(lan_discovery.OpenStation());
|
||||||
|
}
|
||||||
|
|
||||||
|
Result IUserLocalCommunicationService::CloseStation() {
|
||||||
|
LOG_INFO(Service_LDN, "called");
|
||||||
|
|
||||||
|
R_RETURN(lan_discovery.CloseStation());
|
||||||
|
}
|
||||||
|
|
||||||
|
Result IUserLocalCommunicationService::Connect(
|
||||||
|
const ConnectNetworkData& connect_data,
|
||||||
|
InLargeData<NetworkInfo, BufferAttr_HipcPointer> network_info) {
|
||||||
|
LOG_INFO(Service_LDN,
|
||||||
|
"called, passphrase_size={}, security_mode={}, "
|
||||||
|
"local_communication_version={}",
|
||||||
|
connect_data.security_config.passphrase_size,
|
||||||
|
connect_data.security_config.security_mode, connect_data.local_communication_version);
|
||||||
|
|
||||||
|
R_RETURN(lan_discovery.Connect(*network_info, connect_data.user_config,
|
||||||
|
static_cast<u16>(connect_data.local_communication_version)));
|
||||||
|
}
|
||||||
|
|
||||||
|
Result IUserLocalCommunicationService::Disconnect() {
|
||||||
|
LOG_INFO(Service_LDN, "called");
|
||||||
|
|
||||||
|
R_RETURN(lan_discovery.Disconnect());
|
||||||
|
}
|
||||||
|
|
||||||
|
Result IUserLocalCommunicationService::Initialize(ClientProcessId aruid) {
|
||||||
|
LOG_INFO(Service_LDN, "called, process_id={}", aruid.pid);
|
||||||
|
|
||||||
|
const auto network_interface = Network::GetSelectedNetworkInterface();
|
||||||
|
R_UNLESS(network_interface, ResultAirplaneModeEnabled);
|
||||||
|
|
||||||
|
if (auto room_member = room_network.GetRoomMember().lock()) {
|
||||||
|
ldn_packet_received = room_member->BindOnLdnPacketReceived(
|
||||||
|
[this](const Network::LDNPacket& packet) { OnLDNPacketReceived(packet); });
|
||||||
|
} else {
|
||||||
|
LOG_ERROR(Service_LDN, "Couldn't bind callback!");
|
||||||
|
R_RETURN(ResultAirplaneModeEnabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
lan_discovery.Initialize([&]() { OnEventFired(); });
|
||||||
|
is_initialized = true;
|
||||||
|
R_SUCCEED();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result IUserLocalCommunicationService::Finalize() {
|
||||||
|
LOG_INFO(Service_LDN, "called");
|
||||||
|
if (auto room_member = room_network.GetRoomMember().lock()) {
|
||||||
|
room_member->Unbind(ldn_packet_received);
|
||||||
|
}
|
||||||
|
|
||||||
|
is_initialized = false;
|
||||||
|
|
||||||
|
R_RETURN(lan_discovery.Finalize());
|
||||||
|
}
|
||||||
|
|
||||||
|
Result IUserLocalCommunicationService::Initialize2(u32 version, ClientProcessId process_id) {
|
||||||
|
LOG_INFO(Service_LDN, "called, version={}, process_id={}", version, process_id.pid);
|
||||||
|
R_RETURN(Initialize(process_id));
|
||||||
|
}
|
||||||
|
|
||||||
|
void IUserLocalCommunicationService::OnLDNPacketReceived(const Network::LDNPacket& packet) {
|
||||||
|
lan_discovery.ReceivePacket(packet);
|
||||||
|
}
|
||||||
|
|
||||||
|
void IUserLocalCommunicationService::OnEventFired() {
|
||||||
|
state_change_event->Signal();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Service::LDN
|
103
src/core/hle/service/ldn/user_local_communication_service.h
Normal file
103
src/core/hle/service/ldn/user_local_communication_service.h
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "core/hle/service/cmif_types.h"
|
||||||
|
#include "core/hle/service/kernel_helpers.h"
|
||||||
|
#include "core/hle/service/ldn/lan_discovery.h"
|
||||||
|
#include "core/hle/service/ldn/ldn_types.h"
|
||||||
|
#include "core/hle/service/service.h"
|
||||||
|
|
||||||
|
namespace Core {
|
||||||
|
class System;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Network {
|
||||||
|
class RoomNetwork;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Service::LDN {
|
||||||
|
|
||||||
|
class IUserLocalCommunicationService final
|
||||||
|
: public ServiceFramework<IUserLocalCommunicationService> {
|
||||||
|
public:
|
||||||
|
explicit IUserLocalCommunicationService(Core::System& system_);
|
||||||
|
~IUserLocalCommunicationService() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
Result GetState(Out<State> out_state);
|
||||||
|
|
||||||
|
Result GetNetworkInfo(OutLargeData<NetworkInfo, BufferAttr_HipcPointer> out_network_info);
|
||||||
|
|
||||||
|
Result GetIpv4Address(Out<Ipv4Address> out_current_address, Out<Ipv4Address> out_subnet_mask);
|
||||||
|
|
||||||
|
Result GetDisconnectReason(Out<DisconnectReason> out_disconnect_reason);
|
||||||
|
|
||||||
|
Result GetSecurityParameter(Out<SecurityParameter> out_security_parameter);
|
||||||
|
|
||||||
|
Result GetNetworkConfig(Out<NetworkConfig> out_network_config);
|
||||||
|
|
||||||
|
Result AttachStateChangeEvent(OutCopyHandle<Kernel::KReadableEvent> out_event);
|
||||||
|
|
||||||
|
Result GetNetworkInfoLatestUpdate(
|
||||||
|
OutLargeData<NetworkInfo, BufferAttr_HipcPointer> out_network_info,
|
||||||
|
OutArray<NodeLatestUpdate, BufferAttr_HipcPointer> out_node_latest_update);
|
||||||
|
|
||||||
|
Result Scan(Out<s16> network_count, WifiChannel channel, const ScanFilter& scan_filter,
|
||||||
|
OutArray<NetworkInfo, BufferAttr_HipcAutoSelect> out_network_info);
|
||||||
|
|
||||||
|
Result ScanPrivate(Out<s16> network_count, WifiChannel channel, const ScanFilter& scan_filter,
|
||||||
|
OutArray<NetworkInfo, BufferAttr_HipcAutoSelect> out_network_info);
|
||||||
|
|
||||||
|
Result SetWirelessControllerRestriction(WirelessControllerRestriction wireless_restriction);
|
||||||
|
|
||||||
|
Result OpenAccessPoint();
|
||||||
|
|
||||||
|
Result CloseAccessPoint();
|
||||||
|
|
||||||
|
Result CreateNetwork(const CreateNetworkConfig& create_network_Config);
|
||||||
|
|
||||||
|
Result CreateNetworkPrivate(const CreateNetworkConfigPrivate& create_network_Config,
|
||||||
|
InArray<AddressEntry, BufferAttr_HipcPointer> address_list);
|
||||||
|
|
||||||
|
Result DestroyNetwork();
|
||||||
|
|
||||||
|
Result SetAdvertiseData(InBuffer<BufferAttr_HipcAutoSelect> buffer_data);
|
||||||
|
|
||||||
|
Result SetStationAcceptPolicy(AcceptPolicy accept_policy);
|
||||||
|
|
||||||
|
Result AddAcceptFilterEntry(MacAddress mac_address);
|
||||||
|
|
||||||
|
Result OpenStation();
|
||||||
|
|
||||||
|
Result CloseStation();
|
||||||
|
|
||||||
|
Result Connect(const ConnectNetworkData& connect_data,
|
||||||
|
InLargeData<NetworkInfo, BufferAttr_HipcPointer> network_info);
|
||||||
|
|
||||||
|
Result Disconnect();
|
||||||
|
|
||||||
|
Result Initialize(ClientProcessId aruid);
|
||||||
|
|
||||||
|
Result Finalize();
|
||||||
|
|
||||||
|
Result Initialize2(u32 version, ClientProcessId aruid);
|
||||||
|
|
||||||
|
private:
|
||||||
|
/// Callback to parse and handle a received LDN packet.
|
||||||
|
void OnLDNPacketReceived(const Network::LDNPacket& packet);
|
||||||
|
void OnEventFired();
|
||||||
|
|
||||||
|
KernelHelpers::ServiceContext service_context;
|
||||||
|
Kernel::KEvent* state_change_event;
|
||||||
|
Network::RoomNetwork& room_network;
|
||||||
|
LANDiscovery lan_discovery;
|
||||||
|
|
||||||
|
// Callback identifier for the OnLDNPacketReceived event.
|
||||||
|
Network::RoomMember::CallbackHandle<Network::LDNPacket> ldn_packet_received;
|
||||||
|
|
||||||
|
bool is_initialized{};
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Service::LDN
|
@ -54,13 +54,28 @@ std::unique_ptr<TranslationMap> InitializeTranslations(QWidget* parent) {
|
|||||||
QStringLiteral());
|
QStringLiteral());
|
||||||
|
|
||||||
// Core
|
// Core
|
||||||
INSERT(Settings, use_multi_core, tr("Multicore CPU Emulation"), QStringLiteral());
|
INSERT(
|
||||||
INSERT(Settings, memory_layout_mode, tr("Memory Layout"), QStringLiteral());
|
Settings, use_multi_core, tr("Multicore CPU Emulation"),
|
||||||
|
tr("This option increases CPU emulation thread use from 1 to the Switch’s maximum of 4.\n"
|
||||||
|
"This is mainly a debug option and shouldn’t be disabled."));
|
||||||
|
INSERT(
|
||||||
|
Settings, memory_layout_mode, tr("Memory Layout"),
|
||||||
|
tr("Increases the amount of emulated RAM from the stock 4GB of the retail Switch to the "
|
||||||
|
"developer kit's 8/6GB.\nIt’s doesn’t improve stability or performance and is intended "
|
||||||
|
"to let big texture mods fit in emulated RAM.\nEnabling it will increase memory "
|
||||||
|
"use. It is not recommended to enable unless a specific game with a texture mod needs "
|
||||||
|
"it."));
|
||||||
INSERT(Settings, use_speed_limit, QStringLiteral(), QStringLiteral());
|
INSERT(Settings, use_speed_limit, QStringLiteral(), QStringLiteral());
|
||||||
INSERT(Settings, speed_limit, tr("Limit Speed Percent"), QStringLiteral());
|
INSERT(Settings, speed_limit, tr("Limit Speed Percent"),
|
||||||
|
tr("Controls the game's maximum rendering speed, but it’s up to each game if it runs "
|
||||||
|
"faster or not.\n200% for a 30 FPS game is 60 FPS, and for a "
|
||||||
|
"60 FPS game it will be 120 FPS.\nDisabling it means unlocking the framerate to the "
|
||||||
|
"maximum your PC can reach."));
|
||||||
|
|
||||||
// Cpu
|
// Cpu
|
||||||
INSERT(Settings, cpu_accuracy, tr("Accuracy:"), QStringLiteral());
|
INSERT(Settings, cpu_accuracy, tr("Accuracy:"),
|
||||||
|
tr("This setting controls the accuracy of the emulated CPU.\nDon't change this unless "
|
||||||
|
"you know what you are doing."));
|
||||||
INSERT(Settings, cpu_backend, tr("Backend:"), QStringLiteral());
|
INSERT(Settings, cpu_backend, tr("Backend:"), QStringLiteral());
|
||||||
|
|
||||||
// Cpu Debug
|
// Cpu Debug
|
||||||
@ -80,34 +95,75 @@ std::unique_ptr<TranslationMap> InitializeTranslations(QWidget* parent) {
|
|||||||
tr("This option improves the speed of 32 bits ASIMD floating-point functions by running "
|
tr("This option improves the speed of 32 bits ASIMD floating-point functions by running "
|
||||||
"with incorrect rounding modes."));
|
"with incorrect rounding modes."));
|
||||||
INSERT(Settings, cpuopt_unsafe_inaccurate_nan, tr("Inaccurate NaN handling"),
|
INSERT(Settings, cpuopt_unsafe_inaccurate_nan, tr("Inaccurate NaN handling"),
|
||||||
tr("This option improves speed by removing NaN checking. Please note this also reduces "
|
tr("This option improves speed by removing NaN checking.\nPlease note this also reduces "
|
||||||
"accuracy of certain floating-point instructions."));
|
"accuracy of certain floating-point instructions."));
|
||||||
INSERT(Settings, cpuopt_unsafe_fastmem_check, tr("Disable address space checks"),
|
INSERT(Settings, cpuopt_unsafe_fastmem_check, tr("Disable address space checks"),
|
||||||
tr("This option improves speed by eliminating a safety check before every memory "
|
tr("This option improves speed by eliminating a safety check before every memory "
|
||||||
"read/write "
|
"read/write in guest.\nDisabling it may allow a game to read/write the emulator's "
|
||||||
"in guest. Disabling it may allow a game to read/write the emulator's memory."));
|
"memory."));
|
||||||
INSERT(
|
INSERT(
|
||||||
Settings, cpuopt_unsafe_ignore_global_monitor, tr("Ignore global monitor"),
|
Settings, cpuopt_unsafe_ignore_global_monitor, tr("Ignore global monitor"),
|
||||||
tr("This option improves speed by relying only on the semantics of cmpxchg to ensure "
|
tr("This option improves speed by relying only on the semantics of cmpxchg to ensure "
|
||||||
"safety of exclusive access instructions. Please note this may result in deadlocks and "
|
"safety of exclusive access instructions.\nPlease note this may result in deadlocks and "
|
||||||
"other race conditions."));
|
"other race conditions."));
|
||||||
|
|
||||||
// Renderer
|
// Renderer
|
||||||
INSERT(Settings, renderer_backend, tr("API:"), QStringLiteral());
|
INSERT(
|
||||||
INSERT(Settings, vulkan_device, tr("Device:"), QStringLiteral());
|
Settings, renderer_backend, tr("API:"),
|
||||||
INSERT(Settings, shader_backend, tr("Shader Backend:"), QStringLiteral());
|
tr("Switches between the available graphics APIs.\nVulkan is recommended in most cases."));
|
||||||
INSERT(Settings, resolution_setup, tr("Resolution:"), QStringLiteral());
|
INSERT(Settings, vulkan_device, tr("Device:"),
|
||||||
|
tr("This setting selects the GPU to use with the Vulkan backend."));
|
||||||
|
INSERT(Settings, shader_backend, tr("Shader Backend:"),
|
||||||
|
tr("The shader backend to use for the OpenGL renderer.\nGLSL is the fastest in "
|
||||||
|
"performance and the best in rendering accuracy.\n"
|
||||||
|
"GLASM is a deprecated NVIDIA-only backend that offers much better shader building "
|
||||||
|
"performance at the cost of FPS and rendering accuracy.\n"
|
||||||
|
"SPIR-V compiles the fastest, but yields poor results on most GPU drivers."));
|
||||||
|
INSERT(Settings, resolution_setup, tr("Resolution:"),
|
||||||
|
tr("Forces the game to render at a different resolution.\nHigher resolutions require "
|
||||||
|
"much more VRAM and bandwidth.\n"
|
||||||
|
"Options lower than 1X can cause rendering issues."));
|
||||||
INSERT(Settings, scaling_filter, tr("Window Adapting Filter:"), QStringLiteral());
|
INSERT(Settings, scaling_filter, tr("Window Adapting Filter:"), QStringLiteral());
|
||||||
INSERT(Settings, fsr_sharpening_slider, tr("FSR Sharpness:"), QStringLiteral());
|
INSERT(Settings, fsr_sharpening_slider, tr("FSR Sharpness:"),
|
||||||
INSERT(Settings, anti_aliasing, tr("Anti-Aliasing Method:"), QStringLiteral());
|
tr("Determines how sharpened the image will look while using FSR’s dynamic contrast."));
|
||||||
INSERT(Settings, fullscreen_mode, tr("Fullscreen Mode:"), QStringLiteral());
|
INSERT(Settings, anti_aliasing, tr("Anti-Aliasing Method:"),
|
||||||
INSERT(Settings, aspect_ratio, tr("Aspect Ratio:"), QStringLiteral());
|
tr("The anti-aliasing method to use.\nSMAA offers the best quality.\nFXAA has a "
|
||||||
INSERT(Settings, use_disk_shader_cache, tr("Use disk pipeline cache"), QStringLiteral());
|
"lower performance impact and can produce a better and more stable picture under "
|
||||||
INSERT(Settings, use_asynchronous_gpu_emulation, tr("Use asynchronous GPU emulation"),
|
"very low resolutions."));
|
||||||
QStringLiteral());
|
INSERT(Settings, fullscreen_mode, tr("Fullscreen Mode:"),
|
||||||
INSERT(Settings, nvdec_emulation, tr("NVDEC emulation:"), QStringLiteral());
|
tr("The method used to render the window in fullscreen.\nBorderless offers the best "
|
||||||
INSERT(Settings, accelerate_astc, tr("ASTC Decoding Method:"), QStringLiteral());
|
"compatibility with the on-screen keyboard that some games request for "
|
||||||
INSERT(Settings, astc_recompression, tr("ASTC Recompression Method:"), QStringLiteral());
|
"input.\nExclusive "
|
||||||
|
"fullscreen may offer better performance and better Freesync/Gsync support."));
|
||||||
|
INSERT(Settings, aspect_ratio, tr("Aspect Ratio:"),
|
||||||
|
tr("Stretches the game to fit the specified aspect ratio.\nSwitch games only support "
|
||||||
|
"16:9, so custom game mods are required to get other ratios.\nAlso controls the "
|
||||||
|
"aspect ratio of captured screenshots."));
|
||||||
|
INSERT(Settings, use_disk_shader_cache, tr("Use disk pipeline cache"),
|
||||||
|
tr("Allows saving shaders to storage for faster loading on following game "
|
||||||
|
"boots.\nDisabling "
|
||||||
|
"it is only intended for debugging."));
|
||||||
|
INSERT(
|
||||||
|
Settings, use_asynchronous_gpu_emulation, tr("Use asynchronous GPU emulation"),
|
||||||
|
tr("Uses an extra CPU thread for rendering.\nThis option should always remain enabled."));
|
||||||
|
INSERT(Settings, nvdec_emulation, tr("NVDEC emulation:"),
|
||||||
|
tr("Specifies how videos should be decoded.\nIt can either use the CPU or the GPU for "
|
||||||
|
"decoding, or perform no decoding at all (black screen on videos).\n"
|
||||||
|
"In most cases, GPU decoding provides the best performance."));
|
||||||
|
INSERT(Settings, accelerate_astc, tr("ASTC Decoding Method:"),
|
||||||
|
tr("This option controls how ASTC textures should be decoded.\n"
|
||||||
|
"CPU: Use the CPU for decoding, slowest but safest method.\n"
|
||||||
|
"GPU: Use the GPU's compute shaders to decode ASTC textures, recommended for most "
|
||||||
|
"games and users.\n"
|
||||||
|
"CPU Asynchronously: Use the CPU to decode ASTC textures as they arrive. Completely "
|
||||||
|
"eliminates ASTC decoding\nstuttering at the cost of rendering issues while the "
|
||||||
|
"texture is being decoded."));
|
||||||
|
INSERT(
|
||||||
|
Settings, astc_recompression, tr("ASTC Recompression Method:"),
|
||||||
|
tr("Almost all desktop and laptop dedicated GPUs lack support for ASTC textures, forcing "
|
||||||
|
"the emulator to decompress to an intermediate format any card supports, RGBA8.\n"
|
||||||
|
"This option recompresses RGBA8 to either the BC1 or BC3 format, saving VRAM but "
|
||||||
|
"negatively affecting image quality."));
|
||||||
INSERT(
|
INSERT(
|
||||||
Settings, vsync_mode, tr("VSync Mode:"),
|
Settings, vsync_mode, tr("VSync Mode:"),
|
||||||
tr("FIFO (VSync) does not drop frames or exhibit tearing but is limited by the screen "
|
tr("FIFO (VSync) does not drop frames or exhibit tearing but is limited by the screen "
|
||||||
@ -121,22 +177,29 @@ std::unique_ptr<TranslationMap> InitializeTranslations(QWidget* parent) {
|
|||||||
|
|
||||||
// Renderer (Advanced Graphics)
|
// Renderer (Advanced Graphics)
|
||||||
INSERT(Settings, async_presentation, tr("Enable asynchronous presentation (Vulkan only)"),
|
INSERT(Settings, async_presentation, tr("Enable asynchronous presentation (Vulkan only)"),
|
||||||
QStringLiteral());
|
tr("Slightly improves performance by moving presentation to a separate CPU thread."));
|
||||||
INSERT(
|
INSERT(
|
||||||
Settings, renderer_force_max_clock, tr("Force maximum clocks (Vulkan only)"),
|
Settings, renderer_force_max_clock, tr("Force maximum clocks (Vulkan only)"),
|
||||||
tr("Runs work in the background while waiting for graphics commands to keep the GPU from "
|
tr("Runs work in the background while waiting for graphics commands to keep the GPU from "
|
||||||
"lowering its clock speed."));
|
"lowering its clock speed."));
|
||||||
INSERT(Settings, max_anisotropy, tr("Anisotropic Filtering:"), QStringLiteral());
|
INSERT(Settings, max_anisotropy, tr("Anisotropic Filtering:"),
|
||||||
INSERT(Settings, gpu_accuracy, tr("Accuracy Level:"), QStringLiteral());
|
tr("Controls the quality of texture rendering at oblique angles.\nIt’s a light setting "
|
||||||
INSERT(
|
"and safe to set at 16x on most GPUs."));
|
||||||
Settings, use_asynchronous_shaders, tr("Use asynchronous shader building (Hack)"),
|
INSERT(Settings, gpu_accuracy, tr("Accuracy Level:"),
|
||||||
tr("Enables asynchronous shader compilation, which may reduce shader stutter. This feature "
|
tr("GPU emulation accuracy.\nMost games render fine with Normal, but High is still "
|
||||||
"is experimental."));
|
"required for some.\nParticles tend to only render correctly with High "
|
||||||
|
"accuracy.\nExtreme should only be used for debugging.\nThis option can "
|
||||||
|
"be changed while playing.\nSome games may require booting on high to render "
|
||||||
|
"properly."));
|
||||||
|
INSERT(Settings, use_asynchronous_shaders, tr("Use asynchronous shader building (Hack)"),
|
||||||
|
tr("Enables asynchronous shader compilation, which may reduce shader stutter.\nThis "
|
||||||
|
"feature "
|
||||||
|
"is experimental."));
|
||||||
INSERT(Settings, use_fast_gpu_time, tr("Use Fast GPU Time (Hack)"),
|
INSERT(Settings, use_fast_gpu_time, tr("Use Fast GPU Time (Hack)"),
|
||||||
tr("Enables Fast GPU Time. This option will force most games to run at their highest "
|
tr("Enables Fast GPU Time. This option will force most games to run at their highest "
|
||||||
"native resolution."));
|
"native resolution."));
|
||||||
INSERT(Settings, use_vulkan_driver_pipeline_cache, tr("Use Vulkan pipeline cache"),
|
INSERT(Settings, use_vulkan_driver_pipeline_cache, tr("Use Vulkan pipeline cache"),
|
||||||
tr("Enables GPU vendor-specific pipeline cache. This option can improve shader loading "
|
tr("Enables GPU vendor-specific pipeline cache.\nThis option can improve shader loading "
|
||||||
"time significantly in cases where the Vulkan driver does not store pipeline cache "
|
"time significantly in cases where the Vulkan driver does not store pipeline cache "
|
||||||
"files internally."));
|
"files internally."));
|
||||||
INSERT(
|
INSERT(
|
||||||
@ -157,19 +220,27 @@ std::unique_ptr<TranslationMap> InitializeTranslations(QWidget* parent) {
|
|||||||
// Renderer (Debug)
|
// Renderer (Debug)
|
||||||
|
|
||||||
// System
|
// System
|
||||||
INSERT(Settings, rng_seed, tr("RNG Seed"), QStringLiteral());
|
INSERT(Settings, rng_seed, tr("RNG Seed"),
|
||||||
|
tr("Controls the seed of the random number generator.\nMainly used for speedrunning "
|
||||||
|
"purposes."));
|
||||||
INSERT(Settings, rng_seed_enabled, QStringLiteral(), QStringLiteral());
|
INSERT(Settings, rng_seed_enabled, QStringLiteral(), QStringLiteral());
|
||||||
INSERT(Settings, device_name, tr("Device Name"), QStringLiteral());
|
INSERT(Settings, device_name, tr("Device Name"), tr("The name of the emulated Switch."));
|
||||||
INSERT(Settings, custom_rtc, tr("Custom RTC Date:"), QStringLiteral());
|
INSERT(Settings, custom_rtc, tr("Custom RTC Date:"),
|
||||||
|
tr("This option allows to change the emulated clock of the Switch.\n"
|
||||||
|
"Can be used to manipulate time in games."));
|
||||||
INSERT(Settings, custom_rtc_enabled, QStringLiteral(), QStringLiteral());
|
INSERT(Settings, custom_rtc_enabled, QStringLiteral(), QStringLiteral());
|
||||||
INSERT(Settings, custom_rtc_offset, QStringLiteral(" "),
|
INSERT(Settings, custom_rtc_offset, QStringLiteral(" "),
|
||||||
QStringLiteral("The number of seconds from the current unix time"));
|
QStringLiteral("The number of seconds from the current unix time"));
|
||||||
INSERT(Settings, language_index, tr("Language:"),
|
INSERT(Settings, language_index, tr("Language:"),
|
||||||
tr("Note: this can be overridden when region setting is auto-select"));
|
tr("Note: this can be overridden when region setting is auto-select"));
|
||||||
INSERT(Settings, region_index, tr("Region:"), QStringLiteral());
|
INSERT(Settings, region_index, tr("Region:"), tr("The region of the emulated Switch."));
|
||||||
INSERT(Settings, time_zone_index, tr("Time Zone:"), QStringLiteral());
|
INSERT(Settings, time_zone_index, tr("Time Zone:"),
|
||||||
|
tr("The time zone of the emulated Switch."));
|
||||||
INSERT(Settings, sound_index, tr("Sound Output Mode:"), QStringLiteral());
|
INSERT(Settings, sound_index, tr("Sound Output Mode:"), QStringLiteral());
|
||||||
INSERT(Settings, use_docked_mode, tr("Console Mode:"), QStringLiteral());
|
INSERT(Settings, use_docked_mode, tr("Console Mode:"),
|
||||||
|
tr("Selects if the console is emulated in Docked or Handheld mode.\nGames will change "
|
||||||
|
"their resolution, details and supported controllers and depending on this setting.\n"
|
||||||
|
"Setting to Handheld can help improve performance for low end systems."));
|
||||||
INSERT(Settings, current_user, QStringLiteral(), QStringLiteral());
|
INSERT(Settings, current_user, QStringLiteral(), QStringLiteral());
|
||||||
|
|
||||||
// Controls
|
// Controls
|
||||||
@ -187,14 +258,19 @@ std::unique_ptr<TranslationMap> InitializeTranslations(QWidget* parent) {
|
|||||||
// Ui
|
// Ui
|
||||||
|
|
||||||
// Ui General
|
// Ui General
|
||||||
INSERT(UISettings, select_user_on_boot, tr("Prompt for user on game boot"), QStringLiteral());
|
INSERT(UISettings, select_user_on_boot, tr("Prompt for user on game boot"),
|
||||||
|
tr("Ask to select a user profile on each boot, useful if multiple people use yuzu on "
|
||||||
|
"the same PC."));
|
||||||
INSERT(UISettings, pause_when_in_background, tr("Pause emulation when in background"),
|
INSERT(UISettings, pause_when_in_background, tr("Pause emulation when in background"),
|
||||||
QStringLiteral());
|
tr("This setting pauses yuzu when focusing other windows."));
|
||||||
INSERT(UISettings, confirm_before_stopping, tr("Confirm before stopping emulation"),
|
INSERT(UISettings, confirm_before_stopping, tr("Confirm before stopping emulation"),
|
||||||
QStringLiteral());
|
tr("This setting overrides game prompts asking to confirm stopping the game.\nEnabling "
|
||||||
INSERT(UISettings, hide_mouse, tr("Hide mouse on inactivity"), QStringLiteral());
|
"it bypasses such prompts and directly exits the emulation."));
|
||||||
|
INSERT(UISettings, hide_mouse, tr("Hide mouse on inactivity"),
|
||||||
|
tr("This setting hides the mouse after 2.5s of inactivity."));
|
||||||
INSERT(UISettings, controller_applet_disabled, tr("Disable controller applet"),
|
INSERT(UISettings, controller_applet_disabled, tr("Disable controller applet"),
|
||||||
QStringLiteral());
|
tr("Forcibly disables the use of the controller applet by guests.\nWhen a guest "
|
||||||
|
"attempts to open the controller applet, it is immediately closed."));
|
||||||
|
|
||||||
// Linux
|
// Linux
|
||||||
INSERT(Settings, enable_gamemode, tr("Enable Gamemode"), QStringLiteral());
|
INSERT(Settings, enable_gamemode, tr("Enable Gamemode"), QStringLiteral());
|
||||||
|
@ -190,10 +190,8 @@ void ControllerShortcut::ControllerUpdateEvent(Core::HID::ControllerTriggerType
|
|||||||
if (type != Core::HID::ControllerTriggerType::Button) {
|
if (type != Core::HID::ControllerTriggerType::Button) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!Settings::values.controller_navigation) {
|
if (button_sequence.npad.raw == Core::HID::NpadButton::None &&
|
||||||
return;
|
button_sequence.capture.raw == 0 && button_sequence.home.raw == 0) {
|
||||||
}
|
|
||||||
if (button_sequence.npad.raw == Core::HID::NpadButton::None) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user