diff --git a/src/arch/x86_64/syscall.asm b/src/arch/x86_64/syscall.asm index ac3edeb8..24af9504 100644 --- a/src/arch/x86_64/syscall.asm +++ b/src/arch/x86_64/syscall.asm @@ -22,7 +22,8 @@ extern syscall_dup2 extern syscall_fcntl extern syscall_getpid extern syscall_getdirent -func_count equ 21 +extern syscall_ioctl +func_count equ 22 func_table: @@ -47,6 +48,7 @@ func_table: dq syscall_fcntl dq syscall_getpid dq syscall_getdirent + dq syscall_ioctl section .text global asm_syscall_entry diff --git a/src/fs/vfs.c b/src/fs/vfs.c index 2a4b97d1..b9a8a94a 100644 --- a/src/fs/vfs.c +++ b/src/fs/vfs.c @@ -95,6 +95,15 @@ int vfs_isatty(vnode_t* node){ } +int vfs_ioctl(vnode_t* node, unsigned long request, void* arg, int* result){ + + if(GETTYPE(node->st.st_mode) != TYPE_CHARDEV) + return ENOTTY; + + return devman_ioctl(node->st.st_rdev, request, arg, result); + +} + int vfs_read(int* error, vnode_t* node, void* buff, size_t count, size_t offset){ int type = GETTYPE(node->st.st_mode); diff --git a/src/include/kernel/devman.h b/src/include/kernel/devman.h index 68bab37b..e387307c 100644 --- a/src/include/kernel/devman.h +++ b/src/include/kernel/devman.h @@ -14,6 +14,7 @@ typedef struct{ int (*write)(int* error, int minor, void* buff, size_t count, size_t offset); int (*isatty)(int minor); int (*isseekable)(int minor, size_t* seekmax); + int (*ioctl)(int minor, unsigned long request, void* arg, int* result); } devcalls; int devman_read(int *error, int dev, void* buff, size_t count, size_t offset); @@ -21,6 +22,7 @@ int devman_write(int *error, int dev, void* buff, size_t count, size_t offset); int devman_newdevice(char* name, int type, int major, int minor, devcalls* calls); int devman_isatty(int dev); int devman_isseekable(int dev, size_t* seekmax); +int devman_ioctl(int dev, unsigned long request, void* arg, int* result); void devman_init(); #endif diff --git a/src/include/kernel/vfs.h b/src/include/kernel/vfs.h index 55eaa654..9176f719 100644 --- a/src/include/kernel/vfs.h +++ b/src/include/kernel/vfs.h @@ -72,6 +72,7 @@ int vfs_write(int* error, vnode_t* node, void* buff, size_t count, size_t offset int vfs_read(int* error, vnode_t* node, void* buff, size_t count, size_t offset); int vfs_isatty(vnode_t* node); int vfs_getdirent(dirnode_t* node, dent_t* buff, size_t count, uintmax_t offset, size_t* readcount); +int vfs_ioctl(vnode_t* node, unsigned long request, void* arg, int* result); void vfs_init(); dirnode_t* vfs_root(); diff --git a/src/sys/devman.c b/src/sys/devman.c index b6908566..69806f9c 100644 --- a/src/sys/devman.c +++ b/src/sys/devman.c @@ -65,6 +65,15 @@ int devman_isseekable(int dev, size_t* max){ } +int devman_ioctl(int dev, unsigned long request, void* arg, int* result){ + if(major(dev) > highestmajor) + return ENOTTY; + + if(!majorcalls[major(dev)]->ioctl) + return ENOTTY; + + return majorcalls[major(dev)]->ioctl(minor(dev), request, arg, result); +} void devman_init(){ diff --git a/src/sys/syscalls/ioctl.c b/src/sys/syscalls/ioctl.c new file mode 100644 index 00000000..99ad2996 --- /dev/null +++ b/src/sys/syscalls/ioctl.c @@ -0,0 +1,30 @@ +#include +#include +#include +#include +#include +#include + +syscallret syscall_ioctl(int ifd, unsigned long request, void* arg){ + syscallret retv; + retv.ret = -1; + + proc_t* proc = arch_getcls()->thread->proc; + + fd_t* fd; + + int ret = fd_access(&proc->fdtable, &fd, ifd); + + if(ret){ + retv.errno = ret; + return retv; + } + + retv.ret = 0; + retv.errno = vfs_ioctl(fd->node, request, arg, &retv.ret); + + fd_release(fd); + + return retv; + +}