From b12825bb9baa8a29694d27d434cfa3d9f1b062a3 Mon Sep 17 00:00:00 2001
From: Christopher Dellman <christopher@dellman.net>
Date: Tue, 9 Jul 2024 22:38:39 -0400
Subject: [PATCH] Added presence IPC command

---
 patches/include/ipc.h        | 162 ++++++++++++++++++++++++++++++-----
 patches/source/flippy_sync.c |  32 +++++++
 patches/source/flippy_sync.h |   4 +-
 3 files changed, 174 insertions(+), 24 deletions(-)

diff --git a/patches/include/ipc.h b/patches/include/ipc.h
index 45d0cfc..bd7fcc9 100644
--- a/patches/include/ipc.h
+++ b/patches/include/ipc.h
@@ -2,16 +2,26 @@
 #include <stddef.h>
 #include <stdint.h>
 
+#define FLIPPY_IPC_MAJORVER = 1;
+#define FLIPPY_IPC_MINORVER = 3;
+
 #define GCN_ALIGNED(type) type __attribute__((aligned(32)))
 
+// Pre-C11: define a fallback mechanism
+#define ASSERT_SIZE_MULTIPLE_OF_32(T) 
+
 //MUST be a multiple of 32 for DMA reasons in the cube
 #define MAX_FILE_NAME 256
 #define FD_IPC_MAXRESP 1024*16
 
+#define FD_BYPASS_EXIT_MAGIC0 0xE3F72BAB
+#define FD_BYPASS_EXIT_MAGIC1 0X72648977
+
 #define IPC_MAGIC 0xAA55F641
 #pragma pack(push,1)
 
 #define IPC_READ_STATUS_RESPONSE_LEN    sizeof(file_status_t)
+#define IPC_FS_INFO_RESPONSE_LEN        sizeof(fs_info_t)
 #define IPC_FILE_READ_RESPONSE_LEN      read_len
 #define IPC_FILE_WRITE_RESPONSE_LEN     0
 #define IPC_FILE_OPEN_RESPONSE_LEN      0
@@ -19,14 +29,26 @@
 #define IPC_FILE_STAT_RESPONSE_LEN      static_assert(0, "STAT format not yet defined");
 #define IPC_FILE_SEEK_RESPONSE_LEN      0
 #define IPC_FILE_UNLINK_RESPONSE_LEN    0
+#define IPC_FILE_MKDIR_RESPONSE_LEN     0
+#define IPC_FILE_RENAME_RESPONSE_LEN    0
 #define IPC_FILE_READDIR_RESPONSE_LEN   sizeof(file_entry_t)
+#define IPC_NET_STATUS_RESPONSE_LEN     sizeof(flippydrive_net_status_t)
+#define IPC_NET_CONFIGURE_RESPONSE_LEN  0
+#define IPC_NET_PRESENCE_RESPONSE_LEN   0
 
-#define IPC_RESERVED0_SIZE 204
+#define IPC_WRITE_PAYLOAD_MAX_LEN       FD_IPC_MAXRESP-32
+
+#define IPC_RESERVED0_SIZE 224
 
 typedef enum {
     IPC_READ_STATUS        = 0x00,
     IPC_SET_DEFAULT_FD     = 0x01, //Purely 2040
+    IPC_RELOAD_CONFIG      = 0x02, //Purely 2040
+    IPC_NET_STATUS         = 0x03,
 
+    IPC_RESET              = 0x05, //Purely 2040
+    IPC_FS_INFO            = 0x06,
+    IPC_FILE_MKDIR         = 0x07,
     IPC_FILE_READ          = 0x08,
     IPC_FILE_WRITE         = 0x09,
     IPC_FILE_OPEN          = 0x0A,
@@ -36,10 +58,12 @@ typedef enum {
     IPC_FILE_UNLINK        = 0x0E,
     IPC_FILE_READDIR       = 0x0F,
 
-    IPC_RESERVED0          = 0x10,
+    IPC_NET_CONFIGURE      = 0x10,
     IPC_FILE_OPEN_FLASH    = 0x11, //Purely 2040
     IPC_FILE_UNLINK_FLASH  = 0x12, //Purely 2040
-    IPC_RESERVED3          = 0x13,
+    IPC_FILE_RENAME        = 0x13,
+
+    IPC_NET_PRESENCE       = 0x14,
 
     IPC_CMD_MAX            = 0x1F
 } ipc_command_type_t;
@@ -49,15 +73,24 @@ typedef struct
     uint32_t result;
     uint64_t fsize;
     uint8_t fd; //Valid after open
-    uint8_t pad[19];
+    uint8_t flags;
+    uint8_t pad[18];
 } file_status_t;
 
