joycon_driver.cpp 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711
  1. // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
  2. // SPDX-License-Identifier: GPL-2.0-or-later
  3. #include "common/input.h"
  4. #include "common/logging/log.h"
  5. #include "common/scope_exit.h"
  6. #include "common/swap.h"
  7. #include "common/thread.h"
  8. #include "input_common/helpers/joycon_driver.h"
  9. #include "input_common/helpers/joycon_protocol/calibration.h"
  10. #include "input_common/helpers/joycon_protocol/generic_functions.h"
  11. #include "input_common/helpers/joycon_protocol/irs.h"
  12. #include "input_common/helpers/joycon_protocol/nfc.h"
  13. #include "input_common/helpers/joycon_protocol/poller.h"
  14. #include "input_common/helpers/joycon_protocol/ringcon.h"
  15. #include "input_common/helpers/joycon_protocol/rumble.h"
  16. namespace InputCommon::Joycon {
  17. JoyconDriver::JoyconDriver(std::size_t port_) : port{port_} {
  18. hidapi_handle = std::make_shared<JoyconHandle>();
  19. }
  20. JoyconDriver::~JoyconDriver() {
  21. Stop();
  22. }
  23. void JoyconDriver::Stop() {
  24. is_connected = false;
  25. input_thread = {};
  26. }
  27. Common::Input::DriverResult JoyconDriver::RequestDeviceAccess(SDL_hid_device_info* device_info) {
  28. std::scoped_lock lock{mutex};
  29. handle_device_type = ControllerType::None;
  30. GetDeviceType(device_info, handle_device_type);
  31. if (handle_device_type == ControllerType::None) {
  32. return Common::Input::DriverResult::UnsupportedControllerType;
  33. }
  34. hidapi_handle->handle =
  35. SDL_hid_open(device_info->vendor_id, device_info->product_id, device_info->serial_number);
  36. std::memcpy(&handle_serial_number, device_info->serial_number, 15);
  37. if (!hidapi_handle->handle) {
  38. LOG_ERROR(Input, "Yuzu can't gain access to this device: ID {:04X}:{:04X}.",
  39. device_info->vendor_id, device_info->product_id);
  40. return Common::Input::DriverResult::HandleInUse;
  41. }
  42. SDL_hid_set_nonblocking(hidapi_handle->handle, 1);
  43. return Common::Input::DriverResult::Success;
  44. }
  45. Common::Input::DriverResult JoyconDriver::InitializeDevice() {
  46. if (!hidapi_handle->handle) {
  47. return Common::Input::DriverResult::InvalidHandle;
  48. }
  49. std::scoped_lock lock{mutex};
  50. disable_input_thread = true;
  51. // Reset Counters
  52. error_counter = 0;
  53. hidapi_handle->packet_counter = 0;
  54. // Reset external device status
  55. starlink_connected = false;
  56. ring_connected = false;
  57. amiibo_detected = false;
  58. // Set HW default configuration
  59. vibration_enabled = true;
  60. motion_enabled = true;
  61. hidbus_enabled = false;
  62. nfc_enabled = false;
  63. passive_enabled = false;
  64. irs_enabled = false;
  65. input_only_device = false;
  66. gyro_sensitivity = Joycon::GyroSensitivity::DPS2000;
  67. gyro_performance = Joycon::GyroPerformance::HZ833;
  68. accelerometer_sensitivity = Joycon::AccelerometerSensitivity::G8;
  69. accelerometer_performance = Joycon::AccelerometerPerformance::HZ100;
  70. // Initialize HW Protocols
  71. calibration_protocol = std::make_unique<CalibrationProtocol>(hidapi_handle);
  72. generic_protocol = std::make_unique<GenericProtocol>(hidapi_handle);
  73. irs_protocol = std::make_unique<IrsProtocol>(hidapi_handle);
  74. nfc_protocol = std::make_unique<NfcProtocol>(hidapi_handle);
  75. ring_protocol = std::make_unique<RingConProtocol>(hidapi_handle);
  76. rumble_protocol = std::make_unique<RumbleProtocol>(hidapi_handle);
  77. // Get fixed joycon info
  78. if (generic_protocol->GetVersionNumber(version) != Common::Input::DriverResult::Success) {
  79. // If this command fails the device doesn't accept configuration commands
  80. input_only_device = true;
  81. }
  82. if (!input_only_device) {
  83. generic_protocol->SetLowPowerMode(false);
  84. generic_protocol->GetColor(color);
  85. if (handle_device_type == ControllerType::Pro) {
  86. // Some 3rd party controllers aren't pro controllers
  87. generic_protocol->GetControllerType(device_type);
  88. } else {
  89. device_type = handle_device_type;
  90. }
  91. generic_protocol->GetSerialNumber(serial_number);
  92. }
  93. supported_features = GetSupportedFeatures();
  94. // Get Calibration data
  95. calibration_protocol->GetLeftJoyStickCalibration(left_stick_calibration);
  96. calibration_protocol->GetRightJoyStickCalibration(right_stick_calibration);
  97. calibration_protocol->GetImuCalibration(motion_calibration);
  98. // Set led status
  99. generic_protocol->SetLedBlinkPattern(static_cast<u8>(1 + port));
  100. // Apply HW configuration
  101. SetPollingMode();
  102. // Initialize joycon poller
  103. joycon_poller = std::make_unique<JoyconPoller>(device_type, left_stick_calibration,
  104. right_stick_calibration, motion_calibration);
  105. // Start polling for data
  106. is_connected = true;
  107. if (!input_thread_running) {
  108. input_thread =
  109. std::jthread([this](std::stop_token stop_token) { InputThread(stop_token); });
  110. }
  111. disable_input_thread = false;
  112. return Common::Input::DriverResult::Success;
  113. }
  114. void JoyconDriver::InputThread(std::stop_token stop_token) {
  115. LOG_INFO(Input, "Joycon Adapter input thread started");
  116. Common::SetCurrentThreadName("JoyconInput");
  117. input_thread_running = true;
  118. // Max update rate is 5ms, ensure we are always able to read a bit faster
  119. constexpr int ThreadDelay = 2;
  120. std::vector<u8> buffer(MaxBufferSize);
  121. while (!stop_token.stop_requested()) {
  122. int status = 0;
  123. if (!IsInputThreadValid()) {
  124. input_thread.request_stop();
  125. continue;
  126. }
  127. // By disabling the input thread we can ensure custom commands will succeed as no package is
  128. // skipped
  129. if (!disable_input_thread) {
  130. status = SDL_hid_read_timeout(hidapi_handle->handle, buffer.data(), buffer.size(),
  131. ThreadDelay);
  132. } else {
  133. std::this_thread::sleep_for(std::chrono::milliseconds(ThreadDelay));
  134. }
  135. if (IsPayloadCorrect(status, buffer)) {
  136. OnNewData(buffer);
  137. }
  138. std::this_thread::yield();
  139. }
  140. is_connected = false;
  141. input_thread_running = false;
  142. LOG_INFO(Input, "Joycon Adapter input thread stopped");
  143. }
  144. void JoyconDriver::OnNewData(std::span<u8> buffer) {
  145. const auto report_mode = static_cast<ReportMode>(buffer[0]);
  146. // Packages can be a little bit inconsistent. Average the delta time to provide a smoother
  147. // motion experience
  148. switch (report_mode) {
  149. case ReportMode::STANDARD_FULL_60HZ:
  150. case ReportMode::NFC_IR_MODE_60HZ:
  151. case ReportMode::SIMPLE_HID_MODE: {
  152. const auto now = std::chrono::steady_clock::now();
  153. const auto new_delta_time = static_cast<u64>(
  154. std::chrono::duration_cast<std::chrono::microseconds>(now - last_update).count());
  155. delta_time = ((delta_time * 8) + (new_delta_time * 2)) / 10;
  156. last_update = now;
  157. joycon_poller->UpdateColor(color);
  158. break;
  159. }
  160. default:
  161. break;
  162. }
  163. const MotionStatus motion_status{
  164. .is_enabled = motion_enabled,
  165. .delta_time = delta_time,
  166. .gyro_sensitivity = gyro_sensitivity,
  167. .accelerometer_sensitivity = accelerometer_sensitivity,
  168. };
  169. // TODO: Remove this when calibration is properly loaded and not calculated
  170. if (ring_connected && report_mode == ReportMode::STANDARD_FULL_60HZ) {
  171. InputReportActive data{};
  172. memcpy(&data, buffer.data(), sizeof(InputReportActive));
  173. calibration_protocol->GetRingCalibration(ring_calibration, data.ring_input);
  174. }
  175. const RingStatus ring_status{
  176. .is_enabled = ring_connected,
  177. .default_value = ring_calibration.default_value,
  178. .max_value = ring_calibration.max_value,
  179. .min_value = ring_calibration.min_value,
  180. };
  181. if (irs_protocol->IsEnabled()) {
  182. irs_protocol->RequestImage(buffer);
  183. joycon_poller->UpdateCamera(irs_protocol->GetImage(), irs_protocol->GetIrsFormat());
  184. }
  185. if (nfc_protocol->IsPolling()) {
  186. if (amiibo_detected) {
  187. if (!nfc_protocol->HasAmiibo()) {
  188. joycon_poller->UpdateAmiibo({});
  189. amiibo_detected = false;
  190. return;
  191. }
  192. }
  193. if (!amiibo_detected) {
  194. Joycon::TagInfo tag_info;
  195. const auto result = nfc_protocol->GetTagInfo(tag_info);
  196. if (result == Common::Input::DriverResult::Success) {
  197. joycon_poller->UpdateAmiibo(tag_info);
  198. amiibo_detected = true;
  199. }
  200. }
  201. }
  202. switch (report_mode) {
  203. case ReportMode::STANDARD_FULL_60HZ:
  204. joycon_poller->ReadActiveMode(buffer, motion_status, ring_status);
  205. break;
  206. case ReportMode::NFC_IR_MODE_60HZ:
  207. joycon_poller->ReadNfcIRMode(buffer, motion_status);
  208. break;
  209. case ReportMode::SIMPLE_HID_MODE:
  210. joycon_poller->ReadPassiveMode(buffer);
  211. break;
  212. case ReportMode::SUBCMD_REPLY:
  213. LOG_DEBUG(Input, "Unhandled command reply");
  214. break;
  215. default:
  216. LOG_ERROR(Input, "Report mode not Implemented {}", report_mode);
  217. break;
  218. }
  219. }
  220. Common::Input::DriverResult JoyconDriver::SetPollingMode() {
  221. SCOPE_EXIT({ disable_input_thread = false; });
  222. disable_input_thread = true;
  223. rumble_protocol->EnableRumble(vibration_enabled && supported_features.vibration);
  224. if (motion_enabled && supported_features.motion) {
  225. generic_protocol->EnableImu(true);
  226. generic_protocol->SetImuConfig(gyro_sensitivity, gyro_performance,
  227. accelerometer_sensitivity, accelerometer_performance);
  228. } else {
  229. generic_protocol->EnableImu(false);
  230. }
  231. if (input_only_device) {
  232. return Common::Input::DriverResult::NotSupported;
  233. }
  234. if (irs_protocol->IsEnabled()) {
  235. irs_protocol->DisableIrs();
  236. }
  237. if (nfc_protocol->IsEnabled()) {
  238. amiibo_detected = false;
  239. nfc_protocol->DisableNfc();
  240. }
  241. if (ring_protocol->IsEnabled()) {
  242. ring_connected = false;
  243. ring_protocol->DisableRingCon();
  244. }
  245. if (irs_enabled && supported_features.irs) {
  246. auto result = irs_protocol->EnableIrs();
  247. if (result == Common::Input::DriverResult::Success) {
  248. return result;
  249. }
  250. irs_protocol->DisableIrs();
  251. LOG_ERROR(Input, "Error enabling IRS");
  252. return result;
  253. }
  254. if (nfc_enabled && supported_features.nfc) {
  255. auto result = nfc_protocol->EnableNfc();
  256. if (result == Common::Input::DriverResult::Success) {
  257. return result;
  258. }
  259. nfc_protocol->DisableNfc();
  260. LOG_ERROR(Input, "Error enabling NFC");
  261. return result;
  262. }
  263. if (hidbus_enabled && supported_features.hidbus) {
  264. auto result = ring_protocol->EnableRingCon();
  265. if (result == Common::Input::DriverResult::Success) {
  266. result = ring_protocol->StartRingconPolling();
  267. }
  268. if (result == Common::Input::DriverResult::Success) {
  269. ring_connected = true;
  270. return result;
  271. }
  272. ring_connected = false;
  273. ring_protocol->DisableRingCon();
  274. LOG_ERROR(Input, "Error enabling Ringcon");
  275. return result;
  276. }
  277. if (passive_enabled && supported_features.passive) {
  278. const auto result = generic_protocol->EnablePassiveMode();
  279. if (result == Common::Input::DriverResult::Success) {
  280. return result;
  281. }
  282. LOG_ERROR(Input, "Error enabling passive mode");
  283. }
  284. // Default Mode
  285. const auto result = generic_protocol->EnableActiveMode();
  286. if (result != Common::Input::DriverResult::Success) {
  287. LOG_ERROR(Input, "Error enabling active mode");
  288. }
  289. // Switch calls this function after enabling active mode
  290. generic_protocol->TriggersElapsed();
  291. return result;
  292. }
  293. JoyconDriver::SupportedFeatures JoyconDriver::GetSupportedFeatures() {
  294. SupportedFeatures features{
  295. .passive = true,
  296. .motion = true,
  297. .vibration = true,
  298. };
  299. if (input_only_device) {
  300. return features;
  301. }
  302. if (device_type == ControllerType::Right) {
  303. features.nfc = true;
  304. features.irs = true;
  305. features.hidbus = true;
  306. }
  307. if (device_type == ControllerType::Pro) {
  308. features.nfc = true;
  309. }
  310. return features;
  311. }
  312. bool JoyconDriver::IsInputThreadValid() const {
  313. if (!is_connected.load()) {
  314. return false;
  315. }
  316. if (hidapi_handle->handle == nullptr) {
  317. return false;
  318. }
  319. // Controller is not responding. Terminate connection
  320. if (error_counter > MaxErrorCount) {
  321. return false;
  322. }
  323. return true;
  324. }
  325. bool JoyconDriver::IsPayloadCorrect(int status, std::span<const u8> buffer) {
  326. if (status <= -1) {
  327. error_counter++;
  328. return false;
  329. }
  330. // There's no new data
  331. if (status == 0) {
  332. return false;
  333. }
  334. // No reply ever starts with zero
  335. if (buffer[0] == 0x00) {
  336. error_counter++;
  337. return false;
  338. }
  339. error_counter = 0;
  340. return true;
  341. }
  342. Common::Input::DriverResult JoyconDriver::SetVibration(const VibrationValue& vibration) {
  343. std::scoped_lock lock{mutex};
  344. if (disable_input_thread) {
  345. return Common::Input::DriverResult::HandleInUse;
  346. }
  347. return rumble_protocol->SendVibration(vibration);
  348. }
  349. Common::Input::DriverResult JoyconDriver::SetLedConfig(u8 led_pattern) {
  350. std::scoped_lock lock{mutex};
  351. if (disable_input_thread) {
  352. return Common::Input::DriverResult::HandleInUse;
  353. }
  354. return generic_protocol->SetLedPattern(led_pattern);
  355. }
  356. Common::Input::DriverResult JoyconDriver::SetIrsConfig(IrsMode mode_, IrsResolution format_) {
  357. std::scoped_lock lock{mutex};
  358. if (disable_input_thread) {
  359. return Common::Input::DriverResult::HandleInUse;
  360. }
  361. disable_input_thread = true;
  362. const auto result = irs_protocol->SetIrsConfig(mode_, format_);
  363. disable_input_thread = false;
  364. return result;
  365. }
  366. Common::Input::DriverResult JoyconDriver::SetPassiveMode() {
  367. std::scoped_lock lock{mutex};
  368. motion_enabled = false;
  369. hidbus_enabled = false;
  370. nfc_enabled = false;
  371. passive_enabled = true;
  372. irs_enabled = false;
  373. return SetPollingMode();
  374. }
  375. Common::Input::DriverResult JoyconDriver::SetActiveMode() {
  376. if (is_ring_disabled_by_irs) {
  377. is_ring_disabled_by_irs = false;
  378. SetActiveMode();
  379. return SetRingConMode();
  380. }
  381. std::scoped_lock lock{mutex};
  382. motion_enabled = true;
  383. hidbus_enabled = false;
  384. nfc_enabled = false;
  385. passive_enabled = false;
  386. irs_enabled = false;
  387. return SetPollingMode();
  388. }
  389. Common::Input::DriverResult JoyconDriver::SetIrMode() {
  390. std::scoped_lock lock{mutex};
  391. if (!supported_features.irs) {
  392. return Common::Input::DriverResult::NotSupported;
  393. }
  394. if (ring_connected) {
  395. is_ring_disabled_by_irs = true;
  396. }
  397. motion_enabled = false;
  398. hidbus_enabled = false;
  399. nfc_enabled = false;
  400. passive_enabled = false;
  401. irs_enabled = true;
  402. return SetPollingMode();
  403. }
  404. Common::Input::DriverResult JoyconDriver::SetNfcMode() {
  405. std::scoped_lock lock{mutex};
  406. if (!supported_features.nfc) {
  407. return Common::Input::DriverResult::NotSupported;
  408. }
  409. motion_enabled = true;
  410. hidbus_enabled = false;
  411. nfc_enabled = true;
  412. passive_enabled = false;
  413. irs_enabled = false;
  414. return SetPollingMode();
  415. }
  416. Common::Input::DriverResult JoyconDriver::SetRingConMode() {
  417. std::scoped_lock lock{mutex};
  418. if (!supported_features.hidbus) {
  419. return Common::Input::DriverResult::NotSupported;
  420. }
  421. motion_enabled = true;
  422. hidbus_enabled = true;
  423. nfc_enabled = false;
  424. passive_enabled = false;
  425. irs_enabled = false;
  426. const auto result = SetPollingMode();
  427. if (!ring_connected) {
  428. return Common::Input::DriverResult::NoDeviceDetected;
  429. }
  430. return result;
  431. }
  432. Common::Input::DriverResult JoyconDriver::StartNfcPolling() {
  433. std::scoped_lock lock{mutex};
  434. if (!supported_features.nfc) {
  435. return Common::Input::DriverResult::NotSupported;
  436. }
  437. if (!nfc_protocol->IsEnabled()) {
  438. return Common::Input::DriverResult::Disabled;
  439. }
  440. disable_input_thread = true;
  441. const auto result = nfc_protocol->StartNFCPollingMode();
  442. disable_input_thread = false;
  443. return result;
  444. }
  445. Common::Input::DriverResult JoyconDriver::StopNfcPolling() {
  446. std::scoped_lock lock{mutex};
  447. if (!supported_features.nfc) {
  448. return Common::Input::DriverResult::NotSupported;
  449. }
  450. if (!nfc_protocol->IsEnabled()) {
  451. return Common::Input::DriverResult::Disabled;
  452. }
  453. disable_input_thread = true;
  454. const auto result = nfc_protocol->StopNFCPollingMode();
  455. disable_input_thread = false;
  456. if (amiibo_detected) {
  457. amiibo_detected = false;
  458. joycon_poller->UpdateAmiibo({});
  459. }
  460. return result;
  461. }
  462. Common::Input::DriverResult JoyconDriver::ReadAmiiboData(std::vector<u8>& out_data) {
  463. std::scoped_lock lock{mutex};
  464. if (!supported_features.nfc) {
  465. return Common::Input::DriverResult::NotSupported;
  466. }
  467. if (!nfc_protocol->IsEnabled()) {
  468. return Common::Input::DriverResult::Disabled;
  469. }
  470. if (!amiibo_detected) {
  471. return Common::Input::DriverResult::ErrorWritingData;
  472. }
  473. out_data.resize(0x21C);
  474. disable_input_thread = true;
  475. const auto result = nfc_protocol->ReadAmiibo(out_data);
  476. disable_input_thread = false;
  477. return result;
  478. }
  479. Common::Input::DriverResult JoyconDriver::WriteNfcData(std::span<const u8> data) {
  480. std::scoped_lock lock{mutex};
  481. if (!supported_features.nfc) {
  482. return Common::Input::DriverResult::NotSupported;
  483. }
  484. if (!nfc_protocol->IsEnabled()) {
  485. return Common::Input::DriverResult::Disabled;
  486. }
  487. if (!amiibo_detected) {
  488. return Common::Input::DriverResult::ErrorWritingData;
  489. }
  490. disable_input_thread = true;
  491. const auto result = nfc_protocol->WriteAmiibo(data);
  492. disable_input_thread = false;
  493. return result;
  494. }
  495. Common::Input::DriverResult JoyconDriver::ReadMifareData(std::span<const MifareReadChunk> data,
  496. std::span<MifareReadData> out_data) {
  497. std::scoped_lock lock{mutex};
  498. if (!supported_features.nfc) {
  499. return Common::Input::DriverResult::NotSupported;
  500. }
  501. if (!nfc_protocol->IsEnabled()) {
  502. return Common::Input::DriverResult::Disabled;
  503. }
  504. if (!amiibo_detected) {
  505. return Common::Input::DriverResult::ErrorWritingData;
  506. }
  507. disable_input_thread = true;
  508. const auto result = nfc_protocol->ReadMifare(data, out_data);
  509. disable_input_thread = false;
  510. return result;
  511. }
  512. Common::Input::DriverResult JoyconDriver::WriteMifareData(std::span<const MifareWriteChunk> data) {
  513. std::scoped_lock lock{mutex};
  514. if (!supported_features.nfc) {
  515. return Common::Input::DriverResult::NotSupported;
  516. }
  517. if (!nfc_protocol->IsEnabled()) {
  518. return Common::Input::DriverResult::Disabled;
  519. }
  520. if (!amiibo_detected) {
  521. return Common::Input::DriverResult::ErrorWritingData;
  522. }
  523. disable_input_thread = true;
  524. const auto result = nfc_protocol->WriteMifare(data);
  525. disable_input_thread = false;
  526. return result;
  527. }
  528. bool JoyconDriver::IsConnected() const {
  529. std::scoped_lock lock{mutex};
  530. return is_connected.load();
  531. }
  532. bool JoyconDriver::IsVibrationEnabled() const {
  533. std::scoped_lock lock{mutex};
  534. return vibration_enabled;
  535. }
  536. FirmwareVersion JoyconDriver::GetDeviceVersion() const {
  537. std::scoped_lock lock{mutex};
  538. return version;
  539. }
  540. Color JoyconDriver::GetDeviceColor() const {
  541. std::scoped_lock lock{mutex};
  542. return color;
  543. }
  544. std::size_t JoyconDriver::GetDevicePort() const {
  545. std::scoped_lock lock{mutex};
  546. return port;
  547. }
  548. ControllerType JoyconDriver::GetDeviceType() const {
  549. std::scoped_lock lock{mutex};
  550. return device_type;
  551. }
  552. ControllerType JoyconDriver::GetHandleDeviceType() const {
  553. std::scoped_lock lock{mutex};
  554. return handle_device_type;
  555. }
  556. SerialNumber JoyconDriver::GetSerialNumber() const {
  557. std::scoped_lock lock{mutex};
  558. return serial_number;
  559. }
  560. SerialNumber JoyconDriver::GetHandleSerialNumber() const {
  561. std::scoped_lock lock{mutex};
  562. return handle_serial_number;
  563. }
  564. void JoyconDriver::SetCallbacks(const JoyconCallbacks& callbacks) {
  565. joycon_poller->SetCallbacks(callbacks);
  566. }
  567. Common::Input::DriverResult JoyconDriver::GetDeviceType(SDL_hid_device_info* device_info,
  568. ControllerType& controller_type) {
  569. static constexpr std::array<std::pair<u32, ControllerType>, 6> supported_devices{
  570. std::pair<u32, ControllerType>{0x2006, ControllerType::Left},
  571. {0x2007, ControllerType::Right},
  572. {0x2009, ControllerType::Pro},
  573. };
  574. constexpr u16 nintendo_vendor_id = 0x057e;
  575. controller_type = ControllerType::None;
  576. if (device_info->vendor_id != nintendo_vendor_id) {
  577. return Common::Input::DriverResult::UnsupportedControllerType;
  578. }
  579. for (const auto& [product_id, type] : supported_devices) {
  580. if (device_info->product_id == static_cast<u16>(product_id)) {
  581. controller_type = type;
  582. return Common::Input::DriverResult::Success;
  583. }
  584. }
  585. return Common::Input::DriverResult::UnsupportedControllerType;
  586. }
  587. Common::Input::DriverResult JoyconDriver::GetSerialNumber(SDL_hid_device_info* device_info,
  588. SerialNumber& serial_number) {
  589. if (device_info->serial_number == nullptr) {
  590. return Common::Input::DriverResult::Unknown;
  591. }
  592. std::memcpy(&serial_number, device_info->serial_number, 15);
  593. return Common::Input::DriverResult::Success;
  594. }
  595. } // namespace InputCommon::Joycon