mirror of
https://github.com/Fennix-Project/Kernel.git
synced 2025-05-25 22:14:37 +00:00
866 lines
21 KiB
C++
866 lines
21 KiB
C++
/*
|
|
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 <https://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include <driver.hpp>
|
|
|
|
#include <interface/driver.h>
|
|
#include <interface/input.h>
|
|
#include <memory.hpp>
|
|
#include <stropts.h>
|
|
#include <ints.hpp>
|
|
#include <task.hpp>
|
|
#include <printf.h>
|
|
#include <exec.hpp>
|
|
#include <rand.hpp>
|
|
#include <cwalk.h>
|
|
#include <md5.h>
|
|
|
|
#include "../../kernel.h"
|
|
|
|
using namespace vfs;
|
|
|
|
namespace Driver
|
|
{
|
|
/**
|
|
* maj = 0
|
|
* min:
|
|
* 0 - <ROOT>
|
|
* 1 - /proc/self
|
|
* 2 - /dev/null
|
|
* 3 - /dev/zero
|
|
* 4 - /dev/random
|
|
* 5 - /dev/mem
|
|
* 6 - /dev/kcon
|
|
* 7 - /dev/tty
|
|
* 8 - /dev/ptmx
|
|
*
|
|
* maj = 1
|
|
* min:
|
|
* 0 - /dev/input/keyboard
|
|
* 1 - /dev/input/mouse
|
|
* ..- /dev/input/eventX
|
|
*/
|
|
|
|
TTY::PTMXDevice *ptmx = nullptr;
|
|
|
|
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->Node;
|
|
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->Node.Mode = Mode;
|
|
_dev->Node.Index = Parent->Node.Index + Parent->Children.size();
|
|
Parent->Children.push_back(_dev);
|
|
|
|
*Result = &_dev->Node;
|
|
return 0;
|
|
}
|
|
|
|
ssize_t __fs_Read(struct Inode *Node, void *Buffer, size_t Size, off_t Offset)
|
|
{
|
|
func("%#lx %d %d", Node, Size, Offset);
|
|
switch (Node->GetMajor())
|
|
{
|
|
case 0:
|
|
{
|
|
switch (Node->GetMinor())
|
|
{
|
|
case 2: /* /dev/null */
|
|
{
|
|
return 0;
|
|
}
|
|
case 3: /* /dev/zero */
|
|
{
|
|
if (Size <= 0)
|
|
return 0;
|
|
|
|
memset(Buffer, 0, Size);
|
|
return Size;
|
|
}
|
|
case 4: /* /dev/random */
|
|
{
|
|
if (Size <= 0)
|
|
return 0;
|
|
|
|
if (Size < sizeof(uint64_t))
|
|
{
|
|
uint8_t *buf = (uint8_t *)Buffer;
|
|
for (size_t i = 0; i < Size; i++)
|
|
buf[i] = (uint8_t)(Random::rand16() & 0xFF);
|
|
return Size;
|
|
}
|
|
|
|
uint64_t *buf = (uint64_t *)Buffer;
|
|
for (size_t i = 0; i < Size / sizeof(uint64_t); i++)
|
|
buf[i] = Random::rand64();
|
|
return Size;
|
|
}
|
|
case 5: /* /dev/mem */
|
|
{
|
|
stub;
|
|
return 0;
|
|
}
|
|
case 6: /* /dev/kcon */
|
|
return KernelConsole::CurrentTerminal.load()->Read(Buffer, Size, Offset);
|
|
case 7: /* /dev/tty */
|
|
return ((TTY::TeletypeDriver *)thisProcess->tty)->Read(Buffer, Size, Offset);
|
|
case 8: /* /dev/ptmx */
|
|
return -ENOSYS;
|
|
default:
|
|
return -ENOENT;
|
|
};
|
|
break;
|
|
}
|
|
case 1:
|
|
{
|
|
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;
|
|
};
|
|
}
|
|
default:
|
|
{
|
|
std::unordered_map<dev_t, Driver::DriverObject> &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);
|
|
|
|
switch (Node->GetMajor())
|
|
{
|
|
case 0:
|
|
{
|
|
switch (Node->GetMinor())
|
|
{
|
|
case 2: /* /dev/null */
|
|
{
|
|
return Size;
|
|
}
|
|
case 3: /* /dev/zero */
|
|
{
|
|
return Size;
|
|
}
|
|
case 4: /* /dev/random */
|
|
{
|
|
return Size;
|
|
}
|
|
case 5: /* /dev/mem */
|
|
{
|
|
stub;
|
|
return 0;
|
|
}
|
|
case 6: /* /dev/kcon */
|
|
return KernelConsole::CurrentTerminal.load()->Write(Buffer, Size, Offset);
|
|
case 7: /* /dev/tty */
|
|
return ((TTY::TeletypeDriver *)thisProcess->tty)->Write(Buffer, Size, Offset);
|
|
case 8: /* /dev/ptmx */
|
|
return -ENOSYS;
|
|
default:
|
|
return -ENOENT;
|
|
};
|
|
}
|
|
case 1:
|
|
{
|
|
switch (Node->GetMinor())
|
|
{
|
|
case 0: /* /dev/input/keyboard */
|
|
{
|
|
return -ENOTSUP;
|
|
}
|
|
case 1: /* /dev/input/mouse */
|
|
{
|
|
return -ENOTSUP;
|
|
}
|
|
default:
|
|
return -ENOENT;
|
|
};
|
|
}
|
|
default:
|
|
{
|
|
std::unordered_map<dev_t, Driver::DriverObject> &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);
|
|
|
|
switch (Node->GetMajor())
|
|
{
|
|
case 0:
|
|
{
|
|
switch (Node->GetMinor())
|
|
{
|
|
case 2: /* /dev/null */
|
|
case 3: /* /dev/zero */
|
|
case 4: /* /dev/random */
|
|
case 5: /* /dev/mem */
|
|
return -ENOSYS;
|
|
case 6: /* /dev/kcon */
|
|
return KernelConsole::CurrentTerminal.load()->Open(Flags, Mode);
|
|
case 7: /* /dev/tty */
|
|
return ((TTY::TeletypeDriver *)thisProcess->tty)->Open(Flags, Mode);
|
|
case 8: /* /dev/ptmx */
|
|
return ptmx->Open();
|
|
default:
|
|
return -ENOENT;
|
|
};
|
|
}
|
|
case 1:
|
|
{
|
|
switch (Node->GetMinor())
|
|
{
|
|
case 0: /* /dev/input/keyboard */
|
|
case 1: /* /dev/input/mouse */
|
|
return -ENOTSUP;
|
|
default:
|
|
return -ENOENT;
|
|
};
|
|
}
|
|
default:
|
|
{
|
|
std::unordered_map<dev_t, Driver::DriverObject> &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);
|
|
|
|
switch (Node->GetMajor())
|
|
{
|
|
case 0:
|
|
{
|
|
switch (Node->GetMinor())
|
|
{
|
|
case 2: /* /dev/null */
|
|
case 3: /* /dev/zero */
|
|
case 4: /* /dev/random */
|
|
case 5: /* /dev/mem */
|
|
return -ENOSYS;
|
|
case 6: /* /dev/kcon */
|
|
return KernelConsole::CurrentTerminal.load()->Close();
|
|
case 7: /* /dev/tty */
|
|
return ((TTY::TeletypeDriver *)thisProcess->tty)->Close();
|
|
case 8: /* /dev/ptmx */
|
|
return ptmx->Close();
|
|
default:
|
|
return -ENOENT;
|
|
};
|
|
}
|
|
case 1:
|
|
{
|
|
switch (Node->GetMinor())
|
|
{
|
|
case 0: /* /dev/input/keyboard */
|
|
case 1: /* /dev/input/mouse */
|
|
return -ENOTSUP;
|
|
default:
|
|
return -ENOENT;
|
|
};
|
|
}
|
|
default:
|
|
{
|
|
std::unordered_map<dev_t, Driver::DriverObject> &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);
|
|
|
|
switch (Node->GetMajor())
|
|
{
|
|
case 0:
|
|
{
|
|
switch (Node->GetMinor())
|
|
{
|
|
case 2: /* /dev/null */
|
|
case 3: /* /dev/zero */
|
|
case 4: /* /dev/random */
|
|
case 5: /* /dev/mem */
|
|
return -ENOSYS;
|
|
case 6: /* /dev/kcon */
|
|
return KernelConsole::CurrentTerminal.load()->Ioctl(Request, Argp);
|
|
case 7: /* /dev/tty */
|
|
return ((TTY::TeletypeDriver *)thisProcess->tty)->Ioctl(Request, Argp);
|
|
case 8: /* /dev/ptmx */
|
|
return -ENOSYS;
|
|
default:
|
|
return -ENOENT;
|
|
};
|
|
break;
|
|
}
|
|
case 1:
|
|
{
|
|
switch (Node->GetMinor())
|
|
{
|
|
case 0: /* /dev/input/keyboard */
|
|
case 1: /* /dev/input/mouse */
|
|
return -ENOSYS;
|
|
default:
|
|
return -ENOENT;
|
|
};
|
|
}
|
|
default:
|
|
{
|
|
std::unordered_map<dev_t, Driver::DriverObject> &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 (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->Node.Index;
|
|
ent->d_off = Offset++;
|
|
ent->d_reclen = reclen;
|
|
ent->d_type = DT_DIR;
|
|
strcpy(ent->d_name, ".");
|
|
totalSize += reclen;
|
|
}
|
|
|
|
if (Offset <= 1)
|
|
{
|
|
reclen = (uint16_t)(offsetof(struct kdirent, d_name) + strlen("..") + 1);
|
|
if (totalSize + reclen >= Size)
|
|
{
|
|
if (realOffset == 1)
|
|
return -EINVAL;
|
|
return totalSize;
|
|
}
|
|
|
|
ent = (struct kdirent *)((uintptr_t)Buffer + totalSize);
|
|
|
|
if (Node->Parent)
|
|
ent->d_ino = Node->Parent->Node->Index;
|
|
else if (Node->ParentInode)
|
|
ent->d_ino = Node->ParentInode->Index;
|
|
else
|
|
{
|
|
warn("Parent is null for %s", Node->Name.c_str());
|
|
ent->d_ino = Node->Node.Index;
|
|
}
|
|
ent->d_off = Offset++;
|
|
ent->d_reclen = reclen;
|
|
ent->d_type = DT_DIR;
|
|
strcpy(ent->d_name, "..");
|
|
totalSize += reclen;
|
|
}
|
|
|
|
if (!S_ISDIR(Node->Node.Mode))
|
|
return -ENOTDIR;
|
|
|
|
if ((Offset >= 2 ? (Offset - 2) : Offset) > (off_t)Node->Children.size())
|
|
return -EINVAL;
|
|
|
|
off_t entries = 0;
|
|
for (const auto &var : Node->Children)
|
|
{
|
|
debug("iterating \"%s\" inside \"%s\"", var->Name.c_str(), Node->Name.c_str());
|
|
if (var->Node.Offset < realOffset)
|
|
{
|
|
debug("skipping \"%s\" (%d < %d)", var->Name.c_str(), var->Node.Offset, Offset);
|
|
continue;
|
|
}
|
|
|
|
if (entries >= 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->Node.Index;
|
|
ent->d_off = var->Node.Offset;
|
|
ent->d_reclen = reclen;
|
|
ent->d_type = IFTODT(var->Node.Mode);
|
|
strncpy(ent->d_name, var->Name.c_str(), strlen(var->Name.c_str()));
|
|
|
|
totalSize += reclen;
|
|
entries++;
|
|
}
|
|
|
|
if (totalSize + sizeof(struct kdirent) >= 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;
|
|
}
|
|
|
|
void ManagerDaemonWrapper() { DriverManager->Daemon(); }
|
|
|
|
void Manager::Daemon()
|
|
{
|
|
while (true)
|
|
{
|
|
TaskManager->Sleep(1000);
|
|
}
|
|
}
|
|
|
|
dev_t Manager::RegisterInputDevice(std::unordered_map<dev_t, DriverHandlers> *dop,
|
|
dev_t DriverID, size_t i, const InodeOperations *Operations)
|
|
{
|
|
std::string prefix = "event";
|
|
for (size_t j = 0; j < 128; j++)
|
|
{
|
|
std::string deviceName = prefix + std::to_string(j);
|
|
FileNode *node = fs->GetByPath(deviceName.c_str(), devInputNode);
|
|
if (node)
|
|
continue;
|
|
|
|
/* c rwx r-- r-- */
|
|
mode_t mode = S_IRWXU |
|
|
S_IRGRP |
|
|
S_IROTH |
|
|
S_IFCHR;
|
|
|
|
node = fs->ForceCreate(devInputNode, deviceName.c_str(), mode);
|
|
node->Node->SetDevice(DriverID, i);
|
|
|
|
DriverHandlers dh{};
|
|
dh.Ops = Operations;
|
|
dh.Node = node->Node;
|
|
dh.InputReports = new RingBuffer<InputReport>(16);
|
|
dop->insert({i, std::move(dh)});
|
|
return i;
|
|
}
|
|
|
|
ReturnLogError(-1, "No available slots for device %d", DriverID);
|
|
return -1; /* -Werror=return-type */
|
|
}
|
|
|
|
dev_t Manager::RegisterBlockDevice(std::unordered_map<dev_t, DriverHandlers> *dop,
|
|
dev_t DriverID, size_t i, const InodeOperations *Operations)
|
|
{
|
|
std::string prefix = "event";
|
|
for (size_t j = 0; j < 128; j++)
|
|
{
|
|
std::string deviceName = prefix + std::to_string(j);
|
|
FileNode *node = fs->GetByPath(deviceName.c_str(), devInputNode);
|
|
if (node)
|
|
continue;
|
|
|
|
/* c rwx r-- r-- */
|
|
mode_t mode = S_IRWXU |
|
|
S_IRGRP |
|
|
S_IROTH |
|
|
S_IFBLK;
|
|
|
|
node = fs->ForceCreate(devInputNode, deviceName.c_str(), mode);
|
|
node->Node->SetDevice(DriverID, i);
|
|
|
|
DriverHandlers dh{};
|
|
dh.Ops = Operations;
|
|
dh.Node = node->Node;
|
|
dh.InputReports = new RingBuffer<InputReport>(16);
|
|
dop->insert({i, std::move(dh)});
|
|
return i;
|
|
}
|
|
|
|
ReturnLogError(-1, "No available slots for device %d", DriverID);
|
|
return -1; /* -Werror=return-type */
|
|
}
|
|
|
|
dev_t Manager::RegisterDevice(dev_t DriverID, DeviceType Type, const InodeOperations *Operations)
|
|
{
|
|
std::unordered_map<dev_t, Driver::DriverObject> &drivers =
|
|
DriverManager->GetDrivers();
|
|
const auto it = drivers.find(DriverID);
|
|
if (it == drivers.end())
|
|
ReturnLogError(-EINVAL, "Driver %d not found", DriverID);
|
|
const Driver::DriverObject *drv = &it->second;
|
|
|
|
auto dop = drv->DeviceOperations;
|
|
for (size_t i = 0; i < 128; i++)
|
|
{
|
|
const auto dOps = dop->find(i);
|
|
const auto dOpsEnd = dop->end();
|
|
if (dOps != dOpsEnd)
|
|
continue;
|
|
|
|
DeviceType devType = (DeviceType)(Type & DEVICE_TYPE_MASK);
|
|
switch (devType)
|
|
{
|
|
case DEVICE_TYPE_INPUT:
|
|
return RegisterInputDevice(dop, DriverID, i, Operations);
|
|
case DEVICE_TYPE_BLOCK:
|
|
return RegisterBlockDevice(dop, DriverID, i, Operations);
|
|
default:
|
|
ReturnLogError(-1, "Invalid device type %d", Type);
|
|
}
|
|
}
|
|
|
|
ReturnLogError(-1, "No available slots for device %d", DriverID);
|
|
}
|
|
|
|
int Manager::UnregisterDevice(dev_t DriverID, dev_t Device)
|
|
{
|
|
std::unordered_map<dev_t, Driver::DriverObject> &drivers =
|
|
DriverManager->GetDrivers();
|
|
const auto it = drivers.find(DriverID);
|
|
if (it == drivers.end())
|
|
ReturnLogError(-EINVAL, "Driver %d not found", DriverID);
|
|
const Driver::DriverObject *drv = &it->second;
|
|
|
|
auto dop = drv->DeviceOperations;
|
|
const auto dOps = dop->find(Device);
|
|
if (dOps == dop->end())
|
|
ReturnLogError(-EINVAL, "Device %d not found", Device);
|
|
dop->erase(dOps);
|
|
fixme("remove eventX from /dev/input");
|
|
fixme("delete InputReports");
|
|
return 0;
|
|
}
|
|
|
|
int Manager::ReportInputEvent(dev_t DriverID, InputReport *Report)
|
|
{
|
|
std::unordered_map<dev_t, Driver::DriverObject> &drivers =
|
|
DriverManager->GetDrivers();
|
|
const auto it = drivers.find(DriverID);
|
|
if (it == drivers.end())
|
|
ReturnLogError(-EINVAL, "Driver %d not found", DriverID);
|
|
const Driver::DriverObject *drv = &it->second;
|
|
|
|
auto dop = drv->DeviceOperations;
|
|
auto dOps = dop->find(Report->Device);
|
|
if (dOps == dop->end())
|
|
ReturnLogError(-EINVAL, "Device %d not found", Report->Device);
|
|
|
|
dOps->second.InputReports->Write(Report, 1);
|
|
|
|
switch (Report->Type)
|
|
{
|
|
case INPUT_TYPE_KEYBOARD:
|
|
{
|
|
KeyboardReport *kReport = &Report->Keyboard;
|
|
GlobalKeyboardInputReports.Write(kReport, 1);
|
|
break;
|
|
}
|
|
case INPUT_TYPE_MOUSE:
|
|
{
|
|
MouseReport *mReport = &Report->Mouse;
|
|
GlobalMouseInputReports.Write(mReport, 1);
|
|
break;
|
|
}
|
|
default:
|
|
assert(!"Invalid input type");
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void Manager::InitializeDaemonFS()
|
|
{
|
|
ptmx = new TTY::PTMXDevice;
|
|
|
|
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;
|
|
dev->Flags = I_FLAG_MOUNTPOINT | I_FLAG_CACHE_KEEP;
|
|
|
|
FileSystemInfo *fsi = new FileSystemInfo;
|
|
fsi->Name = "Device Virtual File System";
|
|
fsi->RootName = "dev";
|
|
fsi->Flags = I_FLAG_ROOT | I_FLAG_MOUNTPOINT | I_FLAG_CACHE_KEEP;
|
|
fsi->SuperOps = {};
|
|
fsi->Ops.Lookup = __fs_Lookup;
|
|
fsi->Ops.Create = __fs_Create;
|
|
fsi->Ops.Read = __fs_Read;
|
|
fsi->Ops.Write = __fs_Write;
|
|
fsi->Ops.Open = __fs_Open;
|
|
fsi->Ops.Close = __fs_Close;
|
|
fsi->Ops.Ioctl = __fs_Ioctl;
|
|
fsi->Ops.ReadDir = __fs_Readdir;
|
|
|
|
dev->Device = fs->RegisterFileSystem(fsi, dev);
|
|
dev->SetDevice(0, MinorID++);
|
|
MinorID++; /* 1 = /proc/self */
|
|
|
|
devNode = fs->Mount(fs->GetRoot(0), dev, "/dev");
|
|
_dev->Parent = devNode->Parent;
|
|
_dev->ParentInode = devNode->Parent->Node;
|
|
|
|
/* d rwx r-- r-- */
|
|
mode = S_IRWXU |
|
|
S_IRGRP |
|
|
S_IROTH |
|
|
S_IFDIR;
|
|
DeviceInode *input = new DeviceInode;
|
|
input->Parent = devNode;
|
|
input->ParentInode = devNode->Node;
|
|
input->Name = "input";
|
|
input->Node.Device = dev->Device;
|
|
input->Node.Mode = mode;
|
|
input->Node.Flags = I_FLAG_CACHE_KEEP;
|
|
input->Node.Offset = _dev->Children.size();
|
|
_dev->Children.push_back(input);
|
|
devInputNode = fs->GetByPath("input", devNode);
|
|
|
|
auto createDevice = [](DeviceInode *p1, FileNode *p2, const std::string &name, dev_t maj, dev_t min, mode_t mode)
|
|
{
|
|
DeviceInode *device = new DeviceInode;
|
|
device->Parent = p2;
|
|
device->ParentInode = p2->Node;
|
|
device->Name = name;
|
|
device->Node.Device = p2->Node->Device;
|
|
device->Node.Mode = mode;
|
|
device->Node.SetDevice(maj, min);
|
|
device->Node.Flags = I_FLAG_CACHE_KEEP;
|
|
device->Node.Offset = p1->Children.size();
|
|
p1->Children.push_back(device);
|
|
};
|
|
|
|
/* c rw- rw- rw- */
|
|
mode = S_IRUSR | S_IWUSR |
|
|
S_IRGRP | S_IWGRP |
|
|
S_IROTH | S_IWOTH |
|
|
S_IFCHR;
|
|
createDevice(_dev, devNode, "null", 0, MinorID++, mode);
|
|
|
|
/* c rw- rw- rw- */
|
|
mode = S_IRUSR | S_IWUSR |
|
|
S_IRGRP | S_IWGRP |
|
|
S_IROTH | S_IWOTH |
|
|
S_IFCHR;
|
|
createDevice(_dev, devNode, "zero", 0, MinorID++, mode);
|
|
|
|
/* c rw- rw- rw- */
|
|
mode = S_IRUSR | S_IWUSR |
|
|
S_IRGRP | S_IWGRP |
|
|
S_IROTH | S_IWOTH |
|
|
S_IFCHR;
|
|
createDevice(_dev, devNode, "random", 0, MinorID++, mode);
|
|
|
|
/* c rw- r-- --- */
|
|
mode = S_IRUSR | S_IWUSR |
|
|
S_IRGRP |
|
|
|
|
S_IFCHR;
|
|
createDevice(_dev, devNode, "mem", 0, MinorID++, mode);
|
|
|
|
/* c rw- r-- --- */
|
|
mode = S_IRUSR | S_IWUSR |
|
|
S_IRGRP |
|
|
|
|
S_IFCHR;
|
|
createDevice(_dev, devNode, "kcon", 0, MinorID++, mode);
|
|
|
|
/* c rw- rw- rw- */
|
|
mode = S_IRUSR | S_IWUSR |
|
|
S_IRGRP | S_IWGRP |
|
|
S_IRUSR | S_IWUSR |
|
|
S_IFCHR;
|
|
createDevice(_dev, devNode, "tty", 0, MinorID++, mode);
|
|
|
|
/* c rw- rw- rw- */
|
|
mode = S_IRUSR | S_IWUSR |
|
|
S_IRGRP | S_IWGRP |
|
|
S_IRUSR | S_IWUSR |
|
|
S_IFCHR;
|
|
createDevice(_dev, devNode, "ptmx", 0, MinorID++, mode);
|
|
|
|
/* ------------------------------------------------------ */
|
|
|
|
MinorID = 0;
|
|
|
|
/* c rw- r-- --- */
|
|
mode = S_IRUSR | S_IWUSR |
|
|
S_IRGRP |
|
|
|
|
S_IFCHR;
|
|
createDevice(input, devInputNode, "keyboard", 1, MinorID++, mode);
|
|
|
|
/* c rw- r-- --- */
|
|
mode = S_IRUSR | S_IWUSR |
|
|
S_IRGRP |
|
|
|
|
S_IFCHR;
|
|
createDevice(input, devInputNode, "mouse", 1, MinorID++, mode);
|
|
}
|
|
}
|