Compare commits

..

15 Commits

Author SHA1 Message Date
Morph
b94e576653 kernel: Synchronize 2023-07-01 16:21:22 -04:00
Fernando S
9252ad4e10 Merge pull request #10956 from FernandoS27/pikmin-another-game-ill-hate
AccelerateDMA: Don't accelerate 3D texture DMA operations
2023-06-30 09:37:07 +02:00
Fernando Sahmkow
596a6132b9 AccelerateDMA: Don't accelerate 3D texture DMA operations 2023-06-29 17:23:29 +02:00
Charles Lombardo
45be4c3214 Merge pull request #10955 from 8bitDream/gradle
android: Suppress a known incompatibility
2023-06-29 11:07:00 -04:00
liamwhite
5e70db0d43 Merge pull request #10935 from Morph1984/mwaitx
x64: Make use of monitorx instructions for power efficient sleeps (AMD)
2023-06-29 10:01:26 -04:00
liamwhite
4c705db73e Merge pull request #10937 from german77/ring
input_common: Remove duplicated enum and fix ring detection
2023-06-29 10:01:19 -04:00
liamwhite
7de778ad39 Merge pull request #10946 from goldenx86/amdBlending
Blacklist EDS3 blending from new AMD drivers
2023-06-29 10:01:11 -04:00
Abandoned Cart
13506e7782 android: Suppress a known incompatibility
Android Gradle plugin 8.0.2 is designed for API 33, but a newer plugin hasn't been released yet. The warning message is rather extravagant, but also suggests adding this property if you are aware of the risks.
2023-06-29 07:32:12 -04:00
german77
ac755476cd input_common: Allow timeouts to happen while scanning for a ring 2023-06-29 01:07:39 -06:00
Matías Locatti
ed93cbd462 Blacklist EDS3 blending from new AMD drivers 2023-06-28 20:10:27 -03:00
german77
df9685a21c input_common: Remove duplicated DriverResult enum 2023-06-28 09:49:47 -06:00
Morph
295fc7d0f8 x64: cpu_wait: Implement MWAITX for non-MSVC compilers 2023-06-28 01:39:15 -04:00
Morph
2b68a3cbbf x64: cpu_wait: Remove magic values 2023-06-28 01:39:06 -04:00
Morph
3d868baaa4 x64: cpu_wait: Make use of MWAITX in MicroSleep
MWAITX is equivalent to UMWAIT on Intel's Alder Lake CPUs.
We can emulate TPAUSE by using MONITORX in conjunction with MWAITX to wait for 100K cycles.
2023-06-28 01:38:55 -04:00
Morph
4303ed614d x64: Add detection of monitorx instructions
monitorx introduces 2 instructions: MONITORX and MWAITX.
2023-06-28 01:36:06 -04:00
31 changed files with 634 additions and 555 deletions

View File

@@ -15,3 +15,6 @@ android.useAndroidX=true
kotlin.code.style=official
kotlin.parallel.tasks.in.project=true
android.defaults.buildfeatures.buildconfig=true
# Android Gradle plugin 8.0.2
android.suppressUnsupportedCompileSdk=34

View File

@@ -75,8 +75,10 @@ enum class DriverResult {
ErrorWritingData,
NoDeviceDetected,
InvalidHandle,
InvalidParameters,
NotSupported,
Disabled,
Delayed,
Unknown,
};

View File

