From 14602287f761cbf2fc5f0767c0ebccbf217574a2 Mon Sep 17 00:00:00 2001
From: JamePeng <jame_peng@sina.com>
Date: Thu, 21 Apr 2016 02:25:58 +0800
Subject: [PATCH] Update the stub code of NDM service!

---
 src/core/hle/service/ndm/ndm.cpp   | 203 ++++++++++++++++++++++++++-
 src/core/hle/service/ndm/ndm.h     | 216 ++++++++++++++++++++++++++++-
 src/core/hle/service/ndm/ndm_u.cpp |  34 ++---
 3 files changed, 423 insertions(+), 30 deletions(-)

diff --git a/src/core/hle/service/ndm/ndm.cpp b/src/core/hle/service/ndm/ndm.cpp
index 47076a7b82..bc9c3413d8 100644
--- a/src/core/hle/service/ndm/ndm.cpp
+++ b/src/core/hle/service/ndm/ndm.cpp
@@ -11,28 +11,217 @@
 namespace Service {
 namespace NDM {
 
-void SuspendDaemons(Service::Interface* self) {
+enum : u32 {
+    DEFAULT_RETRY_INTERVAL = 10,
+    DEFAULT_SCAN_INTERVAL  = 30
+};
+
+static DaemonMask daemon_bit_mask = DaemonMask::Default;
+static DaemonMask default_daemon_bit_mask = DaemonMask::Default;
+static std::array<DaemonStatus, 4> daemon_status = { DaemonStatus::Idle, DaemonStatus::Idle, DaemonStatus::Idle, DaemonStatus::Idle };
+static ExclusiveState exclusive_state = ExclusiveState::None;
+static u32 scan_interval = DEFAULT_SCAN_INTERVAL;
+static u32 retry_interval = DEFAULT_RETRY_INTERVAL;
+static bool daemon_lock_enabled = false;
+
+void EnterExclusiveState(Service::Interface* self) {
+    u32* cmd_buff = Kernel::GetCommandBuffer();
+    exclusive_state = static_cast<ExclusiveState>(cmd_buff[1]);
+
+    cmd_buff[0] = IPC::MakeHeader(0x1, 1, 0);
+    cmd_buff[1] = RESULT_SUCCESS.raw; // No error
+    LOG_WARNING(Service_NDM, "(STUBBED) exclusive_state=0x%08X ", exclusive_state);
+}
+
+void LeaveExclusiveState(Service::Interface* self) {
+    u32* cmd_buff = Kernel::GetCommandBuffer();
+    exclusive_state = ExclusiveState::None;
+
+    cmd_buff[0] = IPC::MakeHeader(0x2, 1, 0);
+    cmd_buff[1] = RESULT_SUCCESS.raw; // No error
+    LOG_WARNING(Service_NDM, "(STUBBED) exclusive_state=0x%08X ", exclusive_state);
+}
+
+void QueryExclusiveMode(Service::Interface* self) {
     u32* cmd_buff = Kernel::GetCommandBuffer();
 
-    LOG_WARNING(Service_NDM, "(STUBBED) bit_mask=0x%08X ", cmd_buff[1]);
-
+    cmd_buff[0] = IPC::MakeHeader(0x3, 2, 0);
     cmd_buff[1] = RESULT_SUCCESS.raw; // No error
+    cmd_buff[2] = static_cast<u32>(exclusive_state);
+    LOG_WARNING(Service_NDM, "(STUBBED) exclusive_state=0x%08X ", exclusive_state);
+}
+
+void LockState(Service::Interface* self) {
+    u32* cmd_buff = Kernel::GetCommandBuffer();
+    daemon_lock_enabled = true;
+
+    cmd_buff[0] = IPC::MakeHeader(0x4, 1, 0);
+    cmd_buff[1] = RESULT_SUCCESS.raw; // No error
+    LOG_WARNING(Service_NDM, "(STUBBED) daemon_lock_enabled=0x%08X ", daemon_lock_enabled);
+}
+
+void UnlockState(Service::Interface* self) {
+    u32* cmd_buff = Kernel::GetCommandBuffer();
+    daemon_lock_enabled = false;
+
+    cmd_buff[0] = IPC::MakeHeader(0x5, 1, 0);
+    cmd_buff[1] = RESULT_SUCCESS.raw; // No error
+    LOG_WARNING(Service_NDM, "(STUBBED) daemon_lock_enabled=0x%08X ", daemon_lock_enabled);
+}
+
+void SuspendDaemons(Service::Interface* self) {
+    u32* cmd_buff = Kernel::GetCommandBuffer();
+    u32 bit_mask = cmd_buff[1] & 0xF;
+    daemon_bit_mask = static_cast<DaemonMask>(static_cast<u32>(default_daemon_bit_mask) & ~bit_mask);
+    for (size_t index = 0; index < daemon_status.size(); ++index) {
+        if (bit_mask & (1 << index)) {
+            daemon_status[index] = DaemonStatus::Suspended;
+        }
+    }
+
+    cmd_buff[0] = IPC::MakeHeader(0x6, 1, 0);
+    cmd_buff[1] = RESULT_SUCCESS.raw; // No error
+    LOG_WARNING(Service_NDM, "(STUBBED) daemon_bit_mask=0x%08X ", daemon_bit_mask);
 }
 
 void ResumeDaemons(Service::Interface* self) {
     u32* cmd_buff = Kernel::GetCommandBuffer();
+    u32 bit_mask = cmd_buff[1] & 0xF;
+    daemon_bit_mask = static_cast<DaemonMask>(static_cast<u32>(daemon_bit_mask) | bit_mask);
+    for (size_t index = 0; index < daemon_status.size(); ++index) {
+        if (bit_mask & (1 << index)) {
+            daemon_status[index] = DaemonStatus::Idle;
+        }
+    }
 
-    LOG_WARNING(Service_NDM, "(STUBBED) bit_mask=0x%08X ", cmd_buff[1]);
-
+    cmd_buff[0] = IPC::MakeHeader(0x7, 1, 0);
     cmd_buff[1] = RESULT_SUCCESS.raw; // No error
+    LOG_WARNING(Service_NDM, "(STUBBED) daemon_bit_mask=0x%08X ", daemon_bit_mask);
+}
+
+void SuspendScheduler(Service::Interface* self) {
+    u32* cmd_buff = Kernel::GetCommandBuffer();
+
+    cmd_buff[0] = IPC::MakeHeader(0x8, 1, 0);
+    cmd_buff[1] = RESULT_SUCCESS.raw; // No error
+    LOG_WARNING(Service_NDM, "(STUBBED) called");
+}
+
+void ResumeScheduler(Service::Interface* self) {
+    u32* cmd_buff = Kernel::GetCommandBuffer();
+
+    cmd_buff[0] = IPC::MakeHeader(0x9, 1, 0);
+    cmd_buff[1] = RESULT_SUCCESS.raw; // No error
+    LOG_WARNING(Service_NDM, "(STUBBED) called");
+}
+
+void QueryStatus(Service::Interface* self) {
+    u32* cmd_buff = Kernel::GetCommandBuffer();
+    u32 daemon = cmd_buff[1] & 0xF;
+
+    cmd_buff[0] = IPC::MakeHeader(0xD, 2, 0);
+    cmd_buff[1] = RESULT_SUCCESS.raw; // No error
+    cmd_buff[2] = static_cast<u32>(daemon_status.at(daemon));
+    LOG_WARNING(Service_NDM, "(STUBBED) daemon=0x%08X, daemon_status=0x%08X", daemon, cmd_buff[2]);
+}
+
+void GetDaemonDisableCount(Service::Interface* self) {
+    u32* cmd_buff = Kernel::GetCommandBuffer();
+    u32 daemon = cmd_buff[1] & 0xF;
+
+    cmd_buff[0] = IPC::MakeHeader(0xE, 3, 0);
+    cmd_buff[1] = RESULT_SUCCESS.raw; // No error
+    cmd_buff[2] = 0;
+    cmd_buff[3] = 0;
+    LOG_WARNING(Service_NDM, "(STUBBED) daemon=0x%08X", daemon);
+}
+
+void GetSchedulerDisableCount(Service::Interface* self) {
+    u32* cmd_buff = Kernel::GetCommandBuffer();
+
+    cmd_buff[0] = IPC::MakeHeader(0xF, 3, 0);
+    cmd_buff[1] = RESULT_SUCCESS.raw; // No error
+    cmd_buff[2] = 0;
+    cmd_buff[3] = 0;
+    LOG_WARNING(Service_NDM, "(STUBBED) called");
+}
+
+void SetScanInterval(Service::Interface* self) {
+    u32* cmd_buff = Kernel::GetCommandBuffer();
+    scan_interval = cmd_buff[1];
+
+    cmd_buff[0] = IPC::MakeHeader(0x10, 1, 0);
+    cmd_buff[1] = RESULT_SUCCESS.raw; // No error
+    LOG_WARNING(Service_NDM, "(STUBBED) scan_interval=0x%08X ", scan_interval);
+}
+
+void GetScanInterval(Service::Interface* self) {
+    u32* cmd_buff = Kernel::GetCommandBuffer();
+
+    cmd_buff[0] = IPC::MakeHeader(0x11, 2, 0);
+    cmd_buff[1] = RESULT_SUCCESS.raw; // No error
+    cmd_buff[2] = scan_interval;
+    LOG_WARNING(Service_NDM, "(STUBBED) scan_interval=0x%08X ", scan_interval);
+}
+
+void SetRetryInterval(Service::Interface* self) {
+    u32* cmd_buff = Kernel::GetCommandBuffer();
+    retry_interval = cmd_buff[1];
+
+    cmd_buff[0] = IPC::MakeHeader(0x12, 1, 0);
+    cmd_buff[1] = RESULT_SUCCESS.raw; // No error
+    LOG_WARNING(Service_NDM, "(STUBBED) retry_interval=0x%08X ", retry_interval);
+}
+
+void GetRetryInterval(Service::Interface* self) {
+    u32* cmd_buff = Kernel::GetCommandBuffer();
+
+    cmd_buff[0] = IPC::MakeHeader(0x13, 2, 0);
+    cmd_buff[1] = RESULT_SUCCESS.raw; // No error
+    cmd_buff[2] = retry_interval;
+    LOG_WARNING(Service_NDM, "(STUBBED) retry_interval=0x%08X ", retry_interval);
 }
 
 void OverrideDefaultDaemons(Service::Interface* self) {
     u32* cmd_buff = Kernel::GetCommandBuffer();
+    u32 bit_mask = cmd_buff[1] & 0xF;
+    default_daemon_bit_mask = static_cast<DaemonMask>(bit_mask);
+    daemon_bit_mask = default_daemon_bit_mask;
+    for (size_t index = 0; index < daemon_status.size(); ++index) {
+        if (bit_mask & (1 << index)) {
+            daemon_status[index] = DaemonStatus::Idle;
+        }
+    }
 
-    LOG_WARNING(Service_NDM, "(STUBBED) bit_mask=0x%08X ", cmd_buff[1]);
-
+    cmd_buff[0] = IPC::MakeHeader(0x14, 1, 0);
     cmd_buff[1] = RESULT_SUCCESS.raw; // No error
+    LOG_WARNING(Service_NDM, "(STUBBED) default_daemon_bit_mask=0x%08X ", default_daemon_bit_mask);
+}
+
+void ResetDefaultDaemons(Service::Interface* self) {
+    u32* cmd_buff = Kernel::GetCommandBuffer();
+    default_daemon_bit_mask = DaemonMask::Default;
+
+    cmd_buff[0] = IPC::MakeHeader(0x15, 1, 0);
+    cmd_buff[1] = RESULT_SUCCESS.raw; // No error
+    LOG_WARNING(Service_NDM, "(STUBBED) default_daemon_bit_mask=0x%08X ", default_daemon_bit_mask);
+}
+
+void GetDefaultDaemons(Service::Interface* self) {
+    u32* cmd_buff = Kernel::GetCommandBuffer();
+
+    cmd_buff[0] = IPC::MakeHeader(0x16, 2, 0);
+    cmd_buff[1] = RESULT_SUCCESS.raw; // No error
+    cmd_buff[2] = static_cast<u32>(default_daemon_bit_mask);
+    LOG_WARNING(Service_NDM, "(STUBBED) default_daemon_bit_mask=0x%08X ", default_daemon_bit_mask);
+}
+
+void ClearHalfAwakeMacFilter(Service::Interface* self) {
+    u32* cmd_buff = Kernel::GetCommandBuffer();
+
+    cmd_buff[0] = IPC::MakeHeader(0x17, 1, 0);
+    cmd_buff[1] = RESULT_SUCCESS.raw; // No error
+    LOG_WARNING(Service_NDM, "(STUBBED) called");
 }
 
 void Init() {
diff --git a/src/core/hle/service/ndm/ndm.h b/src/core/hle/service/ndm/ndm.h
index 734730f8cf..5c2b968dcf 100644
--- a/src/core/hle/service/ndm/ndm.h
+++ b/src/core/hle/service/ndm/ndm.h
@@ -12,10 +12,91 @@ class Interface;
 
 namespace NDM {
 
+enum class Daemon : u32 {
+    Cec    = 0,
+    Boss   = 1,
+    Nim    = 2,
+    Friend = 3
+};
+
+enum class DaemonMask : u32 {
+    None    =  0,
+    Cec     = (1 << static_cast<u32>(Daemon::Cec)),
+    Boss    = (1 << static_cast<u32>(Daemon::Boss)),
+    Nim     = (1 << static_cast<u32>(Daemon::Nim)),
+    Friend  = (1 << static_cast<u32>(Daemon::Friend)),
+    Default = Cec | Friend,
+    All     = Cec | Boss | Nim | Friend
+};
+
+enum class DaemonStatus : u32 {
+    Busy       = 0,
+    Idle       = 1,
+    Suspending = 2,
+    Suspended  = 3
+};
+
+enum class ExclusiveState : u32 {
+    None                = 0,
+    Infrastructure      = 1,
+    LocalCommunications = 2,
+    Streetpass          = 3,
+    StreetpassData      = 4,
+};
+
 /**
- *  SuspendDaemons
+ *  NDM::EnterExclusiveState service function
  *  Inputs:
- *      0 : Command header (0x00020082)
+ *      0 : Header code [0x00010042]
+ *      1 : Exclusive State
+ *      2 : 0x20
+ *  Outputs:
+ *      1 : Result, 0 on success, otherwise error code
+ */
+void EnterExclusiveState(Service::Interface* self);
+
+/**
+ *  NDM::LeaveExclusiveState service function
+ *  Inputs:
+ *      0 : Header code [0x00020002]
+ *      1 : 0x20
+ *  Outputs:
+ *      1 : Result, 0 on success, otherwise error code
+ */
+void LeaveExclusiveState(Service::Interface* self);
+
+/**
+ *  NDM::QueryExclusiveMode service function
+ *  Inputs:
+ *      0 : Header code [0x00030000]
+ *  Outputs:
+ *      1 : Result, 0 on success, otherwise error code
+ *      2 : Current Exclusive State
+ */
+void QueryExclusiveMode(Service::Interface* self);
+
+/**
+ *  NDM::LockState service function
+ *  Inputs:
+ *      0 : Header code [0x00040002]
+ *  Outputs:
+ *      1 : Result, 0 on success, otherwise error code
+ */
+void LockState(Service::Interface* self);
+
+/**
+ *  NDM::UnlockState service function
+ *  Inputs:
+ *      0 : Header code [0x00050002]
+ *  Outputs:
+ *      1 : Result, 0 on success, otherwise error code
+ */
+void UnlockState(Service::Interface* self);
+
+/**
+ *  NDM::SuspendDaemons service function
+ *  Inputs:
+ *      0 : Header code [0x00060040]
  *      1 : Daemon bit mask
  *  Outputs:
  *      1 : Result, 0 on success, otherwise error code
@@ -23,9 +104,9 @@ namespace NDM {
 void SuspendDaemons(Service::Interface* self);
 
 /**
- *  ResumeDaemons
+ *  NDM::ResumeDaemons service function
  *  Inputs:
- *      0 : Command header (0x00020082)
+ *      0 : Header code [0x00070040]
  *      1 : Daemon bit mask
  *  Outputs:
  *      1 : Result, 0 on success, otherwise error code
@@ -33,15 +114,138 @@ void SuspendDaemons(Service::Interface* self);
 void ResumeDaemons(Service::Interface* self);
 
 /**
- *  OverrideDefaultDaemons
+ *  NDM::SuspendScheduler service function
  *  Inputs:
- *      0 : Command header (0x00020082)
+ *      0 : Header code [0x00080040]
+ *  Outputs:
+ *      1 : Result, 0 on success, otherwise error code
+ */
+void SuspendScheduler(Service::Interface* self);
+
+/**
+ *  NDM::ResumeScheduler service function
+ *  Inputs:
+ *      0 : Header code [0x00090000]
+ *  Outputs:
+ *      1 : Result, 0 on success, otherwise error code
+ */
+void ResumeScheduler(Service::Interface* self);
+
+/**
+ *  NDM::QueryStatus service function
+ *  Inputs:
+ *      0 : Header code [0x000D0040]
+ *      1 : Daemon
+ *  Outputs:
+ *      1 : Result, 0 on success, otherwise error code
+ *      2 : Daemon status
+ */
+void QueryStatus(Service::Interface* self);
+
+/**
+ *  NDM::GetDaemonDisableCount service function
+ *  Inputs:
+ *      0 : Header code [0x000E0040]
+ *      1 : Daemon
+ *  Outputs:
+ *      1 : Result, 0 on success, otherwise error code
+ *      2 : Current process disable count
+ *      3 : Total disable count
+ */
+void GetDaemonDisableCount(Service::Interface* self);
+
+/**
+ *  NDM::GetSchedulerDisableCount service function
+ *  Inputs:
+ *      0 : Header code [0x000F0000]
+ *  Outputs:
+ *      1 : Result, 0 on success, otherwise error code
+ *      2 : Current process disable count
+ *      3 : Total disable count
+ */
+void GetSchedulerDisableCount(Service::Interface* self);
+
+/**
+ *  NDM::SetScanInterval service function
+ *  Inputs:
+ *      0 : Header code [0x00100040]
+ *      1 : Interval (default = 30)
+ *  Outputs:
+ *      1 : Result, 0 on success, otherwise error code
+ */
+void SetScanInterval(Service::Interface* self);
+
+/**
+ *  NDM::GetScanInterval service function
+ *  Inputs:
+ *      0 : Header code [0x00110000]
+ *  Outputs:
+ *      1 : Result, 0 on success, otherwise error code
+ *      2 : Interval (default = 30)
+ */
+void GetScanInterval(Service::Interface* self);
+
+/**
+ *  NDM::SetRetryInterval service function
+ *  Inputs:
+ *      0 : Header code [0x00120040]
+ *      1 : Interval (default = 10)
+ *  Outputs:
+ *      1 : Result, 0 on success, otherwise error code
+ */
+void SetRetryInterval(Service::Interface* self);
+
+/**
+ *  NDM::GetRetryInterval service function
+ *  Inputs:
+ *      0 : Header code [0x00130000]
+ *  Outputs:
+ *      1 : Result, 0 on success, otherwise error code
+ *      2 : Interval (default = 10)
+ */
+void GetRetryInterval(Service::Interface* self);
+
+
+/**
+ *  NDM::OverrideDefaultDaemons service function
+ *  Inputs:
+ *      0 : Header code [0x00140040]
  *      1 : Daemon bit mask
  *  Outputs:
  *      1 : Result, 0 on success, otherwise error code
  */
 void OverrideDefaultDaemons(Service::Interface* self);
 
+/**
+ *  NDM::ResetDefaultDaemons service function
+ *  Inputs:
+ *      0 : Header code [0x00150000]
+ *  Outputs:
+ *      1 : Result, 0 on success, otherwise error code
+ */
+void ResetDefaultDaemons(Service::Interface* self);
+
+/**
+ *  NDM::GetDefaultDaemons service function
+ *  Inputs:
+ *      0 : Header code [0x00160000]
+ *  Outputs:
+ *      1 : Result, 0 on success, otherwise error code
+ *      2 : Daemon bit mask
+ *  Note:
+ *      Gets the current default daemon bit mask. The default value is (DAEMONMASK_CEC | DAEMONMASK_FRIENDS)
+ */
+void GetDefaultDaemons(Service::Interface* self);
+
+/**
+ *  NDM::ClearHalfAwakeMacFilter service function
+ *  Inputs:
+ *      0 : Header code [0x00170000]
+ *  Outputs:
+ *      1 : Result, 0 on success, otherwise error code
+ */
+void ClearHalfAwakeMacFilter(Service::Interface* self);
+
 /// Initialize NDM service
 void Init();
 
diff --git a/src/core/hle/service/ndm/ndm_u.cpp b/src/core/hle/service/ndm/ndm_u.cpp
index bf95cc7aa5..3ff0744ee6 100644
--- a/src/core/hle/service/ndm/ndm_u.cpp
+++ b/src/core/hle/service/ndm/ndm_u.cpp
@@ -9,29 +9,29 @@ namespace Service {
 namespace NDM {
 
 const Interface::FunctionInfo FunctionTable[] = {
-    {0x00010042, nullptr,                 "EnterExclusiveState"},
-    {0x00020002, nullptr,                 "LeaveExclusiveState"},
-    {0x00030000, nullptr,                 "QueryExclusiveMode"},
-    {0x00040002, nullptr,                 "LockState"},
-    {0x00050002, nullptr,                 "UnlockState"},
+    {0x00010042, EnterExclusiveState,     "EnterExclusiveState"},
+    {0x00020002, LeaveExclusiveState,     "LeaveExclusiveState"},
+    {0x00030000, QueryExclusiveMode,      "QueryExclusiveMode"},
+    {0x00040002, LockState,               "LockState"},
+    {0x00050002, UnlockState,             "UnlockState"},
     {0x00060040, SuspendDaemons,          "SuspendDaemons"},
     {0x00070040, ResumeDaemons,           "ResumeDaemons"},
-    {0x00080040, nullptr,                 "DisableWifiUsage"},
-    {0x00090000, nullptr,                 "EnableWifiUsage"},
+    {0x00080040, SuspendScheduler,        "SuspendScheduler"},
+    {0x00090000, ResumeScheduler,         "ResumeScheduler"},
     {0x000A0000, nullptr,                 "GetCurrentState"},
     {0x000B0000, nullptr,                 "GetTargetState"},
     {0x000C0000, nullptr,                 "<Stubbed>"},
-    {0x000D0040, nullptr,                 "QueryStatus"},
-    {0x000E0040, nullptr,                 "GetDaemonDisableCount"},
-    {0x000F0000, nullptr,                 "GetSchedulerDisableCount"},
-    {0x00100040, nullptr,                 "SetScanInterval"},
-    {0x00110000, nullptr,                 "GetScanInterval"},
-    {0x00120040, nullptr,                 "SetRetryInterval"},
-    {0x00130000, nullptr,                 "GetRetryInterval"},
+    {0x000D0040, QueryStatus,             "QueryStatus"},
+    {0x000E0040, GetDaemonDisableCount,   "GetDaemonDisableCount"},
+    {0x000F0000, GetSchedulerDisableCount,"GetSchedulerDisableCount"},
+    {0x00100040, SetScanInterval,         "SetScanInterval"},
+    {0x00110000, GetScanInterval,         "GetScanInterval"},
+    {0x00120040, SetRetryInterval,        "SetRetryInterval"},
+    {0x00130000, GetRetryInterval,        "GetRetryInterval"},
     {0x00140040, OverrideDefaultDaemons,  "OverrideDefaultDaemons"},
-    {0x00150000, nullptr,                 "ResetDefaultDaemons"},
-    {0x00160000, nullptr,                 "GetDefaultDaemons"},
-    {0x00170000, nullptr,                 "ClearHalfAwakeMacFilter"},
+    {0x00150000, ResetDefaultDaemons,     "ResetDefaultDaemons"},
+    {0x00160000, GetDefaultDaemons,       "GetDefaultDaemons"},
+    {0x00170000, ClearHalfAwakeMacFilter, "ClearHalfAwakeMacFilter"},
 };
 
 NDM_U_Interface::NDM_U_Interface() {