ir_rst.cpp 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220
  1. // Copyright 2015 Citra Emulator Project
  2. // Licensed under GPLv2 or any later version
  3. // Refer to the license.txt file included.
  4. #include <atomic>
  5. #include "common/bit_field.h"
  6. #include "core/core_timing.h"
  7. #include "core/frontend/input.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/ir/ir.h"
  12. #include "core/hle/service/ir/ir_rst.h"
  13. #include "core/settings.h"
  14. namespace Service {
  15. namespace IR {
  16. union PadState {
  17. u32_le hex;
  18. BitField<14, 1, u32_le> zl;
  19. BitField<15, 1, u32_le> zr;
  20. BitField<24, 1, u32_le> c_stick_right;
  21. BitField<25, 1, u32_le> c_stick_left;
  22. BitField<26, 1, u32_le> c_stick_up;
  23. BitField<27, 1, u32_le> c_stick_down;
  24. };
  25. struct PadDataEntry {
  26. PadState current_state;
  27. PadState delta_additions;
  28. PadState delta_removals;
  29. s16_le c_stick_x;
  30. s16_le c_stick_y;
  31. };
  32. struct SharedMem {
  33. u64_le index_reset_ticks; ///< CPU tick count for when HID module updated entry index 0
  34. u64_le index_reset_ticks_previous; ///< Previous `index_reset_ticks`
  35. u32_le index;
  36. INSERT_PADDING_WORDS(1);
  37. std::array<PadDataEntry, 8> entries; ///< Last 8 pad entries
  38. };
  39. static_assert(sizeof(SharedMem) == 0x98, "SharedMem has wrong size!");
  40. static Kernel::SharedPtr<Kernel::Event> update_event;
  41. static Kernel::SharedPtr<Kernel::SharedMemory> shared_memory;
  42. static u32 next_pad_index;
  43. static int update_callback_id;
  44. static std::unique_ptr<Input::ButtonDevice> zl_button;
  45. static std::unique_ptr<Input::ButtonDevice> zr_button;
  46. static std::unique_ptr<Input::AnalogDevice> c_stick;
  47. static std::atomic<bool> is_device_reload_pending;
  48. static bool raw_c_stick;
  49. static int update_period;
  50. static void LoadInputDevices() {
  51. zl_button = Input::CreateDevice<Input::ButtonDevice>(
  52. Settings::values.buttons[Settings::NativeButton::ZL]);
  53. zr_button = Input::CreateDevice<Input::ButtonDevice>(
  54. Settings::values.buttons[Settings::NativeButton::ZR]);
  55. c_stick = Input::CreateDevice<Input::AnalogDevice>(
  56. Settings::values.analogs[Settings::NativeAnalog::CStick]);
  57. }
  58. static void UnloadInputDevices() {
  59. zl_button = nullptr;
  60. zr_button = nullptr;
  61. c_stick = nullptr;
  62. }
  63. static void UpdateCallback(u64 userdata, int cycles_late) {
  64. SharedMem* mem = reinterpret_cast<SharedMem*>(shared_memory->GetPointer());
  65. if (is_device_reload_pending.exchange(false))
  66. LoadInputDevices();
  67. PadState state;
  68. state.zl.Assign(zl_button->GetStatus());
  69. state.zr.Assign(zr_button->GetStatus());
  70. // Get current c-stick position and update c-stick direction
  71. float c_stick_x_f, c_stick_y_f;
  72. std::tie(c_stick_x_f, c_stick_y_f) = c_stick->GetStatus();
  73. constexpr int MAX_CSTICK_RADIUS = 0x9C; // Max value for a c-stick radius
  74. const s16 c_stick_x = static_cast<s16>(c_stick_x_f * MAX_CSTICK_RADIUS);
  75. const s16 c_stick_y = static_cast<s16>(c_stick_y_f * MAX_CSTICK_RADIUS);
  76. if (!raw_c_stick) {
  77. const HID::DirectionState direction = HID::GetStickDirectionState(c_stick_x, c_stick_y);
  78. state.c_stick_up.Assign(direction.up);
  79. state.c_stick_down.Assign(direction.down);
  80. state.c_stick_left.Assign(direction.left);
  81. state.c_stick_right.Assign(direction.right);
  82. }
  83. // TODO (wwylele): implement raw C-stick data for raw_c_stick = true
  84. const u32 last_entry_index = mem->index;
  85. mem->index = next_pad_index;
  86. next_pad_index = (next_pad_index + 1) % mem->entries.size();
  87. // Get the previous Pad state
  88. PadState old_state{mem->entries[last_entry_index].current_state};
  89. // Compute bitmask with 1s for bits different from the old state
  90. PadState changed = {state.hex ^ old_state.hex};
  91. // Get the current Pad entry
  92. PadDataEntry& pad_entry = mem->entries[mem->index];
  93. // Update entry properties
  94. pad_entry.current_state.hex = state.hex;
  95. pad_entry.delta_additions.hex = changed.hex & state.hex;
  96. pad_entry.delta_removals.hex = changed.hex & old_state.hex;
  97. pad_entry.c_stick_x = c_stick_x;
  98. pad_entry.c_stick_y = c_stick_y;
  99. // If we just updated index 0, provide a new timestamp
  100. if (mem->index == 0) {
  101. mem->index_reset_ticks_previous = mem->index_reset_ticks;
  102. mem->index_reset_ticks = CoreTiming::GetTicks();
  103. }
  104. update_event->Signal();
  105. // Reschedule recurrent event
  106. CoreTiming::ScheduleEvent(msToCycles(update_period) - cycles_late, update_callback_id);
  107. }
  108. /**
  109. * IR::GetHandles service function
  110. * Outputs:
  111. * 1 : Result of function, 0 on success, otherwise error code
  112. * 2 : Translate header, used by the ARM11-kernel
  113. * 3 : Shared memory handle
  114. * 4 : Event handle
  115. */
  116. static void GetHandles(Interface* self) {
  117. IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x01, 0, 0);
  118. IPC::RequestBuilder rb = rp.MakeBuilder(1, 3);
  119. rb.Push(RESULT_SUCCESS);
  120. rb.PushMoveHandles(Kernel::g_handle_table.Create(Service::IR::shared_memory).MoveFrom(),
  121. Kernel::g_handle_table.Create(Service::IR::update_event).MoveFrom());
  122. }
  123. /**
  124. * IR::Initialize service function
  125. * Inputs:
  126. * 1 : pad state update period in ms
  127. * 2 : bool output raw c-stick data
  128. */
  129. static void Initialize(Interface* self) {
  130. IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x02, 2, 0);
  131. update_period = static_cast<int>(rp.Pop<u32>());
  132. raw_c_stick = rp.Pop<bool>();
  133. if (raw_c_stick)
  134. LOG_ERROR(Service_IR, "raw C-stick data is not implemented!");
  135. next_pad_index = 0;
  136. is_device_reload_pending.store(true);
  137. CoreTiming::ScheduleEvent(msToCycles(update_period), update_callback_id);
  138. IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
  139. rb.Push(RESULT_SUCCESS);
  140. LOG_DEBUG(Service_IR, "called. update_period=%d, raw_c_stick=%d", update_period, raw_c_stick);
  141. }
  142. static void Shutdown(Interface* self) {
  143. IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x03, 1, 0);
  144. CoreTiming::UnscheduleEvent(update_callback_id, 0);
  145. UnloadInputDevices();
  146. IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
  147. rb.Push(RESULT_SUCCESS);
  148. LOG_DEBUG(Service_IR, "called");
  149. }
  150. const Interface::FunctionInfo FunctionTable[] = {
  151. {0x00010000, GetHandles, "GetHandles"},
  152. {0x00020080, Initialize, "Initialize"},
  153. {0x00030000, Shutdown, "Shutdown"},
  154. {0x00090000, nullptr, "WriteToTwoFields"},
  155. };
  156. IR_RST_Interface::IR_RST_Interface() {
  157. Register(FunctionTable);
  158. }
  159. void InitRST() {
  160. using namespace Kernel;
  161. // Note: these two kernel objects are even available before Initialize service function is
  162. // called.
  163. shared_memory =
  164. SharedMemory::Create(nullptr, 0x1000, MemoryPermission::ReadWrite, MemoryPermission::Read,
  165. 0, MemoryRegion::BASE, "IRRST:SharedMemory");
  166. update_event = Event::Create(ResetType::OneShot, "IRRST:UpdateEvent");
  167. update_callback_id = CoreTiming::RegisterEvent("IRRST:UpdateCallBack", UpdateCallback);
  168. }
  169. void ShutdownRST() {
  170. shared_memory = nullptr;
  171. update_event = nullptr;
  172. UnloadInputDevices();
  173. }
  174. void ReloadInputDevicesRST() {
  175. is_device_reload_pending.store(true);
  176. }
  177. } // namespace IR
  178. } // namespace Service