From e943eb6ea558530f810420f297f1e92bcc6af94d Mon Sep 17 00:00:00 2001
From: Michael Scire <SciresM@gmail.com>
Date: Sat, 10 Nov 2018 13:31:35 -0800
Subject: [PATCH] Add fs gamecard attribute retrieve commands

---
 nx/include/switch/services/fs.h   | 13 +++++
 nx/include/switch/services/gpio.h |  2 +-
 nx/include/switch/services/i2c.h  |  2 +-
 nx/source/services/bpc.c          |  2 +-
 nx/source/services/fs.c           | 88 ++++++++++++++++++++++++++++++-
 nx/source/services/set.c          |  2 +-
 6 files changed, 103 insertions(+), 6 deletions(-)

diff --git a/nx/include/switch/services/fs.h b/nx/include/switch/services/fs.h
index ce2341b5..18ee3f02 100644
--- a/nx/include/switch/services/fs.h
+++ b/nx/include/switch/services/fs.h
@@ -139,6 +139,16 @@ typedef enum
     FsSaveDataType_CacheStorage             = 5, ///< [3.0.0+]
 } FsSaveDataType;
 
+typedef enum {
+    FsGameCardAttribute_AutoBoot   = (1 << 0), ///< Causes the cartridge to automatically start on bootup
+    FsGameCardAttribute_ForceError = (1 << 1), ///< Causes NS to throw an error on attempt to load the cartridge
+    FsGameCardAttribute_Repair     = (1 << 2), ///< Indicates that this gamecard is a repair tool.
+} FsGameCardAttribute;
+
+typedef struct {
+    u32 value;
+} FsGameCardHandle;
+
 Result fsInitialize(void);
 void fsExit(void);
 
@@ -242,4 +252,7 @@ void fsEventNotifierClose(FsEventNotifier* e);
 
 // IDeviceOperator
 Result fsDeviceOperatorIsSdCardInserted(FsDeviceOperator* d, bool* out);
+Result fsDeviceOperatorIsGameCardInserted(FsDeviceOperator* d, bool* out);
+Result fsDeviceOperatorGetGameCardHandle(FsDeviceOperator* d, FsGameCardHandle* out);
+Result fsDeviceOperatorGetGameCardAttribute(FsDeviceOperator* d, const FsGameCardHandle* handle, u8 *out);
 void fsDeviceOperatorClose(FsDeviceOperator* d);
diff --git a/nx/include/switch/services/gpio.h b/nx/include/switch/services/gpio.h
index 271582f2..45402a72 100644
--- a/nx/include/switch/services/gpio.h
+++ b/nx/include/switch/services/gpio.h
@@ -37,4 +37,4 @@ Result gpioPadSetDirection(GpioPadSession *p, GpioDirection dir);
 Result gpioPadGetDirection(GpioPadSession *p, GpioDirection *out);
 Result gpioPadSetValue(GpioPadSession *p, GpioValue val);
 Result gpioPadGetValue(GpioPadSession *p, GpioValue *out);
-void gpioPadClose(GpioPadSession *p);
\ No newline at end of file
+void gpioPadClose(GpioPadSession *p);
diff --git a/nx/include/switch/services/i2c.h b/nx/include/switch/services/i2c.h
index d112f982..29847c78 100644
--- a/nx/include/switch/services/i2c.h
+++ b/nx/include/switch/services/i2c.h
@@ -29,4 +29,4 @@ void i2cExit(void);
 Result i2cOpenSession(I2cSession *out, I2cDevice dev);
 
 Result i2csessionSendAuto(I2cSession *s, void *buf, size_t size, I2cTransactionOption option);
-void i2csessionClose(I2cSession *s);
\ No newline at end of file
+void i2csessionClose(I2cSession *s);
diff --git a/nx/source/services/bpc.c b/nx/source/services/bpc.c
index 22c8d8e5..15e31992 100644
--- a/nx/source/services/bpc.c
+++ b/nx/source/services/bpc.c
@@ -127,4 +127,4 @@ Result bpcGetSleepButtonState(BpcSleepButtonState *out) {
     }
 
     return rc;
