From 0570a8c02c9794d8f63fc934ef8b0fb9a82b6043 Mon Sep 17 00:00:00 2001 From: profi200 Date: Thu, 30 Oct 2014 19:09:09 +0100 Subject: [PATCH 01/10] Fixed cmds --- libctru/source/services/am.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libctru/source/services/am.c b/libctru/source/services/am.c index aa57541..dc16ba9 100644 --- a/libctru/source/services/am.c +++ b/libctru/source/services/am.c @@ -95,7 +95,7 @@ Result AM_CancelCIAInstall(Handle *ciahandle) Result ret = 0; u32 *cmdbuf = getThreadCommandBuffer(); - cmdbuf[0] = 0x04050002; + cmdbuf[0] = 0x04040002; cmdbuf[1] = 0x10; cmdbuf[2] = *ciahandle; @@ -109,7 +109,7 @@ Result AM_FinishCiaInstall(u8 mediatype, Handle *ciahandle) Result ret = 0; u32 *cmdbuf = getThreadCommandBuffer(); - cmdbuf[0] = 0x04040002; + cmdbuf[0] = 0x04050002; cmdbuf[1] = 0x10; cmdbuf[2] = *ciahandle; From a9d2f7b97f765d19bfd9acc00df9f090cf63c77c Mon Sep 17 00:00:00 2001 From: mtheall Date: Thu, 30 Oct 2014 13:34:13 -0500 Subject: [PATCH 02/10] start sdmc devoptab --- libctru/source/sdmc_dev.c | 802 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 802 insertions(+) create mode 100644 libctru/source/sdmc_dev.c diff --git a/libctru/source/sdmc_dev.c b/libctru/source/sdmc_dev.c new file mode 100644 index 0000000..98be3c5 --- /dev/null +++ b/libctru/source/sdmc_dev.c @@ -0,0 +1,802 @@ +#include +#include +#include +#include +#include <3ds.h> + +/*! @internal + * + * @file sdmc_dev.c + * + * SDMC Device + */ + +static int sdmc_open(struct _reent *r, void *fileStruct, const char *path, int flags, int mode); +static int sdmc_close(struct _reent *r, int fd); +static ssize_t sdmc_write(struct _reent *r, int fd, const char *ptr, size_t len); +static ssize_t sdmc_read(struct _reent *r, int fd, char *ptr, size_t len); +static off_t sdmc_seek(struct _reent *r, int fd, off_t pos, int dir); +static int sdmc_fstat(struct _reent *r, int fd, struct stat *st); +static int sdmc_stat(struct _reent *r, const char *file, struct stat *st); +static int sdmc_link(struct _reent *r, const char *existing, const char *newLink); +static int sdmc_unlink(struct _reent *r, const char *name); +static int sdmc_chdir(struct _reent *r, const char *name); +static int sdmc_rename(struct _reent *r, const char *oldName, const char *newName); +static int sdmc_mkdir(struct _reent *r, const char *path, int mode); +static DIR_ITER* sdmc_diropen(struct _reent *r, DIR_ITER *dirState, const char *path); +static int sdmc_dirreset(struct _reent *r, DIR_ITER *dirState); +static int sdmc_dirnext(struct _reent *r, DIR_ITER *dirState, char *filename, struct stat *filestat); +static int sdmc_dirclose(struct _reent *r, DIR_ITER *dirState); +static int sdmc_statvfs(struct _reent *r, const char *path, struct statvfs *buf); +static int sdmc_ftruncate(struct _reent *r, int fd, off_t len); +static int sdmc_fsync(struct _reent *r, int fd); +static int sdmc_chmod(struct _reent *r, const char *path, mode_t mode); +static int sdmc_fchmod(struct _reent *r, int fd, mode_t mode); + +/*! @cond INTERNAL */ + +/*! Open file struct */ +typedef struct +{ + Handle fd; /*! CTRU handle */ + int flags; /*! Flags used in open(2) */ + u64 offset; /*! Current file offset */ +} sdmc_file_t; + +/*! Open directory struct */ +typedef struct +{ + Handle fd; /*! CTRU handle */ + FS_dirent entry_data; /*! Temporary storage for reading entries */ +} sdmc_dir_t; + +/*! SDMC devoptab */ +static devoptab_t +sdmc_devoptab = +{ + .name = "sdmc", + .structSize = sizeof(sdmc_file_t), + .open_r = sdmc_open, + .close_r = sdmc_close, + .write_r = sdmc_write, + .read_r = sdmc_read, + .seek_r = sdmc_seek, + .fstat_r = sdmc_fstat, + .stat_r = sdmc_stat, + .link_r = sdmc_link, + .unlink_r = sdmc_unlink, + .chdir_r = sdmc_chdir, + .rename_r = sdmc_rename, + .mkdir_r = sdmc_mkdir, + .dirStateSize = sizeof(sdmc_dir_t), + .diropen_r = sdmc_diropen, + .dirreset_r = sdmc_dirreset, + .dirnext_r = sdmc_dirnext, + .dirclose_r = sdmc_dirclose, + .statvfs_r = sdmc_statvfs, + .ftruncate_r = sdmc_ftruncate, + .fsync_r = sdmc_fsync, + .deviceData = NULL, + .chmod_r = sdmc_chmod, + .fchmod_r = sdmc_fchmod, +}; + +/*! SDMC archive handle */ +static FS_archive sdmcArchive = +{ + .id = 0x00000009, + .lowPath = + { + .type = PATH_EMPTY, + .size = 1, + .data = (u8*)"", + }, +}; + +/*! @endcond */ + +/*! Initialize SDMC device */ +Result sdmcInit(void) +{ + Result rc; + + rc = FSUSER_OpenArchive(NULL, &sdmcArchive); + if(rc == 0) + AddDevice(&sdmc_devoptab); + + return rc; +} + +/*! Clean up SDMC device */ +Result sdmcExit(void) +{ + Result rc; + + rc = FSUSER_CloseArchive(NULL, &sdmcArchive); + if(rc == 0) + RemoveDevice("sdmc"); + + return rc; +} + +/*! Open a file + * + * @param[in,out] r newlib reentrancy struct + * @param[out] fileStruct Pointer to file struct to fill in + * @param[in] path Path to open + * @param[in] flags Open flags from open(2) + * @param[in] mode Permissions to set on create + * + * @returns 0 for success + * @returns -1 for error + */ +static int +sdmc_open(struct _reent *r, + void *fileStruct, + const char *path, + int flags, + int mode) +{ + Handle fd; + Result rc; + u32 sdmc_flags = 0; + u32 attributes = FS_ATTRIBUTE_NONE; + + /* get pointer to our data */ + sdmc_file_t *file = (sdmc_file_t*)fileStruct; + + /* check access mode */ + switch(flags & O_ACCMODE) + { + /* read-only: do not allow O_APPEND */ + case O_RDONLY: + sdmc_flags |= FS_OPEN_READ; + if(flags & O_APPEND) + { + r->_errno = EINVAL; + return -1; + } + break; + + /* write-only */ + case O_WRONLY: + sdmc_flags |= FS_OPEN_WRITE; + break; + + /* read and write */ + case O_RDWR: + sdmc_flags |= (FS_OPEN_READ | FS_OPEN_WRITE); + break; + + /* an invalid option was supplied */ + default: + r->_errno = EINVAL; + return -1; + } + + /* create file */ + if(flags & O_CREAT) + sdmc_flags |= FS_OPEN_CREATE; + + /* TODO: Test O_EXCL. */ + + /* set attributes */ + if(!(mode & S_IWUSR)) + attributes |= FS_ATTRIBUTE_READONLY; + + /* open the file */ + rc = FSUSER_OpenFile(NULL, &fd, sdmcArchive, FS_makePath(PATH_CHAR, path), + sdmc_flags, attributes); + if(rc == 0) + { + file->fd = fd; + file->flags = (flags & (O_ACCMODE|O_APPEND|O_SYNC)); + file->offset = 0; + return 0; + } + + r->_errno = rc; + return -1; +} + +/*! Close an open file + * + * @param[in,out] r newlib reentrancy struct + * @param[in] fd Pointer to sdmc_file_t + * + * @returns 0 for success + * @returns -1 for error + */ +static int +sdmc_close(struct _reent *r, + int fd) +{ + Result rc; + + /* get pointer to our data */ + sdmc_file_t *file = (sdmc_file_t*)fd; + + rc = FSFILE_Close(file->fd); + if(rc == 0) + return 0; + + r->_errno = rc; + return -1; +} + +/*! Write to an open file + * + * @param[in,out] r newlib reentrancy struct + * @param[in,out] fd Pointer to sdmc_file_t + * @param[in] ptr Pointer to data to write + * @param[in] len Length of data to write + * + * @returns number of bytes written + * @returns -1 for error + */ +static ssize_t +sdmc_write(struct _reent *r, + int fd, + const char *ptr, + size_t len) +{ + Result rc; + u32 bytes; + u32 sync = 0; + u64 offset; + + /* get pointer to our data */ + sdmc_file_t *file = (sdmc_file_t*)fd; + + /* check that the file was opened with write access */ + if((file->flags & O_ACCMODE) == O_RDONLY) + { + r->_errno = EBADF; + return -1; + } + + /* check if this is synchronous or not */ + if(file->flags & O_SYNC) + sync = 0x10001; + + /* initialize offset */ + offset = file->offset; + if(file->flags & O_APPEND) + { + /* append means write from the end of the file */ + rc = FSFILE_GetSize(file->fd, &offset); + if(rc != 0) + { + r->_errno = rc; + return -1; + } + } + + /* TODO: Copy to internal buffer and write in chunks. + * You cannot write from read-only memory. + */ + + /* write the data */ + rc = FSFILE_Write(file->fd, &bytes, offset, (u32*)ptr, (u32)len, sync); + if(rc == 0) + { + /* update current file offset; if O_APPEND, this moves it to the + * new end-of-file + */ + file->offset = offset + bytes; + return (ssize_t)bytes; + } + + r->_errno = rc; + return -1; +} + +/*! Read from an open file + * + * @param[in,out] r newlib reentrancy struct + * @param[in,out] fd Pointer to sdmc_file_t + * @param[out] ptr Pointer to buffer to read into + * @param[in] len Length of data to read + * + * @returns number of bytes read + * @returns -1 for error + */ +static ssize_t +sdmc_read(struct _reent *r, + int fd, + char *ptr, + size_t len) +{ + Result rc; + u32 bytes; + + /* get pointer to our data */ + sdmc_file_t *file = (sdmc_file_t*)fd; + + /* check that the file was opened with read access */ + if((file->flags & O_ACCMODE) == O_WRONLY) + { + r->_errno = EBADF; + return -1; + } + + /* read the data */ + rc = FSFILE_Read(file->fd, &bytes, file->offset, (u32*)ptr, (u32)len); + if(rc == 0) + { + /* update current file offset */ + file->offset += bytes; + return (ssize_t)bytes; + } + + r->_errno = rc; + return -1; +} + +/*! Update an open file's current offset + * + * @param[in,out] r newlib reentrancy struct + * @param[in,out] fd Pointer to sdmc_file_t + * @param[in] pos Offset to seek to + * @param[in] whence Where to seek from + * + * @returns 0 for success + * @returns -1 for error + */ +static off_t +sdmc_seek(struct _reent *r, + int fd, + off_t pos, + int whence) +{ + Result rc; + u64 offset; + + /* get pointer to our data */ + sdmc_file_t *file = (sdmc_file_t*)fd; + + /* find the offset to see from */ + switch(whence) + { + /* set absolute position; start offset is 0 */ + case SEEK_SET: + offset = 0; + break; + + /* set position relative to the current position */ + case SEEK_CUR: + offset = file->offset; + break; + + /* set position relative to the end of the file */ + case SEEK_END: + rc = FSFILE_GetSize(file->fd, &offset); + if(rc != 0) + { + r->_errno = rc; + return -1; + } + break; + + /* an invalid option was provided */ + default: + r->_errno = EINVAL; + return -1; + } + + /* TODO: A better check that prevents overflow. */ + if(pos < 0 && offset < -pos) + { + /* don't allow seek to before the beginning of the file */ + r->_errno = EINVAL; + return -1; + } + + /* update the current offset */ + file->offset = offset + pos; + return 0; +} + +/*! Get file stats from an open file + * + * @param[in,out] r newlib reentrancy struct + * @param[in] fd Pointer to sdmc_file_t + * @param[out] st Pointer to file stats to fill + * + * @returns 0 for success + * @returns -1 for error + */ +static int +sdmc_fstat(struct _reent *r, + int fd, + struct stat *st) +{ + r->_errno = ENOSYS; + return -1; +} + +/*! Get file stats + * + * @param[in,out] r newlib reentrancy struct + * @param[in] file Path to file + * @param[out] st Pointer to file stats to fill + * + * @returns 0 for success + * @returns -1 for error + */ +static int +sdmc_stat(struct _reent *r, + const char *file, + struct stat *st) +{ + r->_errno = ENOSYS; + return -1; +} + +/*! Hard link a file + * + * @param[in,out] r newlib reentrancy struct + * @param[in] existing Path of ile to link + * @param[in] newLink Path of new link + * + * @returns 0 for success + * @returns -1 for error + */ +static int +sdmc_link(struct _reent *r, + const char *existing, + const char *newLink) +{ + r->_errno = ENOSYS; + return -1; +} + +/*! Unlink a file + * + * @param[in,out] r newlib reentrancy struct + * @param[in] name Path of file to unlink + * + * @returns 0 for success + * @returns -1 for error + */ +static int +sdmc_unlink(struct _reent *r, + const char *name) +{ + r->_errno = ENOSYS; + return -1; +} + +/*! Change current working directory + * + * @param[in,out] r newlib reentrancy struct + * @param[in] name Path to new working directory + * + * @returns 0 for success + * @returns -1 for error + */ +static int +sdmc_chdir(struct _reent *r, + const char *name) +{ + r->_errno = ENOSYS; + return -1; +} + +/*! Rename a file + * + * @param[in,out] r newlib reentrancy struct + * @param[in] oldName Path to rename from + * @param[in] newName Path to rename to + * + * @returns 0 for success + * @returns -1 for error + */ +static int +sdmc_rename(struct _reent *r, + const char *oldName, + const char *newName) +{ + r->_errno = ENOSYS; + return -1; +} + +/*! Create a directory + * + * @param[in,out] r newlib reentrancy struct + * @param[in] path Path of directory to create + * @param[in] mode Permissions of created directory + * + * @returns 0 for success + * @returns -1 for error + */ +static int +sdmc_mkdir(struct _reent *r, + const char *path, + int mode) +{ + Result rc; + + /* TODO: Use mode to set directory attributes. */ + + rc = FSUSER_CreateDirectory(NULL, sdmcArchive, FS_makePath(PATH_CHAR, path)); + if(rc == 0) + return 0; + + r->_errno = ENOSYS; + return -1; +} + +/*! Open a directory + * + * @param[in,out] r newlib reentrancy struct + * @param[in] dirState Pointer to open directory state + * @param[in] path Path of directory to open + * + * @returns dirState for success + * @returns NULL for error + */ +static DIR_ITER* +sdmc_diropen(struct _reent *r, + DIR_ITER *dirState, + const char *path) +{ + Handle fd; + Result rc; + + /* get pointer to our data */ + sdmc_dir_t *dir = (sdmc_dir_t*)(dirState->dirStruct); + + /* open the directory */ + rc = FSUSER_OpenDirectory(NULL, &fd, sdmcArchive, FS_makePath(PATH_CHAR, path)); + if(rc == 0) + { + dir->fd = fd; + memset(&dir->entry_data, 0, sizeof(dir->entry_data)); + return dirState; + } + + r->_errno = rc; + return NULL; +} + +/*! Reset an open directory to its intial state + * + * @param[in,out] r newlib reentrancy struct + * @param[in] dirState Pointer to open directory state + * + * @returns 0 for success + * @returns -1 for error + */ +static int +sdmc_dirreset(struct _reent *r, + DIR_ITER *dirState) +{ + r->_errno = ENOSYS; + return -1; +} + +/*! Fetch the next entry of an open directory + * + * @param[in,out] r newlib reentrancy struct + * @param[in] dirState Pointer to open directory state + * @param[out] filename Buffer to store entry name + * @param[out] filestat Buffer to store entry attributes + * + * @returns 0 for success + * @returns -1 for error + */ +static int +sdmc_dirnext(struct _reent *r, + DIR_ITER *dirState, + char *filename, + struct stat *filestat) +{ + Result rc; + u32 entries; + u16 *name; + + /* get pointer to our data */ + sdmc_dir_t *dir = (sdmc_dir_t*)(dirState->dirStruct); + + /* fetch the next entry */ + rc = FSDIR_Read(dir->fd, &entries, 1, &dir->entry_data); + if(rc == 0) + { + if(entries == 0) + { + /* there are no more entries; ENOENT signals end-of-directory */ + r->_errno = ENOENT; + return -1; + } + + /* fill in the stat info */ + filestat->st_ino = 0; + if(dir->entry_data.isDirectory) + filestat->st_mode = S_IFDIR; + else + filestat->st_mode = S_IFREG; + + /* copy the name */ + name = dir->entry_data.name; + while(*name) + *filename++ = *name++; + *filename = 0; + + return 0; + } + + r->_errno = rc; + return -1; +} + +/*! Close an open directory + * + * @param[in,out] r newlib reentrancy struct + * @param[in] dirState Pointer to open directory state + * + * @returns 0 for success + * @returns -1 for error + */ +static int +sdmc_dirclose(struct _reent *r, + DIR_ITER *dirState) +{ + Result rc; + + /* get pointer to our data */ + sdmc_dir_t *dir = (sdmc_dir_t*)(dirState->dirStruct); + + /* close the directory */ + rc = FSDIR_Close(dir->fd); + if(rc == 0) + return 0; + + r->_errno = rc; + return -1; +} + +/*! Get filesystem statistics + * + * @param[in,out] r newlib reentrancy struct + * @param[in] path Path to filesystem to get statistics of + * @param[out] buf Buffer to fill + * + * @returns 0 for success + * @returns -1 for error + */ +static int +sdmc_statvfs(struct _reent *r, + const char *path, + struct statvfs *buf) +{ + Result rc; + u32 clusterSize, numClusters, freeClusters; + u32 writable = 0; + + rc = FSUSER_GetSdmcArchiveResource(NULL, + NULL, + &clusterSize, + &numClusters, + &freeClusters); + + if(rc == 0) + { + buf->f_bsize = clusterSize; + buf->f_frsize = clusterSize; + buf->f_blocks = numClusters; + buf->f_bfree = freeClusters; + buf->f_bavail = freeClusters; + buf->f_files = 0; //??? how to get + buf->f_ffree = freeClusters; + buf->f_favail = freeClusters; + buf->f_fsid = 0; //??? how to get + buf->f_flag = ST_NOSUID; + buf->f_namemax = 0; //??? how to get + + rc = FSUSER_IsSdmcWritable(NULL, &writable); + if(rc != 0 || !writable) + buf->f_flag |= ST_RDONLY; + + return 0; + } + + r->_errno = rc; + return -1; +} + +/*! Truncate an open file + * + * @param[in,out] r newlib reentrancy struct + * @param[in] fd Pointer to sdmc_file_t + * @param[in] len Length to truncate file to + * + * @returns 0 for success + * @returns -1 for error + */ +static int +sdmc_ftruncate(struct _reent *r, + int fd, + off_t len) +{ + Result rc; + + /* get pointer to our data */ + sdmc_file_t *file = (sdmc_file_t*)fd; + + /* make sure length is non-negative */ + if(len < 0) + { + r->_errno = EINVAL; + return -1; + } + + /* set the new file size */ + rc = FSFILE_SetSize(file->fd, len); + if(rc == 0) + return 0; + + r->_errno = rc; + return -1; +} + +/*! Synchronize a file to media + * + * @param[in,out] r newlib reentrancy struct + * @param[in] fd Pointer to sdmc_file_t + * + * @returns 0 for success + * @returns -1 for error + */ +static int +sdmc_fsync(struct _reent *r, + int fd) +{ + Result rc; + + /* get pointer to our data */ + sdmc_file_t *file = (sdmc_file_t*)fd; + + rc = FSFILE_Flush(file->fd); + if(rc == 0) + return 0; + + r->_errno = rc; + return -1; +} + +/*! Change a file's mode + * + * @param[in,out] r newlib reentrancy struct + * @param[in] path Path to file to update + * @param[in] mode New mode to set + * + * @returns 0 for success + * @returns -1 for error + */ +static int +sdmc_chmod(struct _reent *r, + const char *path, + mode_t mode) +{ + r->_errno = ENOSYS; + return -1; +} + +/*! Change an open file's mode + * + * @param[in,out] r newlib reentrancy struct + * @param[in] fd Pointer to sdmc_file_t + * @param[in] mode New mode to set + * + * @returns 0 for success + * @returns -1 for failure + */ +static int +sdmc_fchmod(struct _reent *r, + int fd, + mode_t mode) +{ + r->_errno = ENOSYS; + return -1; +} From 498bc248085cd32ba7f687e34fe58591ae9ddaa2 Mon Sep 17 00:00:00 2001 From: mtheall Date: Thu, 30 Oct 2014 13:49:00 -0500 Subject: [PATCH 03/10] return offset in sdmc_seek --- libctru/source/sdmc_dev.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libctru/source/sdmc_dev.c b/libctru/source/sdmc_dev.c index 98be3c5..e6d5376 100644 --- a/libctru/source/sdmc_dev.c +++ b/libctru/source/sdmc_dev.c @@ -340,7 +340,7 @@ sdmc_read(struct _reent *r, * @param[in] pos Offset to seek to * @param[in] whence Where to seek from * - * @returns 0 for success + * @returns new offset for success * @returns -1 for error */ static off_t @@ -394,7 +394,7 @@ sdmc_seek(struct _reent *r, /* update the current offset */ file->offset = offset + pos; - return 0; + return file->offset; } /*! Get file stats from an open file From c8a3207c424a456e265864ad6b023510c54e5345 Mon Sep 17 00:00:00 2001 From: mtheall Date: Thu, 30 Oct 2014 13:52:30 -0500 Subject: [PATCH 04/10] fix typo --- libctru/source/sdmc_dev.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libctru/source/sdmc_dev.c b/libctru/source/sdmc_dev.c index e6d5376..c823fe6 100644 --- a/libctru/source/sdmc_dev.c +++ b/libctru/source/sdmc_dev.c @@ -436,7 +436,7 @@ sdmc_stat(struct _reent *r, /*! Hard link a file * * @param[in,out] r newlib reentrancy struct - * @param[in] existing Path of ile to link + * @param[in] existing Path of file to link * @param[in] newLink Path of new link * * @returns 0 for success From 0d6365aa2f5ee072ff27d5a6dc64ebd5b0ae5ce4 Mon Sep 17 00:00:00 2001 From: mtheall Date: Thu, 30 Oct 2014 15:40:19 -0500 Subject: [PATCH 05/10] use ARCH_SDMC for archive id --- libctru/source/sdmc_dev.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libctru/source/sdmc_dev.c b/libctru/source/sdmc_dev.c index c823fe6..0c19de1 100644 --- a/libctru/source/sdmc_dev.c +++ b/libctru/source/sdmc_dev.c @@ -84,7 +84,7 @@ sdmc_devoptab = /*! SDMC archive handle */ static FS_archive sdmcArchive = { - .id = 0x00000009, + .id = ARCH_SDMC, .lowPath = { .type = PATH_EMPTY, From c38276e37d57c2781926e49c2ccda32b5324f54b Mon Sep 17 00:00:00 2001 From: StapleButter Date: Fri, 31 Oct 2014 01:17:43 +0100 Subject: [PATCH 06/10] Add timer-related SVC calls. --- libctru/include/3ds/svc.h | 4 ++++ libctru/source/svc.s | 27 +++++++++++++++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/libctru/include/3ds/svc.h b/libctru/include/3ds/svc.h index 1ccf992..6e3ff60 100644 --- a/libctru/include/3ds/svc.h +++ b/libctru/include/3ds/svc.h @@ -48,6 +48,10 @@ s32 svcReleaseMutex(Handle handle); s32 svcCreateEvent(Handle* event, u8 reset_type); s32 svcSignalEvent(Handle handle); s32 svcClearEvent(Handle handle); +s32 svcCreateTimer(Handle* timer, u8 reset_type); +s32 svcSetTimer(Handle timer, s64 initial, s64 interval); +s32 svcCancelTimer(Handle timer); +s32 svcClearTimer(Handle timer); s32 svcCreateMemoryBlock(Handle* memblock, u32 addr, u32 size, MemPerm my_perm, MemPerm other_perm); s32 svcMapMemoryBlock(Handle memblock, u32 addr, MemPerm my_perm, MemPerm other_perm); s32 svcUnmapMemoryBlock(Handle memblock, u32 addr); diff --git a/libctru/source/svc.s b/libctru/source/svc.s index 0d047a4..6dbdddd 100644 --- a/libctru/source/svc.s +++ b/libctru/source/svc.s @@ -103,6 +103,33 @@ svcSignalEvent: svcClearEvent: svc 0x19 bx lr + +.global svcCreateTimer +.type svcCreateTimer, %function +svcCreateTimer: + str r0, [sp,#-4]! + svc 0x1A + ldr r2, [sp], #4 + str r1, [r2] + bx lr + +.global svcSetTimer +.type svcSetTimer, %function +svcSetTimer: + svc 0x1B + bx lr + +.global svcCancelTimer +.type svcCancelTimer, %function +svcCancelTimer: + svc 0x1C + bx lr + +.global svcClearTimer +.type svcClearTimer, %function +svcClearTimer: + svc 0x1D + bx lr .global svcCreateMemoryBlock .type svcCreateMemoryBlock, %function From c8795b1b79e77b1ada88afca3d32a010f5708d49 Mon Sep 17 00:00:00 2001 From: yellows8 Date: Sat, 1 Nov 2014 21:39:18 -0400 Subject: [PATCH 07/10] Added APT CheckNew3DS code. Added code for attempting to use the other APT services when APT:U isn't accessible. --- libctru/include/3ds/services/apt.h | 4 ++ libctru/source/services/apt.c | 70 +++++++++++++++++++++++++++++- 2 files changed, 72 insertions(+), 2 deletions(-) diff --git a/libctru/include/3ds/services/apt.h b/libctru/include/3ds/services/apt.h index cf2fb31..3092f99 100644 --- a/libctru/include/3ds/services/apt.h +++ b/libctru/include/3ds/services/apt.h @@ -69,3 +69,7 @@ Result APT_PrepareToCloseApplication(Handle* handle, u8 a); Result APT_CloseApplication(Handle* handle, u32 a, u32 b, u32 c); Result APT_SetAppCpuTimeLimit(Handle* handle, u32 percent); Result APT_GetAppCpuTimeLimit(Handle* handle, u32 *percent); +Result APT_CheckNew3DS_Application(Handle* handle, u8 *out);//*Application and *System use APT commands 0x01010000 and 0x01020000. Using APT_CheckNew3DS() is recommended, this determines which of those two funcs to use automatically. +Result APT_CheckNew3DS_System(Handle* handle, u8 *out); +Result APT_CheckNew3DS(Handle* handle, u8 *out); + diff --git a/libctru/source/services/apt.c b/libctru/source/services/apt.c index 3b995a8..d13d15e 100644 --- a/libctru/source/services/apt.c +++ b/libctru/source/services/apt.c @@ -14,6 +14,9 @@ extern u32 __system_runflags; NS_APPID currentAppId; +static char *__apt_servicestr = NULL; +static char *__apt_servicenames[3] = {"APT:U", "APT:S", "APT:A"}; + Handle aptLockHandle; Handle aptuHandle; Handle aptEvents[3]; @@ -32,6 +35,29 @@ u32 aptParameters[0x1000/4]; //TEMP static void aptAppStarted(void); +static Result __apt_initservicehandle() +{ + Result ret=0; + u32 i; + + if(__apt_servicestr) + { + return srvGetServiceHandle(&aptuHandle, __apt_servicestr); + } + + for(i=0; i<3; i++) + { + ret = srvGetServiceHandle(&aptuHandle, __apt_servicenames[i]); + if(ret==0) + { + __apt_servicestr = __apt_servicenames[i]; + return ret; + } + } + + return ret; +} + void aptInitCaptureInfo(u32 *ns_capinfo) { u32 tmp=0; @@ -303,7 +329,8 @@ Result aptInit(void) Result ret=0; // Initialize APT stuff, escape load screen. - srvGetServiceHandle(&aptuHandle, "APT:U"); + ret = __apt_initservicehandle(); + if(ret!=0)return ret; if((ret=APT_GetLockHandle(&aptuHandle, 0x0, &aptLockHandle)))return ret; svcCloseHandle(aptuHandle); @@ -439,8 +466,10 @@ void aptSetStatusPower(u32 status) void aptOpenSession() { + //Result ret; + svcWaitSynchronization(aptLockHandle, U64_MAX); - srvGetServiceHandle(&aptuHandle, "APT:U"); + __apt_initservicehandle(); } void aptCloseSession() @@ -768,3 +797,40 @@ Result APT_GetAppCpuTimeLimit(Handle* handle, u32 *percent) return cmdbuf[1]; } + +Result APT_CheckNew3DS_Application(Handle* handle, u8 *out) +{ + if(!handle)handle=&aptuHandle; + + u32* cmdbuf=getThreadCommandBuffer(); + cmdbuf[0]=0x01010000; + + Result ret=0; + if((ret=svcSendSyncRequest(*handle)))return ret; + + if(out)*out=cmdbuf[2]; + + return cmdbuf[1]; +} + +Result APT_CheckNew3DS_System(Handle* handle, u8 *out) +{ + if(!handle)handle=&aptuHandle; + + u32* cmdbuf=getThreadCommandBuffer(); + cmdbuf[0]=0x01020000; + + Result ret=0; + if((ret=svcSendSyncRequest(*handle)))return ret; + + if(out)*out=cmdbuf[2]; + + return cmdbuf[1]; +} + +Result APT_CheckNew3DS(Handle* handle, u8 *out) +{ + if(currentAppId==APPID_APPLICATION)return APT_CheckNew3DS_Application(NULL, out); + return APT_CheckNew3DS_System(NULL, out); +} + From 4e90fbb905f11dc20dc271a171328491aa6edc4f Mon Sep 17 00:00:00 2001 From: yellows8 Date: Sat, 1 Nov 2014 22:11:19 -0400 Subject: [PATCH 08/10] Updated CheckNew3DS code. Now the out value is cleared first, then the out value is only set to the cmdreply data when ret is zero. --- libctru/source/services/apt.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/libctru/source/services/apt.c b/libctru/source/services/apt.c index d13d15e..91e1c17 100644 --- a/libctru/source/services/apt.c +++ b/libctru/source/services/apt.c @@ -808,7 +808,11 @@ Result APT_CheckNew3DS_Application(Handle* handle, u8 *out) Result ret=0; if((ret=svcSendSyncRequest(*handle)))return ret; - if(out)*out=cmdbuf[2]; + if(out) + { + *out = 0; + if(ret==0)*out=cmdbuf[2]; + } return cmdbuf[1]; } @@ -823,7 +827,11 @@ Result APT_CheckNew3DS_System(Handle* handle, u8 *out) Result ret=0; if((ret=svcSendSyncRequest(*handle)))return ret; - if(out)*out=cmdbuf[2]; + if(out) + { + *out = 0; + if(ret==0)*out=cmdbuf[2]; + } return cmdbuf[1]; } From 3135d1c344e59261e0cf0f6fb5dd5a769c0dab2a Mon Sep 17 00:00:00 2001 From: yellows8 Date: Sat, 1 Nov 2014 23:48:35 -0400 Subject: [PATCH 09/10] Updated APT_CheckNew3DS to only use the APT cmds once(which also now calls aptOpenSession/aptCloseSession), then store the output value in a flag which is then used for all future APT_CheckNew3DS calls. Updated HID init/shutdown code to automatically call irrst init/shutdown code when running on new3ds. Updated irrst init code to only do init when it wasn't already initialized, likewise for the irrst shutdown code. --- libctru/include/3ds/services/apt.h | 2 +- libctru/source/services/apt.c | 22 ++++++++++++++++++++-- libctru/source/services/hid.c | 19 ++++++++++++++++++- libctru/source/services/irrst.c | 4 ++++ 4 files changed, 43 insertions(+), 4 deletions(-) diff --git a/libctru/include/3ds/services/apt.h b/libctru/include/3ds/services/apt.h index 3092f99..bec85f7 100644 --- a/libctru/include/3ds/services/apt.h +++ b/libctru/include/3ds/services/apt.h @@ -69,7 +69,7 @@ Result APT_PrepareToCloseApplication(Handle* handle, u8 a); Result APT_CloseApplication(Handle* handle, u32 a, u32 b, u32 c); Result APT_SetAppCpuTimeLimit(Handle* handle, u32 percent); Result APT_GetAppCpuTimeLimit(Handle* handle, u32 *percent); -Result APT_CheckNew3DS_Application(Handle* handle, u8 *out);//*Application and *System use APT commands 0x01010000 and 0x01020000. Using APT_CheckNew3DS() is recommended, this determines which of those two funcs to use automatically. +Result APT_CheckNew3DS_Application(Handle* handle, u8 *out);//*Application and *System use APT commands 0x01010000 and 0x01020000. Using APT_CheckNew3DS() is recommended, this determines which of those two funcs to use automatically. When this is first called(this calls aptOpenSession/aptCloseSession internally), this initializes an internal flag, which is then used for the out val for all future calls. Result APT_CheckNew3DS_System(Handle* handle, u8 *out); Result APT_CheckNew3DS(Handle* handle, u8 *out); diff --git a/libctru/source/services/apt.c b/libctru/source/services/apt.c index 91e1c17..9294f1a 100644 --- a/libctru/source/services/apt.c +++ b/libctru/source/services/apt.c @@ -17,6 +17,9 @@ NS_APPID currentAppId; static char *__apt_servicestr = NULL; static char *__apt_servicenames[3] = {"APT:U", "APT:S", "APT:A"}; +static u32 __apt_new3dsflag_initialized = 0; +static u8 __apt_new3dsflag = 0; + Handle aptLockHandle; Handle aptuHandle; Handle aptEvents[3]; @@ -838,7 +841,22 @@ Result APT_CheckNew3DS_System(Handle* handle, u8 *out) Result APT_CheckNew3DS(Handle* handle, u8 *out) { - if(currentAppId==APPID_APPLICATION)return APT_CheckNew3DS_Application(NULL, out); - return APT_CheckNew3DS_System(NULL, out); + Result ret=0; + + if(__apt_new3dsflag_initialized) + { + *out = __apt_new3dsflag; + return 0; + } + + aptOpenSession(); + if(currentAppId==APPID_APPLICATION)ret = APT_CheckNew3DS_Application(NULL, out); + ret = APT_CheckNew3DS_System(NULL, out); + aptCloseSession(); + + __apt_new3dsflag_initialized = 1; + __apt_new3dsflag = *out; + + return ret; } diff --git a/libctru/source/services/hid.c b/libctru/source/services/hid.c index cc17b68..d48f30c 100644 --- a/libctru/source/services/hid.c +++ b/libctru/source/services/hid.c @@ -21,6 +21,8 @@ static angularRate gRate; Result hidInit(u32* sharedMem) { + u8 val=0; + if(!sharedMem)sharedMem=(u32*)HID_SHAREDMEM_DEFAULT; Result ret=0; @@ -34,9 +36,16 @@ Result hidInit(u32* sharedMem) hidSharedMem=sharedMem; if((ret=svcMapMemoryBlock(hidMemHandle, (u32)hidSharedMem, MEMPERM_READ, 0x10000000)))goto cleanup2; + APT_CheckNew3DS(NULL, &val); + + if(val) + { + ret = irrstInit(NULL); + } + // Reset internal state. kOld = kHeld = kDown = kUp = 0; - return 0; + return ret; cleanup2: svcCloseHandle(hidMemHandle); @@ -48,10 +57,18 @@ cleanup1: void hidExit() { // Unmap HID sharedmem and close handles. + u8 val=0; int i; for(i=0; i<5; i++)svcCloseHandle(hidEvents[i]); svcUnmapMemoryBlock(hidMemHandle, (u32)hidSharedMem); svcCloseHandle(hidMemHandle); svcCloseHandle(hidHandle); + + APT_CheckNew3DS(NULL, &val); + + if(val) + { + irrstExit(); + } } void hidWaitForEvent(HID_Event id, bool nextEvent) diff --git a/libctru/source/services/irrst.c b/libctru/source/services/irrst.c index 87121ac..c7a54ff 100644 --- a/libctru/source/services/irrst.c +++ b/libctru/source/services/irrst.c @@ -17,6 +17,8 @@ static bool irrstUsed = false; Result irrstInit(u32* sharedMem) { + if(irrstUsed)return 0; + if(!sharedMem)sharedMem=(u32*)IRRST_SHAREDMEM_DEFAULT; Result ret=0; @@ -44,6 +46,8 @@ cleanup1: void irrstExit() { + if(!irrstUsed)return; + irrstUsed = false; svcCloseHandle(irrstEvent); // Unmap ir:rst sharedmem and close handles. From 7f10ad40977217caf5b22e62c168e18597d2b8d2 Mon Sep 17 00:00:00 2001 From: fincs Date: Sun, 2 Nov 2014 18:58:37 +0100 Subject: [PATCH 10/10] Add aptMainLoop() for handling APT events in main() --- examples/gpu/source/main.c | 28 +++++------- examples/mic/source/main.c | 70 +++++++++++++----------------- libctru/include/3ds/services/apt.h | 1 + libctru/source/services/apt.c | 19 ++++++++ 4 files changed, 61 insertions(+), 57 deletions(-) diff --git a/examples/gpu/source/main.c b/examples/gpu/source/main.c index 1c06bd5..c059540 100644 --- a/examples/gpu/source/main.c +++ b/examples/gpu/source/main.c @@ -177,26 +177,22 @@ int main() gspWaitForPSC0(); gfxSwapBuffersGpu(); - APP_STATUS status; - while((status=aptGetStatus())!=APP_EXITING) + while(aptMainLoop()) { - if(status==APP_RUNNING) - { - demoControls(); + demoControls(); - GX_SetMemoryFill(gxCmdBuf, (u32*)gpuOut, 0x404040FF, (u32*)&gpuOut[0x2EE00], 0x201, (u32*)gpuDOut, 0x00000000, (u32*)&gpuDOut[0x2EE00], 0x201); - gspWaitForPSC0(); + GX_SetMemoryFill(gxCmdBuf, (u32*)gpuOut, 0x404040FF, (u32*)&gpuOut[0x2EE00], 0x201, (u32*)gpuDOut, 0x00000000, (u32*)&gpuDOut[0x2EE00], 0x201); + gspWaitForPSC0(); - GPUCMD_SetBuffer(gpuCmd, gpuCmdSize, 0); - doFrame1(); - GPUCMD_Finalize(); - GPUCMD_Run(gxCmdBuf); - gspWaitForP3D(); + GPUCMD_SetBuffer(gpuCmd, gpuCmdSize, 0); + doFrame1(); + GPUCMD_Finalize(); + GPUCMD_Run(gxCmdBuf); + gspWaitForP3D(); - gfxSwapBuffersGpu(); - GX_SetDisplayTransfer(gxCmdBuf, (u32*)gpuOut, 0x019001E0, (u32*)gfxGetFramebuffer(GFX_TOP, GFX_LEFT, NULL, NULL), 0x019001E0, 0x01001000); - gspWaitForPPF(); - } + gfxSwapBuffersGpu(); + GX_SetDisplayTransfer(gxCmdBuf, (u32*)gpuOut, 0x019001E0, (u32*)gfxGetFramebuffer(GFX_TOP, GFX_LEFT, NULL, NULL), 0x019001E0, 0x01001000); + gspWaitForPPF(); gspWaitForVBlank(); } diff --git a/examples/mic/source/main.c b/examples/mic/source/main.c index 90205b5..8e6fc11 100644 --- a/examples/mic/source/main.c +++ b/examples/mic/source/main.c @@ -24,60 +24,48 @@ int main() MIC_Initialize(sharedmem, sharedmem_size, control, 0, 3, 1, 1);//See mic.h. - APP_STATUS status; - while((status=aptGetStatus())!=APP_EXITING) + while(aptMainLoop()) { - if(status==APP_RUNNING) + framebuf = gfxGetFramebuffer(GFX_TOP, GFX_LEFT, NULL, NULL); + hidScanInput(); + + if(hidKeysDown() & KEY_A) { - framebuf = gfxGetFramebuffer(GFX_TOP, GFX_LEFT, NULL, NULL); - hidScanInput(); + audiobuf_pos = 0; - if(hidKeysDown() & KEY_A) - { - audiobuf_pos = 0; + CSND_setchannel_playbackstate(0x8, 0);//Stop audio playback. + CSND_sharedmemtype0_cmdupdatestate(0); - CSND_setchannel_playbackstate(0x8, 0);//Stop audio playback. - CSND_sharedmemtype0_cmdupdatestate(0); + MIC_SetRecording(1); - MIC_SetRecording(1); + memset(framebuf, 0x20, 0x46500); + } - memset(framebuf, 0x20, 0x46500); - } + if((hidKeysHeld() & KEY_A) && audiobuf_pos < audiobuf_size) + { + audiobuf_pos+= MIC_ReadAudioData(&audiobuf[audiobuf_pos], audiobuf_size-audiobuf_pos, 1); + if(audiobuf_pos > audiobuf_size)audiobuf_pos = audiobuf_size; - if((hidKeysHeld() & KEY_A) && audiobuf_pos < audiobuf_size) - { - audiobuf_pos+= MIC_ReadAudioData(&audiobuf[audiobuf_pos], audiobuf_size-audiobuf_pos, 1); - if(audiobuf_pos > audiobuf_size)audiobuf_pos = audiobuf_size; + memset(framebuf, 0x60, 0x46500); + } - memset(framebuf, 0x60, 0x46500); - } + if(hidKeysUp() & KEY_A) + { + MIC_SetRecording(0); + GSPGPU_FlushDataCache(NULL, audiobuf, audiobuf_pos); + CSND_playsound(0x8, CSND_LOOP_DISABLE, CSND_ENCODING_PCM16, 16000, (u32*)audiobuf, NULL, audiobuf_pos, 2, 0); - if(hidKeysUp() & KEY_A) - { - MIC_SetRecording(0); - GSPGPU_FlushDataCache(NULL, audiobuf, audiobuf_pos); - CSND_playsound(0x8, CSND_LOOP_DISABLE, CSND_ENCODING_PCM16, 16000, (u32*)audiobuf, NULL, audiobuf_pos, 2, 0); - - memset(framebuf, 0xe0, 0x46500); - - gfxFlushBuffers(); - gfxSwapBuffers(); - - framebuf = gfxGetFramebuffer(GFX_TOP, GFX_LEFT, NULL, NULL); - memset(framebuf, 0xe0, 0x46500); - } + memset(framebuf, 0xe0, 0x46500); gfxFlushBuffers(); gfxSwapBuffers(); + + framebuf = gfxGetFramebuffer(GFX_TOP, GFX_LEFT, NULL, NULL); + memset(framebuf, 0xe0, 0x46500); } - else if(status == APP_SUSPENDING) - { - aptReturnToMenu(); - } - else if(status == APP_SLEEPMODE) - { - aptWaitStatusEvent(); - } + + gfxFlushBuffers(); + gfxSwapBuffers(); gspWaitForVBlank(); } diff --git a/libctru/include/3ds/services/apt.h b/libctru/include/3ds/services/apt.h index bec85f7..a0bfc87 100644 --- a/libctru/include/3ds/services/apt.h +++ b/libctru/include/3ds/services/apt.h @@ -49,6 +49,7 @@ void aptReturnToMenu();//This should be called by the user application when aptG void aptWaitStatusEvent(); void aptSignalReadyForSleep(); NS_APPID aptGetMenuAppID(); +bool aptMainLoop(); // Use like this in your main(): while (aptMainLoop()) { your code here... } Result APT_GetLockHandle(Handle* handle, u16 flags, Handle* lockHandle); Result APT_Initialize(Handle* handle, NS_APPID appId, Handle* eventHandle1, Handle* eventHandle2); diff --git a/libctru/source/services/apt.c b/libctru/source/services/apt.c index 9294f1a..b060ad8 100644 --- a/libctru/source/services/apt.c +++ b/libctru/source/services/apt.c @@ -394,6 +394,25 @@ void aptExit() svcCloseHandle(aptStatusEvent); } +bool aptMainLoop() +{ + for (;;) switch (aptGetStatus()) + { + case APP_RUNNING: + return true; + case APP_SUSPENDING: + aptReturnToMenu(); + break; + case APP_SLEEPMODE: + aptWaitStatusEvent(); + break; + case APP_EXITING: + return false; + default: + break; + } +} + void aptAppStarted() { u8 buf1[4], buf2[4];