+ASSERT_SIZE_MULTIPLE_OF_32(file_status_t);
+
 typedef struct
 {
-    uint8_t data[FD_IPC_MAXRESP-32];
-} file_payload_t;
+    uint32_t result;
+    uint64_t free;
+    uint64_t total;
+    uint8_t pad[12];
+} fs_info_t;
+
+ASSERT_SIZE_MULTIPLE_OF_32(fs_info_t);
 
 enum {
+    IPC_FILE_FLAG_NONE            = 0x00,
     IPC_FILE_FLAG_DISABLECACHE    = 0x01,
     IPC_FILE_FLAG_DISABLEFASTSEEK = 0x02,
     IPC_FILE_FLAG_DISABLESPEEDEMU = 0x04,
@@ -74,6 +107,46 @@ typedef struct {
     uint8_t pad[10];
 } file_entry_t;
 
+ASSERT_SIZE_MULTIPLE_OF_32(file_entry_t);
+
+#define FLIPPYDRIVE_NET_STATE_MASK 0x7
+#define FLIPPYDRIVE_NET_FAIL_MASK  0x8
+
+#define FLIPPYDRIVE_NET_STATE_NONE 0
+#define FLIPPYDRIVE_NET_STATE_LINK 1
+#define FLIPPYDRIVE_NET_STATE_IP   2
+#define FLIPPYDRIVE_NET_STATE_CONNECT 3
+
+typedef struct
+{
+    uint8_t net_flags;
+    uint8_t net_status;
+    char ssid[33];
+    char addrstr[40];
+    uint8_t nm;
+    uint8_t gw[16];
+    uint8_t dns0[16];
+    uint8_t dns1[16];
+
+    uint8_t server[16];
+
+    uint8_t pad[20];
+} flippydrive_net_status_t;
+
+ASSERT_SIZE_MULTIPLE_OF_32(flippydrive_net_status_t);
+
+typedef struct
+{
+    uint8_t presence; //Bit 0 - Online/Active
+    char status[40];
+    char sub_status[40];
+    char sys_state[40];
+
+    uint8_t pad[135];
+} flippydrive_net_presence_t;
+
+ASSERT_SIZE_MULTIPLE_OF_32(flippydrive_net_presence_t);
+
 typedef struct {
     uint32_t magic;
     uint8_t ipc_command_type;
@@ -82,7 +155,7 @@ typedef struct {
     uint8_t subcmd;
     union
     {
-        uint8_t shortpayload[8];
+        uint8_t shortpayload[24];
         __attribute__((packed)) struct
         {
             uint32_t offset;
@@ -91,46 +164,89 @@ typedef struct {
     };
 } ipc_req_header_t;
 
+ASSERT_SIZE_MULTIPLE_OF_32(ipc_req_header_t);
+
+typedef struct
+{
+    ipc_req_header_t hdr;
+    flippydrive_net_presence_t presence;
+} ipc_req_net_presence_t;
+
+ASSERT_SIZE_MULTIPLE_OF_32(ipc_req_net_presence_t);
+
 typedef struct {
     ipc_req_header_t hdr;
     file_entry_t file;
 } ipc_req_open_t;
 
+ASSERT_SIZE_MULTIPLE_OF_32(ipc_req_open_t);
+
 typedef struct {
     //Setup alignment such that the payload is 32-byte aligned for the GCN's DMA
     ipc_req_header_t hdr;
-    uint8_t pad[16];
-    file_payload_t payload;
+    uint8_t payload[IPC_WRITE_PAYLOAD_MAX_LEN];
 } ipc_req_write_t;
 
+ASSERT_SIZE_MULTIPLE_OF_32(ipc_req_write_t);
+
 typedef struct
 {
     ipc_req_header_t hdr;
     file_entry_t file;
 } ipc_req_unlink_t;
 
+ASSERT_SIZE_MULTIPLE_OF_32(ipc_req_unlink_t);
+
+typedef struct
+{
+    ipc_req_header_t hdr;
+    file_entry_t file;
+} ipc_req_mkdir_t;
+
+ASSERT_SIZE_MULTIPLE_OF_32(ipc_req_mkdir_t);
+
+typedef struct
+{
+    ipc_req_header_t hdr;
+    file_entry_t oldfile;
+    file_entry_t newfile;
+} ipc_req_rename_t;
+
+ASSERT_SIZE_MULTIPLE_OF_32(ipc_req_rename_t);
+
 enum file_entry_type_enum {
     FILE_ENTRY_TYPE_FILE = 0,
     FILE_ENTRY_TYPE_DIR = 1,
 
+    FILE_ENTRY_TYPE_BAD = 0xFF,
     FILE_ENTRY_TYPE_MAX = 0xFF
 };
 
 #pragma pack(pop)
 
 static const size_t ipc_payloadlen[IPC_CMD_MAX] = {
-    0, 0, 0, 0, 0, 0, 0, 0, //CMD 0-7
-    0, //FILE_READ
-    0, //FILE_WRITE
-    sizeof(file_entry_t), //FILE_OPEN
-    0, //FILE_CLOSE
-    0, //FILE_STAT
-    0, //FILE_SEEK
-    sizeof(file_entry_t), //FILE_UNLINK
-    0, //READDIR
-
-    IPC_RESERVED0_SIZE, //RESERVED0
-    0, //FILE_OPEN_FLASH is purely internal to RP2040 and has no meaning over IPC
-    0, //FILE_UNLINK_FLASH is purely internal
-};
+    0,                    // Read status
+    0,                    // Set default fd
+    0,                    // reload config
+    0,                    // RESERVED1
+    0,
+    0,                    // RESET
+    0,                    // FS_INFO
+    sizeof(file_entry_t), // FILE_MKDIR
+    0,                    // FILE_READ
+    0,                    // FILE_WRITE
+    sizeof(file_entry_t), // FILE_OPEN
+    0,                    // FILE_CLOSE
+    0,                    // FILE_STAT
+    0,                    // FILE_SEEK
+    sizeof(file_entry_t), // FILE_UNLINK
+    0,                    // READDIR
+
+    IPC_RESERVED0_SIZE,   // RESERVED0
+    0,                    // FILE_OPEN_FLASH is purely internal to RP2040 and has no meaning over IPC
+    0,                    // FILE_UNLINK_FLASH is purely internal
+    sizeof(file_entry_t)*2, // FILE_RENAME
+
+    sizeof(flippydrive_net_presence_t), //IPC_NET_PRESENCE
 
+};
diff --git a/patches/source/flippy_sync.c b/patches/source/flippy_sync.c
index d1e7c32..e9f335c 100644
--- a/patches/source/flippy_sync.c
+++ b/patches/source/flippy_sync.c
@@ -418,4 +418,36 @@ void dvd_custom_bypass() {
         ; // transfer complete register
 
     return;
+}
+
+int dvd_custom_presence(bool playing, const char *status, const char *sub_status)
+{
+    GCN_ALIGNED(flippydrive_net_presence_t) presence = {};
+
+    strncpy(presence.status, status, sizeof(presence.status)-1);
+    strncpy(presence.sub_status, sub_status, sizeof(presence.sub_status)-1);
+
+    presence.presence = playing ? 0x01 : 0x00;
+
+    DCFlushRange(&presence, sizeof(flippydrive_net_presence_t));
+
+    _di_regs[DI_SR] = (DI_SR_BRKINTMASK | DI_SR_TCINTMASK | DI_SR_DEINT | DI_SR_DEINTMASK);
+    _di_regs[DI_CVR] = 0; // clear cover int
+
+    _di_regs[DI_CMDBUF0] = DVD_FLIPPY_FILEAPI_BASE | IPC_FILE_OPEN_FLASH;
+    _di_regs[DI_CMDBUF1] = 0;
+    _di_regs[DI_CMDBUF2] = 0; //TODO this was sizeof(file_entry_t) before for no particular reason
+
+    _di_regs[DI_MAR] = (u32)&presence & 0x1FFFFFFF;
+    _di_regs[DI_LENGTH] = sizeof(flippydrive_net_presence_t);
+    _di_regs[DI_CR] = (DI_CR_RW | DI_CR_DMA | DI_CR_TSTART); // start transfer
+
+    while (_di_regs[DI_CR] & DI_CR_TSTART)
+        ; // transfer complete register
+
+    // check if ERR was asserted
+    if (_di_regs[DI_SR] & DI_SR_DEINT) {
+        return 1;
+    }
+    return 0;
 }
\ No newline at end of file
diff --git a/patches/source/flippy_sync.h b/patches/source/flippy_sync.h
index 1fb1cdb..5197a83 100644
--- a/patches/source/flippy_sync.h
+++ b/patches/source/flippy_sync.h
@@ -51,4 +51,6 @@ int dvd_custom_unlink(char *path);
 int dvd_custom_unlink_flash(char *path);
 int dvd_custom_open(char *path, uint8_t type, uint8_t flags);
 int dvd_custom_open_flash(char *path, uint8_t type, uint8_t flags);
-void dvd_custom_bypass();
\ No newline at end of file
+void dvd_custom_bypass();
+
+int dvd_custom_presence(bool playing, const char *status, const char* sub_status);