#include #include #include "kprintf.h" #include "syscall.h" #include "errors.h" #include "spinlock/spinlock.h" #include "proc/proc.h" #include "sysdefs/devctl.h" #include "util/util.h" #include "hshtb.h" #include "dev/dev.h" int32_t SYSCALL5(sys_devctl, devh1, cmd1, buffer1, len1, extra1) { uint64_t *devh = (uint64_t *)devh1; uint64_t cmd = cmd1; int32_t ret = E_OK; spinlock_acquire(&PROCS.spinlock); Proc *proc = PROCS.current; spinlock_release(&PROCS.spinlock); switch (cmd) { case DEVCTL_GET_HANDLE: { char *ident = (char *)buffer1; if (ident == NULL) { ret = E_INVALIDARGUMENT; goto done; } spinlock_acquire(&DEVTABLE.spinlock); Dev *founddev; HSHTB_GET(DEVTABLE.devs, ident, ident, founddev); spinlock_release(&DEVTABLE.spinlock); if (founddev == NULL) { ret = E_NOENTRY; goto done; } bool found = false; for (size_t i = 0; i < PROC_DEVHANDLES_MAX; i++) { if (proc->devs[i] == NULL) { found = true; proc->devs[i] = founddev; *devh = i; break; } } if (!found) { ret = E_NOMEMORY; goto done; } } break; case DEVCTL_DEVLS_SZ: { size_t n = 0; spinlock_acquire(&DEVTABLE.spinlock); for (size_t i = 0; i < LEN(DEVTABLE.devs); i++) { if (DEVTABLE.devs[i]._hshtbstate == HSHTB_TAKEN) { n++; } } spinlock_release(&DEVTABLE.spinlock); ret = n; } break; case DEVCTL_DEVLS_STAT: { DevStat *devstat = (DevStat *)buffer1; size_t idx = (size_t)len1; if (devstat == NULL) { ret = E_INVALIDARGUMENT; goto done; } devstat->present = false; spinlock_acquire(&DEVTABLE.spinlock); for (size_t i = 0; i < LEN(DEVTABLE.devs); i++) { if (i == idx && DEVTABLE.devs[i]._hshtbstate == HSHTB_TAKEN) { Dev *dev = &DEVTABLE.devs[i]; hal_memcpy(devstat->name, dev->ident, sizeof(dev->ident)); for (size_t j = 0; j < DEV_FNS_MAX; j++) { if (dev->fns[j] != NULL) { devstat->nfns++; } } devstat->present = true; break; } } spinlock_release(&DEVTABLE.spinlock); } break; default: { if (devh == NULL) { ret = E_INVALIDARGUMENT; goto done; } if (cmd >= DEV_FNS_MAX) { ret = E_INVALIDARGUMENT; goto done; } Dev *dev = proc->devs[*devh]; if (dev == NULL) { ret = E_NOENTRY; goto done; } spinlock_acquire(&dev->spinlock); ret = dev->fns[cmd]((uint8_t *)buffer1, (size_t)len1, (void *)extra1); spinlock_release(&dev->spinlock); } break; } done: return ret; }