summaryrefslogtreecommitdiff
path: root/src/input_common/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'src/input_common/drivers')
-rw-r--r--src/input_common/drivers/joycon.cpp133
-rw-r--r--src/input_common/drivers/joycon.h18
-rw-r--r--src/input_common/drivers/sdl_driver.cpp32
-rw-r--r--src/input_common/drivers/virtual_amiibo.cpp132
-rw-r--r--src/input_common/drivers/virtual_amiibo.h17
5 files changed, 298 insertions, 34 deletions
diff --git a/src/input_common/drivers/joycon.cpp b/src/input_common/drivers/joycon.cpp
index b2b5677c8..52494e0d9 100644
--- a/src/input_common/drivers/joycon.cpp
+++ b/src/input_common/drivers/joycon.cpp
@@ -195,8 +195,8 @@ void Joycons::RegisterNewDevice(SDL_hid_device_info* device_info) {
195 OnMotionUpdate(port, type, id, value); 195 OnMotionUpdate(port, type, id, value);
196 }}, 196 }},
197 .on_ring_data = {[this](f32 ring_data) { OnRingConUpdate(ring_data); }}, 197 .on_ring_data = {[this](f32 ring_data) { OnRingConUpdate(ring_data); }},
198 .on_amiibo_data = {[this, port, type](const std::vector<u8>& amiibo_data) { 198 .on_amiibo_data = {[this, port, type](const Joycon::TagInfo& tag_info) {
199 OnAmiiboUpdate(port, type, amiibo_data); 199 OnAmiiboUpdate(port, type, tag_info);
200 }}, 200 }},
201 .on_camera_data = {[this, port](const std::vector<u8>& camera_data, 201 .on_camera_data = {[this, port](const std::vector<u8>& camera_data,
202 Joycon::IrsResolution format) { 202 Joycon::IrsResolution format) {
@@ -291,13 +291,105 @@ Common::Input::NfcState Joycons::SupportsNfc(const PadIdentifier& identifier_) c
291 return Common::Input::NfcState::Success; 291 return Common::Input::NfcState::Success;
292}; 292};
293 293
294Common::Input::NfcState Joycons::StartNfcPolling(const PadIdentifier& identifier) {
295 auto handle = GetHandle(identifier);
296 if (handle == nullptr) {
297 return Common::Input::NfcState::Unknown;
298 }
299 return TranslateDriverResult(handle->StartNfcPolling());
300};
301
302Common::Input::NfcState Joycons::StopNfcPolling(const PadIdentifier& identifier) {
303 auto handle = GetHandle(identifier);
304 if (handle == nullptr) {
305 return Common::Input::NfcState::Unknown;
306 }
307 return TranslateDriverResult(handle->StopNfcPolling());
308};
309
310Common::Input::NfcState Joycons::ReadAmiiboData(const PadIdentifier& identifier,
311 std::vector<u8>& out_data) {
312 auto handle = GetHandle(identifier);
313 if (handle == nullptr) {
314 return Common::Input::NfcState::Unknown;
315 }
316 return TranslateDriverResult(handle->ReadAmiiboData(out_data));
317}
318
294Common::Input::NfcState Joycons::WriteNfcData(const PadIdentifier& identifier, 319Common::Input::NfcState Joycons::WriteNfcData(const PadIdentifier& identifier,
295 const std::vector<u8>& data) { 320 const std::vector<u8>& data) {
296 auto handle = GetHandle(identifier); 321 auto handle = GetHandle(identifier);
297 if (handle->WriteNfcData(data) != Joycon::DriverResult::Success) { 322 if (handle == nullptr) {
298 return Common::Input::NfcState::WriteFailed; 323 return Common::Input::NfcState::Unknown;
299 } 324 }
300 return Common::Input::NfcState::Success; 325 return TranslateDriverResult(handle->WriteNfcData(data));
326};
327
328Common::Input::NfcState Joycons::ReadMifareData(const PadIdentifier& identifier,
329 const Common::Input::MifareRequest& request,
330 Common::Input::MifareRequest& data) {
331 auto handle = GetHandle(identifier);
332 if (handle == nullptr) {
333 return Common::Input::NfcState::Unknown;
334 }
335
336 const auto command = static_cast<Joycon::MifareCmd>(request.data[0].command);
337 std::vector<Joycon::MifareReadChunk> read_request{};
338 for (const auto& request_data : request.data) {
339 if (request_data.command == 0) {
340 continue;
341 }
342 Joycon::MifareReadChunk chunk = {
343 .command = command,
344 .sector_key = {},
345 .sector = request_data.sector,
346 };
347 memcpy(chunk.sector_key.data(), request_data.key.data(),
348 sizeof(Joycon::MifareReadChunk::sector_key));
349 read_request.emplace_back(chunk);
350 }
351
352 std::vector<Joycon::MifareReadData> read_data(read_request.size());
353 const auto result = handle->ReadMifareData(read_request, read_data);
354 if (result == Joycon::DriverResult::Success) {
355 for (std::size_t i = 0; i < read_request.size(); i++) {
356 data.data[i] = {
357 .command = static_cast<u8>(command),
358 .sector = read_data[i].sector,
359 .key = {},
360 .data = read_data[i].data,
361 };
362 }
363 }
364 return TranslateDriverResult(result);
365};
366
367Common::Input::NfcState Joycons::WriteMifareData(const PadIdentifier& identifier,
368 const Common::Input::MifareRequest& request) {
369 auto handle = GetHandle(identifier);
370 if (handle == nullptr) {
371 return Common::Input::NfcState::Unknown;
372 }
373
374 const auto command = static_cast<Joycon::MifareCmd>(request.data[0].command);
375 std::vector<Joycon::MifareWriteChunk> write_request{};
376 for (const auto& request_data : request.data) {
377 if (request_data.command == 0) {
378 continue;
379 }
380 Joycon::MifareWriteChunk chunk = {
381 .command = command,
382 .sector_key = {},
383 .sector = request_data.sector,
384 .data = {},
385 };
386 memcpy(chunk.sector_key.data(), request_data.key.data(),
387 sizeof(Joycon::MifareReadChunk::sector_key));
388 memcpy(chunk.data.data(), request_data.data.data(), sizeof(Joycon::MifareWriteChunk::data));
389 write_request.emplace_back(chunk);
390 }
391
392 return TranslateDriverResult(handle->WriteMifareData(write_request));
301}; 393};
302 394
303Common::Input::DriverResult Joycons::SetPollingMode(const PadIdentifier& identifier, 395Common::Input::DriverResult Joycons::SetPollingMode(const PadIdentifier& identifier,
@@ -403,11 +495,20 @@ void Joycons::OnRingConUpdate(f32 ring_data) {
403} 495}
404 496
405void Joycons::OnAmiiboUpdate(std::size_t port, Joycon::ControllerType type, 497void Joycons::OnAmiiboUpdate(std::size_t port, Joycon::ControllerType type,
406 const std::vector<u8>& amiibo_data) { 498 const Joycon::TagInfo& tag_info) {
407 const auto identifier = GetIdentifier(port, type); 499 const auto identifier = GetIdentifier(port, type);
408 const auto nfc_state = amiibo_data.empty() ? Common::Input::NfcState::AmiiboRemoved 500 const auto nfc_state = tag_info.uuid_length == 0 ? Common::Input::NfcState::AmiiboRemoved
409 : Common::Input::NfcState::NewAmiibo; 501 : Common::Input::NfcState::NewAmiibo;
410 SetNfc(identifier, {nfc_state, amiibo_data}); 502
503 const Common::Input::NfcStatus nfc_status{
504 .state = nfc_state,
505 .uuid_length = tag_info.uuid_length,
506 .protocol = tag_info.protocol,
507 .tag_type = tag_info.tag_type,
508 .uuid = tag_info.uuid,
509 };
510
511 SetNfc(identifier, nfc_status);
411} 512}
412 513
413void Joycons::OnCameraUpdate(std::size_t port, const std::vector<u8>& camera_data, 514void Joycons::OnCameraUpdate(std::size_t port, const std::vector<u8>& camera_data,
@@ -726,4 +827,18 @@ std::string Joycons::JoyconName(Joycon::ControllerType type) const {
726 return "Unknown Switch Controller"; 827 return "Unknown Switch Controller";
727 } 828 }
728} 829}
830
831Common::Input::NfcState Joycons::TranslateDriverResult(Joycon::DriverResult result) const {
832 switch (result) {
833 case Joycon::DriverResult::Success:
834 return Common::Input::NfcState::Success;
835 case Joycon::DriverResult::Disabled:
836 return Common::Input::NfcState::WrongDeviceState;
837 case Joycon::DriverResult::NotSupported:
838 return Common::Input::NfcState::NotSupported;
839 default:
840 return Common::Input::NfcState::Unknown;
841 }
842}
843
729} // namespace InputCommon 844} // namespace InputCommon
diff --git a/src/input_common/drivers/joycon.h b/src/input_common/drivers/joycon.h
index e3f0ad78f..4c323d7d6 100644
--- a/src/input_common/drivers/joycon.h
+++ b/src/input_common/drivers/joycon.h
@@ -15,6 +15,7 @@ using SerialNumber = std::array<u8, 15>;
15struct Battery; 15struct Battery;
16struct Color; 16struct Color;
17struct MotionData; 17struct MotionData;
18struct TagInfo;
18enum class ControllerType : u8; 19enum class ControllerType : u8;
19enum class DriverResult; 20enum class DriverResult;
20enum class IrsResolution; 21enum class IrsResolution;
@@ -39,9 +40,18 @@ public:
39 Common::Input::DriverResult SetCameraFormat(const PadIdentifier& identifier, 40 Common::Input::DriverResult SetCameraFormat(const PadIdentifier& identifier,
40 Common::Input::CameraFormat camera_format) override; 41 Common::Input::CameraFormat camera_format) override;
41 42
42 Common::Input::NfcState SupportsNfc(const PadIdentifier& identifier_) const override; 43 Common::Input::NfcState SupportsNfc(const PadIdentifier& identifier) const override;
43 Common::Input::NfcState WriteNfcData(const PadIdentifier& identifier_, 44 Common::Input::NfcState StartNfcPolling(const PadIdentifier& identifier) override;
45 Common::Input::NfcState StopNfcPolling(const PadIdentifier& identifier) override;
46 Common::Input::NfcState ReadAmiiboData(const PadIdentifier& identifier,
47 std::vector<u8>& out_data) override;
48 Common::Input::NfcState WriteNfcData(const PadIdentifier& identifier,
44 const std::vector<u8>& data) override; 49 const std::vector<u8>& data) override;
50 Common::Input::NfcState ReadMifareData(const PadIdentifier& identifier,
51 const Common::Input::MifareRequest& request,
52 Common::Input::MifareRequest& out_data) override;
53 Common::Input::NfcState WriteMifareData(const PadIdentifier& identifier,
54 const Common::Input::MifareRequest& request) override;
45 55
46 Common::Input::DriverResult SetPollingMode( 56 Common::Input::DriverResult SetPollingMode(
47 const PadIdentifier& identifier, const Common::Input::PollingMode polling_mode) override; 57 const PadIdentifier& identifier, const Common::Input::PollingMode polling_mode) override;
@@ -82,7 +92,7 @@ private:
82 const Joycon::MotionData& value); 92 const Joycon::MotionData& value);
83 void OnRingConUpdate(f32 ring_data); 93 void OnRingConUpdate(f32 ring_data);
84 void OnAmiiboUpdate(std::size_t port, Joycon::ControllerType type, 94 void OnAmiiboUpdate(std::size_t port, Joycon::ControllerType type,
85 const std::vector<u8>& amiibo_data); 95 const Joycon::TagInfo& amiibo_data);
86 void OnCameraUpdate(std::size_t port, const std::vector<u8>& camera_data, 96 void OnCameraUpdate(std::size_t port, const std::vector<u8>& camera_data,
87 Joycon::IrsResolution format); 97 Joycon::IrsResolution format);
88 98
@@ -102,6 +112,8 @@ private:
102 /// Returns the name of the device in text format 112 /// Returns the name of the device in text format
103 std::string JoyconName(Joycon::ControllerType type) const; 113 std::string JoyconName(Joycon::ControllerType type) const;
104 114
115 Common::Input::NfcState TranslateDriverResult(Joycon::DriverResult result) const;
116
105 std::jthread scan_thread; 117 std::jthread scan_thread;
106 118
107 // Joycon types are split by type to ease supporting dualjoycon configurations 119 // Joycon types are split by type to ease supporting dualjoycon configurations
diff --git a/src/input_common/drivers/sdl_driver.cpp b/src/input_common/drivers/sdl_driver.cpp
index 9a0439bb5..9f26392b1 100644
--- a/src/input_common/drivers/sdl_driver.cpp
+++ b/src/input_common/drivers/sdl_driver.cpp
@@ -150,6 +150,8 @@ public:
150 if (sdl_controller) { 150 if (sdl_controller) {
151 const auto type = SDL_GameControllerGetType(sdl_controller.get()); 151 const auto type = SDL_GameControllerGetType(sdl_controller.get());
152 return (type == SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_PRO) || 152 return (type == SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_PRO) ||
153 (type == SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_JOYCON_LEFT) ||
154 (type == SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_JOYCON_RIGHT) ||
153 (type == SDL_CONTROLLER_TYPE_PS5); 155 (type == SDL_CONTROLLER_TYPE_PS5);
154 } 156 }
155 return false; 157 return false;
@@ -228,9 +230,8 @@ public:
228 return false; 230 return false;
229 } 231 }
230 232
231 Common::Input::BatteryLevel GetBatteryLevel() { 233 Common::Input::BatteryLevel GetBatteryLevel(SDL_JoystickPowerLevel battery_level) {
232 const auto level = SDL_JoystickCurrentPowerLevel(sdl_joystick.get()); 234 switch (battery_level) {
233 switch (level) {
234 case SDL_JOYSTICK_POWER_EMPTY: 235 case SDL_JOYSTICK_POWER_EMPTY:
235 return Common::Input::BatteryLevel::Empty; 236 return Common::Input::BatteryLevel::Empty;
236 case SDL_JOYSTICK_POWER_LOW: 237 case SDL_JOYSTICK_POWER_LOW:
@@ -378,7 +379,6 @@ void SDLDriver::InitJoystick(int joystick_index) {
378 if (joystick_map.find(guid) == joystick_map.end()) { 379 if (joystick_map.find(guid) == joystick_map.end()) {
379 auto joystick = std::make_shared<SDLJoystick>(guid, 0, sdl_joystick, sdl_gamecontroller); 380 auto joystick = std::make_shared<SDLJoystick>(guid, 0, sdl_joystick, sdl_gamecontroller);
380 PreSetController(joystick->GetPadIdentifier()); 381 PreSetController(joystick->GetPadIdentifier());
381 SetBattery(joystick->GetPadIdentifier(), joystick->GetBatteryLevel());
382 joystick->EnableMotion(); 382 joystick->EnableMotion();
383 joystick_map[guid].emplace_back(std::move(joystick)); 383 joystick_map[guid].emplace_back(std::move(joystick));
384 return; 384 return;
@@ -398,7 +398,6 @@ void SDLDriver::InitJoystick(int joystick_index) {
398 const int port = static_cast<int>(joystick_guid_list.size()); 398 const int port = static_cast<int>(joystick_guid_list.size());
399 auto joystick = std::make_shared<SDLJoystick>(guid, port, sdl_joystick, sdl_gamecontroller); 399 auto joystick = std::make_shared<SDLJoystick>(guid, port, sdl_joystick, sdl_gamecontroller);
400 PreSetController(joystick->GetPadIdentifier()); 400 PreSetController(joystick->GetPadIdentifier());
401 SetBattery(joystick->GetPadIdentifier(), joystick->GetBatteryLevel());
402 joystick->EnableMotion(); 401 joystick->EnableMotion();
403 joystick_guid_list.emplace_back(std::move(joystick)); 402 joystick_guid_list.emplace_back(std::move(joystick));
404} 403}
@@ -438,8 +437,6 @@ void SDLDriver::HandleGameControllerEvent(const SDL_Event& event) {
438 if (const auto joystick = GetSDLJoystickBySDLID(event.jbutton.which)) { 437 if (const auto joystick = GetSDLJoystickBySDLID(event.jbutton.which)) {
439 const PadIdentifier identifier = joystick->GetPadIdentifier(); 438 const PadIdentifier identifier = joystick->GetPadIdentifier();
440 SetButton(identifier, event.jbutton.button, true); 439 SetButton(identifier, event.jbutton.button, true);
441 // Battery doesn't trigger an event so just update every button press
442 SetBattery(identifier, joystick->GetBatteryLevel());
443 } 440 }
444 break; 441 break;
445 } 442 }
@@ -466,6 +463,13 @@ void SDLDriver::HandleGameControllerEvent(const SDL_Event& event) {
466 } 463 }
467 break; 464 break;
468 } 465 }
466 case SDL_JOYBATTERYUPDATED: {
467 if (auto joystick = GetSDLJoystickBySDLID(event.jbattery.which)) {
468 const PadIdentifier identifier = joystick->GetPadIdentifier();
469 SetBattery(identifier, joystick->GetBatteryLevel(event.jbattery.level));
470 }
471 break;
472 }
469 case SDL_JOYDEVICEREMOVED: 473 case SDL_JOYDEVICEREMOVED:
470 LOG_DEBUG(Input, "Controller removed with Instance_ID {}", event.jdevice.which); 474 LOG_DEBUG(Input, "Controller removed with Instance_ID {}", event.jdevice.which);
471 CloseJoystick(SDL_JoystickFromInstanceID(event.jdevice.which)); 475 CloseJoystick(SDL_JoystickFromInstanceID(event.jdevice.which));
@@ -483,6 +487,10 @@ void SDLDriver::CloseJoysticks() {
483} 487}
484 488
485SDLDriver::SDLDriver(std::string input_engine_) : InputEngine(std::move(input_engine_)) { 489SDLDriver::SDLDriver(std::string input_engine_) : InputEngine(std::move(input_engine_)) {
490 // Set our application name. Currently passed to DBus by SDL and visible to the user through
491 // their desktop environment.
492 SDL_SetHint(SDL_HINT_APP_NAME, "yuzu");
493
486 if (!Settings::values.enable_raw_input) { 494 if (!Settings::values.enable_raw_input) {
487 // Disable raw input. When enabled this setting causes SDL to die when a web applet opens 495 // Disable raw input. When enabled this setting causes SDL to die when a web applet opens
488 SDL_SetHint(SDL_HINT_JOYSTICK_RAWINPUT, "0"); 496 SDL_SetHint(SDL_HINT_JOYSTICK_RAWINPUT, "0");
@@ -501,6 +509,9 @@ SDLDriver::SDLDriver(std::string input_engine_) : InputEngine(std::move(input_en
501 SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_JOY_CONS, "0"); 509 SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_JOY_CONS, "0");
502 } else { 510 } else {
503 SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_JOY_CONS, "1"); 511 SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_JOY_CONS, "1");
512 SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_JOYCON_HOME_LED, "0");
513 SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_COMBINE_JOY_CONS, "0");
514 SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_VERTICAL_JOY_CONS, "1");
504 } 515 }
505 516
506 // Disable hidapi drivers for pro controllers when the custom joycon driver is enabled 517 // Disable hidapi drivers for pro controllers when the custom joycon driver is enabled
@@ -508,8 +519,11 @@ SDLDriver::SDLDriver(std::string input_engine_) : InputEngine(std::move(input_en
508 SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_SWITCH, "0"); 519 SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_SWITCH, "0");
509 } else { 520 } else {
510 SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_SWITCH, "1"); 521 SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_SWITCH, "1");
522 SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_SWITCH_HOME_LED, "0");
511 } 523 }
512 524
525 SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_SWITCH_PLAYER_LED, "1");
526
513 // Disable hidapi driver for xbox. Already default on Windows, this causes conflict with native 527 // Disable hidapi driver for xbox. Already default on Windows, this causes conflict with native
514 // driver on Linux. 528 // driver on Linux.
515 SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_XBOX, "0"); 529 SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_XBOX, "0");
@@ -789,7 +803,9 @@ ButtonMapping SDLDriver::GetButtonMappingForDevice(const Common::ParamPackage& p
789 // This list also excludes Screenshot since there's not really a mapping for that 803 // This list also excludes Screenshot since there's not really a mapping for that
790 ButtonBindings switch_to_sdl_button; 804 ButtonBindings switch_to_sdl_button;
791 805
792 if (SDL_GameControllerGetType(controller) == SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_PRO) { 806 if (SDL_GameControllerGetType(controller) == SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_PRO ||
807 SDL_GameControllerGetType(controller) == SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_JOYCON_LEFT ||
808 SDL_GameControllerGetType(controller) == SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_JOYCON_RIGHT) {
793 switch_to_sdl_button = GetNintendoButtonBinding(joystick); 809 switch_to_sdl_button = GetNintendoButtonBinding(joystick);
794 } else { 810 } else {
795 switch_to_sdl_button = GetDefaultButtonBinding(); 811 switch_to_sdl_button = GetDefaultButtonBinding();
diff --git a/src/input_common/drivers/virtual_amiibo.cpp b/src/input_common/drivers/virtual_amiibo.cpp
index f8bafe553..180eb53ef 100644
--- a/src/input_common/drivers/virtual_amiibo.cpp
+++ b/src/input_common/drivers/virtual_amiibo.cpp
@@ -29,14 +29,13 @@ Common::Input::DriverResult VirtualAmiibo::SetPollingMode(
29 29
30 switch (polling_mode) { 30 switch (polling_mode) {
31 case Common::Input::PollingMode::NFC: 31 case Common::Input::PollingMode::NFC:
32 if (state == State::Initialized) { 32 state = State::Initialized;
33 state = State::WaitingForAmiibo;
34 }
35 return Common::Input::DriverResult::Success; 33 return Common::Input::DriverResult::Success;
36 default: 34 default:
37 if (state == State::AmiiboIsOpen) { 35 if (state == State::TagNearby) {
38 CloseAmiibo(); 36 CloseAmiibo();
39 } 37 }
38 state = State::Disabled;
40 return Common::Input::DriverResult::NotSupported; 39 return Common::Input::DriverResult::NotSupported;
41 } 40 }
42} 41}
@@ -45,6 +44,39 @@ Common::Input::NfcState VirtualAmiibo::SupportsNfc(
45 [[maybe_unused]] const PadIdentifier& identifier_) const { 44 [[maybe_unused]] const PadIdentifier& identifier_) const {
46 return Common::Input::NfcState::Success; 45 return Common::Input::NfcState::Success;
47} 46}
47Common::Input::NfcState VirtualAmiibo::StartNfcPolling(const PadIdentifier& identifier_) {
48 if (state != State::Initialized) {
49 return Common::Input::NfcState::WrongDeviceState;
50 }
51 state = State::WaitingForAmiibo;
52 return Common::Input::NfcState::Success;
53}
54
55Common::Input::NfcState VirtualAmiibo::StopNfcPolling(const PadIdentifier& identifier_) {
56 if (state == State::Disabled) {
57 return Common::Input::NfcState::WrongDeviceState;
58 }
59 if (state == State::TagNearby) {
60 CloseAmiibo();
61 }
62 state = State::Initialized;
63 return Common::Input::NfcState::Success;
64}
65
66Common::Input::NfcState VirtualAmiibo::ReadAmiiboData(const PadIdentifier& identifier_,
67 std::vector<u8>& out_data) {
68 if (state != State::TagNearby) {
69 return Common::Input::NfcState::WrongDeviceState;
70 }
71
72 if (status.tag_type != 1U << 1) {
73 return Common::Input::NfcState::InvalidTagType;
74 }
75
76 out_data.resize(nfc_data.size());
77 memcpy(out_data.data(), nfc_data.data(), nfc_data.size());
78 return Common::Input::NfcState::Success;
79}
48 80
49Common::Input::NfcState VirtualAmiibo::WriteNfcData( 81Common::Input::NfcState VirtualAmiibo::WriteNfcData(
50 [[maybe_unused]] const PadIdentifier& identifier_, const std::vector<u8>& data) { 82 [[maybe_unused]] const PadIdentifier& identifier_, const std::vector<u8>& data) {
@@ -66,6 +98,69 @@ Common::Input::NfcState VirtualAmiibo::WriteNfcData(
66 return Common::Input::NfcState::Success; 98 return Common::Input::NfcState::Success;
67} 99}
68 100
101Common::Input::NfcState VirtualAmiibo::ReadMifareData(const PadIdentifier& identifier_,
102 const Common::Input::MifareRequest& request,
103 Common::Input::MifareRequest& out_data) {
104 if (state != State::TagNearby) {
105 return Common::Input::NfcState::WrongDeviceState;
106 }
107
108 if (status.tag_type != 1U << 6) {
109 return Common::Input::NfcState::InvalidTagType;
110 }
111
112 for (std::size_t i = 0; i < request.data.size(); i++) {
113 if (request.data[i].command == 0) {
114 continue;
115 }
116 out_data.data[i].command = request.data[i].command;
117 out_data.data[i].sector = request.data[i].sector;
118
119 const std::size_t sector_index =
120 request.data[i].sector * sizeof(Common::Input::MifareData::data);
121
122 if (nfc_data.size() < sector_index + sizeof(Common::Input::MifareData::data)) {
123 return Common::Input::NfcState::WriteFailed;
124 }
125
126 // Ignore the sector key as we don't support it
127 memcpy(out_data.data[i].data.data(), nfc_data.data() + sector_index,
128 sizeof(Common::Input::MifareData::data));
129 }
130
131 return Common::Input::NfcState::Success;
132}
133
134Common::Input::NfcState VirtualAmiibo::WriteMifareData(
135 const PadIdentifier& identifier_, const Common::Input::MifareRequest& request) {
136 if (state != State::TagNearby) {
137 return Common::Input::NfcState::WrongDeviceState;
138 }
139
140 if (status.tag_type != 1U << 6) {
141 return Common::Input::NfcState::InvalidTagType;
142 }
143
144 for (std::size_t i = 0; i < request.data.size(); i++) {
145 if (request.data[i].command == 0) {
146 continue;
147 }
148
149 const std::size_t sector_index =
150 request.data[i].sector * sizeof(Common::Input::MifareData::data);
151
152 if (nfc_data.size() < sector_index + sizeof(Common::Input::MifareData::data)) {
153 return Common::Input::NfcState::WriteFailed;
154 }
155
156 // Ignore the sector key as we don't support it
157 memcpy(nfc_data.data() + sector_index, request.data[i].data.data(),
158 sizeof(Common::Input::MifareData::data));
159 }
160
161 return Common::Input::NfcState::Success;
162}
163
69VirtualAmiibo::State VirtualAmiibo::GetCurrentState() const { 164VirtualAmiibo::State VirtualAmiibo::GetCurrentState() const {
70 return state; 165 return state;
71} 166}
@@ -82,6 +177,7 @@ VirtualAmiibo::Info VirtualAmiibo::LoadAmiibo(const std::string& filename) {
82 switch (nfc_file.GetSize()) { 177 switch (nfc_file.GetSize()) {
83 case AmiiboSize: 178 case AmiiboSize:
84 case AmiiboSizeWithoutPassword: 179 case AmiiboSizeWithoutPassword:
180 case AmiiboSizeWithSignature:
85 data.resize(AmiiboSize); 181 data.resize(AmiiboSize);
86 if (nfc_file.Read(data) < AmiiboSizeWithoutPassword) { 182 if (nfc_file.Read(data) < AmiiboSizeWithoutPassword) {
87 return Info::NotAnAmiibo; 183 return Info::NotAnAmiibo;
@@ -109,24 +205,33 @@ VirtualAmiibo::Info VirtualAmiibo::LoadAmiibo(std::span<u8> data) {
109 switch (data.size_bytes()) { 205 switch (data.size_bytes()) {
110 case AmiiboSize: 206 case AmiiboSize:
111 case AmiiboSizeWithoutPassword: 207 case AmiiboSizeWithoutPassword:
208 case AmiiboSizeWithSignature:
112 nfc_data.resize(AmiiboSize); 209 nfc_data.resize(AmiiboSize);
210 status.tag_type = 1U << 1;
211 status.uuid_length = 7;
113 break; 212 break;
114 case MifareSize: 213 case MifareSize:
115 nfc_data.resize(MifareSize); 214 nfc_data.resize(MifareSize);
215 status.tag_type = 1U << 6;
216 status.uuid_length = 4;
116 break; 217 break;
117 default: 218 default:
118 return Info::NotAnAmiibo; 219 return Info::NotAnAmiibo;
119 } 220 }
120 221
121 state = State::AmiiboIsOpen; 222 status.uuid = {};
223 status.protocol = 1;
224 state = State::TagNearby;
225 status.state = Common::Input::NfcState::NewAmiibo,
122 memcpy(nfc_data.data(), data.data(), data.size_bytes()); 226 memcpy(nfc_data.data(), data.data(), data.size_bytes());
123 SetNfc(identifier, {Common::Input::NfcState::NewAmiibo, nfc_data}); 227 memcpy(status.uuid.data(), nfc_data.data(), status.uuid_length);
228 SetNfc(identifier, status);
124 return Info::Success; 229 return Info::Success;
125} 230}
126 231
127VirtualAmiibo::Info VirtualAmiibo::ReloadAmiibo() { 232VirtualAmiibo::Info VirtualAmiibo::ReloadAmiibo() {
128 if (state == State::AmiiboIsOpen) { 233 if (state == State::TagNearby) {
129 SetNfc(identifier, {Common::Input::NfcState::NewAmiibo, nfc_data}); 234 SetNfc(identifier, status);
130 return Info::Success; 235 return Info::Success;
131 } 236 }
132 237
@@ -134,9 +239,14 @@ VirtualAmiibo::Info VirtualAmiibo::ReloadAmiibo() {
134} 239}
135 240
136VirtualAmiibo::Info VirtualAmiibo::CloseAmiibo() { 241VirtualAmiibo::Info VirtualAmiibo::CloseAmiibo() {
137 state = polling_mode == Common::Input::PollingMode::NFC ? State::WaitingForAmiibo 242 if (state != State::TagNearby) {
138 : State::Initialized; 243 return Info::Success;
139 SetNfc(identifier, {Common::Input::NfcState::AmiiboRemoved, {}}); 244 }
245
246 state = State::WaitingForAmiibo;
247 status.state = Common::Input::NfcState::AmiiboRemoved;
248 SetNfc(identifier, status);
249 status.tag_type = 0;
140 return Info::Success; 250 return Info::Success;
141} 251}
142 252
diff --git a/src/input_common/drivers/virtual_amiibo.h b/src/input_common/drivers/virtual_amiibo.h
index 34e97cd91..490f38e05 100644
--- a/src/input_common/drivers/virtual_amiibo.h
+++ b/src/input_common/drivers/virtual_amiibo.h
@@ -20,9 +20,10 @@ namespace InputCommon {
20class VirtualAmiibo final : public InputEngine { 20class VirtualAmiibo final : public InputEngine {
21public: 21public:
22 enum class State { 22 enum class State {
23 Disabled,
23 Initialized, 24 Initialized,
24 WaitingForAmiibo, 25 WaitingForAmiibo,
25 AmiiboIsOpen, 26 TagNearby,
26 }; 27 };
27 28
28 enum class Info { 29 enum class Info {
@@ -41,9 +42,17 @@ public:
41 const PadIdentifier& identifier_, const Common::Input::PollingMode polling_mode_) override; 42 const PadIdentifier& identifier_, const Common::Input::PollingMode polling_mode_) override;
42 43
43 Common::Input::NfcState SupportsNfc(const PadIdentifier& identifier_) const override; 44 Common::Input::NfcState SupportsNfc(const PadIdentifier& identifier_) const override;
44 45 Common::Input::NfcState StartNfcPolling(const PadIdentifier& identifier_) override;
46 Common::Input::NfcState StopNfcPolling(const PadIdentifier& identifier_) override;
47 Common::Input::NfcState ReadAmiiboData(const PadIdentifier& identifier_,
48 std::vector<u8>& out_data) override;
45 Common::Input::NfcState WriteNfcData(const PadIdentifier& identifier_, 49 Common::Input::NfcState WriteNfcData(const PadIdentifier& identifier_,
46 const std::vector<u8>& data) override; 50 const std::vector<u8>& data) override;
51 Common::Input::NfcState ReadMifareData(const PadIdentifier& identifier_,
52 const Common::Input::MifareRequest& data,
53 Common::Input::MifareRequest& out_data) override;
54 Common::Input::NfcState WriteMifareData(const PadIdentifier& identifier_,
55 const Common::Input::MifareRequest& data) override;
47 56
48 State GetCurrentState() const; 57 State GetCurrentState() const;
49 58
@@ -57,11 +66,13 @@ public:
57private: 66private:
58 static constexpr std::size_t AmiiboSize = 0x21C; 67 static constexpr std::size_t AmiiboSize = 0x21C;
59 static constexpr std::size_t AmiiboSizeWithoutPassword = AmiiboSize - 0x8; 68 static constexpr std::size_t AmiiboSizeWithoutPassword = AmiiboSize - 0x8;
69 static constexpr std::size_t AmiiboSizeWithSignature = AmiiboSize + 0x20;
60 static constexpr std::size_t MifareSize = 0x400; 70 static constexpr std::size_t MifareSize = 0x400;
61 71
62 std::string file_path{}; 72 std::string file_path{};
63 State state{State::Initialized}; 73 State state{State::Disabled};
64 std::vector<u8> nfc_data; 74 std::vector<u8> nfc_data;
75 Common::Input::NfcStatus status;
65 Common::Input::PollingMode polling_mode{Common::Input::PollingMode::Passive}; 76 Common::Input::PollingMode polling_mode{Common::Input::PollingMode::Passive};
66}; 77};
67} // namespace InputCommon 78} // namespace InputCommon