/*
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);
}
}