-}
\ No newline at end of file
+}
diff --git a/nx/source/services/fs.c b/nx/source/services/fs.c
index 5ef5a941..d84e1eff 100644
--- a/nx/source/services/fs.c
+++ b/nx/source/services/fs.c
@@ -1589,7 +1589,7 @@ void fsEventNotifierClose(FsEventNotifier* e) {
 }
 
 // IDeviceOperator
-Result fsDeviceOperatorIsSdCardInserted(FsDeviceOperator* d, bool* out) {
+static Result _fsDeviceOperatorCheckInserted(FsDeviceOperator* d, u32 cmd_id, bool* out) {
     IpcCommand c;
     ipcInitialize(&c);
 
@@ -1601,7 +1601,7 @@ Result fsDeviceOperatorIsSdCardInserted(FsDeviceOperator* d, bool* out) {
     raw = serviceIpcPrepareHeader(&d->s, &c, sizeof(*raw));
 
     raw->magic = SFCI_MAGIC;
-    raw->cmd_id = 0;
+    raw->cmd_id = cmd_id;
 
     Result rc = serviceIpcDispatch(&d->s);
 
@@ -1626,6 +1626,90 @@ Result fsDeviceOperatorIsSdCardInserted(FsDeviceOperator* d, bool* out) {
     return rc;
 }
 
+Result fsDeviceOperatorIsSdCardInserted(FsDeviceOperator* d, bool* out) {
+    return _fsDeviceOperatorCheckInserted(d, 0, out);
+}
+
+Result fsDeviceOperatorIsGameCardInserted(FsDeviceOperator* d, bool* out) {
+    return _fsDeviceOperatorCheckInserted(d, 200, out);
+}
+
+Result fsDeviceOperatorGetGameCardHandle(FsDeviceOperator* d, FsGameCardHandle* out) {
+    IpcCommand c;
+    ipcInitialize(&c);
+
+    struct {
+        u64 magic;
+        u64 cmd_id;
+    } *raw;
+
+    raw = serviceIpcPrepareHeader(&d->s, &c, sizeof(*raw));
+
+    raw->magic = SFCI_MAGIC;
+    raw->cmd_id = 202;
+
+    Result rc = serviceIpcDispatch(&d->s);
+
+    if (R_SUCCEEDED(rc)) {
+        IpcParsedCommand r;
+        struct {
+            u64 magic;
+            u64 result;
+            u32 handle;
+        } *resp;
+
+        serviceIpcParse(&d->s, &r, sizeof(*resp));
+        resp = r.Raw;
+
+        rc = resp->result;
+
+        if (R_SUCCEEDED(rc)) {
+            out->value = resp->handle;
+        }
+    }
+
+    return rc;
+}
+
+Result fsDeviceOperatorGetGameCardAttribute(FsDeviceOperator* d, const FsGameCardHandle* handle, u8 *out) {
+    IpcCommand c;
+    ipcInitialize(&c);
+
+    struct {
+        u64 magic;
+        u64 cmd_id;
+        u32 handle;
+    } *raw;
+
+    raw = serviceIpcPrepareHeader(&d->s, &c, sizeof(*raw));
+
+    raw->magic = SFCI_MAGIC;
+    raw->cmd_id = 205;
+    raw->handle = handle->value;
+
+    Result rc = serviceIpcDispatch(&d->s);
+
+    if (R_SUCCEEDED(rc)) {
+        IpcParsedCommand r;
+        struct {
+            u64 magic;
+            u64 result;
+            u8 attr;
+        } *resp;
+
+        serviceIpcParse(&d->s, &r, sizeof(*resp));
+        resp = r.Raw;
+
+        rc = resp->result;
+
+        if (R_SUCCEEDED(rc)) {
+            *out = resp->attr;
+        }
+    }
+
+    return rc;
+}
+
 void fsDeviceOperatorClose(FsDeviceOperator* d) {
     serviceClose(&d->s);
 }
diff --git a/nx/source/services/set.c b/nx/source/services/set.c
index a2d08d60..7d67d5c7 100644
--- a/nx/source/services/set.c
+++ b/nx/source/services/set.c
@@ -685,4 +685,4 @@ Result setsysGetFatalDirtyFlags(u64 *flags_0, u64 *flags_1) {
     }
 
     return rc;
-}
\ No newline at end of file
+}