Merge pull request #160 from Gareth422/working
Renamed souce files of services to match port names
This commit is contained in:
commit
0fc71cb6a7
15 changed files with 23 additions and 23 deletions
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "core/hle/service/hid.h"
|
||||
#include "core/hle/service/hid_user.h"
|
||||
|
||||
namespace KeyMap {
|
||||
|
||||
|
|
|
|||
|
|
@ -30,11 +30,11 @@ set(SRCS
|
|||
hle/kernel/mutex.cpp
|
||||
hle/kernel/shared_memory.cpp
|
||||
hle/kernel/thread.cpp
|
||||
hle/service/apt.cpp
|
||||
hle/service/fs.cpp
|
||||
hle/service/gsp.cpp
|
||||
hle/service/hid.cpp
|
||||
hle/service/ndm.cpp
|
||||
hle/service/apt_u.cpp
|
||||
hle/service/fs_user.cpp
|
||||
hle/service/gsp_gpu.cpp
|
||||
hle/service/hid_user.cpp
|
||||
hle/service/ndm_u.cpp
|
||||
hle/service/service.cpp
|
||||
hle/service/srv.cpp
|
||||
hle/config_mem.cpp
|
||||
|
|
@ -91,11 +91,11 @@ set(HEADERS
|
|||
hle/kernel/mutex.h
|
||||
hle/kernel/shared_memory.h
|
||||
hle/kernel/thread.h
|
||||
hle/service/apt.h
|
||||
hle/service/fs.h
|
||||
hle/service/gsp.h
|
||||
hle/service/hid.h
|
||||
hle/service/ndm.h
|
||||
hle/service/apt_u.h
|
||||
hle/service/fs_user.h
|
||||
hle/service/gsp_gpu.h
|
||||
hle/service/hid_user.h
|
||||
hle/service/ndm_u.h
|
||||
hle/service/service.h
|
||||
hle/service/srv.h
|
||||
hle/config_mem.h
|
||||
|
|
|
|||
199
src/core/hle/service/apt_u.cpp
Normal file
199
src/core/hle/service/apt_u.cpp
Normal file
|
|
@ -0,0 +1,199 @@
|
|||
// Copyright 2014 Citra Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
|
||||
#include "common/common.h"
|
||||
|
||||
#include "core/hle/hle.h"
|
||||
#include "core/hle/kernel/event.h"
|
||||
#include "core/hle/kernel/mutex.h"
|
||||
#include "apt_u.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Namespace APT_U
|
||||
|
||||
namespace APT_U {
|
||||
|
||||
/// Signals used by APT functions
|
||||
enum class SignalType : u32 {
|
||||
None = 0x0,
|
||||
AppJustStarted = 0x1,
|
||||
ReturningToApp = 0xB,
|
||||
ExitingApp = 0xC,
|
||||
};
|
||||
|
||||
void Initialize(Service::Interface* self) {
|
||||
u32* cmd_buff = Service::GetCommandBuffer();
|
||||
|
||||
cmd_buff[3] = Kernel::CreateEvent(RESETTYPE_ONESHOT, "APT_U:Menu"); // APT menu event handle
|
||||
cmd_buff[4] = Kernel::CreateEvent(RESETTYPE_ONESHOT, "APT_U:Pause"); // APT pause event handle
|
||||
|
||||
Kernel::SetEventLocked(cmd_buff[3], true);
|
||||
Kernel::SetEventLocked(cmd_buff[4], false); // Fire start event
|
||||
|
||||
cmd_buff[1] = 0; // No error
|
||||
DEBUG_LOG(KERNEL, "called");
|
||||
}
|
||||
|
||||
void GetLockHandle(Service::Interface* self) {
|
||||
u32* cmd_buff = Service::GetCommandBuffer();
|
||||
u32 flags = cmd_buff[1]; // TODO(bunnei): Figure out the purpose of the flag field
|
||||
cmd_buff[1] = 0; // No error
|
||||
cmd_buff[5] = Kernel::CreateMutex(false, "APT_U:Lock");
|
||||
DEBUG_LOG(KERNEL, "called handle=0x%08X", cmd_buff[5]);
|
||||
}
|
||||
|
||||
void Enable(Service::Interface* self) {
|
||||
u32* cmd_buff = Service::GetCommandBuffer();
|
||||
u32 unk = cmd_buff[1]; // TODO(bunnei): What is this field used for?
|
||||
cmd_buff[1] = 0; // No error
|
||||
WARN_LOG(KERNEL, "(STUBBED) called unk=0x%08X", unk);
|
||||
}
|
||||
|
||||
void InquireNotification(Service::Interface* self) {
|
||||
u32* cmd_buff = Service::GetCommandBuffer();
|
||||
u32 app_id = cmd_buff[2];
|
||||
cmd_buff[1] = 0; // No error
|
||||
cmd_buff[2] = static_cast<u32>(SignalType::None); // Signal type
|
||||
WARN_LOG(KERNEL, "(STUBBED) called app_id=0x%08X", app_id);
|
||||
}
|
||||
|
||||
void ReceiveParameter(Service::Interface* self) {
|
||||
u32* cmd_buff = Service::GetCommandBuffer();
|
||||
u32 app_id = cmd_buff[1];
|
||||
u32 buffer_size = cmd_buff[2];
|
||||
cmd_buff[1] = 0; // No error
|
||||
cmd_buff[2] = 0;
|
||||
cmd_buff[3] = static_cast<u32>(SignalType::AppJustStarted); // Signal type
|
||||
cmd_buff[4] = 0x10;
|
||||
cmd_buff[5] = 0;
|
||||
cmd_buff[6] = 0;
|
||||
cmd_buff[7] = 0;
|
||||
WARN_LOG(KERNEL, "(STUBBED) called app_id=0x%08X, buffer_size=0x%08X", app_id, buffer_size);
|
||||
}
|
||||
|
||||
/**
|
||||
* APT_U::GlanceParameter service function
|
||||
* Inputs:
|
||||
* 1 : AppID
|
||||
* 2 : Parameter buffer size, max size is 0x1000
|
||||
* Outputs:
|
||||
* 1 : Result of function, 0 on success, otherwise error code
|
||||
* 2 : Unknown, for now assume AppID of the process which sent these parameters
|
||||
* 3 : Unknown, for now assume Signal type
|
||||
* 4 : Actual parameter buffer size, this is <= to the the input size
|
||||
* 5 : Value
|
||||
* 6 : Handle from the source process which set the parameters, likely used for shared memory
|
||||
* 7 : Size
|
||||
* 8 : Output parameter buffer ptr
|
||||
*/
|
||||
void GlanceParameter(Service::Interface* self) {
|
||||
u32* cmd_buff = Service::GetCommandBuffer();
|
||||
u32 app_id = cmd_buff[1];
|
||||
u32 buffer_size = cmd_buff[2];
|
||||
cmd_buff[1] = 0; // No error
|
||||
cmd_buff[2] = 0;
|
||||
cmd_buff[3] = static_cast<u32>(SignalType::AppJustStarted); // Signal type
|
||||
cmd_buff[4] = 0;
|
||||
cmd_buff[5] = 0;
|
||||
cmd_buff[6] = 0;
|
||||
cmd_buff[7] = 0;
|
||||
cmd_buff[8] = 0;
|
||||
WARN_LOG(KERNEL, "(STUBBED) called app_id=0x%08X, buffer_size=0x%08X", app_id, buffer_size);
|
||||
}
|
||||
|
||||
const Interface::FunctionInfo FunctionTable[] = {
|
||||
{0x00010040, GetLockHandle, "GetLockHandle"},
|
||||
{0x00020080, Initialize, "Initialize"},
|
||||
{0x00030040, Enable, "Enable"},
|
||||
{0x00040040, nullptr, "Finalize"},
|
||||
{0x00050040, nullptr, "GetAppletManInfo"},
|
||||
{0x00060040, nullptr, "GetAppletInfo"},
|
||||
{0x00070000, nullptr, "GetLastSignaledAppletId"},
|
||||
{0x00080000, nullptr, "CountRegisteredApplet"},
|
||||
{0x00090040, nullptr, "IsRegistered"},
|
||||
{0x000A0040, nullptr, "GetAttribute"},
|
||||
{0x000B0040, InquireNotification, "InquireNotification"},
|
||||
{0x000C0104, nullptr, "SendParameter"},
|
||||
{0x000D0080, ReceiveParameter, "ReceiveParameter"},
|
||||
{0x000E0080, GlanceParameter, "GlanceParameter"},
|
||||
{0x000F0100, nullptr, "CancelParameter"},
|
||||
{0x001000C2, nullptr, "DebugFunc"},
|
||||
{0x001100C0, nullptr, "MapProgramIdForDebug"},
|
||||
{0x00120040, nullptr, "SetHomeMenuAppletIdForDebug"},
|
||||
{0x00130000, nullptr, "GetPreparationState"},
|
||||
{0x00140040, nullptr, "SetPreparationState"},
|
||||
{0x00150140, nullptr, "PrepareToStartApplication"},
|
||||
{0x00160040, nullptr, "PreloadLibraryApplet"},
|
||||
{0x00170040, nullptr, "FinishPreloadingLibraryApplet"},
|
||||
{0x00180040, nullptr, "PrepareToStartLibraryApplet"},
|
||||
{0x00190040, nullptr, "PrepareToStartSystemApplet"},
|
||||
{0x001A0000, nullptr, "PrepareToStartNewestHomeMenu"},
|
||||
{0x001B00C4, nullptr, "StartApplication"},
|
||||
{0x001C0000, nullptr, "WakeupApplication"},
|
||||
{0x001D0000, nullptr, "CancelApplication"},
|
||||
{0x001E0084, nullptr, "StartLibraryApplet"},
|
||||
{0x001F0084, nullptr, "StartSystemApplet"},
|
||||
{0x00200044, nullptr, "StartNewestHomeMenu"},
|
||||
{0x00210000, nullptr, "OrderToCloseApplication"},
|
||||
{0x00220040, nullptr, "PrepareToCloseApplication"},
|
||||
{0x00230040, nullptr, "PrepareToJumpToApplication"},
|
||||
{0x00240044, nullptr, "JumpToApplication"},
|
||||
{0x002500C0, nullptr, "PrepareToCloseLibraryApplet"},
|
||||
{0x00260000, nullptr, "PrepareToCloseSystemApplet"},
|
||||
{0x00270044, nullptr, "CloseApplication"},
|
||||
{0x00280044, nullptr, "CloseLibraryApplet"},
|
||||
{0x00290044, nullptr, "CloseSystemApplet"},
|
||||
{0x002A0000, nullptr, "OrderToCloseSystemApplet"},
|
||||
{0x002B0000, nullptr, "PrepareToJumpToHomeMenu"},
|
||||
{0x002C0044, nullptr, "JumpToHomeMenu"},
|
||||
{0x002D0000, nullptr, "PrepareToLeaveHomeMenu"},
|
||||
{0x002E0044, nullptr, "LeaveHomeMenu"},
|
||||
{0x002F0040, nullptr, "PrepareToLeaveResidentApplet"},
|
||||
{0x00300044, nullptr, "LeaveResidentApplet"},
|
||||
{0x00310100, nullptr, "PrepareToDoApplicationJump"},
|
||||
{0x00320084, nullptr, "DoApplicationJump"},
|
||||
{0x00330000, nullptr, "GetProgramIdOnApplicationJump"},
|
||||
{0x00340084, nullptr, "SendDeliverArg"},
|
||||
{0x00350080, nullptr, "ReceiveDeliverArg"},
|
||||
{0x00360040, nullptr, "LoadSysMenuArg"},
|
||||
{0x00370042, nullptr, "StoreSysMenuArg"},
|
||||
{0x00380040, nullptr, "PreloadResidentApplet"},
|
||||
{0x00390040, nullptr, "PrepareToStartResidentApplet"},
|
||||
{0x003A0044, nullptr, "StartResidentApplet"},
|
||||
{0x003B0040, nullptr, "CancelLibraryApplet"},
|
||||
{0x003C0042, nullptr, "SendDspSleep"},
|
||||
{0x003D0042, nullptr, "SendDspWakeUp"},
|
||||
{0x003E0080, nullptr, "ReplySleepQuery"},
|
||||
{0x003F0040, nullptr, "ReplySleepNotificationComplete"},
|
||||
{0x00400042, nullptr, "SendCaptureBufferInfo"},
|
||||
{0x00410040, nullptr, "ReceiveCaptureBufferInfo"},
|
||||
{0x00420080, nullptr, "SleepSystem"},
|
||||
{0x00430040, nullptr, "NotifyToWait"},
|
||||
{0x00440000, nullptr, "GetSharedFont"},
|
||||
{0x00450040, nullptr, "GetWirelessRebootInfo"},
|
||||
{0x00460104, nullptr, "Wrap"},
|
||||
{0x00470104, nullptr, "Unwrap"},
|
||||
{0x00480100, nullptr, "GetProgramInfo"},
|
||||
{0x00490180, nullptr, "Reboot"},
|
||||
{0x004A0040, nullptr, "GetCaptureInfo"},
|
||||
{0x004B00C2, nullptr, "AppletUtility"},
|
||||
{0x004C0000, nullptr, "SetFatalErrDispMode"},
|
||||
{0x004D0080, nullptr, "GetAppletProgramInfo"},
|
||||
{0x004E0000, nullptr, "HardwareResetAsync"},
|
||||
{0x004F0080, nullptr, "SetApplicationCpuTimeLimit"},
|
||||
{0x00500040, nullptr, "GetApplicationCpuTimeLimit"},
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Interface class
|
||||
|
||||
Interface::Interface() {
|
||||
Register(FunctionTable, ARRAY_SIZE(FunctionTable));
|
||||
}
|
||||
|
||||
Interface::~Interface() {
|
||||
}
|
||||
|
||||
} // namespace
|
||||
37
src/core/hle/service/apt_u.h
Normal file
37
src/core/hle/service/apt_u.h
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
// Copyright 2014 Citra Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/hle/service/service.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Namespace APT_U
|
||||
|
||||
namespace APT_U {
|
||||
|
||||
// Application and title launching service. These services handle signaling for home/power button as
|
||||
// well. Only one session for either APT service can be open at a time, normally processes close the
|
||||
// service handle immediately once finished using the service. The commands for APT:U and APT:S are
|
||||
// exactly the same, however certain commands are only accessible with APT:S(NS module will call
|
||||
// svcBreak when the command isn't accessible). See http://3dbrew.org/wiki/NS#APT_Services.
|
||||
|
||||
/// Interface to "APT:U" service
|
||||
class Interface : public Service::Interface {
|
||||
public:
|
||||
|
||||
Interface();
|
||||
|
||||
~Interface();
|
||||
|
||||
/**
|
||||
* Gets the string port name used by CTROS for the service
|
||||
* @return Port name of service
|
||||
*/
|
||||
std::string GetPortName() const override {
|
||||
return "APT:U";
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace
|
||||
302
src/core/hle/service/fs_user.cpp
Normal file
302
src/core/hle/service/fs_user.cpp
Normal file
|
|
@ -0,0 +1,302 @@
|
|||
// Copyright 2014 Citra Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "common/common.h"
|
||||
|
||||
#include "fs_user.h"
|
||||
#include "core/hle/kernel/archive.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Namespace FS_User
|
||||
|
||||
namespace FS_User {
|
||||
|
||||
// Command to access archive file
|
||||
enum class LowPathType : u32 {
|
||||
Invalid = 0,
|
||||
Empty = 1,
|
||||
Binary = 2,
|
||||
Char = 3,
|
||||
Wchar = 4
|
||||
};
|
||||
|
||||
std::string GetStringFromCmdBuff(const u32 pointer, const u32 size) {
|
||||
auto data = reinterpret_cast<const char*>(Memory::GetPointer(pointer));
|
||||
return std::string(data, size - 1);
|
||||
}
|
||||
|
||||
// We currently return 0 for success and -1 for failure in cmd_buff[1]. -1 was chosen because it
|
||||
// puts all the sections of the http://3dbrew.org/wiki/Error_codes to something non-zero, to make
|
||||
// sure we don't mislead the application into thinking something worked.
|
||||
|
||||
void Initialize(Service::Interface* self) {
|
||||
u32* cmd_buff = Service::GetCommandBuffer();
|
||||
|
||||
// TODO(Link Mauve): check the behavior when cmd_buff[1] isn't 32, as per
|
||||
// http://3dbrew.org/wiki/FS:Initialize#Request
|
||||
cmd_buff[1] = 0;
|
||||
|
||||
DEBUG_LOG(KERNEL, "called");
|
||||
}
|
||||
|
||||
void OpenFile(Service::Interface* self) {
|
||||
u32* cmd_buff = Service::GetCommandBuffer();
|
||||
|
||||
u32 transaction = cmd_buff[1];
|
||||
// TODO(Link Mauve): cmd_buff[2], aka archive handle lower word, isn't used according to
|
||||
// 3dmoo's or ctrulib's implementations. Triple check if it's really the case.
|
||||
Handle archive_handle = static_cast<Handle>(cmd_buff[3]);
|
||||
LowPathType type = static_cast<LowPathType>(cmd_buff[4]);
|
||||
u32 size = cmd_buff[5];
|
||||
FileSys::Mode mode; mode.hex = cmd_buff[6];
|
||||
u32 attributes = cmd_buff[7]; // TODO(Link Mauve): do something with those attributes.
|
||||
u32 pointer = cmd_buff[9];
|
||||
|
||||
if (type != LowPathType::Char) {
|
||||
ERROR_LOG(KERNEL, "file LowPath type other than char is currently unsupported");
|
||||
cmd_buff[1] = -1;
|
||||
return;
|
||||
}
|
||||
|
||||
std::string file_name = GetStringFromCmdBuff(pointer, size);
|
||||
|
||||
DEBUG_LOG(KERNEL, "type=%d size=%d mode=%d attrs=%d data=%s", type, size, mode, attributes, file_name.c_str());
|
||||
|
||||
Handle handle = Kernel::OpenFileFromArchive(archive_handle, file_name, mode);
|
||||
if (handle) {
|
||||
cmd_buff[1] = 0;
|
||||
cmd_buff[3] = handle;
|
||||
} else {
|
||||
ERROR_LOG(KERNEL, "failed to get a handle for file %s", file_name.c_str());
|
||||
// TODO(Link Mauve): check for the actual error values, this one was just chosen arbitrarily.
|
||||
cmd_buff[1] = -1;
|
||||
}
|
||||
|
||||
DEBUG_LOG(KERNEL, "called");
|
||||
}
|
||||
|
||||
void OpenFileDirectly(Service::Interface* self) {
|
||||
u32* cmd_buff = Service::GetCommandBuffer();
|
||||
|
||||
u32 transaction = cmd_buff[1];
|
||||
auto archive_id = static_cast<FileSys::Archive::IdCode>(cmd_buff[2]);
|
||||
LowPathType archive_type = static_cast<LowPathType>(cmd_buff[3]);
|
||||
u32 archive_size = cmd_buff[4];
|
||||
LowPathType file_type = static_cast<LowPathType>(cmd_buff[5]);
|
||||
u32 size = cmd_buff[6];
|
||||
FileSys::Mode mode; mode.hex = cmd_buff[7];
|
||||
u32 attributes = cmd_buff[8]; // TODO(Link Mauve): do something with those attributes.
|
||||
u32 archive_pointer = cmd_buff[10];
|
||||
u32 pointer = cmd_buff[12];
|
||||
|
||||
if (archive_type != LowPathType::Empty) {
|
||||
ERROR_LOG(KERNEL, "archive LowPath type other than empty is currently unsupported");
|
||||
cmd_buff[1] = -1;
|
||||
return;
|
||||
}
|
||||
|
||||
std::string archive_name = GetStringFromCmdBuff(archive_pointer, archive_size);
|
||||
std::string file_name = GetStringFromCmdBuff(pointer, size);
|
||||
|
||||
DEBUG_LOG(KERNEL, "archive_type=%d archive_size=%d archive_data=%s"
|
||||
"file_type=%d file_size=%d file_mode=%d file_attrs=%d file_data=%s",
|
||||
archive_type, archive_size, archive_name.c_str(),
|
||||
file_type, size, mode, attributes, file_name.c_str());
|
||||
|
||||
// TODO(Link Mauve): check if we should even get a handle for the archive, and don't leak it.
|
||||
Handle archive_handle = Kernel::OpenArchive(archive_id);
|
||||
if (archive_handle) {
|
||||
cmd_buff[1] = 0;
|
||||
// cmd_buff[2] isn't used according to 3dmoo's implementation.
|
||||
cmd_buff[3] = archive_handle;
|
||||
} else {
|
||||
ERROR_LOG(KERNEL, "failed to get a handle for archive %s", archive_name.c_str());
|
||||
// TODO(Link Mauve): check for the actual error values, this one was just chosen arbitrarily.
|
||||
cmd_buff[1] = -1;
|
||||
return;
|
||||
}
|
||||
|
||||
if (file_type != LowPathType::Char) {
|
||||
WARN_LOG(KERNEL, "file LowPath type other than char is currently unsupported; returning archive handle instead");
|
||||
return;
|
||||
}
|
||||
|
||||
Handle handle = Kernel::OpenFileFromArchive(archive_handle, file_name, mode);
|
||||
if (handle) {
|
||||
cmd_buff[1] = 0;
|
||||
cmd_buff[3] = handle;
|
||||
} else {
|
||||
ERROR_LOG(KERNEL, "failed to get a handle for file %s", file_name.c_str());
|
||||
// TODO(Link Mauve): check for the actual error values, this one was just chosen arbitrarily.
|
||||
cmd_buff[1] = -1;
|
||||
}
|
||||
|
||||
DEBUG_LOG(KERNEL, "called");
|
||||
}
|
||||
|
||||
void OpenDirectory(Service::Interface* self) {
|
||||
u32* cmd_buff = Service::GetCommandBuffer();
|
||||
|
||||
// TODO(Link Mauve): cmd_buff[2], aka archive handle lower word, isn't used according to
|
||||
// 3dmoo's or ctrulib's implementations. Triple check if it's really the case.
|
||||
Handle archive_handle = static_cast<Handle>(cmd_buff[2]);
|
||||
LowPathType type = static_cast<LowPathType>(cmd_buff[3]);
|
||||
u32 size = cmd_buff[4];
|
||||
u32 pointer = cmd_buff[6];
|
||||
|
||||
if (type != LowPathType::Char) {
|
||||
ERROR_LOG(KERNEL, "directory LowPath type other than char is currently unsupported");
|
||||
cmd_buff[1] = -1;
|
||||
return;
|
||||
}
|
||||
|
||||
std::string dir_name = GetStringFromCmdBuff(pointer, size);
|
||||
|
||||
DEBUG_LOG(KERNEL, "type=%d size=%d data=%s", type, size, dir_name.c_str());
|
||||
|
||||
Handle handle = Kernel::OpenDirectoryFromArchive(archive_handle, dir_name);
|
||||
if (handle) {
|
||||
cmd_buff[1] = 0;
|
||||
cmd_buff[3] = handle;
|
||||
} else {
|
||||
ERROR_LOG(KERNEL, "failed to get a handle for directory %s", dir_name.c_str());
|
||||
// TODO(Link Mauve): check for the actual error values, this one was just chosen arbitrarily.
|
||||
cmd_buff[1] = -1;
|
||||
}
|
||||
|
||||
DEBUG_LOG(KERNEL, "called");
|
||||
}
|
||||
|
||||
void OpenArchive(Service::Interface* self) {
|
||||
u32* cmd_buff = Service::GetCommandBuffer();
|
||||
|
||||
auto arch_id = static_cast<FileSys::Archive::IdCode>(cmd_buff[1]);
|
||||
LowPathType type = static_cast<LowPathType>(cmd_buff[2]);
|
||||
u32 size = cmd_buff[3];
|
||||
u32 pointer = cmd_buff[5];
|
||||
|
||||
if (type != LowPathType::Empty) {
|
||||
ERROR_LOG(KERNEL, "archive LowPath type other than empty is currently unsupported");
|
||||
cmd_buff[1] = -1;
|
||||
return;
|
||||
}
|
||||
|
||||
std::string archive_name = GetStringFromCmdBuff(pointer, size);
|
||||
|
||||
DEBUG_LOG(KERNEL, "type=%d size=%d data=%s", type, size, archive_name.c_str());
|
||||
|
||||
Handle handle = Kernel::OpenArchive(arch_id);
|
||||
if (handle) {
|
||||
cmd_buff[1] = 0;
|
||||
// cmd_buff[2] isn't used according to 3dmoo's implementation.
|
||||
cmd_buff[3] = handle;
|
||||
} else {
|
||||
ERROR_LOG(KERNEL, "failed to get a handle for archive %s", archive_name.c_str());
|
||||
// TODO(Link Mauve): check for the actual error values, this one was just chosen arbitrarily.
|
||||
cmd_buff[1] = -1;
|
||||
}
|
||||
|
||||
DEBUG_LOG(KERNEL, "called");
|
||||
}
|
||||
|
||||
const Interface::FunctionInfo FunctionTable[] = {
|
||||
{0x000100C6, nullptr, "Dummy1"},
|
||||
{0x040100C4, nullptr, "Control"},
|
||||
{0x08010002, Initialize, "Initialize"},
|
||||
{0x080201C2, OpenFile, "OpenFile"},
|
||||
{0x08030204, OpenFileDirectly, "OpenFileDirectly"},
|
||||
{0x08040142, nullptr, "DeleteFile"},
|
||||
{0x08050244, nullptr, "RenameFile"},
|
||||
{0x08060142, nullptr, "DeleteDirectory"},
|
||||
{0x08070142, nullptr, "DeleteDirectoryRecursively"},
|
||||
{0x08080202, nullptr, "CreateFile"},
|
||||
{0x08090182, nullptr, "CreateDirectory"},
|
||||
{0x080A0244, nullptr, "RenameDirectory"},
|
||||
{0x080B0102, OpenDirectory, "OpenDirectory"},
|
||||
{0x080C00C2, OpenArchive, "OpenArchive"},
|
||||
{0x080D0144, nullptr, "ControlArchive"},
|
||||
{0x080E0080, nullptr, "CloseArchive"},
|
||||
{0x080F0180, nullptr, "FormatThisUserSaveData"},
|
||||
{0x08100200, nullptr, "CreateSystemSaveData"},
|
||||
{0x08110040, nullptr, "DeleteSystemSaveData"},
|
||||
{0x08120080, nullptr, "GetFreeBytes"},
|
||||
{0x08130000, nullptr, "GetCardType"},
|
||||
{0x08140000, nullptr, "GetSdmcArchiveResource"},
|
||||
{0x08150000, nullptr, "GetNandArchiveResource"},
|
||||
{0x08160000, nullptr, "GetSdmcFatfsErro"},
|
||||
{0x08170000, nullptr, "IsSdmcDetected"},
|
||||
{0x08180000, nullptr, "IsSdmcWritable"},
|
||||
{0x08190042, nullptr, "GetSdmcCid"},
|
||||
{0x081A0042, nullptr, "GetNandCid"},
|
||||
{0x081B0000, nullptr, "GetSdmcSpeedInfo"},
|
||||
{0x081C0000, nullptr, "GetNandSpeedInfo"},
|
||||
{0x081D0042, nullptr, "GetSdmcLog"},
|
||||
{0x081E0042, nullptr, "GetNandLog"},
|
||||
{0x081F0000, nullptr, "ClearSdmcLog"},
|
||||
{0x08200000, nullptr, "ClearNandLog"},
|
||||
{0x08210000, nullptr, "CardSlotIsInserted"},
|
||||
{0x08220000, nullptr, "CardSlotPowerOn"},
|
||||
{0x08230000, nullptr, "CardSlotPowerOff"},
|
||||
{0x08240000, nullptr, "CardSlotGetCardIFPowerStatus"},
|
||||
{0x08250040, nullptr, "CardNorDirectCommand"},
|
||||
{0x08260080, nullptr, "CardNorDirectCommandWithAddress"},
|
||||
{0x08270082, nullptr, "CardNorDirectRead"},
|
||||
{0x082800C2, nullptr, "CardNorDirectReadWithAddress"},
|
||||
{0x08290082, nullptr, "CardNorDirectWrite"},
|
||||
{0x082A00C2, nullptr, "CardNorDirectWriteWithAddress"},
|
||||
{0x082B00C2, nullptr, "CardNorDirectRead_4xIO"},
|
||||
{0x082C0082, nullptr, "CardNorDirectCpuWriteWithoutVerify"},
|
||||
{0x082D0040, nullptr, "CardNorDirectSectorEraseWithoutVerify"},
|
||||
{0x082E0040, nullptr, "GetProductInfo"},
|
||||
{0x082F0040, nullptr, "GetProgramLaunchInfo"},
|
||||
{0x08300182, nullptr, "CreateExtSaveData"},
|
||||
{0x08310180, nullptr, "CreateSharedExtSaveData"},
|
||||
{0x08320102, nullptr, "ReadExtSaveDataIcon"},
|
||||
{0x08330082, nullptr, "EnumerateExtSaveData"},
|
||||
{0x08340082, nullptr, "EnumerateSharedExtSaveData"},
|
||||
{0x08350080, nullptr, "DeleteExtSaveData"},
|
||||
{0x08360080, nullptr, "DeleteSharedExtSaveData"},
|
||||
{0x08370040, nullptr, "SetCardSpiBaudRate"},
|
||||
{0x08380040, nullptr, "SetCardSpiBusMode"},
|
||||
{0x08390000, nullptr, "SendInitializeInfoTo9"},
|
||||
{0x083A0100, nullptr, "GetSpecialContentIndex"},
|
||||
{0x083B00C2, nullptr, "GetLegacyRomHeader"},
|
||||
{0x083C00C2, nullptr, "GetLegacyBannerData"},
|
||||
{0x083D0100, nullptr, "CheckAuthorityToAccessExtSaveData"},
|
||||
{0x083E00C2, nullptr, "QueryTotalQuotaSize"},
|
||||
{0x083F00C0, nullptr, "GetExtDataBlockSize"},
|
||||
{0x08400040, nullptr, "AbnegateAccessRight"},
|
||||
{0x08410000, nullptr, "DeleteSdmcRoot"},
|
||||
{0x08420040, nullptr, "DeleteAllExtSaveDataOnNand"},
|
||||
{0x08430000, nullptr, "InitializeCtrFileSystem"},
|
||||
{0x08440000, nullptr, "CreateSeed"},
|
||||
{0x084500C2, nullptr, "GetFormatInfo"},
|
||||
{0x08460102, nullptr, "GetLegacyRomHeader2"},
|
||||
{0x08470180, nullptr, "FormatCtrCardUserSaveData"},
|
||||
{0x08480042, nullptr, "GetSdmcCtrRootPath"},
|
||||
{0x08490040, nullptr, "GetArchiveResource"},
|
||||
{0x084A0002, nullptr, "ExportIntegrityVerificationSeed"},
|
||||
{0x084B0002, nullptr, "ImportIntegrityVerificationSeed"},
|
||||
{0x084C0242, nullptr, "FormatSaveData"},
|
||||
{0x084D0102, nullptr, "GetLegacySubBannerData"},
|
||||
{0x084E0342, nullptr, "UpdateSha256Context"},
|
||||
{0x084F0102, nullptr, "ReadSpecialFile"},
|
||||
{0x08500040, nullptr, "GetSpecialFileSize"},
|
||||
{0x08580000, nullptr, "GetMovableSedHashedKeyYRandomData"},
|
||||
{0x08610042, nullptr, "InitializeWithSdkVersion"},
|
||||
{0x08620040, nullptr, "SetPriority"},
|
||||
{0x08630000, nullptr, "GetPriority"},
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Interface class
|
||||
|
||||
Interface::Interface() {
|
||||
Register(FunctionTable, ARRAY_SIZE(FunctionTable));
|
||||
}
|
||||
|
||||
Interface::~Interface() {
|
||||
}
|
||||
|
||||
} // namespace
|
||||
31
src/core/hle/service/fs_user.h
Normal file
31
src/core/hle/service/fs_user.h
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
// Copyright 2014 Citra Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/hle/service/service.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Namespace FS_User
|
||||
|
||||
namespace FS_User {
|
||||
|
||||
/// Interface to "fs:USER" service
|
||||
class Interface : public Service::Interface {
|
||||
public:
|
||||
|
||||
Interface();
|
||||
|
||||
~Interface();
|
||||
|
||||
/**
|
||||
* Gets the string port name used by CTROS for the service
|
||||
* @return Port name of service
|
||||
*/
|
||||
std::string GetPortName() const override {
|
||||
return "fs:USER";
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace
|
||||
378
src/core/hle/service/gsp_gpu.cpp
Normal file
378
src/core/hle/service/gsp_gpu.cpp
Normal file
|
|
@ -0,0 +1,378 @@
|
|||
// Copyright 2014 Citra Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
|
||||
#include "common/log.h"
|
||||
#include "common/bit_field.h"
|
||||
|
||||
#include "core/mem_map.h"
|
||||
#include "core/hle/kernel/event.h"
|
||||
#include "core/hle/kernel/shared_memory.h"
|
||||
#include "gsp_gpu.h"
|
||||
#include "core/hw/gpu.h"
|
||||
|
||||
#include "video_core/gpu_debugger.h"
|
||||
|
||||
// Main graphics debugger object - TODO: Here is probably not the best place for this
|
||||
GraphicsDebugger g_debugger;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Namespace GSP_GPU
|
||||
|
||||
namespace GSP_GPU {
|
||||
|
||||
Handle g_interrupt_event = 0; ///< Handle to event triggered when GSP interrupt has been signalled
|
||||
Handle g_shared_memory = 0; ///< Handle to GSP shared memorys
|
||||
u32 g_thread_id = 1; ///< Thread index into interrupt relay queue, 1 is arbitrary
|
||||
|
||||
/// Gets a pointer to a thread command buffer in GSP shared memory
|
||||
static inline u8* GetCommandBuffer(u32 thread_id) {
|
||||
if (0 == g_shared_memory)
|
||||
return nullptr;
|
||||
|
||||
return Kernel::GetSharedMemoryPointer(g_shared_memory,
|
||||
0x800 + (thread_id * sizeof(CommandBuffer)));
|
||||
}
|
||||
|
||||
static inline FrameBufferUpdate* GetFrameBufferInfo(u32 thread_id, u32 screen_index) {
|
||||
if (0 == g_shared_memory)
|
||||
return nullptr;
|
||||
|
||||
_dbg_assert_msg_(GSP, screen_index < 2, "Invalid screen index");
|
||||
|
||||
// For each thread there are two FrameBufferUpdate fields
|
||||
u32 offset = 0x200 + (2 * thread_id + screen_index) * sizeof(FrameBufferUpdate);
|
||||
return (FrameBufferUpdate*)Kernel::GetSharedMemoryPointer(g_shared_memory, offset);
|
||||
}
|
||||
|
||||
/// Gets a pointer to the interrupt relay queue for a given thread index
|
||||
static inline InterruptRelayQueue* GetInterruptRelayQueue(u32 thread_id) {
|
||||
return (InterruptRelayQueue*)Kernel::GetSharedMemoryPointer(g_shared_memory,
|
||||
sizeof(InterruptRelayQueue) * thread_id);
|
||||
}
|
||||
|
||||
void WriteHWRegs(u32 base_address, u32 size_in_bytes, const u32* data) {
|
||||
// TODO: Return proper error codes
|
||||
if (base_address + size_in_bytes >= 0x420000) {
|
||||
ERROR_LOG(GPU, "Write address out of range! (address=0x%08x, size=0x%08x)",
|
||||
base_address, size_in_bytes);
|
||||
return;
|
||||
}
|
||||
|
||||
// size should be word-aligned
|
||||
if ((size_in_bytes % 4) != 0) {
|
||||
ERROR_LOG(GPU, "Invalid size 0x%08x", size_in_bytes);
|
||||
return;
|
||||
}
|
||||
|
||||
while (size_in_bytes > 0) {
|
||||
GPU::Write<u32>(base_address + 0x1EB00000, *data);
|
||||
|
||||
size_in_bytes -= 4;
|
||||
++data;
|
||||
base_address += 4;
|
||||
}
|
||||
}
|
||||
|
||||
/// Write a GSP GPU hardware register
|
||||
void WriteHWRegs(Service::Interface* self) {
|
||||
u32* cmd_buff = Service::GetCommandBuffer();
|
||||
u32 reg_addr = cmd_buff[1];
|
||||
u32 size = cmd_buff[2];
|
||||
|
||||
u32* src = (u32*)Memory::GetPointer(cmd_buff[0x4]);
|
||||
|
||||
WriteHWRegs(reg_addr, size, src);
|
||||
}
|
||||
|
||||
/// Read a GSP GPU hardware register
|
||||
void ReadHWRegs(Service::Interface* self) {
|
||||
u32* cmd_buff = Service::GetCommandBuffer();
|
||||
u32 reg_addr = cmd_buff[1];
|
||||
u32 size = cmd_buff[2];
|
||||
|
||||
// TODO: Return proper error codes
|
||||
if (reg_addr + size >= 0x420000) {
|
||||
ERROR_LOG(GPU, "Read address out of range! (address=0x%08x, size=0x%08x)", reg_addr, size);
|
||||
return;
|
||||
}
|
||||
|
||||
// size should be word-aligned
|
||||
if ((size % 4) != 0) {
|
||||
ERROR_LOG(GPU, "Invalid size 0x%08x", size);
|
||||
return;
|
||||
}
|
||||
|
||||
u32* dst = (u32*)Memory::GetPointer(cmd_buff[0x41]);
|
||||
|
||||
while (size > 0) {
|
||||
GPU::Read<u32>(*dst, reg_addr + 0x1EB00000);
|
||||
|
||||
size -= 4;
|
||||
++dst;
|
||||
reg_addr += 4;
|
||||
}
|
||||
}
|
||||
|
||||
void SetBufferSwap(u32 screen_id, const FrameBufferInfo& info) {
|
||||
u32 base_address = 0x400000;
|
||||
if (info.active_fb == 0) {
|
||||
WriteHWRegs(base_address + 4 * GPU_REG_INDEX(framebuffer_config[screen_id].address_left1), 4, &info.address_left);
|
||||
WriteHWRegs(base_address + 4 * GPU_REG_INDEX(framebuffer_config[screen_id].address_right1), 4, &info.address_right);
|
||||
} else {
|
||||
WriteHWRegs(base_address + 4 * GPU_REG_INDEX(framebuffer_config[screen_id].address_left2), 4, &info.address_left);
|
||||
WriteHWRegs(base_address + 4 * GPU_REG_INDEX(framebuffer_config[screen_id].address_right2), 4, &info.address_right);
|
||||
}
|
||||
WriteHWRegs(base_address + 4 * GPU_REG_INDEX(framebuffer_config[screen_id].stride), 4, &info.stride);
|
||||
WriteHWRegs(base_address + 4 * GPU_REG_INDEX(framebuffer_config[screen_id].color_format), 4, &info.format);
|
||||
WriteHWRegs(base_address + 4 * GPU_REG_INDEX(framebuffer_config[screen_id].active_fb), 4, &info.shown_fb);
|
||||
}
|
||||
|
||||
/**
|
||||
* GSP_GPU::SetBufferSwap service function
|
||||
*
|
||||
* Updates GPU display framebuffer configuration using the specified parameters.
|
||||
*
|
||||
* Inputs:
|
||||
* 1 : Screen ID (0 = top screen, 1 = bottom screen)
|
||||
* 2-7 : FrameBufferInfo structure
|
||||
* Outputs:
|
||||
* 1: Result code
|
||||
*/
|
||||
void SetBufferSwap(Service::Interface* self) {
|
||||
u32* cmd_buff = Service::GetCommandBuffer();
|
||||
u32 screen_id = cmd_buff[1];
|
||||
FrameBufferInfo* fb_info = (FrameBufferInfo*)&cmd_buff[2];
|
||||
SetBufferSwap(screen_id, *fb_info);
|
||||
|
||||
cmd_buff[1] = 0; // No error
|
||||
}
|
||||
|
||||
/**
|
||||
* GSP_GPU::RegisterInterruptRelayQueue service function
|
||||
* Inputs:
|
||||
* 1 : "Flags" field, purpose is unknown
|
||||
* 3 : Handle to GSP synchronization event
|
||||
* Outputs:
|
||||
* 0 : Result of function, 0 on success, otherwise error code
|
||||
* 2 : Thread index into GSP command buffer
|
||||
* 4 : Handle to GSP shared memory
|
||||
*/
|
||||
void RegisterInterruptRelayQueue(Service::Interface* self) {
|
||||
u32* cmd_buff = Service::GetCommandBuffer();
|
||||
u32 flags = cmd_buff[1];
|
||||
g_interrupt_event = cmd_buff[3];
|
||||
g_shared_memory = Kernel::CreateSharedMemory("GSPSharedMem");
|
||||
|
||||
_assert_msg_(GSP, (g_interrupt_event != 0), "handle is not valid!");
|
||||
|
||||
cmd_buff[2] = g_thread_id++; // ThreadID
|
||||
cmd_buff[4] = g_shared_memory; // GSP shared memory
|
||||
|
||||
Kernel::SignalEvent(g_interrupt_event); // TODO(bunnei): Is this correct?
|
||||
}
|
||||
|
||||
/**
|
||||
* Signals that the specified interrupt type has occurred to userland code
|
||||
* @param interrupt_id ID of interrupt that is being signalled
|
||||
* @todo This should probably take a thread_id parameter and only signal this thread?
|
||||
*/
|
||||
void SignalInterrupt(InterruptId interrupt_id) {
|
||||
if (0 == g_interrupt_event) {
|
||||
WARN_LOG(GSP, "cannot synchronize until GSP event has been created!");
|
||||
return;
|
||||
}
|
||||
if (0 == g_shared_memory) {
|
||||
WARN_LOG(GSP, "cannot synchronize until GSP shared memory has been created!");
|
||||
return;
|
||||
}
|
||||
for (int thread_id = 0; thread_id < 0x4; ++thread_id) {
|
||||
InterruptRelayQueue* interrupt_relay_queue = GetInterruptRelayQueue(thread_id);
|
||||
interrupt_relay_queue->number_interrupts = interrupt_relay_queue->number_interrupts + 1;
|
||||
|
||||
u8 next = interrupt_relay_queue->index;
|
||||
next += interrupt_relay_queue->number_interrupts;
|
||||
next = next % 0x34; // 0x34 is the number of interrupt slots
|
||||
|
||||
interrupt_relay_queue->slot[next] = interrupt_id;
|
||||
interrupt_relay_queue->error_code = 0x0; // No error
|
||||
}
|
||||
Kernel::SignalEvent(g_interrupt_event);
|
||||
}
|
||||
|
||||
/// Executes the next GSP command
|
||||
void ExecuteCommand(const Command& command, u32 thread_id) {
|
||||
// Utility function to convert register ID to address
|
||||
auto WriteGPURegister = [](u32 id, u32 data) {
|
||||
GPU::Write<u32>(0x1EF00000 + 4 * id, data);
|
||||
};
|
||||
|
||||
switch (command.id) {
|
||||
|
||||
// GX request DMA - typically used for copying memory from GSP heap to VRAM
|
||||
case CommandId::REQUEST_DMA:
|
||||
memcpy(Memory::GetPointer(command.dma_request.dest_address),
|
||||
Memory::GetPointer(command.dma_request.source_address),
|
||||
command.dma_request.size);
|
||||
break;
|
||||
|
||||
// ctrulib homebrew sends all relevant command list data with this command,
|
||||
// hence we do all "interesting" stuff here and do nothing in SET_COMMAND_LIST_FIRST.
|
||||
// TODO: This will need some rework in the future.
|
||||
case CommandId::SET_COMMAND_LIST_LAST:
|
||||
{
|
||||
auto& params = command.set_command_list_last;
|
||||
WriteGPURegister(GPU_REG_INDEX(command_processor_config.address), Memory::VirtualToPhysicalAddress(params.address) >> 3);
|
||||
WriteGPURegister(GPU_REG_INDEX(command_processor_config.size), params.size >> 3);
|
||||
|
||||
// TODO: Not sure if we are supposed to always write this .. seems to trigger processing though
|
||||
WriteGPURegister(GPU_REG_INDEX(command_processor_config.trigger), 1);
|
||||
|
||||
SignalInterrupt(InterruptId::P3D);
|
||||
break;
|
||||
}
|
||||
|
||||
// It's assumed that the two "blocks" behave equivalently.
|
||||
// Presumably this is done simply to allow two memory fills to run in parallel.
|
||||
case CommandId::SET_MEMORY_FILL:
|
||||
{
|
||||
auto& params = command.memory_fill;
|
||||
WriteGPURegister(GPU_REG_INDEX(memory_fill_config[0].address_start), Memory::VirtualToPhysicalAddress(params.start1) >> 3);
|
||||
WriteGPURegister(GPU_REG_INDEX(memory_fill_config[0].address_end), Memory::VirtualToPhysicalAddress(params.end1) >> 3);
|
||||
WriteGPURegister(GPU_REG_INDEX(memory_fill_config[0].size), params.end1 - params.start1);
|
||||
WriteGPURegister(GPU_REG_INDEX(memory_fill_config[0].value), params.value1);
|
||||
|
||||
WriteGPURegister(GPU_REG_INDEX(memory_fill_config[1].address_start), Memory::VirtualToPhysicalAddress(params.start2) >> 3);
|
||||
WriteGPURegister(GPU_REG_INDEX(memory_fill_config[1].address_end), Memory::VirtualToPhysicalAddress(params.end2) >> 3);
|
||||
WriteGPURegister(GPU_REG_INDEX(memory_fill_config[1].size), params.end2 - params.start2);
|
||||
WriteGPURegister(GPU_REG_INDEX(memory_fill_config[1].value), params.value2);
|
||||
break;
|
||||
}
|
||||
|
||||
case CommandId::SET_DISPLAY_TRANSFER:
|
||||
{
|
||||
auto& params = command.image_copy;
|
||||
WriteGPURegister(GPU_REG_INDEX(display_transfer_config.input_address), Memory::VirtualToPhysicalAddress(params.in_buffer_address) >> 3);
|
||||
WriteGPURegister(GPU_REG_INDEX(display_transfer_config.output_address), Memory::VirtualToPhysicalAddress(params.out_buffer_address) >> 3);
|
||||
WriteGPURegister(GPU_REG_INDEX(display_transfer_config.input_size), params.in_buffer_size);
|
||||
WriteGPURegister(GPU_REG_INDEX(display_transfer_config.output_size), params.out_buffer_size);
|
||||
WriteGPURegister(GPU_REG_INDEX(display_transfer_config.flags), params.flags);
|
||||
WriteGPURegister(GPU_REG_INDEX(display_transfer_config.trigger), 1);
|
||||
|
||||
// TODO(bunnei): Signalling all of these interrupts here is totally wrong, but it seems to
|
||||
// work well enough for running demos. Need to figure out how these all work and trigger
|
||||
// them correctly.
|
||||
SignalInterrupt(InterruptId::PSC0);
|
||||
SignalInterrupt(InterruptId::PSC1);
|
||||
SignalInterrupt(InterruptId::PPF);
|
||||
SignalInterrupt(InterruptId::P3D);
|
||||
SignalInterrupt(InterruptId::DMA);
|
||||
|
||||
// Update framebuffer information if requested
|
||||
for (int screen_id = 0; screen_id < 2; ++screen_id) {
|
||||
FrameBufferUpdate* info = GetFrameBufferInfo(thread_id, screen_id);
|
||||
if (info->is_dirty)
|
||||
SetBufferSwap(screen_id, info->framebuffer_info[info->index]);
|
||||
|
||||
info->is_dirty = false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// TODO: Check if texture copies are implemented correctly..
|
||||
case CommandId::SET_TEXTURE_COPY:
|
||||
{
|
||||
auto& params = command.image_copy;
|
||||
WriteGPURegister(GPU_REG_INDEX(display_transfer_config.input_address), Memory::VirtualToPhysicalAddress(params.in_buffer_address) >> 3);
|
||||
WriteGPURegister(GPU_REG_INDEX(display_transfer_config.output_address), Memory::VirtualToPhysicalAddress(params.out_buffer_address) >> 3);
|
||||
WriteGPURegister(GPU_REG_INDEX(display_transfer_config.input_size), params.in_buffer_size);
|
||||
WriteGPURegister(GPU_REG_INDEX(display_transfer_config.output_size), params.out_buffer_size);
|
||||
WriteGPURegister(GPU_REG_INDEX(display_transfer_config.flags), params.flags);
|
||||
|
||||
// TODO: Should this register be set to 1 or should instead its value be OR-ed with 1?
|
||||
WriteGPURegister(GPU_REG_INDEX(display_transfer_config.trigger), 1);
|
||||
break;
|
||||
}
|
||||
|
||||
// TODO: Figure out what exactly SET_COMMAND_LIST_FIRST and SET_COMMAND_LIST_LAST
|
||||
// are supposed to do.
|
||||
case CommandId::SET_COMMAND_LIST_FIRST:
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
ERROR_LOG(GSP, "unknown command 0x%08X", (int)command.id.Value());
|
||||
}
|
||||
}
|
||||
|
||||
/// This triggers handling of the GX command written to the command buffer in shared memory.
|
||||
void TriggerCmdReqQueue(Service::Interface* self) {
|
||||
|
||||
// Iterate through each thread's command queue...
|
||||
for (unsigned thread_id = 0; thread_id < 0x4; ++thread_id) {
|
||||
CommandBuffer* command_buffer = (CommandBuffer*)GetCommandBuffer(thread_id);
|
||||
|
||||
// Iterate through each command...
|
||||
for (unsigned i = 0; i < command_buffer->number_commands; ++i) {
|
||||
g_debugger.GXCommandProcessed((u8*)&command_buffer->commands[i]);
|
||||
|
||||
// Decode and execute command
|
||||
ExecuteCommand(command_buffer->commands[i], thread_id);
|
||||
|
||||
// Indicates that command has completed
|
||||
command_buffer->number_commands = command_buffer->number_commands - 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const Interface::FunctionInfo FunctionTable[] = {
|
||||
{0x00010082, WriteHWRegs, "WriteHWRegs"},
|
||||
{0x00020084, nullptr, "WriteHWRegsWithMask"},
|
||||
{0x00030082, nullptr, "WriteHWRegRepeat"},
|
||||
{0x00040080, ReadHWRegs, "ReadHWRegs"},
|
||||
{0x00050200, SetBufferSwap, "SetBufferSwap"},
|
||||
{0x00060082, nullptr, "SetCommandList"},
|
||||
{0x000700C2, nullptr, "RequestDma"},
|
||||
{0x00080082, nullptr, "FlushDataCache"},
|
||||
{0x00090082, nullptr, "InvalidateDataCache"},
|
||||
{0x000A0044, nullptr, "RegisterInterruptEvents"},
|
||||
{0x000B0040, nullptr, "SetLcdForceBlack"},
|
||||
{0x000C0000, TriggerCmdReqQueue, "TriggerCmdReqQueue"},
|
||||
{0x000D0140, nullptr, "SetDisplayTransfer"},
|
||||
{0x000E0180, nullptr, "SetTextureCopy"},
|
||||
{0x000F0200, nullptr, "SetMemoryFill"},
|
||||
{0x00100040, nullptr, "SetAxiConfigQoSMode"},
|
||||
{0x00110040, nullptr, "SetPerfLogMode"},
|
||||
{0x00120000, nullptr, "GetPerfLog"},
|
||||
{0x00130042, RegisterInterruptRelayQueue, "RegisterInterruptRelayQueue"},
|
||||
{0x00140000, nullptr, "UnregisterInterruptRelayQueue"},
|
||||
{0x00150002, nullptr, "TryAcquireRight"},
|
||||
{0x00160042, nullptr, "AcquireRight"},
|
||||
{0x00170000, nullptr, "ReleaseRight"},
|
||||
{0x00180000, nullptr, "ImportDisplayCaptureInfo"},
|
||||
{0x00190000, nullptr, "SaveVramSysArea"},
|
||||
{0x001A0000, nullptr, "RestoreVramSysArea"},
|
||||
{0x001B0000, nullptr, "ResetGpuCore"},
|
||||
{0x001C0040, nullptr, "SetLedForceOff"},
|
||||
{0x001D0040, nullptr, "SetTestCommand"},
|
||||
{0x001E0080, nullptr, "SetInternalPriorities"},
|
||||
{0x001F0082, nullptr, "StoreDataCache"},
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Interface class
|
||||
|
||||
Interface::Interface() {
|
||||
Register(FunctionTable, ARRAY_SIZE(FunctionTable));
|
||||
|
||||
g_interrupt_event = 0;
|
||||
g_shared_memory = 0;
|
||||
g_thread_id = 1;
|
||||
}
|
||||
|
||||
Interface::~Interface() {
|
||||
}
|
||||
|
||||
} // namespace
|
||||
182
src/core/hle/service/gsp_gpu.h
Normal file
182
src/core/hle/service/gsp_gpu.h
Normal file
|
|
@ -0,0 +1,182 @@
|
|||
// Copyright 2014 Citra Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
#include "common/bit_field.h"
|
||||
#include "core/hle/service/service.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Namespace GSP_GPU
|
||||
|
||||
namespace GSP_GPU {
|
||||
|
||||
/// GSP interrupt ID
|
||||
enum class InterruptId : u8 {
|
||||
PSC0 = 0x00,
|
||||
PSC1 = 0x01,
|
||||
PDC0 = 0x02, // Seems called every vertical screen line
|
||||
PDC1 = 0x03, // Seems called every frame
|
||||
PPF = 0x04,
|
||||
P3D = 0x05,
|
||||
DMA = 0x06,
|
||||
};
|
||||
|
||||
/// GSP command ID
|
||||
enum class CommandId : u32 {
|
||||
REQUEST_DMA = 0x00,
|
||||
SET_COMMAND_LIST_LAST = 0x01,
|
||||
|
||||
// Fills a given memory range with a particular value
|
||||
SET_MEMORY_FILL = 0x02,
|
||||
|
||||
// Copies an image and optionally performs color-conversion or scaling.
|
||||
// This is highly similar to the GameCube's EFB copy feature
|
||||
SET_DISPLAY_TRANSFER = 0x03,
|
||||
|
||||
// Conceptionally similar to SET_DISPLAY_TRANSFER and presumable uses the same hardware path
|
||||
SET_TEXTURE_COPY = 0x04,
|
||||
|
||||
SET_COMMAND_LIST_FIRST = 0x05,
|
||||
};
|
||||
|
||||
/// GSP thread interrupt relay queue
|
||||
struct InterruptRelayQueue {
|
||||
union {
|
||||
u32 hex;
|
||||
|
||||
// Index of last interrupt in the queue
|
||||
BitField<0,8,u32> index;
|
||||
|
||||
// Number of interrupts remaining to be processed by the userland code
|
||||
BitField<8,8,u32> number_interrupts;
|
||||
|
||||
// Error code - zero on success, otherwise an error has occurred
|
||||
BitField<16,8,u32> error_code;
|
||||
};
|
||||
|
||||
u32 unk0;
|
||||
u32 unk1;
|
||||
|
||||
InterruptId slot[0x34]; ///< Interrupt ID slots
|
||||
};
|
||||
static_assert(sizeof(InterruptRelayQueue) == 0x40,
|
||||
"InterruptRelayQueue struct has incorrect size");
|
||||
|
||||
struct FrameBufferInfo {
|
||||
BitField<0, 1, u32> active_fb; // 0 = first, 1 = second
|
||||
|
||||
u32 address_left;
|
||||
u32 address_right;
|
||||
u32 stride; // maps to 0x1EF00X90 ?
|
||||
u32 format; // maps to 0x1EF00X70 ?
|
||||
u32 shown_fb; // maps to 0x1EF00X78 ?
|
||||
u32 unknown;
|
||||
};
|
||||
static_assert(sizeof(FrameBufferInfo) == 0x1c, "Struct has incorrect size");
|
||||
|
||||
struct FrameBufferUpdate {
|
||||
BitField<0, 1, u8> index; // Index used for GSP::SetBufferSwap
|
||||
BitField<0, 1, u8> is_dirty; // true if GSP should update GPU framebuffer registers
|
||||
u16 pad1;
|
||||
|
||||
FrameBufferInfo framebuffer_info[2];
|
||||
|
||||
u32 pad2;
|
||||
};
|
||||
static_assert(sizeof(FrameBufferUpdate) == 0x40, "Struct has incorrect size");
|
||||
// TODO: Not sure if this padding is correct.
|
||||
// Chances are the second block is stored at offset 0x24 rather than 0x20.
|
||||
#ifndef _MSC_VER
|
||||
static_assert(offsetof(FrameBufferUpdate, framebuffer_info[1]) == 0x20, "FrameBufferInfo element has incorrect alignment");
|
||||
#endif
|
||||
|
||||
/// GSP command
|
||||
struct Command {
|
||||
BitField<0, 8, CommandId> id;
|
||||
|
||||
union {
|
||||
struct {
|
||||
u32 source_address;
|
||||
u32 dest_address;
|
||||
u32 size;
|
||||
} dma_request;
|
||||
|
||||
struct {
|
||||
u32 address;
|
||||
u32 size;
|
||||
} set_command_list_last;
|
||||
|
||||
struct {
|
||||
u32 start1;
|
||||
u32 value1;
|
||||
u32 end1;
|
||||
u32 start2;
|
||||
u32 value2;
|
||||
u32 end2;
|
||||
} memory_fill;
|
||||
|
||||
struct {
|
||||
u32 in_buffer_address;
|
||||
u32 out_buffer_address;
|
||||
u32 in_buffer_size;
|
||||
u32 out_buffer_size;
|
||||
u32 flags;
|
||||
} image_copy;
|
||||
|
||||
u8 raw_data[0x1C];
|
||||
};
|
||||
};
|
||||
static_assert(sizeof(Command) == 0x20, "Command struct has incorrect size");
|
||||
|
||||
/// GSP shared memory GX command buffer header
|
||||
struct CommandBuffer {
|
||||
union {
|
||||
u32 hex;
|
||||
|
||||
// Current command index. This index is updated by GSP module after loading the command
|
||||
// data, right before the command is processed. When this index is updated by GSP module,
|
||||
// the total commands field is decreased by one as well.
|
||||
BitField<0,8,u32> index;
|
||||
|
||||
// Total commands to process, must not be value 0 when GSP module handles commands. This
|
||||
// must be <=15 when writing a command to shared memory. This is incremented by the
|
||||
// application when writing a command to shared memory, after increasing this value
|
||||
// TriggerCmdReqQueue is only used if this field is value 1.
|
||||
BitField<8,8,u32> number_commands;
|
||||
};
|
||||
|
||||
u32 unk[7];
|
||||
|
||||
Command commands[0xF];
|
||||
};
|
||||
static_assert(sizeof(CommandBuffer) == 0x200, "CommandBuffer struct has incorrect size");
|
||||
|
||||
/// Interface to "srv:" service
|
||||
class Interface : public Service::Interface {
|
||||
public:
|
||||
|
||||
Interface();
|
||||
|
||||
~Interface();
|
||||
|
||||
/**
|
||||
* Gets the string port name used by CTROS for the service
|
||||
* @return Port name of service
|
||||
*/
|
||||
std::string GetPortName() const override {
|
||||
return "gsp::Gpu";
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Signals that the specified interrupt type has occurred to userland code
|
||||
* @param interrupt_id ID of interrupt that is being signalled
|
||||
*/
|
||||
void SignalInterrupt(InterruptId interrupt_id);
|
||||
|
||||
} // namespace
|
||||
205
src/core/hle/service/hid_user.cpp
Normal file
205
src/core/hle/service/hid_user.cpp
Normal file
|
|
@ -0,0 +1,205 @@
|
|||
// Copyright 2014 Citra Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "common/log.h"
|
||||
|
||||
#include "core/hle/hle.h"
|
||||
#include "core/hle/kernel/event.h"
|
||||
#include "core/hle/kernel/shared_memory.h"
|
||||
#include "hid_user.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Namespace HID_User
|
||||
|
||||
namespace HID_User {
|
||||
|
||||
// Handle to shared memory region designated to HID_User service
|
||||
static Handle shared_mem = 0;
|
||||
|
||||
// Event handles
|
||||
static Handle event_pad_or_touch_1 = 0;
|
||||
static Handle event_pad_or_touch_2 = 0;
|
||||
static Handle event_accelerometer = 0;
|
||||
static Handle event_gyroscope = 0;
|
||||
static Handle event_debug_pad = 0;
|
||||
|
||||
// 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 (0 == shared_mem)
|
||||
return nullptr;
|
||||
|
||||
return reinterpret_cast<PadData*>(Kernel::GetSharedMemoryPointer(shared_mem, 0));
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a Pad state (button or button combo) as pressed
|
||||
*/
|
||||
void PadButtonPress(PadState pad_state) {
|
||||
next_state.hex |= pad_state.hex;
|
||||
UpdateNextCirclePadState();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a Pad state (button or button combo) as released
|
||||
*/
|
||||
void PadButtonRelease(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) {
|
||||
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();
|
||||
|
||||
// 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;
|
||||
|
||||
// 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;
|
||||
|
||||
// Get the current Pad entry
|
||||
PadDataEntry* current_pad_entry = &pad_data->entries[pad_data->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;
|
||||
|
||||
// Set circle Pad
|
||||
current_pad_entry->circle_pad_x = next_circle_x;
|
||||
current_pad_entry->circle_pad_y = next_circle_y;
|
||||
|
||||
// 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();
|
||||
}
|
||||
|
||||
// Signal both handles when there's an update to Pad or touch
|
||||
Kernel::SignalEvent(event_pad_or_touch_1);
|
||||
Kernel::SignalEvent(event_pad_or_touch_2);
|
||||
}
|
||||
|
||||
|
||||
// TODO(peachum):
|
||||
// Add a method for setting analog input from joystick device for the circle Pad.
|
||||
//
|
||||
// This method should:
|
||||
// * Be called after both PadButton<Press, Release>().
|
||||
// * Be called before PadUpdateComplete()
|
||||
// * Set current PadEntry.circle_pad_<axis> using analog data
|
||||
// * Set PadData.raw_circle_pad_data
|
||||
// * Set PadData.current_state.circle_right = 1 if current PadEntry.circle_pad_x >= 41
|
||||
// * Set PadData.current_state.circle_up = 1 if current PadEntry.circle_pad_y >= 41
|
||||
// * 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
|
||||
|
||||
|
||||
/**
|
||||
* HID_User::GetIPCHandles service function
|
||||
* Inputs:
|
||||
* None
|
||||
* Outputs:
|
||||
* 1 : Result of function, 0 on success, otherwise error code
|
||||
* 2 : Unused
|
||||
* 3 : Handle to HID_User shared memory
|
||||
* 4 : Event signaled by HID_User
|
||||
* 5 : Event signaled by HID_User
|
||||
* 6 : Event signaled by HID_User
|
||||
* 7 : Gyroscope event
|
||||
* 8 : Event signaled by HID_User
|
||||
*/
|
||||
void GetIPCHandles(Service::Interface* self) {
|
||||
u32* cmd_buff = Service::GetCommandBuffer();
|
||||
|
||||
cmd_buff[1] = 0; // No error
|
||||
cmd_buff[3] = shared_mem;
|
||||
cmd_buff[4] = event_pad_or_touch_1;
|
||||
cmd_buff[5] = event_pad_or_touch_2;
|
||||
cmd_buff[6] = event_accelerometer;
|
||||
cmd_buff[7] = event_gyroscope;
|
||||
cmd_buff[8] = event_debug_pad;
|
||||
|
||||
DEBUG_LOG(KERNEL, "called");
|
||||
}
|
||||
|
||||
const Interface::FunctionInfo FunctionTable[] = {
|
||||
{0x000A0000, GetIPCHandles, "GetIPCHandles"},
|
||||
{0x000B0000, nullptr, "StartAnalogStickCalibration"},
|
||||
{0x000E0000, nullptr, "GetAnalogStickCalibrateParam"},
|
||||
{0x00110000, nullptr, "EnableAccelerometer"},
|
||||
{0x00120000, nullptr, "DisableAccelerometer"},
|
||||
{0x00130000, nullptr, "EnableGyroscopeLow"},
|
||||
{0x00140000, nullptr, "DisableGyroscopeLow"},
|
||||
{0x00150000, nullptr, "GetGyroscopeLowRawToDpsCoefficient"},
|
||||
{0x00160000, nullptr, "GetGyroscopeLowCalibrateParam"},
|
||||
{0x00170000, nullptr, "GetSoundVolume"},
|
||||
};
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Interface class
|
||||
|
||||
Interface::Interface() {
|
||||
shared_mem = Kernel::CreateSharedMemory("HID_User:SharedMem"); // Create shared memory object
|
||||
|
||||
// Create event handles
|
||||
event_pad_or_touch_1 = Kernel::CreateEvent(RESETTYPE_ONESHOT, "HID_User:EventPadOrTouch1");
|
||||
event_pad_or_touch_2 = Kernel::CreateEvent(RESETTYPE_ONESHOT, "HID_User:EventPadOrTouch2");
|
||||
event_accelerometer = Kernel::CreateEvent(RESETTYPE_ONESHOT, "HID_User:EventAccelerometer");
|
||||
event_gyroscope = Kernel::CreateEvent(RESETTYPE_ONESHOT, "HID_User:EventGyroscope");
|
||||
event_debug_pad = Kernel::CreateEvent(RESETTYPE_ONESHOT, "HID_User:EventDebugPad");
|
||||
|
||||
Register(FunctionTable, ARRAY_SIZE(FunctionTable));
|
||||
}
|
||||
|
||||
Interface::~Interface() {
|
||||
}
|
||||
|
||||
} // namespace
|
||||
120
src/core/hle/service/hid_user.h
Normal file
120
src/core/hle/service/hid_user.h
Normal file
|
|
@ -0,0 +1,120 @@
|
|||
// Copyright 2014 Citra Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/hle/service/service.h"
|
||||
#include "common/bit_field.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Namespace HID_User
|
||||
|
||||
// This service is used for interfacing to physical user controls.
|
||||
// Uses include game pad controls, touchscreen, accelerometers, gyroscopes, and debug pad.
|
||||
|
||||
namespace HID_User {
|
||||
|
||||
/**
|
||||
* Structure of a Pad controller state.
|
||||
*/
|
||||
struct PadState {
|
||||
union {
|
||||
u32 hex;
|
||||
|
||||
BitField<0, 1, u32> a;
|
||||
BitField<1, 1, u32> b;
|
||||
BitField<2, 1, u32> select;
|
||||
BitField<3, 1, u32> start;
|
||||
BitField<4, 1, u32> right;
|
||||
BitField<5, 1, u32> left;
|
||||
BitField<6, 1, u32> up;
|
||||
BitField<7, 1, u32> down;
|
||||
BitField<8, 1, u32> r;
|
||||
BitField<9, 1, u32> l;
|
||||
BitField<10, 1, u32> x;
|
||||
BitField<11, 1, u32> y;
|
||||
|
||||
BitField<28, 1, u32> circle_right;
|
||||
BitField<29, 1, u32> circle_left;
|
||||
BitField<30, 1, u32> circle_up;
|
||||
BitField<31, 1, u32> circle_down;
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Structure of a single entry in the PadData's Pad state history array.
|
||||
*/
|
||||
struct PadDataEntry {
|
||||
PadState current_state;
|
||||
PadState delta_additions;
|
||||
PadState delta_removals;
|
||||
|
||||
s16 circle_pad_x;
|
||||
s16 circle_pad_y;
|
||||
};
|
||||
|
||||
/**
|
||||
* Structure of all data related to the 3DS Pad.
|
||||
*/
|
||||
struct PadData {
|
||||
s64 index_reset_ticks;
|
||||
s64 index_reset_ticks_previous;
|
||||
u32 index; // the index of the last updated Pad state history element
|
||||
|
||||
u32 pad1;
|
||||
u32 pad2;
|
||||
|
||||
PadState current_state; // same as entries[index].current_state
|
||||
u32 raw_circle_pad_data;
|
||||
|
||||
u32 pad3;
|
||||
|
||||
std::array<PadDataEntry, 8> entries; // Pad state history
|
||||
};
|
||||
|
||||
// Pre-defined PadStates for single button presses
|
||||
const PadState PAD_NONE = {{0}};
|
||||
const PadState PAD_A = {{1u << 0}};
|
||||
const PadState PAD_B = {{1u << 1}};
|
||||
const PadState PAD_SELECT = {{1u << 2}};
|
||||
const PadState PAD_START = {{1u << 3}};
|
||||
const PadState PAD_RIGHT = {{1u << 4}};
|
||||
const PadState PAD_LEFT = {{1u << 5}};
|
||||
const PadState PAD_UP = {{1u << 6}};
|
||||
const PadState PAD_DOWN = {{1u << 7}};
|
||||
const PadState PAD_R = {{1u << 8}};
|
||||
const PadState PAD_L = {{1u << 9}};
|
||||
const PadState PAD_X = {{1u << 10}};
|
||||
const PadState PAD_Y = {{1u << 11}};
|
||||
const PadState PAD_CIRCLE_RIGHT = {{1u << 28}};
|
||||
const PadState PAD_CIRCLE_LEFT = {{1u << 29}};
|
||||
const PadState PAD_CIRCLE_UP = {{1u << 30}};
|
||||
const PadState PAD_CIRCLE_DOWN = {{1u << 31}};
|
||||
|
||||
// Methods for updating the HID module's state
|
||||
void PadButtonPress(PadState pad_state);
|
||||
void PadButtonRelease(PadState pad_state);
|
||||
void PadUpdateComplete();
|
||||
|
||||
/**
|
||||
* HID service interface.
|
||||
*/
|
||||
class Interface : public Service::Interface {
|
||||
public:
|
||||
|
||||
Interface();
|
||||
|
||||
~Interface();
|
||||
|
||||
/**
|
||||
* Gets the string port name used by CTROS for the service
|
||||
* @return Port name of service
|
||||
*/
|
||||
std::string GetPortName() const override {
|
||||
return "hid:USER";
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
} // namespace
|
||||
30
src/core/hle/service/ndm_u.cpp
Normal file
30
src/core/hle/service/ndm_u.cpp
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
// Copyright 2014 Citra Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "core/hle/hle.h"
|
||||
#include "ndm_u.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Namespace NDM_U
|
||||
|
||||
namespace NDM_U {
|
||||
|
||||
const Interface::FunctionInfo FunctionTable[] = {
|
||||
{0x00060040, nullptr, "SuspendDaemons"},
|
||||
{0x00080040, nullptr, "DisableWifiUsage"},
|
||||
{0x00090000, nullptr, "EnableWifiUsage"},
|
||||
{0x00140040, nullptr, "OverrideDefaultDaemons"},
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Interface class
|
||||
|
||||
Interface::Interface() {
|
||||
Register(FunctionTable, ARRAY_SIZE(FunctionTable));
|
||||
}
|
||||
|
||||
Interface::~Interface() {
|
||||
}
|
||||
|
||||
} // namespace
|
||||
33
src/core/hle/service/ndm_u.h
Normal file
33
src/core/hle/service/ndm_u.h
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
// Copyright 2014 Citra Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/hle/service/service.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Namespace NDM
|
||||
|
||||
// No idea what this is
|
||||
|
||||
namespace NDM_U {
|
||||
|
||||
class Interface : public Service::Interface {
|
||||
public:
|
||||
|
||||
Interface();
|
||||
|
||||
~Interface();
|
||||
|
||||
/**
|
||||
* Gets the string port name used by CTROS for the service
|
||||
* @return Port name of service
|
||||
*/
|
||||
std::string GetPortName() const override {
|
||||
return "ndm:u";
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
|
@ -6,11 +6,11 @@
|
|||
#include "common/string_util.h"
|
||||
|
||||
#include "core/hle/service/service.h"
|
||||
#include "core/hle/service/apt.h"
|
||||
#include "core/hle/service/fs.h"
|
||||
#include "core/hle/service/gsp.h"
|
||||
#include "core/hle/service/hid.h"
|
||||
#include "core/hle/service/ndm.h"
|
||||
#include "core/hle/service/apt_u.h"
|
||||
#include "core/hle/service/fs_user.h"
|
||||
#include "core/hle/service/gsp_gpu.h"
|
||||
#include "core/hle/service/hid_user.h"
|
||||
#include "core/hle/service/ndm_u.h"
|
||||
#include "core/hle/service/srv.h"
|
||||
|
||||
namespace Service {
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@
|
|||
#include "core/mem_map.h"
|
||||
|
||||
#include "core/hle/hle.h"
|
||||
#include "core/hle/service/gsp.h"
|
||||
#include "core/hle/service/gsp_gpu.h"
|
||||
|
||||
#include "core/hw/gpu.h"
|
||||
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@
|
|||
|
||||
#include "common/log.h"
|
||||
|
||||
#include "core/hle/service/gsp.h"
|
||||
#include "core/hle/service/gsp_gpu.h"
|
||||
|
||||
#include "command_processor.h"
|
||||
#include "pica.h"
|
||||
|
|
|
|||
Loading…
Reference in a new issue