Merge branch 'master' of github.com:smealum/ctrulib
This commit is contained in:
commit
c7be1e415f
@ -177,10 +177,7 @@ int main()
|
||||
gspWaitForPSC0();
|
||||
gfxSwapBuffersGpu();
|
||||
|
||||
APP_STATUS status;
|
||||
while((status=aptGetStatus())!=APP_EXITING)
|
||||
{
|
||||
if(status==APP_RUNNING)
|
||||
while(aptMainLoop())
|
||||
{
|
||||
demoControls();
|
||||
|
||||
@ -196,7 +193,6 @@ int main()
|
||||
gfxSwapBuffersGpu();
|
||||
GX_SetDisplayTransfer(gxCmdBuf, (u32*)gpuOut, 0x019001E0, (u32*)gfxGetFramebuffer(GFX_TOP, GFX_LEFT, NULL, NULL), 0x019001E0, 0x01001000);
|
||||
gspWaitForPPF();
|
||||
}
|
||||
gspWaitForVBlank();
|
||||
}
|
||||
|
||||
|
@ -24,10 +24,7 @@ int main()
|
||||
|
||||
MIC_Initialize(sharedmem, sharedmem_size, control, 0, 3, 1, 1);//See mic.h.
|
||||
|
||||
APP_STATUS status;
|
||||
while((status=aptGetStatus())!=APP_EXITING)
|
||||
{
|
||||
if(status==APP_RUNNING)
|
||||
while(aptMainLoop())
|
||||
{
|
||||
framebuf = gfxGetFramebuffer(GFX_TOP, GFX_LEFT, NULL, NULL);
|
||||
hidScanInput();
|
||||
@ -69,15 +66,6 @@ int main()
|
||||
|
||||
gfxFlushBuffers();
|
||||
gfxSwapBuffers();
|
||||
}
|
||||
else if(status == APP_SUSPENDING)
|
||||
{
|
||||
aptReturnToMenu();
|
||||
}
|
||||
else if(status == APP_SLEEPMODE)
|
||||
{
|
||||
aptWaitStatusEvent();
|
||||
}
|
||||
gspWaitForVBlank();
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
@ -69,3 +70,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. 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);
|
||||
|
||||
|
@ -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);
|
||||
|
802
libctru/source/sdmc_dev.c
Normal file
802
libctru/source/sdmc_dev.c
Normal file
@ -0,0 +1,802 @@
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/iosupport.h>
|
||||
#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 = ARCH_SDMC,
|
||||
.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 new offset 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 file->offset;
|
||||
}
|
||||
|
||||
/*! 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 file 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;
|
||||
}
|
@ -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;
|
||||
|
||||
|
@ -14,6 +14,12 @@ extern u32 __system_runflags;
|
||||
|
||||
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];
|
||||
@ -32,6 +38,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 +332,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);
|
||||
|
||||
@ -364,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];
|
||||
@ -439,8 +488,10 @@ void aptSetStatusPower(u32 status)
|
||||
|
||||
void aptOpenSession()
|
||||
{
|
||||
//Result ret;
|
||||
|
||||
svcWaitSynchronization(aptLockHandle, U64_MAX);
|
||||
srvGetServiceHandle(&aptuHandle, "APT:U");
|
||||
__apt_initservicehandle();
|
||||
}
|
||||
|
||||
void aptCloseSession()
|
||||
@ -768,3 +819,63 @@ 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 = 0;
|
||||
if(ret==0)*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 = 0;
|
||||
if(ret==0)*out=cmdbuf[2];
|
||||
}
|
||||
|
||||
return cmdbuf[1];
|
||||
}
|
||||
|
||||
Result APT_CheckNew3DS(Handle* handle, u8 *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;
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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.
|
||||
|
@ -104,6 +104,33 @@ 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
|
||||
svcCreateMemoryBlock:
|
||||
|
Loading…
Reference in New Issue
Block a user