@@ -93,6 +93,7 @@ void AppendCPUInfo(FieldCollection& fc) {
add_field("CPU_Extension_x64_GFNI", caps.gfni);
add_field("CPU_Extension_x64_INVARIANT_TSC", caps.invariant_tsc);
add_field("CPU_Extension_x64_LZCNT", caps.lzcnt);
add_field("CPU_Extension_x64_MONITORX", caps.monitorx);
add_field("CPU_Extension_x64_MOVBE", caps.movbe);
add_field("CPU_Extension_x64_PCLMULQDQ", caps.pclmulqdq);
add_field("CPU_Extension_x64_POPCNT", caps.popcnt);

View File

@@ -168,6 +168,7 @@ static CPUCaps Detect() {
__cpuid(cpu_id, 0x80000001);
caps.lzcnt = Common::Bit<5>(cpu_id[2]);
caps.fma4 = Common::Bit<16>(cpu_id[2]);
caps.monitorx = Common::Bit<29>(cpu_id[2]);
}
if (max_ex_fn >= 0x80000007) {

View File

@@ -63,6 +63,7 @@ struct CPUCaps {
bool gfni : 1;
bool invariant_tsc : 1;
bool lzcnt : 1;
bool monitorx : 1;
bool movbe : 1;
bool pclmulqdq : 1;
bool popcnt : 1;

View File

@@ -13,36 +13,60 @@
namespace Common::X64 {
namespace {
// 100,000 cycles is a reasonable amount of time to wait to save on CPU resources.
// For reference:
// At 1 GHz, 100K cycles is 100us
// At 2 GHz, 100K cycles is 50us
// At 4 GHz, 100K cycles is 25us
constexpr auto PauseCycles = 100'000U;
} // Anonymous namespace
#ifdef _MSC_VER
__forceinline static void TPAUSE() {
// 100,000 cycles is a reasonable amount of time to wait to save on CPU resources.
// For reference:
// At 1 GHz, 100K cycles is 100us
// At 2 GHz, 100K cycles is 50us
// At 4 GHz, 100K cycles is 25us
static constexpr auto PauseCycles = 100'000;
_tpause(0, FencedRDTSC() + PauseCycles);
static constexpr auto RequestC02State = 0U;
_tpause(RequestC02State, FencedRDTSC() + PauseCycles);
}
__forceinline static void MWAITX() {
static constexpr auto EnableWaitTimeFlag = 1U << 1;
static constexpr auto RequestC1State = 0U;
// monitor_var should be aligned to a cache line.
alignas(64) u64 monitor_var{};
_mm_monitorx(&monitor_var, 0, 0);
_mm_mwaitx(EnableWaitTimeFlag, RequestC1State, PauseCycles);
}
#else
static void TPAUSE() {
// 100,000 cycles is a reasonable amount of time to wait to save on CPU resources.
// For reference:
// At 1 GHz, 100K cycles is 100us
// At 2 GHz, 100K cycles is 50us
// At 4 GHz, 100K cycles is 25us
static constexpr auto PauseCycles = 100'000;
static constexpr auto RequestC02State = 0U;
const auto tsc = FencedRDTSC() + PauseCycles;
const auto eax = static_cast<u32>(tsc & 0xFFFFFFFF);
const auto edx = static_cast<u32>(tsc >> 32);
asm volatile("tpause %0" : : "r"(0), "d"(edx), "a"(eax));
asm volatile("tpause %0" : : "r"(RequestC02State), "d"(edx), "a"(eax));
}
static void MWAITX() {
static constexpr auto EnableWaitTimeFlag = 1U << 1;
static constexpr auto RequestC1State = 0U;
// monitor_var should be aligned to a cache line.
alignas(64) u64 monitor_var{};
asm volatile("monitorx" : : "a"(&monitor_var), "c"(0), "d"(0));
asm volatile("mwaitx" : : "a"(RequestC1State), "b"(PauseCycles), "c"(EnableWaitTimeFlag));
}
#endif
void MicroSleep() {
static const bool has_waitpkg = GetCPUCaps().waitpkg;
static const bool has_monitorx = GetCPUCaps().monitorx;
if (has_waitpkg) {
TPAUSE();
} else if (has_monitorx) {
MWAITX();
} else {
std::this_thread::yield();
}

View File

@@ -338,6 +338,15 @@ public:
return m_parent != nullptr;
}
std::span<KSynchronizationObject*> GetSynchronizationObjectBuffer() {
return m_sync_object_buffer.sync_objects;
}
std::span<Handle> GetHandleBuffer() {
return {m_sync_object_buffer.handles.data() + Svc::ArgumentHandleCountMax,
Svc::ArgumentHandleCountMax};
}
u16 GetUserDisableCount() const;
void SetInterruptFlag();
void ClearInterruptFlag();
@@ -855,6 +864,7 @@ private:
u32* m_light_ipc_data{};
KProcessAddress m_tls_address{};
KLightLock m_activity_pause_lock;
SyncObjectBuffer m_sync_object_buffer{};
s64 m_schedule_count{};
s64 m_last_scheduled_tick{};
std::array<QueueEntry, Core::Hardware::NUM_CPU_CORES> m_per_core_priority_queue_entry{};

View File

@@ -38,22 +38,31 @@ Result SendAsyncRequestWithUserBuffer(Core::System& system, Handle* out_event_ha
Result ReplyAndReceive(Core::System& system, s32* out_index, uint64_t handles_addr, s32 num_handles,
Handle reply_target, s64 timeout_ns) {
// Ensure number of handles is valid.
R_UNLESS(0 <= num_handles && num_handles <= ArgumentHandleCountMax, ResultOutOfRange);
// Get the synchronization context.
auto& kernel = system.Kernel();
auto& handle_table = GetCurrentProcess(kernel).GetHandleTable();
auto objs = GetCurrentThread(kernel).GetSynchronizationObjectBuffer();
auto handles = GetCurrentThread(kernel).GetHandleBuffer();
R_UNLESS(0 <= num_handles && num_handles <= ArgumentHandleCountMax, ResultOutOfRange);
R_UNLESS(GetCurrentMemory(kernel).IsValidVirtualAddressRange(
handles_addr, static_cast<u64>(sizeof(Handle) * num_handles)),
ResultInvalidPointer);
// Copy user handles.
if (num_handles > 0) {
// Ensure we can try to get the handles.
R_UNLESS(GetCurrentMemory(kernel).IsValidVirtualAddressRange(
handles_addr, static_cast<u64>(sizeof(Handle) * num_handles)),
ResultInvalidPointer);
std::array<Handle, Svc::ArgumentHandleCountMax> handles;
GetCurrentMemory(kernel).ReadBlock(handles_addr, handles.data(), sizeof(Handle) * num_handles);
// Get the handles.
GetCurrentMemory(kernel).ReadBlock(handles_addr, handles.data(),
sizeof(Handle) * num_handles);
// Convert handle list to object table.
std::array<KSynchronizationObject*, Svc::ArgumentHandleCountMax> objs;
R_UNLESS(handle_table.GetMultipleObjects<KSynchronizationObject>(objs.data(), handles.data(),
num_handles),
ResultInvalidHandle);
// Convert the handles to objects.
R_UNLESS(handle_table.GetMultipleObjects<KSynchronizationObject>(
objs.data(), handles.data(), num_handles),
ResultInvalidHandle);
}
// Ensure handles are closed when we're done.
SCOPE_EXIT({

View File

@@ -47,21 +47,35 @@ Result ResetSignal(Core::System& system, Handle handle) {
R_THROW(ResultInvalidHandle);
}
static Result WaitSynchronization(Core::System& system, int32_t* out_index, const Handle* handles,
int32_t num_handles, int64_t timeout_ns) {
/// Wait for the given handles to synchronize, timeout after the specified nanoseconds
Result WaitSynchronization(Core::System& system, int32_t* out_index, u64 user_handles,
int32_t num_handles, int64_t timeout_ns) {
LOG_TRACE(Kernel_SVC, "called user_handles={:#x}, num_handles={}, timeout_ns={}", user_handles,
num_handles, timeout_ns);
// Ensure number of handles is valid.
R_UNLESS(0 <= num_handles && num_handles <= Svc::ArgumentHandleCountMax, ResultOutOfRange);
// Get the synchronization context.
auto& kernel = system.Kernel();
auto& handle_table = GetCurrentProcess(kernel).GetHandleTable();
std::array<KSynchronizationObject*, Svc::ArgumentHandleCountMax> objs;
auto objs = GetCurrentThread(kernel).GetSynchronizationObjectBuffer();
auto handles = GetCurrentThread(kernel).GetHandleBuffer();
// Copy user handles.
if (num_handles > 0) {
// Ensure we can try to get the handles.
R_UNLESS(GetCurrentMemory(kernel).IsValidVirtualAddressRange(
user_handles, static_cast<u64>(sizeof(Handle) * num_handles)),
ResultInvalidPointer);
// Get the handles.
GetCurrentMemory(kernel).ReadBlock(user_handles, handles.data(),
sizeof(Handle) * num_handles);
// Convert the handles to objects.
R_UNLESS(handle_table.GetMultipleObjects<KSynchronizationObject>(objs.data(), handles,
num_handles),
R_UNLESS(handle_table.GetMultipleObjects<KSynchronizationObject>(
objs.data(), handles.data(), num_handles),
ResultInvalidHandle);
}
@@ -80,23 +94,6 @@ static Result WaitSynchronization(Core::System& system, int32_t* out_index, cons
R_RETURN(res);
}
/// Wait for the given handles to synchronize, timeout after the specified nanoseconds
Result WaitSynchronization(Core::System& system, int32_t* out_index, u64 user_handles,
int32_t num_handles, int64_t timeout_ns) {
LOG_TRACE(Kernel_SVC, "called user_handles={:#x}, num_handles={}, timeout_ns={}", user_handles,
num_handles, timeout_ns);
// Ensure number of handles is valid.
R_UNLESS(0 <= num_handles && num_handles <= Svc::ArgumentHandleCountMax, ResultOutOfRange);
std::array<Handle, Svc::ArgumentHandleCountMax> handles;
if (num_handles > 0) {
GetCurrentMemory(system.Kernel())
.ReadBlock(user_handles, handles.data(), num_handles * sizeof(Handle));
}
R_RETURN(WaitSynchronization(system, out_index, handles.data(), num_handles, timeout_ns));
}
/// Resumes a thread waiting on WaitSynchronization
Result CancelSynchronization(Core::System& system, Handle handle) {
LOG_TRACE(Kernel_SVC, "called handle=0x{:X}", handle);

View File

@@ -102,12 +102,12 @@ bool Joycons::IsDeviceNew(SDL_hid_device_info* device_info) const {
Joycon::SerialNumber serial_number{};
const auto result = Joycon::JoyconDriver::GetDeviceType(device_info, type);
if (result != Joycon::DriverResult::Success) {
if (result != Common::Input::DriverResult::Success) {
return false;
}
const auto result2 = Joycon::JoyconDriver::GetSerialNumber(device_info, serial_number);
if (result2 != Joycon::DriverResult::Success) {
if (result2 != Common::Input::DriverResult::Success) {
return false;
}
@@ -171,10 +171,10 @@ void Joycons::RegisterNewDevice(SDL_hid_device_info* device_info) {
LOG_WARNING(Input, "No free handles available");
return;
}
if (result == Joycon::DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
result = handle->RequestDeviceAccess(device_info);
}
if (result == Joycon::DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
LOG_WARNING(Input, "Initialize device");
const std::size_t port = handle->GetDevicePort();
@@ -273,8 +273,7 @@ Common::Input::DriverResult Joycons::SetLeds(const PadIdentifier& identifier,
led_config += led_status.led_3 ? 4 : 0;
led_config += led_status.led_4 ? 8 : 0;
return static_cast<Common::Input::DriverResult>(
handle->SetLedConfig(static_cast<u8>(led_config)));
return handle->SetLedConfig(static_cast<u8>(led_config));
}
Common::Input::DriverResult Joycons::SetCameraFormat(const PadIdentifier& identifier,
@@ -283,8 +282,8 @@ Common::Input::DriverResult Joycons::SetCameraFormat(const PadIdentifier& identi
if (handle == nullptr) {
return Common::Input::DriverResult::InvalidHandle;
}
return static_cast<Common::Input::DriverResult>(handle->SetIrsConfig(
Joycon::IrsMode::ImageTransfer, static_cast<Joycon::IrsResolution>(camera_format)));
return handle->SetIrsConfig(Joycon::IrsMode::ImageTransfer,
static_cast<Joycon::IrsResolution>(camera_format));
};
Common::Input::NfcState Joycons::SupportsNfc(const PadIdentifier& identifier_) const {
@@ -351,7 +350,7 @@ Common::Input::NfcState Joycons::ReadMifareData(const PadIdentifier& identifier,
std::vector<Joycon::MifareReadData> read_data(read_request.size());
const auto result = handle->ReadMifareData(read_request, read_data);
if (result == Joycon::DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
for (std::size_t i = 0; i < read_request.size(); i++) {
data.data[i] = {
.command = static_cast<u8>(command),
@@ -402,15 +401,15 @@ Common::Input::DriverResult Joycons::SetPollingMode(const PadIdentifier& identif
switch (polling_mode) {
case Common::Input::PollingMode::Active:
return static_cast<Common::Input::DriverResult>(handle->SetActiveMode());
return handle->SetActiveMode();
case Common::Input::PollingMode::Passive:
return static_cast<Common::Input::DriverResult>(handle->SetPassiveMode());
return handle->SetPassiveMode();
case Common::Input::PollingMode::IR:
return static_cast<Common::Input::DriverResult>(handle->SetIrMode());
return handle->SetIrMode();
case Common::Input::PollingMode::NFC:
return static_cast<Common::Input::DriverResult>(handle->SetNfcMode());
return handle->SetNfcMode();
case Common::Input::PollingMode::Ring:
return static_cast<Common::Input::DriverResult>(handle->SetRingConMode());
return handle->SetRingConMode();
default:
return Common::Input::DriverResult::NotSupported;
}
@@ -828,13 +827,13 @@ std::string Joycons::JoyconName(Joycon::ControllerType type) const {
}
}
Common::Input::NfcState Joycons::TranslateDriverResult(Joycon::DriverResult result) const {
Common::Input::NfcState Joycons::TranslateDriverResult(Common::Input::DriverResult result) const {
switch (result) {
case Joycon::DriverResult::Success:
case Common::Input::DriverResult::Success:
return Common::Input::NfcState::Success;
case Joycon::DriverResult::Disabled:
case Common::Input::DriverResult::Disabled:
return Common::Input::NfcState::WrongDeviceState;
case Joycon::DriverResult::NotSupported:
case Common::Input::DriverResult::NotSupported:
return Common::Input::NfcState::NotSupported;
default:
return Common::Input::NfcState::Unknown;

View File

@@ -17,7 +17,6 @@ struct Color;
struct MotionData;
struct TagInfo;
enum class ControllerType : u8;
enum class DriverResult;
enum class IrsResolution;
class JoyconDriver;
} // namespace InputCommon::Joycon
@@ -112,7 +111,7 @@ private:
/// Returns the name of the device in text format
std::string JoyconName(Joycon::ControllerType type) const;
Common::Input::NfcState TranslateDriverResult(Joycon::DriverResult result) const;
Common::Input::NfcState TranslateDriverResult(Common::Input::DriverResult result) const;
std::jthread scan_thread;

View File

@@ -1,6 +1,7 @@
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "common/input.h"
#include "common/logging/log.h"
#include "common/scope_exit.h"
#include "common/swap.h"
@@ -28,13 +29,13 @@ void JoyconDriver::Stop() {
input_thread = {};
}
DriverResult JoyconDriver::RequestDeviceAccess(SDL_hid_device_info* device_info) {
Common::Input::DriverResult JoyconDriver::RequestDeviceAccess(SDL_hid_device_info* device_info) {
std::scoped_lock lock{mutex};
handle_device_type = ControllerType::None;
GetDeviceType(device_info, handle_device_type);
if (handle_device_type == ControllerType::None) {
return DriverResult::UnsupportedControllerType;
return Common::Input::DriverResult::UnsupportedControllerType;
}
hidapi_handle->handle =
@@ -43,15 +44,15 @@ DriverResult JoyconDriver::RequestDeviceAccess(SDL_hid_device_info* device_info)
if (!hidapi_handle->handle) {
LOG_ERROR(Input, "Yuzu can't gain access to this device: ID {:04X}:{:04X}.",
device_info->vendor_id, device_info->product_id);
return DriverResult::HandleInUse;
return Common::Input::DriverResult::HandleInUse;
}
SDL_hid_set_nonblocking(hidapi_handle->handle, 1);
return DriverResult::Success;
return Common::Input::DriverResult::Success;
}
DriverResult JoyconDriver::InitializeDevice() {
Common::Input::DriverResult JoyconDriver::InitializeDevice() {
if (!hidapi_handle->handle) {
return DriverResult::InvalidHandle;
return Common::Input::DriverResult::InvalidHandle;
}
std::scoped_lock lock{mutex};
disable_input_thread = true;
@@ -87,7 +88,7 @@ DriverResult JoyconDriver::InitializeDevice() {
rumble_protocol = std::make_unique<RumbleProtocol>(hidapi_handle);
// Get fixed joycon info
if (generic_protocol->GetVersionNumber(version) != DriverResult::Success) {
if (generic_protocol->GetVersionNumber(version) != Common::Input::DriverResult::Success) {
// If this command fails the device doesn't accept configuration commands
input_only_device = true;
}
@@ -129,7 +130,7 @@ DriverResult JoyconDriver::InitializeDevice() {
}
disable_input_thread = false;
return DriverResult::Success;
return Common::Input::DriverResult::Success;
}
void JoyconDriver::InputThread(std::stop_token stop_token) {
@@ -229,7 +230,7 @@ void JoyconDriver::OnNewData(std::span<u8> buffer) {
if (!amiibo_detected) {
Joycon::TagInfo tag_info;
const auto result = nfc_protocol->GetTagInfo(tag_info);
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
joycon_poller->UpdateAmiibo(tag_info);
amiibo_detected = true;
}
@@ -255,7 +256,7 @@ void JoyconDriver::OnNewData(std::span<u8> buffer) {
}
}
DriverResult JoyconDriver::SetPollingMode() {
Common::Input::DriverResult JoyconDriver::SetPollingMode() {
SCOPE_EXIT({ disable_input_thread = false; });
disable_input_thread = true;
@@ -270,7 +271,7 @@ DriverResult JoyconDriver::SetPollingMode() {
}
if (input_only_device) {
return DriverResult::NotSupported;
return Common::Input::DriverResult::NotSupported;
}
if (irs_protocol->IsEnabled()) {
@@ -289,7 +290,7 @@ DriverResult JoyconDriver::SetPollingMode() {
if (irs_enabled && supported_features.irs) {
auto result = irs_protocol->EnableIrs();
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
return result;
}
irs_protocol->DisableIrs();
@@ -299,7 +300,7 @@ DriverResult JoyconDriver::SetPollingMode() {
if (nfc_enabled && supported_features.nfc) {
auto result = nfc_protocol->EnableNfc();
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
return result;
}
nfc_protocol->DisableNfc();
@@ -309,10 +310,10 @@ DriverResult JoyconDriver::SetPollingMode() {
if (hidbus_enabled && supported_features.hidbus) {
auto result = ring_protocol->EnableRingCon();
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
result = ring_protocol->StartRingconPolling();
}
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
ring_connected = true;
return result;
}
@@ -324,7 +325,7 @@ DriverResult JoyconDriver::SetPollingMode() {
if (passive_enabled && supported_features.passive) {
const auto result = generic_protocol->EnablePassiveMode();
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
return result;
}
LOG_ERROR(Input, "Error enabling passive mode");
@@ -332,7 +333,7 @@ DriverResult JoyconDriver::SetPollingMode() {
// Default Mode
const auto result = generic_protocol->EnableActiveMode();
if (result != DriverResult::Success) {
if (result != Common::Input::DriverResult::Success) {
LOG_ERROR(Input, "Error enabling active mode");
}
// Switch calls this function after enabling active mode
@@ -396,26 +397,26 @@ bool JoyconDriver::IsPayloadCorrect(int status, std::span<const u8> buffer) {
return true;
}
DriverResult JoyconDriver::SetVibration(const VibrationValue& vibration) {
Common::Input::DriverResult JoyconDriver::SetVibration(const VibrationValue& vibration) {
std::scoped_lock lock{mutex};
if (disable_input_thread) {
return DriverResult::HandleInUse;
return Common::Input::DriverResult::HandleInUse;
}
return rumble_protocol->SendVibration(vibration);
}
DriverResult JoyconDriver::SetLedConfig(u8 led_pattern) {
Common::Input::DriverResult JoyconDriver::SetLedConfig(u8 led_pattern) {
std::scoped_lock lock{mutex};
if (disable_input_thread) {
return DriverResult::HandleInUse;
return Common::Input::DriverResult::HandleInUse;
}
return generic_protocol->SetLedPattern(led_pattern);
}
DriverResult JoyconDriver::SetIrsConfig(IrsMode mode_, IrsResolution format_) {
Common::Input::DriverResult JoyconDriver::SetIrsConfig(IrsMode mode_, IrsResolution format_) {
std::scoped_lock lock{mutex};
if (disable_input_thread) {
return DriverResult::HandleInUse;
return Common::Input::DriverResult::HandleInUse;
}
disable_input_thread = true;
const auto result = irs_protocol->SetIrsConfig(mode_, format_);
@@ -423,7 +424,7 @@ DriverResult JoyconDriver::SetIrsConfig(IrsMode mode_, IrsResolution format_) {
return result;
}
DriverResult JoyconDriver::SetPassiveMode() {
Common::Input::DriverResult JoyconDriver::SetPassiveMode() {
std::scoped_lock lock{mutex};
motion_enabled = false;
hidbus_enabled = false;
@@ -433,7 +434,7 @@ DriverResult JoyconDriver::SetPassiveMode() {
return SetPollingMode();
}
DriverResult JoyconDriver::SetActiveMode() {
Common::Input::DriverResult JoyconDriver::SetActiveMode() {
if (is_ring_disabled_by_irs) {
is_ring_disabled_by_irs = false;
SetActiveMode();
@@ -449,11 +450,11 @@ DriverResult JoyconDriver::SetActiveMode() {
return SetPollingMode();
}
DriverResult JoyconDriver::SetIrMode() {
Common::Input::DriverResult JoyconDriver::SetIrMode() {
std::scoped_lock lock{mutex};
if (!supported_features.irs) {
return DriverResult::NotSupported;
return Common::Input::DriverResult::NotSupported;
}
if (ring_connected) {
@@ -468,11 +469,11 @@ DriverResult JoyconDriver::SetIrMode() {
return SetPollingMode();
}
DriverResult JoyconDriver::SetNfcMode() {
Common::Input::DriverResult JoyconDriver::SetNfcMode() {
std::scoped_lock lock{mutex};
if (!supported_features.nfc) {
return DriverResult::NotSupported;
return Common::Input::DriverResult::NotSupported;
}
motion_enabled = true;
@@ -483,11 +484,11 @@ DriverResult JoyconDriver::SetNfcMode() {
return SetPollingMode();
}
DriverResult JoyconDriver::SetRingConMode() {
Common::Input::DriverResult JoyconDriver::SetRingConMode() {
std::scoped_lock lock{mutex};
if (!supported_features.hidbus) {
return DriverResult::NotSupported;
return Common::Input::DriverResult::NotSupported;
}
motion_enabled = true;
@@ -499,20 +500,20 @@ DriverResult JoyconDriver::SetRingConMode() {
const auto result = SetPollingMode();
if (!ring_connected) {
return DriverResult::NoDeviceDetected;
return Common::Input::DriverResult::NoDeviceDetected;
}
return result;
}
DriverResult JoyconDriver::StartNfcPolling() {
Common::Input::DriverResult JoyconDriver::StartNfcPolling() {
std::scoped_lock lock{mutex};
if (!supported_features.nfc) {
return DriverResult::NotSupported;
return Common::Input::DriverResult::NotSupported;
}
if (!nfc_protocol->IsEnabled()) {
return DriverResult::Disabled;
return Common::Input::DriverResult::Disabled;
}
disable_input_thread = true;
@@ -522,14 +523,14 @@ DriverResult JoyconDriver::StartNfcPolling() {
return result;
}
DriverResult JoyconDriver::StopNfcPolling() {
Common::Input::DriverResult JoyconDriver::StopNfcPolling() {
std::scoped_lock lock{mutex};
if (!supported_features.nfc) {
return DriverResult::NotSupported;
return Common::Input::DriverResult::NotSupported;
}
if (!nfc_protocol->IsEnabled()) {
return DriverResult::Disabled;
return Common::Input::DriverResult::Disabled;
}
disable_input_thread = true;
@@ -544,17 +545,17 @@ DriverResult JoyconDriver::StopNfcPolling() {
return result;
}
DriverResult JoyconDriver::ReadAmiiboData(std::vector<u8>& out_data) {
Common::Input::DriverResult JoyconDriver::ReadAmiiboData(std::vector<u8>& out_data) {
std::scoped_lock lock{mutex};
if (!supported_features.nfc) {
return DriverResult::NotSupported;
return Common::Input::DriverResult::NotSupported;
}
if (!nfc_protocol->IsEnabled()) {
return DriverResult::Disabled;
return Common::Input::DriverResult::Disabled;
}
if (!amiibo_detected) {
return DriverResult::ErrorWritingData;
return Common::Input::DriverResult::ErrorWritingData;
}
out_data.resize(0x21C);
@@ -565,17 +566,17 @@ DriverResult JoyconDriver::ReadAmiiboData(std::vector<u8>& out_data) {
return result;
}
DriverResult JoyconDriver::WriteNfcData(std::span<const u8> data) {
Common::Input::DriverResult JoyconDriver::WriteNfcData(std::span<const u8> data) {
std::scoped_lock lock{mutex};
if (!supported_features.nfc) {
return DriverResult::NotSupported;
return Common::Input::DriverResult::NotSupported;
}
if (!nfc_protocol->IsEnabled()) {
return DriverResult::Disabled;
return Common::Input::DriverResult::Disabled;
}
if (!amiibo_detected) {
return DriverResult::ErrorWritingData;
return Common::Input::DriverResult::ErrorWritingData;
}
disable_input_thread = true;
@@ -585,18 +586,18 @@ DriverResult JoyconDriver::WriteNfcData(std::span<const u8> data) {
return result;
}
DriverResult JoyconDriver::ReadMifareData(std::span<const MifareReadChunk> data,
std::span<MifareReadData> out_data) {
Common::Input::DriverResult JoyconDriver::ReadMifareData(std::span<const MifareReadChunk> data,
std::span<MifareReadData> out_data) {
std::scoped_lock lock{mutex};
if (!supported_features.nfc) {
return DriverResult::NotSupported;
return Common::Input::DriverResult::NotSupported;
}
if (!nfc_protocol->IsEnabled()) {
return DriverResult::Disabled;
return Common::Input::DriverResult::Disabled;
}
if (!amiibo_detected) {
return DriverResult::ErrorWritingData;
return Common::Input::DriverResult::ErrorWritingData;
}
disable_input_thread = true;
@@ -606,17 +607,17 @@ DriverResult JoyconDriver::ReadMifareData(std::span<const MifareReadChunk> data,
return result;
}
DriverResult JoyconDriver::WriteMifareData(std::span<const MifareWriteChunk> data) {
Common::Input::DriverResult JoyconDriver::WriteMifareData(std::span<const MifareWriteChunk> data) {
std::scoped_lock lock{mutex};
if (!supported_features.nfc) {
return DriverResult::NotSupported;
return Common::Input::DriverResult::NotSupported;
}
if (!nfc_protocol->IsEnabled()) {
return DriverResult::Disabled;
return Common::Input::DriverResult::Disabled;
}
if (!amiibo_detected) {
return DriverResult::ErrorWritingData;
return Common::Input::DriverResult::ErrorWritingData;
}
disable_input_thread = true;
@@ -675,8 +676,8 @@ void JoyconDriver::SetCallbacks(const JoyconCallbacks& callbacks) {
joycon_poller->SetCallbacks(callbacks);
}
DriverResult JoyconDriver::GetDeviceType(SDL_hid_device_info* device_info,
ControllerType& controller_type) {
Common::Input::DriverResult JoyconDriver::GetDeviceType(SDL_hid_device_info* device_info,
ControllerType& controller_type) {
static constexpr std::array<std::pair<u32, ControllerType>, 6> supported_devices{
std::pair<u32, ControllerType>{0x2006, ControllerType::Left},
{0x2007, ControllerType::Right},
@@ -686,25 +687,25 @@ DriverResult JoyconDriver::GetDeviceType(SDL_hid_device_info* device_info,
controller_type = ControllerType::None;
if (device_info->vendor_id != nintendo_vendor_id) {
return DriverResult::UnsupportedControllerType;
return Common::Input::DriverResult::UnsupportedControllerType;
}
for (const auto& [product_id, type] : supported_devices) {
if (device_info->product_id == static_cast<u16>(product_id)) {
controller_type = type;
return Joycon::DriverResult::Success;
return Common::Input::DriverResult::Success;
}
}
return Joycon::DriverResult::UnsupportedControllerType;
return Common::Input::DriverResult::UnsupportedControllerType;
}
DriverResult JoyconDriver::GetSerialNumber(SDL_hid_device_info* device_info,
SerialNumber& serial_number) {
Common::Input::DriverResult JoyconDriver::GetSerialNumber(SDL_hid_device_info* device_info,
SerialNumber& serial_number) {
if (device_info->serial_number == nullptr) {
return DriverResult::Unknown;
return Common::Input::DriverResult::Unknown;
}
std::memcpy(&serial_number, device_info->serial_number, 15);
return Joycon::DriverResult::Success;
return Common::Input::DriverResult::Success;
}
} // namespace InputCommon::Joycon

View File

@@ -11,6 +11,10 @@
#include "input_common/helpers/joycon_protocol/joycon_types.h"
namespace Common::Input {
enum class DriverResult;
}
namespace InputCommon::Joycon {
class CalibrationProtocol;
class GenericProtocol;
@@ -26,8 +30,8 @@ public:
~JoyconDriver();
DriverResult RequestDeviceAccess(SDL_hid_device_info* device_info);
DriverResult InitializeDevice();
Common::Input::DriverResult RequestDeviceAccess(SDL_hid_device_info* device_info);
Common::Input::DriverResult InitializeDevice();
void Stop();
bool IsConnected() const;
@@ -41,31 +45,31 @@ public:
SerialNumber GetSerialNumber() const;
SerialNumber GetHandleSerialNumber() const;
DriverResult SetVibration(const VibrationValue& vibration);
DriverResult SetLedConfig(u8 led_pattern);
DriverResult SetIrsConfig(IrsMode mode_, IrsResolution format_);
DriverResult SetPassiveMode();
DriverResult SetActiveMode();
DriverResult SetIrMode();
DriverResult SetNfcMode();
DriverResult SetRingConMode();
DriverResult StartNfcPolling();
DriverResult StopNfcPolling();
DriverResult ReadAmiiboData(std::vector<u8>& out_data);
DriverResult WriteNfcData(std::span<const u8> data);
DriverResult ReadMifareData(std::span<const MifareReadChunk> request,
std::span<MifareReadData> out_data);
DriverResult WriteMifareData(std::span<const MifareWriteChunk> request);
Common::Input::DriverResult SetVibration(const VibrationValue& vibration);
Common::Input::DriverResult SetLedConfig(u8 led_pattern);
Common::Input::DriverResult SetIrsConfig(IrsMode mode_, IrsResolution format_);
Common::Input::DriverResult SetPassiveMode();
Common::Input::DriverResult SetActiveMode();
Common::Input::DriverResult SetIrMode();
Common::Input::DriverResult SetNfcMode();
Common::Input::DriverResult SetRingConMode();
Common::Input::DriverResult StartNfcPolling();
Common::Input::DriverResult StopNfcPolling();
Common::Input::DriverResult ReadAmiiboData(std::vector<u8>& out_data);
Common::Input::DriverResult WriteNfcData(std::span<const u8> data);
Common::Input::DriverResult ReadMifareData(std::span<const MifareReadChunk> request,
std::span<MifareReadData> out_data);
Common::Input::DriverResult WriteMifareData(std::span<const MifareWriteChunk> request);
void SetCallbacks(const JoyconCallbacks& callbacks);
// Returns device type from hidapi handle
static DriverResult GetDeviceType(SDL_hid_device_info* device_info,
ControllerType& controller_type);
static Common::Input::DriverResult GetDeviceType(SDL_hid_device_info* device_info,
ControllerType& controller_type);
// Returns serial number from hidapi handle
static DriverResult GetSerialNumber(SDL_hid_device_info* device_info,
SerialNumber& serial_number);
static Common::Input::DriverResult GetSerialNumber(SDL_hid_device_info* device_info,
SerialNumber& serial_number);
private:
struct SupportedFeatures {
@@ -84,7 +88,7 @@ private:
void OnNewData(std::span<u8> buffer);
/// Updates device configuration to enable or disable features
DriverResult SetPollingMode();
Common::Input::DriverResult SetPollingMode();
/// Returns true if input thread is valid and doesn't need to be stopped
bool IsInputThreadValid() const;

View File

@@ -3,6 +3,7 @@
#include <cstring>
#include "common/input.h"
#include "input_common/helpers/joycon_protocol/calibration.h"
#include "input_common/helpers/joycon_protocol/joycon_types.h"
@@ -11,28 +12,29 @@ namespace InputCommon::Joycon {
CalibrationProtocol::CalibrationProtocol(std::shared_ptr<JoyconHandle> handle)
: JoyconCommonProtocol(std::move(handle)) {}
DriverResult CalibrationProtocol::GetLeftJoyStickCalibration(JoyStickCalibration& calibration) {
Common::Input::DriverResult CalibrationProtocol::GetLeftJoyStickCalibration(
JoyStickCalibration& calibration) {
ScopedSetBlocking sb(this);
DriverResult result{DriverResult::Success};
Common::Input::DriverResult result{Common::Input::DriverResult::Success};
JoystickLeftSpiCalibration spi_calibration{};
bool has_user_calibration = false;
calibration = {};
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
result = HasUserCalibration(SpiAddress::USER_LEFT_MAGIC, has_user_calibration);
}
// Read User defined calibration
if (result == DriverResult::Success && has_user_calibration) {
if (result == Common::Input::DriverResult::Success && has_user_calibration) {
result = ReadSPI(SpiAddress::USER_LEFT_DATA, spi_calibration);
}
// Read Factory calibration
if (result == DriverResult::Success && !has_user_calibration) {
if (result == Common::Input::DriverResult::Success && !has_user_calibration) {
result = ReadSPI(SpiAddress::FACT_LEFT_DATA, spi_calibration);
}
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
calibration.x.center = GetXAxisCalibrationValue(spi_calibration.center);
calibration.y.center = GetYAxisCalibrationValue(spi_calibration.center);
calibration.x.min = GetXAxisCalibrationValue(spi_calibration.min);
@@ -47,28 +49,29 @@ DriverResult CalibrationProtocol::GetLeftJoyStickCalibration(JoyStickCalibration
return result;
}
DriverResult CalibrationProtocol::GetRightJoyStickCalibration(JoyStickCalibration& calibration) {
Common::Input::DriverResult CalibrationProtocol::GetRightJoyStickCalibration(
JoyStickCalibration& calibration) {
ScopedSetBlocking sb(this);
DriverResult result{DriverResult::Success};
Common::Input::DriverResult result{Common::Input::DriverResult::Success};
JoystickRightSpiCalibration spi_calibration{};
bool has_user_calibration = false;
calibration = {};
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
result = HasUserCalibration(SpiAddress::USER_RIGHT_MAGIC, has_user_calibration);
}
// Read User defined calibration
if (result == DriverResult::Success && has_user_calibration) {
if (result == Common::Input::DriverResult::Success && has_user_calibration) {
result = ReadSPI(SpiAddress::USER_RIGHT_DATA, spi_calibration);
}
// Read Factory calibration
if (result == DriverResult::Success && !has_user_calibration) {
if (result == Common::Input::DriverResult::Success && !has_user_calibration) {
result = ReadSPI(SpiAddress::FACT_RIGHT_DATA, spi_calibration);
}
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
calibration.x.center = GetXAxisCalibrationValue(spi_calibration.center);
calibration.y.center = GetYAxisCalibrationValue(spi_calibration.center);
calibration.x.min = GetXAxisCalibrationValue(spi_calibration.min);
@@ -83,28 +86,28 @@ DriverResult CalibrationProtocol::GetRightJoyStickCalibration(JoyStickCalibratio
return result;
}
DriverResult CalibrationProtocol::GetImuCalibration(MotionCalibration& calibration) {
Common::Input::DriverResult CalibrationProtocol::GetImuCalibration(MotionCalibration& calibration) {
ScopedSetBlocking sb(this);
DriverResult result{DriverResult::Success};
Common::Input::DriverResult result{Common::Input::DriverResult::Success};
ImuSpiCalibration spi_calibration{};
bool has_user_calibration = false;
calibration = {};
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
result = HasUserCalibration(SpiAddress::USER_IMU_MAGIC, has_user_calibration);
}
// Read User defined calibration
if (result == DriverResult::Success && has_user_calibration) {
if (result == Common::Input::DriverResult::Success && has_user_calibration) {
result = ReadSPI(SpiAddress::USER_IMU_DATA, spi_calibration);
}
// Read Factory calibration
if (result == DriverResult::Success && !has_user_calibration) {
if (result == Common::Input::DriverResult::Success && !has_user_calibration) {
result = ReadSPI(SpiAddress::FACT_IMU_DATA, spi_calibration);
}
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
calibration.accelerometer[0].offset = spi_calibration.accelerometer_offset[0];
calibration.accelerometer[1].offset = spi_calibration.accelerometer_offset[1];
calibration.accelerometer[2].offset = spi_calibration.accelerometer_offset[2];
@@ -127,8 +130,8 @@ DriverResult CalibrationProtocol::GetImuCalibration(MotionCalibration& calibrati
return result;
}
DriverResult CalibrationProtocol::GetRingCalibration(RingCalibration& calibration,
s16 current_value) {
Common::Input::DriverResult CalibrationProtocol::GetRingCalibration(RingCalibration& calibration,
s16 current_value) {
constexpr s16 DefaultRingRange{800};
// TODO: Get default calibration form ring itself
@@ -144,15 +147,15 @@ DriverResult CalibrationProtocol::GetRingCalibration(RingCalibration& calibratio
.max_value = ring_data_max,
.min_value = ring_data_min,
};
return DriverResult::Success;
return Common::Input::DriverResult::Success;
}
DriverResult CalibrationProtocol::HasUserCalibration(SpiAddress address,
bool& has_user_calibration) {
Common::Input::DriverResult CalibrationProtocol::HasUserCalibration(SpiAddress address,
bool& has_user_calibration) {
MagicSpiCalibration spi_magic{};
const DriverResult result{ReadSPI(address, spi_magic)};
const Common::Input::DriverResult result{ReadSPI(address, spi_magic)};
has_user_calibration = false;
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
has_user_calibration = spi_magic.first == CalibrationMagic::USR_MAGIC_0 &&
spi_magic.second == CalibrationMagic::USR_MAGIC_1;
}

View File

@@ -12,8 +12,11 @@
#include "input_common/helpers/joycon_protocol/common_protocol.h"
namespace InputCommon::Joycon {
namespace Common::Input {
enum class DriverResult;
}
namespace InputCommon::Joycon {
struct JoyStickCalibration;
struct IMUCalibration;
struct JoyconHandle;
@@ -31,30 +34,30 @@ public:
* @param is_factory_calibration if true factory values will be returned
* @returns JoyStickCalibration of the left joystick
*/
DriverResult GetLeftJoyStickCalibration(JoyStickCalibration& calibration);
Common::Input::DriverResult GetLeftJoyStickCalibration(JoyStickCalibration& calibration);
/**
* Sends a request to obtain the right stick calibration from memory
* @param is_factory_calibration if true factory values will be returned
* @returns JoyStickCalibration of the right joystick
*/
DriverResult GetRightJoyStickCalibration(JoyStickCalibration& calibration);
Common::Input::DriverResult GetRightJoyStickCalibration(JoyStickCalibration& calibration);
/**
* Sends a request to obtain the motion calibration from memory
* @returns ImuCalibration of the motion sensor
*/
DriverResult GetImuCalibration(MotionCalibration& calibration);
Common::Input::DriverResult GetImuCalibration(MotionCalibration& calibration);
/**
* Calculates on run time the proper calibration of the ring controller
* @returns RingCalibration of the ring sensor
*/
DriverResult GetRingCalibration(RingCalibration& calibration, s16 current_value);
Common::Input::DriverResult GetRingCalibration(RingCalibration& calibration, s16 current_value);
private:
/// Returns true if the specified address corresponds to the magic value of user calibration
DriverResult HasUserCalibration(SpiAddress address, bool& has_user_calibration);
Common::Input::DriverResult HasUserCalibration(SpiAddress address, bool& has_user_calibration);
/// Converts a raw calibration block to an u16 value containing the x axis value
u16 GetXAxisCalibrationValue(std::span<u8> block) const;

View File

@@ -1,6 +1,7 @@
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "common/input.h"
#include "common/logging/log.h"
#include "input_common/helpers/joycon_protocol/common_protocol.h"
@@ -21,10 +22,10 @@ void JoyconCommonProtocol::SetNonBlocking() {
SDL_hid_set_nonblocking(hidapi_handle->handle, 1);
}
DriverResult JoyconCommonProtocol::GetDeviceType(ControllerType& controller_type) {
Common::Input::DriverResult JoyconCommonProtocol::GetDeviceType(ControllerType& controller_type) {
const auto result = ReadSPI(SpiAddress::DEVICE_TYPE, controller_type);
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
// Fallback to 3rd party pro controllers
if (controller_type == ControllerType::None) {
controller_type = ControllerType::Pro;
@@ -34,12 +35,13 @@ DriverResult JoyconCommonProtocol::GetDeviceType(ControllerType& controller_type
return result;
}
DriverResult JoyconCommonProtocol::CheckDeviceAccess(SDL_hid_device_info* device_info) {
Common::Input::DriverResult JoyconCommonProtocol::CheckDeviceAccess(
SDL_hid_device_info* device_info) {
ControllerType controller_type{ControllerType::None};
const auto result = GetDeviceType(controller_type);
if (result != DriverResult::Success || controller_type == ControllerType::None) {
return DriverResult::UnsupportedControllerType;
if (result != Common::Input::DriverResult::Success || controller_type == ControllerType::None) {
return Common::Input::DriverResult::UnsupportedControllerType;
}
hidapi_handle->handle =
@@ -48,32 +50,32 @@ DriverResult JoyconCommonProtocol::CheckDeviceAccess(SDL_hid_device_info* device
if (!hidapi_handle->handle) {
LOG_ERROR(Input, "Yuzu can't gain access to this device: ID {:04X}:{:04X}.",
device_info->vendor_id, device_info->product_id);
return DriverResult::HandleInUse;
return Common::Input::DriverResult::HandleInUse;
}
SetNonBlocking();
return DriverResult::Success;
return Common::Input::DriverResult::Success;
}
DriverResult JoyconCommonProtocol::SetReportMode(ReportMode report_mode) {
Common::Input::DriverResult JoyconCommonProtocol::SetReportMode(ReportMode report_mode) {
const std::array<u8, 1> buffer{static_cast<u8>(report_mode)};
return SendSubCommand(SubCommand::SET_REPORT_MODE, buffer);
}
DriverResult JoyconCommonProtocol::SendRawData(std::span<const u8> buffer) {
Common::Input::DriverResult JoyconCommonProtocol::SendRawData(std::span<const u8> buffer) {
const auto result = SDL_hid_write(hidapi_handle->handle, buffer.data(), buffer.size());
if (result == -1) {
return DriverResult::ErrorWritingData;
return Common::Input::DriverResult::ErrorWritingData;
}
return DriverResult::Success;
return Common::Input::DriverResult::Success;
}
DriverResult JoyconCommonProtocol::GetSubCommandResponse(SubCommand sc,
SubCommandResponse& output) {
Common::Input::DriverResult JoyconCommonProtocol::GetSubCommandResponse(
SubCommand sc, SubCommandResponse& output) {
constexpr int timeout_mili = 66;
constexpr int MaxTries = 3;
constexpr int MaxTries = 10;
int tries = 0;
do {
@@ -84,16 +86,17 @@ DriverResult JoyconCommonProtocol::GetSubCommandResponse(SubCommand sc,
LOG_ERROR(Input, "No response from joycon");
}
if (tries++ > MaxTries) {
return DriverResult::Timeout;
return Common::Input::DriverResult::Timeout;
}
} while (output.input_report.report_mode != ReportMode::SUBCMD_REPLY &&
output.sub_command != sc);
return DriverResult::Success;
return Common::Input::DriverResult::Success;
}
DriverResult JoyconCommonProtocol::SendSubCommand(SubCommand sc, std::span<const u8> buffer,
SubCommandResponse& output) {
Common::Input::DriverResult JoyconCommonProtocol::SendSubCommand(SubCommand sc,
std::span<const u8> buffer,
SubCommandResponse& output) {
SubCommandPacket packet{
.output_report = OutputReport::RUMBLE_AND_SUBCMD,
.packet_counter = GetCounter(),
@@ -102,26 +105,28 @@ DriverResult JoyconCommonProtocol::SendSubCommand(SubCommand sc, std::span<const
};
if (buffer.size() > packet.command_data.size()) {
return DriverResult::InvalidParameters;
return Common::Input::DriverResult::InvalidParameters;
}
memcpy(packet.command_data.data(), buffer.data(), buffer.size());
auto result = SendData(packet);
if (result != DriverResult::Success) {
if (result != Common::Input::DriverResult::Success) {
return result;
}
return GetSubCommandResponse(sc, output);
}
DriverResult JoyconCommonProtocol::SendSubCommand(SubCommand sc, std::span<const u8> buffer) {
Common::Input::DriverResult JoyconCommonProtocol::SendSubCommand(SubCommand sc,
std::span<const u8> buffer) {
SubCommandResponse output{};
return SendSubCommand(sc, buffer, output);
}
DriverResult JoyconCommonProtocol::SendMCUCommand(SubCommand sc, std::span<const u8> buffer) {
Common::Input::DriverResult JoyconCommonProtocol::SendMCUCommand(SubCommand sc,
std::span<const u8> buffer) {
SubCommandPacket packet{
.output_report = OutputReport::MCU_DATA,
.packet_counter = GetCounter(),
@@ -130,7 +135,7 @@ DriverResult JoyconCommonProtocol::SendMCUCommand(SubCommand sc, std::span<const
};
if (buffer.size() > packet.command_data.size()) {
return DriverResult::InvalidParameters;
return Common::Input::DriverResult::InvalidParameters;
}
memcpy(packet.command_data.data(), buffer.data(), buffer.size());
@@ -138,7 +143,7 @@ DriverResult JoyconCommonProtocol::SendMCUCommand(SubCommand sc, std::span<const
return SendData(packet);
}
DriverResult JoyconCommonProtocol::SendVibrationReport(std::span<const u8> buffer) {
Common::Input::DriverResult JoyconCommonProtocol::SendVibrationReport(std::span<const u8> buffer) {
VibrationPacket packet{
.output_report = OutputReport::RUMBLE_ONLY,
.packet_counter = GetCounter(),
@@ -146,7 +151,7 @@ DriverResult JoyconCommonProtocol::SendVibrationReport(std::span<const u8> buffe
};
if (buffer.size() > packet.vibration_data.size()) {
return DriverResult::InvalidParameters;
return Common::Input::DriverResult::InvalidParameters;
}
memcpy(packet.vibration_data.data(), buffer.data(), buffer.size());
@@ -154,7 +159,8 @@ DriverResult JoyconCommonProtocol::SendVibrationReport(std::span<const u8> buffe
return SendData(packet);
}
DriverResult JoyconCommonProtocol::ReadRawSPI(SpiAddress addr, std::span<u8> output) {
Common::Input::DriverResult JoyconCommonProtocol::ReadRawSPI(SpiAddress addr,
std::span<u8> output) {
constexpr std::size_t HeaderSize = 5;
constexpr std::size_t MaxTries = 5;
std::size_t tries = 0;
@@ -168,36 +174,36 @@ DriverResult JoyconCommonProtocol::ReadRawSPI(SpiAddress addr, std::span<u8> out
memcpy(buffer.data(), &packet_data, sizeof(ReadSpiPacket));
do {
const auto result = SendSubCommand(SubCommand::SPI_FLASH_READ, buffer, response);
if (result != DriverResult::Success) {
if (result != Common::Input::DriverResult::Success) {
return result;
}
if (tries++ > MaxTries) {
return DriverResult::Timeout;
return Common::Input::DriverResult::Timeout;
}
} while (response.spi_address != addr);
if (response.command_data.size() < packet_data.size + HeaderSize) {
return DriverResult::WrongReply;
return Common::Input::DriverResult::WrongReply;
}
// Remove header from output
memcpy(output.data(), response.command_data.data() + HeaderSize, packet_data.size);
return DriverResult::Success;
return Common::Input::DriverResult::Success;
}
DriverResult JoyconCommonProtocol::EnableMCU(bool enable) {
Common::Input::DriverResult JoyconCommonProtocol::EnableMCU(bool enable) {
const std::array<u8, 1> mcu_state{static_cast<u8>(enable ? 1 : 0)};
const auto result = SendSubCommand(SubCommand::SET_MCU_STATE, mcu_state);
if (result != DriverResult::Success) {
if (result != Common::Input::DriverResult::Success) {
LOG_ERROR(Input, "Failed with error {}", result);
}
return result;
}
DriverResult JoyconCommonProtocol::ConfigureMCU(const MCUConfig& config) {
Common::Input::DriverResult JoyconCommonProtocol::ConfigureMCU(const MCUConfig& config) {
LOG_DEBUG(Input, "ConfigureMCU");
std::array<u8, sizeof(MCUConfig)> config_buffer;
memcpy(config_buffer.data(), &config, sizeof(MCUConfig));
@@ -205,15 +211,15 @@ DriverResult JoyconCommonProtocol::ConfigureMCU(const MCUConfig& config) {
const auto result = SendSubCommand(SubCommand::SET_MCU_CONFIG, config_buffer);
if (result != DriverResult::Success) {
if (result != Common::Input::DriverResult::Success) {
LOG_ERROR(Input, "Failed with error {}", result);
}
return result;
}
DriverResult JoyconCommonProtocol::GetMCUDataResponse(ReportMode report_mode,
MCUCommandResponse& output) {
Common::Input::DriverResult JoyconCommonProtocol::GetMCUDataResponse(ReportMode report_mode,
MCUCommandResponse& output) {
constexpr int TimeoutMili = 200;
constexpr int MaxTries = 9;
int tries = 0;
@@ -226,17 +232,18 @@ DriverResult JoyconCommonProtocol::GetMCUDataResponse(ReportMode report_mode,
LOG_ERROR(Input, "No response from joycon attempt {}", tries);
}
if (tries++ > MaxTries) {
return DriverResult::Timeout;
return Common::Input::DriverResult::Timeout;
}
} while (output.input_report.report_mode != report_mode ||
output.mcu_report == MCUReport::EmptyAwaitingCmd);
return DriverResult::Success;
return Common::Input::DriverResult::Success;
}
DriverResult JoyconCommonProtocol::SendMCUData(ReportMode report_mode, MCUSubCommand sc,
std::span<const u8> buffer,
MCUCommandResponse& output) {
Common::Input::DriverResult JoyconCommonProtocol::SendMCUData(ReportMode report_mode,
MCUSubCommand sc,
std::span<const u8> buffer,
MCUCommandResponse& output) {
SubCommandPacket packet{
.output_report = OutputReport::MCU_DATA,
.packet_counter = GetCounter(),
@@ -245,23 +252,24 @@ DriverResult JoyconCommonProtocol::SendMCUData(ReportMode report_mode, MCUSubCom
};
if (buffer.size() > packet.command_data.size()) {
return DriverResult::InvalidParameters;
return Common::Input::DriverResult::InvalidParameters;
}
memcpy(packet.command_data.data(), buffer.data(), buffer.size());
auto result = SendData(packet);
if (result != DriverResult::Success) {
if (result != Common::Input::DriverResult::Success) {
return result;
}
result = GetMCUDataResponse(report_mode, output);
return DriverResult::Success;
return Common::Input::DriverResult::Success;
}
DriverResult JoyconCommonProtocol::WaitSetMCUMode(ReportMode report_mode, MCUMode mode) {
Common::Input::DriverResult JoyconCommonProtocol::WaitSetMCUMode(ReportMode report_mode,
MCUMode mode) {
MCUCommandResponse output{};
constexpr std::size_t MaxTries{16};
std::size_t tries{};
@@ -269,17 +277,17 @@ DriverResult JoyconCommonProtocol::WaitSetMCUMode(ReportMode report_mode, MCUMod
do {
const auto result = SendMCUData(report_mode, MCUSubCommand::SetDeviceMode, {}, output);
if (result != DriverResult::Success) {
if (result != Common::Input::DriverResult::Success) {
return result;
}
if (tries++ > MaxTries) {
return DriverResult::WrongReply;
return Common::Input::DriverResult::WrongReply;
}
} while (output.mcu_report != MCUReport::StateReport ||
output.mcu_data[6] != static_cast<u8>(mode));
return DriverResult::Success;
return Common::Input::DriverResult::Success;
}
// crc-8-ccitt / polynomial 0x07 look up table

View File

@@ -38,30 +38,30 @@ public:
* Sends a request to obtain the joycon type from device
* @returns controller type of the joycon
*/
DriverResult GetDeviceType(ControllerType& controller_type);
Common::Input::DriverResult GetDeviceType(ControllerType& controller_type);
/**
* Verifies and sets the joycon_handle if device is valid
* @param device info from the driver
* @returns success if the device is valid
*/
DriverResult CheckDeviceAccess(SDL_hid_device_info* device);
Common::Input::DriverResult CheckDeviceAccess(SDL_hid_device_info* device);
/**
* Sends a request to set the polling mode of the joycon
* @param report_mode polling mode to be set
*/
DriverResult SetReportMode(Joycon::ReportMode report_mode);
Common::Input::DriverResult SetReportMode(Joycon::ReportMode report_mode);
/**
* Sends data to the joycon device
* @param buffer data to be send
*/
DriverResult SendRawData(std::span<const u8> buffer);
Common::Input::DriverResult SendRawData(std::span<const u8> buffer);
template <typename Output>
requires std::is_trivially_copyable_v<Output>
DriverResult SendData(const Output& output) {
Common::Input::DriverResult SendData(const Output& output) {
std::array<u8, sizeof(Output)> buffer;
std::memcpy(buffer.data(), &output, sizeof(Output));
return SendRawData(buffer);
@@ -72,7 +72,8 @@ public:
* @param sub_command type of data to be returned
* @returns a buffer containing the response
*/
DriverResult GetSubCommandResponse(SubCommand sub_command, SubCommandResponse& output);
Common::Input::DriverResult GetSubCommandResponse(SubCommand sub_command,
SubCommandResponse& output);
/**
* Sends a sub command to the device and waits for it's reply
@@ -80,35 +81,35 @@ public:
* @param buffer data to be send
* @returns output buffer containing the response
*/
DriverResult SendSubCommand(SubCommand sc, std::span<const u8> buffer,
SubCommandResponse& output);
Common::Input::DriverResult SendSubCommand(SubCommand sc, std::span<const u8> buffer,
SubCommandResponse& output);
/**
* Sends a sub command to the device and waits for it's reply and ignores the output
* @param sc sub command to be send
* @param buffer data to be send
*/
DriverResult SendSubCommand(SubCommand sc, std::span<const u8> buffer);
Common::Input::DriverResult SendSubCommand(SubCommand sc, std::span<const u8> buffer);
/**
* Sends a mcu command to the device
* @param sc sub command to be send
* @param buffer data to be send
*/
DriverResult SendMCUCommand(SubCommand sc, std::span<const u8> buffer);
Common::Input::DriverResult SendMCUCommand(SubCommand sc, std::span<const u8> buffer);
/**
* Sends vibration data to the joycon
* @param buffer data to be send
*/
DriverResult SendVibrationReport(std::span<const u8> buffer);
Common::Input::DriverResult SendVibrationReport(std::span<const u8> buffer);
/**
* Reads the SPI memory stored on the joycon
* @param Initial address location
* @returns output buffer containing the response
*/
DriverResult ReadRawSPI(SpiAddress addr, std::span<u8> output);
Common::Input::DriverResult ReadRawSPI(SpiAddress addr, std::span<u8> output);
/**
* Reads the SPI memory stored on the joycon
@@ -117,37 +118,38 @@ public:
*/
template <typename Output>
requires std::is_trivially_copyable_v<Output>
DriverResult ReadSPI(SpiAddress addr, Output& output) {
Common::Input::DriverResult ReadSPI(SpiAddress addr, Output& output) {
std::array<u8, sizeof(Output)> buffer;
output = {};
const auto result = ReadRawSPI(addr, buffer);
if (result != DriverResult::Success) {
if (result != Common::Input::DriverResult::Success) {
return result;
}
std::memcpy(&output, buffer.data(), sizeof(Output));
return DriverResult::Success;
return Common::Input::DriverResult::Success;
}
/**
* Enables MCU chip on the joycon
* @param enable if true the chip will be enabled
*/
DriverResult EnableMCU(bool enable);
Common::Input::DriverResult EnableMCU(bool enable);
/**
* Configures the MCU to the corresponding mode
* @param MCUConfig configuration
*/
DriverResult ConfigureMCU(const MCUConfig& config);
Common::Input::DriverResult ConfigureMCU(const MCUConfig& config);
/**
* Waits until there's MCU data available. On timeout returns error
* @param report mode of the expected reply
* @returns a buffer containing the response
*/
DriverResult GetMCUDataResponse(ReportMode report_mode_, MCUCommandResponse& output);
Common::Input::DriverResult GetMCUDataResponse(ReportMode report_mode_,
MCUCommandResponse& output);
/**
* Sends data to the MCU chip and waits for it's reply
@@ -156,15 +158,15 @@ public:
* @param buffer data to be send
* @returns output buffer containing the response
*/
DriverResult SendMCUData(ReportMode report_mode, MCUSubCommand sc, std::span<const u8> buffer,
MCUCommandResponse& output);
Common::Input::DriverResult SendMCUData(ReportMode report_mode, MCUSubCommand sc,
std::span<const u8> buffer, MCUCommandResponse& output);
/**
* Wait's until the MCU chip is on the specified mode
* @param report mode of the expected reply
* @param MCUMode configuration
*/
DriverResult WaitSetMCUMode(ReportMode report_mode, MCUMode mode);
Common::Input::DriverResult WaitSetMCUMode(ReportMode report_mode, MCUMode mode);
/**
* Calculates the checksum from the MCU data

View File

@@ -1,6 +1,7 @@
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "common/input.h"
#include "common/logging/log.h"
#include "input_common/helpers/joycon_protocol/generic_functions.h"
@@ -9,73 +10,74 @@ namespace InputCommon::Joycon {
GenericProtocol::GenericProtocol(std::shared_ptr<JoyconHandle> handle)
: JoyconCommonProtocol(std::move(handle)) {}
DriverResult GenericProtocol::EnablePassiveMode() {
Common::Input::DriverResult GenericProtocol::EnablePassiveMode() {
ScopedSetBlocking sb(this);
return SetReportMode(ReportMode::SIMPLE_HID_MODE);
}
DriverResult GenericProtocol::EnableActiveMode() {
Common::Input::DriverResult GenericProtocol::EnableActiveMode() {
ScopedSetBlocking sb(this);
return SetReportMode(ReportMode::STANDARD_FULL_60HZ);
}
DriverResult GenericProtocol::SetLowPowerMode(bool enable) {
Common::Input::DriverResult GenericProtocol::SetLowPowerMode(bool enable) {
ScopedSetBlocking sb(this);
const std::array<u8, 1> buffer{static_cast<u8>(enable ? 1 : 0)};
return SendSubCommand(SubCommand::LOW_POWER_MODE, buffer);
}
DriverResult GenericProtocol::TriggersElapsed() {
Common::Input::DriverResult GenericProtocol::TriggersElapsed() {
ScopedSetBlocking sb(this);
return SendSubCommand(SubCommand::TRIGGERS_ELAPSED, {});
}
DriverResult GenericProtocol::GetDeviceInfo(DeviceInfo& device_info) {
Common::Input::DriverResult GenericProtocol::GetDeviceInfo(DeviceInfo& device_info) {
ScopedSetBlocking sb(this);
SubCommandResponse output{};
const auto result = SendSubCommand(SubCommand::REQ_DEV_INFO, {}, output);
device_info = {};
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
device_info = output.device_info;
}
return result;
}
DriverResult GenericProtocol::GetControllerType(ControllerType& controller_type) {
Common::Input::DriverResult GenericProtocol::GetControllerType(ControllerType& controller_type) {
return GetDeviceType(controller_type);
}
DriverResult GenericProtocol::EnableImu(bool enable) {
Common::Input::DriverResult GenericProtocol::EnableImu(bool enable) {
ScopedSetBlocking sb(this);
const std::array<u8, 1> buffer{static_cast<u8>(enable ? 1 : 0)};
return SendSubCommand(SubCommand::ENABLE_IMU, buffer);
}
DriverResult GenericProtocol::SetImuConfig(GyroSensitivity gsen, GyroPerformance gfrec,
AccelerometerSensitivity asen,
AccelerometerPerformance afrec) {
Common::Input::DriverResult GenericProtocol::SetImuConfig(GyroSensitivity gsen,
GyroPerformance gfrec,
AccelerometerSensitivity asen,
AccelerometerPerformance afrec) {
ScopedSetBlocking sb(this);
const std::array<u8, 4> buffer{static_cast<u8>(gsen), static_cast<u8>(asen),
static_cast<u8>(gfrec), static_cast<u8>(afrec)};
return SendSubCommand(SubCommand::SET_IMU_SENSITIVITY, buffer);
}
DriverResult GenericProtocol::GetBattery(u32& battery_level) {
Common::Input::DriverResult GenericProtocol::GetBattery(u32& battery_level) {
// This function is meant to request the high resolution battery status
battery_level = 0;
return DriverResult::NotSupported;
return Common::Input::DriverResult::NotSupported;
}
DriverResult GenericProtocol::GetColor(Color& color) {
Common::Input::DriverResult GenericProtocol::GetColor(Color& color) {
ScopedSetBlocking sb(this);
std::array<u8, 12> buffer{};
const auto result = ReadRawSPI(SpiAddress::COLOR_DATA, buffer);
color = {};
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
color.body = static_cast<u32>((buffer[0] << 16) | (buffer[1] << 8) | buffer[2]);
color.buttons = static_cast<u32>((buffer[3] << 16) | (buffer[4] << 8) | buffer[5]);
color.left_grip = static_cast<u32>((buffer[6] << 16) | (buffer[7] << 8) | buffer[8]);
@@ -85,26 +87,26 @@ DriverResult GenericProtocol::GetColor(Color& color) {
return result;
}
DriverResult GenericProtocol::GetSerialNumber(SerialNumber& serial_number) {
Common::Input::DriverResult GenericProtocol::GetSerialNumber(SerialNumber& serial_number) {
ScopedSetBlocking sb(this);
std::array<u8, 16> buffer{};
const auto result = ReadRawSPI(SpiAddress::SERIAL_NUMBER, buffer);
serial_number = {};
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
memcpy(serial_number.data(), buffer.data() + 1, sizeof(SerialNumber));
}
return result;
}
DriverResult GenericProtocol::GetTemperature(u32& temperature) {
Common::Input::DriverResult GenericProtocol::GetTemperature(u32& temperature) {
// Not all devices have temperature sensor
temperature = 25;
return DriverResult::NotSupported;
return Common::Input::DriverResult::NotSupported;
}
DriverResult GenericProtocol::GetVersionNumber(FirmwareVersion& version) {
Common::Input::DriverResult GenericProtocol::GetVersionNumber(FirmwareVersion& version) {
DeviceInfo device_info{};
const auto result = GetDeviceInfo(device_info);
@@ -113,23 +115,23 @@ DriverResult GenericProtocol::GetVersionNumber(FirmwareVersion& version) {
return result;
}
DriverResult GenericProtocol::SetHomeLight() {
Common::Input::DriverResult GenericProtocol::SetHomeLight() {
ScopedSetBlocking sb(this);
static constexpr std::array<u8, 3> buffer{0x0f, 0xf0, 0x00};
return SendSubCommand(SubCommand::SET_HOME_LIGHT, buffer);
}
DriverResult GenericProtocol::SetLedBusy() {
return DriverResult::NotSupported;
Common::Input::DriverResult GenericProtocol::SetLedBusy() {
return Common::Input::DriverResult::NotSupported;
}
DriverResult GenericProtocol::SetLedPattern(u8 leds) {
Common::Input::DriverResult GenericProtocol::SetLedPattern(u8 leds) {
ScopedSetBlocking sb(this);
const std::array<u8, 1> buffer{leds};
return SendSubCommand(SubCommand::SET_PLAYER_LIGHTS, buffer);
}
DriverResult GenericProtocol::SetLedBlinkPattern(u8 leds) {
Common::Input::DriverResult GenericProtocol::SetLedBlinkPattern(u8 leds) {
return SetLedPattern(static_cast<u8>(leds << 4));
}

View File

@@ -11,6 +11,10 @@
#include "input_common/helpers/joycon_protocol/common_protocol.h"
#include "input_common/helpers/joycon_protocol/joycon_types.h"
namespace Common::Input {
enum class DriverResult;
}
namespace InputCommon::Joycon {
/// Joycon driver functions that easily implemented
@@ -20,34 +24,34 @@ public:
/// Enables passive mode. This mode only sends button data on change. Sticks will return digital
/// data instead of analog. Motion will be disabled
DriverResult EnablePassiveMode();
Common::Input::DriverResult EnablePassiveMode();
/// Enables active mode. This mode will return the current status every 5-15ms
DriverResult EnableActiveMode();
Common::Input::DriverResult EnableActiveMode();
/// Enables or disables the low power mode
DriverResult SetLowPowerMode(bool enable);
Common::Input::DriverResult SetLowPowerMode(bool enable);
/// Unknown function used by the switch
DriverResult TriggersElapsed();
Common::Input::DriverResult TriggersElapsed();
/**
* Sends a request to obtain the joycon firmware and mac from handle
* @returns controller device info
*/
DriverResult GetDeviceInfo(DeviceInfo& controller_type);
Common::Input::DriverResult GetDeviceInfo(DeviceInfo& controller_type);
/**
* Sends a request to obtain the joycon type from handle
* @returns controller type of the joycon
*/
DriverResult GetControllerType(ControllerType& controller_type);
Common::Input::DriverResult GetControllerType(ControllerType& controller_type);
/**
* Enables motion input
* @param enable if true motion data will be enabled
*/
DriverResult EnableImu(bool enable);
Common::Input::DriverResult EnableImu(bool enable);
/**
* Configures the motion sensor with the specified parameters
@@ -56,59 +60,60 @@ public:
* @param asen accelerometer sensitivity in G force
* @param afrec accelerometer frequency in hertz
*/
DriverResult SetImuConfig(GyroSensitivity gsen, GyroPerformance gfrec,
AccelerometerSensitivity asen, AccelerometerPerformance afrec);
Common::Input::DriverResult SetImuConfig(GyroSensitivity gsen, GyroPerformance gfrec,
AccelerometerSensitivity asen,
AccelerometerPerformance afrec);
/**
* Request battery level from the device
* @returns battery level
*/
DriverResult GetBattery(u32& battery_level);
Common::Input::DriverResult GetBattery(u32& battery_level);
/**
* Request joycon colors from the device
* @returns colors of the body and buttons
*/
DriverResult GetColor(Color& color);
Common::Input::DriverResult GetColor(Color& color);
/**
* Request joycon serial number from the device
* @returns 16 byte serial number
*/
DriverResult GetSerialNumber(SerialNumber& serial_number);
Common::Input::DriverResult GetSerialNumber(SerialNumber& serial_number);
/**
* Request joycon serial number from the device
* @returns 16 byte serial number
*/
DriverResult GetTemperature(u32& temperature);
Common::Input::DriverResult GetTemperature(u32& temperature);
/**
* Request joycon serial number from the device
* @returns 16 byte serial number
*/
DriverResult GetVersionNumber(FirmwareVersion& version);
Common::Input::DriverResult GetVersionNumber(FirmwareVersion& version);
/**
* Sets home led behaviour
*/
DriverResult SetHomeLight();
Common::Input::DriverResult SetHomeLight();
/**
* Sets home led into a slow breathing state
*/
DriverResult SetLedBusy();
Common::Input::DriverResult SetLedBusy();
/**
* Sets the 4 player leds on the joycon on a solid state
* @params bit flag containing the led state
*/
DriverResult SetLedPattern(u8 leds);
Common::Input::DriverResult SetLedPattern(u8 leds);
/**
* Sets the 4 player leds on the joycon on a blinking state
* @returns bit flag containing the led state
*/
DriverResult SetLedBlinkPattern(u8 leds);
Common::Input::DriverResult SetLedBlinkPattern(u8 leds);
};
} // namespace InputCommon::Joycon

View File

@@ -1,7 +1,7 @@
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include <thread>
#include "common/input.h"
#include "common/logging/log.h"
#include "input_common/helpers/joycon_protocol/irs.h"
@@ -10,21 +10,21 @@ namespace InputCommon::Joycon {
IrsProtocol::IrsProtocol(std::shared_ptr<JoyconHandle> handle)
: JoyconCommonProtocol(std::move(handle)) {}
DriverResult IrsProtocol::EnableIrs() {
Common::Input::DriverResult IrsProtocol::EnableIrs() {
LOG_INFO(Input, "Enable IRS");
ScopedSetBlocking sb(this);
DriverResult result{DriverResult::Success};
Common::Input::DriverResult result{Common::Input::DriverResult::Success};
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
result = SetReportMode(ReportMode::NFC_IR_MODE_60HZ);
}
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
result = EnableMCU(true);
}
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
result = WaitSetMCUMode(ReportMode::NFC_IR_MODE_60HZ, MCUMode::Standby);
}
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
const MCUConfig config{
.command = MCUCommand::ConfigureMCU,
.sub_command = MCUSubCommand::SetMCUMode,
@@ -34,16 +34,16 @@ DriverResult IrsProtocol::EnableIrs() {
result = ConfigureMCU(config);
}
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
result = WaitSetMCUMode(ReportMode::NFC_IR_MODE_60HZ, MCUMode::IR);
}
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
result = ConfigureIrs();
}
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
result = WriteRegistersStep1();
}
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
result = WriteRegistersStep2();
}
@@ -52,12 +52,12 @@ DriverResult IrsProtocol::EnableIrs() {
return result;
}
DriverResult IrsProtocol::DisableIrs() {
Common::Input::DriverResult IrsProtocol::DisableIrs() {
LOG_DEBUG(Input, "Disable IRS");
ScopedSetBlocking sb(this);
DriverResult result{DriverResult::Success};
Common::Input::DriverResult result{Common::Input::DriverResult::Success};
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
result = EnableMCU(false);
}
@@ -66,7 +66,7 @@ DriverResult IrsProtocol::DisableIrs() {
return result;
}
DriverResult IrsProtocol::SetIrsConfig(IrsMode mode, IrsResolution format) {
Common::Input::DriverResult IrsProtocol::SetIrsConfig(IrsMode mode, IrsResolution format) {
irs_mode = mode;
switch (format) {
case IrsResolution::Size320x240:
@@ -103,10 +103,10 @@ DriverResult IrsProtocol::SetIrsConfig(IrsMode mode, IrsResolution format) {
return EnableIrs();
}
return DriverResult::Success;
return Common::Input::DriverResult::Success;
}
DriverResult IrsProtocol::RequestImage(std::span<u8> buffer) {
Common::Input::DriverResult IrsProtocol::RequestImage(std::span<u8> buffer) {
const u8 next_packet_fragment =
static_cast<u8>((packet_fragment + 1) % (static_cast<u8>(fragments) + 1));
@@ -129,7 +129,7 @@ DriverResult IrsProtocol::RequestImage(std::span<u8> buffer) {
return RequestFrame(packet_fragment);
}
DriverResult IrsProtocol::ConfigureIrs() {
Common::Input::DriverResult IrsProtocol::ConfigureIrs() {
LOG_DEBUG(Input, "Configure IRS");
constexpr std::size_t max_tries = 28;
SubCommandResponse output{};
@@ -152,20 +152,20 @@ DriverResult IrsProtocol::ConfigureIrs() {
do {
const auto result = SendSubCommand(SubCommand::SET_MCU_CONFIG, request_data, output);
if (result != DriverResult::Success) {
if (result != Common::Input::DriverResult::Success) {
return result;
}
if (tries++ >= max_tries) {
return DriverResult::WrongReply;
return Common::Input::DriverResult::WrongReply;
}
} while (output.command_data[0] != 0x0b);
return DriverResult::Success;
return Common::Input::DriverResult::Success;
}
DriverResult IrsProtocol::WriteRegistersStep1() {
Common::Input::DriverResult IrsProtocol::WriteRegistersStep1() {
LOG_DEBUG(Input, "WriteRegistersStep1");
DriverResult result{DriverResult::Success};
Common::Input::DriverResult result{Common::Input::DriverResult::Success};
constexpr std::size_t max_tries = 28;
SubCommandResponse output{};
std::size_t tries = 0;
@@ -197,7 +197,7 @@ DriverResult IrsProtocol::WriteRegistersStep1() {
mcu_request[36] = CalculateMCU_CRC8(mcu_request.data(), 36);
mcu_request[37] = 0xFF;
if (result != DriverResult::Success) {
if (result != Common::Input::DriverResult::Success) {
return result;
}
@@ -205,26 +205,26 @@ DriverResult IrsProtocol::WriteRegistersStep1() {
result = SendSubCommand(SubCommand::SET_MCU_CONFIG, request_data, output);
// First time we need to set the report mode
if (result == DriverResult::Success && tries == 0) {
if (result == Common::Input::DriverResult::Success && tries == 0) {
result = SendMCUCommand(SubCommand::SET_REPORT_MODE, mcu_request);
}
if (result == DriverResult::Success && tries == 0) {
if (result == Common::Input::DriverResult::Success && tries == 0) {
GetSubCommandResponse(SubCommand::SET_MCU_CONFIG, output);
}
if (result != DriverResult::Success) {
if (result != Common::Input::DriverResult::Success) {
return result;
}
if (tries++ >= max_tries) {
return DriverResult::WrongReply;
return Common::Input::DriverResult::WrongReply;
}
} while (!(output.command_data[0] == 0x13 && output.command_data[2] == 0x07) &&
output.command_data[0] != 0x23);
return DriverResult::Success;
return Common::Input::DriverResult::Success;
}
DriverResult IrsProtocol::WriteRegistersStep2() {
Common::Input::DriverResult IrsProtocol::WriteRegistersStep2() {
LOG_DEBUG(Input, "WriteRegistersStep2");
constexpr std::size_t max_tries = 28;
SubCommandResponse output{};
@@ -255,18 +255,18 @@ DriverResult IrsProtocol::WriteRegistersStep2() {
do {
const auto result = SendSubCommand(SubCommand::SET_MCU_CONFIG, request_data, output);
if (result != DriverResult::Success) {
if (result != Common::Input::DriverResult::Success) {
return result;
}
if (tries++ >= max_tries) {
return DriverResult::WrongReply;
return Common::Input::DriverResult::WrongReply;
}
} while (output.command_data[0] != 0x13 && output.command_data[0] != 0x23);
return DriverResult::Success;
return Common::Input::DriverResult::Success;
}
DriverResult IrsProtocol::RequestFrame(u8 frame) {
Common::Input::DriverResult IrsProtocol::RequestFrame(u8 frame) {
std::array<u8, 38> mcu_request{};
mcu_request[3] = frame;
mcu_request[36] = CalculateMCU_CRC8(mcu_request.data(), 36);
@@ -274,7 +274,7 @@ DriverResult IrsProtocol::RequestFrame(u8 frame) {
return SendMCUCommand(SubCommand::SET_REPORT_MODE, mcu_request);
}
DriverResult IrsProtocol::ResendFrame(u8 frame) {
Common::Input::DriverResult IrsProtocol::ResendFrame(u8 frame) {
std::array<u8, 38> mcu_request{};
mcu_request[1] = 0x1;
mcu_request[2] = frame;

View File

@@ -13,19 +13,23 @@
#include "input_common/helpers/joycon_protocol/common_protocol.h"
#include "input_common/helpers/joycon_protocol/joycon_types.h"
namespace Common::Input {
enum class DriverResult;
}
namespace InputCommon::Joycon {
class IrsProtocol final : private JoyconCommonProtocol {
public:
explicit IrsProtocol(std::shared_ptr<JoyconHandle> handle);
DriverResult EnableIrs();
Common::Input::DriverResult EnableIrs();
DriverResult DisableIrs();
Common::Input::DriverResult DisableIrs();
DriverResult SetIrsConfig(IrsMode mode, IrsResolution format);
Common::Input::DriverResult SetIrsConfig(IrsMode mode, IrsResolution format);
DriverResult RequestImage(std::span<u8> buffer);
Common::Input::DriverResult RequestImage(std::span<u8> buffer);
std::vector<u8> GetImage() const;
@@ -34,13 +38,13 @@ public:
bool IsEnabled() const;
private:
DriverResult ConfigureIrs();
Common::Input::DriverResult ConfigureIrs();
DriverResult WriteRegistersStep1();
DriverResult WriteRegistersStep2();
Common::Input::DriverResult WriteRegistersStep1();
Common::Input::DriverResult WriteRegistersStep2();
DriverResult RequestFrame(u8 frame);
DriverResult ResendFrame(u8 frame);
Common::Input::DriverResult RequestFrame(u8 frame);
Common::Input::DriverResult ResendFrame(u8 frame);
IrsMode irs_mode{IrsMode::ImageTransfer};
IrsResolution resolution{IrsResolution::Size40x30};

View File

@@ -402,23 +402,6 @@ enum class ExternalDeviceId : u16 {
Starlink = 0x2800,
};
enum class DriverResult {
Success,
WrongReply,
Timeout,
InvalidParameters,
UnsupportedControllerType,
HandleInUse,
ErrorReadingData,
ErrorWritingData,
NoDeviceDetected,
InvalidHandle,
NotSupported,
Disabled,
Delayed,
Unknown,
};
struct MotionSensorCalibration {
s16 offset;
s16 scale;

View File

@@ -1,7 +1,7 @@
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include <thread>
#include "common/input.h"
#include "common/logging/log.h"
#include "input_common/helpers/joycon_protocol/nfc.h"
@@ -10,21 +10,21 @@ namespace InputCommon::Joycon {
NfcProtocol::NfcProtocol(std::shared_ptr<JoyconHandle> handle)
: JoyconCommonProtocol(std::move(handle)) {}
DriverResult NfcProtocol::EnableNfc() {
Common::Input::DriverResult NfcProtocol::EnableNfc() {
LOG_INFO(Input, "Enable NFC");
ScopedSetBlocking sb(this);
DriverResult result{DriverResult::Success};
Common::Input::DriverResult result{Common::Input::DriverResult::Success};
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
result = SetReportMode(ReportMode::NFC_IR_MODE_60HZ);
}
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
result = EnableMCU(true);
}
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
result = WaitSetMCUMode(ReportMode::NFC_IR_MODE_60HZ, MCUMode::Standby);
}
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
const MCUConfig config{
.command = MCUCommand::ConfigureMCU,
.sub_command = MCUSubCommand::SetMCUMode,
@@ -34,32 +34,32 @@ DriverResult NfcProtocol::EnableNfc() {
result = ConfigureMCU(config);
}
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
result = WaitSetMCUMode(ReportMode::NFC_IR_MODE_60HZ, MCUMode::NFC);
}
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
result = WaitUntilNfcIs(NFCStatus::Ready);
}
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
MCUCommandResponse output{};
result = SendStopPollingRequest(output);
}
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
result = WaitUntilNfcIs(NFCStatus::Ready);
}
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
is_enabled = true;
}
return result;
}
DriverResult NfcProtocol::DisableNfc() {
Common::Input::DriverResult NfcProtocol::DisableNfc() {
LOG_DEBUG(Input, "Disable NFC");
ScopedSetBlocking sb(this);
DriverResult result{DriverResult::Success};
Common::Input::DriverResult result{Common::Input::DriverResult::Success};
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
result = EnableMCU(false);
}
@@ -69,60 +69,60 @@ DriverResult NfcProtocol::DisableNfc() {
return result;
}
DriverResult NfcProtocol::StartNFCPollingMode() {
Common::Input::DriverResult NfcProtocol::StartNFCPollingMode() {
LOG_DEBUG(Input, "Start NFC polling Mode");
ScopedSetBlocking sb(this);
DriverResult result{DriverResult::Success};
Common::Input::DriverResult result{Common::Input::DriverResult::Success};
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
MCUCommandResponse output{};
result = SendStartPollingRequest(output);
}
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
result = WaitUntilNfcIs(NFCStatus::Polling);
}
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
is_polling = true;
}
return result;
}
DriverResult NfcProtocol::StopNFCPollingMode() {
Common::Input::DriverResult NfcProtocol::StopNFCPollingMode() {
LOG_DEBUG(Input, "Stop NFC polling Mode");
ScopedSetBlocking sb(this);
DriverResult result{DriverResult::Success};
Common::Input::DriverResult result{Common::Input::DriverResult::Success};
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
MCUCommandResponse output{};
result = SendStopPollingRequest(output);
}
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
result = WaitUntilNfcIs(NFCStatus::WriteReady);
}
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
is_polling = false;
}
return result;
}
DriverResult NfcProtocol::GetTagInfo(Joycon::TagInfo& tag_info) {
Common::Input::DriverResult NfcProtocol::GetTagInfo(Joycon::TagInfo& tag_info) {
if (update_counter++ < AMIIBO_UPDATE_DELAY) {
return DriverResult::Delayed;
return Common::Input::DriverResult::Delayed;
}
update_counter = 0;
LOG_DEBUG(Input, "Scan for amiibos");
ScopedSetBlocking sb(this);
DriverResult result{DriverResult::Success};
Common::Input::DriverResult result{Common::Input::DriverResult::Success};
TagFoundData tag_data{};
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
result = IsTagInRange(tag_data);
}
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
tag_info = {
.uuid_length = tag_data.uuid_size,
.protocol = 1,
@@ -147,59 +147,59 @@ DriverResult NfcProtocol::GetTagInfo(Joycon::TagInfo& tag_info) {
return result;
}
DriverResult NfcProtocol::ReadAmiibo(std::vector<u8>& data) {
Common::Input::DriverResult NfcProtocol::ReadAmiibo(std::vector<u8>& data) {
LOG_DEBUG(Input, "Scan for amiibos");
ScopedSetBlocking sb(this);
DriverResult result{DriverResult::Success};
Common::Input::DriverResult result{Common::Input::DriverResult::Success};
TagFoundData tag_data{};
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
result = IsTagInRange(tag_data, 7);
}
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
result = GetAmiiboData(data);
}
return result;
}
DriverResult NfcProtocol::WriteAmiibo(std::span<const u8> data) {
Common::Input::DriverResult NfcProtocol::WriteAmiibo(std::span<const u8> data) {
LOG_DEBUG(Input, "Write amiibo");
ScopedSetBlocking sb(this);
DriverResult result{DriverResult::Success};
Common::Input::DriverResult result{Common::Input::DriverResult::Success};
TagUUID tag_uuid = GetTagUUID(data);
TagFoundData tag_data{};
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
result = IsTagInRange(tag_data, 7);
}
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
if (tag_data.uuid != tag_uuid) {
result = DriverResult::InvalidParameters;
result = Common::Input::DriverResult::InvalidParameters;
}
}
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
MCUCommandResponse output{};
result = SendStopPollingRequest(output);
}
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
result = WaitUntilNfcIs(NFCStatus::Ready);
}
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
MCUCommandResponse output{};
result = SendStartPollingRequest(output, true);
}
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
result = WaitUntilNfcIs(NFCStatus::WriteReady);
}
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
result = WriteAmiiboData(tag_uuid, data);
}
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
result = WaitUntilNfcIs(NFCStatus::WriteDone);
}
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
MCUCommandResponse output{};
result = SendStopPollingRequest(output);
}
@@ -207,64 +207,65 @@ DriverResult NfcProtocol::WriteAmiibo(std::span<const u8> data) {
return result;
}
DriverResult NfcProtocol::ReadMifare(std::span<const MifareReadChunk> read_request,
std::span<MifareReadData> out_data) {
Common::Input::DriverResult NfcProtocol::ReadMifare(std::span<const MifareReadChunk> read_request,
std::span<MifareReadData> out_data) {
LOG_DEBUG(Input, "Read mifare");
ScopedSetBlocking sb(this);
DriverResult result{DriverResult::Success};
Common::Input::DriverResult result{Common::Input::DriverResult::Success};
TagFoundData tag_data{};
MifareUUID tag_uuid{};
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
result = IsTagInRange(tag_data, 7);
}
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
memcpy(tag_uuid.data(), tag_data.uuid.data(), sizeof(MifareUUID));
result = GetMifareData(tag_uuid, read_request, out_data);
}
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
MCUCommandResponse output{};
result = SendStopPollingRequest(output);
}
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
result = WaitUntilNfcIs(NFCStatus::Ready);
}
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
MCUCommandResponse output{};
result = SendStartPollingRequest(output, true);
}
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
result = WaitUntilNfcIs(NFCStatus::WriteReady);
}
return result;
}
DriverResult NfcProtocol::WriteMifare(std::span<const MifareWriteChunk> write_request) {
Common::Input::DriverResult NfcProtocol::WriteMifare(
std::span<const MifareWriteChunk> write_request) {
LOG_DEBUG(Input, "Write mifare");
ScopedSetBlocking sb(this);
DriverResult result{DriverResult::Success};
Common::Input::DriverResult result{Common::Input::DriverResult::Success};
TagFoundData tag_data{};
MifareUUID tag_uuid{};
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
result = IsTagInRange(tag_data, 7);
}
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
memcpy(tag_uuid.data(), tag_data.uuid.data(), sizeof(MifareUUID));
result = WriteMifareData(tag_uuid, write_request);
}
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
MCUCommandResponse output{};
result = SendStopPollingRequest(output);
}
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
result = WaitUntilNfcIs(NFCStatus::Ready);
}
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
MCUCommandResponse output{};
result = SendStartPollingRequest(output, true);
}
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
result = WaitUntilNfcIs(NFCStatus::WriteReady);
}
return result;
@@ -277,17 +278,17 @@ bool NfcProtocol::HasAmiibo() {
update_counter = 0;
ScopedSetBlocking sb(this);
DriverResult result{DriverResult::Success};
Common::Input::DriverResult result{Common::Input::DriverResult::Success};
TagFoundData tag_data{};
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
result = IsTagInRange(tag_data, 7);
}
return result == DriverResult::Success;
return result == Common::Input::DriverResult::Success;
}
DriverResult NfcProtocol::WaitUntilNfcIs(NFCStatus status) {
Common::Input::DriverResult NfcProtocol::WaitUntilNfcIs(NFCStatus status) {
constexpr std::size_t timeout_limit = 10;
MCUCommandResponse output{};
std::size_t tries = 0;
@@ -295,30 +296,31 @@ DriverResult NfcProtocol::WaitUntilNfcIs(NFCStatus status) {
do {
auto result = SendNextPackageRequest(output, {});
if (result != DriverResult::Success) {
if (result != Common::Input::DriverResult::Success) {
return result;
}
if (tries++ > timeout_limit) {
return DriverResult::Timeout;
return Common::Input::DriverResult::Timeout;
}
} while (output.mcu_report != MCUReport::NFCState ||
(output.mcu_data[1] << 8) + output.mcu_data[0] != 0x0500 ||
output.mcu_data[5] != 0x31 || output.mcu_data[6] != static_cast<u8>(status));
return DriverResult::Success;
return Common::Input::DriverResult::Success;
}
DriverResult NfcProtocol::IsTagInRange(TagFoundData& data, std::size_t timeout_limit) {
Common::Input::DriverResult NfcProtocol::IsTagInRange(TagFoundData& data,
std::size_t timeout_limit) {
MCUCommandResponse output{};
std::size_t tries = 0;
do {
const auto result = SendNextPackageRequest(output, {});
if (result != DriverResult::Success) {
if (result != Common::Input::DriverResult::Success) {
return result;
}
if (tries++ > timeout_limit) {
return DriverResult::Timeout;
return Common::Input::DriverResult::Timeout;
}
} while (output.mcu_report != MCUReport::NFCState ||
(output.mcu_data[1] << 8) + output.mcu_data[0] != 0x0500 ||
@@ -328,10 +330,10 @@ DriverResult NfcProtocol::IsTagInRange(TagFoundData& data, std::size_t timeout_l
data.uuid_size = std::min(output.mcu_data[14], static_cast<u8>(sizeof(TagUUID)));
memcpy(data.uuid.data(), output.mcu_data.data() + 15, data.uuid.size());
return DriverResult::Success;
return Common::Input::DriverResult::Success;
}
DriverResult NfcProtocol::GetAmiiboData(std::vector<u8>& ntag_data) {
Common::Input::DriverResult NfcProtocol::GetAmiiboData(std::vector<u8>& ntag_data) {
constexpr std::size_t timeout_limit = 60;
MCUCommandResponse output{};
std::size_t tries = 0;
@@ -340,7 +342,7 @@ DriverResult NfcProtocol::GetAmiiboData(std::vector<u8>& ntag_data) {
std::size_t ntag_buffer_pos = 0;
auto result = SendReadAmiiboRequest(output, NFCPages::Block135);
if (result != DriverResult::Success) {
if (result != Common::Input::DriverResult::Success) {
return result;
}
@@ -349,14 +351,14 @@ DriverResult NfcProtocol::GetAmiiboData(std::vector<u8>& ntag_data) {
result = SendNextPackageRequest(output, package_index);
const auto nfc_status = static_cast<NFCStatus>(output.mcu_data[6]);
if (result != DriverResult::Success) {
if (result != Common::Input::DriverResult::Success) {
return result;
}
if ((output.mcu_report == MCUReport::NFCReadData ||
output.mcu_report == MCUReport::NFCState) &&
nfc_status == NFCStatus::TagLost) {
return DriverResult::ErrorReadingData;
return Common::Input::DriverResult::ErrorReadingData;
}
if (output.mcu_report == MCUReport::NFCReadData && output.mcu_data[1] == 0x07) {
@@ -375,14 +377,15 @@ DriverResult NfcProtocol::GetAmiiboData(std::vector<u8>& ntag_data) {
if (output.mcu_report == MCUReport::NFCState && nfc_status == NFCStatus::LastPackage) {
LOG_INFO(Input, "Finished reading amiibo");
return DriverResult::Success;
return Common::Input::DriverResult::Success;
}
}
return DriverResult::Timeout;
return Common::Input::DriverResult::Timeout;
}
DriverResult NfcProtocol::WriteAmiiboData(const TagUUID& tag_uuid, std::span<const u8> data) {
Common::Input::DriverResult NfcProtocol::WriteAmiiboData(const TagUUID& tag_uuid,
std::span<const u8> data) {
constexpr std::size_t timeout_limit = 60;
const auto nfc_data = MakeAmiiboWritePackage(tag_uuid, data);
const std::vector<u8> nfc_buffer_data = SerializeWritePackage(nfc_data);
@@ -397,7 +400,7 @@ DriverResult NfcProtocol::WriteAmiiboData(const TagUUID& tag_uuid, std::span<con
auto result = SendWriteAmiiboRequest(output, tag_uuid);
if (result != DriverResult::Success) {
if (result != Common::Input::DriverResult::Success) {
return result;
}
@@ -406,14 +409,14 @@ DriverResult NfcProtocol::WriteAmiiboData(const TagUUID& tag_uuid, std::span<con
result = SendNextPackageRequest(output, package_index);
const auto nfc_status = static_cast<NFCStatus>(output.mcu_data[6]);
if (result != DriverResult::Success) {
if (result != Common::Input::DriverResult::Success) {
return result;
}
if ((output.mcu_report == MCUReport::NFCReadData ||
output.mcu_report == MCUReport::NFCState) &&
nfc_status == NFCStatus::TagLost) {
return DriverResult::ErrorReadingData;
return Common::Input::DriverResult::ErrorReadingData;
}
if (output.mcu_report == MCUReport::NFCReadData && output.mcu_data[1] == 0x07) {
@@ -442,7 +445,7 @@ DriverResult NfcProtocol::WriteAmiiboData(const TagUUID& tag_uuid, std::span<con
if ((output.mcu_report == MCUReport::NFCReadData ||
output.mcu_report == MCUReport::NFCState) &&
nfc_status == NFCStatus::TagLost) {
return DriverResult::ErrorReadingData;
return Common::Input::DriverResult::ErrorReadingData;
}
// Increase position when data is confirmed by the joycon
@@ -457,14 +460,14 @@ DriverResult NfcProtocol::WriteAmiiboData(const TagUUID& tag_uuid, std::span<con
return result;
}
DriverResult NfcProtocol::GetMifareData(const MifareUUID& tag_uuid,
std::span<const MifareReadChunk> read_request,
std::span<MifareReadData> out_data) {
Common::Input::DriverResult NfcProtocol::GetMifareData(
const MifareUUID& tag_uuid, std::span<const MifareReadChunk> read_request,
std::span<MifareReadData> out_data) {
constexpr std::size_t timeout_limit = 60;
const auto nfc_data = MakeMifareReadPackage(tag_uuid, read_request);
const std::vector<u8> nfc_buffer_data = SerializeMifareReadPackage(nfc_data);
std::span<const u8> buffer(nfc_buffer_data);
DriverResult result = DriverResult::Success;
Common::Input::DriverResult result = Common::Input::DriverResult::Success;
MCUCommandResponse output{};
u8 block_id = 1;
u8 package_index = 0;
@@ -486,7 +489,7 @@ DriverResult NfcProtocol::GetMifareData(const MifareUUID& tag_uuid,
const auto nfc_status = static_cast<NFCStatus>(output.mcu_data[6]);
if (output.mcu_report == MCUReport::NFCState && nfc_status == NFCStatus::TagLost) {
return DriverResult::ErrorReadingData;
return Common::Input::DriverResult::ErrorReadingData;
}
// Increase position when data is confirmed by the joycon
@@ -498,7 +501,7 @@ DriverResult NfcProtocol::GetMifareData(const MifareUUID& tag_uuid,
}
}
if (result != DriverResult::Success) {
if (result != Common::Input::DriverResult::Success) {
return result;
}
@@ -507,12 +510,12 @@ DriverResult NfcProtocol::GetMifareData(const MifareUUID& tag_uuid,
result = SendNextPackageRequest(output, package_index);
const auto nfc_status = static_cast<NFCStatus>(output.mcu_data[6]);
if (result != DriverResult::Success) {
if (result != Common::Input::DriverResult::Success) {
return result;
}
if (output.mcu_report == MCUReport::NFCState && nfc_status == NFCStatus::TagLost) {
return DriverResult::ErrorReadingData;
return Common::Input::DriverResult::ErrorReadingData;
}
if (output.mcu_report == MCUReport::NFCState && output.mcu_data[1] == 0x10) {
@@ -538,13 +541,13 @@ DriverResult NfcProtocol::GetMifareData(const MifareUUID& tag_uuid,
return result;
}
DriverResult NfcProtocol::WriteMifareData(const MifareUUID& tag_uuid,
std::span<const MifareWriteChunk> write_request) {
Common::Input::DriverResult NfcProtocol::WriteMifareData(
const MifareUUID& tag_uuid, std::span<const MifareWriteChunk> write_request) {
constexpr std::size_t timeout_limit = 60;
const auto nfc_data = MakeMifareWritePackage(tag_uuid, write_request);
const std::vector<u8> nfc_buffer_data = SerializeMifareWritePackage(nfc_data);
std::span<const u8> buffer(nfc_buffer_data);
DriverResult result = DriverResult::Success;
Common::Input::DriverResult result = Common::Input::DriverResult::Success;
MCUCommandResponse output{};
u8 block_id = 1;
u8 package_index = 0;
@@ -566,7 +569,7 @@ DriverResult NfcProtocol::WriteMifareData(const MifareUUID& tag_uuid,
const auto nfc_status = static_cast<NFCStatus>(output.mcu_data[6]);
if (output.mcu_report == MCUReport::NFCState && nfc_status == NFCStatus::TagLost) {
return DriverResult::ErrorReadingData;
return Common::Input::DriverResult::ErrorReadingData;
}
// Increase position when data is confirmed by the joycon
@@ -578,7 +581,7 @@ DriverResult NfcProtocol::WriteMifareData(const MifareUUID& tag_uuid,
}
}
if (result != DriverResult::Success) {
if (result != Common::Input::DriverResult::Success) {
return result;
}
@@ -587,12 +590,12 @@ DriverResult NfcProtocol::WriteMifareData(const MifareUUID& tag_uuid,
result = SendNextPackageRequest(output, package_index);
const auto nfc_status = static_cast<NFCStatus>(output.mcu_data[6]);
if (result != DriverResult::Success) {
if (result != Common::Input::DriverResult::Success) {
return result;
}
if (output.mcu_report == MCUReport::NFCState && nfc_status == NFCStatus::TagLost) {
return DriverResult::ErrorReadingData;
return Common::Input::DriverResult::ErrorReadingData;
}
if (output.mcu_report == MCUReport::NFCState && output.mcu_data[1] == 0x10) {
@@ -609,8 +612,8 @@ DriverResult NfcProtocol::WriteMifareData(const MifareUUID& tag_uuid,
return result;
}
DriverResult NfcProtocol::SendStartPollingRequest(MCUCommandResponse& output,
bool is_second_attempt) {
Common::Input::DriverResult NfcProtocol::SendStartPollingRequest(MCUCommandResponse& output,
bool is_second_attempt) {
NFCRequestState request{
.command_argument = NFCCommand::StartPolling,
.block_id = {},
@@ -635,7 +638,7 @@ DriverResult NfcProtocol::SendStartPollingRequest(MCUCommandResponse& output,
output);
}
DriverResult NfcProtocol::SendStopPollingRequest(MCUCommandResponse& output) {
Common::Input::DriverResult NfcProtocol::SendStopPollingRequest(MCUCommandResponse& output) {
NFCRequestState request{
.command_argument = NFCCommand::StopPolling,
.block_id = {},
@@ -653,7 +656,8 @@ DriverResult NfcProtocol::SendStopPollingRequest(MCUCommandResponse& output) {
output);
}
DriverResult NfcProtocol::SendNextPackageRequest(MCUCommandResponse& output, u8 packet_id) {
Common::Input::DriverResult NfcProtocol::SendNextPackageRequest(MCUCommandResponse& output,
u8 packet_id) {
NFCRequestState request{
.command_argument = NFCCommand::StartWaitingRecieve,
.block_id = {},
@@ -671,7 +675,8 @@ DriverResult NfcProtocol::SendNextPackageRequest(MCUCommandResponse& output, u8
output);
}
DriverResult NfcProtocol::SendReadAmiiboRequest(MCUCommandResponse& output, NFCPages ntag_pages) {
Common::Input::DriverResult NfcProtocol::SendReadAmiiboRequest(MCUCommandResponse& output,
NFCPages ntag_pages) {
NFCRequestState request{
.command_argument = NFCCommand::ReadNtag,
.block_id = {},
@@ -696,8 +701,8 @@ DriverResult NfcProtocol::SendReadAmiiboRequest(MCUCommandResponse& output, NFCP
output);
}
DriverResult NfcProtocol::SendWriteAmiiboRequest(MCUCommandResponse& output,
const TagUUID& tag_uuid) {
Common::Input::DriverResult NfcProtocol::SendWriteAmiiboRequest(MCUCommandResponse& output,
const TagUUID& tag_uuid) {
NFCRequestState request{
.command_argument = NFCCommand::ReadNtag,
.block_id = {},
@@ -722,9 +727,10 @@ DriverResult NfcProtocol::SendWriteAmiiboRequest(MCUCommandResponse& output,
output);
}
DriverResult NfcProtocol::SendWriteDataAmiiboRequest(MCUCommandResponse& output, u8 block_id,
bool is_last_packet,
std::span<const u8> data) {
Common::Input::DriverResult NfcProtocol::SendWriteDataAmiiboRequest(MCUCommandResponse& output,
u8 block_id,
bool is_last_packet,
std::span<const u8> data) {
const auto data_size = std::min(data.size(), sizeof(NFCRequestState::raw_data));
NFCRequestState request{
.command_argument = NFCCommand::WriteNtag,
@@ -745,8 +751,9 @@ DriverResult NfcProtocol::SendWriteDataAmiiboRequest(MCUCommandResponse& output,
output);
}
DriverResult NfcProtocol::SendReadDataMifareRequest(MCUCommandResponse& output, u8 block_id,
bool is_last_packet, std::span<const u8> data) {
Common::Input::DriverResult NfcProtocol::SendReadDataMifareRequest(MCUCommandResponse& output,
u8 block_id, bool is_last_packet,
std::span<const u8> data) {
const auto data_size = std::min(data.size(), sizeof(NFCRequestState::raw_data));
NFCRequestState request{
.command_argument = NFCCommand::Mifare,

View File

@@ -13,30 +13,34 @@
#include "input_common/helpers/joycon_protocol/common_protocol.h"
#include "input_common/helpers/joycon_protocol/joycon_types.h"
namespace Common::Input {
enum class DriverResult;
}
namespace InputCommon::Joycon {
class NfcProtocol final : private JoyconCommonProtocol {
public:
explicit NfcProtocol(std::shared_ptr<JoyconHandle> handle);
DriverResult EnableNfc();
Common::Input::DriverResult EnableNfc();
DriverResult DisableNfc();
Common::Input::DriverResult DisableNfc();
DriverResult StartNFCPollingMode();
Common::Input::DriverResult StartNFCPollingMode();
DriverResult StopNFCPollingMode();
Common::Input::DriverResult StopNFCPollingMode();
DriverResult GetTagInfo(Joycon::TagInfo& tag_info);
Common::Input::DriverResult GetTagInfo(Joycon::TagInfo& tag_info);
DriverResult ReadAmiibo(std::vector<u8>& data);
Common::Input::DriverResult ReadAmiibo(std::vector<u8>& data);
DriverResult WriteAmiibo(std::span<const u8> data);
Common::Input::DriverResult WriteAmiibo(std::span<const u8> data);
DriverResult ReadMifare(std::span<const MifareReadChunk> read_request,
std::span<MifareReadData> out_data);
Common::Input::DriverResult ReadMifare(std::span<const MifareReadChunk> read_request,
std::span<MifareReadData> out_data);
DriverResult WriteMifare(std::span<const MifareWriteChunk> write_request);
Common::Input::DriverResult WriteMifare(std::span<const MifareWriteChunk> write_request);
bool HasAmiibo();
@@ -54,37 +58,41 @@ private:
TagUUID uuid;
};
DriverResult WaitUntilNfcIs(NFCStatus status);
Common::Input::DriverResult WaitUntilNfcIs(NFCStatus status);
DriverResult IsTagInRange(TagFoundData& data, std::size_t timeout_limit = 1);
Common::Input::DriverResult IsTagInRange(TagFoundData& data, std::size_t timeout_limit = 1);
DriverResult GetAmiiboData(std::vector<u8>& data);
Common::Input::DriverResult GetAmiiboData(std::vector<u8>& data);
DriverResult WriteAmiiboData(const TagUUID& tag_uuid, std::span<const u8> data);
Common::Input::DriverResult WriteAmiiboData(const TagUUID& tag_uuid, std::span<const u8> data);
DriverResult GetMifareData(const MifareUUID& tag_uuid,
std::span<const MifareReadChunk> read_request,
std::span<MifareReadData> out_data);
Common::Input::DriverResult GetMifareData(const MifareUUID& tag_uuid,
std::span<const MifareReadChunk> read_request,
std::span<MifareReadData> out_data);
DriverResult WriteMifareData(const MifareUUID& tag_uuid,
std::span<const MifareWriteChunk> write_request);
Common::Input::DriverResult WriteMifareData(const MifareUUID& tag_uuid,
std::span<const MifareWriteChunk> write_request);
DriverResult SendStartPollingRequest(MCUCommandResponse& output,
bool is_second_attempt = false);
Common::Input::DriverResult SendStartPollingRequest(MCUCommandResponse& output,
bool is_second_attempt = false);
DriverResult SendStopPollingRequest(MCUCommandResponse& output);
Common::Input::DriverResult SendStopPollingRequest(MCUCommandResponse& output);
DriverResult SendNextPackageRequest(MCUCommandResponse& output, u8 packet_id);
Common::Input::DriverResult SendNextPackageRequest(MCUCommandResponse& output, u8 packet_id);
DriverResult SendReadAmiiboRequest(MCUCommandResponse& output, NFCPages ntag_pages);
Common::Input::DriverResult SendReadAmiiboRequest(MCUCommandResponse& output,
NFCPages ntag_pages);
DriverResult SendWriteAmiiboRequest(MCUCommandResponse& output, const TagUUID& tag_uuid);
Common::Input::DriverResult SendWriteAmiiboRequest(MCUCommandResponse& output,
const TagUUID& tag_uuid);
DriverResult SendWriteDataAmiiboRequest(MCUCommandResponse& output, u8 block_id,
bool is_last_packet, std::span<const u8> data);
Common::Input::DriverResult SendWriteDataAmiiboRequest(MCUCommandResponse& output, u8 block_id,
bool is_last_packet,
std::span<const u8> data);
DriverResult SendReadDataMifareRequest(MCUCommandResponse& output, u8 block_id,
bool is_last_packet, std::span<const u8> data);
Common::Input::DriverResult SendReadDataMifareRequest(MCUCommandResponse& output, u8 block_id,
bool is_last_packet,
std::span<const u8> data);
std::vector<u8> SerializeWritePackage(const NFCWritePackage& package) const;

View File

@@ -1,6 +1,7 @@
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "common/input.h"
#include "common/logging/log.h"
#include "input_common/helpers/joycon_protocol/ringcon.h"
@@ -9,18 +10,18 @@ namespace InputCommon::Joycon {
RingConProtocol::RingConProtocol(std::shared_ptr<JoyconHandle> handle)
: JoyconCommonProtocol(std::move(handle)) {}
DriverResult RingConProtocol::EnableRingCon() {
Common::Input::DriverResult RingConProtocol::EnableRingCon() {
LOG_DEBUG(Input, "Enable Ringcon");
ScopedSetBlocking sb(this);
DriverResult result{DriverResult::Success};
Common::Input::DriverResult result{Common::Input::DriverResult::Success};
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
result = SetReportMode(ReportMode::STANDARD_FULL_60HZ);
}
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
result = EnableMCU(true);
}
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
const MCUConfig config{
.command = MCUCommand::ConfigureMCU,
.sub_command = MCUSubCommand::SetDeviceMode,
@@ -33,12 +34,12 @@ DriverResult RingConProtocol::EnableRingCon() {
return result;
}
DriverResult RingConProtocol::DisableRingCon() {
Common::Input::DriverResult RingConProtocol::DisableRingCon() {
LOG_DEBUG(Input, "Disable RingCon");
ScopedSetBlocking sb(this);
DriverResult result{DriverResult::Success};
Common::Input::DriverResult result{Common::Input::DriverResult::Success};
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
result = EnableMCU(false);
}
@@ -47,29 +48,29 @@ DriverResult RingConProtocol::DisableRingCon() {
return result;
}
DriverResult RingConProtocol::StartRingconPolling() {
Common::Input::DriverResult RingConProtocol::StartRingconPolling() {
LOG_DEBUG(Input, "Enable Ringcon");
ScopedSetBlocking sb(this);
DriverResult result{DriverResult::Success};
Common::Input::DriverResult result{Common::Input::DriverResult::Success};
bool is_connected = false;
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
result = IsRingConnected(is_connected);
}
if (result == DriverResult::Success && is_connected) {
if (result == Common::Input::DriverResult::Success && is_connected) {
LOG_INFO(Input, "Ringcon detected");
result = ConfigureRing();
}
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
is_enabled = true;
}
return result;
}
DriverResult RingConProtocol::IsRingConnected(bool& is_connected) {
Common::Input::DriverResult RingConProtocol::IsRingConnected(bool& is_connected) {
LOG_DEBUG(Input, "IsRingConnected");
constexpr std::size_t max_tries = 28;
constexpr std::size_t max_tries = 42;
SubCommandResponse output{};
std::size_t tries = 0;
is_connected = false;
@@ -77,20 +78,21 @@ DriverResult RingConProtocol::IsRingConnected(bool& is_connected) {
do {
const auto result = SendSubCommand(SubCommand::GET_EXTERNAL_DEVICE_INFO, {}, output);
if (result != DriverResult::Success) {
if (result != Common::Input::DriverResult::Success &&
result != Common::Input::DriverResult::Timeout) {
return result;
}
if (tries++ >= max_tries) {
return DriverResult::NoDeviceDetected;
return Common::Input::DriverResult::NoDeviceDetected;
}
} while (output.external_device_id != ExternalDeviceId::RingController);
is_connected = true;
return DriverResult::Success;
return Common::Input::DriverResult::Success;
}
DriverResult RingConProtocol::ConfigureRing() {
Common::Input::DriverResult RingConProtocol::ConfigureRing() {
LOG_DEBUG(Input, "ConfigureRing");
static constexpr std::array<u8, 37> ring_config{
@@ -98,9 +100,10 @@ DriverResult RingConProtocol::ConfigureRing() {
0x00, 0x00, 0x00, 0x0A, 0x64, 0x0B, 0xE6, 0xA9, 0x22, 0x00, 0x00, 0x04, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x90, 0xA8, 0xE1, 0x34, 0x36};
const DriverResult result = SendSubCommand(SubCommand::SET_EXTERNAL_FORMAT_CONFIG, ring_config);
const Common::Input::DriverResult result =
SendSubCommand(SubCommand::SET_EXTERNAL_FORMAT_CONFIG, ring_config);
if (result != DriverResult::Success) {
if (result != Common::Input::DriverResult::Success) {
return result;
}

View File

@@ -13,24 +13,28 @@
#include "input_common/helpers/joycon_protocol/common_protocol.h"
#include "input_common/helpers/joycon_protocol/joycon_types.h"
namespace Common::Input {
enum class DriverResult;
}
namespace InputCommon::Joycon {
class RingConProtocol final : private JoyconCommonProtocol {
public:
explicit RingConProtocol(std::shared_ptr<JoyconHandle> handle);
DriverResult EnableRingCon();
Common::Input::DriverResult EnableRingCon();
DriverResult DisableRingCon();
Common::Input::DriverResult DisableRingCon();
DriverResult StartRingconPolling();
Common::Input::DriverResult StartRingconPolling();
bool IsEnabled() const;
private:
DriverResult IsRingConnected(bool& is_connected);
Common::Input::DriverResult IsRingConnected(bool& is_connected);
DriverResult ConfigureRing();
Common::Input::DriverResult ConfigureRing();
bool is_enabled{};
};

View File

@@ -4,6 +4,7 @@
#include <algorithm>
#include <cmath>
#include "common/input.h"
#include "common/logging/log.h"
#include "input_common/helpers/joycon_protocol/rumble.h"
@@ -12,14 +13,14 @@ namespace InputCommon::Joycon {
RumbleProtocol::RumbleProtocol(std::shared_ptr<JoyconHandle> handle)
: JoyconCommonProtocol(std::move(handle)) {}
DriverResult RumbleProtocol::EnableRumble(bool is_enabled) {
Common::Input::DriverResult RumbleProtocol::EnableRumble(bool is_enabled) {
LOG_DEBUG(Input, "Enable Rumble");
ScopedSetBlocking sb(this);
const std::array<u8, 1> buffer{static_cast<u8>(is_enabled ? 1 : 0)};
return SendSubCommand(SubCommand::ENABLE_VIBRATION, buffer);
}
DriverResult RumbleProtocol::SendVibration(const VibrationValue& vibration) {
Common::Input::DriverResult RumbleProtocol::SendVibration(const VibrationValue& vibration) {
std::array<u8, sizeof(DefaultVibrationBuffer)> buffer{};
if (vibration.high_amplitude <= 0.0f && vibration.low_amplitude <= 0.0f) {

View File

@@ -13,15 +13,19 @@
#include "input_common/helpers/joycon_protocol/common_protocol.h"
#include "input_common/helpers/joycon_protocol/joycon_types.h"
namespace Common::Input {
enum class DriverResult;
}
namespace InputCommon::Joycon {
class RumbleProtocol final : private JoyconCommonProtocol {
public:
explicit RumbleProtocol(std::shared_ptr<JoyconHandle> handle);
DriverResult EnableRumble(bool is_enabled);
Common::Input::DriverResult EnableRumble(bool is_enabled);
DriverResult SendVibration(const VibrationValue& vibration);
Common::Input::DriverResult SendVibration(const VibrationValue& vibration);
private:
u16 EncodeHighFrequency(f32 frequency) const;

View File

@@ -879,6 +879,10 @@ ImageId TextureCache<P>::DmaImageId(const Tegra::DMA::ImageOperand& operand, boo
return NULL_IMAGE_ID;
}
auto& image = slot_images[image_id];
if (image.info.type == ImageType::e3D) {
// Don't accelerate 3D images.
return NULL_IMAGE_ID;
}
if (!is_upload && !image.info.dma_downloaded) {
// Force a full sync.
image.info.dma_downloaded = true;

View File

@@ -485,7 +485,7 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR
loaded_extensions.erase(VK_EXT_EXTENDED_DYNAMIC_STATE_EXTENSION_NAME);
}
}
if (extensions.extended_dynamic_state2 && is_radv) {
if (extensions.extended_dynamic_state2 && (is_radv || is_qualcomm)) {
const u32 version = (properties.properties.driverVersion << 3) >> 3;
if (version < VK_MAKE_API_VERSION(0, 22, 3, 1)) {
LOG_WARNING(
@@ -498,19 +498,6 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR
loaded_extensions.erase(VK_EXT_EXTENDED_DYNAMIC_STATE_2_EXTENSION_NAME);
}
}
if (extensions.extended_dynamic_state2 && is_qualcomm) {
const u32 version = (properties.properties.driverVersion << 3) >> 3;
if (version >= VK_MAKE_API_VERSION(0, 0, 676, 0)) {
// Qualcomm Adreno 7xx drivers do not properly support extended_dynamic_state2.
LOG_WARNING(Render_Vulkan,
"Qualcomm Adreno 7xx drivers have broken VK_EXT_extended_dynamic_state2");
features.extended_dynamic_state2.extendedDynamicState2 = false;
features.extended_dynamic_state2.extendedDynamicState2LogicOp = false;
features.extended_dynamic_state2.extendedDynamicState2PatchControlPoints = false;
extensions.extended_dynamic_state2 = false;
loaded_extensions.erase(VK_EXT_EXTENDED_DYNAMIC_STATE_2_EXTENSION_NAME);
}
}
if (extensions.extended_dynamic_state3 && is_radv) {
LOG_WARNING(Render_Vulkan, "RADV has broken extendedDynamicState3ColorBlendEquation");
features.extended_dynamic_state3.extendedDynamicState3ColorBlendEnable = false;
@@ -525,7 +512,8 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR
dynamic_state3_enables = false;
}
}
if (extensions.vertex_input_dynamic_state && is_radv) {
if (extensions.vertex_input_dynamic_state && (is_radv || is_qualcomm)) {
// Qualcomm S8gen2 drivers do not properly support vertex_input_dynamic_state.
// TODO(ameerj): Blacklist only offending driver versions
// TODO(ameerj): Confirm if RDNA1 is affected
const bool is_rdna2 =
@@ -538,20 +526,16 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR
loaded_extensions.erase(VK_EXT_VERTEX_INPUT_DYNAMIC_STATE_EXTENSION_NAME);
}
}
if (extensions.vertex_input_dynamic_state && is_qualcomm) {
const u32 version = (properties.properties.driverVersion << 3) >> 3;
if (version >= VK_MAKE_API_VERSION(0, 0, 676, 0)) {
// Qualcomm Adreno 7xx drivers do not properly support vertex_input_dynamic_state.
LOG_WARNING(
Render_Vulkan,
"Qualcomm Adreno 7xx drivers have broken VK_EXT_vertex_input_dynamic_state");
features.vertex_input_dynamic_state.vertexInputDynamicState = false;
extensions.vertex_input_dynamic_state = false;
loaded_extensions.erase(VK_EXT_VERTEX_INPUT_DYNAMIC_STATE_EXTENSION_NAME);
}
}
sets_per_pool = 64;
if (extensions.extended_dynamic_state3 && is_amd_driver &&
properties.properties.driverVersion >= VK_MAKE_API_VERSION(0, 2, 0, 270)) {
LOG_WARNING(Render_Vulkan,
"AMD drivers after 23.5.2 have broken extendedDynamicState3ColorBlendEquation");
features.extended_dynamic_state3.extendedDynamicState3ColorBlendEnable = false;
features.extended_dynamic_state3.extendedDynamicState3ColorBlendEquation = false;
dynamic_state3_blending = false;
}
if (is_amd_driver) {
// AMD drivers need a higher amount of Sets per Pool in certain circumstances like in XC2.
sets_per_pool = 96;

View File

@@ -305,6 +305,9 @@ void ConfigureRingController::EnableRingController() {
QMessageBox::warning(this, dialog_title,
tr("The current mapped device doesn't have a ring attached"));
break;
case Common::Input::DriverResult::InvalidHandle:
QMessageBox::warning(this, dialog_title, tr("The current mapped device is not connected"));
break;
default:
QMessageBox::warning(this, dialog_title,
tr("Unexpected driver result %1").arg(static_cast<int>(result)));