hid.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354
  1. // Copyright 2015 Citra Emulator Project
  2. // Licensed under GPLv2 or any later version
  3. // Refer to the license.txt file included.
  4. #include <cmath>
  5. #include "common/logging/log.h"
  6. #include "core/core_timing.h"
  7. #include "core/frontend/emu_window.h"
  8. #include "core/hle/kernel/event.h"
  9. #include "core/hle/kernel/shared_memory.h"
  10. #include "core/hle/service/hid/hid.h"
  11. #include "core/hle/service/hid/hid_spvr.h"
  12. #include "core/hle/service/hid/hid_user.h"
  13. #include "core/hle/service/service.h"
  14. #include "video_core/video_core.h"
  15. namespace Service {
  16. namespace HID {
  17. // Handle to shared memory region designated to HID_User service
  18. static Kernel::SharedPtr<Kernel::SharedMemory> shared_mem;
  19. // Event handles
  20. static Kernel::SharedPtr<Kernel::Event> event_pad_or_touch_1;
  21. static Kernel::SharedPtr<Kernel::Event> event_pad_or_touch_2;
  22. static Kernel::SharedPtr<Kernel::Event> event_accelerometer;
  23. static Kernel::SharedPtr<Kernel::Event> event_gyroscope;
  24. static Kernel::SharedPtr<Kernel::Event> event_debug_pad;
  25. static u32 next_pad_index;
  26. static u32 next_touch_index;
  27. static u32 next_accelerometer_index;
  28. static u32 next_gyroscope_index;
  29. static int enable_accelerometer_count = 0; // positive means enabled
  30. static int enable_gyroscope_count = 0; // positive means enabled
  31. static int pad_update_event;
  32. static int accelerometer_update_event;
  33. static int gyroscope_update_event;
  34. // Updating period for each HID device. These empirical values are measured from a 11.2 3DS.
  35. constexpr u64 pad_update_ticks = BASE_CLOCK_RATE_ARM11 / 234;
  36. constexpr u64 accelerometer_update_ticks = BASE_CLOCK_RATE_ARM11 / 104;
  37. constexpr u64 gyroscope_update_ticks = BASE_CLOCK_RATE_ARM11 / 101;
  38. static PadState GetCirclePadDirectionState(s16 circle_pad_x, s16 circle_pad_y) {
  39. // 30 degree and 60 degree are angular thresholds for directions
  40. constexpr float TAN30 = 0.577350269f;
  41. constexpr float TAN60 = 1 / TAN30;
  42. // a circle pad radius greater than 40 will trigger circle pad direction
  43. constexpr int CIRCLE_PAD_THRESHOLD_SQUARE = 40 * 40;
  44. PadState state;
  45. state.hex = 0;
  46. if (circle_pad_x * circle_pad_x + circle_pad_y * circle_pad_y > CIRCLE_PAD_THRESHOLD_SQUARE) {
  47. float t = std::abs(static_cast<float>(circle_pad_y) / circle_pad_x);
  48. if (circle_pad_x != 0 && t < TAN60) {
  49. if (circle_pad_x > 0)
  50. state.circle_right.Assign(1);
  51. else
  52. state.circle_left.Assign(1);
  53. }
  54. if (circle_pad_x == 0 || t > TAN30) {
  55. if (circle_pad_y > 0)
  56. state.circle_up.Assign(1);
  57. else
  58. state.circle_down.Assign(1);
  59. }
  60. }
  61. return state;
  62. }
  63. static void UpdatePadCallback(u64 userdata, int cycles_late) {
  64. SharedMem* mem = reinterpret_cast<SharedMem*>(shared_mem->GetPointer());
  65. PadState state = VideoCore::g_emu_window->GetPadState();
  66. // Get current circle pad position and update circle pad direction
  67. s16 circle_pad_x, circle_pad_y;
  68. std::tie(circle_pad_x, circle_pad_y) = VideoCore::g_emu_window->GetCirclePadState();
  69. state.hex |= GetCirclePadDirectionState(circle_pad_x, circle_pad_y).hex;
  70. mem->pad.current_state.hex = state.hex;
  71. mem->pad.index = next_pad_index;
  72. next_pad_index = (next_pad_index + 1) % mem->pad.entries.size();
  73. // Get the previous Pad state
  74. u32 last_entry_index = (mem->pad.index - 1) % mem->pad.entries.size();
  75. PadState old_state = mem->pad.entries[last_entry_index].current_state;
  76. // Compute bitmask with 1s for bits different from the old state
  77. PadState changed = {{(state.hex ^ old_state.hex)}};
  78. // Get the current Pad entry
  79. PadDataEntry& pad_entry = mem->pad.entries[mem->pad.index];
  80. // Update entry properties
  81. pad_entry.current_state.hex = state.hex;
  82. pad_entry.delta_additions.hex = changed.hex & state.hex;
  83. pad_entry.delta_removals.hex = changed.hex & old_state.hex;
  84. pad_entry.circle_pad_x = circle_pad_x;
  85. pad_entry.circle_pad_y = circle_pad_y;
  86. // If we just updated index 0, provide a new timestamp
  87. if (mem->pad.index == 0) {
  88. mem->pad.index_reset_ticks_previous = mem->pad.index_reset_ticks;
  89. mem->pad.index_reset_ticks = (s64)CoreTiming::GetTicks();
  90. }
  91. mem->touch.index = next_touch_index;
  92. next_touch_index = (next_touch_index + 1) % mem->touch.entries.size();
  93. // Get the current touch entry
  94. TouchDataEntry& touch_entry = mem->touch.entries[mem->touch.index];
  95. bool pressed = false;
  96. std::tie(touch_entry.x, touch_entry.y, pressed) = VideoCore::g_emu_window->GetTouchState();
  97. touch_entry.valid.Assign(pressed ? 1 : 0);
  98. // TODO(bunnei): We're not doing anything with offset 0xA8 + 0x18 of HID SharedMemory, which
  99. // supposedly is "Touch-screen entry, which contains the raw coordinate data prior to being
  100. // converted to pixel coordinates." (http://3dbrew.org/wiki/HID_Shared_Memory#Offset_0xA8).
  101. // If we just updated index 0, provide a new timestamp
  102. if (mem->touch.index == 0) {
  103. mem->touch.index_reset_ticks_previous = mem->touch.index_reset_ticks;
  104. mem->touch.index_reset_ticks = (s64)CoreTiming::GetTicks();
  105. }
  106. // Signal both handles when there's an update to Pad or touch
  107. event_pad_or_touch_1->Signal();
  108. event_pad_or_touch_2->Signal();
  109. // Reschedule recurrent event
  110. CoreTiming::ScheduleEvent(pad_update_ticks - cycles_late, pad_update_event);
  111. }
  112. static void UpdateAccelerometerCallback(u64 userdata, int cycles_late) {
  113. SharedMem* mem = reinterpret_cast<SharedMem*>(shared_mem->GetPointer());
  114. mem->accelerometer.index = next_accelerometer_index;
  115. next_accelerometer_index = (next_accelerometer_index + 1) % mem->accelerometer.entries.size();
  116. AccelerometerDataEntry& accelerometer_entry =
  117. mem->accelerometer.entries[mem->accelerometer.index];
  118. std::tie(accelerometer_entry.x, accelerometer_entry.y, accelerometer_entry.z) =
  119. VideoCore::g_emu_window->GetAccelerometerState();
  120. // Make up "raw" entry
  121. // TODO(wwylele):
  122. // From hardware testing, the raw_entry values are approximately, but not exactly, as twice as
  123. // corresponding entries (or with a minus sign). It may caused by system calibration to the
  124. // accelerometer. Figure out how it works, or, if no game reads raw_entry, the following three
  125. // lines can be removed and leave raw_entry unimplemented.
  126. mem->accelerometer.raw_entry.x = -2 * accelerometer_entry.x;
  127. mem->accelerometer.raw_entry.z = 2 * accelerometer_entry.y;
  128. mem->accelerometer.raw_entry.y = -2 * accelerometer_entry.z;
  129. // If we just updated index 0, provide a new timestamp
  130. if (mem->accelerometer.index == 0) {
  131. mem->accelerometer.index_reset_ticks_previous = mem->accelerometer.index_reset_ticks;
  132. mem->accelerometer.index_reset_ticks = (s64)CoreTiming::GetTicks();
  133. }
  134. event_accelerometer->Signal();
  135. // Reschedule recurrent event
  136. CoreTiming::ScheduleEvent(accelerometer_update_ticks - cycles_late, accelerometer_update_event);
  137. }
  138. static void UpdateGyroscopeCallback(u64 userdata, int cycles_late) {
  139. SharedMem* mem = reinterpret_cast<SharedMem*>(shared_mem->GetPointer());
  140. mem->gyroscope.index = next_gyroscope_index;
  141. next_gyroscope_index = (next_gyroscope_index + 1) % mem->gyroscope.entries.size();
  142. GyroscopeDataEntry& gyroscope_entry = mem->gyroscope.entries[mem->gyroscope.index];
  143. std::tie(gyroscope_entry.x, gyroscope_entry.y, gyroscope_entry.z) =
  144. VideoCore::g_emu_window->GetGyroscopeState();
  145. // Make up "raw" entry
  146. mem->gyroscope.raw_entry.x = gyroscope_entry.x;
  147. mem->gyroscope.raw_entry.z = -gyroscope_entry.y;
  148. mem->gyroscope.raw_entry.y = gyroscope_entry.z;
  149. // If we just updated index 0, provide a new timestamp
  150. if (mem->gyroscope.index == 0) {
  151. mem->gyroscope.index_reset_ticks_previous = mem->gyroscope.index_reset_ticks;
  152. mem->gyroscope.index_reset_ticks = (s64)CoreTiming::GetTicks();
  153. }
  154. event_gyroscope->Signal();
  155. // Reschedule recurrent event
  156. CoreTiming::ScheduleEvent(gyroscope_update_ticks - cycles_late, gyroscope_update_event);
  157. }
  158. void GetIPCHandles(Service::Interface* self) {
  159. u32* cmd_buff = Kernel::GetCommandBuffer();
  160. cmd_buff[1] = 0; // No error
  161. cmd_buff[2] = 0x14000000; // IPC Command Structure translate-header
  162. // TODO(yuriks): Return error from SendSyncRequest is this fails (part of IPC marshalling)
  163. cmd_buff[3] = Kernel::g_handle_table.Create(Service::HID::shared_mem).MoveFrom();
  164. cmd_buff[4] = Kernel::g_handle_table.Create(Service::HID::event_pad_or_touch_1).MoveFrom();
  165. cmd_buff[5] = Kernel::g_handle_table.Create(Service::HID::event_pad_or_touch_2).MoveFrom();
  166. cmd_buff[6] = Kernel::g_handle_table.Create(Service::HID::event_accelerometer).MoveFrom();
  167. cmd_buff[7] = Kernel::g_handle_table.Create(Service::HID::event_gyroscope).MoveFrom();
  168. cmd_buff[8] = Kernel::g_handle_table.Create(Service::HID::event_debug_pad).MoveFrom();
  169. }
  170. void EnableAccelerometer(Service::Interface* self) {
  171. u32* cmd_buff = Kernel::GetCommandBuffer();
  172. ++enable_accelerometer_count;
  173. // Schedules the accelerometer update event if the accelerometer was just enabled
  174. if (enable_accelerometer_count == 1) {
  175. CoreTiming::ScheduleEvent(accelerometer_update_ticks, accelerometer_update_event);
  176. }
  177. cmd_buff[1] = RESULT_SUCCESS.raw;
  178. LOG_DEBUG(Service_HID, "called");
  179. }
  180. void DisableAccelerometer(Service::Interface* self) {
  181. u32* cmd_buff = Kernel::GetCommandBuffer();
  182. --enable_accelerometer_count;
  183. // Unschedules the accelerometer update event if the accelerometer was just disabled
  184. if (enable_accelerometer_count == 0) {
  185. CoreTiming::UnscheduleEvent(accelerometer_update_event, 0);
  186. }
  187. cmd_buff[1] = RESULT_SUCCESS.raw;
  188. LOG_DEBUG(Service_HID, "called");
  189. }
  190. void EnableGyroscopeLow(Service::Interface* self) {
  191. u32* cmd_buff = Kernel::GetCommandBuffer();
  192. ++enable_gyroscope_count;
  193. // Schedules the gyroscope update event if the gyroscope was just enabled
  194. if (enable_gyroscope_count == 1) {
  195. CoreTiming::ScheduleEvent(gyroscope_update_ticks, gyroscope_update_event);
  196. }
  197. cmd_buff[1] = RESULT_SUCCESS.raw;
  198. LOG_DEBUG(Service_HID, "called");
  199. }
  200. void DisableGyroscopeLow(Service::Interface* self) {
  201. u32* cmd_buff = Kernel::GetCommandBuffer();
  202. --enable_gyroscope_count;
  203. // Unschedules the gyroscope update event if the gyroscope was just disabled
  204. if (enable_gyroscope_count == 0) {
  205. CoreTiming::UnscheduleEvent(gyroscope_update_event, 0);
  206. }
  207. cmd_buff[1] = RESULT_SUCCESS.raw;
  208. LOG_DEBUG(Service_HID, "called");
  209. }
  210. void GetGyroscopeLowRawToDpsCoefficient(Service::Interface* self) {
  211. u32* cmd_buff = Kernel::GetCommandBuffer();
  212. cmd_buff[1] = RESULT_SUCCESS.raw;
  213. f32 coef = VideoCore::g_emu_window->GetGyroscopeRawToDpsCoefficient();
  214. memcpy(&cmd_buff[2], &coef, 4);
  215. }
  216. void GetGyroscopeLowCalibrateParam(Service::Interface* self) {
  217. u32* cmd_buff = Kernel::GetCommandBuffer();
  218. cmd_buff[1] = RESULT_SUCCESS.raw;
  219. const s16 param_unit = 6700; // an approximate value taken from hw
  220. GyroscopeCalibrateParam param = {
  221. {0, param_unit, -param_unit}, {0, param_unit, -param_unit}, {0, param_unit, -param_unit},
  222. };
  223. memcpy(&cmd_buff[2], &param, sizeof(param));
  224. LOG_WARNING(Service_HID, "(STUBBED) called");
  225. }
  226. void GetSoundVolume(Service::Interface* self) {
  227. u32* cmd_buff = Kernel::GetCommandBuffer();
  228. const u8 volume = 0x3F; // TODO(purpasmart): Find out if this is the max value for the volume
  229. cmd_buff[1] = RESULT_SUCCESS.raw;
  230. cmd_buff[2] = volume;
  231. LOG_WARNING(Service_HID, "(STUBBED) called");
  232. }
  233. void Init() {
  234. using namespace Kernel;
  235. AddService(new HID_U_Interface);
  236. AddService(new HID_SPVR_Interface);
  237. using Kernel::MemoryPermission;
  238. shared_mem =
  239. SharedMemory::Create(nullptr, 0x1000, MemoryPermission::ReadWrite, MemoryPermission::Read,
  240. 0, Kernel::MemoryRegion::BASE, "HID:SharedMemory");
  241. next_pad_index = 0;
  242. next_touch_index = 0;
  243. next_accelerometer_index = 0;
  244. next_gyroscope_index = 0;
  245. // Create event handles
  246. event_pad_or_touch_1 = Event::Create(ResetType::OneShot, "HID:EventPadOrTouch1");
  247. event_pad_or_touch_2 = Event::Create(ResetType::OneShot, "HID:EventPadOrTouch2");
  248. event_accelerometer = Event::Create(ResetType::OneShot, "HID:EventAccelerometer");
  249. event_gyroscope = Event::Create(ResetType::OneShot, "HID:EventGyroscope");
  250. event_debug_pad = Event::Create(ResetType::OneShot, "HID:EventDebugPad");
  251. // Register update callbacks
  252. pad_update_event = CoreTiming::RegisterEvent("HID::UpdatePadCallback", UpdatePadCallback);
  253. accelerometer_update_event =
  254. CoreTiming::RegisterEvent("HID::UpdateAccelerometerCallback", UpdateAccelerometerCallback);
  255. gyroscope_update_event =
  256. CoreTiming::RegisterEvent("HID::UpdateGyroscopeCallback", UpdateGyroscopeCallback);
  257. CoreTiming::ScheduleEvent(pad_update_ticks, pad_update_event);
  258. }
  259. void Shutdown() {
  260. shared_mem = nullptr;
  261. event_pad_or_touch_1 = nullptr;
  262. event_pad_or_touch_2 = nullptr;
  263. event_accelerometer = nullptr;
  264. event_gyroscope = nullptr;
  265. event_debug_pad = nullptr;
  266. }
  267. } // namespace HID
  268. } // namespace Service