aboutsummaryrefslogtreecommitdiff
path: root/src/core/hle
diff options
context:
space:
mode:
authornéo Luigi <85024393+neoluigi4123@users.noreply.github.com>2026-11-03 02:15:22 +0100
committernéo Luigi <85024393+neoluigi4123@users.noreply.github.com>2026-11-03 02:15:22 +0100
commit465aa33077f44d3f8664c076f8580e78446c0dee (patch)
tree8106a200ba7f5f9f4f072284ae490298eebc7f58 /src/core/hle
parentc84e5caf82a786f748c233e27b7f4ed9aaad9f44 (diff)
Vibration support for ns2 games
This branch supports vibration by achieving proper rumble reading from games and uses regular eglantine/eden logic from ns1 to send them over. Tested on windows 10 on Mario Kart World Assisted-by: Claude Opus 5.5 (code cleanup)
Diffstat (limited to 'src/core/hle')
-rw-r--r--src/core/hle/service/hid/hid_server.cpp50
-rw-r--r--src/core/hle/service/hid/hid_server.h11
2 files changed, 25 insertions, 36 deletions
diff --git a/src/core/hle/service/hid/hid_server.cpp b/src/core/hle/service/hid/hid_server.cpp
index eb6a29c158..f2a7b7d04a 100644
--- a/src/core/hle/service/hid/hid_server.cpp
+++ b/src/core/hle/service/hid/hid_server.cpp
@@ -4,6 +4,7 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
+#include <algorithm>
#include <array>
#include "common/common_types.h"
@@ -140,7 +141,7 @@ IHidServer::IHidServer(Core::System& system_, std::shared_ptr<ResourceManager> r
{211, C<&IHidServer::IsVibrationDeviceMounted>, "IsVibrationDeviceMounted"},
{212, C<&IHidServer::SendVibrationValueInBool>, "SendVibrationValueInBool"},
{213, C<&IHidServer::Unknown213>, "Unknown213"},
- {214, &IHidServer::SendNx2VibrationValues, "SendNx2VibrationValues (guessed)"},
+ {214, C<&IHidServer::SendNx2VibrationValues>, "SendNx2VibrationValues (guessed)"},
{220, C<&IHidServer::Unknown220>, "Unknown220"},
{300, C<&IHidServer::ActivateConsoleSixAxisSensor>, "ActivateConsoleSixAxisSensor"},
{301, C<&IHidServer::StartConsoleSixAxisSensor>, "StartConsoleSixAxisSensor"},
@@ -1112,40 +1113,25 @@ Result IHidServer::IsVibrationDeviceMounted(
R_SUCCEED();
}
-// TEMPORARY local diagnostic for #103: dumps the request layout of 214 when it changes.
-void IHidServer::SendNx2VibrationValues(HLERequestContext& ctx) {
- static std::string last_dump;
- static u64 call_count = 0;
- ++call_count;
-
- std::string dump = fmt::format("words(payload@{}):", ctx.GetDataPayloadOffset());
- const u32* cmd_buf = ctx.CommandBuffer();
- for (u32 i = 0; i < 16; ++i) {
- dump += fmt::format(" {:08x}", cmd_buf[i]);
- }
- dump += fmt::format(" | X={} A={} B={} C={}", ctx.BufferDescriptorX().size(),
- ctx.BufferDescriptorA().size(), ctx.BufferDescriptorB().size(),
- ctx.BufferDescriptorC().size());
- const auto dump_buffer = [&dump](char kind, std::size_t index, std::span<const u8> data) {
- dump += fmt::format(" | {}{} size={}:", kind, index, data.size());
- for (std::size_t i = 0; i < std::min<std::size_t>(data.size(), 96); ++i) {
- dump += fmt::format("{}{:02x}", i % 4 == 0 ? " " : "", data[i]);
+Result IHidServer::SendNx2VibrationValues(
+ u64 unknown, AppletResourceUserId aruid,
+ InArray<Core::HID::VibrationDeviceHandle, BufferAttr_HipcPointer> vibration_handles,
+ InArray<Core::HID::VibrationValue, BufferAttr_HipcPointer> vibration_values) {
+ LOG_DEBUG(Service_HID, "called, unknown={}, applet_resource_user_id={}", unknown, aruid.pid);
+
+ // Unlike 206 this never fails: rumble is best effort and the command is only known from
+ // captures, so an unexpected handle or layout shouldn't return an error a game may treat as
+ // fatal.
+ const auto count = (std::min)(vibration_handles.size(), vibration_values.size());
+ for (std::size_t i = 0; i < count; i++) {
+ const auto result = GetResourceManager()->SendVibrationValue(
+ aruid.pid, vibration_handles[i], vibration_values[i]);
+ if (result.IsError()) {
+ LOG_DEBUG(Service_HID, "failed to send vibration {}, result={:#x}", i, result.raw);
}
- };
- for (std::size_t i = 0; i < ctx.BufferDescriptorX().size(); ++i) {
- dump_buffer('X', i, ctx.ReadBufferX(i));
- }
- for (std::size_t i = 0; i < ctx.BufferDescriptorA().size(); ++i) {
- dump_buffer('A', i, ctx.ReadBufferA(i));
- }
-
- if (dump != last_dump) {
- LOG_INFO(Service_HID, "214 #{}: {}", call_count, dump);
- last_dump = std::move(dump);
}
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultSuccess);
+ R_SUCCEED();
}
Result IHidServer::Unknown213() {
diff --git a/src/core/hle/service/hid/hid_server.h b/src/core/hle/service/hid/hid_server.h
index 5738e1798f..9bb62fabc4 100644
--- a/src/core/hle/service/hid/hid_server.h
+++ b/src/core/hle/service/hid/hid_server.h
@@ -189,11 +189,14 @@ private:
Result SendVibrationValueInBool(bool is_vibrating,
Core::HID::VibrationDeviceHandle vibration_device_handle,
ClientAppletResourceUserId aruid);
- // Switch 2 sends vibration every frame with 214 (pointer buffers of device handles and
- // values, like 206); Eden doesn't emulate vibration, so accept and drop it.
- void SendNx2VibrationValues(HLERequestContext& ctx);
+ // Switch 2 sends vibration every frame with 214: pointer buffers of device handles and values
+ // like 206, but the aruid is raw data after an unknown u64 instead of a sent process id.
+ Result SendNx2VibrationValues(
+ u64 unknown, AppletResourceUserId aruid,
+ InArray<Core::HID::VibrationDeviceHandle, BufferAttr_HipcPointer> vibration_handles,
+ InArray<Core::HID::VibrationValue, BufferAttr_HipcPointer> vibration_values);
// 213 (32 bytes, aruid): sent per controller every frame by Kirby Air Riders (tens of
- // thousands of auto stub log lines a run); no reply data. Accepted and dropped like 214.
+ // thousands of auto stub log lines a run); no reply data. Accepted and dropped.
Result Unknown213();
// 220 (16 bytes, aruid): replies one byte (meaning unknown); answer 0 instead of leaving it to
// the message buffer's leftovers.