summaryrefslogtreecommitdiffstats
path: root/src/core/hle
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/hle')
-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
3 files changed, 136 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 @@
#include "core/hle/kernel/shared_memory.h"
#include "core/hle/hle.h"
+#include "video_core/video_core.h"
+
namespace Service {
namespace HID {
-Kernel::SharedPtr<Kernel::SharedMemory> g_shared_mem = nullptr;
-
-Kernel::SharedPtr<Kernel::Event> g_event_pad_or_touch_1;
-Kernel::SharedPtr<Kernel::Event> g_event_pad_or_touch_2;
-Kernel::SharedPtr<Kernel::Event> g_event_accelerometer;
-Kernel::SharedPtr<Kernel::Event> g_event_gyroscope;
-Kernel::SharedPtr<Kernel::Event> g_event_debug_pad;
-
-// Next Pad state update information
-static PadState next_state = {{0}};
-static u32 next_index = 0;
-static s16 next_circle_x = 0;
-static s16 next_circle_y = 0;
-
-/**
- * Gets a pointer to the PadData structure inside HID shared memory
- */
-static inline PadData* GetPadData() {
- if (g_shared_mem == nullptr)
- return nullptr;
- return reinterpret_cast<PadData*>(g_shared_mem->GetPointer().ValueOr(nullptr));
-}
+static const int MAX_CIRCLEPAD_POS = 0x9C; ///< Max value for a circle pad position
+
+// Handle to shared memory region designated to HID_User service
+static Kernel::SharedPtr<Kernel::SharedMemory> shared_mem = nullptr;
+
+// Event handles
+static Kernel::SharedPtr<Kernel::Event> event_pad_or_touch_1 = nullptr;
+static Kernel::SharedPtr<Kernel::Event> event_pad_or_touch_2 = nullptr;
+static Kernel::SharedPtr<Kernel::Event> event_accelerometer = nullptr;
+static Kernel::SharedPtr<Kernel::Event> event_gyroscope = nullptr;
+static Kernel::SharedPtr<Kernel::Event> event_debug_pad = nullptr;
+
+static u32 next_pad_index = 0;
+static u32 next_touch_index = 0;
// TODO(peachum):
// Add a method for setting analog input from joystick device for the circle Pad.
@@ -51,90 +45,69 @@ static inline PadData* GetPadData() {
// * Set PadData.current_state.circle_left = 1 if current PadEntry.circle_pad_x <= -41
// * Set PadData.current_state.circle_right = 1 if current PadEntry.circle_pad_y <= -41
-/**
- * Circle Pad from keys.
- *
- * This is implemented as "pushed all the way to an edge (max) or centered (0)".
- *
- * Indicate the circle pad is pushed completely to the edge in 1 of 8 directions.
- */
-static void UpdateNextCirclePadState() {
- static const s16 max_value = 0x9C;
- next_circle_x = next_state.circle_left ? -max_value : 0x0;
- next_circle_x += next_state.circle_right ? max_value : 0x0;
- next_circle_y = next_state.circle_down ? -max_value : 0x0;
- next_circle_y += next_state.circle_up ? max_value : 0x0;
-}
+void HIDUpdate() {
+ SharedMem* mem = reinterpret_cast<SharedMem*>(shared_mem->GetPointer().ValueOr(nullptr));
+ const PadState state = VideoCore::g_emu_window->GetPadState();
-/**
- * Sets a Pad state (button or button combo) as pressed
- */
-void PadButtonPress(const PadState& pad_state) {
- next_state.hex |= pad_state.hex;
- UpdateNextCirclePadState();
-}
-
-/**
- * Sets a Pad state (button or button combo) as released
- */
-void PadButtonRelease(const PadState& pad_state) {
- next_state.hex &= ~pad_state.hex;
- UpdateNextCirclePadState();
-}
-
-/**
- * Called after all Pad changes to be included in this update have been made,
- * including both Pad key changes and analog circle Pad changes.
- */
-void PadUpdateComplete() {
- PadData* pad_data = GetPadData();
-
- if (pad_data == nullptr) {
+ if (mem == nullptr) {
+ LOG_DEBUG(Service_HID, "Cannot update HID prior to mapping shared memory!");
return;
}
- // Update PadData struct
- pad_data->current_state.hex = next_state.hex;
- pad_data->index = next_index;
- next_index = (next_index + 1) % pad_data->entries.size();
+ mem->pad.current_state.hex = state.hex;
+ mem->pad.index = next_pad_index;
+ ++next_touch_index %= mem->pad.entries.size();
// Get the previous Pad state
- u32 last_entry_index = (pad_data->index - 1) % pad_data->entries.size();
- PadState old_state = pad_data->entries[last_entry_index].current_state;
+ u32 last_entry_index = (mem->pad.index - 1) % mem->pad.entries.size();
+ PadState old_state = mem->pad.entries[last_entry_index].current_state;
// Compute bitmask with 1s for bits different from the old state
- PadState changed;
- changed.hex = (next_state.hex ^ old_state.hex);
-
- // Compute what was added
- PadState additions;
- additions.hex = changed.hex & next_state.hex;
-
- // Compute what was removed
- PadState removals;
- removals.hex = changed.hex & old_state.hex;
+ PadState changed = { { (state.hex ^ old_state.hex) } };
// Get the current Pad entry
- PadDataEntry* current_pad_entry = &pad_data->entries[pad_data->index];
+ PadDataEntry* pad_entry = &mem->pad.entries[mem->pad.index];
// Update entry properties
- current_pad_entry->current_state.hex = next_state.hex;
- current_pad_entry->delta_additions.hex = additions.hex;
- current_pad_entry->delta_removals.hex = removals.hex;
+ pad_entry->current_state.hex = state.hex;
+ pad_entry->delta_additions.hex = changed.hex & state.hex;
+ pad_entry->delta_removals.hex = changed.hex & old_state.hex;;
// Set circle Pad
- current_pad_entry->circle_pad_x = next_circle_x;
- current_pad_entry->circle_pad_y = next_circle_y;
+ pad_entry->circle_pad_x = state.circle_left ? -MAX_CIRCLEPAD_POS :
+ state.circle_right ? MAX_CIRCLEPAD_POS : 0x0;
+ pad_entry->circle_pad_y = state.circle_down ? -MAX_CIRCLEPAD_POS :
+ state.circle_up ? MAX_CIRCLEPAD_POS : 0x0;
// If we just updated index 0, provide a new timestamp
- if (pad_data->index == 0) {
- pad_data->index_reset_ticks_previous = pad_data->index_reset_ticks;
- pad_data->index_reset_ticks = (s64)Core::g_app_core->GetTicks();
+ if (mem->pad.index == 0) {
+ mem->pad.index_reset_ticks_previous = mem->pad.index_reset_ticks;
+ mem->pad.index_reset_ticks = (s64)Core::g_app_core->GetTicks();
+ }
+
+ mem->touch.index = next_touch_index;
+ ++next_touch_index %= mem->touch.entries.size();
+
+ // Get the current touch entry
+ TouchDataEntry* touch_entry = &mem->touch.entries[mem->touch.index];
+ bool pressed = false;
+
+ std::tie(touch_entry->x, touch_entry->y, pressed) = VideoCore::g_emu_window->GetTouchState();
+ touch_entry->valid = pressed ? 1 : 0;
+
+ // TODO(bunnei): We're not doing anything with offset 0xA8 + 0x18 of HID SharedMemory, which
+ // supposedly is "Touch-screen entry, which contains the raw coordinate data prior to being
+ // converted to pixel coordinates." (http://3dbrew.org/wiki/HID_Shared_Memory#Offset_0xA8).
+
+ // If we just updated index 0, provide a new timestamp
+ if (mem->touch.index == 0) {
+ mem->touch.index_reset_ticks_previous = mem->touch.index_reset_ticks;
+ mem->touch.index_reset_ticks = (s64)Core::g_app_core->GetTicks();
}
// Signal both handles when there's an update to Pad or touch
- g_event_pad_or_touch_1->Signal();
- g_event_pad_or_touch_2->Signal();
+ event_pad_or_touch_1->Signal();
+ event_pad_or_touch_2->Signal();
}
void GetIPCHandles(Service::Interface* self) {
@@ -142,12 +115,12 @@ void GetIPCHandles(Service::Interface* self) {
cmd_buff[1] = 0; // No error
// TODO(yuriks): Return error from SendSyncRequest is this fails (part of IPC marshalling)
- cmd_buff[3] = Kernel::g_handle_table.Create(Service::HID::g_shared_mem).MoveFrom();
- cmd_buff[4] = Kernel::g_handle_table.Create(Service::HID::g_event_pad_or_touch_1).MoveFrom();
- cmd_buff[5] = Kernel::g_handle_table.Create(Service::HID::g_event_pad_or_touch_2).MoveFrom();
- cmd_buff[6] = Kernel::g_handle_table.Create(Service::HID::g_event_accelerometer).MoveFrom();
- cmd_buff[7] = Kernel::g_handle_table.Create(Service::HID::g_event_gyroscope).MoveFrom();
- cmd_buff[8] = Kernel::g_handle_table.Create(Service::HID::g_event_debug_pad).MoveFrom();
+ cmd_buff[3] = Kernel::g_handle_table.Create(Service::HID::shared_mem).MoveFrom();
+ cmd_buff[4] = Kernel::g_handle_table.Create(Service::HID::event_pad_or_touch_1).MoveFrom();
+ cmd_buff[5] = Kernel::g_handle_table.Create(Service::HID::event_pad_or_touch_2).MoveFrom();
+ cmd_buff[6] = Kernel::g_handle_table.Create(Service::HID::event_accelerometer).MoveFrom();
+ cmd_buff[7] = Kernel::g_handle_table.Create(Service::HID::event_gyroscope).MoveFrom();
+ cmd_buff[8] = Kernel::g_handle_table.Create(Service::HID::event_debug_pad).MoveFrom();
}
void HIDInit() {
@@ -156,19 +129,22 @@ void HIDInit() {
AddService(new HID_U_Interface);
AddService(new HID_SPVR_Interface);
- g_shared_mem = SharedMemory::Create("HID:SharedMem");
+ shared_mem = SharedMemory::Create("HID:SharedMem");
+
+ next_pad_index = 0;
+ next_touch_index = 0;
// Create event handles
- g_event_pad_or_touch_1 = Event::Create(RESETTYPE_ONESHOT, "HID:EventPadOrTouch1");
- g_event_pad_or_touch_2 = Event::Create(RESETTYPE_ONESHOT, "HID:EventPadOrTouch2");
- g_event_accelerometer = Event::Create(RESETTYPE_ONESHOT, "HID:EventAccelerometer");
- g_event_gyroscope = Event::Create(RESETTYPE_ONESHOT, "HID:EventGyroscope");
- g_event_debug_pad = Event::Create(RESETTYPE_ONESHOT, "HID:EventDebugPad");
+ event_pad_or_touch_1 = Event::Create(RESETTYPE_ONESHOT, "HID:EventPadOrTouch1");
+ event_pad_or_touch_2 = Event::Create(RESETTYPE_ONESHOT, "HID:EventPadOrTouch2");
+ event_accelerometer = Event::Create(RESETTYPE_ONESHOT, "HID:EventAccelerometer");
+ event_gyroscope = Event::Create(RESETTYPE_ONESHOT, "HID:EventGyroscope");
+ event_debug_pad = Event::Create(RESETTYPE_ONESHOT, "HID:EventDebugPad");
}
void HIDShutdown() {
-
}
-}
-}
+} // namespace HID
+
+} // 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 {
namespace Service {
namespace HID {
-// Handle to shared memory region designated to HID_User service
-extern Kernel::SharedPtr<Kernel::SharedMemory> g_shared_mem;
-
-// Event handles
-extern Kernel::SharedPtr<Kernel::Event> g_event_pad_or_touch_1;
-extern Kernel::SharedPtr<Kernel::Event> g_event_pad_or_touch_2;
-extern Kernel::SharedPtr<Kernel::Event> g_event_accelerometer;
-extern Kernel::SharedPtr<Kernel::Event> g_event_gyroscope;
-extern Kernel::SharedPtr<Kernel::Event> g_event_debug_pad;
-
/**
* Structure of a Pad controller state.
*/
@@ -65,7 +55,7 @@ struct PadState {
};
/**
- * Structure of a single entry in the PadData's Pad state history array.
+ * Structure of a single entry of Pad state history within HID shared memory
*/
struct PadDataEntry {
PadState current_state;
@@ -77,24 +67,65 @@ struct PadDataEntry {
};
/**
- * Structure of all data related to the 3DS Pad.
+ * Structure of a single entry of touch state history within HID shared memory
+ */
+struct TouchDataEntry {
+ u16 x; ///< Y-coordinate of a touchpad press on the lower screen
+ u16 y; ///< X-coordinate of a touchpad press on the lower screen
+ BitField<0, 7, u32> valid; ///< Set to 1 when this entry contains actual X/Y data, otherwise 0
+};
+
+/**
+ * Structure of data stored in HID shared memory
*/
-struct PadData {
- s64 index_reset_ticks;
- s64 index_reset_ticks_previous;
- u32 index; // the index of the last updated Pad state history element
+struct SharedMem {
+ /// Pad data, this is used for buttons and the circle pad
+ struct {
+ s64 index_reset_ticks; ///< CPU tick count for when HID module updated entry index 0
+ s64 index_reset_ticks_previous; ///< Previous `index_reset_ticks`
+ u32 index; ///< Index of the last updated pad state entry
+
+ INSERT_PADDING_WORDS(0x2);
+
+ PadState current_state; ///< Current state of the pad buttons
- u32 pad1;
- u32 pad2;
+ // TODO(bunnei): Implement `raw_circle_pad_data` field
+ u32 raw_circle_pad_data; ///< Raw (analog) circle pad data, before being converted
- PadState current_state; // same as entries[index].current_state
- u32 raw_circle_pad_data;
+ INSERT_PADDING_WORDS(0x1);
- u32 pad3;
+ std::array<PadDataEntry, 8> entries; ///< Last 8 pad entries
+ } pad;
- std::array<PadDataEntry, 8> entries; // Pad state history
+ /// Touchpad data, this is used for touchpad input
+ struct {
+ s64 index_reset_ticks; ///< CPU tick count for when HID module updated entry index 0
+ s64 index_reset_ticks_previous; ///< Previous `index_reset_ticks`
+ u32 index; ///< Index of the last updated touch entry
+
+ INSERT_PADDING_WORDS(0x1);
+
+ // TODO(bunnei): Implement `raw_entry` field
+ TouchDataEntry raw_entry; ///< Raw (analog) touch data, before being converted
+
+ std::array<TouchDataEntry, 8> entries; ///< Last 8 touch entries, in pixel coordinates
+ } touch;
};
+// TODO: MSVC does not support using offsetof() on non-static data members even though this
+// is technically allowed since C++11. This macro should be enabled once MSVC adds
+// support for that.
+#ifndef _MSC_VER
+#define ASSERT_REG_POSITION(field_name, position) \
+ static_assert(offsetof(SharedMem, field_name) == position * 4, \
+ "Field "#field_name" has invalid position")
+
+ASSERT_REG_POSITION(pad.index_reset_ticks, 0x0);
+ASSERT_REG_POSITION(touch.index_reset_ticks, 0x2A);
+
+#undef ASSERT_REG_POSITION
+#endif // !defined(_MSC_VER)
+
// Pre-defined PadStates for single button presses
const PadState PAD_NONE = {{0}};
const PadState PAD_A = {{1u << 0}};
@@ -140,12 +171,13 @@ const PadState PAD_CIRCLE_DOWN = {{1u << 31}};
*/
void GetIPCHandles(Interface* self);
-// Methods for updating the HID module's state
-void PadButtonPress(const PadState& pad_state);
-void PadButtonRelease(const PadState& pad_state);
-void PadUpdateComplete();
+/// Checks for user input updates
+void HIDUpdate();
+/// Initialize HID service
void HIDInit();
+
+/// Shutdown HID service
void HIDShutdown();
}
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 @@
// Refer to the license.txt file included.
#include "core/hle/hle.h"
-#include "core/hle/kernel/event.h"
-#include "core/hle/kernel/shared_memory.h"
#include "core/hle/service/hid/hid.h"
#include "core/hle/service/hid/hid_user.h"