mirror of
https://github.com/Fennix-Project/Kernel.git
synced 2025-05-25 14:04:36 +00:00
tty: Fix kcon & tty implementation; Add stub ptmx
This commit is contained in:
parent
f48032658f
commit
396ad681ba
@ -17,7 +17,6 @@
|
||||
|
||||
#include <kcon.hpp>
|
||||
|
||||
#include <filesystem/ioctl.hpp>
|
||||
#include <memory.hpp>
|
||||
#include <stropts.h>
|
||||
#include <string.h>
|
||||
@ -27,100 +26,6 @@
|
||||
|
||||
namespace KernelConsole
|
||||
{
|
||||
int KConIoctl(struct Inode *Node, unsigned long Request, void *Argp)
|
||||
{
|
||||
fixme("KConIoctl");
|
||||
switch (Request)
|
||||
{
|
||||
case TCGETS:
|
||||
{
|
||||
struct termios *t = (struct termios *)Argp;
|
||||
// memcpy(t, &term, sizeof(struct termios));
|
||||
return 0;
|
||||
}
|
||||
case TCSETS:
|
||||
{
|
||||
debug("TCSETS not supported");
|
||||
return -EINVAL;
|
||||
|
||||
struct termios *t = (struct termios *)Argp;
|
||||
// memcpy(&term, t, sizeof(struct termios));
|
||||
return 0;
|
||||
}
|
||||
case TIOCGPGRP:
|
||||
{
|
||||
*((pid_t *)Argp) = 0;
|
||||
return 0;
|
||||
}
|
||||
case TIOCSPGRP:
|
||||
{
|
||||
*((pid_t *)Argp) = 0;
|
||||
return 0;
|
||||
}
|
||||
case TIOCGWINSZ:
|
||||
{
|
||||
struct winsize *ws = (struct winsize *)Argp;
|
||||
// memcpy(ws, &termSize, sizeof(struct winsize));
|
||||
return 0;
|
||||
}
|
||||
case TIOCSWINSZ:
|
||||
{
|
||||
debug("TIOCSWINSZ not supported");
|
||||
return -EINVAL;
|
||||
|
||||
struct winsize *ws = (struct winsize *)Argp;
|
||||
// memcpy(&termSize, ws, sizeof(struct winsize));
|
||||
return 0;
|
||||
}
|
||||
case TCSETSW:
|
||||
case TCSETSF:
|
||||
case TCGETA:
|
||||
case TCSETA:
|
||||
case TCSETAW:
|
||||
case TCSETAF:
|
||||
case TCSBRK:
|
||||
case TCXONC:
|
||||
case TCFLSH:
|
||||
case TIOCEXCL:
|
||||
case TIOCNXCL:
|
||||
case TIOCSCTTY:
|
||||
case TIOCOUTQ:
|
||||
case TIOCSTI:
|
||||
case TIOCMGET:
|
||||
case TIOCMBIS:
|
||||
case TIOCMBIC:
|
||||
case TIOCMSET:
|
||||
{
|
||||
fixme("ioctl %#lx not implemented", Request);
|
||||
return -ENOSYS;
|
||||
}
|
||||
case TIOCGPTN:
|
||||
case 0xffffffff80045430: /* FIXME: ???? */
|
||||
{
|
||||
fixme("stub ioctl %#lx", Request);
|
||||
|
||||
int *n = (int *)Argp;
|
||||
*n = -1;
|
||||
break;
|
||||
}
|
||||
case TIOCSPTLCK:
|
||||
{
|
||||
fixme("stub ioctl %#lx", Request);
|
||||
|
||||
int *n = (int *)Argp;
|
||||
*n = 0;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
debug("Unknown ioctl %#lx", Request);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int TermColors[] = {
|
||||
[TerminalColor::BLACK] = 0x000000,
|
||||
[TerminalColor::RED] = 0xAA0000,
|
||||
@ -369,8 +274,6 @@ namespace KernelConsole
|
||||
|
||||
void LateInit()
|
||||
{
|
||||
new vfs::PTMXDevice;
|
||||
|
||||
FileNode *rn = fs->GetByPath("/etc/term", thisProcess->Info.RootNode);
|
||||
if (rn == nullptr)
|
||||
return;
|
||||
|
@ -20,6 +20,7 @@
|
||||
#include <interface/driver.h>
|
||||
#include <interface/input.h>
|
||||
#include <memory.hpp>
|
||||
#include <stropts.h>
|
||||
#include <ints.hpp>
|
||||
#include <task.hpp>
|
||||
#include <printf.h>
|
||||
@ -44,6 +45,8 @@ namespace Driver
|
||||
* 4 - /dev/random
|
||||
* 5 - /dev/mem
|
||||
* 6 - /dev/kcon
|
||||
* 7 - /dev/tty
|
||||
* 8 - /dev/ptmx
|
||||
*
|
||||
* maj = 1
|
||||
* min:
|
||||
@ -52,9 +55,13 @@ namespace Driver
|
||||
* ..- /dev/input/eventX
|
||||
*/
|
||||
|
||||
TTY::PTMXDevice *ptmx = nullptr;
|
||||
|
||||
int __fs_Lookup(struct Inode *_Parent, const char *Name, struct Inode **Result)
|
||||
{
|
||||
auto Parent = (Manager::DeviceInode *)_Parent;
|
||||
func("%#lx %s %#lx", _Parent, Name, Result);
|
||||
|
||||
assert(_Parent != nullptr);
|
||||
|
||||
const char *basename;
|
||||
size_t length;
|
||||
@ -65,9 +72,10 @@ namespace Driver
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
auto Parent = (Manager::DeviceInode *)_Parent;
|
||||
for (const auto &child : Parent->Children)
|
||||
{
|
||||
debug("Comparing %s with %s", child->Name.c_str(), basename);
|
||||
debug("Comparing %s with %s", basename, child->Name.c_str());
|
||||
if (strcmp(child->Name.c_str(), basename) != 0)
|
||||
continue;
|
||||
|
||||
@ -81,6 +89,8 @@ namespace Driver
|
||||
|
||||
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 */
|
||||
@ -99,6 +109,7 @@ namespace Driver
|
||||
|
||||
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:
|
||||
@ -141,10 +152,11 @@ namespace Driver
|
||||
return 0;
|
||||
}
|
||||
case 6: /* /dev/kcon */
|
||||
{
|
||||
stub;
|
||||
return 0;
|
||||
}
|
||||
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;
|
||||
};
|
||||
@ -210,6 +222,8 @@ namespace Driver
|
||||
|
||||
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:
|
||||
@ -234,13 +248,11 @@ namespace Driver
|
||||
return 0;
|
||||
}
|
||||
case 6: /* /dev/kcon */
|
||||
{
|
||||
char *buf = (char *)Buffer;
|
||||
KernelConsole::VirtualTerminal *vt = KernelConsole::CurrentTerminal.load();
|
||||
for (size_t i = 0; i < Size; i++)
|
||||
vt->Process(buf[i]);
|
||||
return Size;
|
||||
}
|
||||
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;
|
||||
};
|
||||
@ -281,9 +293,180 @@ namespace Driver
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
@ -545,6 +728,8 @@ namespace Driver
|
||||
|
||||
void Manager::InitializeDaemonFS()
|
||||
{
|
||||
ptmx = new TTY::PTMXDevice;
|
||||
|
||||
dev_t MinorID = 0;
|
||||
DeviceInode *_dev = new DeviceInode;
|
||||
_dev->Name = "dev";
|
||||
@ -559,7 +744,7 @@ namespace Driver
|
||||
dev->Flags = I_FLAG_MOUNTPOINT | I_FLAG_CACHE_KEEP;
|
||||
|
||||
FileSystemInfo *fsi = new FileSystemInfo;
|
||||
fsi->Name = "Driver Manager";
|
||||
fsi->Name = "Device Virtual File System";
|
||||
fsi->RootName = "dev";
|
||||
fsi->Flags = I_FLAG_ROOT | I_FLAG_MOUNTPOINT | I_FLAG_CACHE_KEEP;
|
||||
fsi->SuperOps = {};
|
||||
@ -567,6 +752,9 @@ namespace Driver
|
||||
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);
|
||||
@ -642,6 +830,20 @@ namespace Driver
|
||||
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;
|
||||
|
@ -157,6 +157,10 @@ namespace Execute
|
||||
return false;
|
||||
};
|
||||
|
||||
fixme("remove workarounds for stdio and tty");
|
||||
if (!Parent->tty)
|
||||
Process->tty = KernelConsole::CurrentTerminal.load();
|
||||
|
||||
if (!ForkStdio(Parent->stdin))
|
||||
fdt->usr_open("/dev/kcon", O_RDWR, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
|
||||
|
||||
|
@ -93,6 +93,7 @@ namespace Driver
|
||||
FileNode *devNode = nullptr;
|
||||
FileNode *devInputNode = nullptr;
|
||||
|
||||
|
||||
int LoadDriverFile(DriverObject &Drv, FileNode *File);
|
||||
|
||||
void InitializeDaemonFS();
|
||||
|
@ -1,76 +0,0 @@
|
||||
/*
|
||||
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/>.
|
||||
*/
|
||||
|
||||
#ifndef __FENNIX_KERNEL_FILESYSTEM_DEV_H__
|
||||
#define __FENNIX_KERNEL_FILESYSTEM_DEV_H__
|
||||
|
||||
#include <types.h>
|
||||
|
||||
#include <filesystem.hpp>
|
||||
#include <bitmap.hpp>
|
||||
#include <termios.h>
|
||||
#include <lock.hpp>
|
||||
#include <vector>
|
||||
|
||||
namespace vfs
|
||||
{
|
||||
class PTYDevice
|
||||
{
|
||||
private:
|
||||
Inode *pts;
|
||||
int id;
|
||||
termios term{};
|
||||
winsize termSize{};
|
||||
|
||||
class PTYSlave
|
||||
{
|
||||
};
|
||||
|
||||
class PTYMaster
|
||||
{
|
||||
};
|
||||
|
||||
public:
|
||||
decltype(id) &ptyId = id;
|
||||
|
||||
ssize_t Read(struct Inode *Node, void *Buffer, size_t Size, off_t Offset);
|
||||
ssize_t Write(struct Inode *Node, const void *Buffer, size_t Size, off_t Offset);
|
||||
int Ioctl(struct Inode *Node, unsigned long Request, void *Argp);
|
||||
|
||||
PTYDevice(Inode *pts, int id);
|
||||
~PTYDevice();
|
||||
};
|
||||
|
||||
class PTMXDevice
|
||||
{
|
||||
private:
|
||||
NewLock(PTMXLock);
|
||||
FileNode *ptmx;
|
||||
FileNode *pts;
|
||||
Bitmap ptysId;
|
||||
std::unordered_map<size_t, PTYDevice *> ptysList;
|
||||
|
||||
public:
|
||||
int Open(struct Inode *Node, int Flags, mode_t Mode, struct Inode *Result);
|
||||
int Close(struct Inode *Node);
|
||||
|
||||
PTMXDevice();
|
||||
~PTMXDevice();
|
||||
};
|
||||
}
|
||||
|
||||
#endif // !__FENNIX_KERNEL_FILESYSTEM_DEV_H__
|
@ -19,8 +19,7 @@
|
||||
#define __FENNIX_KERNEL_KERNEL_CONSOLE_H__
|
||||
|
||||
#include <display.hpp>
|
||||
#include <termios.h>
|
||||
#include <atomic>
|
||||
#include <tty.hpp>
|
||||
|
||||
namespace KernelConsole
|
||||
{
|
||||
@ -86,7 +85,7 @@ namespace KernelConsole
|
||||
char Paint(long CellX, long CellY, char Char, uint32_t Foreground, uint32_t Background);
|
||||
};
|
||||
|
||||
class VirtualTerminal
|
||||
class VirtualTerminal : public TTY::TeletypeDriver
|
||||
{
|
||||
private:
|
||||
ANSIParser Parser{};
|
||||
@ -98,9 +97,17 @@ namespace KernelConsole
|
||||
PaintCallback PaintCB = nullptr;
|
||||
CursorCallback CursorCB = nullptr;
|
||||
|
||||
std::mutex Mutex;
|
||||
|
||||
public:
|
||||
termios term;
|
||||
winsize termSize;
|
||||
termios *GetTermios() { return &this->TerminalConfig; }
|
||||
winsize *GetWinsize() { return &this->TerminalSize; }
|
||||
|
||||
int Open(int Flags, mode_t Mode) final;
|
||||
int Close() final;
|
||||
ssize_t Read(void *Buffer, size_t Size, off_t Offset) final;
|
||||
ssize_t Write(const void *Buffer, size_t Size, off_t Offset) final;
|
||||
int Ioctl(unsigned long Request, void *Argp) final;
|
||||
|
||||
void Clear(unsigned short StartX, unsigned short StartY, unsigned short EndX, unsigned short EndY);
|
||||
void Scroll(unsigned short Lines);
|
||||
|
@ -484,6 +484,7 @@ namespace Tasking
|
||||
FileNode *stdin;
|
||||
FileNode *stdout;
|
||||
FileNode *stderr;
|
||||
/*TTY::TeletypeDriver*/ void *tty;
|
||||
|
||||
/* Memory */
|
||||
Memory::PageTable *PageTable;
|
||||
|
130
include/tty.hpp
Normal file
130
include/tty.hpp
Normal file
@ -0,0 +1,130 @@
|
||||
/*
|
||||
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/>.
|
||||
*/
|
||||
|
||||
#ifndef __FENNIX_KERNEL_TTY_H__
|
||||
#define __FENNIX_KERNEL_TTY_H__
|
||||
|
||||
#include <termios.h>
|
||||
#include <mutex>
|
||||
|
||||
namespace TTY
|
||||
{
|
||||
class TerminalBuffer
|
||||
{
|
||||
private:
|
||||
std::vector<char> Buffer;
|
||||
size_t ReadIndex;
|
||||
size_t WriteIndex;
|
||||
std::mutex Mutex;
|
||||
|
||||
public:
|
||||
TerminalBuffer(size_t Size) : Buffer(Size), ReadIndex(0), WriteIndex(0) {}
|
||||
|
||||
ssize_t Read(char *OutputBuffer, size_t Size);
|
||||
ssize_t Write(const char *InputBuffer, size_t Size);
|
||||
|
||||
void DrainOutput()
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(Mutex);
|
||||
ReadIndex = WriteIndex;
|
||||
}
|
||||
|
||||
size_t AvailableToRead() const
|
||||
{
|
||||
return (WriteIndex - ReadIndex + Buffer.size()) % Buffer.size();
|
||||
}
|
||||
|
||||
size_t AvailableToWrite() const
|
||||
{
|
||||
return Buffer.size() - AvailableToRead() - 1;
|
||||
}
|
||||
};
|
||||
|
||||
class TeletypeDriver
|
||||
{
|
||||
protected:
|
||||
termios TerminalConfig;
|
||||
winsize TerminalSize;
|
||||
TerminalBuffer TermBuf;
|
||||
|
||||
public:
|
||||
virtual int Open(int Flags, mode_t Mode);
|
||||
virtual int Close();
|
||||
virtual ssize_t Read(void *Buffer, size_t Size, off_t Offset);
|
||||
virtual ssize_t Write(const void *Buffer, size_t Size, off_t Offset);
|
||||
virtual int Ioctl(unsigned long Request, void *Argp);
|
||||
|
||||
TeletypeDriver();
|
||||
virtual ~TeletypeDriver();
|
||||
};
|
||||
|
||||
class PTYDevice
|
||||
{
|
||||
private:
|
||||
class PTYMaster
|
||||
{
|
||||
private:
|
||||
TerminalBuffer TermBuf;
|
||||
|
||||
public:
|
||||
PTYMaster();
|
||||
~PTYMaster();
|
||||
ssize_t Read(void *Buffer, size_t Size);
|
||||
ssize_t Write(const void *Buffer, size_t Size);
|
||||
};
|
||||
|
||||
class PTYSlave
|
||||
{
|
||||
private:
|
||||
TerminalBuffer TermBuf;
|
||||
|
||||
public:
|
||||
PTYSlave();
|
||||
~PTYSlave();
|
||||
ssize_t Read(void *Buffer, size_t Size);
|
||||
ssize_t Write(const void *Buffer, size_t Size);
|
||||
};
|
||||
|
||||
PTYMaster Master;
|
||||
PTYSlave Slave;
|
||||
|
||||
public:
|
||||
PTYDevice();
|
||||
~PTYDevice();
|
||||
int Open();
|
||||
int Close();
|
||||
ssize_t Read(void *Buffer, size_t Size);
|
||||
ssize_t Write(const void *Buffer, size_t Size);
|
||||
};
|
||||
|
||||
class PTMXDevice
|
||||
{
|
||||
private:
|
||||
std::vector<PTYDevice *> PTYs;
|
||||
std::mutex PTYMutex;
|
||||
|
||||
public:
|
||||
PTMXDevice();
|
||||
~PTMXDevice();
|
||||
int Open();
|
||||
int Close();
|
||||
PTYDevice *CreatePTY();
|
||||
int RemovePTY(PTYDevice *pty);
|
||||
};
|
||||
}
|
||||
|
||||
#endif // !__FENNIX_KERNEL_TTY_H__
|
@ -17,7 +17,6 @@
|
||||
|
||||
#include "kernel.h"
|
||||
|
||||
#include <filesystem/mounts.hpp>
|
||||
#include <filesystem/ustar.hpp>
|
||||
#include <memory.hpp>
|
||||
#include <convert.h>
|
||||
|
2
kernel.h
2
kernel.h
@ -22,7 +22,6 @@
|
||||
|
||||
#include <boot/binfo.h>
|
||||
#ifdef __cplusplus
|
||||
#include <filesystem/mounts.hpp>
|
||||
#include <filesystem.hpp>
|
||||
#include <display.hpp>
|
||||
#include <symbols.hpp>
|
||||
@ -34,6 +33,7 @@
|
||||
#include <time.hpp>
|
||||
#include <disk.hpp>
|
||||
#include <kcon.hpp>
|
||||
#include <tty.hpp>
|
||||
#include <pci.hpp>
|
||||
#include <smp.hpp>
|
||||
#endif
|
||||
|
@ -17,7 +17,6 @@
|
||||
|
||||
#include "kernel.h"
|
||||
|
||||
#include <filesystem/mounts.hpp>
|
||||
#include <filesystem/ustar.hpp>
|
||||
#include <memory.hpp>
|
||||
|
||||
|
@ -1,90 +0,0 @@
|
||||
/*
|
||||
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 <filesystem/mounts.hpp>
|
||||
#include <filesystem/ioctl.hpp>
|
||||
#include <smp.hpp>
|
||||
#include <errno.h>
|
||||
|
||||
#include "../../../kernel.h"
|
||||
|
||||
namespace vfs
|
||||
{
|
||||
int PTMXDevice::Open(Inode *Node, int Flags, mode_t Mode, struct Inode *Result)
|
||||
{
|
||||
// SmartLock(PTMXLock);
|
||||
|
||||
// int ptyID = -1;
|
||||
// for (int i = 0; i < (int)ptysId.Size; i++)
|
||||
// {
|
||||
// if (ptysId.Buffer[i])
|
||||
// continue;
|
||||
|
||||
// ptyID = i;
|
||||
// ptysId.Buffer[i] = true;
|
||||
// break;
|
||||
// }
|
||||
|
||||
// if (ptyID == -1)
|
||||
// return -ENFILE;
|
||||
|
||||
// PTYDevice *pty = new PTYDevice(pts, ptyID);
|
||||
// ptysList.insert(std::make_pair(ptyID, pty));
|
||||
// // return pty->OpenMaster(Flags, Mode);
|
||||
assert(!"Function not implemented");
|
||||
}
|
||||
|
||||
int PTMXDevice::Close(struct Inode *Node)
|
||||
{
|
||||
SmartLock(PTMXLock);
|
||||
|
||||
PTYDevice *pty = ptysList.at(Node->Index);
|
||||
ptysList.erase(Node->Index);
|
||||
assert(!"Function not implemented");
|
||||
}
|
||||
|
||||
PTMXDevice::PTMXDevice()
|
||||
{
|
||||
fixme("PTMXDevice");
|
||||
// /* c rw- rw- rw- */
|
||||
// mode_t mode = S_IRUSR | S_IWUSR |
|
||||
// S_IRGRP | S_IWGRP |
|
||||
// S_IROTH | S_IWOTH |
|
||||
// S_IFCHR;
|
||||
|
||||
// ptmx = fs->Create(ptmx, "pts", mode);
|
||||
// assert(!"Function not implemented");
|
||||
// // ptmx->SetDevice(5, 2);
|
||||
|
||||
// /* d rwx r-x r-x */
|
||||
// mode_t ptsMode = S_IRWXU |
|
||||
// S_IRGRP | S_IXGRP |
|
||||
// S_IROTH | S_IXOTH |
|
||||
// S_IFDIR;
|
||||
// pts = fs->Create(ptmx, "pts", ptsMode);
|
||||
// assert(pts != nullptr);
|
||||
|
||||
// ptysId.Buffer = new uint8_t[0x1000];
|
||||
// ptysId.Size = 0x1000;
|
||||
}
|
||||
|
||||
PTMXDevice::~PTMXDevice()
|
||||
{
|
||||
SmartLock(PTMXLock);
|
||||
delete[] ptysId.Buffer;
|
||||
}
|
||||
}
|
@ -1,69 +0,0 @@
|
||||
/*
|
||||
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 <filesystem/mounts.hpp>
|
||||
#include <filesystem/ioctl.hpp>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "../../../kernel.h"
|
||||
|
||||
namespace vfs
|
||||
{
|
||||
PTYDevice::PTYDevice(Inode *_pts, int _id)
|
||||
{
|
||||
assert(!"Function not implemented");
|
||||
char nameBuffer[16];
|
||||
snprintf(nameBuffer, 16, "%d", id);
|
||||
// this->Name = strdup(nameBuffer);
|
||||
|
||||
/*
|
||||
- ICRNL - Map Carriage Return to New Line
|
||||
- IXON - Enable XON/XOFF flow control
|
||||
|
||||
- OPOST - Enable output processing
|
||||
- ONLCR - Map New Line to Carriage Return - New Line
|
||||
|
||||
- CS8 - 8-bit characters
|
||||
- CREAD - Enable receiver
|
||||
- HUPCL - Hang up on last close
|
||||
|
||||
- ECHO - Echo input characters
|
||||
- ICANON - Enable canonical input (enable line editing)
|
||||
*/
|
||||
this->term.c_iflag = /*ICRNL |*/ IXON;
|
||||
this->term.c_oflag = OPOST | ONLCR;
|
||||
this->term.c_cflag = CS8 | CREAD | HUPCL;
|
||||
this->term.c_lflag = ECHO | ICANON;
|
||||
this->term.c_cc[VEOF] = 0x04; /* ^D */
|
||||
this->term.c_cc[VEOL] = 0x00; /* NUL */
|
||||
this->term.c_cc[VERASE] = 0x7f; /* DEL */
|
||||
this->term.c_cc[VINTR] = 0x03; /* ^C */
|
||||
this->term.c_cc[VKILL] = 0x15; /* ^U */
|
||||
this->term.c_cc[VMIN] = 1; /* Minimum number of characters for non-canonical read */
|
||||
this->term.c_cc[VQUIT] = 0x1c; /* ^\ */
|
||||
this->term.c_cc[VSTART] = 0x11; /* ^Q */
|
||||
this->term.c_cc[VSTOP] = 0x13; /* ^S */
|
||||
this->term.c_cc[VSUSP] = 0x1a; /* ^Z */
|
||||
this->term.c_cc[VTIME] = 0; /* Timeout for non-canonical read */
|
||||
this->term.c_cc[VWERASE] = 0x17; /* ^W */
|
||||
|
||||
// debug("Created PTY device %s", this->Name);
|
||||
}
|
||||
|
||||
PTYDevice::~PTYDevice() {}
|
||||
}
|
@ -213,6 +213,7 @@ namespace Tasking
|
||||
}
|
||||
|
||||
this->FileDescriptors = new FileDescriptorTable(this);
|
||||
this->tty = nullptr;
|
||||
|
||||
/* If create page table */
|
||||
if (UseKernelPageTable == false)
|
||||
@ -268,6 +269,10 @@ namespace Tasking
|
||||
debug("Closing file descriptors");
|
||||
delete this->FileDescriptors;
|
||||
|
||||
debug("Deleting tty");
|
||||
if (this->tty)
|
||||
delete ((TTY::TeletypeDriver *)this->tty);
|
||||
|
||||
/* If we own the pointer to the
|
||||
PageTable, we need to free it */
|
||||
if (this->PageTable && OwnPageTable)
|
||||
|
66
tty/ptmx.cpp
Normal file
66
tty/ptmx.cpp
Normal file
@ -0,0 +1,66 @@
|
||||
/*
|
||||
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 <tty.hpp>
|
||||
#include <filesystem/ioctl.hpp>
|
||||
#include <smp.hpp>
|
||||
#include <errno.h>
|
||||
|
||||
#include "../kernel.h"
|
||||
|
||||
namespace TTY
|
||||
{
|
||||
PTMXDevice::PTMXDevice()
|
||||
{
|
||||
}
|
||||
|
||||
PTMXDevice::~PTMXDevice()
|
||||
{
|
||||
for (auto pty : PTYs)
|
||||
delete pty;
|
||||
}
|
||||
|
||||
int PTMXDevice::Open()
|
||||
{
|
||||
stub;
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
int PTMXDevice::Close()
|
||||
{
|
||||
stub;
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
PTYDevice *PTMXDevice::CreatePTY()
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(PTYMutex);
|
||||
PTYDevice *pty = new PTYDevice();
|
||||
PTYs.push_back(pty);
|
||||
return pty;
|
||||
}
|
||||
|
||||
int PTMXDevice::RemovePTY(PTYDevice *pty)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(PTYMutex);
|
||||
auto it = PTYs.erase(std::remove(PTYs.begin(), PTYs.end(), pty), PTYs.end());
|
||||
if (it == PTYs.end())
|
||||
return -ENOENT;
|
||||
delete pty;
|
||||
return 0;
|
||||
}
|
||||
}
|
95
tty/pty.cpp
Normal file
95
tty/pty.cpp
Normal file
@ -0,0 +1,95 @@
|
||||
/*
|
||||
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 <tty.hpp>
|
||||
#include <filesystem/ioctl.hpp>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "../kernel.h"
|
||||
|
||||
namespace TTY
|
||||
{
|
||||
PTYDevice::PTYDevice()
|
||||
: Master(), Slave()
|
||||
{
|
||||
}
|
||||
|
||||
PTYDevice::~PTYDevice()
|
||||
{
|
||||
}
|
||||
|
||||
int PTYDevice::Open()
|
||||
{
|
||||
stub;
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
int PTYDevice::Close()
|
||||
{
|
||||
stub;
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
ssize_t PTYDevice::Read(void *Buffer, size_t Size)
|
||||
{
|
||||
return Slave.Read(Buffer, Size);
|
||||
}
|
||||
|
||||
ssize_t PTYDevice::Write(const void *Buffer, size_t Size)
|
||||
{
|
||||
return Master.Write(Buffer, Size);
|
||||
}
|
||||
|
||||
PTYDevice::PTYMaster::PTYMaster()
|
||||
: TermBuf(1024)
|
||||
{
|
||||
}
|
||||
|
||||
PTYDevice::PTYMaster::~PTYMaster()
|
||||
{
|
||||
}
|
||||
|
||||
ssize_t PTYDevice::PTYMaster::Read(void *Buffer, size_t Size)
|
||||
{
|
||||
return TermBuf.Read((char *)Buffer, Size);
|
||||
}
|
||||
|
||||
ssize_t PTYDevice::PTYMaster::Write(const void *Buffer, size_t Size)
|
||||
{
|
||||
return TermBuf.Write((const char *)Buffer, Size);
|
||||
}
|
||||
|
||||
PTYDevice::PTYSlave::PTYSlave()
|
||||
: TermBuf(1024)
|
||||
{
|
||||
}
|
||||
|
||||
PTYDevice::PTYSlave::~PTYSlave()
|
||||
{
|
||||
}
|
||||
|
||||
ssize_t PTYDevice::PTYSlave::Read(void *Buffer, size_t Size)
|
||||
{
|
||||
return TermBuf.Read((char *)Buffer, Size);
|
||||
}
|
||||
|
||||
ssize_t PTYDevice::PTYSlave::Write(const void *Buffer, size_t Size)
|
||||
{
|
||||
return TermBuf.Write((const char *)Buffer, Size);
|
||||
}
|
||||
}
|
141
tty/teletype.cpp
Normal file
141
tty/teletype.cpp
Normal file
@ -0,0 +1,141 @@
|
||||
/*
|
||||
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 <tty.hpp>
|
||||
|
||||
#include <memory.hpp>
|
||||
#include <stropts.h>
|
||||
#include <string.h>
|
||||
#include <uart.hpp>
|
||||
|
||||
#include "../kernel.h"
|
||||
|
||||
namespace TTY
|
||||
{
|
||||
ssize_t TerminalBuffer::Read(char *OutputBuffer, size_t Size)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(Mutex);
|
||||
size_t bytesRead = 0;
|
||||
|
||||
while (bytesRead < Size && ReadIndex != WriteIndex)
|
||||
{
|
||||
OutputBuffer[bytesRead++] = Buffer[ReadIndex];
|
||||
ReadIndex = (ReadIndex + 1) % Buffer.size();
|
||||
}
|
||||
|
||||
return bytesRead;
|
||||
}
|
||||
|
||||
ssize_t TerminalBuffer::Write(const char *InputBuffer, size_t Size)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(Mutex);
|
||||
size_t bytesWritten = 0;
|
||||
|
||||
for (size_t i = 0; i < Size; ++i)
|
||||
{
|
||||
Buffer[WriteIndex] = InputBuffer[i];
|
||||
WriteIndex = (WriteIndex + 1) % Buffer.size();
|
||||
bytesWritten++;
|
||||
}
|
||||
|
||||
return bytesWritten;
|
||||
}
|
||||
|
||||
/* ======================================================================== */
|
||||
|
||||
int TeletypeDriver::Open(int Flags, mode_t Mode)
|
||||
{
|
||||
warn("Unimplemented open(%#x, %#x)", Flags, Mode);
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
int TeletypeDriver::Close()
|
||||
{
|
||||
warn("Unimplemented close()");
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
ssize_t TeletypeDriver::Read(void *Buffer, size_t Size, off_t Offset)
|
||||
{
|
||||
warn("Unimplemented read(%#lx, %#lx, %#lx)", Buffer, Size, Offset);
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
ssize_t TeletypeDriver::Write(const void *Buffer, size_t Size, off_t Offset)
|
||||
{
|
||||
warn("Unimplemented write(%#lx, %#lx, %#lx)", Buffer, Size, Offset);
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
int TeletypeDriver::Ioctl(unsigned long Request, void *Argp)
|
||||
{
|
||||
warn("Unimplemented ioctl(%#lx, %#lx)", Request, Argp);
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
TeletypeDriver::TeletypeDriver()
|
||||
: TermBuf(1024)
|
||||
{
|
||||
this->TerminalSize = {
|
||||
.ws_row = 0,
|
||||
.ws_col = 0,
|
||||
.ws_xpixel = 0,
|
||||
.ws_ypixel = 0,
|
||||
};
|
||||
|
||||
/*
|
||||
- ICRNL - Map Carriage Return to New Line
|
||||
- IXON - Enable XON/XOFF flow control
|
||||
|
||||
- OPOST - Enable output processing
|
||||
- ONLCR - Map New Line to Carriage Return - New Line
|
||||
|
||||
- CS8 - 8-bit characters
|
||||
- CREAD - Enable receiver
|
||||
- HUPCL - Hang up on last close
|
||||
|
||||
- ECHO - Echo input characters
|
||||
- ICANON - Enable canonical input (enable line editing)
|
||||
*/
|
||||
this->TerminalConfig.c_iflag = /*ICRNL |*/ IXON;
|
||||
this->TerminalConfig.c_oflag = OPOST | ONLCR;
|
||||
this->TerminalConfig.c_cflag = CS8 | CREAD | HUPCL;
|
||||
this->TerminalConfig.c_lflag = ECHO | ICANON;
|
||||
|
||||
this->TerminalConfig.c_cc[VINTR] = 0x03; /* ^C */
|
||||
this->TerminalConfig.c_cc[VQUIT] = 0x1C; /* ^\ */
|
||||
this->TerminalConfig.c_cc[VERASE] = 0x7F; /* DEL */
|
||||
this->TerminalConfig.c_cc[VKILL] = 0x15; /* ^U */
|
||||
this->TerminalConfig.c_cc[VEOF] = 0x04; /* ^D */
|
||||
this->TerminalConfig.c_cc[VTIME] = 0; /* Timeout for non-canonical read */
|
||||
this->TerminalConfig.c_cc[VMIN] = 1; /* Minimum number of characters for non-canonical read */
|
||||
this->TerminalConfig.c_cc[VSWTC] = 0; /* ^O */
|
||||
this->TerminalConfig.c_cc[VSTART] = 0x11; /* ^Q */
|
||||
this->TerminalConfig.c_cc[VSTOP] = 0x13; /* ^S */
|
||||
this->TerminalConfig.c_cc[VSUSP] = 0x1A; /* ^Z */
|
||||
this->TerminalConfig.c_cc[VEOL] = 0x00; /* NUL */
|
||||
this->TerminalConfig.c_cc[VREPRINT] = 0x12; /* ^R */
|
||||
this->TerminalConfig.c_cc[VDISCARD] = 0x14; /* ^T */
|
||||
this->TerminalConfig.c_cc[VWERASE] = 0x17; /* ^W */
|
||||
this->TerminalConfig.c_cc[VLNEXT] = 0x19; /* ^Y */
|
||||
this->TerminalConfig.c_cc[VEOL2] = 0x7F; /* DEL (or sometimes EOF) */
|
||||
}
|
||||
|
||||
TeletypeDriver::~TeletypeDriver()
|
||||
{
|
||||
}
|
||||
}
|
@ -17,6 +17,7 @@
|
||||
|
||||
#include <kcon.hpp>
|
||||
|
||||
#include <filesystem/ioctl.hpp>
|
||||
#include <memory.hpp>
|
||||
#include <stropts.h>
|
||||
#include <string.h>
|
||||
@ -26,16 +27,184 @@
|
||||
|
||||
namespace KernelConsole
|
||||
{
|
||||
int VirtualTerminal::Open(int Flags, mode_t Mode)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(Mutex);
|
||||
stub;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int VirtualTerminal::Close()
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(Mutex);
|
||||
stub;
|
||||
return 0;
|
||||
}
|
||||
|
||||
ssize_t VirtualTerminal::Read(void *Buffer, size_t Size, off_t Offset)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(Mutex);
|
||||
|
||||
KeyboardReport report{};
|
||||
|
||||
/* FIXME: this is a hack, "static" is not a good idea */
|
||||
static bool upperCase = false;
|
||||
|
||||
RecheckKeyboard:
|
||||
while (DriverManager->GlobalKeyboardInputReports.Count() == 0)
|
||||
TaskManager->Yield();
|
||||
|
||||
DriverManager->GlobalKeyboardInputReports.Read(&report, sizeof(report));
|
||||
|
||||
int pkey = report.Key & ~KEY_PRESSED;
|
||||
if (pkey == KEY_LEFT_SHIFT || pkey == KEY_RIGHT_SHIFT)
|
||||
{
|
||||
if (report.Key & KEY_PRESSED)
|
||||
upperCase = true;
|
||||
else
|
||||
upperCase = false;
|
||||
goto RecheckKeyboard;
|
||||
}
|
||||
|
||||
if (!(report.Key & KEY_PRESSED))
|
||||
goto RecheckKeyboard;
|
||||
|
||||
if (!Driver::IsValidChar(report.Key))
|
||||
goto RecheckKeyboard;
|
||||
|
||||
char c = Driver::GetScanCode(report.Key, upperCase);
|
||||
char *buf = (char *)Buffer;
|
||||
buf[0] = c;
|
||||
debug("KCON: %c", c);
|
||||
|
||||
if (this->TerminalConfig.c_lflag & ECHO)
|
||||
{
|
||||
debug("ECHO");
|
||||
if (this->TerminalConfig.c_lflag & ICANON)
|
||||
this->Process(buf[0]);
|
||||
else
|
||||
this->Append(buf[0]);
|
||||
}
|
||||
|
||||
if (this->TerminalConfig.c_lflag & ICANON)
|
||||
{
|
||||
fixme("ICANON");
|
||||
// if (pkey == KEY_RETURN)
|
||||
// {
|
||||
//
|
||||
// return bufLength;
|
||||
// }
|
||||
}
|
||||
else
|
||||
{
|
||||
debug("~ICANON");
|
||||
}
|
||||
|
||||
debug("ret 1");
|
||||
return 1;
|
||||
}
|
||||
|
||||
ssize_t VirtualTerminal::Write(const void *Buffer, size_t Size, off_t Offset)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(Mutex);
|
||||
|
||||
char *buf = (char *)Buffer;
|
||||
debug("string: \"%*s\"", Size, buf);
|
||||
for (size_t i = 0; i < Size; i++)
|
||||
{
|
||||
if (this->TerminalConfig.c_lflag & ICANON)
|
||||
this->Process(buf[i]);
|
||||
else
|
||||
this->Append(buf[i]);
|
||||
}
|
||||
|
||||
debug("ret %ld", Size);
|
||||
return Size;
|
||||
}
|
||||
|
||||
int VirtualTerminal::Ioctl(unsigned long Request, void *Argp)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(Mutex);
|
||||
|
||||
switch (Request)
|
||||
{
|
||||
case 0xffffffff80045430: /* FIXME: ???? */
|
||||
debug("???");
|
||||
[[fallthrough]];
|
||||
case TIOCGPTN:
|
||||
{
|
||||
fixme("stub ioctl TIOCGPTN");
|
||||
|
||||
int *n = (int *)Argp;
|
||||
*n = -1;
|
||||
return 0;
|
||||
}
|
||||
case TIOCSPTLCK:
|
||||
{
|
||||
fixme("stub ioctl TIOCSPTLCK");
|
||||
|
||||
int *n = (int *)Argp;
|
||||
*n = 0;
|
||||
return 0;
|
||||
}
|
||||
case TCGETS:
|
||||
{
|
||||
struct termios *t = (struct termios *)Argp;
|
||||
*t = TerminalConfig;
|
||||
return 0;
|
||||
}
|
||||
case TCSETSW:
|
||||
{
|
||||
debug("draining output buffer...");
|
||||
TermBuf.DrainOutput();
|
||||
debug("output buffer drained");
|
||||
|
||||
TerminalConfig = *(struct termios *)Argp;
|
||||
return 0;
|
||||
}
|
||||
case TIOCGWINSZ:
|
||||
{
|
||||
struct winsize *ws = (struct winsize *)Argp;
|
||||
*ws = TerminalSize;
|
||||
return 0;
|
||||
}
|
||||
case TIOCGPGRP:
|
||||
{
|
||||
*((pid_t *)Argp) = thisProcess->Security.ProcessGroupID;
|
||||
debug("returning pgid %d", thisProcess->Security.ProcessGroupID);
|
||||
return 0;
|
||||
}
|
||||
case TIOCSPGRP:
|
||||
{
|
||||
thisProcess->Security.ProcessGroupID = *((pid_t *)Argp);
|
||||
debug("updated pgid to %d", thisProcess->Security.ProcessGroupID);
|
||||
return 0;
|
||||
}
|
||||
case TIOCGSID:
|
||||
{
|
||||
*((pid_t *)Argp) = thisProcess->Security.SessionID;
|
||||
debug("returning sid %d", thisProcess->Security.SessionID);
|
||||
return 0;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
debug("Unknown ioctl %#lx", Request);
|
||||
return -ENOTSUP;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void VirtualTerminal::Clear(unsigned short StartX, unsigned short StartY, unsigned short EndX, unsigned short EndY)
|
||||
{
|
||||
assert(this->PaintCB != nullptr);
|
||||
for (long i = StartX + StartY * this->termSize.ws_row; i < EndX + EndY * this->termSize.ws_row; i++)
|
||||
for (long i = StartX + StartY * this->TerminalSize.ws_row; i < EndX + EndY * this->TerminalSize.ws_row; i++)
|
||||
{
|
||||
TerminalCell *cell = &this->Cells[i];
|
||||
cell->c = ' ';
|
||||
cell->attr = {};
|
||||
|
||||
this->PaintCB(cell, i % this->termSize.ws_row, i / this->termSize.ws_row);
|
||||
this->PaintCB(cell, i % this->TerminalSize.ws_row, i / this->TerminalSize.ws_row);
|
||||
}
|
||||
}
|
||||
|
||||
@ -45,21 +214,21 @@ namespace KernelConsole
|
||||
if (Lines == 0)
|
||||
return;
|
||||
|
||||
Lines = Lines > this->termSize.ws_col ? this->termSize.ws_col : Lines;
|
||||
Lines = Lines > this->TerminalSize.ws_col ? this->TerminalSize.ws_col : Lines;
|
||||
|
||||
for (int i = 0; i < ((this->termSize.ws_row * this->termSize.ws_col) - (this->termSize.ws_row * Lines)); i++)
|
||||
for (int i = 0; i < ((this->TerminalSize.ws_row * this->TerminalSize.ws_col) - (this->TerminalSize.ws_row * Lines)); i++)
|
||||
{
|
||||
this->Cells[i] = this->Cells[i + (this->termSize.ws_row * Lines)];
|
||||
this->PaintCB(&this->Cells[i], i % this->termSize.ws_row, i / this->termSize.ws_row);
|
||||
this->Cells[i] = this->Cells[i + (this->TerminalSize.ws_row * Lines)];
|
||||
this->PaintCB(&this->Cells[i], i % this->TerminalSize.ws_row, i / this->TerminalSize.ws_row);
|
||||
}
|
||||
|
||||
for (int i = ((this->termSize.ws_row * this->termSize.ws_col) - (this->termSize.ws_row * Lines)); i < this->termSize.ws_row * this->termSize.ws_col; i++)
|
||||
for (int i = ((this->TerminalSize.ws_row * this->TerminalSize.ws_col) - (this->TerminalSize.ws_row * Lines)); i < this->TerminalSize.ws_row * this->TerminalSize.ws_col; i++)
|
||||
{
|
||||
TerminalCell *cell = &this->Cells[i];
|
||||
cell->attr = {};
|
||||
cell->c = ' ';
|
||||
|
||||
this->PaintCB(cell, i % this->termSize.ws_row, i / this->termSize.ws_row);
|
||||
this->PaintCB(cell, i % this->TerminalSize.ws_row, i / this->TerminalSize.ws_row);
|
||||
}
|
||||
|
||||
// Move the cursor up $lines
|
||||
@ -80,7 +249,7 @@ namespace KernelConsole
|
||||
this->Cursor.X = 0;
|
||||
this->Cursor.Y++;
|
||||
|
||||
if (this->Cursor.Y >= this->termSize.ws_col)
|
||||
if (this->Cursor.Y >= this->TerminalSize.ws_col)
|
||||
this->Scroll(1);
|
||||
|
||||
if (this->CursorCB != nullptr)
|
||||
@ -113,7 +282,7 @@ namespace KernelConsole
|
||||
else
|
||||
{
|
||||
this->Cursor.Y--;
|
||||
this->Cursor.X = this->termSize.ws_row - 1;
|
||||
this->Cursor.X = this->TerminalSize.ws_row - 1;
|
||||
}
|
||||
|
||||
if (this->CursorCB != nullptr)
|
||||
@ -121,10 +290,10 @@ namespace KernelConsole
|
||||
}
|
||||
else
|
||||
{
|
||||
if (this->Cursor.X >= this->termSize.ws_row)
|
||||
if (this->Cursor.X >= this->TerminalSize.ws_row)
|
||||
this->NewLine();
|
||||
|
||||
TerminalCell *cell = &this->Cells[this->Cursor.X + this->Cursor.Y * this->termSize.ws_row];
|
||||
TerminalCell *cell = &this->Cells[this->Cursor.X + this->Cursor.Y * this->TerminalSize.ws_row];
|
||||
cell->c = c;
|
||||
cell->attr = this->Attribute;
|
||||
|
||||
@ -150,12 +319,12 @@ namespace KernelConsole
|
||||
if (Args[0].Empty)
|
||||
this->Cursor.Y = 0;
|
||||
else
|
||||
this->Cursor.Y = MIN(Args[0].Value - 1, this->termSize.ws_col - 1);
|
||||
this->Cursor.Y = MIN(Args[0].Value - 1, this->TerminalSize.ws_col - 1);
|
||||
|
||||
if (Args[1].Empty)
|
||||
this->Cursor.Y = 0;
|
||||
else
|
||||
this->Cursor.X = MIN(Args[1].Value - 1, this->termSize.ws_row - 1);
|
||||
this->Cursor.X = MIN(Args[1].Value - 1, this->TerminalSize.ws_row - 1);
|
||||
}
|
||||
|
||||
if (this->CursorCB != nullptr)
|
||||
@ -167,17 +336,17 @@ namespace KernelConsole
|
||||
TerminalCursor cursor = this->Cursor;
|
||||
|
||||
if (Args[0].Empty)
|
||||
this->Clear(cursor.X, cursor.Y, this->termSize.ws_row, this->termSize.ws_col - 1);
|
||||
this->Clear(cursor.X, cursor.Y, this->TerminalSize.ws_row, this->TerminalSize.ws_col - 1);
|
||||
else
|
||||
{
|
||||
int attr = Args[0].Value;
|
||||
|
||||
if (attr == 0)
|
||||
this->Clear(cursor.X, cursor.Y, this->termSize.ws_row, this->termSize.ws_col - 1);
|
||||
this->Clear(cursor.X, cursor.Y, this->TerminalSize.ws_row, this->TerminalSize.ws_col - 1);
|
||||
else if (attr == 1)
|
||||
this->Clear(0, 0, cursor.X, cursor.Y);
|
||||
else if (attr == 2)
|
||||
this->Clear(0, 0, this->termSize.ws_row, this->termSize.ws_col - 1);
|
||||
this->Clear(0, 0, this->TerminalSize.ws_row, this->TerminalSize.ws_col - 1);
|
||||
}
|
||||
}
|
||||
|
||||
@ -186,17 +355,17 @@ namespace KernelConsole
|
||||
TerminalCursor cursor = this->Cursor;
|
||||
|
||||
if (Args[0].Empty)
|
||||
this->Clear(cursor.X, cursor.Y, this->termSize.ws_row, cursor.Y);
|
||||
this->Clear(cursor.X, cursor.Y, this->TerminalSize.ws_row, cursor.Y);
|
||||
else
|
||||
{
|
||||
int attr = Args[0].Value;
|
||||
|
||||
if (attr == 0)
|
||||
this->Clear(cursor.X, cursor.Y, this->termSize.ws_row, cursor.Y);
|
||||
this->Clear(cursor.X, cursor.Y, this->TerminalSize.ws_row, cursor.Y);
|
||||
else if (attr == 1)
|
||||
this->Clear(0, cursor.Y, cursor.X, cursor.Y);
|
||||
else if (attr == 2)
|
||||
this->Clear(0, cursor.Y, this->termSize.ws_row, cursor.Y);
|
||||
this->Clear(0, cursor.Y, this->TerminalSize.ws_row, cursor.Y);
|
||||
}
|
||||
}
|
||||
|
||||
@ -234,8 +403,8 @@ namespace KernelConsole
|
||||
{
|
||||
int P1 = (ArgsCount > 0 && !Args[0].Empty) ? Args[0].Value : 1;
|
||||
Cursor.Y += P1;
|
||||
if (Cursor.Y >= this->termSize.ws_col)
|
||||
Cursor.Y = this->termSize.ws_col - 1;
|
||||
if (Cursor.Y >= this->TerminalSize.ws_col)
|
||||
Cursor.Y = this->TerminalSize.ws_col - 1;
|
||||
if (CursorCB)
|
||||
CursorCB(&Cursor);
|
||||
}
|
||||
@ -244,8 +413,8 @@ namespace KernelConsole
|
||||
{
|
||||
int P1 = (ArgsCount > 0 && !Args[0].Empty) ? Args[0].Value : 1;
|
||||
Cursor.X += P1;
|
||||
if (Cursor.X >= this->termSize.ws_row)
|
||||
Cursor.X = this->termSize.ws_row - 1;
|
||||
if (Cursor.X >= this->TerminalSize.ws_row)
|
||||
Cursor.X = this->TerminalSize.ws_row - 1;
|
||||
if (CursorCB)
|
||||
CursorCB(&Cursor);
|
||||
}
|
||||
@ -264,8 +433,8 @@ namespace KernelConsole
|
||||
{
|
||||
int P1 = (ArgsCount > 0 && !Args[0].Empty) ? Args[0].Value : 1;
|
||||
Cursor.Y += P1;
|
||||
if (Cursor.Y >= this->termSize.ws_col)
|
||||
Cursor.Y = this->termSize.ws_col - 1;
|
||||
if (Cursor.Y >= this->TerminalSize.ws_col)
|
||||
Cursor.Y = this->TerminalSize.ws_col - 1;
|
||||
Cursor.X = 0;
|
||||
if (CursorCB)
|
||||
CursorCB(&Cursor);
|
||||
@ -286,8 +455,8 @@ namespace KernelConsole
|
||||
{
|
||||
int P1 = (ArgsCount > 0 && !Args[0].Empty) ? Args[0].Value : 1;
|
||||
Cursor.X = P1 - 1;
|
||||
if (Cursor.X >= this->termSize.ws_row)
|
||||
Cursor.X = this->termSize.ws_row - 1;
|
||||
if (Cursor.X >= this->TerminalSize.ws_row)
|
||||
Cursor.X = this->TerminalSize.ws_row - 1;
|
||||
if (CursorCB)
|
||||
CursorCB(&Cursor);
|
||||
}
|
||||
@ -378,8 +547,11 @@ namespace KernelConsole
|
||||
case ANSIParser::ParserState::EndValue:
|
||||
break;
|
||||
default:
|
||||
{
|
||||
error("Invalid parser state: %d", parser->State);
|
||||
assert(!"Invalid parser state");
|
||||
}
|
||||
}
|
||||
|
||||
if (parser->State == ANSIParser::ParserState::EndValue)
|
||||
{
|
||||
@ -442,7 +614,7 @@ namespace KernelConsole
|
||||
PaintCallback _Paint, CursorCallback _Print)
|
||||
: PaintCB(_Paint), CursorCB(_Print)
|
||||
{
|
||||
this->termSize = {
|
||||
this->TerminalSize = {
|
||||
.ws_row = Rows,
|
||||
.ws_col = Columns,
|
||||
.ws_xpixel = XPixels,
|
||||
@ -463,28 +635,29 @@ namespace KernelConsole
|
||||
- ECHO - Echo input characters
|
||||
- ICANON - Enable canonical input (enable line editing)
|
||||
*/
|
||||
this->term.c_iflag = /*ICRNL |*/ IXON;
|
||||
this->term.c_oflag = OPOST | ONLCR;
|
||||
this->term.c_cflag = CS8 | CREAD | HUPCL;
|
||||
this->term.c_lflag = ECHO | ICANON;
|
||||
this->TerminalConfig.c_iflag = /*ICRNL |*/ IXON;
|
||||
this->TerminalConfig.c_oflag = OPOST | ONLCR;
|
||||
this->TerminalConfig.c_cflag = CS8 | CREAD | HUPCL;
|
||||
this->TerminalConfig.c_lflag = ECHO | ICANON;
|
||||
this->TerminalConfig.c_lflag &= ~ICANON; /* FIXME: not ready for this yet */
|
||||
|
||||
this->term.c_cc[VINTR] = 0x03; /* ^C */
|
||||
this->term.c_cc[VQUIT] = 0x1C; /* ^\ */
|
||||
this->term.c_cc[VERASE] = 0x7F; /* DEL */
|
||||
this->term.c_cc[VKILL] = 0x15; /* ^U */
|
||||
this->term.c_cc[VEOF] = 0x04; /* ^D */
|
||||
this->term.c_cc[VTIME] = 0; /* Timeout for non-canonical read */
|
||||
this->term.c_cc[VMIN] = 1; /* Minimum number of characters for non-canonical read */
|
||||
this->term.c_cc[VSWTC] = 0; /* ^O */
|
||||
this->term.c_cc[VSTART] = 0x11; /* ^Q */
|
||||
this->term.c_cc[VSTOP] = 0x13; /* ^S */
|
||||
this->term.c_cc[VSUSP] = 0x1A; /* ^Z */
|
||||
this->term.c_cc[VEOL] = 0x00; /* NUL */
|
||||
this->term.c_cc[VREPRINT] = 0x12; /* ^R */
|
||||
this->term.c_cc[VDISCARD] = 0x14; /* ^T */
|
||||
this->term.c_cc[VWERASE] = 0x17; /* ^W */
|
||||
this->term.c_cc[VLNEXT] = 0x19; /* ^Y */
|
||||
this->term.c_cc[VEOL2] = 0x7F; /* DEL (or sometimes EOF) */
|
||||
this->TerminalConfig.c_cc[VINTR] = 0x03; /* ^C */
|
||||
this->TerminalConfig.c_cc[VQUIT] = 0x1C; /* ^\ */
|
||||
this->TerminalConfig.c_cc[VERASE] = 0x7F; /* DEL */
|
||||
this->TerminalConfig.c_cc[VKILL] = 0x15; /* ^U */
|
||||
this->TerminalConfig.c_cc[VEOF] = 0x04; /* ^D */
|
||||
this->TerminalConfig.c_cc[VTIME] = 0; /* Timeout for non-canonical read */
|
||||
this->TerminalConfig.c_cc[VMIN] = 1; /* Minimum number of characters for non-canonical read */
|
||||
this->TerminalConfig.c_cc[VSWTC] = 0; /* ^O */
|
||||
this->TerminalConfig.c_cc[VSTART] = 0x11; /* ^Q */
|
||||
this->TerminalConfig.c_cc[VSTOP] = 0x13; /* ^S */
|
||||
this->TerminalConfig.c_cc[VSUSP] = 0x1A; /* ^Z */
|
||||
this->TerminalConfig.c_cc[VEOL] = 0x00; /* NUL */
|
||||
this->TerminalConfig.c_cc[VREPRINT] = 0x12; /* ^R */
|
||||
this->TerminalConfig.c_cc[VDISCARD] = 0x14; /* ^T */
|
||||
this->TerminalConfig.c_cc[VWERASE] = 0x17; /* ^W */
|
||||
this->TerminalConfig.c_cc[VLNEXT] = 0x19; /* ^Y */
|
||||
this->TerminalConfig.c_cc[VEOL2] = 0x7F; /* DEL (or sometimes EOF) */
|
||||
|
||||
this->Cells = new TerminalCell[Rows * Columns];
|
||||
|
Loading…
x
Reference in New Issue
Block a user