diff --git a/iop/system/iomanx/src/imports.lst b/iop/system/iomanx/src/imports.lst index 851c6ddc38f..9324a2bc925 100644 --- a/iop/system/iomanx/src/imports.lst +++ b/iop/system/iomanx/src/imports.lst @@ -1,3 +1,8 @@ + +sysmem_IMPORTS_start +I_Kprintf +sysmem_IMPORTS_end + stdio_IMPORTS_start I_printf stdio_IMPORTS_end diff --git a/iop/system/iomanx/src/iomanX.c b/iop/system/iomanx/src/iomanX.c index 22d6ce0a936..ea13e71071b 100644 --- a/iop/system/iomanx/src/iomanX.c +++ b/iop/system/iomanx/src/iomanX.c @@ -3,8 +3,7 @@ # ____| | ____| | | |____| # | ___| |____ ___| ____| | \ PS2DEV Open Source Project. #----------------------------------------------------------------------- -# Copyright (c) 2003 Marcus R. Brown -# Copyright (c) 2004 adresd +# Copyright ps2dev - http://www.ps2dev.org # Licenced under Academic Free License version 2.0 # Review ps2sdk README & LICENSE files for further details. */ @@ -14,665 +13,1185 @@ * Advanced I/O library. */ -#include "types.h" #ifdef _IOP -#include "loadcore.h" -#endif -#include "iomanX.h" -#ifdef _IOP -#include "sysclib.h" +#include "irx_imports.h" #else #include +#include #define index strchr +#include +#include +#define Kprintf printf #endif -#include "stdarg.h" -#include "intrman.h" +#include -#define MODNAME "iomanx" -#ifdef _IOP +#include +#include + +#ifdef IOP +#ifdef IOMANX_ENABLE_LEGACY_IOMAN_HOOK IRX_ID("IOX/File_Manager", 1, 1); +#else +IRX_ID("IO/File_Manager", 2, 3); +// Based on the module from SCE SDK 3.1.0. +#endif #endif - -#include "errno.h" - -#define MAX_DEVICES 32 -#define MAX_FILES 128 - -static iomanX_iop_device_t *dev_list[MAX_DEVICES]; -iomanX_iop_file_t file_table[MAX_FILES]; - -#define isnum(c) ((c) >= '0' && (c) <= '9') - #ifdef _IOP +#ifdef IOMANX_ENABLE_LEGACY_IOMAN_HOOK extern struct irx_export_table _exp_iomanx; +#else +extern struct irx_export_table _exp_ioman; +#endif #endif #ifdef IOMANX_ENABLE_LEGACY_IOMAN_HOOK -extern int hook_ioman(); -extern int unhook_ioman(); +#define MAX_DEVICES 32 +#define MAX_FILES 128 +#else +#define MAX_DEVICES 16 +#define MAX_FILES 32 #endif -iomanX_iop_device_t **iomanX_GetDeviceList(void) -{ - return(dev_list); -} - -#ifndef IOMANX_ENTRYPOINT -#define IOMANX_ENTRYPOINT _start +#ifndef IOMANX_ENABLE_LEGACY_IOMAN_HOOK +void iomanX_StdioInit(int mode); +static int open_tty_handles(const char *tty_name); +#endif +static int xx_stat(int op, const char *name, iox_stat_t *stat, unsigned int statmask); +static int xx_rename(int op, const char *oldname, const char *newname); +static int xx_dir(int op, const char *name, int mode); +static int _ioabort(const char *str1, const char *str2); +static iomanX_iop_file_t *new_iob(void); +static iomanX_iop_file_t *get_iob(int fd); +static iomanX_iop_device_t *lookup_dev(const char *name, int show_unkdev_msg); +static const char *parsefile(const char *path, iomanX_iop_device_t **p_device, int *p_unit); +#ifndef IOMANX_ENABLE_LEGACY_IOMAN_HOOK +static int tty_noop(void); +unsigned int iomanX_GetDevType(int fd); +#endif +static void ShowDrv(void); +#ifndef IOMANX_ENABLE_LEGACY_IOMAN_HOOK +static void register_tty(void); +static void register_dummytty(void); #endif -int IOMANX_ENTRYPOINT(int argc, char *argv[]) +#ifdef IOMANX_USE_DEVICE_LINKED_LIST +struct ioman_dev_listentry { - (void)argc; - (void)argv; + struct ioman_dev_listentry *next; + iomanX_iop_device_t *device; +}; +#endif -#ifdef _IOP - if(RegisterLibraryEntries(&_exp_iomanx) != 0) - { - return MODULE_NO_RESIDENT_END; - } +static int showdrvflag = 1; +#ifndef IOMANX_ENABLE_LEGACY_IOMAN_HOOK +static iomanX_iop_device_ops_t dev_tty_dev_operations = { + (void *)&tty_noop, + (void *)&tty_noop, + (void *)&tty_noop, + (void *)&tty_noop, + (void *)&tty_noop, + (void *)&tty_noop, + (void *)&tty_noop, + (void *)&tty_noop, + (void *)&tty_noop, + (void *)&tty_noop, + (void *)&tty_noop, + (void *)&tty_noop, + (void *)&tty_noop, + (void *)&tty_noop, + (void *)&tty_noop, + (void *)&tty_noop, + (void *)&tty_noop, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, +}; +static iomanX_iop_device_t dev_tty = { + "tty", + IOP_DT_CHAR, + 1, + "CONSOLE", + &dev_tty_dev_operations, +}; +static iomanX_iop_device_t dev_dummytty = { + "dummytty", + IOP_DT_CHAR, + 1, + "CONSOLE", + &dev_tty_dev_operations, +}; +#endif +static int adddeldrv_in_process; +#ifdef IOMANX_USE_ERRNO +static int errno_local; +#endif +#ifdef IOMANX_USE_DEVICE_LINKED_LIST +static struct ioman_dev_listentry *device_entry_empty_list_head; +static struct ioman_dev_listentry *device_entry_used_list_head; +#endif +#ifndef IOMANX_ENABLE_LEGACY_IOMAN_HOOK +static +#endif + iomanX_iop_file_t file_table[MAX_FILES]; +#ifdef IOMANX_USE_DEVICE_LINKED_LIST +static struct ioman_dev_listentry device_entry_list[MAX_DEVICES]; +#else +static iomanX_iop_device_t *device_table[MAX_DEVICES]; #endif - memset(dev_list, 0, sizeof(dev_list)); - memset(file_table, 0, sizeof(file_table)); +#ifndef isnum +#define isnum(c) ((c) >= '0' && (c) <= '9') +#endif -#ifdef IOMANX_ENABLE_LEGACY_IOMAN_HOOK - if(hook_ioman() != 0) - { - return MODULE_NO_RESIDENT_END; - } +#ifndef EUNSUP +#ifdef ENOTSUP +#define EUNSUP ENOTSUP +#else +#define EUNSUP 48 +#endif #endif - return MODULE_RESIDENT_END; +#define HANDLE_RESULT_CLEAR_INFO 1 +#define HANDLE_RESULT_CLEAR_INFO_ON_ERROR 2 +#define HANDLE_RESULT_RETURN_ZERO 4 +#define HANDLE_RESULT_RETURN_FD 8 + +static inline void write_str_to_stdout(const char *in_str) +{ + iomanX_write(1, (void *)in_str, strlen(in_str)); } -int shutdown() +static inline int set_errno(int in_errno) { -#ifdef IOMANX_ENABLE_LEGACY_IOMAN_HOOK - unhook_ioman(); +#ifdef IOMANX_USE_ERRNO + errno_local = in_errno; #endif - return MODULE_NO_RESIDENT_END; + return -in_errno; } -int iomanX_AddDrv(iomanX_iop_device_t *device) +static inline void handle_result_pre(int in_result, iomanX_iop_file_t *f, int op) { - int i; - int oldIntr; - - CpuSuspendIntr(&oldIntr); - - for (i = 0; i < MAX_DEVICES; i++) + if ( (op & HANDLE_RESULT_CLEAR_INFO) ) { - if (dev_list[i] == NULL) - break; + if ( f ) + { + f->mode = 0; + f->device = NULL; + } } - - if (i >= MAX_DEVICES) + if ( (op & HANDLE_RESULT_CLEAR_INFO_ON_ERROR) ) { - CpuResumeIntr(oldIntr); - return(-1); + if ( f && (in_result < 0) ) + { + // Unofficial: also clear mode + f->mode = 0; + f->device = NULL; + } } +} - dev_list[i] = device; - CpuResumeIntr(oldIntr); +static inline int handle_result(int in_result, iomanX_iop_file_t *f, int op) +{ + handle_result_pre(in_result, f, op); + if ( in_result < 0 ) + return set_errno(-in_result); + if ( (op & HANDLE_RESULT_RETURN_ZERO) ) + return 0; + if ( (op & HANDLE_RESULT_RETURN_FD) ) + return f - file_table; + return in_result; +} +static inline s64 handle_result64(s64 in_result, iomanX_iop_file_t *f, int op) +{ + handle_result_pre(in_result, f, op); + if ( in_result < 0 ) + return set_errno(-(int)in_result); + if ( (op & HANDLE_RESULT_RETURN_ZERO) ) + return 0; + if ( (op & HANDLE_RESULT_RETURN_FD) ) + return f - file_table; + return in_result; +} + +#ifdef IOMANX_ENABLE_LEGACY_IOMAN_HOOK +extern int hook_ioman(); +extern int unhook_ioman(); +#endif + +#ifndef IOMANX_ENTRYPOINT #ifdef _IOP - FlushIcache(); +#define IOMANX_ENTRYPOINT _start +#else +#define IOMANX_ENTRYPOINT iomanX_start +#endif #endif - if (device->ops->init(device) < 0) - { - dev_list[i] = NULL; - return(-1); - } +#ifndef IOMANX_CLEANUP +#define IOMANX_CLEANUP shutdown +#endif + +int IOMANX_ENTRYPOINT(int ac, char **av) +{ +#ifdef IOMANX_USE_DEVICE_LINKED_LIST + unsigned int i; +#endif + + (void)ac; + (void)av; - return(0); +#ifdef _IOP +#ifdef IOMANX_ENABLE_LEGACY_IOMAN_HOOK + if ( RegisterLibraryEntries(&_exp_iomanx) ) + return MODULE_NO_RESIDENT_END; +#else + if ( RegisterLibraryEntries(&_exp_ioman) ) + return MODULE_NO_RESIDENT_END; +#if 0 + SetRebootTimeLibraryHandlingMode(&_exp_ioman, 2); +#else + // Call termination before disabling interrupts + _exp_ioman.mode &= ~6; + _exp_ioman.mode |= 2; +#endif +#endif +#endif + adddeldrv_in_process = 0; +#ifdef IOMANX_USE_DEVICE_LINKED_LIST + // Unofficial: memset instead of bzero + memset(device_entry_list, 0, sizeof(device_entry_list)); + device_entry_used_list_head = NULL; + device_entry_empty_list_head = device_entry_list; + // Unofficial: link forwards instead of backwards + for ( i = 0; i < ((sizeof(device_entry_list) / sizeof(device_entry_list[0])) - 1); i += 1 ) + device_entry_list[i].next = &device_entry_list[i + 1]; +#else + memset(device_table, 0, sizeof(device_table)); +#endif + // Unofficial: memset instead of bzero + memset(file_table, 0, sizeof(file_table)); +#ifdef IOMANX_ENABLE_LEGACY_IOMAN_HOOK + if ( hook_ioman() ) + return MODULE_NO_RESIDENT_END; +#else + iomanX_StdioInit(0); +#endif + return MODULE_RESIDENT_END; } -int iomanX_DelDrv(const char *name) +int IOMANX_CLEANUP(int arg) { - int i; +#ifdef IOMANX_ENABLE_LEGACY_IOMAN_HOOK + unhook_ioman(); + return MODULE_NO_RESIDENT_END; +#else +#ifdef IOMANX_USE_DEVICE_LINKED_LIST + struct ioman_dev_listentry *i; +#else + unsigned int i; +#endif - for (i = 0; i < MAX_DEVICES; i++) { - if (dev_list[i] != NULL && !strcmp(name, dev_list[i]->name)) { - dev_list[i]->ops->deinit(dev_list[i]); - dev_list[i] = NULL; - return 0; + if ( !arg ) + { +#ifdef IOMANX_USE_DEVICE_LINKED_LIST + for ( i = device_entry_used_list_head; i; i = i->next ) + { + i->device->ops->deinit(i->device); + i->device = NULL; } +#else + for ( i = 0; i < (sizeof(device_table) / sizeof(device_table[0])); i += 1 ) + { + if ( device_table[i] ) + { + device_table[i]->ops->deinit(device_table[i]); + device_table[i] = NULL; + } + } +#endif } - - return -1; + return MODULE_RESIDENT_END; +#endif } - -static char * find_iop_device(const char *dev, int *unit, iomanX_iop_device_t **device) +#ifdef IOMANX_ENABLE_LEGACY_IOMAN_HOOK +iomanX_iop_device_t **iomanX_GetDeviceList(void) { - char canon[16]; - char *filename, *tail, *d = (char *)dev; - int i, len; - - while (*d == ' ') - d += 1; + return device_table; +} - if ((tail = index(d, ':')) == NULL) - return (char *)-1; +int mode2modex(int mode) +{ + int modex = 0; - len = (int)(tail - d); - if ((unsigned int)len > (sizeof(canon) - 1)) - return (char *)-1; - strncpy(canon, d, len); - canon[len] = '\0'; + if ( FIO_SO_ISLNK(mode) ) + modex |= FIO_S_IFLNK; + if ( FIO_SO_ISREG(mode) ) + modex |= FIO_S_IFREG; + if ( FIO_SO_ISDIR(mode) ) + modex |= FIO_S_IFDIR; - /* This is the name passed to the device op. */ - filename = d + len + 1; + /* Convert the file access modes. */ + if ( mode & FIO_SO_IROTH ) + modex |= FIO_S_IRUSR | FIO_S_IRGRP | FIO_S_IROTH; + if ( mode & FIO_SO_IWOTH ) + modex |= FIO_S_IWUSR | FIO_S_IWGRP | FIO_S_IWOTH; + if ( mode & FIO_SO_IXOTH ) + modex |= FIO_S_IXUSR | FIO_S_IXGRP | FIO_S_IXOTH; - /* Search backward for the unit number. */ - while (isnum(canon[len - 1])) - len -= 1; - if (unit) { - int num; + return modex; +} - num = 0; - if (isnum(canon[len])) { - num = strtol(canon + len, 0, 10); - } - *unit = num; - } +int modex2mode(int modex) +{ + int mode = 0; - /* Find the actual device. */ - canon[len] = '\0'; - for (i = 0; i < MAX_DEVICES; i++) { - if (dev_list[i] != NULL && !strcmp(canon, dev_list[i]->name)) { - if (device) - *device = dev_list[i]; + if ( FIO_S_ISLNK(modex) ) + mode |= FIO_SO_IFLNK; + if ( FIO_S_ISREG(modex) ) + mode |= FIO_SO_IFREG; + if ( FIO_S_ISDIR(modex) ) + mode |= FIO_SO_IFDIR; - return filename; - } - } + /* Convert the file access modes. */ + if ( modex & (FIO_S_IRUSR | FIO_S_IRGRP | FIO_S_IROTH) ) + mode |= FIO_SO_IROTH; + if ( modex & (FIO_S_IWUSR | FIO_S_IWGRP | FIO_S_IWOTH) ) + mode |= FIO_SO_IWOTH; + if ( modex & (FIO_S_IXUSR | FIO_S_IXGRP | FIO_S_IXOTH) ) + mode |= FIO_SO_IXOTH; - return (char *)-1; + return mode; } iomanX_iop_file_t *get_file(int fd) { - if (fd >= MAX_FILES) - return NULL; - - if (file_table[fd].device != NULL) - return &file_table[fd]; - - return NULL; + return get_iob(fd); } +#endif -iomanX_iop_file_t *get_new_file(void) +#ifndef IOMANX_ENABLE_LEGACY_IOMAN_HOOK +void iomanX_StdioInit(int mode) { - int i; - iomanX_iop_file_t *fd = NULL; - int oldIntr; - - CpuSuspendIntr(&oldIntr); +#ifdef _IOP + const int *BootMode; + iop_thread_info_t thinfo; +#endif - for (i = 0; i < MAX_FILES; i++) +#ifdef _IOP + BootMode = QueryBootMode(3); + if ( BootMode && (BootMode[1] & 4) ) + return; + ReferThreadStatus(0, &thinfo); + ChangeThreadPriority(0, 4); +#endif +#ifdef _IOP + switch ( mode ) { - if (!file_table[i].device) + case 0: { - fd = &file_table[i]; - - // fill in "device" temporarily to mark the fd as allocated. - fd->device = (iomanX_iop_device_t *) 0xFFFFFFFF; + iomanX_close(0); + iomanX_close(1); + register_tty(); + open_tty_handles("tty:"); + break; + } + case 1: + { + iomanX_close(0); + iomanX_close(1); + register_dummytty(); + open_tty_handles("dummytty:"); break; } + default: + break; } +#else + iomanX_close(0); + iomanX_close(1); + register_tty(); + open_tty_handles("tty:"); +#endif +#ifdef _IOP + ChangeThreadPriority(0, thinfo.currentPriority); +#endif +} - CpuResumeIntr(oldIntr); - - return fd; +static int open_tty_handles(const char *tty_name) +{ + if ( iomanX_open(tty_name, 3) != 0 || iomanX_open(tty_name, 2) != 1 ) + return -1; + return 0; } +#endif int iomanX_open(const char *name, int flags, ...) { - iomanX_iop_file_t *f = get_new_file(); - char *filename; - va_list alist; - int res, mode; - - va_start(alist, flags); - mode = va_arg(alist, int); - va_end(alist); - - if (!f) - { - return -EMFILE; - } - - if ((filename = find_iop_device(name, &f->unit, &f->device)) == (char *)-1) - { - f->device = NULL; - return -ENODEV; - } - + iomanX_iop_file_t *f; + const char *parsefile_res; + int mode; + va_list va; + + va_start(va, flags); + mode = va_arg(va, int); + va_end(va); + f = new_iob(); + if ( !f ) + return handle_result(-EMFILE, f, HANDLE_RESULT_CLEAR_INFO_ON_ERROR); + parsefile_res = parsefile(name, &(f->device), &(f->unit)); + if ( !parsefile_res ) + return handle_result(-ENODEV, f, HANDLE_RESULT_CLEAR_INFO_ON_ERROR); f->mode = flags; - if ((res = f->device->ops->open(f, filename, flags, mode)) >= 0) - { - res = (int)(f - file_table); - } - else - { - f->mode = 0; - f->device = NULL; - } - - return res; + return handle_result( + f->device->ops->open(f, parsefile_res, flags, mode), + f, + HANDLE_RESULT_CLEAR_INFO_ON_ERROR | HANDLE_RESULT_RETURN_FD); } -int iomanX_close(int fd) +int iomanX_lseek(int fd, int offset, int mode) { iomanX_iop_file_t *f; - int res; - if ((f = get_file(fd)) == NULL) + f = get_iob(fd); + if ( !f ) + return handle_result(-EBADF, f, 0); + switch ( mode ) { - return -EBADF; + case FIO_SEEK_SET: + case FIO_SEEK_CUR: + case FIO_SEEK_END: + return handle_result(f->device->ops->lseek(f, offset, mode), f, 0); + default: + write_str_to_stdout("invalid lseek arg\r\n"); + return handle_result(-EINVAL, f, 0); } +} - if (f->mode & 8) - { /* Directory. */ - res = f->device->ops->dclose(f); - } - else +s64 iomanX_lseek64(int fd, s64 offset, int whence) +{ + iomanX_iop_file_t *f; + + f = get_iob(fd); + if ( !f ) + return handle_result(-EBADF, f, 0); + if ( (f->device->type & 0xF0000000) != IOP_DT_FSEXT ) + return handle_result(-EUNSUP, f, 0); + switch ( whence ) { - res = f->device->ops->close(f); + case FIO_SEEK_SET: + case FIO_SEEK_CUR: + case FIO_SEEK_END: + return handle_result64(f->device->ops->lseek64(f, offset, whence), f, 0); + default: + write_str_to_stdout("invalid lseek arg\r\n"); + return handle_result(-EINVAL, f, 0); } - - f->mode = 0; - f->device = NULL; - return res; } int iomanX_read(int fd, void *ptr, int size) { - iomanX_iop_file_t *f = get_file(fd); - - if (f == NULL || !(f->mode & FIO_O_RDONLY)) - return -EBADF; + iomanX_iop_file_t *f; - return f->device->ops->read(f, ptr, size); + f = get_iob(fd); + if ( !f || !(f->mode & FIO_O_RDONLY) ) + return handle_result(-EBADF, f, 0); + return handle_result(f->device->ops->read(f, ptr, size), f, 0); } int iomanX_write(int fd, void *ptr, int size) { - iomanX_iop_file_t *f = get_file(fd); - - if (f == NULL || !(f->mode & FIO_O_WRONLY)) - return -EBADF; + iomanX_iop_file_t *f; - return f->device->ops->write(f, ptr, size); + f = get_iob(fd); + if ( !f || !(f->mode & FIO_O_WRONLY) ) + return handle_result(-EBADF, f, 0); + return handle_result(f->device->ops->write(f, ptr, size), f, 0); } -int iomanX_lseek(int fd, int offset, int whence) +int iomanX_close(int fd) { - iomanX_iop_file_t *f = get_file(fd); - - if (f == NULL) - return -EBADF; - - if (whence < FIO_SEEK_SET || whence > FIO_SEEK_END) - return -EINVAL; + iomanX_iop_file_t *f; - return f->device->ops->lseek(f, offset, whence); + f = get_iob(fd); + if ( !f ) + return handle_result(-EBADF, f, 0); + return handle_result( + (f->mode & FIO_O_DIROPEN) ? f->device->ops->dclose(f) : f->device->ops->close(f), + f, + HANDLE_RESULT_CLEAR_INFO | HANDLE_RESULT_RETURN_FD); } -int iomanX_ioctl(int fd, int cmd, void *arg) +int iomanX_ioctl(int fd, int cmd, void *param) { - iomanX_iop_file_t *f = get_file(fd); - - if (f == NULL) - return -EBADF; + iomanX_iop_file_t *f; - return f->device->ops->ioctl(f, cmd, arg); + f = get_iob(fd); + if ( !f ) + return handle_result(-EBADF, f, 0); + return handle_result(f->device->ops->ioctl(f, cmd, param), f, 0); } -int iomanX_remove(const char *name) +int iomanX_ioctl2(int fd, int cmd, void *arg, unsigned int arglen, void *buf, unsigned int buflen) { - iomanX_iop_file_t file; - char *filename; - - if ((filename = find_iop_device(name, &file.unit, &file.device)) == (char *)-1) - return -ENODEV; - - return file.device->ops->remove(&file, filename); -} - -/* Because mkdir, rmdir, chdir, and sync have similiar arguments (each starts - with a path followed by an optional integer), we use a common routine to - handle all of them. */ -static int path_common(const char *name, int arg, int code) -{ - iomanX_iop_file_t file; - iomanX_iop_device_ops_t *dops; - char *filename; - - if ((filename = find_iop_device(name, &file.unit, &file.device)) == (char *)-1) - return -ENODEV; - - if (code & 0x100) - if ((file.device->type & 0xf0000000) != IOP_DT_FSEXT) - return -48; - - dops = (iomanX_iop_device_ops_t *)file.device->ops; - switch (code) { - case 4: /* mkdir() */ - return dops->mkdir(&file, filename, arg); - case 5: /* rmdir() */ - return dops->rmdir(&file, filename); - case 0x103: /* chdir() */ - return dops->chdir(&file, filename); - case 0x106: - return dops->sync(&file, filename, arg); - } + iomanX_iop_file_t *f; - return -EINVAL; + f = get_iob(fd); + if ( !f ) + return handle_result(-EBADF, f, 0); + // The filesystem must support these ops. + if ( (f->device->type & 0xF0000000) != IOP_DT_FSEXT ) + return handle_result(-EUNSUP, f, 0); + return handle_result(f->device->ops->ioctl2(f, cmd, arg, arglen, buf, buflen), f, 0); } -int iomanX_mkdir(const char *name, int mode) +int iomanX_dopen(const char *path) { - return path_common(name, mode, 4); + iomanX_iop_file_t *f; + const char *parsefile_res; + + f = new_iob(); + if ( !f ) + return handle_result(-EMFILE, f, HANDLE_RESULT_CLEAR_INFO_ON_ERROR); + parsefile_res = parsefile(path, &(f->device), &(f->unit)); + if ( !parsefile_res ) + return handle_result(-ENODEV, f, HANDLE_RESULT_CLEAR_INFO_ON_ERROR); + f->mode = FIO_O_DIROPEN; + return handle_result( + f->device->ops->dopen(f, parsefile_res), f, HANDLE_RESULT_CLEAR_INFO_ON_ERROR | HANDLE_RESULT_RETURN_FD); } -int iomanX_rmdir(const char *name) +int iomanX_dread(int fd, iox_dirent_t *buf) { - return path_common(name, 0, 5); -} + iomanX_iop_file_t *f; -int iomanX_dopen(const char *name) -{ - iomanX_iop_file_t *f = get_new_file(); - char *filename; - int res; + f = get_iob(fd); + if ( !f || !(f->mode & FIO_O_DIROPEN) ) + return handle_result(-EBADF, f, 0); +#ifdef IOMANX_ENABLE_LEGACY_IOMAN_HOOK + /* If this is a legacy device (such as mc:) then we need to convert the mode + variable of the stat structure to iomanX's extended format. */ + if ( (f->device->type & 0xF0000000) != IOP_DT_FSEXT ) + { + int res; + typedef int io_dread_t(iomanX_iop_file_t *, io_dirent_t *); + io_dirent_t io_dirent; + io_dread_t *io_dread; - if (!f) - return -EMFILE; + io_dread = (io_dread_t *)f->device->ops->dread; + res = io_dread(f, &io_dirent); - if ((filename = find_iop_device(name, &f->unit, &f->device)) == (char *)-1) - { - f->device = NULL; - return -ENODEV; - } + buf->stat.mode = mode2modex(io_dirent.stat.mode); - f->mode = 8; /* Indicates a directory. */ - if ((res = f->device->ops->dopen(f, filename)) >= 0) - res = (int)(f - file_table); - else - { - f->mode = 0; - f->device = NULL; - } + buf->stat.attr = io_dirent.stat.attr; + buf->stat.size = io_dirent.stat.size; + memcpy(buf->stat.ctime, io_dirent.stat.ctime, sizeof(io_dirent.stat.ctime)); + memcpy(buf->stat.atime, io_dirent.stat.atime, sizeof(io_dirent.stat.atime)); + memcpy(buf->stat.mtime, io_dirent.stat.mtime, sizeof(io_dirent.stat.mtime)); + buf->stat.hisize = io_dirent.stat.hisize; - return res; + strncpy(buf->name, io_dirent.name, sizeof(buf->name)); + return handle_result(res, f, 0); + } +#endif + return handle_result(f->device->ops->dread(f, buf), f, 0); } -int mode2modex(int mode) +int iomanX_remove(const char *name) { - int modex = 0; - - if (FIO_SO_ISLNK(mode)) - modex |= FIO_S_IFLNK; - if (FIO_SO_ISREG(mode)) - modex |= FIO_S_IFREG; - if (FIO_SO_ISDIR(mode)) - modex |= FIO_S_IFDIR; - - /* Convert the file access modes. */ - if (mode & FIO_SO_IROTH) - modex |= FIO_S_IRUSR | FIO_S_IRGRP | FIO_S_IROTH; - if (mode & FIO_SO_IWOTH) - modex |= FIO_S_IWUSR | FIO_S_IWGRP | FIO_S_IWOTH; - if (mode & FIO_SO_IXOTH) - modex |= FIO_S_IXUSR | FIO_S_IXGRP | FIO_S_IXOTH; - - return modex; + iomanX_iop_file_t *f; + const char *parsefile_res; + + f = new_iob(); + if ( !f ) + return handle_result(-EMFILE, f, HANDLE_RESULT_CLEAR_INFO_ON_ERROR); + parsefile_res = parsefile(name, &(f->device), &(f->unit)); + if ( !parsefile_res ) + return handle_result(-ENODEV, f, HANDLE_RESULT_CLEAR_INFO_ON_ERROR); + return handle_result( + f->device->ops->remove(f, parsefile_res), f, HANDLE_RESULT_CLEAR_INFO | HANDLE_RESULT_RETURN_ZERO); } -int modex2mode(int modex) +int iomanX_mkdir(const char *path, int mode) { - int mode = 0; - - if (FIO_S_ISLNK(modex)) - mode |= FIO_SO_IFLNK; - if (FIO_S_ISREG(modex)) - mode |= FIO_SO_IFREG; - if (FIO_S_ISDIR(modex)) - mode |= FIO_SO_IFDIR; - - /* Convert the file access modes. */ - if (modex & (FIO_S_IRUSR | FIO_S_IRGRP | FIO_S_IROTH)) - mode |= FIO_SO_IROTH; - if (modex & (FIO_S_IWUSR | FIO_S_IWGRP | FIO_S_IWOTH)) - mode |= FIO_SO_IWOTH; - if (modex & (FIO_S_IXUSR | FIO_S_IXGRP | FIO_S_IXOTH)) - mode |= FIO_SO_IXOTH; - - return mode; + return xx_dir(4, path, mode); } -int iomanX_dread(int fd, iox_dirent_t *iox_dirent) +int iomanX_rmdir(const char *path) { - iomanX_iop_file_t *f = get_file(fd); - int res; - - if (f == NULL || !(f->mode & 8)) - return -EBADF; + return xx_dir(5, path, 0); +} +static int xx_stat(int op, const char *name, iox_stat_t *stat, unsigned int statmask) +{ + iomanX_iop_file_t *f; + const char *parsefile_res; + + f = new_iob(); + if ( !f ) + return handle_result(-EMFILE, f, HANDLE_RESULT_CLEAR_INFO_ON_ERROR); + parsefile_res = parsefile(name, &(f->device), &(f->unit)); + if ( !parsefile_res ) + return handle_result(-ENODEV, f, HANDLE_RESULT_CLEAR_INFO_ON_ERROR); + switch ( op ) + { + case 1: + { #ifdef IOMANX_ENABLE_LEGACY_IOMAN_HOOK - /* If this is a legacy device (such as mc:) then we need to convert the mode - variable of the stat structure to iomanX's extended format. */ - if ((f->device->type & 0xf0000000) != IOP_DT_FSEXT) - { - typedef int io_dread_t(iomanX_iop_file_t *, io_dirent_t *); - io_dirent_t io_dirent; - io_dread_t *io_dread = (io_dread_t*) f->device->ops->dread; - res = io_dread(f, &io_dirent); - - iox_dirent->stat.mode = mode2modex(io_dirent.stat.mode); - - iox_dirent->stat.attr = io_dirent.stat.attr; - iox_dirent->stat.size = io_dirent.stat.size; - memcpy(iox_dirent->stat.ctime, io_dirent.stat.ctime, sizeof(io_dirent.stat.ctime)); - memcpy(iox_dirent->stat.atime, io_dirent.stat.atime, sizeof(io_dirent.stat.atime)); - memcpy(iox_dirent->stat.mtime, io_dirent.stat.mtime, sizeof(io_dirent.stat.mtime)); - iox_dirent->stat.hisize = io_dirent.stat.hisize; - - strncpy(iox_dirent->name, io_dirent.name, sizeof(iox_dirent->name)); - } - else + /* If this is a legacy device (such as mc:) then we need to convert the mode + variable to iomanX's extended format. */ + if ( (f->device->type & 0xF0000000) != IOP_DT_FSEXT ) + { + iox_stat_t stat_tmp; + + memcpy(&stat_tmp, stat, sizeof(stat_tmp)); + stat_tmp.mode = modex2mode(stat->mode); + return handle_result( + f->device->ops->chstat(f, parsefile_res, &stat_tmp, statmask), + f, + HANDLE_RESULT_CLEAR_INFO | HANDLE_RESULT_RETURN_ZERO); + } #endif - { - res = f->device->ops->dread(f, iox_dirent); - } - - return res; + return handle_result( + f->device->ops->chstat(f, parsefile_res, stat, statmask), + f, + HANDLE_RESULT_CLEAR_INFO | HANDLE_RESULT_RETURN_ZERO); + } + case 2: + { +#ifdef IOMANX_ENABLE_LEGACY_IOMAN_HOOK + /* If this is a legacy device (such as mc:) then we need to convert the mode + variable to iomanX's extended format. */ + if ( (f->device->type & 0xF0000000) != IOP_DT_FSEXT ) + { + int res; + + res = f->device->ops->getstat(f, parsefile_res, stat); + if ( res == 0 ) + stat->mode = mode2modex(stat->mode); + return handle_result(res, f, HANDLE_RESULT_CLEAR_INFO | HANDLE_RESULT_RETURN_ZERO); + } +#endif + return handle_result( + f->device->ops->getstat(f, parsefile_res, stat), f, HANDLE_RESULT_CLEAR_INFO | HANDLE_RESULT_RETURN_ZERO); + } + default: + // Unofficial: return negative instead of positive if op not found + return handle_result(-ENODEV, f, HANDLE_RESULT_CLEAR_INFO_ON_ERROR); + } } int iomanX_getstat(const char *name, iox_stat_t *stat) { - iomanX_iop_file_t file; - char *filename; - int res; - - if ((filename = find_iop_device(name, &file.unit, &file.device)) == (char *)-1) - return -ENODEV; - - res = file.device->ops->getstat(&file, filename, stat); - - if (res == 0) - { - /* If this is a legacy device (such as mc:) then we need to convert the mode - variable to iomanX's extended format. */ - if ((file.device->type & 0xf0000000) != IOP_DT_FSEXT) - stat->mode = mode2modex(stat->mode); - } - - return res; + return xx_stat(2, name, stat, 0); } -int iomanX_chstat(const char *name, iox_stat_t *stat, unsigned int mask) +int iomanX_chstat(const char *name, iox_stat_t *stat, unsigned int statmask) { - iomanX_iop_file_t file; - char *filename; - - if ((filename = find_iop_device(name, &file.unit, &file.device)) == (char *)-1) - return -ENODEV; - - /* If this is a legacy device (such as mc:) then we need to convert the mode - variable to iomanX's extended format. */ - if ((file.device->type & 0xf0000000) != IOP_DT_FSEXT) - stat->mode = modex2mode(stat->mode); - - return file.device->ops->chstat(&file, filename, stat, mask); + return xx_stat(1, name, stat, statmask); } int iomanX_format(const char *dev, const char *blockdev, void *arg, int arglen) { - iomanX_iop_file_t file; - char *filename; - - if ((filename = find_iop_device(dev, &file.unit, &file.device)) == (char *)-1) - return -ENODEV; - - return file.device->ops->format(&file, filename, blockdev, arg, arglen); + iomanX_iop_file_t *f; + const char *parsefile_res; + + f = new_iob(); + if ( !f ) + return handle_result(-EMFILE, f, HANDLE_RESULT_CLEAR_INFO_ON_ERROR); + parsefile_res = parsefile(dev, &(f->device), &(f->unit)); + if ( !parsefile_res ) + return handle_result(-ENODEV, f, HANDLE_RESULT_CLEAR_INFO_ON_ERROR); + return handle_result( + f->device->ops->format(f, parsefile_res, blockdev, arg, arglen), + f, + HANDLE_RESULT_CLEAR_INFO | HANDLE_RESULT_RETURN_ZERO); } -static int link_common(const char *old, const char *new, int code) +static int xx_rename(int op, const char *oldname, const char *newname) { - iomanX_iop_file_t file; - iomanX_iop_device_t *new_device; - char *filename, *new_filename = (char *)new; - int new_unit; - - if ((filename = find_iop_device(old, &file.unit, &file.device)) == (char *)-1) - return -ENODEV; - - /* Make sure the user isn't attempting to link across devices. */ - if (index(new, ':') != NULL) { - new_filename = find_iop_device(new, &new_unit, &new_device); - if ((new_filename == (char *)-1) || (new_unit != file.unit) || - (new_device != file.device)) - return -ENXIO; + iomanX_iop_file_t *f; + const char *parsefile_res; + const char *parsefile_res_new; + iomanX_iop_device_t *device_new; + int unit_new; + + f = new_iob(); + if ( !f ) + return handle_result(-EMFILE, f, HANDLE_RESULT_CLEAR_INFO_ON_ERROR); + parsefile_res = parsefile(oldname, &(f->device), &(f->unit)); + if ( !parsefile_res ) + return handle_result(-ENODEV, f, HANDLE_RESULT_CLEAR_INFO_ON_ERROR); + // Unofficial: initialize variables and check if newname is not NULL + parsefile_res_new = newname; + device_new = f->device; + unit_new = f->unit; + if ( newname && index(newname, ':') ) + parsefile_res_new = parsefile(newname, &device_new, &unit_new); + // Make sure the user isn't attempting to link across devices. + if ( !parsefile_res_new || (device_new != f->device) || (unit_new != f->unit) ) + return handle_result(-EXDEV, f, HANDLE_RESULT_CLEAR_INFO_ON_ERROR); + // The filesystem must support these ops. + if ( (f->device->type & 0xF0000000) != IOP_DT_FSEXT ) + return handle_result(-EUNSUP, f, HANDLE_RESULT_CLEAR_INFO_ON_ERROR); + switch ( op ) + { + case 7: + return handle_result( + f->device->ops->rename(f, parsefile_res, parsefile_res_new), + f, + HANDLE_RESULT_CLEAR_INFO | HANDLE_RESULT_RETURN_ZERO); + case 8: + return handle_result( + f->device->ops->symlink(f, parsefile_res, parsefile_res_new), + f, + HANDLE_RESULT_CLEAR_INFO | HANDLE_RESULT_RETURN_ZERO); + default: + // Unofficial: return negative instead of positive if op not found + return handle_result(-ENODEV, f, HANDLE_RESULT_CLEAR_INFO_ON_ERROR); } +} - /* The filesystem must support these ops. */ - if ((file.device->type & 0xf0000000) != IOP_DT_FSEXT) - return -48; - - if (code == 7) /* rename() */ - return file.device->ops->rename(&file, filename, new_filename); - - return file.device->ops->symlink(&file, filename, new_filename); +// cppcheck-suppress funcArgNamesDifferent +int iomanX_rename(const char *oldname, const char *newname) +{ + return xx_rename(7, oldname, newname); } -int iomanX_rename(const char *old, const char *new) +// cppcheck-suppress funcArgNamesDifferent +int iomanX_symlink(const char *oldname, const char *newname) { - return link_common(old, new, 7); + return xx_rename(8, oldname, newname); } int iomanX_chdir(const char *name) { - return path_common(name, 0, 0x103); + return xx_dir(0x103, name, 0); +} + +/* Because mkdir, rmdir, chdir, and sync have similiar arguments (each starts + with a path followed by an optional integer), we use a common routine to + handle all of them. */ +static int xx_dir(int op, const char *name, int mode) +{ + iomanX_iop_file_t *f; + const char *parsefile_res; + + f = new_iob(); + if ( !f ) + return handle_result(-EMFILE, f, HANDLE_RESULT_CLEAR_INFO_ON_ERROR); + parsefile_res = parsefile(name, &(f->device), &(f->unit)); + if ( !parsefile_res ) + return handle_result(-ENODEV, f, HANDLE_RESULT_CLEAR_INFO_ON_ERROR); + // The filesystem must support these ops. + if ( (op & 0x100) && ((f->device->type & 0xF0000000) != IOP_DT_FSEXT) ) + return handle_result(-EUNSUP, f, HANDLE_RESULT_CLEAR_INFO_ON_ERROR); + switch ( op ) + { + case 4: + return handle_result( + f->device->ops->mkdir(f, parsefile_res, mode), f, HANDLE_RESULT_CLEAR_INFO | HANDLE_RESULT_RETURN_ZERO); + case 5: + return handle_result( + f->device->ops->rmdir(f, parsefile_res), f, HANDLE_RESULT_CLEAR_INFO | HANDLE_RESULT_RETURN_ZERO); + case 0x103: + return handle_result( + f->device->ops->chdir(f, parsefile_res), f, HANDLE_RESULT_CLEAR_INFO | HANDLE_RESULT_RETURN_ZERO); + case 0x106: + return handle_result( + f->device->ops->sync(f, parsefile_res, mode), f, HANDLE_RESULT_CLEAR_INFO | HANDLE_RESULT_RETURN_ZERO); + default: + // Unofficial: return negative instead of positive if op not found + return handle_result(-ENODEV, f, HANDLE_RESULT_CLEAR_INFO_ON_ERROR); + } } int iomanX_sync(const char *dev, int flag) { - return path_common(dev, flag, 0x106); + return xx_dir(0x106, dev, flag); } int iomanX_mount(const char *fsname, const char *devname, int flag, void *arg, int arglen) { - iomanX_iop_file_t file; - char *filename; - - if ((filename = find_iop_device(fsname, &file.unit, &file.device)) == (char *)-1) - return -ENODEV; - - /* The filesystem must support these ops. */ - if ((file.device->type & 0xf0000000) != IOP_DT_FSEXT) - return -48; - - return file.device->ops->mount(&file, filename, devname, flag, arg, arglen); + iomanX_iop_file_t *f; + const char *parsefile_res; + + f = new_iob(); + if ( !f ) + return handle_result(-EMFILE, f, HANDLE_RESULT_CLEAR_INFO_ON_ERROR); + parsefile_res = parsefile(fsname, &(f->device), &(f->unit)); + if ( !parsefile_res ) + return handle_result(-ENODEV, f, HANDLE_RESULT_CLEAR_INFO_ON_ERROR); + // The filesystem must support these ops. + if ( (f->device->type & 0xF0000000) != IOP_DT_FSEXT ) + return handle_result(-EUNSUP, f, HANDLE_RESULT_CLEAR_INFO_ON_ERROR); + return handle_result( + f->device->ops->mount(f, parsefile_res, devname, flag, arg, arglen), + f, + HANDLE_RESULT_CLEAR_INFO | HANDLE_RESULT_RETURN_ZERO); } int iomanX_umount(const char *fsname) { - iomanX_iop_file_t file; - char *filename; + iomanX_iop_file_t *f; + const char *parsefile_res; + + f = new_iob(); + if ( !f ) + return handle_result(-EMFILE, f, HANDLE_RESULT_CLEAR_INFO_ON_ERROR); + parsefile_res = parsefile(fsname, &(f->device), &(f->unit)); + if ( !parsefile_res ) + return handle_result(-ENODEV, f, HANDLE_RESULT_CLEAR_INFO_ON_ERROR); + // The filesystem must support these ops. + if ( (f->device->type & 0xF0000000) != IOP_DT_FSEXT ) + return handle_result(-EUNSUP, f, HANDLE_RESULT_CLEAR_INFO_ON_ERROR); + return handle_result( + f->device->ops->umount(f, parsefile_res), f, HANDLE_RESULT_CLEAR_INFO | HANDLE_RESULT_RETURN_ZERO); +} - if ((filename = find_iop_device(fsname, &file.unit, &file.device)) == (char *)-1) - return -ENODEV; +int iomanX_devctl(const char *name, int cmd, void *arg, unsigned int arglen, void *buf, unsigned int buflen) +{ + iomanX_iop_file_t *f; + const char *parsefile_res; + + f = new_iob(); + if ( !f ) + return handle_result(-EMFILE, f, HANDLE_RESULT_CLEAR_INFO_ON_ERROR); + parsefile_res = parsefile(name, &(f->device), &(f->unit)); + if ( !parsefile_res ) + return handle_result(-ENODEV, f, HANDLE_RESULT_CLEAR_INFO_ON_ERROR); + // The filesystem must support these ops. + if ( (f->device->type & 0xF0000000) != IOP_DT_FSEXT ) + return handle_result(-EUNSUP, f, HANDLE_RESULT_CLEAR_INFO_ON_ERROR); + return handle_result( + f->device->ops->devctl(f, parsefile_res, cmd, arg, arglen, buf, buflen), f, HANDLE_RESULT_CLEAR_INFO); +} - /* The filesystem must support these ops. */ - if ((file.device->type & 0xf0000000) != IOP_DT_FSEXT) - return -48; +int iomanX_readlink(const char *path, char *buf, unsigned int buflen) +{ + iomanX_iop_file_t *f; + const char *parsefile_res; + + f = new_iob(); + if ( !f ) + return handle_result(-EMFILE, f, HANDLE_RESULT_CLEAR_INFO_ON_ERROR); + parsefile_res = parsefile(path, &(f->device), &(f->unit)); + if ( !parsefile_res ) + return handle_result(-ENODEV, f, HANDLE_RESULT_CLEAR_INFO_ON_ERROR); + // The filesystem must support these ops. + if ( (f->device->type & 0xF0000000) != IOP_DT_FSEXT ) + return handle_result(-EUNSUP, f, HANDLE_RESULT_CLEAR_INFO_ON_ERROR); + return handle_result(f->device->ops->readlink(f, parsefile_res, buf, buflen), f, HANDLE_RESULT_CLEAR_INFO); +} - return file.device->ops->umount(&file, filename); +static int _ioabort(const char *str1, const char *str2) +{ + return Kprintf("ioabort exit:%s %s\n", str1, str2); } -s64 iomanX_lseek64(int fd, s64 offset, int whence) +static iomanX_iop_file_t *new_iob(void) { - iomanX_iop_file_t *f = get_file(fd); + iomanX_iop_file_t *file_table_entry; + int state; + + CpuSuspendIntr(&state); + file_table_entry = file_table; + while ( (file_table_entry < &file_table[sizeof(file_table) / sizeof(file_table[0])]) && file_table_entry->mode ) + file_table_entry += 1; + if ( file_table_entry >= &file_table[sizeof(file_table) / sizeof(file_table[0])] ) + file_table_entry = NULL; + // fill in "mode" temporarily to mark the fd as allocated. + if ( file_table_entry ) + file_table_entry->mode = -20; + CpuResumeIntr(state); + if ( !file_table_entry ) + _ioabort("out of file descriptors", "[too many open]"); + return file_table_entry; +} - if (f == NULL) - return -EBADF; +static iomanX_iop_file_t *get_iob(int fd) +{ + if ( ((unsigned int)fd >= (sizeof(file_table) / sizeof(file_table[0]))) || (!file_table[fd].device) ) + return NULL; + return &file_table[fd]; +} - if (whence < FIO_SEEK_SET || whence > FIO_SEEK_END) - return -EINVAL; +static iomanX_iop_device_t *lookup_dev(const char *name, int show_unkdev_msg) +{ +#ifdef IOMANX_USE_DEVICE_LINKED_LIST + struct ioman_dev_listentry *entry; +#else + iomanX_iop_device_t *device; + unsigned int i; +#endif + int state; + + CpuSuspendIntr(&state); +#ifdef IOMANX_USE_DEVICE_LINKED_LIST + entry = device_entry_used_list_head; + while ( entry && strcmp(name, entry->device->name) ) + entry = entry->next; + if ( !entry && show_unkdev_msg ) + { + Kprintf("Unknown device '%s'\n", name); + ShowDrv(); + } +#else + device = NULL; + for ( i = 0; i < (sizeof(device_table) / sizeof(device_table[0])); i += 1 ) + { + if ( device_table[i] && !strcmp(name, device_table[i]->name) ) + { + device = device_table[i]; + break; + } + } + if ( !device && show_unkdev_msg ) + { + Kprintf("Unknown device '%s'\n", name); + ShowDrv(); + } +#endif + CpuResumeIntr(state); +#ifdef IOMANX_USE_DEVICE_LINKED_LIST + return entry ? entry->device : NULL; +#else + return device; +#endif +} + +static const char *parsefile(const char *path, iomanX_iop_device_t **p_device, int *p_unit) +{ + const char *path_trimmed; + char *colon_index; + size_t devname_len; + iomanX_iop_device_t *device; + int unit; + char canon[32]; + + path_trimmed = path; + while ( *path_trimmed == ' ' ) + path_trimmed += 1; + colon_index = index(path_trimmed, ':'); + // Unofficial: On error, return NULL instead of -1 + if ( !colon_index ) + { + Kprintf("Unknown device '%s'\n", path_trimmed); + return NULL; + } + devname_len = colon_index - path_trimmed; + // Unofficial: bounds check + if ( devname_len > (sizeof(canon) - 1) ) + return NULL; + strncpy(canon, path_trimmed, devname_len); + unit = 0; + // Search backward for the unit number. + while ( isnum(canon[devname_len - 1]) ) + devname_len -= 1; + if ( isnum(canon[devname_len]) ) + unit = strtol(&canon[devname_len], 0, 10); + canon[devname_len] = 0; + // Find the actual device. + device = lookup_dev(canon, 1); + // Unofficial: On error, return NULL instead of -1 + if ( !device ) + return NULL; + // Unofficial: set unit and device only after success + *p_unit = unit; + *p_device = device; + // This is the name passed to the device op. + return colon_index + 1; +} - if ((f->device->type & 0xf0000000) != IOP_DT_FSEXT) - return -48; +// Unofficial: unused "io request for unsupported operation" func removed - return f->device->ops->lseek64(f, offset, whence); +#ifndef IOMANX_ENABLE_LEGACY_IOMAN_HOOK +static int tty_noop(void) +{ + return 0; } +#endif -int iomanX_devctl(const char *name, int cmd, void *arg, unsigned int arglen, void *buf, unsigned int buflen) +int iomanX_AddDrv(iomanX_iop_device_t *device) { - iomanX_iop_file_t file; - char *filename; +#ifdef IOMANX_USE_DEVICE_LINKED_LIST + struct ioman_dev_listentry *entry; + struct ioman_dev_listentry *old_head; +#else + unsigned int i; +#endif + int state; - if ((filename = find_iop_device(name, &file.unit, &file.device)) == (char *)-1) - return -ENODEV; + CpuSuspendIntr(&state); + if ( adddeldrv_in_process ) + { + Kprintf("AddDrv()/DelDrv() recursive/mutithread call error !!"); + CpuResumeIntr(state); + return -1; + } + // Unofficial: move list check out of interrupt disabled area + adddeldrv_in_process = 1; + CpuResumeIntr(state); +#ifdef IOMANX_USE_DEVICE_LINKED_LIST + entry = device_entry_empty_list_head; + // Unofficial: check if entry exists first + if ( !entry || lookup_dev(device->name, 0) ) + { + adddeldrv_in_process = 0; + return -1; + } + entry->device = device; + device_entry_empty_list_head = entry->next; + if ( device->ops->init(device) < 0 ) + { + old_head = device_entry_empty_list_head; + entry->device = NULL; + device_entry_empty_list_head = entry; + entry->next = old_head; + adddeldrv_in_process = 0; + return -1; + } + old_head = device_entry_used_list_head; + device_entry_used_list_head = entry; + entry->next = old_head; +#else + for ( i = 0; i < (sizeof(device_table) / sizeof(device_table[0])); i += 1 ) + { + if ( !device_table[i] ) + break; + } - /* The filesystem must support these ops. */ - if ((file.device->type & 0xf0000000) != IOP_DT_FSEXT) - return -48; + if ( i >= (sizeof(device_table) / sizeof(device_table[0])) ) + { + adddeldrv_in_process = 0; + return -1; + } - return file.device->ops->devctl(&file, filename, cmd, arg, arglen, buf, buflen); + device_table[i] = device; +#ifdef _IOP + FlushIcache(); +#endif + if ( device->ops->init(device) < 0 ) + { + device_table[i] = NULL; + adddeldrv_in_process = 0; + return -1; + } +#endif + showdrvflag = 1; + adddeldrv_in_process = 0; + return 0; } -int iomanX_symlink(const char *old, const char *new) +int iomanX_DelDrv(const char *name) { - return link_common(old, new, 8); +#ifdef IOMANX_USE_DEVICE_LINKED_LIST + struct ioman_dev_listentry *entry; + struct ioman_dev_listentry **p_next; + struct ioman_dev_listentry *old_head; +#else + unsigned int i; +#endif + int state; + + CpuSuspendIntr(&state); + if ( adddeldrv_in_process ) + { + Kprintf("AddDrv()/DelDrv() recursive/mutithread call error !!"); + CpuResumeIntr(state); + return -1; + } + adddeldrv_in_process = 1; + CpuResumeIntr(state); +#ifdef IOMANX_USE_DEVICE_LINKED_LIST + entry = device_entry_used_list_head; + p_next = &device_entry_used_list_head; + while ( entry && strcmp(name, entry->device->name) ) + { + p_next = &entry->next; + entry = entry->next; + } + if ( !entry || entry->device->ops->deinit(entry->device) < 0 ) + { + adddeldrv_in_process = 0; + return -1; + } + old_head = device_entry_empty_list_head; + entry->device = NULL; + device_entry_empty_list_head = entry; + *p_next = entry->next; + entry->next = old_head; + adddeldrv_in_process = 0; + return 0; +#else + for ( i = 0; i < (sizeof(device_table) / sizeof(device_table[0])); i += 1 ) + { + if ( device_table[i] && !strcmp(name, device_table[i]->name) ) + { + device_table[i]->ops->deinit(device_table[i]); + device_table[i] = NULL; + adddeldrv_in_process = 0; + return 0; + } + } + + adddeldrv_in_process = 0; + return -1; +#endif } -int iomanX_readlink(const char *name, char *buf, unsigned int buflen) +#ifndef IOMANX_ENABLE_LEGACY_IOMAN_HOOK +unsigned int iomanX_GetDevType(int fd) { - iomanX_iop_file_t file; - char *filename; + iomanX_iop_file_t *f; - if ((filename = find_iop_device(name, &file.unit, &file.device)) == (char *)-1) - return -ENODEV; + f = get_iob(fd); + if ( !f ) + return handle_result(-EBADF, f, 0); + return f->device->type; +} +#endif - /* The filesystem must support these ops. */ - if ((file.device->type & 0xf0000000) != IOP_DT_FSEXT) - return -48; +static void ShowDrv(void) +{ +#ifdef IOMANX_USE_DEVICE_LINKED_LIST + struct ioman_dev_listentry *i; +#else + unsigned int i; +#endif - return file.device->ops->readlink(&file, filename, buf, buflen); + if ( !showdrvflag ) + return; + Kprintf("Known devices are "); +#ifdef IOMANX_USE_DEVICE_LINKED_LIST + for ( i = device_entry_used_list_head; i; i = i->next ) + Kprintf(" %s:(%s) ", i->device->name, i->device->desc); +#else + for ( i = 0; i < (sizeof(device_table) / sizeof(device_table[0])); i += 1 ) + if ( device_table[i] != NULL && device_table[i]->name != NULL ) + Kprintf(" %s:(%s) ", device_table[i]->name, device_table[i]->desc); +#endif + Kprintf("\n"); + showdrvflag = 0; } - -int iomanX_ioctl2(int fd, int command, void *arg, unsigned int arglen, void *buf, unsigned int buflen) +#ifndef IOMANX_ENABLE_LEGACY_IOMAN_HOOK +static void register_tty(void) { - iomanX_iop_file_t *f; - - if ((f = get_file(fd)) == NULL) - return -EBADF; + iomanX_DelDrv(dev_tty.name); + iomanX_AddDrv(&dev_tty); +} - return f->device->ops->ioctl2(f, command, arg, arglen, buf, buflen); +static void register_dummytty(void) +{ + iomanX_DelDrv(dev_dummytty.name); + iomanX_AddDrv(&dev_dummytty); } +#endif diff --git a/iop/system/iomanx/src/irx_imports.h b/iop/system/iomanx/src/irx_imports.h index f1365570f68..6cc871b9ad0 100644 --- a/iop/system/iomanx/src/irx_imports.h +++ b/iop/system/iomanx/src/irx_imports.h @@ -19,6 +19,7 @@ #include "loadcore.h" #include "stdio.h" #include "sysclib.h" +#include "sysmem.h" #include "intrman.h" #endif /* IOP_IRX_IMPORTS_H */