diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/core/CMakeLists.txt | 2 | ||||
| -rw-r--r-- | src/core/hle/service/nfc/mifare_user.cpp | 400 | ||||
| -rw-r--r-- | src/core/hle/service/nfc/mifare_user.h | 52 | ||||
| -rw-r--r-- | src/core/hle/service/nfc/nfc.cpp | 27 | ||||
| -rw-r--r-- | src/core/hle/service/nfc/nfc_device.cpp | 84 | ||||
| -rw-r--r-- | src/core/hle/service/nfc/nfc_device.h | 13 | ||||
| -rw-r--r-- | src/core/hle/service/nfc/nfc_result.h | 8 | ||||
| -rw-r--r-- | src/core/hle/service/nfc/nfc_user.cpp | 4 | ||||
| -rw-r--r-- | src/core/hle/service/nfp/nfp_types.h | 46 | ||||
| -rw-r--r-- | src/input_common/drivers/virtual_amiibo.cpp | 38 | ||||
| -rw-r--r-- | src/input_common/drivers/virtual_amiibo.h | 7 | ||||
| -rw-r--r-- | src/video_core/engines/maxwell_3d.cpp | 68 |
12 files changed, 668 insertions, 81 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index ad8b8ef95..c6b5ac196 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt | |||
| @@ -528,6 +528,8 @@ add_library(core STATIC | |||
| 528 | hle/service/mnpp/mnpp_app.h | 528 | hle/service/mnpp/mnpp_app.h |
| 529 | hle/service/ncm/ncm.cpp | 529 | hle/service/ncm/ncm.cpp |
| 530 | hle/service/ncm/ncm.h | 530 | hle/service/ncm/ncm.h |
| 531 | hle/service/nfc/mifare_user.cpp | ||
| 532 | hle/service/nfc/mifare_user.h | ||
| 531 | hle/service/nfc/nfc.cpp | 533 | hle/service/nfc/nfc.cpp |
| 532 | hle/service/nfc/nfc.h | 534 | hle/service/nfc/nfc.h |
| 533 | hle/service/nfc/nfc_device.cpp | 535 | hle/service/nfc/nfc_device.cpp |
diff --git a/src/core/hle/service/nfc/mifare_user.cpp b/src/core/hle/service/nfc/mifare_user.cpp new file mode 100644 index 000000000..51523a3ae --- /dev/null +++ b/src/core/hle/service/nfc/mifare_user.cpp | |||
| @@ -0,0 +1,400 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include "common/logging/log.h" | ||
| 5 | #include "core/core.h" | ||
| 6 | #include "core/hid/hid_types.h" | ||
| 7 | #include "core/hle/ipc_helpers.h" | ||
| 8 | #include "core/hle/kernel/k_event.h" | ||
| 9 | #include "core/hle/service/nfc/mifare_user.h" | ||
| 10 | #include "core/hle/service/nfc/nfc_device.h" | ||
| 11 | #include "core/hle/service/nfc/nfc_result.h" | ||
| 12 | |||
| 13 | namespace Service::NFC { | ||
| 14 | |||
| 15 | MFIUser::MFIUser(Core::System& system_) | ||
| 16 | : ServiceFramework{system_, "NFC::MFIUser"}, service_context{system_, service_name} { | ||
| 17 | static const FunctionInfo functions[] = { | ||
| 18 | {0, &MFIUser::Initialize, "Initialize"}, | ||
| 19 | {1, &MFIUser::Finalize, "Finalize"}, | ||
| 20 | {2, &MFIUser::ListDevices, "ListDevices"}, | ||
| 21 | {3, &MFIUser::StartDetection, "StartDetection"}, | ||
| 22 | {4, &MFIUser::StopDetection, "StopDetection"}, | ||
| 23 | {5, &MFIUser::Read, "Read"}, | ||
| 24 | {6, &MFIUser::Write, "Write"}, | ||
| 25 | {7, &MFIUser::GetTagInfo, "GetTagInfo"}, | ||
| 26 | {8, &MFIUser::GetActivateEventHandle, "GetActivateEventHandle"}, | ||
| 27 | {9, &MFIUser::GetDeactivateEventHandle, "GetDeactivateEventHandle"}, | ||
| 28 | {10, &MFIUser::GetState, "GetState"}, | ||
| 29 | {11, &MFIUser::GetDeviceState, "GetDeviceState"}, | ||
| 30 | {12, &MFIUser::GetNpadId, "GetNpadId"}, | ||
| 31 | {13, &MFIUser::GetAvailabilityChangeEventHandle, "GetAvailabilityChangeEventHandle"}, | ||
| 32 | }; | ||
| 33 | RegisterHandlers(functions); | ||
| 34 | |||
| 35 | availability_change_event = service_context.CreateEvent("MFIUser:AvailabilityChangeEvent"); | ||
| 36 | |||
| 37 | for (u32 device_index = 0; device_index < 10; device_index++) { | ||
| 38 | devices[device_index] = | ||
| 39 | std::make_shared<NfcDevice>(Core::HID::IndexToNpadIdType(device_index), system, | ||
| 40 | service_context, availability_change_event); | ||
| 41 | } | ||
| 42 | } | ||
| 43 | |||
| 44 | MFIUser ::~MFIUser() { | ||
| 45 | availability_change_event->Close(); | ||
| 46 | } | ||
| 47 | |||
| 48 | void MFIUser::Initialize(Kernel::HLERequestContext& ctx) { | ||
| 49 | LOG_INFO(Service_NFC, "called"); | ||
| 50 | |||
| 51 | state = State::Initialized; | ||
| 52 | |||
| 53 | for (auto& device : devices) { | ||
| 54 | device->Initialize(); | ||
| 55 | } | ||
| 56 | |||
| 57 | IPC::ResponseBuilder rb{ctx, 2, 0}; | ||
| 58 | rb.Push(ResultSuccess); | ||
| 59 | } | ||
| 60 | |||
| 61 | void MFIUser::Finalize(Kernel::HLERequestContext& ctx) { | ||
| 62 | LOG_INFO(Service_NFC, "called"); | ||
| 63 | |||
| 64 | state = State::NonInitialized; | ||
| 65 | |||
| 66 | for (auto& device : devices) { | ||
| 67 | device->Finalize(); | ||
| 68 | } | ||
| 69 | |||
| 70 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 71 | rb.Push(ResultSuccess); | ||
| 72 | } | ||
| 73 | |||
| 74 | void MFIUser::ListDevices(Kernel::HLERequestContext& ctx) { | ||
| 75 | LOG_DEBUG(Service_NFC, "called"); | ||
| 76 | |||
| 77 | if (state == State::NonInitialized) { | ||
| 78 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 79 | rb.Push(MifareNfcDisabled); | ||
| 80 | return; | ||
| 81 | } | ||
| 82 | |||
| 83 | if (!ctx.CanWriteBuffer()) { | ||
| 84 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 85 | rb.Push(MifareInvalidArgument); | ||
| 86 | return; | ||
| 87 | } | ||
| 88 | |||
| 89 | if (ctx.GetWriteBufferSize() == 0) { | ||
| 90 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 91 | rb.Push(MifareInvalidArgument); | ||
| 92 | return; | ||
| 93 | } | ||
| 94 | |||
| 95 | std::vector<u64> nfp_devices; | ||
| 96 | const std::size_t max_allowed_devices = ctx.GetWriteBufferNumElements<u64>(); | ||
| 97 | |||
| 98 | for (const auto& device : devices) { | ||
| 99 | if (nfp_devices.size() >= max_allowed_devices) { | ||
| 100 | continue; | ||
| 101 | } | ||
| 102 | if (device->GetCurrentState() != NFP::DeviceState::Unavailable) { | ||
| 103 | nfp_devices.push_back(device->GetHandle()); | ||
| 104 | } | ||
| 105 | } | ||
| 106 | |||
| 107 | if (nfp_devices.empty()) { | ||
| 108 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 109 | rb.Push(MifareDeviceNotFound); | ||
| 110 | return; | ||
| 111 | } | ||
| 112 | |||
| 113 | ctx.WriteBuffer(nfp_devices); | ||
| 114 | |||
| 115 | IPC::ResponseBuilder rb{ctx, 3}; | ||
| 116 | rb.Push(ResultSuccess); | ||
| 117 | rb.Push(static_cast<s32>(nfp_devices.size())); | ||
| 118 | } | ||
| 119 | |||
| 120 | void MFIUser::StartDetection(Kernel::HLERequestContext& ctx) { | ||
| 121 | IPC::RequestParser rp{ctx}; | ||
| 122 | const auto device_handle{rp.Pop<u64>()}; | ||
| 123 | LOG_INFO(Service_NFC, "called, device_handle={}", device_handle); | ||
| 124 | |||
| 125 | if (state == State::NonInitialized) { | ||
| 126 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 127 | rb.Push(MifareNfcDisabled); | ||
| 128 | return; | ||
| 129 | } | ||
| 130 | |||
| 131 | auto device = GetNfcDevice(device_handle); | ||
| 132 | |||
| 133 | if (!device.has_value()) { | ||
| 134 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 135 | rb.Push(MifareDeviceNotFound); | ||
| 136 | return; | ||
| 137 | } | ||
| 138 | |||
| 139 | const auto result = device.value()->StartDetection(NFP::TagProtocol::All); | ||
| 140 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 141 | rb.Push(result); | ||
| 142 | } | ||
| 143 | |||
| 144 | void MFIUser::StopDetection(Kernel::HLERequestContext& ctx) { | ||
| 145 | IPC::RequestParser rp{ctx}; | ||
| 146 | const auto device_handle{rp.Pop<u64>()}; | ||
| 147 | LOG_INFO(Service_NFC, "called, device_handle={}", device_handle); | ||
| 148 | |||
| 149 | if (state == State::NonInitialized) { | ||
| 150 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 151 | rb.Push(MifareNfcDisabled); | ||
| 152 | return; | ||
| 153 | } | ||
| 154 | |||
| 155 | auto device = GetNfcDevice(device_handle); | ||
| 156 | |||
| 157 | if (!device.has_value()) { | ||
| 158 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 159 | rb.Push(MifareDeviceNotFound); | ||
| 160 | return; | ||
| 161 | } | ||
| 162 | |||
| 163 | const auto result = device.value()->StopDetection(); | ||
| 164 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 165 | rb.Push(result); | ||
| 166 | } | ||
| 167 | |||
| 168 | void MFIUser::Read(Kernel::HLERequestContext& ctx) { | ||
| 169 | IPC::RequestParser rp{ctx}; | ||
| 170 | const auto device_handle{rp.Pop<u64>()}; | ||
| 171 | const auto buffer{ctx.ReadBuffer()}; | ||
| 172 | const auto number_of_commands{ctx.GetReadBufferNumElements<NFP::MifareReadBlockParameter>()}; | ||
| 173 | std::vector<NFP::MifareReadBlockParameter> read_commands(number_of_commands); | ||
| 174 | |||
| 175 | memcpy(read_commands.data(), buffer.data(), | ||
| 176 | number_of_commands * sizeof(NFP::MifareReadBlockParameter)); | ||
| 177 | |||
| 178 | LOG_INFO(Service_NFC, "(STUBBED) called, device_handle={}, read_commands_size={}", | ||
| 179 | device_handle, number_of_commands); | ||
| 180 | |||
| 181 | if (state == State::NonInitialized) { | ||
| 182 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 183 | rb.Push(MifareNfcDisabled); | ||
| 184 | return; | ||
| 185 | } | ||
| 186 | |||
| 187 | auto device = GetNfcDevice(device_handle); | ||
| 188 | |||
| 189 | if (!device.has_value()) { | ||
| 190 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 191 | rb.Push(MifareDeviceNotFound); | ||
| 192 | return; | ||
| 193 | } | ||
| 194 | |||
| 195 | Result result = ResultSuccess; | ||
| 196 | std::vector<NFP::MifareReadBlockData> out_data(number_of_commands); | ||
| 197 | for (std::size_t i = 0; i < number_of_commands; i++) { | ||
| 198 | result = device.value()->MifareRead(read_commands[i], out_data[i]); | ||
| 199 | if (result.IsError()) { | ||
| 200 | break; | ||
| 201 | } | ||
| 202 | } | ||
| 203 | |||
| 204 | ctx.WriteBuffer(out_data); | ||
| 205 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 206 | rb.Push(result); | ||
| 207 | } | ||
| 208 | |||
| 209 | void MFIUser::Write(Kernel::HLERequestContext& ctx) { | ||
| 210 | IPC::RequestParser rp{ctx}; | ||
| 211 | const auto device_handle{rp.Pop<u64>()}; | ||
| 212 | const auto buffer{ctx.ReadBuffer()}; | ||
| 213 | const auto number_of_commands{ctx.GetReadBufferNumElements<NFP::MifareWriteBlockParameter>()}; | ||
| 214 | std::vector<NFP::MifareWriteBlockParameter> write_commands(number_of_commands); | ||
| 215 | |||
| 216 | memcpy(write_commands.data(), buffer.data(), | ||
| 217 | number_of_commands * sizeof(NFP::MifareWriteBlockParameter)); | ||
| 218 | |||
| 219 | LOG_INFO(Service_NFC, "(STUBBED) called, device_handle={}, write_commands_size={}", | ||
| 220 | device_handle, number_of_commands); | ||
| 221 | |||
| 222 | if (state == State::NonInitialized) { | ||
| 223 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 224 | rb.Push(MifareNfcDisabled); | ||
| 225 | return; | ||
| 226 | } | ||
| 227 | |||
| 228 | auto device = GetNfcDevice(device_handle); | ||
| 229 | |||
| 230 | if (!device.has_value()) { | ||
| 231 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 232 | rb.Push(MifareDeviceNotFound); | ||
| 233 | return; | ||
| 234 | } | ||
| 235 | |||
| 236 | Result result = ResultSuccess; | ||
| 237 | std::vector<NFP::MifareReadBlockData> out_data(number_of_commands); | ||
| 238 | for (std::size_t i = 0; i < number_of_commands; i++) { | ||
| 239 | result = device.value()->MifareWrite(write_commands[i]); | ||
| 240 | if (result.IsError()) { | ||
| 241 | break; | ||
| 242 | } | ||
| 243 | } | ||
| 244 | |||
| 245 | if (result.IsSuccess()) { | ||
| 246 | result = device.value()->Flush(); | ||
| 247 | } | ||
| 248 | |||
| 249 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 250 | rb.Push(result); | ||
| 251 | } | ||
| 252 | |||
| 253 | void MFIUser::GetTagInfo(Kernel::HLERequestContext& ctx) { | ||
| 254 | IPC::RequestParser rp{ctx}; | ||
| 255 | const auto device_handle{rp.Pop<u64>()}; | ||
| 256 | LOG_INFO(Service_NFC, "called, device_handle={}", device_handle); | ||
| 257 | |||
| 258 | if (state == State::NonInitialized) { | ||
| 259 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 260 | rb.Push(MifareNfcDisabled); | ||
| 261 | return; | ||
| 262 | } | ||
| 263 | |||
| 264 | auto device = GetNfcDevice(device_handle); | ||
| 265 | |||
| 266 | if (!device.has_value()) { | ||
| 267 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 268 | rb.Push(MifareDeviceNotFound); | ||
| 269 | return; | ||
| 270 | } | ||
| 271 | |||
| 272 | NFP::TagInfo tag_info{}; | ||
| 273 | const auto result = device.value()->GetTagInfo(tag_info, true); | ||
| 274 | ctx.WriteBuffer(tag_info); | ||
| 275 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 276 | rb.Push(result); | ||
| 277 | } | ||
| 278 | |||
| 279 | void MFIUser::GetActivateEventHandle(Kernel::HLERequestContext& ctx) { | ||
| 280 | IPC::RequestParser rp{ctx}; | ||
| 281 | const auto device_handle{rp.Pop<u64>()}; | ||
| 282 | LOG_DEBUG(Service_NFC, "called, device_handle={}", device_handle); | ||
| 283 | |||
| 284 | if (state == State::NonInitialized) { | ||
| 285 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 286 | rb.Push(MifareNfcDisabled); | ||
| 287 | return; | ||
| 288 | } | ||
| 289 | |||
| 290 | auto device = GetNfcDevice(device_handle); | ||
| 291 | |||
| 292 | if (!device.has_value()) { | ||
| 293 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 294 | rb.Push(MifareDeviceNotFound); | ||
| 295 | return; | ||
| 296 | } | ||
| 297 | |||
| 298 | IPC::ResponseBuilder rb{ctx, 2, 1}; | ||
| 299 | rb.Push(ResultSuccess); | ||
| 300 | rb.PushCopyObjects(device.value()->GetActivateEvent()); | ||
| 301 | } | ||
| 302 | |||
| 303 | void MFIUser::GetDeactivateEventHandle(Kernel::HLERequestContext& ctx) { | ||
| 304 | IPC::RequestParser rp{ctx}; | ||
| 305 | const auto device_handle{rp.Pop<u64>()}; | ||
| 306 | LOG_DEBUG(Service_NFC, "called, device_handle={}", device_handle); | ||
| 307 | |||
| 308 | if (state == State::NonInitialized) { | ||
| 309 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 310 | rb.Push(MifareNfcDisabled); | ||
| 311 | return; | ||
| 312 | } | ||
| 313 | |||
| 314 | auto device = GetNfcDevice(device_handle); | ||
| 315 | |||
| 316 | if (!device.has_value()) { | ||
| 317 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 318 | rb.Push(MifareDeviceNotFound); | ||
| 319 | return; | ||
| 320 | } | ||
| 321 | |||
| 322 | IPC::ResponseBuilder rb{ctx, 2, 1}; | ||
| 323 | rb.Push(ResultSuccess); | ||
| 324 | rb.PushCopyObjects(device.value()->GetDeactivateEvent()); | ||
| 325 | } | ||
| 326 | |||
| 327 | void MFIUser::GetState(Kernel::HLERequestContext& ctx) { | ||
| 328 | LOG_DEBUG(Service_NFC, "called"); | ||
| 329 | |||
| 330 | IPC::ResponseBuilder rb{ctx, 3}; | ||
| 331 | rb.Push(ResultSuccess); | ||
| 332 | rb.PushEnum(state); | ||
| 333 | } | ||
| 334 | |||
| 335 | void MFIUser::GetDeviceState(Kernel::HLERequestContext& ctx) { | ||
| 336 | IPC::RequestParser rp{ctx}; | ||
| 337 | const auto device_handle{rp.Pop<u64>()}; | ||
| 338 | LOG_DEBUG(Service_NFC, "called, device_handle={}", device_handle); | ||
| 339 | |||
| 340 | auto device = GetNfcDevice(device_handle); | ||
| 341 | |||
| 342 | if (!device.has_value()) { | ||
| 343 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 344 | rb.Push(MifareDeviceNotFound); | ||
| 345 | return; | ||
| 346 | } | ||
| 347 | |||
| 348 | IPC::ResponseBuilder rb{ctx, 3}; | ||
| 349 | rb.Push(ResultSuccess); | ||
| 350 | rb.PushEnum(device.value()->GetCurrentState()); | ||
| 351 | } | ||
| 352 | |||
| 353 | void MFIUser::GetNpadId(Kernel::HLERequestContext& ctx) { | ||
| 354 | IPC::RequestParser rp{ctx}; | ||
| 355 | const auto device_handle{rp.Pop<u64>()}; | ||
| 356 | LOG_DEBUG(Service_NFC, "called, device_handle={}", device_handle); | ||
| 357 | |||
| 358 | if (state == State::NonInitialized) { | ||
| 359 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 360 | rb.Push(MifareNfcDisabled); | ||
| 361 | return; | ||
| 362 | } | ||
| 363 | |||
| 364 | auto device = GetNfcDevice(device_handle); | ||
| 365 | |||
| 366 | if (!device.has_value()) { | ||
| 367 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 368 | rb.Push(MifareDeviceNotFound); | ||
| 369 | return; | ||
| 370 | } | ||
| 371 | |||
| 372 | IPC::ResponseBuilder rb{ctx, 3}; | ||
| 373 | rb.Push(ResultSuccess); | ||
| 374 | rb.PushEnum(device.value()->GetNpadId()); | ||
| 375 | } | ||
| 376 | |||
| 377 | void MFIUser::GetAvailabilityChangeEventHandle(Kernel::HLERequestContext& ctx) { | ||
| 378 | LOG_INFO(Service_NFC, "called"); | ||
| 379 | |||
| 380 | if (state == State::NonInitialized) { | ||
| 381 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 382 | rb.Push(MifareNfcDisabled); | ||
| 383 | return; | ||
| 384 | } | ||
| 385 | |||
| 386 | IPC::ResponseBuilder rb{ctx, 2, 1}; | ||
| 387 | rb.Push(ResultSuccess); | ||
| 388 | rb.PushCopyObjects(availability_change_event->GetReadableEvent()); | ||
| 389 | } | ||
| 390 | |||
| 391 | std::optional<std::shared_ptr<NfcDevice>> MFIUser::GetNfcDevice(u64 handle) { | ||
| 392 | for (auto& device : devices) { | ||
| 393 | if (device->GetHandle() == handle) { | ||
| 394 | return device; | ||
| 395 | } | ||
| 396 | } | ||
| 397 | return std::nullopt; | ||
| 398 | } | ||
| 399 | |||
| 400 | } // namespace Service::NFC | ||
diff --git a/src/core/hle/service/nfc/mifare_user.h b/src/core/hle/service/nfc/mifare_user.h new file mode 100644 index 000000000..0e0638cb6 --- /dev/null +++ b/src/core/hle/service/nfc/mifare_user.h | |||
| @@ -0,0 +1,52 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include <array> | ||
| 7 | #include <memory> | ||
| 8 | #include <optional> | ||
| 9 | |||
| 10 | #include "core/hle/service/kernel_helpers.h" | ||
| 11 | #include "core/hle/service/service.h" | ||
| 12 | |||
| 13 | namespace Service::NFC { | ||
| 14 | class NfcDevice; | ||
| 15 | |||
| 16 | class MFIUser final : public ServiceFramework<MFIUser> { | ||
| 17 | public: | ||
| 18 | explicit MFIUser(Core::System& system_); | ||
| 19 | ~MFIUser(); | ||
| 20 | |||
| 21 | private: | ||
| 22 | enum class State : u32 { | ||
| 23 | NonInitialized, | ||
| 24 | Initialized, | ||
| 25 | }; | ||
| 26 | |||
| 27 | void Initialize(Kernel::HLERequestContext& ctx); | ||
| 28 | void Finalize(Kernel::HLERequestContext& ctx); | ||
| 29 | void ListDevices(Kernel::HLERequestContext& ctx); | ||
| 30 | void StartDetection(Kernel::HLERequestContext& ctx); | ||
| 31 | void StopDetection(Kernel::HLERequestContext& ctx); | ||
| 32 | void Read(Kernel::HLERequestContext& ctx); | ||
| 33 | void Write(Kernel::HLERequestContext& ctx); | ||
| 34 | void GetTagInfo(Kernel::HLERequestContext& ctx); | ||
| 35 | void GetActivateEventHandle(Kernel::HLERequestContext& ctx); | ||
| 36 | void GetDeactivateEventHandle(Kernel::HLERequestContext& ctx); | ||
| 37 | void GetState(Kernel::HLERequestContext& ctx); | ||
| 38 | void GetDeviceState(Kernel::HLERequestContext& ctx); | ||
| 39 | void GetNpadId(Kernel::HLERequestContext& ctx); | ||
| 40 | void GetAvailabilityChangeEventHandle(Kernel::HLERequestContext& ctx); | ||
| 41 | |||
| 42 | std::optional<std::shared_ptr<NfcDevice>> GetNfcDevice(u64 handle); | ||
| 43 | |||
| 44 | KernelHelpers::ServiceContext service_context; | ||
| 45 | |||
| 46 | std::array<std::shared_ptr<NfcDevice>, 10> devices{}; | ||
| 47 | |||
| 48 | State state{State::NonInitialized}; | ||
| 49 | Kernel::KEvent* availability_change_event; | ||
| 50 | }; | ||
| 51 | |||
| 52 | } // namespace Service::NFC | ||
diff --git a/src/core/hle/service/nfc/nfc.cpp b/src/core/hle/service/nfc/nfc.cpp index 2f4bacb3b..b17b18ab9 100644 --- a/src/core/hle/service/nfc/nfc.cpp +++ b/src/core/hle/service/nfc/nfc.cpp | |||
| @@ -6,6 +6,7 @@ | |||
| 6 | #include "common/logging/log.h" | 6 | #include "common/logging/log.h" |
| 7 | #include "common/settings.h" | 7 | #include "common/settings.h" |
| 8 | #include "core/hle/ipc_helpers.h" | 8 | #include "core/hle/ipc_helpers.h" |
| 9 | #include "core/hle/service/nfc/mifare_user.h" | ||
| 9 | #include "core/hle/service/nfc/nfc.h" | 10 | #include "core/hle/service/nfc/nfc.h" |
| 10 | #include "core/hle/service/nfc/nfc_user.h" | 11 | #include "core/hle/service/nfc/nfc_user.h" |
| 11 | #include "core/hle/service/service.h" | 12 | #include "core/hle/service/service.h" |
| @@ -50,32 +51,6 @@ private: | |||
| 50 | } | 51 | } |
| 51 | }; | 52 | }; |
| 52 | 53 | ||
| 53 | class MFIUser final : public ServiceFramework<MFIUser> { | ||
| 54 | public: | ||
| 55 | explicit MFIUser(Core::System& system_) : ServiceFramework{system_, "NFC::MFIUser"} { | ||
| 56 | // clang-format off | ||
| 57 | static const FunctionInfo functions[] = { | ||
| 58 | {0, nullptr, "Initialize"}, | ||
| 59 | {1, nullptr, "Finalize"}, | ||
| 60 | {2, nullptr, "ListDevices"}, | ||
| 61 | {3, nullptr, "StartDetection"}, | ||
| 62 | {4, nullptr, "StopDetection"}, | ||
| 63 | {5, nullptr, "Read"}, | ||
| 64 | {6, nullptr, "Write"}, | ||
| 65 | {7, nullptr, "GetTagInfo"}, | ||
| 66 | {8, nullptr, "GetActivateEventHandle"}, | ||
| 67 | {9, nullptr, "GetDeactivateEventHandle"}, | ||
| 68 | {10, nullptr, "GetState"}, | ||
| 69 | {11, nullptr, "GetDeviceState"}, | ||
| 70 | {12, nullptr, "GetNpadId"}, | ||
| 71 | {13, nullptr, "GetAvailabilityChangeEventHandle"}, | ||
| 72 | }; | ||
| 73 | // clang-format on | ||
| 74 | |||
| 75 | RegisterHandlers(functions); | ||
| 76 | } | ||
| 77 | }; | ||
| 78 | |||
| 79 | class NFC_MF_U final : public ServiceFramework<NFC_MF_U> { | 54 | class NFC_MF_U final : public ServiceFramework<NFC_MF_U> { |
| 80 | public: | 55 | public: |
| 81 | explicit NFC_MF_U(Core::System& system_) : ServiceFramework{system_, "nfc:mf:u"} { | 56 | explicit NFC_MF_U(Core::System& system_) : ServiceFramework{system_, "nfc:mf:u"} { |
diff --git a/src/core/hle/service/nfc/nfc_device.cpp b/src/core/hle/service/nfc/nfc_device.cpp index 4d514cf5f..78578f723 100644 --- a/src/core/hle/service/nfc/nfc_device.cpp +++ b/src/core/hle/service/nfc/nfc_device.cpp | |||
| @@ -77,11 +77,13 @@ bool NfcDevice::LoadNfcTag(std::span<const u8> data) { | |||
| 77 | return false; | 77 | return false; |
| 78 | } | 78 | } |
| 79 | 79 | ||
| 80 | if (data.size() != sizeof(NFP::EncryptedNTAG215File)) { | 80 | if (data.size() < sizeof(NFP::EncryptedNTAG215File)) { |
| 81 | LOG_ERROR(Service_NFC, "Not an amiibo, size={}", data.size()); | 81 | LOG_ERROR(Service_NFC, "Not an amiibo, size={}", data.size()); |
| 82 | return false; | 82 | return false; |
| 83 | } | 83 | } |
| 84 | 84 | ||
| 85 | tag_data.resize(data.size()); | ||
| 86 | memcpy(tag_data.data(), data.data(), data.size()); | ||
| 85 | memcpy(&encrypted_tag_data, data.data(), sizeof(NFP::EncryptedNTAG215File)); | 87 | memcpy(&encrypted_tag_data, data.data(), sizeof(NFP::EncryptedNTAG215File)); |
| 86 | 88 | ||
| 87 | device_state = NFP::DeviceState::TagFound; | 89 | device_state = NFP::DeviceState::TagFound; |
| @@ -121,7 +123,7 @@ void NfcDevice::Finalize() { | |||
| 121 | device_state = NFP::DeviceState::Unavailable; | 123 | device_state = NFP::DeviceState::Unavailable; |
| 122 | } | 124 | } |
| 123 | 125 | ||
| 124 | Result NfcDevice::StartDetection(s32 protocol_) { | 126 | Result NfcDevice::StartDetection(NFP::TagProtocol allowed_protocol) { |
| 125 | if (device_state != NFP::DeviceState::Initialized && | 127 | if (device_state != NFP::DeviceState::Initialized && |
| 126 | device_state != NFP::DeviceState::TagRemoved) { | 128 | device_state != NFP::DeviceState::TagRemoved) { |
| 127 | LOG_ERROR(Service_NFC, "Wrong device state {}", device_state); | 129 | LOG_ERROR(Service_NFC, "Wrong device state {}", device_state); |
| @@ -134,7 +136,7 @@ Result NfcDevice::StartDetection(s32 protocol_) { | |||
| 134 | } | 136 | } |
| 135 | 137 | ||
| 136 | device_state = NFP::DeviceState::SearchingForTag; | 138 | device_state = NFP::DeviceState::SearchingForTag; |
| 137 | protocol = protocol_; | 139 | allowed_protocols = allowed_protocol; |
| 138 | return ResultSuccess; | 140 | return ResultSuccess; |
| 139 | } | 141 | } |
| 140 | 142 | ||
| @@ -160,7 +162,7 @@ Result NfcDevice::StopDetection() { | |||
| 160 | return WrongDeviceState; | 162 | return WrongDeviceState; |
| 161 | } | 163 | } |
| 162 | 164 | ||
| 163 | Result NfcDevice::GetTagInfo(NFP::TagInfo& tag_info) const { | 165 | Result NfcDevice::Flush() { |
| 164 | if (device_state != NFP::DeviceState::TagFound && | 166 | if (device_state != NFP::DeviceState::TagFound && |
| 165 | device_state != NFP::DeviceState::TagMounted) { | 167 | device_state != NFP::DeviceState::TagMounted) { |
| 166 | LOG_ERROR(Service_NFC, "Wrong device state {}", device_state); | 168 | LOG_ERROR(Service_NFC, "Wrong device state {}", device_state); |
| @@ -170,6 +172,34 @@ Result NfcDevice::GetTagInfo(NFP::TagInfo& tag_info) const { | |||
| 170 | return WrongDeviceState; | 172 | return WrongDeviceState; |
| 171 | } | 173 | } |
| 172 | 174 | ||
| 175 | if (!npad_device->WriteNfc(tag_data)) { | ||
| 176 | LOG_ERROR(Service_NFP, "Error writing to file"); | ||
| 177 | return MifareReadError; | ||
| 178 | } | ||
| 179 | |||
| 180 | return ResultSuccess; | ||
| 181 | } | ||
| 182 | |||
| 183 | Result NfcDevice::GetTagInfo(NFP::TagInfo& tag_info, bool is_mifare) const { | ||
| 184 | if (device_state != NFP::DeviceState::TagFound && | ||
| 185 | device_state != NFP::DeviceState::TagMounted) { | ||
| 186 | LOG_ERROR(Service_NFC, "Wrong device state {}", device_state); | ||
| 187 | if (device_state == NFP::DeviceState::TagRemoved) { | ||
| 188 | return TagRemoved; | ||
| 189 | } | ||
| 190 | return WrongDeviceState; | ||
| 191 | } | ||
| 192 | |||
| 193 | if (is_mifare) { | ||
| 194 | tag_info = { | ||
| 195 | .uuid = encrypted_tag_data.uuid.uid, | ||
| 196 | .uuid_length = static_cast<u8>(encrypted_tag_data.uuid.uid.size()), | ||
| 197 | .protocol = NFP::TagProtocol::TypeA, | ||
| 198 | .tag_type = NFP::TagType::Type4, | ||
| 199 | }; | ||
| 200 | return ResultSuccess; | ||
| 201 | } | ||
| 202 | |||
| 173 | // Protocol and tag type may change here | 203 | // Protocol and tag type may change here |
| 174 | tag_info = { | 204 | tag_info = { |
| 175 | .uuid = encrypted_tag_data.uuid.uid, | 205 | .uuid = encrypted_tag_data.uuid.uid, |
| @@ -181,6 +211,52 @@ Result NfcDevice::GetTagInfo(NFP::TagInfo& tag_info) const { | |||
| 181 | return ResultSuccess; | 211 | return ResultSuccess; |
| 182 | } | 212 | } |
| 183 | 213 | ||
| 214 | Result NfcDevice::MifareRead(const NFP::MifareReadBlockParameter& parameter, | ||
| 215 | NFP::MifareReadBlockData& read_block_data) { | ||
| 216 | const std::size_t sector_index = parameter.sector_number * sizeof(NFP::DataBlock); | ||
| 217 | read_block_data.sector_number = parameter.sector_number; | ||
| 218 | |||
| 219 | if (device_state != NFP::DeviceState::TagFound && | ||
| 220 | device_state != NFP::DeviceState::TagMounted) { | ||
| 221 | LOG_ERROR(Service_NFC, "Wrong device state {}", device_state); | ||
| 222 | if (device_state == NFP::DeviceState::TagRemoved) { | ||
| 223 | return TagRemoved; | ||
| 224 | } | ||
| 225 | return WrongDeviceState; | ||
| 226 | } | ||
| 227 | |||
| 228 | if (tag_data.size() < sector_index + sizeof(NFP::DataBlock)) { | ||
| 229 | return MifareReadError; | ||
| 230 | } | ||
| 231 | |||
| 232 | // TODO: Use parameter.sector_key to read encrypted data | ||
| 233 | memcpy(read_block_data.data.data(), tag_data.data() + sector_index, sizeof(NFP::DataBlock)); | ||
| 234 | |||
| 235 | return ResultSuccess; | ||
| 236 | } | ||
| 237 | |||
| 238 | Result NfcDevice::MifareWrite(const NFP::MifareWriteBlockParameter& parameter) { | ||
| 239 | const std::size_t sector_index = parameter.sector_number * sizeof(NFP::DataBlock); | ||
| 240 | |||
| 241 | if (device_state != NFP::DeviceState::TagFound && | ||
| 242 | device_state != NFP::DeviceState::TagMounted) { | ||
| 243 | LOG_ERROR(Service_NFC, "Wrong device state {}", device_state); | ||
| 244 | if (device_state == NFP::DeviceState::TagRemoved) { | ||
| 245 | return TagRemoved; | ||
| 246 | } | ||
| 247 | return WrongDeviceState; | ||
| 248 | } | ||
| 249 | |||
| 250 | if (tag_data.size() < sector_index + sizeof(NFP::DataBlock)) { | ||
| 251 | return MifareReadError; | ||
| 252 | } | ||
| 253 | |||
| 254 | // TODO: Use parameter.sector_key to encrypt the data | ||
| 255 | memcpy(tag_data.data() + sector_index, parameter.data.data(), sizeof(NFP::DataBlock)); | ||
| 256 | |||
| 257 | return ResultSuccess; | ||
| 258 | } | ||
| 259 | |||
| 184 | u64 NfcDevice::GetHandle() const { | 260 | u64 NfcDevice::GetHandle() const { |
| 185 | // Generate a handle based of the npad id | 261 | // Generate a handle based of the npad id |
| 186 | return static_cast<u64>(npad_id); | 262 | return static_cast<u64>(npad_id); |
diff --git a/src/core/hle/service/nfc/nfc_device.h b/src/core/hle/service/nfc/nfc_device.h index fa1348f1a..a6e114d36 100644 --- a/src/core/hle/service/nfc/nfc_device.h +++ b/src/core/hle/service/nfc/nfc_device.h | |||
| @@ -34,10 +34,16 @@ public: | |||
| 34 | void Initialize(); | 34 | void Initialize(); |
| 35 | void Finalize(); | 35 | void Finalize(); |
| 36 | 36 | ||
| 37 | Result StartDetection(s32 protocol_); | 37 | Result StartDetection(NFP::TagProtocol allowed_protocol); |
| 38 | Result StopDetection(); | 38 | Result StopDetection(); |
| 39 | Result Flush(); | ||
| 39 | 40 | ||
| 40 | Result GetTagInfo(NFP::TagInfo& tag_info) const; | 41 | Result GetTagInfo(NFP::TagInfo& tag_info, bool is_mifare) const; |
| 42 | |||
| 43 | Result MifareRead(const NFP::MifareReadBlockParameter& parameter, | ||
| 44 | NFP::MifareReadBlockData& read_block_data); | ||
| 45 | |||
| 46 | Result MifareWrite(const NFP::MifareWriteBlockParameter& parameter); | ||
| 41 | 47 | ||
| 42 | u64 GetHandle() const; | 48 | u64 GetHandle() const; |
| 43 | NFP::DeviceState GetCurrentState() const; | 49 | NFP::DeviceState GetCurrentState() const; |
| @@ -61,10 +67,11 @@ private: | |||
| 61 | Kernel::KEvent* deactivate_event = nullptr; | 67 | Kernel::KEvent* deactivate_event = nullptr; |
| 62 | Kernel::KEvent* availability_change_event = nullptr; | 68 | Kernel::KEvent* availability_change_event = nullptr; |
| 63 | 69 | ||
| 64 | s32 protocol{}; | 70 | NFP::TagProtocol allowed_protocols{}; |
| 65 | NFP::DeviceState device_state{NFP::DeviceState::Unavailable}; | 71 | NFP::DeviceState device_state{NFP::DeviceState::Unavailable}; |
| 66 | 72 | ||
| 67 | NFP::EncryptedNTAG215File encrypted_tag_data{}; | 73 | NFP::EncryptedNTAG215File encrypted_tag_data{}; |
| 74 | std::vector<u8> tag_data{}; | ||
| 68 | }; | 75 | }; |
| 69 | 76 | ||
| 70 | } // namespace Service::NFC | 77 | } // namespace Service::NFC |
diff --git a/src/core/hle/service/nfc/nfc_result.h b/src/core/hle/service/nfc/nfc_result.h index 537dc15f4..146b8ba61 100644 --- a/src/core/hle/service/nfc/nfc_result.h +++ b/src/core/hle/service/nfc/nfc_result.h | |||
| @@ -12,6 +12,12 @@ constexpr Result InvalidArgument(ErrorModule::NFC, 65); | |||
| 12 | constexpr Result WrongDeviceState(ErrorModule::NFC, 73); | 12 | constexpr Result WrongDeviceState(ErrorModule::NFC, 73); |
| 13 | constexpr Result NfcDisabled(ErrorModule::NFC, 80); | 13 | constexpr Result NfcDisabled(ErrorModule::NFC, 80); |
| 14 | constexpr Result TagRemoved(ErrorModule::NFC, 97); | 14 | constexpr Result TagRemoved(ErrorModule::NFC, 97); |
| 15 | constexpr Result CorruptedData(ErrorModule::NFC, 144); | 15 | |
| 16 | constexpr Result MifareDeviceNotFound(ErrorModule::NFCMifare, 64); | ||
| 17 | constexpr Result MifareInvalidArgument(ErrorModule::NFCMifare, 65); | ||
| 18 | constexpr Result MifareWrongDeviceState(ErrorModule::NFCMifare, 73); | ||
| 19 | constexpr Result MifareNfcDisabled(ErrorModule::NFCMifare, 80); | ||
| 20 | constexpr Result MifareTagRemoved(ErrorModule::NFCMifare, 97); | ||
| 21 | constexpr Result MifareReadError(ErrorModule::NFCMifare, 288); | ||
| 16 | 22 | ||
| 17 | } // namespace Service::NFC | 23 | } // namespace Service::NFC |
diff --git a/src/core/hle/service/nfc/nfc_user.cpp b/src/core/hle/service/nfc/nfc_user.cpp index ced2d560b..4615697e2 100644 --- a/src/core/hle/service/nfc/nfc_user.cpp +++ b/src/core/hle/service/nfc/nfc_user.cpp | |||
| @@ -201,7 +201,7 @@ void IUser::AttachAvailabilityChangeEvent(Kernel::HLERequestContext& ctx) { | |||
| 201 | void IUser::StartDetection(Kernel::HLERequestContext& ctx) { | 201 | void IUser::StartDetection(Kernel::HLERequestContext& ctx) { |
| 202 | IPC::RequestParser rp{ctx}; | 202 | IPC::RequestParser rp{ctx}; |
| 203 | const auto device_handle{rp.Pop<u64>()}; | 203 | const auto device_handle{rp.Pop<u64>()}; |
| 204 | const auto nfp_protocol{rp.Pop<s32>()}; | 204 | const auto nfp_protocol{rp.PopEnum<NFP::TagProtocol>()}; |
| 205 | LOG_INFO(Service_NFC, "called, device_handle={}, nfp_protocol={}", device_handle, nfp_protocol); | 205 | LOG_INFO(Service_NFC, "called, device_handle={}, nfp_protocol={}", device_handle, nfp_protocol); |
| 206 | 206 | ||
| 207 | if (state == State::NonInitialized) { | 207 | if (state == State::NonInitialized) { |
| @@ -267,7 +267,7 @@ void IUser::GetTagInfo(Kernel::HLERequestContext& ctx) { | |||
| 267 | } | 267 | } |
| 268 | 268 | ||
| 269 | NFP::TagInfo tag_info{}; | 269 | NFP::TagInfo tag_info{}; |
| 270 | const auto result = device.value()->GetTagInfo(tag_info); | 270 | const auto result = device.value()->GetTagInfo(tag_info, false); |
| 271 | ctx.WriteBuffer(tag_info); | 271 | ctx.WriteBuffer(tag_info); |
| 272 | IPC::ResponseBuilder rb{ctx, 2}; | 272 | IPC::ResponseBuilder rb{ctx, 2}; |
| 273 | rb.Push(result); | 273 | rb.Push(result); |
diff --git a/src/core/hle/service/nfp/nfp_types.h b/src/core/hle/service/nfp/nfp_types.h index 69858096a..fc228c2b2 100644 --- a/src/core/hle/service/nfp/nfp_types.h +++ b/src/core/hle/service/nfp/nfp_types.h | |||
| @@ -106,11 +106,24 @@ enum class CabinetMode : u8 { | |||
| 106 | StartFormatter, | 106 | StartFormatter, |
| 107 | }; | 107 | }; |
| 108 | 108 | ||
| 109 | enum class MifareCmd : u8 { | ||
| 110 | AuthA = 0x60, | ||
| 111 | AuthB = 0x61, | ||
| 112 | Read = 0x30, | ||
| 113 | Write = 0xA0, | ||
| 114 | Transfer = 0xB0, | ||
| 115 | Decrement = 0xC0, | ||
| 116 | Increment = 0xC1, | ||
| 117 | Store = 0xC2 | ||
| 118 | }; | ||
| 119 | |||
| 109 | using UniqueSerialNumber = std::array<u8, 7>; | 120 | using UniqueSerialNumber = std::array<u8, 7>; |
| 110 | using LockBytes = std::array<u8, 2>; | 121 | using LockBytes = std::array<u8, 2>; |
| 111 | using HashData = std::array<u8, 0x20>; | 122 | using HashData = std::array<u8, 0x20>; |
| 112 | using ApplicationArea = std::array<u8, 0xD8>; | 123 | using ApplicationArea = std::array<u8, 0xD8>; |
| 113 | using AmiiboName = std::array<char, (amiibo_name_length * 4) + 1>; | 124 | using AmiiboName = std::array<char, (amiibo_name_length * 4) + 1>; |
| 125 | using DataBlock = std::array<u8, 0x10>; | ||
| 126 | using KeyData = std::array<u8, 0x6>; | ||
| 114 | 127 | ||
| 115 | struct TagUuid { | 128 | struct TagUuid { |
| 116 | UniqueSerialNumber uid; | 129 | UniqueSerialNumber uid; |
| @@ -323,4 +336,37 @@ struct RegisterInfo { | |||
| 323 | }; | 336 | }; |
| 324 | static_assert(sizeof(RegisterInfo) == 0x100, "RegisterInfo is an invalid size"); | 337 | static_assert(sizeof(RegisterInfo) == 0x100, "RegisterInfo is an invalid size"); |
| 325 | 338 | ||
| 339 | struct SectorKey { | ||
| 340 | MifareCmd command; | ||
| 341 | u8 unknown; // Usually 1 | ||
| 342 | INSERT_PADDING_BYTES(0x6); | ||
| 343 | KeyData sector_key; | ||
| 344 | INSERT_PADDING_BYTES(0x2); | ||
| 345 | }; | ||
| 346 | static_assert(sizeof(SectorKey) == 0x10, "SectorKey is an invalid size"); | ||
| 347 | |||
| 348 | struct MifareReadBlockParameter { | ||
| 349 | u8 sector_number; | ||
| 350 | INSERT_PADDING_BYTES(0x7); | ||
| 351 | SectorKey sector_key; | ||
| 352 | }; | ||
| 353 | static_assert(sizeof(MifareReadBlockParameter) == 0x18, | ||
| 354 | "MifareReadBlockParameter is an invalid size"); | ||
| 355 | |||
| 356 | struct MifareReadBlockData { | ||
| 357 | DataBlock data; | ||
| 358 | u8 sector_number; | ||
| 359 | INSERT_PADDING_BYTES(0x7); | ||
| 360 | }; | ||
| 361 | static_assert(sizeof(MifareReadBlockData) == 0x18, "MifareReadBlockData is an invalid size"); | ||
| 362 | |||
| 363 | struct MifareWriteBlockParameter { | ||
| 364 | DataBlock data; | ||
| 365 | u8 sector_number; | ||
| 366 | INSERT_PADDING_BYTES(0x7); | ||
| 367 | SectorKey sector_key; | ||
| 368 | }; | ||
| 369 | static_assert(sizeof(MifareWriteBlockParameter) == 0x28, | ||
| 370 | "MifareWriteBlockParameter is an invalid size"); | ||
| 371 | |||
| 326 | } // namespace Service::NFP | 372 | } // namespace Service::NFP |
diff --git a/src/input_common/drivers/virtual_amiibo.cpp b/src/input_common/drivers/virtual_amiibo.cpp index 564a188e5..63ffaca67 100644 --- a/src/input_common/drivers/virtual_amiibo.cpp +++ b/src/input_common/drivers/virtual_amiibo.cpp | |||
| @@ -47,20 +47,20 @@ Common::Input::NfcState VirtualAmiibo::SupportsNfc( | |||
| 47 | 47 | ||
| 48 | Common::Input::NfcState VirtualAmiibo::WriteNfcData( | 48 | Common::Input::NfcState VirtualAmiibo::WriteNfcData( |
| 49 | [[maybe_unused]] const PadIdentifier& identifier_, const std::vector<u8>& data) { | 49 | [[maybe_unused]] const PadIdentifier& identifier_, const std::vector<u8>& data) { |
| 50 | const Common::FS::IOFile amiibo_file{file_path, Common::FS::FileAccessMode::ReadWrite, | 50 | const Common::FS::IOFile nfc_file{file_path, Common::FS::FileAccessMode::ReadWrite, |
| 51 | Common::FS::FileType::BinaryFile}; | 51 | Common::FS::FileType::BinaryFile}; |
| 52 | 52 | ||
| 53 | if (!amiibo_file.IsOpen()) { | 53 | if (!nfc_file.IsOpen()) { |
| 54 | LOG_ERROR(Core, "Amiibo is already on use"); | 54 | LOG_ERROR(Core, "Amiibo is already on use"); |
| 55 | return Common::Input::NfcState::WriteFailed; | 55 | return Common::Input::NfcState::WriteFailed; |
| 56 | } | 56 | } |
| 57 | 57 | ||
| 58 | if (!amiibo_file.Write(data)) { | 58 | if (!nfc_file.Write(data)) { |
| 59 | LOG_ERROR(Service_NFP, "Error writting to file"); | 59 | LOG_ERROR(Service_NFP, "Error writting to file"); |
| 60 | return Common::Input::NfcState::WriteFailed; | 60 | return Common::Input::NfcState::WriteFailed; |
| 61 | } | 61 | } |
| 62 | 62 | ||
| 63 | amiibo_data = data; | 63 | nfc_data = data; |
| 64 | 64 | ||
| 65 | return Common::Input::NfcState::Success; | 65 | return Common::Input::NfcState::Success; |
| 66 | } | 66 | } |
| @@ -70,32 +70,44 @@ VirtualAmiibo::State VirtualAmiibo::GetCurrentState() const { | |||
| 70 | } | 70 | } |
| 71 | 71 | ||
| 72 | VirtualAmiibo::Info VirtualAmiibo::LoadAmiibo(const std::string& filename) { | 72 | VirtualAmiibo::Info VirtualAmiibo::LoadAmiibo(const std::string& filename) { |
| 73 | const Common::FS::IOFile amiibo_file{filename, Common::FS::FileAccessMode::Read, | 73 | const Common::FS::IOFile nfc_file{filename, Common::FS::FileAccessMode::Read, |
| 74 | Common::FS::FileType::BinaryFile}; | 74 | Common::FS::FileType::BinaryFile}; |
| 75 | 75 | ||
| 76 | if (state != State::WaitingForAmiibo) { | 76 | if (state != State::WaitingForAmiibo) { |
| 77 | return Info::WrongDeviceState; | 77 | return Info::WrongDeviceState; |
| 78 | } | 78 | } |
| 79 | 79 | ||
| 80 | if (!amiibo_file.IsOpen()) { | 80 | if (!nfc_file.IsOpen()) { |
| 81 | return Info::UnableToLoad; | 81 | return Info::UnableToLoad; |
| 82 | } | 82 | } |
| 83 | 83 | ||
| 84 | amiibo_data.resize(amiibo_size); | 84 | switch (nfc_file.GetSize()) { |
| 85 | 85 | case AmiiboSize: | |
| 86 | if (amiibo_file.Read(amiibo_data) < amiibo_size_without_password) { | 86 | case AmiiboSizeWithoutPassword: |
| 87 | nfc_data.resize(AmiiboSize); | ||
| 88 | if (nfc_file.Read(nfc_data) < AmiiboSizeWithoutPassword) { | ||
| 89 | return Info::NotAnAmiibo; | ||
| 90 | } | ||
| 91 | break; | ||
| 92 | case MifareSize: | ||
| 93 | nfc_data.resize(MifareSize); | ||
| 94 | if (nfc_file.Read(nfc_data) < MifareSize) { | ||
| 95 | return Info::NotAnAmiibo; | ||
| 96 | } | ||
| 97 | break; | ||
| 98 | default: | ||
| 87 | return Info::NotAnAmiibo; | 99 | return Info::NotAnAmiibo; |
| 88 | } | 100 | } |
| 89 | 101 | ||
| 90 | file_path = filename; | 102 | file_path = filename; |
| 91 | state = State::AmiiboIsOpen; | 103 | state = State::AmiiboIsOpen; |
| 92 | SetNfc(identifier, {Common::Input::NfcState::NewAmiibo, amiibo_data}); | 104 | SetNfc(identifier, {Common::Input::NfcState::NewAmiibo, nfc_data}); |
| 93 | return Info::Success; | 105 | return Info::Success; |
| 94 | } | 106 | } |
| 95 | 107 | ||
| 96 | VirtualAmiibo::Info VirtualAmiibo::ReloadAmiibo() { | 108 | VirtualAmiibo::Info VirtualAmiibo::ReloadAmiibo() { |
| 97 | if (state == State::AmiiboIsOpen) { | 109 | if (state == State::AmiiboIsOpen) { |
| 98 | SetNfc(identifier, {Common::Input::NfcState::NewAmiibo, amiibo_data}); | 110 | SetNfc(identifier, {Common::Input::NfcState::NewAmiibo, nfc_data}); |
| 99 | return Info::Success; | 111 | return Info::Success; |
| 100 | } | 112 | } |
| 101 | 113 | ||
diff --git a/src/input_common/drivers/virtual_amiibo.h b/src/input_common/drivers/virtual_amiibo.h index 9baeb3997..0f9dad333 100644 --- a/src/input_common/drivers/virtual_amiibo.h +++ b/src/input_common/drivers/virtual_amiibo.h | |||
| @@ -53,12 +53,13 @@ public: | |||
| 53 | std::string GetLastFilePath() const; | 53 | std::string GetLastFilePath() const; |
| 54 | 54 | ||
| 55 | private: | 55 | private: |
| 56 | static constexpr std::size_t amiibo_size = 0x21C; | 56 | static constexpr std::size_t AmiiboSize = 0x21C; |
| 57 | static constexpr std::size_t amiibo_size_without_password = amiibo_size - 0x8; | 57 | static constexpr std::size_t AmiiboSizeWithoutPassword = AmiiboSize - 0x8; |
| 58 | static constexpr std::size_t MifareSize = 0x400; | ||
| 58 | 59 | ||
| 59 | std::string file_path{}; | 60 | std::string file_path{}; |
| 60 | State state{State::Initialized}; | 61 | State state{State::Initialized}; |
| 61 | std::vector<u8> amiibo_data; | 62 | std::vector<u8> nfc_data; |
| 62 | Common::Input::PollingMode polling_mode{Common::Input::PollingMode::Pasive}; | 63 | Common::Input::PollingMode polling_mode{Common::Input::PollingMode::Pasive}; |
| 63 | }; | 64 | }; |
| 64 | } // namespace InputCommon | 65 | } // namespace InputCommon |
diff --git a/src/video_core/engines/maxwell_3d.cpp b/src/video_core/engines/maxwell_3d.cpp index 34bbc72cf..fb9b9b94e 100644 --- a/src/video_core/engines/maxwell_3d.cpp +++ b/src/video_core/engines/maxwell_3d.cpp | |||
| @@ -493,41 +493,51 @@ void Maxwell3D::ProcessQueryGet() { | |||
| 493 | 493 | ||
| 494 | void Maxwell3D::ProcessQueryCondition() { | 494 | void Maxwell3D::ProcessQueryCondition() { |
| 495 | const GPUVAddr condition_address{regs.render_enable.Address()}; | 495 | const GPUVAddr condition_address{regs.render_enable.Address()}; |
| 496 | switch (regs.render_enable.mode) { | 496 | switch (regs.render_enable_override) { |
| 497 | case Regs::RenderEnable::Mode::True: { | 497 | case Regs::RenderEnable::Override::AlwaysRender: |
| 498 | execute_on = true; | 498 | execute_on = true; |
| 499 | break; | 499 | break; |
| 500 | } | 500 | case Regs::RenderEnable::Override::NeverRender: |
| 501 | case Regs::RenderEnable::Mode::False: { | ||
| 502 | execute_on = false; | 501 | execute_on = false; |
| 503 | break; | 502 | break; |
| 504 | } | 503 | case Regs::RenderEnable::Override::UseRenderEnable: |
| 505 | case Regs::RenderEnable::Mode::Conditional: { | 504 | switch (regs.render_enable.mode) { |
| 506 | Regs::ReportSemaphore::Compare cmp; | 505 | case Regs::RenderEnable::Mode::True: { |
| 507 | memory_manager.ReadBlock(condition_address, &cmp, sizeof(cmp)); | 506 | execute_on = true; |
| 508 | execute_on = cmp.initial_sequence != 0U && cmp.initial_mode != 0U; | 507 | break; |
| 509 | break; | 508 | } |
| 510 | } | 509 | case Regs::RenderEnable::Mode::False: { |
| 511 | case Regs::RenderEnable::Mode::IfEqual: { | 510 | execute_on = false; |
| 512 | Regs::ReportSemaphore::Compare cmp; | 511 | break; |
| 513 | memory_manager.ReadBlock(condition_address, &cmp, sizeof(cmp)); | 512 | } |
| 514 | execute_on = | 513 | case Regs::RenderEnable::Mode::Conditional: { |
| 515 | cmp.initial_sequence == cmp.current_sequence && cmp.initial_mode == cmp.current_mode; | 514 | Regs::ReportSemaphore::Compare cmp; |
| 516 | break; | 515 | memory_manager.ReadBlock(condition_address, &cmp, sizeof(cmp)); |
| 517 | } | 516 | execute_on = cmp.initial_sequence != 0U && cmp.initial_mode != 0U; |
| 518 | case Regs::RenderEnable::Mode::IfNotEqual: { | 517 | break; |
| 519 | Regs::ReportSemaphore::Compare cmp; | 518 | } |
| 520 | memory_manager.ReadBlock(condition_address, &cmp, sizeof(cmp)); | 519 | case Regs::RenderEnable::Mode::IfEqual: { |
| 521 | execute_on = | 520 | Regs::ReportSemaphore::Compare cmp; |
| 522 | cmp.initial_sequence != cmp.current_sequence || cmp.initial_mode != cmp.current_mode; | 521 | memory_manager.ReadBlock(condition_address, &cmp, sizeof(cmp)); |
| 523 | break; | 522 | execute_on = cmp.initial_sequence == cmp.current_sequence && |
| 524 | } | 523 | cmp.initial_mode == cmp.current_mode; |
| 525 | default: { | 524 | break; |
| 526 | UNIMPLEMENTED_MSG("Uninplemented Condition Mode!"); | 525 | } |
| 527 | execute_on = true; | 526 | case Regs::RenderEnable::Mode::IfNotEqual: { |
| 527 | Regs::ReportSemaphore::Compare cmp; | ||
| 528 | memory_manager.ReadBlock(condition_address, &cmp, sizeof(cmp)); | ||
| 529 | execute_on = cmp.initial_sequence != cmp.current_sequence || | ||
| 530 | cmp.initial_mode != cmp.current_mode; | ||
| 531 | break; | ||
| 532 | } | ||
| 533 | default: { | ||
| 534 | UNIMPLEMENTED_MSG("Uninplemented Condition Mode!"); | ||
| 535 | execute_on = true; | ||
| 536 | break; | ||
| 537 | } | ||
| 538 | } | ||
| 528 | break; | 539 | break; |
| 529 | } | 540 | } |
| 530 | } | ||
| 531 | } | 541 | } |
| 532 | 542 | ||
| 533 | void Maxwell3D::ProcessCounterReset() { | 543 | void Maxwell3D::ProcessCounterReset() { |