abse/gameboy-advance
A tscircuit package created by abse.
- Version
- 0.0.45
- License
- unset
- Stars
- 0
firmware/game-console/filesystem.c
/* Native newlib/FatFs bridge. Firmware heap lives in detected QMI PSRAM. */
#include "ff.h"
#include "hardware/psram.h"
#include "pico/stdlib.h"
#include <errno.h>
#include <fcntl.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
static FIL files[12];
static bool used[12];
static int fail(FRESULT r) {
errno = (r == FR_NO_FILE || r == FR_NO_PATH) ? ENOENT : r == FR_EXIST ? EEXIST : EIO;
return -1;
}
void *_sbrk(int incr) {
static uintptr_t pos = 0;
uintptr_t base = 0x11010000, limit = 0x11000000 + psram_get_size();
if (!psram_is_available()) {
errno = ENOMEM;
return (void *)-1;
}
if (!pos)
pos = base;
uintptr_t next = pos + incr;
if (next < base || next > limit - 65536) {
errno = ENOMEM;
return (void *)-1;
}
void *r = (void *)pos;
pos = next;
return r;
}
int _open(const char *path, int flags, ...) {
for (int i = 0; i < 12; i++)
if (!used[i]) {
BYTE mode = (flags & O_RDWR) ? FA_READ | FA_WRITE
: (flags & O_WRONLY) ? FA_WRITE
: FA_READ;
if (flags & O_CREAT)
mode |= (flags & O_EXCL) ? FA_CREATE_NEW
: (flags & O_TRUNC) ? FA_CREATE_ALWAYS
: FA_OPEN_ALWAYS;
FRESULT r = f_open(&files[i], path, mode);
if (r)
return fail(r);
if (flags & O_APPEND)
f_lseek(&files[i], f_size(&files[i]));
used[i] = true;
return i + 3;
}
errno = EMFILE;
return -1;
}
int _close(int fd) {
if (fd < 3)
return 0;
if (fd >= 15 || !used[fd - 3]) {
errno = EBADF;
return -1;
}
FRESULT r = f_close(&files[fd - 3]);
used[fd - 3] = false;
return r ? fail(r) : 0;
}
int _read(int fd, char *buf, int n) {
if (fd == 0) {
int i = 0;
for (; i < n; i++) {
int c = getchar_timeout_us(i ? 0 : 1000);
if (c < 0)
break;
buf[i] = c;
}
return i;
}
if (fd < 3 || fd >= 15 || !used[fd - 3]) {
errno = EBADF;
return -1;
}
UINT got;
FRESULT r = f_read(&files[fd - 3], buf, n, &got);
return r ? fail(r) : got;
}
int _write(int fd, const char *buf, int n) {
if (fd == 1 || fd == 2) {
for (int i = 0; i < n; i++)
putchar_raw(buf[i]);
return n;
}
if (fd < 3 || fd >= 15 || !used[fd - 3]) {
errno = EBADF;
return -1;
}
UINT put;
FRESULT r = f_write(&files[fd - 3], buf, n, &put);
return r ? fail(r) : put;
}
off_t _lseek(int fd, off_t pos, int whence) {
if (fd < 3 || fd >= 15 || !used[fd - 3]) {
errno = EBADF;
return -1;
}
FIL *f = &files[fd - 3];
int64_t dest = pos;
if (whence == SEEK_CUR)
dest += f_tell(f);
if (whence == SEEK_END)
dest += f_size(f);
if (dest < 0) {
errno = EINVAL;
return -1;
}
FRESULT r = f_lseek(f, dest);
return r ? fail(r) : (off_t)f_tell(f);
}
int _fstat(int fd, struct stat *s) {
memset(s, 0, sizeof(*s));
if (fd < 3) {
s->st_mode = S_IFCHR;
return 0;
}
if (fd >= 15 || !used[fd - 3]) {
errno = EBADF;
return -1;
}
s->st_mode = S_IFREG | 0666;
s->st_size = f_size(&files[fd - 3]);
return 0;
}
int _stat(const char *p, struct stat *s) {
FILINFO info;
FRESULT r = f_stat(p, &info);
if (r)
return fail(r);
memset(s, 0, sizeof(*s));
s->st_mode = (info.fattrib & AM_DIR) ? S_IFDIR | 0777 : S_IFREG | 0666;
s->st_size = info.fsize;
return 0;
}
int _isatty(int fd) { return fd < 3; }
int _unlink(const char *p) {
FRESULT r = f_unlink(p);
return r ? fail(r) : 0;
}
int _rename(const char *a, const char *b) {
FRESULT r = f_rename(a, b);
return r ? fail(r) : 0;
}
int mkdir(const char *p, mode_t mode) {
(void)mode;
FRESULT r = f_mkdir(p);
return r ? fail(r) : 0;
}
int access(const char *p, int mode) {
(void)mode;
FILINFO f;
FRESULT r = f_stat(p, &f);
return r ? fail(r) : 0;
}
int system(const char *cmd) {
(void)cmd;
return -1;
}
int _link(const char *oldpath, const char *newpath) {
(void)oldpath;
(void)newpath;
errno = ENOSYS;
return -1;
}