]> Chaos Git - corbenik/ctrulib.git/commitdiff
Add pxi:dev service.
authorSteven Smith <Steveice10@gmail.com>
Tue, 31 May 2016 21:50:27 +0000 (14:50 -0700)
committerSteven Smith <Steveice10@gmail.com>
Tue, 31 May 2016 22:29:09 +0000 (15:29 -0700)
libctru/include/3ds/services/pxidev.h [new file with mode: 0644]
libctru/source/services/pxidev.c [new file with mode: 0644]

diff --git a/libctru/include/3ds/services/pxidev.h b/libctru/include/3ds/services/pxidev.h
new file mode 100644 (file)
index 0000000..96144e8
--- /dev/null
@@ -0,0 +1,79 @@
+/**
+ * @file pxidev.h
+ * @brief Gamecard PXI service.
+ */
+#pragma once
+
+#include <3ds/services/fs.h>
+
+/// Card SPI wait operation type.
+typedef enum {
+       WAIT_NONE          = 0, ///< Do not wait.
+       WAIT_SLEEP         = 1, ///< Sleep for the specified number of nanoseconds.
+       WAIT_IREQ_RETURN   = 2, ///< Wait for IREQ, return if timeout.
+       WAIT_IREQ_CONTINUE = 3  ///< Wait for IREQ, continue if timeout.
+} PXIDEV_WaitType;
+
+/// Card SPI register deassertion type.
+typedef enum {
+       DEASSERT_NONE        = 0, ///< Do not deassert.
+       DEASSERT_BEFORE_WAIT = 1, ///< Deassert before waiting.
+       DEASSERT_AFTER_WAIT  = 2  ///< Deassert after waiting.
+} PXIDEV_DeassertType;
+
+/// Card SPI transfer buffer.
+typedef struct {
+       void* ptr;         ///< Data pointer.
+       u32 size;          ///< Data size.
+       u8 transferOption; ///< Transfer options. See @ref pxiDevMakeTransferOption
+       u64 waitOperation; ///< Wait operation. See @ref pxiDevMakeWaitOperation
+} PXIDEV_SPIBuffer;
+
+/// Initializes pxi:dev.
+Result pxiDevInit(void);
+
+/// Shuts down pxi:dev.
+void pxiDevExit(void);
+
+/**
+ * @brief Creates a packed card SPI transfer option value.
+ * @param baudRate Baud rate to use when transferring.
+ * @param busMode Bus mode to use when transferring.
+ * @return A packed card SPI transfer option value.
+ */
+static inline u8 pxiDevMakeTransferOption(FS_CardSpiBaudRate baudRate, FS_CardSpiBusMode busMode)
+{
+       return (baudRate & 0x3F) | ((busMode & 0x3) << 6);
+}
+
+/**
+ * @brief Creates a packed card SPI wait operation value.
+ * @param waitType Type of wait to perform.
+ * @param deassertType Type of register deassertion to perform.
+ * @param timeout Timeout, in nanoseconds, to wait, if applicable.
+ * @return A packed card SPI wait operation value.
+ */
+static inline u64 pxiDevMakeWaitOperation(PXIDEV_WaitType waitType, PXIDEV_DeassertType deassertType, u64 timeout)
+{
+       return (waitType & 0xF) | ((deassertType & 0xF) << 4) | ((timeout & 0xFFFFFFFFFFFFFF) << 8);
+}
+
+/**
+ * @brief Performs multiple card SPI writes and reads.
+ * @param header Header to lead the transfers with. Must be, at most, 8 bytes in size.
+ * @param writeBuffer1 Buffer to make first transfer from.
+ * @param readBuffer1 Buffer to receive first response to.
+ * @param writeBuffer2 Buffer to make second transfer from.
+ * @param readBuffer2 Buffer to receive second response to.
+ * @param footer Footer to follow the transfers with. Must be, at most, 8 bytes in size. Wait operation is unused.
+ */
+Result PXIDEV_SPIMultiWriteRead(PXIDEV_SPIBuffer* header, PXIDEV_SPIBuffer* writeBuffer1, PXIDEV_SPIBuffer* readBuffer1, PXIDEV_SPIBuffer* writeBuffer2, PXIDEV_SPIBuffer* readBuffer2, PXIDEV_SPIBuffer* footer);
+
+/**
+ * @brief Performs a single card SPI write and read.
+ * @param bytesRead Pointer to output the number of bytes received to.
+ * @param initialWaitOperation Wait operation to perform before transferring data.
+ * @param writeBuffer Buffer to transfer data from.
+ * @param readBuffer Buffer to receive data to.
+ */
+Result PXIDEV_SPIWriteRead(u32* bytesRead, u64 initialWaitOperation, PXIDEV_SPIBuffer* writeBuffer, PXIDEV_SPIBuffer* readBuffer);
diff --git a/libctru/source/services/pxidev.c b/libctru/source/services/pxidev.c
new file mode 100644 (file)
index 0000000..55d608c
--- /dev/null
@@ -0,0 +1,101 @@
+#include <string.h>
+#include <3ds/types.h>
+#include <3ds/result.h>
+#include <3ds/svc.h>
+#include <3ds/srv.h>
+#include <3ds/synchronization.h>
+#include <3ds/services/pxidev.h>
+#include <3ds/ipc.h>
+
+static Handle pxiDevHandle;
+static int pxiDevRefCount;
+
+Result pxiDevInit(void)
+{
+       Result ret;
+
+       if (AtomicPostIncrement(&pxiDevRefCount)) return 0;
+
+       ret = srvGetServiceHandle(&pxiDevHandle, "pxi:dev");
+       if (R_FAILED(ret)) AtomicDecrement(&pxiDevRefCount);
+
+       return ret;
+}
+
+void pxiDevExit(void)
+{
+       if (AtomicDecrement(&pxiDevRefCount)) return;
+       svcCloseHandle(pxiDevHandle);
+}
+
+Result PXIDEV_SPIMultiWriteRead(PXIDEV_SPIBuffer* header, PXIDEV_SPIBuffer* writeBuffer1, PXIDEV_SPIBuffer* readBuffer1, PXIDEV_SPIBuffer* writeBuffer2, PXIDEV_SPIBuffer* readBuffer2, PXIDEV_SPIBuffer* footer)
+{
+       Result ret=0;
+       u32 *cmdbuf = getThreadCommandBuffer();
+
+       cmdbuf[0] = IPC_MakeHeader(0xD,26,8); // 0x000D0688
+       memcpy(&cmdbuf[1], header->ptr, header->size);
+       cmdbuf[3] = header->size;
+       cmdbuf[4] = header->transferOption;
+       cmdbuf[5] = (u32) (header->waitOperation & 0xFFFFFFFF);
+       cmdbuf[6] = (u32) ((header->waitOperation >> 32) & 0xFFFFFFFF);
+       cmdbuf[7] = writeBuffer1->size;
+       cmdbuf[8] = writeBuffer1->transferOption;
+       cmdbuf[9] = (u32) (writeBuffer1->waitOperation & 0xFFFFFFFF);
+       cmdbuf[10] = (u32) ((writeBuffer1->waitOperation >> 32) & 0xFFFFFFFF);
+       cmdbuf[11] = readBuffer1->size;
+       cmdbuf[12] = readBuffer1->transferOption;
+       cmdbuf[13] = (u32) (readBuffer1->waitOperation & 0xFFFFFFFF);
+       cmdbuf[14] = (u32) ((readBuffer1->waitOperation >> 32) & 0xFFFFFFFF);
+       cmdbuf[15] = writeBuffer2->size;
+       cmdbuf[16] = writeBuffer2->transferOption;
+       cmdbuf[17] = (u32) (writeBuffer2->waitOperation & 0xFFFFFFFF);
+       cmdbuf[18] = (u32) ((writeBuffer2->waitOperation >> 32) & 0xFFFFFFFF);
+       cmdbuf[19] = readBuffer2->size;
+       cmdbuf[20] = readBuffer2->transferOption;
+       cmdbuf[21] = (u32) (readBuffer2->waitOperation & 0xFFFFFFFF);
+       cmdbuf[22] = (u32) ((readBuffer2->waitOperation >> 32) & 0xFFFFFFFF);
+       memcpy(&cmdbuf[23], footer->ptr, footer->size);
+       cmdbuf[25] = footer->size;
+       cmdbuf[26] = footer->transferOption;
+       cmdbuf[27] = IPC_Desc_PXIBuffer(writeBuffer1->size, 0, true);
+       cmdbuf[28] = (u32) writeBuffer1->ptr;
+       cmdbuf[29] = IPC_Desc_PXIBuffer(writeBuffer2->size, 1, true);
+       cmdbuf[30] = (u32) writeBuffer2->ptr;
+       cmdbuf[31] = IPC_Desc_PXIBuffer(readBuffer1->size, 2, false);
+       cmdbuf[32] = (u32) readBuffer1->ptr;
+       cmdbuf[33] = IPC_Desc_PXIBuffer(readBuffer2->size, 3, false);
+       cmdbuf[34] = (u32) readBuffer2->ptr;
+
+       if (R_FAILED(ret = svcSendSyncRequest(pxiDevHandle))) return ret;
+
+       return (Result)cmdbuf[1];
+}
+
+Result PXIDEV_SPIWriteRead(u32* bytesRead, u64 initialWaitOperation, PXIDEV_SPIBuffer* writeBuffer, PXIDEV_SPIBuffer* readBuffer)
+{
+       Result ret=0;
+       u32 *cmdbuf = getThreadCommandBuffer();
+
+       cmdbuf[0] = IPC_MakeHeader(0xE,10,4); // 0x000E0284
+       cmdbuf[1] = (u32) (initialWaitOperation & 0xFFFFFFFF);
+       cmdbuf[2] = (u32) ((initialWaitOperation >> 32) & 0xFFFFFFFF);
+       cmdbuf[3] = writeBuffer->size;
+       cmdbuf[4] = writeBuffer->transferOption;
+       cmdbuf[5] = (u32) (writeBuffer->waitOperation & 0xFFFFFFFF);
+       cmdbuf[6] = (u32) ((writeBuffer->waitOperation >> 32) & 0xFFFFFFFF);
+       cmdbuf[7] = readBuffer->size;
+       cmdbuf[8] = readBuffer->transferOption;
+       cmdbuf[9] = (u32) (readBuffer->waitOperation & 0xFFFFFFFF);
+       cmdbuf[10] = (u32) ((readBuffer->waitOperation >> 32) & 0xFFFFFFFF);
+       cmdbuf[11] = IPC_Desc_PXIBuffer(writeBuffer->size, 0, true);
+       cmdbuf[12] = (u32) writeBuffer->ptr;
+       cmdbuf[13] = IPC_Desc_PXIBuffer(readBuffer->size, 1, false);
+       cmdbuf[14] = (u32) readBuffer->ptr;
+
+       if (R_FAILED(ret = svcSendSyncRequest(pxiDevHandle))) return ret;
+
+       if (bytesRead) *bytesRead = cmdbuf[2];
+
+       return (Result)cmdbuf[1];
+}