hid.cpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432
  1. // Copyright 2018 yuzu emulator team
  2. // Licensed under GPLv2 or any later version
  3. // Refer to the license.txt file included.
  4. #include <atomic>
  5. #include "common/logging/log.h"
  6. #include "core/core_timing.h"
  7. #include "core/frontend/input.h"
  8. #include "core/hle/ipc_helpers.h"
  9. #include "core/hle/kernel/client_port.h"
  10. #include "core/hle/kernel/client_session.h"
  11. #include "core/hle/kernel/event.h"
  12. #include "core/hle/kernel/shared_memory.h"
  13. #include "core/hle/service/hid/hid.h"
  14. #include "core/hle/service/service.h"
  15. namespace Service {
  16. namespace HID {
  17. // Updating period for each HID device.
  18. // TODO(shinyquagsire23): These need better values.
  19. constexpr u64 pad_update_ticks = BASE_CLOCK_RATE / 10000;
  20. constexpr u64 accelerometer_update_ticks = BASE_CLOCK_RATE / 10000;
  21. constexpr u64 gyroscope_update_ticks = BASE_CLOCK_RATE / 10000;
  22. class IAppletResource final : public ServiceFramework<IAppletResource> {
  23. public:
  24. IAppletResource() : ServiceFramework("IAppletResource") {
  25. static const FunctionInfo functions[] = {
  26. {0, &IAppletResource::GetSharedMemoryHandle, "GetSharedMemoryHandle"},
  27. };
  28. RegisterHandlers(functions);
  29. shared_mem = Kernel::SharedMemory::Create(
  30. nullptr, 0x40000, Kernel::MemoryPermission::ReadWrite, Kernel::MemoryPermission::Read,
  31. 0, Kernel::MemoryRegion::BASE, "HID:SharedMemory");
  32. // Register update callbacks
  33. pad_update_event = CoreTiming::RegisterEvent(
  34. "HID::UpdatePadCallback",
  35. [this](u64 userdata, int cycles_late) { UpdatePadCallback(userdata, cycles_late); });
  36. // TODO(shinyquagsire23): Other update callbacks? (accel, gyro?)
  37. CoreTiming::ScheduleEvent(pad_update_ticks, pad_update_event);
  38. }
  39. ~IAppletResource() {
  40. CoreTiming::UnscheduleEvent(pad_update_event, 0);
  41. }
  42. private:
  43. void GetSharedMemoryHandle(Kernel::HLERequestContext& ctx) {
  44. IPC::ResponseBuilder rb{ctx, 2, 1};
  45. rb.Push(RESULT_SUCCESS);
  46. rb.PushCopyObjects(shared_mem);
  47. LOG_DEBUG(Service_HID, "called");
  48. }
  49. void LoadInputDevices() {
  50. std::transform(Settings::values.buttons.begin() + Settings::NativeButton::BUTTON_HID_BEGIN,
  51. Settings::values.buttons.begin() + Settings::NativeButton::BUTTON_HID_END,
  52. buttons.begin(), Input::CreateDevice<Input::ButtonDevice>);
  53. // TODO(shinyquagsire23): sticks, gyro, touch, mouse, keyboard
  54. }
  55. void UpdatePadCallback(u64 userdata, int cycles_late) {
  56. SharedMemory mem{};
  57. std::memcpy(&mem, shared_mem->GetPointer(), sizeof(SharedMemory));
  58. if (is_device_reload_pending.exchange(false))
  59. LoadInputDevices();
  60. // Set up controllers as neon red+blue Joy-Con attached to console
  61. ControllerHeader& controller_header = mem.controllers[Controller_Handheld].header;
  62. controller_header.type = ControllerType_Handheld | ControllerType_JoyconPair;
  63. controller_header.single_colors_descriptor = ColorDesc_ColorsNonexistent;
  64. controller_header.right_color_body = JOYCON_BODY_NEON_RED;
  65. controller_header.right_color_buttons = JOYCON_BUTTONS_NEON_RED;
  66. controller_header.left_color_body = JOYCON_BODY_NEON_BLUE;
  67. controller_header.left_color_buttons = JOYCON_BUTTONS_NEON_BLUE;
  68. for (int index = 0; index < HID_NUM_LAYOUTS; index++) {
  69. ControllerLayout& layout = mem.controllers[Controller_Handheld].layouts[index];
  70. layout.header.num_entries = HID_NUM_ENTRIES;
  71. layout.header.max_entry_index = HID_NUM_ENTRIES - 1;
  72. // HID shared memory stores the state of the past 17 samples in a circlular buffer,
  73. // each with a timestamp in number of samples since boot.
  74. layout.header.timestamp_ticks = CoreTiming::GetTicks();
  75. layout.header.latest_entry = (layout.header.latest_entry + 1) % HID_NUM_ENTRIES;
  76. ControllerInputEntry& entry = layout.entries[layout.header.latest_entry];
  77. entry.connection_state = ConnectionState_Connected | ConnectionState_Wired;
  78. entry.timestamp++;
  79. entry.timestamp_2++; // TODO(shinyquagsire23): Is this always identical to timestamp?
  80. // TODO(shinyquagsire23): Set up some LUTs for each layout mapping in the future?
  81. // For now everything is just the default handheld layout, but split Joy-Con will
  82. // rotate the face buttons and directions for certain layouts.
  83. ControllerPadState& state = entry.buttons;
  84. using namespace Settings::NativeButton;
  85. state.a.Assign(buttons[A - BUTTON_HID_BEGIN]->GetStatus());
  86. state.b.Assign(buttons[B - BUTTON_HID_BEGIN]->GetStatus());
  87. state.x.Assign(buttons[X - BUTTON_HID_BEGIN]->GetStatus());
  88. state.y.Assign(buttons[Y - BUTTON_HID_BEGIN]->GetStatus());
  89. state.lstick.Assign(buttons[LStick - BUTTON_HID_BEGIN]->GetStatus());
  90. state.rstick.Assign(buttons[RStick - BUTTON_HID_BEGIN]->GetStatus());
  91. state.l.Assign(buttons[L - BUTTON_HID_BEGIN]->GetStatus());
  92. state.r.Assign(buttons[R - BUTTON_HID_BEGIN]->GetStatus());
  93. state.zl.Assign(buttons[ZL - BUTTON_HID_BEGIN]->GetStatus());
  94. state.zr.Assign(buttons[ZR - BUTTON_HID_BEGIN]->GetStatus());
  95. state.plus.Assign(buttons[Plus - BUTTON_HID_BEGIN]->GetStatus());
  96. state.minus.Assign(buttons[Minus - BUTTON_HID_BEGIN]->GetStatus());
  97. state.dleft.Assign(buttons[DLeft - BUTTON_HID_BEGIN]->GetStatus());
  98. state.dup.Assign(buttons[DUp - BUTTON_HID_BEGIN]->GetStatus());
  99. state.dright.Assign(buttons[DRight - BUTTON_HID_BEGIN]->GetStatus());
  100. state.ddown.Assign(buttons[DDown - BUTTON_HID_BEGIN]->GetStatus());
  101. state.lstick_left.Assign(buttons[LStick_Left - BUTTON_HID_BEGIN]->GetStatus());
  102. state.lstick_up.Assign(buttons[LStick_Up - BUTTON_HID_BEGIN]->GetStatus());
  103. state.lstick_right.Assign(buttons[LStick_Right - BUTTON_HID_BEGIN]->GetStatus());
  104. state.lstick_down.Assign(buttons[LStick_Down - BUTTON_HID_BEGIN]->GetStatus());
  105. state.rstick_left.Assign(buttons[RStick_Left - BUTTON_HID_BEGIN]->GetStatus());
  106. state.rstick_up.Assign(buttons[RStick_Up - BUTTON_HID_BEGIN]->GetStatus());
  107. state.rstick_right.Assign(buttons[RStick_Right - BUTTON_HID_BEGIN]->GetStatus());
  108. state.rstick_down.Assign(buttons[RStick_Down - BUTTON_HID_BEGIN]->GetStatus());
  109. state.sl.Assign(buttons[SL - BUTTON_HID_BEGIN]->GetStatus());
  110. state.sr.Assign(buttons[SR - BUTTON_HID_BEGIN]->GetStatus());
  111. // TODO(shinyquagsire23): Analog stick vals
  112. // TODO(shinyquagsire23): Update pad info proper, (circular buffers, timestamps,
  113. // layouts)
  114. }
  115. // TODO(bunnei): Properly implement the touch screen, the below will just write empty data
  116. TouchScreen& touchscreen = mem.touchscreen;
  117. const u64 last_entry = touchscreen.header.latest_entry;
  118. const u64 curr_entry = (last_entry + 1) % touchscreen.entries.size();
  119. const u64 timestamp = CoreTiming::GetTicks();
  120. const u64 sample_counter = touchscreen.entries[last_entry].header.timestamp + 1;
  121. touchscreen.header.timestamp_ticks = timestamp;
  122. touchscreen.header.num_entries = touchscreen.entries.size();
  123. touchscreen.header.latest_entry = curr_entry;
  124. touchscreen.header.max_entry_index = touchscreen.entries.size();
  125. touchscreen.header.timestamp = timestamp;
  126. touchscreen.entries[curr_entry].header.timestamp = sample_counter;
  127. touchscreen.entries[curr_entry].header.num_touches = 0;
  128. // TODO(shinyquagsire23): Signal events
  129. std::memcpy(shared_mem->GetPointer(), &mem, sizeof(SharedMemory));
  130. // Reschedule recurrent event
  131. CoreTiming::ScheduleEvent(pad_update_ticks - cycles_late, pad_update_event);
  132. }
  133. // Handle to shared memory region designated to HID service
  134. Kernel::SharedPtr<Kernel::SharedMemory> shared_mem;
  135. // CoreTiming update events
  136. CoreTiming::EventType* pad_update_event;
  137. // Stored input state info
  138. std::atomic<bool> is_device_reload_pending{true};
  139. std::array<std::unique_ptr<Input::ButtonDevice>, Settings::NativeButton::NUM_BUTTONS_HID>
  140. buttons;
  141. };
  142. class IActiveVibrationDeviceList final : public ServiceFramework<IActiveVibrationDeviceList> {
  143. public:
  144. IActiveVibrationDeviceList() : ServiceFramework("IActiveVibrationDeviceList") {
  145. static const FunctionInfo functions[] = {
  146. {0, &IActiveVibrationDeviceList::ActivateVibrationDevice, "ActivateVibrationDevice"},
  147. };
  148. RegisterHandlers(functions);
  149. }
  150. private:
  151. void ActivateVibrationDevice(Kernel::HLERequestContext& ctx) {
  152. IPC::ResponseBuilder rb{ctx, 2};
  153. rb.Push(RESULT_SUCCESS);
  154. LOG_WARNING(Service_HID, "(STUBBED) called");
  155. }
  156. };
  157. class Hid final : public ServiceFramework<Hid> {
  158. public:
  159. Hid() : ServiceFramework("hid") {
  160. static const FunctionInfo functions[] = {
  161. {0, &Hid::CreateAppletResource, "CreateAppletResource"},
  162. {1, &Hid::ActivateDebugPad, "ActivateDebugPad"},
  163. {11, &Hid::ActivateTouchScreen, "ActivateTouchScreen"},
  164. {21, &Hid::ActivateMouse, "ActivateMouse"},
  165. {31, &Hid::ActivateKeyboard, "ActivateKeyboard"},
  166. {40, nullptr, "AcquireXpadIdEventHandle"},
  167. {41, nullptr, "ReleaseXpadIdEventHandle"},
  168. {51, nullptr, "ActivateXpad"},
  169. {55, nullptr, "GetXpadIds"},
  170. {56, nullptr, "ActivateJoyXpad"},
  171. {58, nullptr, "GetJoyXpadLifoHandle"},
  172. {59, nullptr, "GetJoyXpadIds"},
  173. {60, nullptr, "ActivateSixAxisSensor"},
  174. {61, nullptr, "DeactivateSixAxisSensor"},
  175. {62, nullptr, "GetSixAxisSensorLifoHandle"},
  176. {63, nullptr, "ActivateJoySixAxisSensor"},
  177. {64, nullptr, "DeactivateJoySixAxisSensor"},
  178. {65, nullptr, "GetJoySixAxisSensorLifoHandle"},
  179. {66, &Hid::StartSixAxisSensor, "StartSixAxisSensor"},
  180. {67, nullptr, "StopSixAxisSensor"},
  181. {68, nullptr, "IsSixAxisSensorFusionEnabled"},
  182. {69, nullptr, "EnableSixAxisSensorFusion"},
  183. {70, nullptr, "SetSixAxisSensorFusionParameters"},
  184. {71, nullptr, "GetSixAxisSensorFusionParameters"},
  185. {72, nullptr, "ResetSixAxisSensorFusionParameters"},
  186. {73, nullptr, "SetAccelerometerParameters"},
  187. {74, nullptr, "GetAccelerometerParameters"},
  188. {75, nullptr, "ResetAccelerometerParameters"},
  189. {76, nullptr, "SetAccelerometerPlayMode"},
  190. {77, nullptr, "GetAccelerometerPlayMode"},
  191. {78, nullptr, "ResetAccelerometerPlayMode"},
  192. {79, &Hid::SetGyroscopeZeroDriftMode, "SetGyroscopeZeroDriftMode"},
  193. {80, nullptr, "GetGyroscopeZeroDriftMode"},
  194. {81, nullptr, "ResetGyroscopeZeroDriftMode"},
  195. {82, nullptr, "IsSixAxisSensorAtRest"},
  196. {91, nullptr, "ActivateGesture"},
  197. {100, &Hid::SetSupportedNpadStyleSet, "SetSupportedNpadStyleSet"},
  198. {101, &Hid::GetSupportedNpadStyleSet, "GetSupportedNpadStyleSet"},
  199. {102, &Hid::SetSupportedNpadIdType, "SetSupportedNpadIdType"},
  200. {103, &Hid::ActivateNpad, "ActivateNpad"},
  201. {104, nullptr, "DeactivateNpad"},
  202. {106, &Hid::AcquireNpadStyleSetUpdateEventHandle,
  203. "AcquireNpadStyleSetUpdateEventHandle"},
  204. {107, nullptr, "DisconnectNpad"},
  205. {108, nullptr, "GetPlayerLedPattern"},
  206. {120, &Hid::SetNpadJoyHoldType, "SetNpadJoyHoldType"},
  207. {121, &Hid::GetNpadJoyHoldType, "GetNpadJoyHoldType"},
  208. {122, &Hid::SetNpadJoyAssignmentModeSingleByDefault,
  209. "SetNpadJoyAssignmentModeSingleByDefault"},
  210. {123, nullptr, "SetNpadJoyAssignmentModeSingleByDefault"},
  211. {124, &Hid::SetNpadJoyAssignmentModeDual, "SetNpadJoyAssignmentModeDual"},
  212. {125, nullptr, "MergeSingleJoyAsDualJoy"},
  213. {126, nullptr, "StartLrAssignmentMode"},
  214. {127, nullptr, "StopLrAssignmentMode"},
  215. {128, &Hid::SetNpadHandheldActivationMode, "SetNpadHandheldActivationMode"},
  216. {129, nullptr, "GetNpadHandheldActivationMode"},
  217. {130, nullptr, "SwapNpadAssignment"},
  218. {131, nullptr, "IsUnintendedHomeButtonInputProtectionEnabled"},
  219. {132, nullptr, "EnableUnintendedHomeButtonInputProtection"},
  220. {200, &Hid::GetVibrationDeviceInfo, "GetVibrationDeviceInfo"},
  221. {201, &Hid::SendVibrationValue, "SendVibrationValue"},
  222. {202, &Hid::GetActualVibrationValue, "GetActualVibrationValue"},
  223. {203, &Hid::CreateActiveVibrationDeviceList, "CreateActiveVibrationDeviceList"},
  224. {204, nullptr, "PermitVibration"},
  225. {205, nullptr, "IsVibrationPermitted"},
  226. {206, &Hid::SendVibrationValues, "SendVibrationValues"},
  227. {300, nullptr, "ActivateConsoleSixAxisSensor"},
  228. {301, nullptr, "StartConsoleSixAxisSensor"},
  229. {302, nullptr, "StopConsoleSixAxisSensor"},
  230. {400, nullptr, "IsUsbFullKeyControllerEnabled"},
  231. {401, nullptr, "EnableUsbFullKeyController"},
  232. {402, nullptr, "IsUsbFullKeyControllerConnected"},
  233. {1000, nullptr, "SetNpadCommunicationMode"},
  234. {1001, nullptr, "GetNpadCommunicationMode"},
  235. };
  236. RegisterHandlers(functions);
  237. event = Kernel::Event::Create(Kernel::ResetType::OneShot, "hid:EventHandle");
  238. }
  239. ~Hid() = default;
  240. private:
  241. std::shared_ptr<IAppletResource> applet_resource;
  242. u32 joy_hold_type{0};
  243. Kernel::SharedPtr<Kernel::Event> event;
  244. void CreateAppletResource(Kernel::HLERequestContext& ctx) {
  245. if (applet_resource == nullptr) {
  246. applet_resource = std::make_shared<IAppletResource>();
  247. }
  248. IPC::ResponseBuilder rb{ctx, 2, 0, 1};
  249. rb.Push(RESULT_SUCCESS);
  250. rb.PushIpcInterface<IAppletResource>(applet_resource);
  251. LOG_DEBUG(Service_HID, "called");
  252. }
  253. void ActivateDebugPad(Kernel::HLERequestContext& ctx) {
  254. IPC::ResponseBuilder rb{ctx, 2};
  255. rb.Push(RESULT_SUCCESS);
  256. LOG_WARNING(Service_HID, "(STUBBED) called");
  257. }
  258. void ActivateTouchScreen(Kernel::HLERequestContext& ctx) {
  259. IPC::ResponseBuilder rb{ctx, 2};
  260. rb.Push(RESULT_SUCCESS);
  261. LOG_WARNING(Service_HID, "(STUBBED) called");
  262. }
  263. void ActivateMouse(Kernel::HLERequestContext& ctx) {
  264. IPC::ResponseBuilder rb{ctx, 2};
  265. rb.Push(RESULT_SUCCESS);
  266. LOG_WARNING(Service_HID, "(STUBBED) called");
  267. }
  268. void ActivateKeyboard(Kernel::HLERequestContext& ctx) {
  269. IPC::ResponseBuilder rb{ctx, 2};
  270. rb.Push(RESULT_SUCCESS);
  271. LOG_WARNING(Service_HID, "(STUBBED) called");
  272. }
  273. void StartSixAxisSensor(Kernel::HLERequestContext& ctx) {
  274. IPC::ResponseBuilder rb{ctx, 2};
  275. rb.Push(RESULT_SUCCESS);
  276. LOG_WARNING(Service_HID, "(STUBBED) called");
  277. }
  278. void SetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx) {
  279. IPC::ResponseBuilder rb{ctx, 2};
  280. rb.Push(RESULT_SUCCESS);
  281. LOG_WARNING(Service_HID, "(STUBBED) called");
  282. }
  283. void SetSupportedNpadStyleSet(Kernel::HLERequestContext& ctx) {
  284. IPC::ResponseBuilder rb{ctx, 2};
  285. rb.Push(RESULT_SUCCESS);
  286. LOG_WARNING(Service_HID, "(STUBBED) called");
  287. }
  288. void GetSupportedNpadStyleSet(Kernel::HLERequestContext& ctx) {
  289. IPC::ResponseBuilder rb{ctx, 3};
  290. rb.Push(RESULT_SUCCESS);
  291. rb.Push<u32>(0);
  292. LOG_WARNING(Service_HID, "(STUBBED) called");
  293. }
  294. void SetSupportedNpadIdType(Kernel::HLERequestContext& ctx) {
  295. IPC::ResponseBuilder rb{ctx, 2};
  296. rb.Push(RESULT_SUCCESS);
  297. LOG_WARNING(Service_HID, "(STUBBED) called");
  298. }
  299. void ActivateNpad(Kernel::HLERequestContext& ctx) {
  300. IPC::ResponseBuilder rb{ctx, 2};
  301. rb.Push(RESULT_SUCCESS);
  302. LOG_WARNING(Service_HID, "(STUBBED) called");
  303. }
  304. void AcquireNpadStyleSetUpdateEventHandle(Kernel::HLERequestContext& ctx) {
  305. IPC::ResponseBuilder rb{ctx, 2, 1};
  306. rb.Push(RESULT_SUCCESS);
  307. rb.PushCopyObjects(event);
  308. LOG_WARNING(Service_HID, "(STUBBED) called");
  309. }
  310. void SetNpadJoyHoldType(Kernel::HLERequestContext& ctx) {
  311. IPC::ResponseBuilder rb{ctx, 2};
  312. rb.Push(RESULT_SUCCESS);
  313. LOG_WARNING(Service_HID, "(STUBBED) called");
  314. }
  315. void GetNpadJoyHoldType(Kernel::HLERequestContext& ctx) {
  316. IPC::ResponseBuilder rb{ctx, 3};
  317. rb.Push(RESULT_SUCCESS);
  318. rb.Push(joy_hold_type);
  319. LOG_WARNING(Service_HID, "(STUBBED) called");
  320. }
  321. void SetNpadJoyAssignmentModeSingleByDefault(Kernel::HLERequestContext& ctx) {
  322. IPC::ResponseBuilder rb{ctx, 2};
  323. rb.Push(RESULT_SUCCESS);
  324. LOG_WARNING(Service_HID, "(STUBBED) called");
  325. }
  326. void SendVibrationValue(Kernel::HLERequestContext& ctx) {
  327. IPC::ResponseBuilder rb{ctx, 2};
  328. rb.Push(RESULT_SUCCESS);
  329. LOG_WARNING(Service_HID, "(STUBBED) called");
  330. }
  331. void GetActualVibrationValue(Kernel::HLERequestContext& ctx) {
  332. IPC::ResponseBuilder rb{ctx, 2};
  333. rb.Push(RESULT_SUCCESS);
  334. LOG_WARNING(Service_HID, "(STUBBED) called");
  335. }
  336. void SetNpadJoyAssignmentModeDual(Kernel::HLERequestContext& ctx) {
  337. IPC::ResponseBuilder rb{ctx, 2};
  338. rb.Push(RESULT_SUCCESS);
  339. LOG_WARNING(Service_HID, "(STUBBED) called");
  340. }
  341. void SetNpadHandheldActivationMode(Kernel::HLERequestContext& ctx) {
  342. IPC::ResponseBuilder rb{ctx, 2};
  343. rb.Push(RESULT_SUCCESS);
  344. LOG_WARNING(Service_HID, "(STUBBED) called");
  345. }
  346. void GetVibrationDeviceInfo(Kernel::HLERequestContext& ctx) {
  347. IPC::ResponseBuilder rb{ctx, 4};
  348. rb.Push(RESULT_SUCCESS);
  349. rb.Push<u64>(0);
  350. LOG_WARNING(Service_HID, "(STUBBED) called");
  351. }
  352. void CreateActiveVibrationDeviceList(Kernel::HLERequestContext& ctx) {
  353. IPC::ResponseBuilder rb{ctx, 2, 0, 1};
  354. rb.Push(RESULT_SUCCESS);
  355. rb.PushIpcInterface<IActiveVibrationDeviceList>();
  356. LOG_DEBUG(Service_HID, "called");
  357. }
  358. void SendVibrationValues(Kernel::HLERequestContext& ctx) {
  359. IPC::ResponseBuilder rb{ctx, 2};
  360. rb.Push(RESULT_SUCCESS);
  361. LOG_WARNING(Service_HID, "(STUBBED) called");
  362. }
  363. };
  364. void ReloadInputDevices() {}
  365. void InstallInterfaces(SM::ServiceManager& service_manager) {
  366. std::make_shared<Hid>()->InstallAsService(service_manager);
  367. }
  368. } // namespace HID
  369. } // namespace Service