diff --git a/src/citra_qt/CMakeLists.txt b/src/citra_qt/CMakeLists.txt index 7f880df8b..4607709fa 100644 --- a/src/citra_qt/CMakeLists.txt +++ b/src/citra_qt/CMakeLists.txt @@ -7,6 +7,7 @@ set(SRCS debugger/ramview.cpp debugger/registers.cpp hotkeys.cpp + key_bindings.cpp main.cpp config/controller_config.cpp config/controller_config_util.cpp) @@ -17,11 +18,13 @@ set (HEADERS debugger/ramview.hxx debugger/registers.hxx hotkeys.hxx + key_bindings.hxx main.hxx ui_callstack.h ui_controller_config.h ui_disassembler.h ui_hotkeys.h + ui_key_bindings.h ui_main.h ui_registers.h version.h @@ -33,6 +36,7 @@ qt4_wrap_ui(UI_HDRS debugger/disassembler.ui debugger/registers.ui hotkeys.ui + key_bindings.ui main.ui config/controller_config.ui) @@ -45,6 +49,7 @@ qt4_wrap_cpp(MOC_SRCS debugger/registers.hxx debugger/ramview.hxx hotkeys.hxx + key_bindings.hxx main.hxx config/controller_config.hxx config/controller_config_util.hxx) diff --git a/src/citra_qt/bootmanager.cpp b/src/citra_qt/bootmanager.cpp index f85116419..74bd13f9e 100644 --- a/src/citra_qt/bootmanager.cpp +++ b/src/citra_qt/bootmanager.cpp @@ -3,10 +3,13 @@ #include "common/common.h" #include "bootmanager.hxx" +#include "key_bindings.hxx" + #include "core/core.h" #include "core/loader.h" #include "core/hw/hw.h" +#include "core/hw/hid.h" #include "video_core/video_core.h" @@ -119,6 +122,8 @@ GRenderWindow::GRenderWindow(QWidget* parent) : QWidget(parent), emu_thread(this setLayout(layout); BackupGeometry(); + + buttonReg = 0x0; } GRenderWindow::~GRenderWindow() @@ -192,12 +197,17 @@ void GRenderWindow::keyPressEvent(QKeyEvent* event) /* bool key_processed = false; for (unsigned int channel = 0; channel < 4 && controller_interface(); ++channel) - if (controller_interface()->SetControllerStatus(channel, event->key(), input_common::GCController::PRESSED)) - key_processed = true; + if (controller_interface()->SetControllerStatus(channel, event->key(), input_common::GCController::PRESSED)) + key_processed = true; if (!key_processed) - QWidget::keyPressEvent(event); + QWidget::keyPressEvent(event); */ + + + buttonReg |= GetKeyBinding(event); + HID::SetButtonReg(buttonReg); + return; } void GRenderWindow::keyReleaseEvent(QKeyEvent* event) @@ -211,4 +221,7 @@ void GRenderWindow::keyReleaseEvent(QKeyEvent* event) if (!key_processed) QWidget::keyPressEvent(event); */ + + buttonReg &= 0xffffffff ^ GetKeyBinding(event); + HID::SetButtonReg(buttonReg); } \ No newline at end of file diff --git a/src/citra_qt/bootmanager.hxx b/src/citra_qt/bootmanager.hxx index 1001e1ee4..84216cf2a 100644 --- a/src/citra_qt/bootmanager.hxx +++ b/src/citra_qt/bootmanager.hxx @@ -1,5 +1,6 @@ #include #include +#include #include "common/common.h" #include "common/emu_window.h" @@ -109,4 +110,6 @@ private: EmuThread emu_thread; QByteArray geometry; + + u32 buttonReg; }; diff --git a/src/citra_qt/citra_qt.vcxproj b/src/citra_qt/citra_qt.vcxproj index c99c8eeee..71e86dc93 100644 --- a/src/citra_qt/citra_qt.vcxproj +++ b/src/citra_qt/citra_qt.vcxproj @@ -137,6 +137,7 @@ + @@ -152,6 +153,7 @@ + @@ -177,6 +179,7 @@ + diff --git a/src/citra_qt/citra_qt.vcxproj.filters b/src/citra_qt/citra_qt.vcxproj.filters index 903082c3c..483b37dc0 100644 --- a/src/citra_qt/citra_qt.vcxproj.filters +++ b/src/citra_qt/citra_qt.vcxproj.filters @@ -51,6 +51,7 @@ debugger + @@ -86,6 +87,7 @@ debugger + @@ -114,6 +116,7 @@ debugger + diff --git a/src/citra_qt/debugger/graphics_cmdlists.cpp b/src/citra_qt/debugger/graphics_cmdlists.cpp index 195197ef5..081c63ff0 100644 --- a/src/citra_qt/debugger/graphics_cmdlists.cpp +++ b/src/citra_qt/debugger/graphics_cmdlists.cpp @@ -17,6 +17,7 @@ GPUCommandListModel::GPUCommandListModel(QObject* parent) : QAbstractItemModel(p QModelIndex GPUCommandListModel::index(int row, int column, const QModelIndex& parent) const { TreeItem* item; + TreeItem* internal; if (!parent.isValid()) { item = root_item; @@ -24,7 +25,13 @@ QModelIndex GPUCommandListModel::index(int row, int column, const QModelIndex& p item = (TreeItem*)parent.internalPointer(); } - return createIndex(row, column, item->children[row]); + if (item->children.size() <= row) { + internal = item; + } + else { internal = item->children[row]; } + + + return createIndex(row, column, internal); } QModelIndex GPUCommandListModel::parent(const QModelIndex& child) const diff --git a/src/citra_qt/key_bindings.cpp b/src/citra_qt/key_bindings.cpp new file mode 100644 index 000000000..b49ead464 --- /dev/null +++ b/src/citra_qt/key_bindings.cpp @@ -0,0 +1,143 @@ +#include +#include +#include +#include +#include "key_bindings.hxx" +#include +#include "core/hw/hid.h" + +typedef std::map BindingsMap; + +BindingsMap bindings; + + +typedef std::map ReverseBindingsMap; + +ReverseBindingsMap reverseBindings; + + +typedef std::map NameMap; + +NameMap names; + +typedef std::map ReverseNameMap; + +ReverseNameMap reverseNames; + +void SaveKeyBindings(QSettings& settings) +{ + settings.beginGroup("KeyBindings"); + + for (BindingsMap::iterator group = bindings.begin(); group != bindings.end(); ++group) + { + settings.setValue(group->first.toString(), group->second); + settings.endGroup(); + } + settings.endGroup(); +} + +void LoadKeyBindings(QSettings& settings) +{ + settings.beginGroup("KeyBindings"); + + // Make sure NOT to use a reference here because it would become invalid once we call beginGroup() + QStringList keys = settings.allKeys(); + for (QList::iterator key = keys.begin(); key != keys.end(); ++key) + { + settings.beginGroup(*key); + QKeySequence keyseq = QKeySequence::fromString(settings.value("").toString()); + } + + settings.endGroup(); +} + +HID::PAD GetKeyBinding(QKeyEvent * event) +{ + QKeySequence keySeq = QKeySequence(event->text()); + return bindings[keySeq]; +} + +void RegisterKeyBinding(const QKeySequence keySeq, const HID::PAD pad) +{ + bindings[keySeq] = pad; + reverseBindings[pad] = keySeq; +} + +void createNameMap() { + for (int i = 0; i < HID::numPadItems; i++){ + names[(HID::PAD)(1 << i)] = QString(HID::PAD_NAMES[i]); + reverseNames[QString(HID::PAD_NAMES[i])] = (HID::PAD)(1 << i); + } + +} + +void setDefaultKeyBindings() { + RegisterKeyBinding(QKeySequence("Y"), HID::PAD::PAD_A); + RegisterKeyBinding(QKeySequence("H"), HID::PAD::PAD_B); + RegisterKeyBinding(QKeySequence("Z"), HID::PAD::PAD_SELECT); + RegisterKeyBinding(QKeySequence("X"), HID::PAD::PAD_START); + + RegisterKeyBinding(QKeySequence("W"), HID::PAD::PAD_UP); + RegisterKeyBinding(QKeySequence("A"), HID::PAD::PAD_LEFT); + RegisterKeyBinding(QKeySequence("S"), HID::PAD::PAD_DOWN); + RegisterKeyBinding(QKeySequence("D"), HID::PAD::PAD_RIGHT); + + RegisterKeyBinding(QKeySequence("6"), HID::PAD::PAD_R); + RegisterKeyBinding(QKeySequence("7"), HID::PAD::PAD_L); + RegisterKeyBinding(QKeySequence("U"), HID::PAD::PAD_X); + RegisterKeyBinding(QKeySequence("J"), HID::PAD::PAD_Y); + +} + +//class makes single columns uneditable +class NoEditDelegate : public QStyledItemDelegate { +public: + NoEditDelegate(QObject* parent = 0) : QStyledItemDelegate(parent) {} + virtual QWidget* createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const { + return 0; + } +}; + +void GKeyBindingsDialog::updateItem(QTreeWidgetItem * item, int column) { + bindings[item->text(1)] = reverseNames[item->text(0)]; //TODO: sanitise + reverseBindings[reverseNames[item->text(0)]] = item->text(1); + return; +} + +GKeyBindingsDialog::GKeyBindingsDialog(QWidget* parent) : QDialog(parent) +{ + ui.setupUi(this); + + createNameMap(); + + for (NameMap::iterator key = names.begin(); key != names.end(); ++key) + { + QKeySequence keySeq = reverseBindings[key->first]; + QStringList columns; + columns << key->second << keySeq.toString(); + QTreeWidgetItem* item = new QTreeWidgetItem(columns); + item->setFlags(Qt::ItemIsEnabled | Qt::ItemIsEditable | Qt::ItemIsSelectable); + ui.treeWidget->addTopLevelItem(item); + + } + // TODO: Make context configurable as well (hiding the column for now) + + ui.treeWidget->setEditTriggers( + QAbstractItemView::EditKeyPressed + | QAbstractItemView::SelectedClicked + | QAbstractItemView::AnyKeyPressed + ); + connect( + this, SIGNAL(itemDoubleClicked(QTreeWidgetItem*, int)), + this, SLOT(OnMouseDoubleClicked(QTreeWidgetItem*, int)) + ); + ui.treeWidget->setColumnCount(2); + + ui.treeWidget->resizeColumnToContents(0); + ui.treeWidget->resizeColumnToContents(1); + + connect(ui.treeWidget, SIGNAL(itemChanged(QTreeWidgetItem *, int)), + this, SLOT(updateItem(QTreeWidgetItem *, int))); + ui.treeWidget->setItemDelegateForColumn(0, new NoEditDelegate(this)); + +} diff --git a/src/citra_qt/key_bindings.hxx b/src/citra_qt/key_bindings.hxx new file mode 100644 index 000000000..690934a47 --- /dev/null +++ b/src/citra_qt/key_bindings.hxx @@ -0,0 +1,62 @@ +#include +#include "ui_key_bindings.h" +#include "core/hw/hid.h" + + + +class QSettings; + +/** + * Register a hotkey. + * + * @param key Keyboard button + * @param pad Name of the pad + */ + +void RegisterKeyBinding(const QKeySequence keySeq, const HID::PAD pad); + + +/** + * Saves all key bindings to the settings file. + * + * + */ +void SaveKeyBindings(QSettings& settings); + + +/** +* Get PAD associated with key event +* +* +*/ +HID::PAD GetKeyBinding(QKeyEvent * event); + +/** + * Loads key bindings from the settings file. + * + * + */ +void LoadKeyBindings(QSettings& settings); + + +/** +* Sets default key bindings. +* +* +*/ +void setDefaultKeyBindings(); + + +class GKeyBindingsDialog : public QDialog +{ + Q_OBJECT + +public: + GKeyBindingsDialog(QWidget* parent = NULL); + +private: + Ui::key_bindings ui; + +private slots: + void updateItem(QTreeWidgetItem * item, int column); +}; diff --git a/src/citra_qt/key_bindings.ui b/src/citra_qt/key_bindings.ui new file mode 100644 index 000000000..0b97ec7d7 --- /dev/null +++ b/src/citra_qt/key_bindings.ui @@ -0,0 +1,89 @@ + + + key_bindings + + + + 0 + 0 + 363 + 388 + + + + Key Bindings + + + + + + QAbstractItemView::SelectItems + + + false + + + + Action + + + + + Key + + + + + Pad + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok|QDialogButtonBox::Reset + + + + + + + + + buttonBox + accepted() + key_bindings + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + key_bindings + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/src/citra_qt/main.cpp b/src/citra_qt/main.cpp index 087716c01..3b055f037 100644 --- a/src/citra_qt/main.cpp +++ b/src/citra_qt/main.cpp @@ -13,6 +13,7 @@ #include "bootmanager.hxx" #include "hotkeys.hxx" +#include "key_bindings.hxx" //debugger #include "debugger/disassembler.hxx" @@ -92,7 +93,8 @@ GMainWindow::GMainWindow() connect(ui.action_Pause, SIGNAL(triggered()), this, SLOT(OnPauseGame())); connect(ui.action_Stop, SIGNAL(triggered()), this, SLOT(OnStopGame())); connect(ui.action_Popout_Window_Mode, SIGNAL(triggered(bool)), this, SLOT(ToggleWindowMode())); - connect(ui.action_Hotkeys, SIGNAL(triggered()), this, SLOT(OnOpenHotkeysDialog())); + connect(ui.action_Hotkeys, SIGNAL(triggered()), this, SLOT(OnOpenHotkeysDialog()));\ + connect(ui.action_Key_Bindings, SIGNAL(triggered()), this, SLOT(OnOpenKeyBindingsDialog())); // BlockingQueuedConnection is important here, it makes sure we've finished refreshing our views before the CPU continues connect(&render_window->GetEmuThread(), SIGNAL(CPUStepped()), disasmWidget, SLOT(OnCPUStepped()), Qt::BlockingQueuedConnection); @@ -107,6 +109,11 @@ GMainWindow::GMainWindow() connect(GetHotkey("Main Window", "Load File", this), SIGNAL(activated()), this, SLOT(OnMenuLoadFile())); connect(GetHotkey("Main Window", "Start Emulation", this), SIGNAL(activated()), this, SLOT(OnStartGame())); + // Setup key bindings + setDefaultKeyBindings(); + LoadKeyBindings(settings); + + setWindowTitle(render_window->GetWindowTitle().c_str()); show(); @@ -199,6 +206,13 @@ void GMainWindow::OnOpenHotkeysDialog() } +void GMainWindow::OnOpenKeyBindingsDialog() +{ + GKeyBindingsDialog dialog(this); + dialog.exec(); +} + + void GMainWindow::ToggleWindowMode() { bool enable = ui.action_Popout_Window_Mode->isChecked(); diff --git a/src/citra_qt/main.hxx b/src/citra_qt/main.hxx index 6bcb37a30..c392bba2c 100644 --- a/src/citra_qt/main.hxx +++ b/src/citra_qt/main.hxx @@ -41,6 +41,7 @@ private slots: void OnMenuLoadFile(); void OnMenuLoadSymbolMap(); void OnOpenHotkeysDialog(); + void OnOpenKeyBindingsDialog(); void OnConfigure(); void ToggleWindowMode(); diff --git a/src/citra_qt/main.ui b/src/citra_qt/main.ui index f3596716f..dabcd3505 100644 --- a/src/citra_qt/main.ui +++ b/src/citra_qt/main.ui @@ -53,6 +53,7 @@ + @@ -127,6 +128,11 @@ Configure &Hotkeys ... + + + Set Key Bindings + + Configure ... diff --git a/src/citra_qt/ui_key_bindings.h b/src/citra_qt/ui_key_bindings.h new file mode 100644 index 000000000..7e1a88946 --- /dev/null +++ b/src/citra_qt/ui_key_bindings.h @@ -0,0 +1,77 @@ +/******************************************************************************** +** Form generated from reading UI file 'key_bindings.ui' +** +** Created by: Qt User Interface Compiler version 4.8.6 +** +** WARNING! All changes made in this file will be lost when recompiling UI file! +********************************************************************************/ + +#ifndef UI_KEY_BINDINGS_H +#define UI_KEY_BINDINGS_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +class Ui_key_bindings +{ +public: + QVBoxLayout *verticalLayout; + QTreeWidget *treeWidget; + QDialogButtonBox *buttonBox; + + void setupUi(QDialog *key_bindings) + { + if (key_bindings->objectName().isEmpty()) + key_bindings->setObjectName(QString::fromUtf8("key_bindings")); + key_bindings->resize(363, 388); + verticalLayout = new QVBoxLayout(key_bindings); + verticalLayout->setObjectName(QString::fromUtf8("verticalLayout")); + treeWidget = new QTreeWidget(key_bindings); + treeWidget->setObjectName(QString::fromUtf8("treeWidget")); + treeWidget->setSelectionBehavior(QAbstractItemView::SelectItems); + treeWidget->setHeaderHidden(false); + + verticalLayout->addWidget(treeWidget); + + buttonBox = new QDialogButtonBox(key_bindings); + buttonBox->setObjectName(QString::fromUtf8("buttonBox")); + buttonBox->setOrientation(Qt::Horizontal); + buttonBox->setStandardButtons(QDialogButtonBox::Cancel|QDialogButtonBox::Ok|QDialogButtonBox::Reset); + + verticalLayout->addWidget(buttonBox); + + + retranslateUi(key_bindings); + QObject::connect(buttonBox, SIGNAL(accepted()), key_bindings, SLOT(accept())); + QObject::connect(buttonBox, SIGNAL(rejected()), key_bindings, SLOT(reject())); + + QMetaObject::connectSlotsByName(key_bindings); + } // setupUi + + void retranslateUi(QDialog *key_bindings) + { + key_bindings->setWindowTitle(QApplication::translate("key_bindings", "Key Bindings", 0, QApplication::UnicodeUTF8)); + QTreeWidgetItem *___qtreewidgetitem = treeWidget->headerItem(); + ___qtreewidgetitem->setText(2, QApplication::translate("key_bindings", "Pad", 0, QApplication::UnicodeUTF8)); + ___qtreewidgetitem->setText(1, QApplication::translate("key_bindings", "Key", 0, QApplication::UnicodeUTF8)); + ___qtreewidgetitem->setText(0, QApplication::translate("key_bindings", "Action", 0, QApplication::UnicodeUTF8)); + } // retranslateUi + +}; + +namespace Ui { + class key_bindings: public Ui_key_bindings {}; +} // namespace Ui + +QT_END_NAMESPACE + +#endif // UI_KEY_BINDINGS_H diff --git a/src/common/common.vcxproj.filters b/src/common/common.vcxproj.filters index e8c4ce360..f1a5a3b51 100644 --- a/src/common/common.vcxproj.filters +++ b/src/common/common.vcxproj.filters @@ -30,18 +30,18 @@ + + + - - - @@ -56,14 +56,18 @@ + + - - - + + + + + \ No newline at end of file diff --git a/src/common/log.h b/src/common/log.h index d0da68aad..71becd893 100644 --- a/src/common/log.h +++ b/src/common/log.h @@ -64,6 +64,7 @@ enum LOG_TYPE { HW, TIME, NETPLAY, + HID, NUMBER_OF_LOGS // Must be last }; diff --git a/src/common/log_manager.cpp b/src/common/log_manager.cpp index b4a761c75..734e25728 100644 --- a/src/common/log_manager.cpp +++ b/src/common/log_manager.cpp @@ -73,6 +73,7 @@ LogManager::LogManager() m_Log[LogTypes::ACTIONREPLAY] = new LogContainer("ActionReplay", "ActionReplay"); m_Log[LogTypes::MEMCARD_MANAGER] = new LogContainer("MemCard Manager", "MemCard Manager"); m_Log[LogTypes::NETPLAY] = new LogContainer("NETPLAY", "Netplay"); + m_Log[LogTypes::HID] = new LogContainer("HID", "Human Interface Devices"); m_fileLog = new FileLogListener(File::GetUserPath(F_MAINLOG_IDX).c_str()); m_consoleLog = new ConsoleListener(); diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 1c1a2eeb3..8a4975dd0 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -36,6 +36,7 @@ set(SRCS core.cpp hle/svc.cpp hle/kernel/kernel.cpp hle/kernel/mutex.cpp + hle/kernel/shared_memory.cpp hle/kernel/thread.cpp hle/service/apt.cpp hle/service/gsp.cpp @@ -44,7 +45,8 @@ set(SRCS core.cpp hle/service/srv.cpp hw/gpu.cpp hw/hw.cpp - hw/ndma.cpp) + hw/ndma.cpp + hw/hid.cpp) set(HEADERS core.h core_timing.h @@ -81,6 +83,7 @@ set(HEADERS core.h hle/svc.h hle/kernel/kernel.h hle/kernel/mutex.h + hle/kernel/shared_memory.h hle/kernel/thread.h hle/function_wrappers.h hle/service/apt.h @@ -90,6 +93,7 @@ set(HEADERS core.h hle/service/srv.h hw/gpu.h hw/hw.h - hw/ndma.h) + hw/ndma.h + hw/hid.h) add_library(core STATIC ${SRCS} ${HEADERS}) diff --git a/src/core/core.vcxproj b/src/core/core.vcxproj index 8a3ad83ea..2c4e48032 100644 --- a/src/core/core.vcxproj +++ b/src/core/core.vcxproj @@ -99,6 +99,9 @@ true + + $(IntDir)%(RelativeDir) + @@ -106,6 +109,9 @@ true + + $(IntDir)%(RelativeDir) + @@ -120,6 +126,7 @@ Fast false StreamingSIMDExtensions2 + $(IntDir)%(RelativeDir) @@ -130,6 +137,9 @@ true + + $(IntDir)%(RelativeDir) + @@ -170,6 +180,7 @@ + @@ -178,6 +189,7 @@ + @@ -219,6 +231,7 @@ + @@ -227,6 +240,7 @@ + @@ -239,4 +253,4 @@ - + \ No newline at end of file diff --git a/src/core/core.vcxproj.filters b/src/core/core.vcxproj.filters index f7b342f98..63cfc5194 100644 --- a/src/core/core.vcxproj.filters +++ b/src/core/core.vcxproj.filters @@ -165,6 +165,12 @@ arm\interpreter + + hw + + + hle\kernel + @@ -295,8 +301,14 @@ hle\kernel + + hw + + + hle\kernel + - + \ No newline at end of file diff --git a/src/core/hle/kernel/shared_memory.cpp b/src/core/hle/kernel/shared_memory.cpp new file mode 100644 index 000000000..66594f0fc --- /dev/null +++ b/src/core/hle/kernel/shared_memory.cpp @@ -0,0 +1,98 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#include +#include + +#include "common/common.h" + +#include "core/hle/kernel/kernel.h" +#include "core/hle/kernel/thread.h" + +namespace Kernel { + +class SharedMemory : public Object { +public: + const char* GetTypeName() { return "SharedMemory"; } + + static Kernel::HandleType GetStaticHandleType() { return Kernel::HandleType::SharedMemory; } + Kernel::HandleType GetHandleType() const { return Kernel::HandleType::SharedMemory; } + + //TODO: implement + /** + * Wait for kernel object to synchronize + * @param wait Boolean wait set if current thread should wait as a result of sync operation + * @return Result of operation, 0 on success, otherwise error code + */ + Result WaitSynchronization(bool* wait) { + // TODO(bravia): ImplementMe + return 0; + } + + template + inline void Read(T &var, const u32 addr); + + template + inline void Write(T &var, const u32 addr); + + u32 size; + u8* mem_ptr = NULL; +}; + +//////////////////////////////////////////////////////////////////////////////////////////////////// + + + +SharedMemory* CreateSharedMemory(Handle& handle, u32 size) { + SharedMemory* mem = new SharedMemory; + handle = Kernel::g_object_pool.Create(mem); + mem->size = size; + return mem; +} + +Handle CreateSharedMemory(u32 size) { + Handle handle; + SharedMemory* mem = CreateSharedMemory(handle, size); + return handle; +} + +u32 GetSharedMemorySize(Handle handle) { + SharedMemory* mem = Kernel::g_object_pool.GetFast(handle); + _assert_msg_(KERNEL, (mem != nullptr), "called, but mem is nullptr!"); + return mem->size; +} + +void SetSharedMemoryPointer(Handle handle, u8* ptr) { + SharedMemory* mem = Kernel::g_object_pool.GetFast(handle); + _assert_msg_(KERNEL, (mem != nullptr), "called, but mem is nullptr!"); + mem->mem_ptr = ptr; +} + +template +inline void ReadSharedMemory(Handle handle, T &var, const u32 addr) { + SharedMemory* mem = Kernel::g_object_pool.GetFast(handle); + _assert_msg_(KERNEL, (mem != nullptr), "called, but mem is nullptr!"); + if (mem->mem_ptr!=NULL) + var = *((const T*)&mem->mem_ptr[addr & (mem->size - 1)]); +} + +template +inline void WriteSharedMemory(Handle handle, const T data, const u32 addr) { + SharedMemory* mem = Kernel::g_object_pool.GetFast(handle); + _assert_msg_(KERNEL, (mem != nullptr), "called, but mem is nullptr!"); + if (mem->mem_ptr != NULL) + *(T*)&mem->mem_ptr[addr & (mem->size - 1)] = data; +} + +template void WriteSharedMemory(Handle handle, const u64 data, const u32 addr); +template void WriteSharedMemory(Handle handle, const u32 data, const u32 addr); +template void WriteSharedMemory(Handle handle, const u16 data, const u32 addr); +template void WriteSharedMemory(Handle handle, const u8 data, const u32 addr); + +template void ReadSharedMemory(Handle handle, u64 &var, const u32 addr); +template void ReadSharedMemory(Handle handle, u32 &var, const u32 addr); +template void ReadSharedMemory(Handle handle, u16 &var, const u32 addr); +template void ReadSharedMemory(Handle handle, u8 &var, const u32 addr); + +} // namespace diff --git a/src/core/hle/kernel/shared_memory.h b/src/core/hle/kernel/shared_memory.h new file mode 100644 index 000000000..85a39a337 --- /dev/null +++ b/src/core/hle/kernel/shared_memory.h @@ -0,0 +1,30 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#pragma once + +#include "common/common_types.h" + +#include "core/hle/kernel/kernel.h" + +namespace Kernel { + +/** +* Creates a shared memory object +* @param handle Reference to handle for the newly created mutex +* @param +*/ +Handle CreateSharedMemory(u32 size); + +u32 GetSharedMemorySize(Handle handle); + +void SetSharedMemoryPointer(Handle handle, u8* ptr); + +template +inline void ReadSharedMemory(Handle handle, T &var, const u32 addr); + +template +inline void WriteSharedMemory(Handle handle, const T data, const u32 addr); + +} // namespace diff --git a/src/core/hle/service/gsp.cpp b/src/core/hle/service/gsp.cpp index aabcb48db..79a81d3bc 100644 --- a/src/core/hle/service/gsp.cpp +++ b/src/core/hle/service/gsp.cpp @@ -8,6 +8,7 @@ #include "core/mem_map.h" #include "core/hle/hle.h" +#include "core/hle/kernel/shared_memory.h" #include "core/hle/service/gsp.h" #include "core/hw/gpu.h" @@ -19,6 +20,10 @@ // Main graphics debugger object - TODO: Here is probably not the best place for this GraphicsDebugger g_debugger; +//Handle to irq memory +Handle memIRQ; + + /// GSP shared memory GX command buffer header union GX_CmdBufferHeader { u32 hex; @@ -107,6 +112,8 @@ void RegisterInterruptRelayQueue(Service::Interface* self) { u32 event_handle = cmd_buff[3]; // TODO(bunnei): Implement event handling cmd_buff[2] = g_thread_id; // ThreadID + memIRQ = Kernel::CreateSharedMemory(0x1000); //page size for now + cmd_buff[4] = memIRQ; } diff --git a/src/core/hle/service/hid.cpp b/src/core/hle/service/hid.cpp index 5542e5bf2..a92a9aa0a 100644 --- a/src/core/hle/service/hid.cpp +++ b/src/core/hle/service/hid.cpp @@ -6,18 +6,31 @@ #include "core/hle/hle.h" #include "core/hle/service/hid.h" +#include "core/hle/kernel/shared_memory.h" //////////////////////////////////////////////////////////////////////////////////////////////////// // Namespace HID_User namespace HID_User { +Handle g_mem_ipc = NULL; + +Handle GetMemIPCHandle() { + return g_mem_ipc; +} + +void GetIPCHandles(Service::Interface* self) { + u32* cmd_buff = Service::GetCommandBuffer(); + g_mem_ipc = Kernel::CreateSharedMemory(0x1000); //page size for now + cmd_buff[3] = g_mem_ipc; +} + const Interface::FunctionInfo FunctionTable[] = { - {0x000A0000, NULL, "GetIPCHandles"}, - {0x00110000, NULL, "EnableAccelerometer"}, - {0x00130000, NULL, "EnableGyroscopeLow"}, - {0x00150000, NULL, "GetGyroscopeLowRawToDpsCoefficient"}, - {0x00160000, NULL, "GetGyroscopeLowCalibrateParam"}, + {0x000A0000, GetIPCHandles, "GetIPCHandles" }, + {0x00110000, nullptr, "EnableAccelerometer"}, + {0x00130000, nullptr, "EnableGyroscopeLow"}, + {0x00150000, nullptr, "GetGyroscopeLowRawToDpsCoefficient"}, + {0x00160000, nullptr, "GetGyroscopeLowCalibrateParam"}, }; //////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/src/core/hle/service/hid.h b/src/core/hle/service/hid.h index 81c29eb2e..ad7919605 100644 --- a/src/core/hle/service/hid.h +++ b/src/core/hle/service/hid.h @@ -14,6 +14,8 @@ namespace HID_User { +Handle GetMemIPCHandle(); + class Interface : public Service::Interface { public: diff --git a/src/core/hw/hid.cpp b/src/core/hw/hid.cpp new file mode 100644 index 000000000..a8aff1aa7 --- /dev/null +++ b/src/core/hw/hid.cpp @@ -0,0 +1,28 @@ +#include "hid.h" +#include "core/hle/service/hid.h" +#include "core/hle/kernel/shared_memory.h" + + +namespace HID { + +void SetButtonReg(u32 buttonData) { + Handle sharedMem = HID_User::GetMemIPCHandle(); + if (sharedMem != NULL) + Kernel::WriteSharedMemory(sharedMem, buttonData, OFFSET_BUTTONS); +} + +/// Update hardware +void Update() { +} + +/// Initialize hardware +void Init() { + NOTICE_LOG(HID, "initialized OK"); +} + +/// Shutdown hardware +void Shutdown() { + NOTICE_LOG(HID, "shutdown OK"); +} + +} \ No newline at end of file diff --git a/src/core/hw/hid.h b/src/core/hw/hid.h new file mode 100644 index 000000000..ab64e1284 --- /dev/null +++ b/src/core/hw/hid.h @@ -0,0 +1,67 @@ +#pragma once + +#include "common/common_types.h" +#include "core/mem_map.h" + + +namespace HID { +struct Registers { + u32 buttons; + //u32 pad1; etc... +}; + +extern Registers g_regs; + +enum { + OFFSET_BUTTONS = 0x1c, //TODO: it works using the shared mem mapping with all homebrew tested, however the wiki states 0x10146000 as the paddr +}; + + +enum { + REG_BUTTONS = 0x1EC46000 //does not work due to confusion between shared mem and hardware IO +}; + +const int numPadItems = 12; // figure out a better way :( + +enum PAD { + PAD_A = (1 << 0), + PAD_B = (1 << 1), + PAD_SELECT = (1 << 2), + PAD_START = (1 << 3), + PAD_RIGHT = (1 << 4), + PAD_LEFT = (1 << 5), + PAD_UP = (1 << 6), + PAD_DOWN = (1 << 7), + PAD_R = (1 << 8), + PAD_L = (1 << 9), + PAD_X = (1 << 10), + PAD_Y = (1 << 11), +}; + +char * const PAD_NAMES[] = { + "PAD_A", + "PAD_B", + "PAD_SELECT", + "PAD_START", + "PAD_RIGHT", + "PAD_LEFT", + "PAD_UP", + "PAD_DOWN", + "PAD_R", + "PAD_L", + "PAD_X", + "PAD_Y" +}; + +void SetButtonReg(u32 buttonData); + +/// Update hardware +void Update(); + +/// Initialize hardware +void Init(); + +/// Shutdown hardware +void Shutdown(); +} + diff --git a/src/core/hw/hw.cpp b/src/core/hw/hw.cpp index ed70486e6..bb3c7ae68 100644 --- a/src/core/hw/hw.cpp +++ b/src/core/hw/hw.cpp @@ -8,6 +8,8 @@ #include "core/hw/hw.h" #include "core/hw/gpu.h" #include "core/hw/ndma.h" +#include "core/hw/hid.h" + namespace HW { @@ -89,12 +91,14 @@ template void Write(u32 addr, const u8 data); void Update() { GPU::Update(); NDMA::Update(); + HID::Update(); } /// Initialize hardware void Init() { GPU::Init(); NDMA::Init(); + HID::Init(); NOTICE_LOG(HW, "initialized OK"); } diff --git a/src/core/mem_map_funcs.cpp b/src/core/mem_map_funcs.cpp index 86e9eaa20..c8ef8dbf6 100644 --- a/src/core/mem_map_funcs.cpp +++ b/src/core/mem_map_funcs.cpp @@ -9,6 +9,8 @@ #include "core/mem_map.h" #include "core/hw/hw.h" #include "hle/hle.h" +#include "hle/kernel/kernel.h" +#include "hle/kernel/shared_memory.h" #include "hle/config_mem.h" namespace Memory { @@ -71,8 +73,15 @@ inline void _Read(T &var, const u32 addr) { // Shared memory } else if ((vaddr >= SHARED_MEMORY_VADDR) && (vaddr < SHARED_MEMORY_VADDR_END)) { - var = *((const T*)&g_shared_mem[vaddr & SHARED_MEMORY_MASK]); - + for (std::map::iterator it = g_shared_map.begin(); it != g_shared_map.end(); it++) { + MemoryBlock block = it->second; + if ((vaddr >= block.base_address) && (vaddr < block.GetVirtualAddress())) { + Handle handle = block.handle; + Kernel::ReadSharedMemory(handle, var, addr); + return; + } + } + ERROR_LOG(MEMMAP, "Read from unknown shared mapping : Read%d @ 0x%08X", sizeof(var) * 8, vaddr); // System memory } else if ((vaddr >= SYSTEM_MEMORY_VADDR) && (vaddr < SYSTEM_MEMORY_VADDR_END)) { var = *((const T*)&g_system_mem[vaddr & SYSTEM_MEMORY_MASK]); @@ -86,7 +95,7 @@ inline void _Read(T &var, const u32 addr) { var = *((const T*)&g_vram[vaddr & VRAM_MASK]); } else { - //_assert_msg_(MEMMAP, false, "unknown Read%d @ 0x%08X", sizeof(var) * 8, vaddr); + ERROR_LOG(MEMMAP, "unknown Read%d @ 0x%08X", sizeof(var) * 8, vaddr); } } @@ -117,7 +126,15 @@ inline void _Write(u32 addr, const T data) { // Shared memory } else if ((vaddr >= SHARED_MEMORY_VADDR) && (vaddr < SHARED_MEMORY_VADDR_END)) { - *(T*)&g_shared_mem[vaddr & SHARED_MEMORY_MASK] = data; + for (std::map::iterator it = g_shared_map.begin(); it != g_shared_map.end(); it++) { + MemoryBlock block = it->second; + if ((vaddr >= block.base_address) && (vaddr < block.base_address + block.size)) { + Handle handle = block.handle; + Kernel::WriteSharedMemory(handle, data, addr); + return; + } + } + ERROR_LOG(MEMMAP, "Write to unknown shared mapping : Write%d 0x%08X @ 0x%08X", sizeof(data) * 8, data, vaddr); // System memory } else if ((vaddr >= SYSTEM_MEMORY_VADDR) && (vaddr < SYSTEM_MEMORY_VADDR_END)) { @@ -136,8 +153,7 @@ inline void _Write(u32 addr, const T data) { // Error out... } else { - _assert_msg_(MEMMAP, false, "unknown Write%d 0x%08X @ 0x%08X", sizeof(data) * 8, - data, vaddr); + ERROR_LOG(MEMMAP, "unknown Write%d 0x%08X @ 0x%08X", sizeof(data) * 8, data, vaddr); } } @@ -186,8 +202,9 @@ u8 *GetPointer(const u32 addr) { */ u32 MapBlock_Shared(u32 handle, u32 addr,u32 permissions) { MemoryBlock block; - + block.handle = handle; + block.size = Kernel::GetSharedMemorySize(handle); block.base_address = addr; block.permissions = permissions; @@ -195,9 +212,14 @@ u32 MapBlock_Shared(u32 handle, u32 addr,u32 permissions) { const MemoryBlock last_block = g_shared_map.rbegin()->second; block.address = last_block.address + last_block.size; } - g_shared_map[block.GetVirtualAddress()] = block; - return block.GetVirtualAddress(); + u32 vaddr = block.GetVirtualAddress(); + + g_shared_map[vaddr] = block; + + Kernel::SetSharedMemoryPointer(handle, &g_shared_mem[vaddr & SHARED_MEMORY_MASK]); + + return vaddr; } /**