hid.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305
  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. private:
  40. void GetSharedMemoryHandle(Kernel::HLERequestContext& ctx) {
  41. IPC::ResponseBuilder rb{ctx, 2, 1};
  42. rb.Push(RESULT_SUCCESS);
  43. rb.PushCopyObjects(shared_mem);
  44. LOG_DEBUG(Service_HID, "called");
  45. }
  46. void LoadInputDevices() {
  47. std::transform(Settings::values.buttons.begin() + Settings::NativeButton::BUTTON_HID_BEGIN,
  48. Settings::values.buttons.begin() + Settings::NativeButton::BUTTON_HID_END,
  49. buttons.begin(), Input::CreateDevice<Input::ButtonDevice>);
  50. // TODO(shinyquagsire23): sticks, gyro, touch, mouse, keyboard
  51. }
  52. void UpdatePadCallback(u64 userdata, int cycles_late) {
  53. SharedMemory* mem = reinterpret_cast<SharedMemory*>(shared_mem->GetPointer());
  54. if (is_device_reload_pending.exchange(false))
  55. LoadInputDevices();
  56. // Set up controllers as neon red+blue Joy-Con attached to console
  57. ControllerHeader& controller_header = mem->controllers[Controller_Handheld].header;
  58. controller_header.type = ControllerType_Handheld | ControllerType_JoyconPair;
  59. controller_header.single_colors_descriptor = ColorDesc_ColorsNonexistent;
  60. controller_header.right_color_body = JOYCON_BODY_NEON_RED;
  61. controller_header.right_color_buttons = JOYCON_BUTTONS_NEON_RED;
  62. controller_header.left_color_body = JOYCON_BODY_NEON_BLUE;
  63. controller_header.left_color_buttons = JOYCON_BUTTONS_NEON_BLUE;
  64. for (int layoutIdx = 0; layoutIdx < HID_NUM_LAYOUTS; layoutIdx++) {
  65. ControllerLayout& layout = mem->controllers[Controller_Handheld].layouts[layoutIdx];
  66. layout.header.num_entries = HID_NUM_ENTRIES;
  67. layout.header.max_entry_index = HID_NUM_ENTRIES - 1;
  68. // HID shared memory stores the state of the past 17 samples in a circlular buffer,
  69. // each with a timestamp in number of samples since boot.
  70. layout.header.timestamp_ticks = CoreTiming::GetTicks();
  71. layout.header.latest_entry = (layout.header.latest_entry + 1) % HID_NUM_ENTRIES;
  72. ControllerInputEntry& entry = layout.entries[layout.header.latest_entry];
  73. entry.connection_state = ConnectionState_Connected | ConnectionState_Wired;
  74. entry.timestamp++;
  75. entry.timestamp_2++; // TODO(shinyquagsire23): Is this always identical to timestamp?
  76. // TODO(shinyquagsire23): Set up some LUTs for each layout mapping in the future?
  77. // For now everything is just the default handheld layout, but split Joy-Con will
  78. // rotate the face buttons and directions for certain layouts.
  79. ControllerPadState& state = entry.buttons;
  80. using namespace Settings::NativeButton;
  81. state.a.Assign(buttons[A - BUTTON_HID_BEGIN]->GetStatus());
  82. state.b.Assign(buttons[B - BUTTON_HID_BEGIN]->GetStatus());
  83. state.x.Assign(buttons[X - BUTTON_HID_BEGIN]->GetStatus());
  84. state.y.Assign(buttons[Y - BUTTON_HID_BEGIN]->GetStatus());
  85. state.lstick.Assign(buttons[LStick - BUTTON_HID_BEGIN]->GetStatus());
  86. state.rstick.Assign(buttons[RStick - BUTTON_HID_BEGIN]->GetStatus());
  87. state.l.Assign(buttons[L - BUTTON_HID_BEGIN]->GetStatus());
  88. state.r.Assign(buttons[R - BUTTON_HID_BEGIN]->GetStatus());
  89. state.zl.Assign(buttons[ZL - BUTTON_HID_BEGIN]->GetStatus());
  90. state.zr.Assign(buttons[ZR - BUTTON_HID_BEGIN]->GetStatus());
  91. state.plus.Assign(buttons[Plus - BUTTON_HID_BEGIN]->GetStatus());
  92. state.minus.Assign(buttons[Minus - BUTTON_HID_BEGIN]->GetStatus());
  93. state.dleft.Assign(buttons[DLeft - BUTTON_HID_BEGIN]->GetStatus());
  94. state.dup.Assign(buttons[DUp - BUTTON_HID_BEGIN]->GetStatus());
  95. state.dright.Assign(buttons[DRight - BUTTON_HID_BEGIN]->GetStatus());
  96. state.ddown.Assign(buttons[DDown - BUTTON_HID_BEGIN]->GetStatus());
  97. state.lstick_left.Assign(buttons[LStick_Left - BUTTON_HID_BEGIN]->GetStatus());
  98. state.lstick_up.Assign(buttons[LStick_Up - BUTTON_HID_BEGIN]->GetStatus());
  99. state.lstick_right.Assign(buttons[LStick_Right - BUTTON_HID_BEGIN]->GetStatus());
  100. state.lstick_down.Assign(buttons[LStick_Down - BUTTON_HID_BEGIN]->GetStatus());
  101. state.rstick_left.Assign(buttons[RStick_Left - BUTTON_HID_BEGIN]->GetStatus());
  102. state.rstick_up.Assign(buttons[RStick_Up - BUTTON_HID_BEGIN]->GetStatus());
  103. state.rstick_right.Assign(buttons[RStick_Right - BUTTON_HID_BEGIN]->GetStatus());
  104. state.rstick_down.Assign(buttons[RStick_Down - BUTTON_HID_BEGIN]->GetStatus());
  105. state.sl.Assign(buttons[SL - BUTTON_HID_BEGIN]->GetStatus());
  106. state.sr.Assign(buttons[SR - BUTTON_HID_BEGIN]->GetStatus());
  107. // TODO(shinyquagsire23): Analog stick vals
  108. // TODO(shinyquagsire23): Update pad info proper, (circular buffers, timestamps,
  109. // layouts)
  110. }
  111. // TODO(shinyquagsire23): Update touch info
  112. // TODO(shinyquagsire23): Signal events
  113. // Reschedule recurrent event
  114. CoreTiming::ScheduleEvent(pad_update_ticks - cycles_late, pad_update_event);
  115. }
  116. // Handle to shared memory region designated to HID service
  117. Kernel::SharedPtr<Kernel::SharedMemory> shared_mem;
  118. // CoreTiming update events
  119. CoreTiming::EventType* pad_update_event;
  120. // Stored input state info
  121. std::atomic<bool> is_device_reload_pending{true};
  122. std::array<std::unique_ptr<Input::ButtonDevice>, Settings::NativeButton::NUM_BUTTONS_HID>
  123. buttons;
  124. };
  125. class IActiveVibrationDeviceList final : public ServiceFramework<IActiveVibrationDeviceList> {
  126. public:
  127. IActiveVibrationDeviceList() : ServiceFramework("IActiveVibrationDeviceList") {
  128. static const FunctionInfo functions[] = {
  129. {0, &IActiveVibrationDeviceList::ActivateVibrationDevice, "ActivateVibrationDevice"},
  130. };
  131. RegisterHandlers(functions);
  132. }
  133. private:
  134. void ActivateVibrationDevice(Kernel::HLERequestContext& ctx) {
  135. IPC::ResponseBuilder rb{ctx, 2};
  136. rb.Push(RESULT_SUCCESS);
  137. LOG_WARNING(Service_HID, "(STUBBED) called");
  138. }
  139. };
  140. class Hid final : public ServiceFramework<Hid> {
  141. public:
  142. Hid() : ServiceFramework("hid") {
  143. static const FunctionInfo functions[] = {
  144. {0, &Hid::CreateAppletResource, "CreateAppletResource"},
  145. {1, &Hid::ActivateDebugPad, "ActivateDebugPad"},
  146. {11, &Hid::ActivateTouchScreen, "ActivateTouchScreen"},
  147. {66, &Hid::StartSixAxisSensor, "StartSixAxisSensor"},
  148. {100, &Hid::SetSupportedNpadStyleSet, "SetSupportedNpadStyleSet"},
  149. {102, &Hid::SetSupportedNpadIdType, "SetSupportedNpadIdType"},
  150. {103, &Hid::ActivateNpad, "ActivateNpad"},
  151. {106, &Hid::AcquireNpadStyleSetUpdateEventHandle,
  152. "AcquireNpadStyleSetUpdateEventHandle"},
  153. {120, &Hid::SetNpadJoyHoldType, "SetNpadJoyHoldType"},
  154. {121, &Hid::GetNpadJoyHoldType, "GetNpadJoyHoldType"},
  155. {124, nullptr, "SetNpadJoyAssignmentModeDual"},
  156. {128, &Hid::SetNpadHandheldActivationMode, "SetNpadHandheldActivationMode"},
  157. {200, &Hid::GetVibrationDeviceInfo, "GetVibrationDeviceInfo"},
  158. {203, &Hid::CreateActiveVibrationDeviceList, "CreateActiveVibrationDeviceList"},
  159. {206, &Hid::SendVibrationValues, "SendVibrationValues"},
  160. };
  161. RegisterHandlers(functions);
  162. event = Kernel::Event::Create(Kernel::ResetType::OneShot, "hid:EventHandle");
  163. }
  164. ~Hid() = default;
  165. private:
  166. std::shared_ptr<IAppletResource> applet_resource;
  167. u32 joy_hold_type{0};
  168. Kernel::SharedPtr<Kernel::Event> event;
  169. void CreateAppletResource(Kernel::HLERequestContext& ctx) {
  170. if (applet_resource == nullptr) {
  171. applet_resource = std::make_shared<IAppletResource>();
  172. }
  173. IPC::ResponseBuilder rb{ctx, 2, 0, 1};
  174. rb.Push(RESULT_SUCCESS);
  175. rb.PushIpcInterface<IAppletResource>(applet_resource);
  176. LOG_DEBUG(Service_HID, "called");
  177. }
  178. void ActivateDebugPad(Kernel::HLERequestContext& ctx) {
  179. IPC::ResponseBuilder rb{ctx, 2};
  180. rb.Push(RESULT_SUCCESS);
  181. LOG_WARNING(Service_HID, "(STUBBED) called");
  182. }
  183. void ActivateTouchScreen(Kernel::HLERequestContext& ctx) {
  184. IPC::ResponseBuilder rb{ctx, 2};
  185. rb.Push(RESULT_SUCCESS);
  186. LOG_WARNING(Service_HID, "(STUBBED) called");
  187. }
  188. void StartSixAxisSensor(Kernel::HLERequestContext& ctx) {
  189. IPC::ResponseBuilder rb{ctx, 2};
  190. rb.Push(RESULT_SUCCESS);
  191. LOG_WARNING(Service_HID, "(STUBBED) called");
  192. }
  193. void SetSupportedNpadStyleSet(Kernel::HLERequestContext& ctx) {
  194. IPC::ResponseBuilder rb{ctx, 2};
  195. rb.Push(RESULT_SUCCESS);
  196. LOG_WARNING(Service_HID, "(STUBBED) called");
  197. }
  198. void SetSupportedNpadIdType(Kernel::HLERequestContext& ctx) {
  199. IPC::ResponseBuilder rb{ctx, 2};
  200. rb.Push(RESULT_SUCCESS);
  201. LOG_WARNING(Service_HID, "(STUBBED) called");
  202. }
  203. void ActivateNpad(Kernel::HLERequestContext& ctx) {
  204. IPC::ResponseBuilder rb{ctx, 2};
  205. rb.Push(RESULT_SUCCESS);
  206. LOG_WARNING(Service_HID, "(STUBBED) called");
  207. }
  208. void AcquireNpadStyleSetUpdateEventHandle(Kernel::HLERequestContext& ctx) {
  209. IPC::ResponseBuilder rb{ctx, 2, 1};
  210. rb.Push(RESULT_SUCCESS);
  211. rb.PushCopyObjects(event);
  212. LOG_WARNING(Service_HID, "(STUBBED) called");
  213. }
  214. void SetNpadJoyHoldType(Kernel::HLERequestContext& ctx) {
  215. IPC::ResponseBuilder rb{ctx, 2};
  216. rb.Push(RESULT_SUCCESS);
  217. LOG_WARNING(Service_HID, "(STUBBED) called");
  218. }
  219. void GetNpadJoyHoldType(Kernel::HLERequestContext& ctx) {
  220. IPC::ResponseBuilder rb{ctx, 3};
  221. rb.Push(RESULT_SUCCESS);
  222. rb.Push(joy_hold_type);
  223. LOG_WARNING(Service_HID, "(STUBBED) called");
  224. }
  225. void SetNpadHandheldActivationMode(Kernel::HLERequestContext& ctx) {
  226. IPC::ResponseBuilder rb{ctx, 2};
  227. rb.Push(RESULT_SUCCESS);
  228. LOG_WARNING(Service_HID, "(STUBBED) called");
  229. }
  230. void GetVibrationDeviceInfo(Kernel::HLERequestContext& ctx) {
  231. IPC::ResponseBuilder rb{ctx, 4};
  232. rb.Push(RESULT_SUCCESS);
  233. rb.Push<u64>(0);
  234. LOG_WARNING(Service_HID, "(STUBBED) called");
  235. }
  236. void CreateActiveVibrationDeviceList(Kernel::HLERequestContext& ctx) {
  237. IPC::ResponseBuilder rb{ctx, 2, 0, 1};
  238. rb.Push(RESULT_SUCCESS);
  239. rb.PushIpcInterface<IActiveVibrationDeviceList>();
  240. LOG_DEBUG(Service_HID, "called");
  241. }
  242. void SendVibrationValues(Kernel::HLERequestContext& ctx) {
  243. IPC::ResponseBuilder rb{ctx, 2};
  244. rb.Push(RESULT_SUCCESS);
  245. LOG_WARNING(Service_HID, "(STUBBED) called");
  246. }
  247. };
  248. void ReloadInputDevices() {}
  249. void InstallInterfaces(SM::ServiceManager& service_manager) {
  250. std::make_shared<Hid>()->InstallAsService(service_manager);
  251. }
  252. } // namespace HID
  253. } // namespace Service