/* This file is part of Fennix Kernel. Fennix Kernel is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Fennix Kernel is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Fennix Kernel. If not, see . */ #include #include "../../kernel.h" namespace Driver { dev_t DeviceDirID; int __fs_Lookup(struct Inode *_Parent, const char *Name, struct Inode **Result) { func("%#lx %s %#lx", _Parent, Name, Result); assert(_Parent != nullptr); const char *basename; size_t length; cwk_path_get_basename(Name, &basename, &length); if (basename == NULL) { error("Invalid name %s", Name); return -EINVAL; } auto Parent = (Manager::DeviceInode *)_Parent; for (const auto &child : Parent->Children) { debug("Comparing %s with %s", basename, child->Name.c_str()); if (strcmp(child->Name.c_str(), basename) != 0) continue; *Result = &child->inode; return 0; } debug("Not found %s", Name); return -ENOENT; } int __fs_Create(struct Inode *_Parent, const char *Name, mode_t Mode, struct Inode **Result) { func("%#lx %s %d", _Parent, Name, Mode); assert(_Parent != nullptr); /* We expect to be /dev or children of it */ auto Parent = (Manager::DeviceInode *)_Parent; auto _dev = new Manager::DeviceInode; _dev->Parent = nullptr; _dev->ParentInode = _Parent; _dev->Name = Name; _dev->inode.Device = Parent->inode.Device; _dev->inode.Mode = Mode; _dev->inode.Index = Parent->inode.Index + Parent->Children.size(); _dev->inode.Offset = Parent->Children.size(); Parent->Children.push_back(_dev); *Result = &_dev->inode; return 0; } ssize_t __fs_Read(struct Inode *Node, void *Buffer, size_t Size, off_t Offset) { func("%#lx %d %d", Node, Size, Offset); if ((dev_t)Node->GetMajor() == DeviceDirID) { switch (Node->GetMinor()) { case 0: /* /dev/input/keyboard */ { if (Size < sizeof(KeyboardReport)) return -EINVAL; size_t nReads = Size / sizeof(KeyboardReport); KeyboardReport *report = (KeyboardReport *)Buffer; while (DriverManager->GlobalKeyboardInputReports.Count() == 0) TaskManager->Yield(); DriverManager->GlobalKeyboardInputReports.Read(report, nReads); return sizeof(KeyboardReport) * nReads; } case 1: /* /dev/input/mouse */ { if (Size < sizeof(MouseReport)) return -EINVAL; size_t nReads = Size / sizeof(MouseReport); MouseReport *report = (MouseReport *)Buffer; while (DriverManager->GlobalMouseInputReports.Count() == 0) TaskManager->Yield(); DriverManager->GlobalMouseInputReports.Read(report, nReads); return sizeof(MouseReport) * nReads; } default: return -ENOENT; }; } std::unordered_map &drivers = DriverManager->GetDrivers(); const auto it = drivers.find(Node->GetMajor()); if (it == drivers.end()) ReturnLogError(-EINVAL, "Driver %d not found", Node->GetMajor()); const Driver::DriverObject *drv = &it->second; auto dop = drv->DeviceOperations; auto dOps = dop->find(Node->GetMinor()); if (dOps == dop->end()) ReturnLogError(-EINVAL, "Device %d not found", Node->GetMinor()); AssertReturnError(dOps->second.Ops, -ENOTSUP); AssertReturnError(dOps->second.Ops->Read, -ENOTSUP); return dOps->second.Ops->Read(Node, Buffer, Size, Offset); } ssize_t __fs_Write(struct Inode *Node, const void *Buffer, size_t Size, off_t Offset) { func("%#lx %p %d %d", Node, Buffer, Size, Offset); if ((dev_t)Node->GetMajor() == DeviceDirID) { switch (Node->GetMinor()) { case 0: /* /dev/input/keyboard */ { return -ENOTSUP; } case 1: /* /dev/input/mouse */ { return -ENOTSUP; } default: return -ENOENT; }; } std::unordered_map &drivers = DriverManager->GetDrivers(); const auto it = drivers.find(Node->GetMajor()); if (it == drivers.end()) ReturnLogError(-EINVAL, "Driver %d not found", Node->GetMajor()); const Driver::DriverObject *drv = &it->second; auto dop = drv->DeviceOperations; auto dOps = dop->find(Node->GetMinor()); if (dOps == dop->end()) ReturnLogError(-EINVAL, "Device %d not found", Node->GetMinor()); AssertReturnError(dOps->second.Ops, -ENOTSUP); AssertReturnError(dOps->second.Ops->Write, -ENOTSUP); return dOps->second.Ops->Write(Node, Buffer, Size, Offset); } int __fs_Open(struct Inode *Node, int Flags, mode_t Mode) { func("%#lx %d %d", Node, Flags, Mode); if ((dev_t)Node->GetMajor() == DeviceDirID) { switch (Node->GetMinor()) { case 0: /* /dev/input/keyboard */ case 1: /* /dev/input/mouse */ return -ENOTSUP; default: return -ENOENT; }; } std::unordered_map &drivers = DriverManager->GetDrivers(); const auto it = drivers.find(Node->GetMajor()); if (it == drivers.end()) ReturnLogError(-EINVAL, "Driver %d not found", Node->GetMajor()); const Driver::DriverObject *drv = &it->second; auto dop = drv->DeviceOperations; auto dOps = dop->find(Node->GetMinor()); if (dOps == dop->end()) ReturnLogError(-EINVAL, "Device %d not found", Node->GetMinor()); AssertReturnError(dOps->second.Ops, -ENOTSUP); AssertReturnError(dOps->second.Ops->Open, -ENOTSUP); return dOps->second.Ops->Open(Node, Flags, Mode); } int __fs_Close(struct Inode *Node) { func("%#lx", Node); if ((dev_t)Node->GetMajor() == DeviceDirID) { switch (Node->GetMinor()) { case 0: /* /dev/input/keyboard */ case 1: /* /dev/input/mouse */ return -ENOTSUP; default: return -ENOENT; }; } std::unordered_map &drivers = DriverManager->GetDrivers(); const auto it = drivers.find(Node->GetMajor()); if (it == drivers.end()) ReturnLogError(-EINVAL, "Driver %d not found", Node->GetMajor()); const Driver::DriverObject *drv = &it->second; auto dop = drv->DeviceOperations; auto dOps = dop->find(Node->GetMinor()); if (dOps == dop->end()) ReturnLogError(-EINVAL, "Device %d not found", Node->GetMinor()); AssertReturnError(dOps->second.Ops, -ENOTSUP); AssertReturnError(dOps->second.Ops->Close, -ENOTSUP); return dOps->second.Ops->Close(Node); } int __fs_Ioctl(struct Inode *Node, unsigned long Request, void *Argp) { func("%#lx %lu %#lx", Node, Request, Argp); if ((dev_t)Node->GetMajor() == DeviceDirID) { switch (Node->GetMinor()) { case 0: /* /dev/input/keyboard */ case 1: /* /dev/input/mouse */ return -ENOSYS; default: return -ENOENT; }; } std::unordered_map &drivers = DriverManager->GetDrivers(); const auto it = drivers.find(Node->GetMajor()); if (it == drivers.end()) ReturnLogError(-EINVAL, "Driver %d not found", Node->GetMajor()); const Driver::DriverObject *drv = &it->second; auto dop = drv->DeviceOperations; auto dOps = dop->find(Node->GetMinor()); if (dOps == dop->end()) ReturnLogError(-EINVAL, "Device %d not found", Node->GetMinor()); AssertReturnError(dOps->second.Ops, -ENOTSUP); AssertReturnError(dOps->second.Ops->Ioctl, -ENOTSUP); return dOps->second.Ops->Ioctl(Node, Request, Argp); } __no_sanitize("alignment") ssize_t __fs_Readdir(struct Inode *_Node, struct kdirent *Buffer, size_t Size, off_t Offset, off_t Entries) { func("%#lx %#lx %d %d %d", _Node, Buffer, Size, Offset, Entries); auto node = (Manager::DeviceInode *)_Node; off_t realOffset = Offset; size_t totalSize = 0; uint16_t reclen = 0; struct kdirent *ent = nullptr; if (!S_ISDIR(node->inode.Mode)) return -ENOTDIR; if (Offset == 0) { reclen = (uint16_t)(offsetof(struct kdirent, d_name) + strlen(".") + 1); if (totalSize + reclen > Size) return -EINVAL; ent = (struct kdirent *)((uintptr_t)Buffer + totalSize); ent->d_ino = node->inode.Index; ent->d_off = 0; ent->d_reclen = reclen; ent->d_type = DT_DIR; strcpy(ent->d_name, "."); totalSize += reclen; Offset++; } if (Offset == 1) { reclen = (uint16_t)(offsetof(struct kdirent, d_name) + strlen("..") + 1); if (totalSize + reclen > Size) return totalSize; ent = (struct kdirent *)((uintptr_t)Buffer + totalSize); if (node->Parent) ent->d_ino = node->Parent->inode->Index; else if (node->ParentInode) ent->d_ino = node->ParentInode->Index; else ent->d_ino = node->inode.Index; ent->d_off = 1; ent->d_reclen = reclen; ent->d_type = DT_DIR; strcpy(ent->d_name, ".."); totalSize += reclen; Offset++; } off_t entryIndex = 0; for (const auto &var : node->Children) { if (entryIndex + 2 < realOffset) { entryIndex++; continue; } if (Entries && entryIndex >= Entries) break; reclen = (uint16_t)(offsetof(struct kdirent, d_name) + strlen(var->Name.c_str()) + 1); if (totalSize + reclen > Size) break; ent = (struct kdirent *)((uintptr_t)Buffer + totalSize); ent->d_ino = var->inode.Index; ent->d_off = entryIndex + 2; ent->d_reclen = reclen; ent->d_type = IFTODT(var->inode.Mode); strcpy(ent->d_name, var->Name.c_str()); totalSize += reclen; entryIndex++; } if (totalSize + offsetof(struct kdirent, d_name) + 1 > Size) return totalSize; ent = (struct kdirent *)((uintptr_t)Buffer + totalSize); ent->d_ino = 0; ent->d_off = 0; ent->d_reclen = 0; ent->d_type = DT_UNKNOWN; ent->d_name[0] = '\0'; return totalSize; } int __fs_Stat(struct Inode *_Node, struct kstat *Stat) { func("%#lx %#lx", _Node, Stat); auto node = (Manager::DeviceInode *)_Node; assert(node != nullptr); assert(Stat != nullptr); Stat->Device = node->inode.Device; Stat->Index = node->inode.Index; Stat->HardLinks = 1; Stat->UserID = 0; Stat->GroupID = 0; Stat->RawDevice = node->inode.RawDevice; Stat->Size = node->Size; Stat->AccessTime = node->AccessTime; Stat->ModifyTime = node->ModifyTime; Stat->ChangeTime = node->ChangeTime; Stat->BlockSize = node->BlockSize; Stat->Blocks = node->Blocks; Stat->Attribute = 0; return 0; } void Manager::InitializeDeviceDirectory() { dev_t MinorID = 0; DeviceInode *_dev = new DeviceInode; _dev->Name = "dev"; /* d rwx r-- r-- */ mode_t mode = S_IRWXU | S_IRGRP | S_IROTH | S_IFDIR; Inode *dev = (Inode *)_dev; dev->Mode = mode; FileSystemInfo *fsi = new FileSystemInfo; fsi->Name = "Device Virtual File System"; fsi->SuperOps = {}; fsi->Ops.Lookup = __fs_Lookup; fsi->Ops.Create = __fs_Create; fsi->Ops.Remove = nullptr; fsi->Ops.Rename = nullptr; fsi->Ops.Read = __fs_Read; fsi->Ops.Write = __fs_Write; fsi->Ops.Truncate = nullptr; fsi->Ops.Open = __fs_Open; fsi->Ops.Close = __fs_Close; fsi->Ops.Ioctl = __fs_Ioctl; fsi->Ops.ReadDir = __fs_Readdir; fsi->Ops.MkDir = nullptr; fsi->Ops.RmDir = nullptr; fsi->Ops.SymLink = nullptr; fsi->Ops.ReadLink = nullptr; fsi->Ops.Seek = nullptr; fsi->Ops.Stat = __fs_Stat; DeviceDirID = dev->Device = fs->RegisterFileSystem(fsi); dev->SetDevice(0, MinorID++); Node root = fs->GetRoot(0); devNode = fs->Mount(root, dev, "dev", fsi); assert(devNode->Parent != nullptr); _dev->Parent = devNode->Parent; _dev->ParentInode = devNode->Parent->inode; /* d rwx r-- r-- */ mode = S_IRWXU | S_IRGRP | S_IROTH | S_IFDIR; DeviceInode *blk = new DeviceInode; blk->Parent = devNode; blk->ParentInode = devNode->inode; blk->Name = "block"; blk->inode.Device = dev->Device; blk->inode.Mode = mode; blk->inode.Offset = _dev->Children.size(); _dev->Children.push_back(blk); devBlockNode = fs->Lookup(devNode, "block"); /* d rwx r-- r-- */ mode = S_IRWXU | S_IRGRP | S_IROTH | S_IFDIR; DeviceInode *input = new DeviceInode; input->Parent = devNode; input->ParentInode = devNode->inode; input->Name = "input"; input->inode.Device = dev->Device; input->inode.Mode = mode; input->inode.Offset = _dev->Children.size(); _dev->Children.push_back(input); devInputNode = fs->Lookup(devNode, "input"); auto createDevice = [](DeviceInode *p1, Node p2, const std::string &name, dev_t maj, dev_t min, mode_t mode) { DeviceInode *device = new DeviceInode; device->Parent = p2; device->ParentInode = p2->inode; device->Name = name; device->inode.Device = p2->inode->Device; device->inode.Mode = mode; device->inode.SetDevice(maj, min); device->inode.Offset = p1->Children.size(); p1->Children.push_back(device); }; MinorID = 0; /* c rw- r-- --- */ mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IFCHR; createDevice(input, devInputNode, "keyboard", DeviceDirID, MinorID++, mode); /* c rw- r-- --- */ mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IFCHR; createDevice(input, devInputNode, "mouse", DeviceDirID, MinorID++, mode); } }