summaryrefslogtreecommitdiff
path: root/src/core/hle/service/hid
diff options
context:
space:
mode:
authorGravatar bunnei2017-10-12 21:21:49 -0400
committerGravatar bunnei2017-10-12 21:21:49 -0400
commit72b03025ac4ef0d8633c2f3e55b513cd149c59e5 (patch)
treef1fbeb915a0b3df8e4e988a6a562a763e18ea666 /src/core/hle/service/hid
parenthle: Remove a large amount of 3ds-specific service code. (diff)
downloadyuzu-72b03025ac4ef0d8633c2f3e55b513cd149c59e5.tar.gz
yuzu-72b03025ac4ef0d8633c2f3e55b513cd149c59e5.tar.xz
yuzu-72b03025ac4ef0d8633c2f3e55b513cd149c59e5.zip
Remove lots more 3DS-specific code.
Diffstat (limited to 'src/core/hle/service/hid')
-rw-r--r--src/core/hle/service/hid/hid.cpp425
-rw-r--r--src/core/hle/service/hid/hid.h266
-rw-r--r--src/core/hle/service/hid/hid_spvr.cpp29
-rw-r--r--src/core/hle/service/hid/hid_spvr.h22
-rw-r--r--src/core/hle/service/hid/hid_user.cpp29
-rw-r--r--src/core/hle/service/hid/hid_user.h28
6 files changed, 6 insertions, 793 deletions
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp
index 379fbd71c..f838713a3 100644
--- a/src/core/hle/service/hid/hid.cpp
+++ b/src/core/hle/service/hid/hid.cpp
@@ -2,437 +2,18 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <algorithm>
6#include <atomic>
7#include <cmath>
8#include <memory>
9#include "common/logging/log.h" 5#include "common/logging/log.h"
10#include "core/3ds.h"
11#include "core/core.h"
12#include "core/core_timing.h"
13#include "core/frontend/input.h"
14#include "core/hle/ipc.h"
15#include "core/hle/kernel/event.h"
16#include "core/hle/kernel/handle_table.h"
17#include "core/hle/kernel/shared_memory.h"
18#include "core/hle/service/hid/hid.h" 6#include "core/hle/service/hid/hid.h"
19#include "core/hle/service/hid/hid_spvr.h"
20#include "core/hle/service/hid/hid_user.h"
21#include "core/hle/service/service.h" 7#include "core/hle/service/service.h"
22 8
23namespace Service { 9namespace Service {
24namespace HID { 10namespace HID {
25 11
26// Handle to shared memory region designated to HID_User service 12void Init() {}
27static Kernel::SharedPtr<Kernel::SharedMemory> shared_mem;
28 13
29// Event handles 14void Shutdown() {}
30static Kernel::SharedPtr<Kernel::Event> event_pad_or_touch_1;
31static Kernel::SharedPtr<Kernel::Event> event_pad_or_touch_2;
32static Kernel::SharedPtr<Kernel::Event> event_accelerometer;
33static Kernel::SharedPtr<Kernel::Event> event_gyroscope;
34static Kernel::SharedPtr<Kernel::Event> event_debug_pad;
35 15
36static u32 next_pad_index; 16void ReloadInputDevices() {}
37static u32 next_touch_index;
38static u32 next_accelerometer_index;
39static u32 next_gyroscope_index;
40
41static int enable_accelerometer_count; // positive means enabled
42static int enable_gyroscope_count; // positive means enabled
43
44static int pad_update_event;
45static int accelerometer_update_event;
46static int gyroscope_update_event;
47
48// Updating period for each HID device. These empirical values are measured from a 11.2 3DS.
49constexpr u64 pad_update_ticks = BASE_CLOCK_RATE_ARM11 / 234;
50constexpr u64 accelerometer_update_ticks = BASE_CLOCK_RATE_ARM11 / 104;
51constexpr u64 gyroscope_update_ticks = BASE_CLOCK_RATE_ARM11 / 101;
52
53constexpr float accelerometer_coef = 512.0f; // measured from hw test result
54constexpr float gyroscope_coef = 14.375f; // got from hwtest GetGyroscopeLowRawToDpsCoefficient call
55
56static std::atomic<bool> is_device_reload_pending;
57static std::array<std::unique_ptr<Input::ButtonDevice>, Settings::NativeButton::NUM_BUTTONS_HID>
58 buttons;
59static std::unique_ptr<Input::AnalogDevice> circle_pad;
60static std::unique_ptr<Input::MotionDevice> motion_device;
61static std::unique_ptr<Input::TouchDevice> touch_device;
62
63DirectionState GetStickDirectionState(s16 circle_pad_x, s16 circle_pad_y) {
64 // 30 degree and 60 degree are angular thresholds for directions
65 constexpr float TAN30 = 0.577350269f;
66 constexpr float TAN60 = 1 / TAN30;
67 // a circle pad radius greater than 40 will trigger circle pad direction
68 constexpr int CIRCLE_PAD_THRESHOLD_SQUARE = 40 * 40;
69 DirectionState state{false, false, false, false};
70
71 if (circle_pad_x * circle_pad_x + circle_pad_y * circle_pad_y > CIRCLE_PAD_THRESHOLD_SQUARE) {
72 float t = std::abs(static_cast<float>(circle_pad_y) / circle_pad_x);
73
74 if (circle_pad_x != 0 && t < TAN60) {
75 if (circle_pad_x > 0)
76 state.right = true;
77 else
78 state.left = true;
79 }
80
81 if (circle_pad_x == 0 || t > TAN30) {
82 if (circle_pad_y > 0)
83 state.up = true;
84 else
85 state.down = true;
86 }
87 }
88
89 return state;
90}
91
92static void LoadInputDevices() {
93 std::transform(Settings::values.buttons.begin() + Settings::NativeButton::BUTTON_HID_BEGIN,
94 Settings::values.buttons.begin() + Settings::NativeButton::BUTTON_HID_END,
95 buttons.begin(), Input::CreateDevice<Input::ButtonDevice>);
96 circle_pad = Input::CreateDevice<Input::AnalogDevice>(
97 Settings::values.analogs[Settings::NativeAnalog::CirclePad]);
98 motion_device = Input::CreateDevice<Input::MotionDevice>(Settings::values.motion_device);
99 touch_device = Input::CreateDevice<Input::TouchDevice>(Settings::values.touch_device);
100}
101
102static void UnloadInputDevices() {
103 for (auto& button : buttons) {
104 button.reset();
105 }
106 circle_pad.reset();
107 motion_device.reset();
108 touch_device.reset();
109}
110
111static void UpdatePadCallback(u64 userdata, int cycles_late) {
112 SharedMem* mem = reinterpret_cast<SharedMem*>(shared_mem->GetPointer());
113
114 if (is_device_reload_pending.exchange(false))
115 LoadInputDevices();
116
117 PadState state;
118 using namespace Settings::NativeButton;
119 state.a.Assign(buttons[A - BUTTON_HID_BEGIN]->GetStatus());
120 state.b.Assign(buttons[B - BUTTON_HID_BEGIN]->GetStatus());
121 state.x.Assign(buttons[X - BUTTON_HID_BEGIN]->GetStatus());
122 state.y.Assign(buttons[Y - BUTTON_HID_BEGIN]->GetStatus());
123 state.right.Assign(buttons[Right - BUTTON_HID_BEGIN]->GetStatus());
124 state.left.Assign(buttons[Left - BUTTON_HID_BEGIN]->GetStatus());
125 state.up.Assign(buttons[Up - BUTTON_HID_BEGIN]->GetStatus());
126 state.down.Assign(buttons[Down - BUTTON_HID_BEGIN]->GetStatus());
127 state.l.Assign(buttons[L - BUTTON_HID_BEGIN]->GetStatus());
128 state.r.Assign(buttons[R - BUTTON_HID_BEGIN]->GetStatus());
129 state.start.Assign(buttons[Start - BUTTON_HID_BEGIN]->GetStatus());
130 state.select.Assign(buttons[Select - BUTTON_HID_BEGIN]->GetStatus());
131
132 // Get current circle pad position and update circle pad direction
133 float circle_pad_x_f, circle_pad_y_f;
134 std::tie(circle_pad_x_f, circle_pad_y_f) = circle_pad->GetStatus();
135 constexpr int MAX_CIRCLEPAD_POS = 0x9C; // Max value for a circle pad position
136 s16 circle_pad_x = static_cast<s16>(circle_pad_x_f * MAX_CIRCLEPAD_POS);
137 s16 circle_pad_y = static_cast<s16>(circle_pad_y_f * MAX_CIRCLEPAD_POS);
138 const DirectionState direction = GetStickDirectionState(circle_pad_x, circle_pad_y);
139 state.circle_up.Assign(direction.up);
140 state.circle_down.Assign(direction.down);
141 state.circle_left.Assign(direction.left);
142 state.circle_right.Assign(direction.right);
143
144 mem->pad.current_state.hex = state.hex;
145 mem->pad.index = next_pad_index;
146 next_pad_index = (next_pad_index + 1) % mem->pad.entries.size();
147
148 // Get the previous Pad state
149 u32 last_entry_index = (mem->pad.index - 1) % mem->pad.entries.size();
150 PadState old_state = mem->pad.entries[last_entry_index].current_state;
151
152 // Compute bitmask with 1s for bits different from the old state
153 PadState changed = {{(state.hex ^ old_state.hex)}};
154
155 // Get the current Pad entry
156 PadDataEntry& pad_entry = mem->pad.entries[mem->pad.index];
157
158 // Update entry properties
159 pad_entry.current_state.hex = state.hex;
160 pad_entry.delta_additions.hex = changed.hex & state.hex;
161 pad_entry.delta_removals.hex = changed.hex & old_state.hex;
162 pad_entry.circle_pad_x = circle_pad_x;
163 pad_entry.circle_pad_y = circle_pad_y;
164
165 // If we just updated index 0, provide a new timestamp
166 if (mem->pad.index == 0) {
167 mem->pad.index_reset_ticks_previous = mem->pad.index_reset_ticks;
168 mem->pad.index_reset_ticks = (s64)CoreTiming::GetTicks();
169 }
170
171 mem->touch.index = next_touch_index;
172 next_touch_index = (next_touch_index + 1) % mem->touch.entries.size();
173
174 // Get the current touch entry
175 TouchDataEntry& touch_entry = mem->touch.entries[mem->touch.index];
176 bool pressed = false;
177 float x, y;
178 std::tie(x, y, pressed) = touch_device->GetStatus();
179 touch_entry.x = static_cast<u16>(x * Core::kScreenBottomWidth);
180 touch_entry.y = static_cast<u16>(y * Core::kScreenBottomHeight);
181 touch_entry.valid.Assign(pressed ? 1 : 0);
182
183 // TODO(bunnei): We're not doing anything with offset 0xA8 + 0x18 of HID SharedMemory, which
184 // supposedly is "Touch-screen entry, which contains the raw coordinate data prior to being
185 // converted to pixel coordinates." (http://3dbrew.org/wiki/HID_Shared_Memory#Offset_0xA8).
186
187 // If we just updated index 0, provide a new timestamp
188 if (mem->touch.index == 0) {
189 mem->touch.index_reset_ticks_previous = mem->touch.index_reset_ticks;
190 mem->touch.index_reset_ticks = (s64)CoreTiming::GetTicks();
191 }
192
193 // Signal both handles when there's an update to Pad or touch
194 event_pad_or_touch_1->Signal();
195 event_pad_or_touch_2->Signal();
196
197 // Reschedule recurrent event
198 CoreTiming::ScheduleEvent(pad_update_ticks - cycles_late, pad_update_event);
199}
200
201static void UpdateAccelerometerCallback(u64 userdata, int cycles_late) {
202 SharedMem* mem = reinterpret_cast<SharedMem*>(shared_mem->GetPointer());
203
204 mem->accelerometer.index = next_accelerometer_index;
205 next_accelerometer_index = (next_accelerometer_index + 1) % mem->accelerometer.entries.size();
206
207 Math::Vec3<float> accel;
208 std::tie(accel, std::ignore) = motion_device->GetStatus();
209 accel *= accelerometer_coef;
210 // TODO(wwylele): do a time stretch like the one in UpdateGyroscopeCallback
211 // The time stretch formula should be like
212 // stretched_vector = (raw_vector - gravity) * stretch_ratio + gravity
213
214 AccelerometerDataEntry& accelerometer_entry =
215 mem->accelerometer.entries[mem->accelerometer.index];
216
217 accelerometer_entry.x = static_cast<s16>(accel.x);
218 accelerometer_entry.y = static_cast<s16>(accel.y);
219 accelerometer_entry.z = static_cast<s16>(accel.z);
220
221 // Make up "raw" entry
222 // TODO(wwylele):
223 // From hardware testing, the raw_entry values are approximately, but not exactly, as twice as
224 // corresponding entries (or with a minus sign). It may caused by system calibration to the
225 // accelerometer. Figure out how it works, or, if no game reads raw_entry, the following three
226 // lines can be removed and leave raw_entry unimplemented.
227 mem->accelerometer.raw_entry.x = -2 * accelerometer_entry.x;
228 mem->accelerometer.raw_entry.z = 2 * accelerometer_entry.y;
229 mem->accelerometer.raw_entry.y = -2 * accelerometer_entry.z;
230
231 // If we just updated index 0, provide a new timestamp
232 if (mem->accelerometer.index == 0) {
233 mem->accelerometer.index_reset_ticks_previous = mem->accelerometer.index_reset_ticks;
234 mem->accelerometer.index_reset_ticks = (s64)CoreTiming::GetTicks();
235 }
236
237 event_accelerometer->Signal();
238
239 // Reschedule recurrent event
240 CoreTiming::ScheduleEvent(accelerometer_update_ticks - cycles_late, accelerometer_update_event);
241}
242
243static void UpdateGyroscopeCallback(u64 userdata, int cycles_late) {
244 SharedMem* mem = reinterpret_cast<SharedMem*>(shared_mem->GetPointer());
245
246 mem->gyroscope.index = next_gyroscope_index;
247 next_gyroscope_index = (next_gyroscope_index + 1) % mem->gyroscope.entries.size();
248
249 GyroscopeDataEntry& gyroscope_entry = mem->gyroscope.entries[mem->gyroscope.index];
250
251 Math::Vec3<float> gyro;
252 std::tie(std::ignore, gyro) = motion_device->GetStatus();
253 double stretch = Core::System::GetInstance().perf_stats.GetLastFrameTimeScale();
254 gyro *= gyroscope_coef * static_cast<float>(stretch);
255 gyroscope_entry.x = static_cast<s16>(gyro.x);
256 gyroscope_entry.y = static_cast<s16>(gyro.y);
257 gyroscope_entry.z = static_cast<s16>(gyro.z);
258
259 // Make up "raw" entry
260 mem->gyroscope.raw_entry.x = gyroscope_entry.x;
261 mem->gyroscope.raw_entry.z = -gyroscope_entry.y;
262 mem->gyroscope.raw_entry.y = gyroscope_entry.z;
263
264 // If we just updated index 0, provide a new timestamp
265 if (mem->gyroscope.index == 0) {
266 mem->gyroscope.index_reset_ticks_previous = mem->gyroscope.index_reset_ticks;
267 mem->gyroscope.index_reset_ticks = (s64)CoreTiming::GetTicks();
268 }
269
270 event_gyroscope->Signal();
271
272 // Reschedule recurrent event
273 CoreTiming::ScheduleEvent(gyroscope_update_ticks - cycles_late, gyroscope_update_event);
274}
275
276void GetIPCHandles(Service::Interface* self) {
277 u32* cmd_buff = Kernel::GetCommandBuffer();
278
279 cmd_buff[1] = 0; // No error
280 cmd_buff[2] = 0x14000000; // IPC Command Structure translate-header
281 // TODO(yuriks): Return error from SendSyncRequest is this fails (part of IPC marshalling)
282 cmd_buff[3] = Kernel::g_handle_table.Create(Service::HID::shared_mem).Unwrap();
283 cmd_buff[4] = Kernel::g_handle_table.Create(Service::HID::event_pad_or_touch_1).Unwrap();
284 cmd_buff[5] = Kernel::g_handle_table.Create(Service::HID::event_pad_or_touch_2).Unwrap();
285 cmd_buff[6] = Kernel::g_handle_table.Create(Service::HID::event_accelerometer).Unwrap();
286 cmd_buff[7] = Kernel::g_handle_table.Create(Service::HID::event_gyroscope).Unwrap();
287 cmd_buff[8] = Kernel::g_handle_table.Create(Service::HID::event_debug_pad).Unwrap();
288}
289
290void EnableAccelerometer(Service::Interface* self) {
291 u32* cmd_buff = Kernel::GetCommandBuffer();
292
293 ++enable_accelerometer_count;
294
295 // Schedules the accelerometer update event if the accelerometer was just enabled
296 if (enable_accelerometer_count == 1) {
297 CoreTiming::ScheduleEvent(accelerometer_update_ticks, accelerometer_update_event);
298 }
299
300 cmd_buff[1] = RESULT_SUCCESS.raw;
301
302 LOG_DEBUG(Service_HID, "called");
303}
304
305void DisableAccelerometer(Service::Interface* self) {
306 u32* cmd_buff = Kernel::GetCommandBuffer();
307
308 --enable_accelerometer_count;
309
310 // Unschedules the accelerometer update event if the accelerometer was just disabled
311 if (enable_accelerometer_count == 0) {
312 CoreTiming::UnscheduleEvent(accelerometer_update_event, 0);
313 }
314
315 cmd_buff[1] = RESULT_SUCCESS.raw;
316
317 LOG_DEBUG(Service_HID, "called");
318}
319
320void EnableGyroscopeLow(Service::Interface* self) {
321 u32* cmd_buff = Kernel::GetCommandBuffer();
322
323 ++enable_gyroscope_count;
324
325 // Schedules the gyroscope update event if the gyroscope was just enabled
326 if (enable_gyroscope_count == 1) {
327 CoreTiming::ScheduleEvent(gyroscope_update_ticks, gyroscope_update_event);
328 }
329
330 cmd_buff[1] = RESULT_SUCCESS.raw;
331
332 LOG_DEBUG(Service_HID, "called");
333}
334
335void DisableGyroscopeLow(Service::Interface* self) {
336 u32* cmd_buff = Kernel::GetCommandBuffer();
337
338 --enable_gyroscope_count;
339
340 // Unschedules the gyroscope update event if the gyroscope was just disabled
341 if (enable_gyroscope_count == 0) {
342 CoreTiming::UnscheduleEvent(gyroscope_update_event, 0);
343 }
344
345 cmd_buff[1] = RESULT_SUCCESS.raw;
346
347 LOG_DEBUG(Service_HID, "called");
348}
349
350void GetGyroscopeLowRawToDpsCoefficient(Service::Interface* self) {
351 u32* cmd_buff = Kernel::GetCommandBuffer();
352
353 cmd_buff[1] = RESULT_SUCCESS.raw;
354
355 f32 coef = gyroscope_coef;
356 memcpy(&cmd_buff[2], &coef, 4);
357}
358
359void GetGyroscopeLowCalibrateParam(Service::Interface* self) {
360 u32* cmd_buff = Kernel::GetCommandBuffer();
361
362 cmd_buff[1] = RESULT_SUCCESS.raw;
363
364 const s16 param_unit = 6700; // an approximate value taken from hw
365 GyroscopeCalibrateParam param = {
366 {0, param_unit, -param_unit}, {0, param_unit, -param_unit}, {0, param_unit, -param_unit},
367 };
368 memcpy(&cmd_buff[2], &param, sizeof(param));
369
370 LOG_WARNING(Service_HID, "(STUBBED) called");
371}
372
373void GetSoundVolume(Service::Interface* self) {
374 u32* cmd_buff = Kernel::GetCommandBuffer();
375
376 const u8 volume = 0x3F; // TODO(purpasmart): Find out if this is the max value for the volume
377
378 cmd_buff[1] = RESULT_SUCCESS.raw;
379 cmd_buff[2] = volume;
380
381 LOG_WARNING(Service_HID, "(STUBBED) called");
382}
383
384void Init() {
385 using namespace Kernel;
386
387 AddService(new HID_U_Interface);
388 AddService(new HID_SPVR_Interface);
389
390 is_device_reload_pending.store(true);
391
392 using Kernel::MemoryPermission;
393 shared_mem =
394 SharedMemory::Create(nullptr, 0x1000, MemoryPermission::ReadWrite, MemoryPermission::Read,
395 0, Kernel::MemoryRegion::BASE, "HID:SharedMemory");
396
397 next_pad_index = 0;
398 next_touch_index = 0;
399 next_accelerometer_index = 0;
400 next_gyroscope_index = 0;
401
402 enable_accelerometer_count = 0;
403 enable_gyroscope_count = 0;
404
405 // Create event handles
406 event_pad_or_touch_1 = Event::Create(ResetType::OneShot, "HID:EventPadOrTouch1");
407 event_pad_or_touch_2 = Event::Create(ResetType::OneShot, "HID:EventPadOrTouch2");
408 event_accelerometer = Event::Create(ResetType::OneShot, "HID:EventAccelerometer");
409 event_gyroscope = Event::Create(ResetType::OneShot, "HID:EventGyroscope");
410 event_debug_pad = Event::Create(ResetType::OneShot, "HID:EventDebugPad");
411
412 // Register update callbacks
413 pad_update_event = CoreTiming::RegisterEvent("HID::UpdatePadCallback", UpdatePadCallback);
414 accelerometer_update_event =
415 CoreTiming::RegisterEvent("HID::UpdateAccelerometerCallback", UpdateAccelerometerCallback);
416 gyroscope_update_event =
417 CoreTiming::RegisterEvent("HID::UpdateGyroscopeCallback", UpdateGyroscopeCallback);
418
419 CoreTiming::ScheduleEvent(pad_update_ticks, pad_update_event);
420}
421
422void Shutdown() {
423 shared_mem = nullptr;
424 event_pad_or_touch_1 = nullptr;
425 event_pad_or_touch_2 = nullptr;
426 event_accelerometer = nullptr;
427 event_gyroscope = nullptr;
428 event_debug_pad = nullptr;
429 UnloadInputDevices();
430}
431
432void ReloadInputDevices() {
433 is_device_reload_pending.store(true);
434}
435 17
436} // namespace HID 18} // namespace HID
437
438} // namespace Service 19} // namespace Service
diff --git a/src/core/hle/service/hid/hid.h b/src/core/hle/service/hid/hid.h
index ef25926b5..a1d227dfe 100644
--- a/src/core/hle/service/hid/hid.h
+++ b/src/core/hle/service/hid/hid.h
@@ -4,270 +4,9 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <array>
8#ifndef _MSC_VER
9#include <cstddef>
10#endif
11#include "common/bit_field.h"
12#include "common/common_funcs.h"
13#include "common/common_types.h"
14#include "core/settings.h"
15
16namespace Service { 7namespace Service {
17
18class Interface;
19
20namespace HID { 8namespace HID {
21 9
22/**
23 * Structure of a Pad controller state.
24 */
25struct PadState {
26 union {
27 u32 hex{};
28
29 BitField<0, 1, u32> a;
30 BitField<1, 1, u32> b;
31 BitField<2, 1, u32> select;
32 BitField<3, 1, u32> start;
33 BitField<4, 1, u32> right;
34 BitField<5, 1, u32> left;
35 BitField<6, 1, u32> up;
36 BitField<7, 1, u32> down;
37 BitField<8, 1, u32> r;
38 BitField<9, 1, u32> l;
39 BitField<10, 1, u32> x;
40 BitField<11, 1, u32> y;
41
42 BitField<28, 1, u32> circle_right;
43 BitField<29, 1, u32> circle_left;
44 BitField<30, 1, u32> circle_up;
45 BitField<31, 1, u32> circle_down;
46 };
47};
48
49/**
50 * Structure of a single entry of Pad state history within HID shared memory
51 */
52struct PadDataEntry {
53 PadState current_state;
54 PadState delta_additions;
55 PadState delta_removals;
56
57 s16 circle_pad_x;
58 s16 circle_pad_y;
59};
60
61/**
62 * Structure of a single entry of touch state history within HID shared memory
63 */
64struct TouchDataEntry {
65 u16 x; ///< Y-coordinate of a touchpad press on the lower screen
66 u16 y; ///< X-coordinate of a touchpad press on the lower screen
67 BitField<0, 7, u32> valid; ///< Set to 1 when this entry contains actual X/Y data, otherwise 0
68};
69
70/**
71 * Structure of a single entry of accelerometer state history within HID shared memory
72 */
73struct AccelerometerDataEntry {
74 s16 x;
75 s16 y;
76 s16 z;
77};
78
79/**
80 * Structure of a single entry of gyroscope state history within HID shared memory
81 */
82struct GyroscopeDataEntry {
83 s16 x;
84 s16 y;
85 s16 z;
86};
87
88/**
89 * Structure of data stored in HID shared memory
90 */
91struct SharedMem {
92 /// Pad data, this is used for buttons and the circle pad
93 struct {
94 s64 index_reset_ticks; ///< CPU tick count for when HID module updated entry index 0
95 s64 index_reset_ticks_previous; ///< Previous `index_reset_ticks`
96 u32 index; ///< Index of the last updated pad state entry
97
98 INSERT_PADDING_WORDS(0x2);
99
100 PadState current_state; ///< Current state of the pad buttons
101
102 // TODO(bunnei): Implement `raw_circle_pad_data` field
103 u32 raw_circle_pad_data; ///< Raw (analog) circle pad data, before being converted
104
105 INSERT_PADDING_WORDS(0x1);
106
107 std::array<PadDataEntry, 8> entries; ///< Last 8 pad entries
108 } pad;
109
110 /// Touchpad data, this is used for touchpad input
111 struct {
112 s64 index_reset_ticks; ///< CPU tick count for when HID module updated entry index 0
113 s64 index_reset_ticks_previous; ///< Previous `index_reset_ticks`
114 u32 index; ///< Index of the last updated touch entry
115
116 INSERT_PADDING_WORDS(0x1);
117
118 // TODO(bunnei): Implement `raw_entry` field
119 TouchDataEntry raw_entry; ///< Raw (analog) touch data, before being converted
120
121 std::array<TouchDataEntry, 8> entries; ///< Last 8 touch entries, in pixel coordinates
122 } touch;
123
124 /// Accelerometer data
125 struct {
126 s64 index_reset_ticks; ///< CPU tick count for when HID module updated entry index 0
127 s64 index_reset_ticks_previous; ///< Previous `index_reset_ticks`
128 u32 index; ///< Index of the last updated accelerometer entry
129
130 INSERT_PADDING_WORDS(0x1);
131
132 AccelerometerDataEntry raw_entry;
133 INSERT_PADDING_BYTES(2);
134
135 std::array<AccelerometerDataEntry, 8> entries;
136 } accelerometer;
137
138 /// Gyroscope data
139 struct {
140 s64 index_reset_ticks; ///< CPU tick count for when HID module updated entry index 0
141 s64 index_reset_ticks_previous; ///< Previous `index_reset_ticks`
142 u32 index; ///< Index of the last updated accelerometer entry
143
144 INSERT_PADDING_WORDS(0x1);
145
146 GyroscopeDataEntry raw_entry;
147 INSERT_PADDING_BYTES(2);
148
149 std::array<GyroscopeDataEntry, 32> entries;
150 } gyroscope;
151};
152
153/**
154 * Structure of calibrate params that GetGyroscopeLowCalibrateParam returns
155 */
156struct GyroscopeCalibrateParam {
157 struct {
158 // TODO (wwylele): figure out the exact meaning of these params
159 s16 zero_point;
160 s16 positive_unit_point;
161 s16 negative_unit_point;
162 } x, y, z;
163};
164
165// TODO: MSVC does not support using offsetof() on non-static data members even though this
166// is technically allowed since C++11. This macro should be enabled once MSVC adds
167// support for that.
168#ifndef _MSC_VER
169#define ASSERT_REG_POSITION(field_name, position) \
170 static_assert(offsetof(SharedMem, field_name) == position * 4, \
171 "Field " #field_name " has invalid position")
172
173ASSERT_REG_POSITION(pad.index_reset_ticks, 0x0);
174ASSERT_REG_POSITION(touch.index_reset_ticks, 0x2A);
175
176#undef ASSERT_REG_POSITION
177#endif // !defined(_MSC_VER)
178
179struct DirectionState {
180 bool up;
181 bool down;
182 bool left;
183 bool right;
184};
185
186/// Translates analog stick axes to directions. This is exposed for ir_rst module to use.
187DirectionState GetStickDirectionState(s16 circle_pad_x, s16 circle_pad_y);
188
189/**
190 * HID::GetIPCHandles service function
191 * Inputs:
192 * None
193 * Outputs:
194 * 1 : Result of function, 0 on success, otherwise error code
195 * 2 : IPC Command Structure translate-header
196 * 3 : Handle to HID shared memory
197 * 4 : Event signaled by HID
198 * 5 : Event signaled by HID
199 * 6 : Event signaled by HID
200 * 7 : Gyroscope event
201 * 8 : Event signaled by HID
202 */
203void GetIPCHandles(Interface* self);
204
205/**
206 * HID::EnableAccelerometer service function
207 * Inputs:
208 * None
209 * Outputs:
210 * 1 : Result of function, 0 on success, otherwise error code
211 */
212void EnableAccelerometer(Interface* self);
213
214/**
215 * HID::DisableAccelerometer service function
216 * Inputs:
217 * None
218 * Outputs:
219 * 1 : Result of function, 0 on success, otherwise error code
220 */
221void DisableAccelerometer(Interface* self);
222
223/**
224 * HID::EnableGyroscopeLow service function
225 * Inputs:
226 * None
227 * Outputs:
228 * 1 : Result of function, 0 on success, otherwise error code
229 */
230void EnableGyroscopeLow(Interface* self);
231
232/**
233 * HID::DisableGyroscopeLow service function
234 * Inputs:
235 * None
236 * Outputs:
237 * 1 : Result of function, 0 on success, otherwise error code
238 */
239void DisableGyroscopeLow(Interface* self);
240
241/**
242 * HID::GetSoundVolume service function
243 * Inputs:
244 * None
245 * Outputs:
246 * 1 : Result of function, 0 on success, otherwise error code
247 * 2 : u8 output value
248 */
249void GetSoundVolume(Interface* self);
250
251/**
252 * HID::GetGyroscopeLowRawToDpsCoefficient service function
253 * Inputs:
254 * None
255 * Outputs:
256 * 1 : Result of function, 0 on success, otherwise error code
257 * 2 : float output value
258 */
259void GetGyroscopeLowRawToDpsCoefficient(Service::Interface* self);
260
261/**
262 * HID::GetGyroscopeLowCalibrateParam service function
263 * Inputs:
264 * None
265 * Outputs:
266 * 1 : Result of function, 0 on success, otherwise error code
267 * 2~6 (18 bytes) : struct GyroscopeCalibrateParam
268 */
269void GetGyroscopeLowCalibrateParam(Service::Interface* self);
270
271/// Initialize HID service 10/// Initialize HID service
272void Init(); 11void Init();
273 12
@@ -276,5 +15,6 @@ void Shutdown();
276 15
277/// Reload input devices. Used when input configuration changed 16/// Reload input devices. Used when input configuration changed
278void ReloadInputDevices(); 17void ReloadInputDevices();
279} 18
280} 19} // namespace HID
20} // namespace Service
diff --git a/src/core/hle/service/hid/hid_spvr.cpp b/src/core/hle/service/hid/hid_spvr.cpp
deleted file mode 100644
index 09007e304..000000000
--- a/src/core/hle/service/hid/hid_spvr.cpp
+++ /dev/null
@@ -1,29 +0,0 @@
1// Copyright 2015 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include "core/hle/service/hid/hid.h"
6#include "core/hle/service/hid/hid_spvr.h"
7
8namespace Service {
9namespace HID {
10
11const Interface::FunctionInfo FunctionTable[] = {
12 {0x000A0000, GetIPCHandles, "GetIPCHandles"},
13 {0x000B0000, nullptr, "StartAnalogStickCalibration"},
14 {0x000E0000, nullptr, "GetAnalogStickCalibrateParam"},
15 {0x00110000, EnableAccelerometer, "EnableAccelerometer"},
16 {0x00120000, DisableAccelerometer, "DisableAccelerometer"},
17 {0x00130000, EnableGyroscopeLow, "EnableGyroscopeLow"},
18 {0x00140000, DisableGyroscopeLow, "DisableGyroscopeLow"},
19 {0x00150000, GetGyroscopeLowRawToDpsCoefficient, "GetGyroscopeLowRawToDpsCoefficient"},
20 {0x00160000, GetGyroscopeLowCalibrateParam, "GetGyroscopeLowCalibrateParam"},
21 {0x00170000, GetSoundVolume, "GetSoundVolume"},
22};
23
24HID_SPVR_Interface::HID_SPVR_Interface() {
25 Register(FunctionTable);
26}
27
28} // namespace HID
29} // namespace Service
diff --git a/src/core/hle/service/hid/hid_spvr.h b/src/core/hle/service/hid/hid_spvr.h
deleted file mode 100644
index ba61583d2..000000000
--- a/src/core/hle/service/hid/hid_spvr.h
+++ /dev/null
@@ -1,22 +0,0 @@
1// Copyright 2015 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include "core/hle/service/service.h"
8
9namespace Service {
10namespace HID {
11
12class HID_SPVR_Interface : public Service::Interface {
13public:
14 HID_SPVR_Interface();
15
16 std::string GetPortName() const override {
17 return "hid:SPVR";
18 }
19};
20
21} // namespace HID
22} // namespace Service \ No newline at end of file
diff --git a/src/core/hle/service/hid/hid_user.cpp b/src/core/hle/service/hid/hid_user.cpp
deleted file mode 100644
index 42591543c..000000000
--- a/src/core/hle/service/hid/hid_user.cpp
+++ /dev/null
@@ -1,29 +0,0 @@
1// Copyright 2015 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include "core/hle/service/hid/hid.h"
6#include "core/hle/service/hid/hid_user.h"
7
8namespace Service {
9namespace HID {
10
11const Interface::FunctionInfo FunctionTable[] = {
12 {0x000A0000, GetIPCHandles, "GetIPCHandles"},
13 {0x000B0000, nullptr, "StartAnalogStickCalibration"},
14 {0x000E0000, nullptr, "GetAnalogStickCalibrateParam"},
15 {0x00110000, EnableAccelerometer, "EnableAccelerometer"},
16 {0x00120000, DisableAccelerometer, "DisableAccelerometer"},
17 {0x00130000, EnableGyroscopeLow, "EnableGyroscopeLow"},
18 {0x00140000, DisableGyroscopeLow, "DisableGyroscopeLow"},
19 {0x00150000, GetGyroscopeLowRawToDpsCoefficient, "GetGyroscopeLowRawToDpsCoefficient"},
20 {0x00160000, GetGyroscopeLowCalibrateParam, "GetGyroscopeLowCalibrateParam"},
21 {0x00170000, GetSoundVolume, "GetSoundVolume"},
22};
23
24HID_U_Interface::HID_U_Interface() {
25 Register(FunctionTable);
26}
27
28} // namespace HID
29} // namespace Service
diff --git a/src/core/hle/service/hid/hid_user.h b/src/core/hle/service/hid/hid_user.h
deleted file mode 100644
index baf7fed79..000000000
--- a/src/core/hle/service/hid/hid_user.h
+++ /dev/null
@@ -1,28 +0,0 @@
1// Copyright 2015 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include "core/hle/service/service.h"
8
9// This service is used for interfacing to physical user controls.
10// Uses include game pad controls, touchscreen, accelerometers, gyroscopes, and debug pad.
11
12namespace Service {
13namespace HID {
14
15/**
16 * HID service interface.
17 */
18class HID_U_Interface : public Service::Interface {
19public:
20 HID_U_Interface();
21
22 std::string GetPortName() const override {
23 return "hid:USER";
24 }
25};
26
27} // namespace HID
28} // namespace Service \ No newline at end of file