summaryrefslogtreecommitdiff
path: root/src/core
diff options
context:
space:
mode:
Diffstat (limited to 'src/core')
-rw-r--r--src/core/hle/service/hid/hid.cpp180
-rw-r--r--src/core/hle/service/hid/hid.h84
-rw-r--r--src/core/hle/service/hid/hid_user.cpp2
-rw-r--r--src/core/hw/gpu.cpp4
4 files changed, 140 insertions, 130 deletions
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp
index e0689be2e..e7f9bec7e 100644
--- a/src/core/hle/service/hid/hid.cpp
+++ b/src/core/hle/service/hid/hid.cpp
@@ -12,31 +12,25 @@
12#include "core/hle/kernel/shared_memory.h" 12#include "core/hle/kernel/shared_memory.h"
13#include "core/hle/hle.h" 13#include "core/hle/hle.h"
14 14
15#include "video_core/video_core.h"
16
15namespace Service { 17namespace Service {
16namespace HID { 18namespace HID {
17 19
18Kernel::SharedPtr<Kernel::SharedMemory> g_shared_mem = nullptr; 20static const int MAX_CIRCLEPAD_POS = 0x9C; ///< Max value for a circle pad position
19 21
20Kernel::SharedPtr<Kernel::Event> g_event_pad_or_touch_1; 22// Handle to shared memory region designated to HID_User service
21Kernel::SharedPtr<Kernel::Event> g_event_pad_or_touch_2; 23static Kernel::SharedPtr<Kernel::SharedMemory> shared_mem = nullptr;
22Kernel::SharedPtr<Kernel::Event> g_event_accelerometer; 24
23Kernel::SharedPtr<Kernel::Event> g_event_gyroscope; 25// Event handles
24Kernel::SharedPtr<Kernel::Event> g_event_debug_pad; 26static Kernel::SharedPtr<Kernel::Event> event_pad_or_touch_1 = nullptr;
25 27static Kernel::SharedPtr<Kernel::Event> event_pad_or_touch_2 = nullptr;
26// Next Pad state update information 28static Kernel::SharedPtr<Kernel::Event> event_accelerometer = nullptr;
27static PadState next_state = {{0}}; 29static Kernel::SharedPtr<Kernel::Event> event_gyroscope = nullptr;
28static u32 next_index = 0; 30static Kernel::SharedPtr<Kernel::Event> event_debug_pad = nullptr;
29static s16 next_circle_x = 0; 31
30static s16 next_circle_y = 0; 32static u32 next_pad_index = 0;
31 33static u32 next_touch_index = 0;
32/**
33 * Gets a pointer to the PadData structure inside HID shared memory
34 */
35static inline PadData* GetPadData() {
36 if (g_shared_mem == nullptr)
37 return nullptr;
38 return reinterpret_cast<PadData*>(g_shared_mem->GetPointer().ValueOr(nullptr));
39}
40 34
41// TODO(peachum): 35// TODO(peachum):
42// Add a method for setting analog input from joystick device for the circle Pad. 36// Add a method for setting analog input from joystick device for the circle Pad.
@@ -51,90 +45,69 @@ static inline PadData* GetPadData() {
51// * Set PadData.current_state.circle_left = 1 if current PadEntry.circle_pad_x <= -41 45// * Set PadData.current_state.circle_left = 1 if current PadEntry.circle_pad_x <= -41
52// * Set PadData.current_state.circle_right = 1 if current PadEntry.circle_pad_y <= -41 46// * Set PadData.current_state.circle_right = 1 if current PadEntry.circle_pad_y <= -41
53 47
54/** 48void HIDUpdate() {
55 * Circle Pad from keys. 49 SharedMem* mem = reinterpret_cast<SharedMem*>(shared_mem->GetPointer().ValueOr(nullptr));
56 * 50 const PadState state = VideoCore::g_emu_window->GetPadState();
57 * This is implemented as "pushed all the way to an edge (max) or centered (0)".
58 *
59 * Indicate the circle pad is pushed completely to the edge in 1 of 8 directions.
60 */
61static void UpdateNextCirclePadState() {
62 static const s16 max_value = 0x9C;
63 next_circle_x = next_state.circle_left ? -max_value : 0x0;
64 next_circle_x += next_state.circle_right ? max_value : 0x0;
65 next_circle_y = next_state.circle_down ? -max_value : 0x0;
66 next_circle_y += next_state.circle_up ? max_value : 0x0;
67}
68 51
69/** 52 if (mem == nullptr) {
70 * Sets a Pad state (button or button combo) as pressed 53 LOG_DEBUG(Service_HID, "Cannot update HID prior to mapping shared memory!");
71 */
72void PadButtonPress(const PadState& pad_state) {
73 next_state.hex |= pad_state.hex;
74 UpdateNextCirclePadState();
75}
76
77/**
78 * Sets a Pad state (button or button combo) as released
79 */
80void PadButtonRelease(const PadState& pad_state) {
81 next_state.hex &= ~pad_state.hex;
82 UpdateNextCirclePadState();
83}
84
85/**
86 * Called after all Pad changes to be included in this update have been made,
87 * including both Pad key changes and analog circle Pad changes.
88 */
89void PadUpdateComplete() {
90 PadData* pad_data = GetPadData();
91
92 if (pad_data == nullptr) {
93 return; 54 return;
94 } 55 }
95 56
96 // Update PadData struct 57 mem->pad.current_state.hex = state.hex;
97 pad_data->current_state.hex = next_state.hex; 58 mem->pad.index = next_pad_index;
98 pad_data->index = next_index; 59 ++next_touch_index %= mem->pad.entries.size();
99 next_index = (next_index + 1) % pad_data->entries.size();
100 60
101 // Get the previous Pad state 61 // Get the previous Pad state
102 u32 last_entry_index = (pad_data->index - 1) % pad_data->entries.size(); 62 u32 last_entry_index = (mem->pad.index - 1) % mem->pad.entries.size();
103 PadState old_state = pad_data->entries[last_entry_index].current_state; 63 PadState old_state = mem->pad.entries[last_entry_index].current_state;
104 64
105 // Compute bitmask with 1s for bits different from the old state 65 // Compute bitmask with 1s for bits different from the old state
106 PadState changed; 66 PadState changed = { { (state.hex ^ old_state.hex) } };
107 changed.hex = (next_state.hex ^ old_state.hex);
108
109 // Compute what was added
110 PadState additions;
111 additions.hex = changed.hex & next_state.hex;
112
113 // Compute what was removed
114 PadState removals;
115 removals.hex = changed.hex & old_state.hex;
116 67
117 // Get the current Pad entry 68 // Get the current Pad entry
118 PadDataEntry* current_pad_entry = &pad_data->entries[pad_data->index]; 69 PadDataEntry* pad_entry = &mem->pad.entries[mem->pad.index];
119 70
120 // Update entry properties 71 // Update entry properties
121 current_pad_entry->current_state.hex = next_state.hex; 72 pad_entry->current_state.hex = state.hex;
122 current_pad_entry->delta_additions.hex = additions.hex; 73 pad_entry->delta_additions.hex = changed.hex & state.hex;
123 current_pad_entry->delta_removals.hex = removals.hex; 74 pad_entry->delta_removals.hex = changed.hex & old_state.hex;;
124 75
125 // Set circle Pad 76 // Set circle Pad
126 current_pad_entry->circle_pad_x = next_circle_x; 77 pad_entry->circle_pad_x = state.circle_left ? -MAX_CIRCLEPAD_POS :
127 current_pad_entry->circle_pad_y = next_circle_y; 78 state.circle_right ? MAX_CIRCLEPAD_POS : 0x0;
79 pad_entry->circle_pad_y = state.circle_down ? -MAX_CIRCLEPAD_POS :
80 state.circle_up ? MAX_CIRCLEPAD_POS : 0x0;
128 81
129 // If we just updated index 0, provide a new timestamp 82 // If we just updated index 0, provide a new timestamp
130 if (pad_data->index == 0) { 83 if (mem->pad.index == 0) {
131 pad_data->index_reset_ticks_previous = pad_data->index_reset_ticks; 84 mem->pad.index_reset_ticks_previous = mem->pad.index_reset_ticks;
132 pad_data->index_reset_ticks = (s64)Core::g_app_core->GetTicks(); 85 mem->pad.index_reset_ticks = (s64)Core::g_app_core->GetTicks();
86 }
87
88 mem->touch.index = next_touch_index;
89 ++next_touch_index %= mem->touch.entries.size();
90
91 // Get the current touch entry
92 TouchDataEntry* touch_entry = &mem->touch.entries[mem->touch.index];
93 bool pressed = false;
94
95 std::tie(touch_entry->x, touch_entry->y, pressed) = VideoCore::g_emu_window->GetTouchState();
96 touch_entry->valid = pressed ? 1 : 0;
97
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
102 // If we just updated index 0, provide a new timestamp
103 if (mem->touch.index == 0) {
104 mem->touch.index_reset_ticks_previous = mem->touch.index_reset_ticks;
105 mem->touch.index_reset_ticks = (s64)Core::g_app_core->GetTicks();
133 } 106 }
134 107
135 // Signal both handles when there's an update to Pad or touch 108 // Signal both handles when there's an update to Pad or touch
136 g_event_pad_or_touch_1->Signal(); 109 event_pad_or_touch_1->Signal();
137 g_event_pad_or_touch_2->Signal(); 110 event_pad_or_touch_2->Signal();
138} 111}
139 112
140void GetIPCHandles(Service::Interface* self) { 113void GetIPCHandles(Service::Interface* self) {
@@ -142,12 +115,12 @@ void GetIPCHandles(Service::Interface* self) {
142 115
143 cmd_buff[1] = 0; // No error 116 cmd_buff[1] = 0; // No error
144 // TODO(yuriks): Return error from SendSyncRequest is this fails (part of IPC marshalling) 117 // TODO(yuriks): Return error from SendSyncRequest is this fails (part of IPC marshalling)
145 cmd_buff[3] = Kernel::g_handle_table.Create(Service::HID::g_shared_mem).MoveFrom(); 118 cmd_buff[3] = Kernel::g_handle_table.Create(Service::HID::shared_mem).MoveFrom();
146 cmd_buff[4] = Kernel::g_handle_table.Create(Service::HID::g_event_pad_or_touch_1).MoveFrom(); 119 cmd_buff[4] = Kernel::g_handle_table.Create(Service::HID::event_pad_or_touch_1).MoveFrom();
147 cmd_buff[5] = Kernel::g_handle_table.Create(Service::HID::g_event_pad_or_touch_2).MoveFrom(); 120 cmd_buff[5] = Kernel::g_handle_table.Create(Service::HID::event_pad_or_touch_2).MoveFrom();
148 cmd_buff[6] = Kernel::g_handle_table.Create(Service::HID::g_event_accelerometer).MoveFrom(); 121 cmd_buff[6] = Kernel::g_handle_table.Create(Service::HID::event_accelerometer).MoveFrom();
149 cmd_buff[7] = Kernel::g_handle_table.Create(Service::HID::g_event_gyroscope).MoveFrom(); 122 cmd_buff[7] = Kernel::g_handle_table.Create(Service::HID::event_gyroscope).MoveFrom();
150 cmd_buff[8] = Kernel::g_handle_table.Create(Service::HID::g_event_debug_pad).MoveFrom(); 123 cmd_buff[8] = Kernel::g_handle_table.Create(Service::HID::event_debug_pad).MoveFrom();
151} 124}
152 125
153void HIDInit() { 126void HIDInit() {
@@ -156,19 +129,22 @@ void HIDInit() {
156 AddService(new HID_U_Interface); 129 AddService(new HID_U_Interface);
157 AddService(new HID_SPVR_Interface); 130 AddService(new HID_SPVR_Interface);
158 131
159 g_shared_mem = SharedMemory::Create("HID:SharedMem"); 132 shared_mem = SharedMemory::Create("HID:SharedMem");
133
134 next_pad_index = 0;
135 next_touch_index = 0;
160 136
161 // Create event handles 137 // Create event handles
162 g_event_pad_or_touch_1 = Event::Create(RESETTYPE_ONESHOT, "HID:EventPadOrTouch1"); 138 event_pad_or_touch_1 = Event::Create(RESETTYPE_ONESHOT, "HID:EventPadOrTouch1");
163 g_event_pad_or_touch_2 = Event::Create(RESETTYPE_ONESHOT, "HID:EventPadOrTouch2"); 139 event_pad_or_touch_2 = Event::Create(RESETTYPE_ONESHOT, "HID:EventPadOrTouch2");
164 g_event_accelerometer = Event::Create(RESETTYPE_ONESHOT, "HID:EventAccelerometer"); 140 event_accelerometer = Event::Create(RESETTYPE_ONESHOT, "HID:EventAccelerometer");
165 g_event_gyroscope = Event::Create(RESETTYPE_ONESHOT, "HID:EventGyroscope"); 141 event_gyroscope = Event::Create(RESETTYPE_ONESHOT, "HID:EventGyroscope");
166 g_event_debug_pad = Event::Create(RESETTYPE_ONESHOT, "HID:EventDebugPad"); 142 event_debug_pad = Event::Create(RESETTYPE_ONESHOT, "HID:EventDebugPad");
167} 143}
168 144
169void HIDShutdown() { 145void HIDShutdown() {
170
171} 146}
172 147
173} 148} // namespace HID
174} 149
150} // namespace Service
diff --git a/src/core/hle/service/hid/hid.h b/src/core/hle/service/hid/hid.h
index 9c6e86f77..0946cf660 100644
--- a/src/core/hle/service/hid/hid.h
+++ b/src/core/hle/service/hid/hid.h
@@ -18,16 +18,6 @@ namespace Kernel {
18namespace Service { 18namespace Service {
19namespace HID { 19namespace HID {
20 20
21// Handle to shared memory region designated to HID_User service
22extern Kernel::SharedPtr<Kernel::SharedMemory> g_shared_mem;
23
24// Event handles
25extern Kernel::SharedPtr<Kernel::Event> g_event_pad_or_touch_1;
26extern Kernel::SharedPtr<Kernel::Event> g_event_pad_or_touch_2;
27extern Kernel::SharedPtr<Kernel::Event> g_event_accelerometer;
28extern Kernel::SharedPtr<Kernel::Event> g_event_gyroscope;
29extern Kernel::SharedPtr<Kernel::Event> g_event_debug_pad;
30
31/** 21/**
32 * Structure of a Pad controller state. 22 * Structure of a Pad controller state.
33 */ 23 */
@@ -65,7 +55,7 @@ struct PadState {
65}; 55};
66 56
67/** 57/**
68 * Structure of a single entry in the PadData's Pad state history array. 58 * Structure of a single entry of Pad state history within HID shared memory
69 */ 59 */
70struct PadDataEntry { 60struct PadDataEntry {
71 PadState current_state; 61 PadState current_state;
@@ -77,24 +67,65 @@ struct PadDataEntry {
77}; 67};
78 68
79/** 69/**
80 * Structure of all data related to the 3DS Pad. 70 * Structure of a single entry of touch state history within HID shared memory
71 */
72struct TouchDataEntry {
73 u16 x; ///< Y-coordinate of a touchpad press on the lower screen
74 u16 y; ///< X-coordinate of a touchpad press on the lower screen
75 BitField<0, 7, u32> valid; ///< Set to 1 when this entry contains actual X/Y data, otherwise 0
76};
77
78/**
79 * Structure of data stored in HID shared memory
81 */ 80 */
82struct PadData { 81struct SharedMem {
83 s64 index_reset_ticks; 82 /// Pad data, this is used for buttons and the circle pad
84 s64 index_reset_ticks_previous; 83 struct {
85 u32 index; // the index of the last updated Pad state history element 84 s64 index_reset_ticks; ///< CPU tick count for when HID module updated entry index 0
85 s64 index_reset_ticks_previous; ///< Previous `index_reset_ticks`
86 u32 index; ///< Index of the last updated pad state entry
87
88 INSERT_PADDING_WORDS(0x2);
89
90 PadState current_state; ///< Current state of the pad buttons
86 91
87 u32 pad1; 92 // TODO(bunnei): Implement `raw_circle_pad_data` field
88 u32 pad2; 93 u32 raw_circle_pad_data; ///< Raw (analog) circle pad data, before being converted
89 94
90 PadState current_state; // same as entries[index].current_state 95 INSERT_PADDING_WORDS(0x1);
91 u32 raw_circle_pad_data;
92 96
93 u32 pad3; 97 std::array<PadDataEntry, 8> entries; ///< Last 8 pad entries
98 } pad;
94 99
95 std::array<PadDataEntry, 8> entries; // Pad state history 100 /// Touchpad data, this is used for touchpad input
101 struct {
102 s64 index_reset_ticks; ///< CPU tick count for when HID module updated entry index 0
103 s64 index_reset_ticks_previous; ///< Previous `index_reset_ticks`
104 u32 index; ///< Index of the last updated touch entry
105
106 INSERT_PADDING_WORDS(0x1);
107
108 // TODO(bunnei): Implement `raw_entry` field
109 TouchDataEntry raw_entry; ///< Raw (analog) touch data, before being converted
110
111 std::array<TouchDataEntry, 8> entries; ///< Last 8 touch entries, in pixel coordinates
112 } touch;
96}; 113};
97 114
115// TODO: MSVC does not support using offsetof() on non-static data members even though this
116// is technically allowed since C++11. This macro should be enabled once MSVC adds
117// support for that.
118#ifndef _MSC_VER
119#define ASSERT_REG_POSITION(field_name, position) \
120 static_assert(offsetof(SharedMem, field_name) == position * 4, \
121 "Field "#field_name" has invalid position")
122
123ASSERT_REG_POSITION(pad.index_reset_ticks, 0x0);
124ASSERT_REG_POSITION(touch.index_reset_ticks, 0x2A);
125
126#undef ASSERT_REG_POSITION
127#endif // !defined(_MSC_VER)
128
98// Pre-defined PadStates for single button presses 129// Pre-defined PadStates for single button presses
99const PadState PAD_NONE = {{0}}; 130const PadState PAD_NONE = {{0}};
100const PadState PAD_A = {{1u << 0}}; 131const PadState PAD_A = {{1u << 0}};
@@ -140,12 +171,13 @@ const PadState PAD_CIRCLE_DOWN = {{1u << 31}};
140 */ 171 */
141void GetIPCHandles(Interface* self); 172void GetIPCHandles(Interface* self);
142 173
143// Methods for updating the HID module's state 174/// Checks for user input updates
144void PadButtonPress(const PadState& pad_state); 175void HIDUpdate();
145void PadButtonRelease(const PadState& pad_state);
146void PadUpdateComplete();
147 176
177/// Initialize HID service
148void HIDInit(); 178void HIDInit();
179
180/// Shutdown HID service
149void HIDShutdown(); 181void HIDShutdown();
150 182
151} 183}
diff --git a/src/core/hle/service/hid/hid_user.cpp b/src/core/hle/service/hid/hid_user.cpp
index 1d0accefe..c2d5758fb 100644
--- a/src/core/hle/service/hid/hid_user.cpp
+++ b/src/core/hle/service/hid/hid_user.cpp
@@ -3,8 +3,6 @@
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include "core/hle/hle.h" 5#include "core/hle/hle.h"
6#include "core/hle/kernel/event.h"
7#include "core/hle/kernel/shared_memory.h"
8#include "core/hle/service/hid/hid.h" 6#include "core/hle/service/hid/hid.h"
9#include "core/hle/service/hid/hid_user.h" 7#include "core/hle/service/hid/hid_user.h"
10 8
diff --git a/src/core/hw/gpu.cpp b/src/core/hw/gpu.cpp
index 30318fc06..f933a5e8d 100644
--- a/src/core/hw/gpu.cpp
+++ b/src/core/hw/gpu.cpp
@@ -14,6 +14,7 @@
14#include "core/hle/hle.h" 14#include "core/hle/hle.h"
15#include "core/hle/service/gsp_gpu.h" 15#include "core/hle/service/gsp_gpu.h"
16#include "core/hle/service/dsp_dsp.h" 16#include "core/hle/service/dsp_dsp.h"
17#include "core/hle/service/hid/hid.h"
17 18
18#include "core/hw/hw.h" 19#include "core/hw/hw.h"
19#include "core/hw/gpu.h" 20#include "core/hw/gpu.h"
@@ -295,6 +296,9 @@ static void VBlankCallback(u64 userdata, int cycles_late) {
295 // this. Certain games expect this to be periodically signaled. 296 // this. Certain games expect this to be periodically signaled.
296 DSP_DSP::SignalInterrupt(); 297 DSP_DSP::SignalInterrupt();
297 298
299 // Check for user input updates
300 Service::HID::HIDUpdate();
301
298 // Reschedule recurrent event 302 // Reschedule recurrent event
299 CoreTiming::ScheduleEvent(frame_ticks - cycles_late, vblank_event); 303 CoreTiming::ScheduleEvent(frame_ticks - cycles_late, vblank_event);
300} 304}