mirror of
https://github.com/Fennix-Project/Kernel.git
synced 2025-07-11 07:19:20 +00:00
Update kernel
This commit is contained in:
939
core/driver/api.cpp
Normal file
939
core/driver/api.cpp
Normal file
@ -0,0 +1,939 @@
|
||||
/*
|
||||
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 "../../kernel.h"
|
||||
#include "../../driver.h"
|
||||
|
||||
// #define DEBUG_API
|
||||
|
||||
#ifdef DEBUG_API
|
||||
#define dbg_api(Format, ...) function(Format, ##__VA_ARGS__)
|
||||
#else
|
||||
#define dbg_api(Format, ...)
|
||||
#endif
|
||||
|
||||
using enum PCI::PCICommands;
|
||||
|
||||
#define VMWARE_MAGIC 0x564D5868 /* hXMV */
|
||||
#define VMWARE_PORT 0x5658
|
||||
#define CMD_GETVERSION 0xA
|
||||
|
||||
namespace Driver
|
||||
{
|
||||
int RegisterFunction(dev_t MajorID, void *Function, __driverRegFunc Type)
|
||||
{
|
||||
dbg_api("%d, %#lx, %d", MajorID, (uintptr_t)Function, Type);
|
||||
|
||||
std::unordered_map<dev_t, DriverObject> &Drivers =
|
||||
DriverManager->GetDrivers();
|
||||
|
||||
auto itr = Drivers.find(MajorID);
|
||||
if (itr == Drivers.end())
|
||||
return -EINVAL;
|
||||
|
||||
DriverObject *drv = &itr->second;
|
||||
|
||||
switch (Type)
|
||||
{
|
||||
case _drf_Entry:
|
||||
drv->Entry = (int (*)())Function;
|
||||
debug("Entry %#lx for %s", (uintptr_t)Function, drv->Path);
|
||||
break;
|
||||
case _drf_Final:
|
||||
drv->Final = (int (*)())Function;
|
||||
debug("Finalize %#lx for %s", (uintptr_t)Function, drv->Path);
|
||||
break;
|
||||
case _drf_Panic:
|
||||
drv->Panic = (int (*)())Function;
|
||||
debug("Panic %#lx for %s", (uintptr_t)Function, drv->Path);
|
||||
break;
|
||||
case _drf_Probe:
|
||||
drv->Probe = (int (*)())Function;
|
||||
debug("Probe %#lx for %s", (uintptr_t)Function, drv->Path);
|
||||
break;
|
||||
default:
|
||||
assert(!"Invalid driver function type");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int GetDriverInfo(dev_t MajorID, const char *Name, const char *Description, const char *Author, const char *Version, const char *License)
|
||||
{
|
||||
dbg_api("%d, %s, %s, %s, %s, %s", MajorID, Name, Description, Author, Version, License);
|
||||
|
||||
std::unordered_map<dev_t, DriverObject> &Drivers =
|
||||
DriverManager->GetDrivers();
|
||||
|
||||
auto itr = Drivers.find(MajorID);
|
||||
if (itr == Drivers.end())
|
||||
return -EINVAL;
|
||||
|
||||
DriverObject *drv = &itr->second;
|
||||
|
||||
strncpy(drv->Name, Name, sizeof(drv->Name));
|
||||
strncpy(drv->Description, Description, sizeof(drv->Description));
|
||||
strncpy(drv->Author, Author, sizeof(drv->Author));
|
||||
strncpy(drv->Version, Version, sizeof(drv->Version));
|
||||
strncpy(drv->License, License, sizeof(drv->License));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* --------- */
|
||||
|
||||
int RegisterInterruptHandler(dev_t MajorID, uint8_t IRQ, void *Handler)
|
||||
{
|
||||
dbg_api("%d, %d, %#lx", MajorID, IRQ, Handler);
|
||||
|
||||
std::unordered_map<dev_t, DriverObject> &Drivers =
|
||||
DriverManager->GetDrivers();
|
||||
|
||||
auto itr = Drivers.find(MajorID);
|
||||
if (itr == Drivers.end())
|
||||
return -EINVAL;
|
||||
|
||||
DriverObject *drv = &itr->second;
|
||||
|
||||
if (drv->InterruptHandlers->contains(IRQ))
|
||||
return -EEXIST;
|
||||
|
||||
Interrupts::AddHandler((void (*)(CPU::TrapFrame *))Handler, IRQ);
|
||||
drv->InterruptHandlers->insert(std::pair<uint8_t, void *>(IRQ, Handler));
|
||||
return 0;
|
||||
}
|
||||
|
||||
int OverrideInterruptHandler(dev_t MajorID, uint8_t IRQ, void *Handler)
|
||||
{
|
||||
dbg_api("%d, %d, %#lx", MajorID, IRQ, Handler);
|
||||
|
||||
debug("Overriding IRQ %d with %#lx", IRQ, Handler);
|
||||
|
||||
std::unordered_map<dev_t, DriverObject> &Drivers =
|
||||
DriverManager->GetDrivers();
|
||||
|
||||
foreach (auto &var in Drivers)
|
||||
{
|
||||
DriverObject *drv = &var.second;
|
||||
|
||||
foreach (auto &ih in * drv->InterruptHandlers)
|
||||
{
|
||||
if (ih.first == IRQ)
|
||||
{
|
||||
debug("Removing IRQ %d: %#lx for %s", IRQ, (uintptr_t)ih.second, drv->Path);
|
||||
Interrupts::RemoveHandler((void (*)(CPU::TrapFrame *))ih.second, IRQ);
|
||||
drv->InterruptHandlers->erase(IRQ);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return RegisterInterruptHandler(MajorID, IRQ, Handler);
|
||||
}
|
||||
|
||||
int UnregisterInterruptHandler(dev_t MajorID, uint8_t IRQ, void *Handler)
|
||||
{
|
||||
dbg_api("%d, %d, %#lx", MajorID, IRQ, Handler);
|
||||
|
||||
std::unordered_map<dev_t, DriverObject> &Drivers =
|
||||
DriverManager->GetDrivers();
|
||||
|
||||
auto itr = Drivers.find(MajorID);
|
||||
if (itr == Drivers.end())
|
||||
return -EINVAL;
|
||||
|
||||
DriverObject *drv = &itr->second;
|
||||
Interrupts::RemoveHandler((void (*)(CPU::TrapFrame *))Handler, IRQ);
|
||||
drv->InterruptHandlers->erase(IRQ);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int UnregisterAllInterruptHandlers(dev_t MajorID, void *Handler)
|
||||
{
|
||||
dbg_api("%d, %#lx", MajorID, Handler);
|
||||
|
||||
std::unordered_map<dev_t, DriverObject> &Drivers =
|
||||
DriverManager->GetDrivers();
|
||||
|
||||
auto itr = Drivers.find(MajorID);
|
||||
if (itr == Drivers.end())
|
||||
return -EINVAL;
|
||||
|
||||
DriverObject *drv = &itr->second;
|
||||
foreach (auto &i in * drv->InterruptHandlers)
|
||||
{
|
||||
Interrupts::RemoveHandler((void (*)(CPU::TrapFrame *))Handler, i.first);
|
||||
debug("Removed IRQ %d: %#lx for %s", i.first, (uintptr_t)Handler, drv->Path);
|
||||
}
|
||||
drv->InterruptHandlers->clear();
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* --------- */
|
||||
|
||||
dev_t RegisterInputDevice(dev_t MajorID, DeviceDriverType Type)
|
||||
{
|
||||
dbg_api("%d, %d", MajorID, Type);
|
||||
|
||||
switch (Type)
|
||||
{
|
||||
case ddt_Keyboard:
|
||||
return DriverManager->InputKeyboardDev->Register(MajorID);
|
||||
case ddt_Mouse:
|
||||
return DriverManager->InputMouseDev->Register(MajorID);
|
||||
/* ... */
|
||||
default:
|
||||
assert(!"Invalid input device type");
|
||||
}
|
||||
}
|
||||
|
||||
int UnregisterInputDevice(dev_t MajorID, dev_t MinorID, DeviceDriverType Type)
|
||||
{
|
||||
dbg_api("%d, %d, %d", MajorID, MinorID, Type);
|
||||
|
||||
switch (Type)
|
||||
{
|
||||
case ddt_Keyboard:
|
||||
return DriverManager->InputKeyboardDev->Unregister(MajorID, MinorID);
|
||||
case ddt_Mouse:
|
||||
return DriverManager->InputMouseDev->Unregister(MajorID, MinorID);
|
||||
/* ... */
|
||||
default:
|
||||
assert(!"Invalid input device type");
|
||||
}
|
||||
}
|
||||
|
||||
int ReportKeyboardEvent(dev_t MajorID, dev_t MinorID, uint8_t ScanCode)
|
||||
{
|
||||
dbg_api("%d, %d, %d", MajorID, MinorID, ScanCode);
|
||||
|
||||
return DriverManager->InputKeyboardDev->ReportKeyEvent(MajorID, MinorID, ScanCode);
|
||||
}
|
||||
|
||||
int ReportRelativeMouseEvent(dev_t MajorID, dev_t MinorID, __MouseButtons Button, int X, int Y, int8_t Z)
|
||||
{
|
||||
dbg_api("%d, %d, %d, %d, %d, %d", MajorID, MinorID, Button, X, Y, Z);
|
||||
|
||||
return DriverManager->InputMouseDev->ReportMouseEvent(MajorID, MinorID,
|
||||
Button.LeftButton, Button.RightButton, Button.MiddleButton,
|
||||
Button.Button4, Button.Button5, Button.Button6, Button.Button7, Button.Button8,
|
||||
X, Y, Z, true);
|
||||
}
|
||||
|
||||
int ReportAbsoluteMouseEvent(dev_t MajorID, dev_t MinorID, __MouseButtons Button, uintptr_t X, uintptr_t Y, int8_t Z)
|
||||
{
|
||||
dbg_api("%d, %d, %d, %d, %d, %d", MajorID, MinorID, Button, X, Y, Z);
|
||||
|
||||
return DriverManager->InputMouseDev->ReportMouseEvent(MajorID, MinorID,
|
||||
Button.LeftButton, Button.RightButton, Button.MiddleButton,
|
||||
Button.Button4, Button.Button5, Button.Button6, Button.Button7, Button.Button8,
|
||||
X, Y, Z, false);
|
||||
}
|
||||
|
||||
/* --------- */
|
||||
|
||||
dev_t RegisterBlockDevice(dev_t MajorID, DeviceDriverType Type, void *Open, void *Close, void *Read, void *Write, void *Ioctl)
|
||||
{
|
||||
dbg_api("%d, %d, %#lx, %#lx, %#lx, %#lx, %#lx", MajorID, Type, Open, Close, Read, Write, Ioctl);
|
||||
|
||||
switch (Type)
|
||||
{
|
||||
case ddt_SATA:
|
||||
{
|
||||
dev_t ret = DriverManager->BlockSATADev->Register(MajorID);
|
||||
DriverManager->BlockSATADev->NewBlock(MajorID, ret,
|
||||
(SlaveDeviceFile::drvOpen_t)Open,
|
||||
(SlaveDeviceFile::drvClose_t)Close,
|
||||
(SlaveDeviceFile::drvRead_t)Read,
|
||||
(SlaveDeviceFile::drvWrite_t)Write,
|
||||
(SlaveDeviceFile::drvIoctl_t)Ioctl);
|
||||
return ret;
|
||||
}
|
||||
case ddt_ATA:
|
||||
{
|
||||
dev_t ret = DriverManager->BlockHDDev->Register(MajorID);
|
||||
DriverManager->BlockHDDev->NewBlock(MajorID, ret,
|
||||
(SlaveDeviceFile::drvOpen_t)Open,
|
||||
(SlaveDeviceFile::drvClose_t)Close,
|
||||
(SlaveDeviceFile::drvRead_t)Read,
|
||||
(SlaveDeviceFile::drvWrite_t)Write,
|
||||
(SlaveDeviceFile::drvIoctl_t)Ioctl);
|
||||
return ret;
|
||||
}
|
||||
case ddt_NVMe:
|
||||
{
|
||||
dev_t ret = DriverManager->BlockNVMeDev->Register(MajorID);
|
||||
DriverManager->BlockNVMeDev->NewBlock(MajorID, ret,
|
||||
(SlaveDeviceFile::drvOpen_t)Open,
|
||||
(SlaveDeviceFile::drvClose_t)Close,
|
||||
(SlaveDeviceFile::drvRead_t)Read,
|
||||
(SlaveDeviceFile::drvWrite_t)Write,
|
||||
(SlaveDeviceFile::drvIoctl_t)Ioctl);
|
||||
return ret;
|
||||
}
|
||||
/* ... */
|
||||
default:
|
||||
assert(!"Invalid storage device type");
|
||||
}
|
||||
}
|
||||
|
||||
int UnregisterBlockDevice(dev_t MajorID, dev_t MinorID, DeviceDriverType Type)
|
||||
{
|
||||
dbg_api("%d, %d, %d", MajorID, MinorID, Type);
|
||||
|
||||
switch (Type)
|
||||
{
|
||||
case ddt_SATA:
|
||||
return DriverManager->BlockSATADev->Unregister(MajorID, MinorID);
|
||||
case ddt_ATA:
|
||||
return DriverManager->BlockHDDev->Unregister(MajorID, MinorID);
|
||||
case ddt_NVMe:
|
||||
return DriverManager->BlockNVMeDev->Unregister(MajorID, MinorID);
|
||||
/* ... */
|
||||
default:
|
||||
assert(!"Invalid storage device type");
|
||||
}
|
||||
}
|
||||
|
||||
/* --------- */
|
||||
|
||||
dev_t RegisterAudioDevice(dev_t MajorID, DeviceDriverType Type, void *Open, void *Close, void *Read, void *Write, void *Ioctl)
|
||||
{
|
||||
dbg_api("%d, %d, %#lx, %#lx, %#lx, %#lx, %#lx", MajorID, Type, Open, Close, Read, Write, Ioctl);
|
||||
|
||||
switch (Type)
|
||||
{
|
||||
case ddt_Audio:
|
||||
{
|
||||
dev_t ret = DriverManager->AudioDev->Register(MajorID);
|
||||
DriverManager->AudioDev->NewAudio(MajorID, ret,
|
||||
(SlaveDeviceFile::drvOpen_t)Open,
|
||||
(SlaveDeviceFile::drvClose_t)Close,
|
||||
(SlaveDeviceFile::drvRead_t)Read,
|
||||
(SlaveDeviceFile::drvWrite_t)Write,
|
||||
(SlaveDeviceFile::drvIoctl_t)Ioctl);
|
||||
return ret;
|
||||
}
|
||||
/* ... */
|
||||
default:
|
||||
assert(!"Invalid audio device type");
|
||||
}
|
||||
}
|
||||
|
||||
int UnregisterAudioDevice(dev_t MajorID, dev_t MinorID, DeviceDriverType Type)
|
||||
{
|
||||
dbg_api("%d, %d, %d", MajorID, MinorID, Type);
|
||||
|
||||
switch (Type)
|
||||
{
|
||||
case ddt_Audio:
|
||||
return DriverManager->AudioDev->Unregister(MajorID, MinorID);
|
||||
/* ... */
|
||||
default:
|
||||
assert(!"Invalid audio device type");
|
||||
}
|
||||
}
|
||||
|
||||
/* --------- */
|
||||
|
||||
dev_t RegisterNetDevice(dev_t MajorID, DeviceDriverType Type, void *Open, void *Close, void *Read, void *Write, void *Ioctl)
|
||||
{
|
||||
dbg_api("%d, %d, %#lx, %#lx, %#lx, %#lx, %#lx", MajorID, Type, Open, Close, Read, Write, Ioctl);
|
||||
|
||||
switch (Type)
|
||||
{
|
||||
case ddt_Network:
|
||||
{
|
||||
dev_t ret = DriverManager->NetDev->Register(MajorID);
|
||||
DriverManager->NetDev->NewNet(MajorID, ret,
|
||||
(SlaveDeviceFile::drvOpen_t)Open,
|
||||
(SlaveDeviceFile::drvClose_t)Close,
|
||||
(SlaveDeviceFile::drvRead_t)Read,
|
||||
(SlaveDeviceFile::drvWrite_t)Write,
|
||||
(SlaveDeviceFile::drvIoctl_t)Ioctl);
|
||||
return ret;
|
||||
}
|
||||
/* ... */
|
||||
default:
|
||||
assert(!"Invalid audio device type");
|
||||
}
|
||||
}
|
||||
|
||||
int UnregisterNetDevice(dev_t MajorID, dev_t MinorID, DeviceDriverType Type)
|
||||
{
|
||||
dbg_api("%d, %d, %d", MajorID, MinorID, Type);
|
||||
|
||||
switch (Type)
|
||||
{
|
||||
case ddt_Network:
|
||||
return DriverManager->NetDev->Unregister(MajorID, MinorID);
|
||||
/* ... */
|
||||
default:
|
||||
assert(!"Invalid audio device type");
|
||||
}
|
||||
}
|
||||
|
||||
int ReportNetworkPacket(dev_t MajorID, dev_t MinorID, void *Buffer, size_t Size)
|
||||
{
|
||||
dbg_api("%d, %d, %#lx, %d", MajorID, MinorID, Buffer, Size);
|
||||
|
||||
return DriverManager->NetDev->ReportNetworkPacket(MajorID, MinorID, Buffer, Size);
|
||||
}
|
||||
|
||||
/* --------- */
|
||||
|
||||
void d_KPrint(dev_t MajorID, const char *Format, va_list args)
|
||||
{
|
||||
dbg_api("%d %s, %#lx", MajorID, Format, args);
|
||||
|
||||
_KPrint(Format, args);
|
||||
}
|
||||
|
||||
void KernelLog(dev_t MajorID, const char *Format, va_list args)
|
||||
{
|
||||
dbg_api("%d, %s, %#lx", MajorID, Format, args);
|
||||
|
||||
fctprintf(uart_wrapper, nullptr, "DRVER| %ld: ", MajorID);
|
||||
vfctprintf(uart_wrapper, nullptr, Format, args);
|
||||
uart_wrapper('\n', nullptr);
|
||||
}
|
||||
|
||||
/* --------- */
|
||||
|
||||
void *RequestPages(dev_t MajorID, size_t Pages)
|
||||
{
|
||||
dbg_api("%d, %d", MajorID, Pages);
|
||||
|
||||
std::unordered_map<dev_t, DriverObject> &Drivers =
|
||||
DriverManager->GetDrivers();
|
||||
auto itr = Drivers.find(MajorID);
|
||||
assert(itr != Drivers.end());
|
||||
|
||||
return itr->second.vma->RequestPages(Pages);
|
||||
}
|
||||
|
||||
void FreePages(dev_t MajorID, void *Pointer, size_t Pages)
|
||||
{
|
||||
dbg_api("%d, %#lx, %d", MajorID, Pointer, Pages);
|
||||
|
||||
std::unordered_map<dev_t, DriverObject> &Drivers =
|
||||
DriverManager->GetDrivers();
|
||||
|
||||
auto itr = Drivers.find(MajorID);
|
||||
assert(itr != Drivers.end());
|
||||
|
||||
itr->second.vma->FreePages(Pointer, Pages);
|
||||
}
|
||||
|
||||
/* --------- */
|
||||
|
||||
void AppendMapFlag(dev_t MajorID, void *Address, PageMapFlags Flag)
|
||||
{
|
||||
dbg_api("%d, %#lx, %d", MajorID, Address, Flag);
|
||||
|
||||
Memory::Virtual vmm(KernelPageTable);
|
||||
vmm.GetPTE(Address)->raw |= Flag;
|
||||
}
|
||||
|
||||
void RemoveMapFlag(dev_t MajorID, void *Address, PageMapFlags Flag)
|
||||
{
|
||||
dbg_api("%d, %#lx, %d", MajorID, Address, Flag);
|
||||
|
||||
Memory::Virtual vmm(KernelPageTable);
|
||||
vmm.GetPTE(Address)->raw &= ~Flag;
|
||||
}
|
||||
|
||||
void MapPages(dev_t MajorID, void *PhysicalAddress, void *VirtualAddress, size_t Pages, uint32_t Flags)
|
||||
{
|
||||
dbg_api("%d, %#lx, %#lx, %d, %d", MajorID, PhysicalAddress, VirtualAddress, Pages, Flags);
|
||||
|
||||
Memory::Virtual vmm(KernelPageTable);
|
||||
vmm.Map(VirtualAddress, PhysicalAddress, Pages, Flags);
|
||||
}
|
||||
|
||||
void UnmapPages(dev_t MajorID, void *VirtualAddress, size_t Pages)
|
||||
{
|
||||
dbg_api("%d, %#lx, %d", MajorID, VirtualAddress, Pages);
|
||||
|
||||
Memory::Virtual vmm(KernelPageTable);
|
||||
vmm.Unmap(VirtualAddress, Pages);
|
||||
}
|
||||
|
||||
/* --------- */
|
||||
|
||||
pid_t CreateKernelProcess(dev_t MajorID, const char *Name)
|
||||
{
|
||||
dbg_api("%d, %s", MajorID, Name);
|
||||
|
||||
Tasking::PCB *pcb = TaskManager->CreateProcess(nullptr,
|
||||
Name, Tasking::System,
|
||||
nullptr, true, 0, 0);
|
||||
|
||||
return pcb->ID;
|
||||
}
|
||||
|
||||
pid_t CreateKernelThread(dev_t MajorID, pid_t pId, const char *Name, void *EntryPoint, void *Argument)
|
||||
{
|
||||
dbg_api("%d, %d, %s, %#lx, %#lx", MajorID, pId, Name, EntryPoint, Argument);
|
||||
|
||||
Tasking::PCB *parent = TaskManager->GetProcessByID(pId);
|
||||
if (!parent)
|
||||
return -EINVAL;
|
||||
|
||||
CriticalSection cs;
|
||||
Tasking::TCB *tcb = TaskManager->CreateThread(parent, (Tasking::IP)EntryPoint);
|
||||
if (Argument)
|
||||
tcb->SYSV_ABI_Call((uintptr_t)Argument);
|
||||
tcb->Rename(Name);
|
||||
return tcb->ID;
|
||||
}
|
||||
|
||||
int KillProcess(dev_t MajorID, pid_t pId, int ExitCode)
|
||||
{
|
||||
dbg_api("%d, %d, %d", MajorID, pId, ExitCode);
|
||||
|
||||
Tasking::PCB *pcb = TaskManager->GetProcessByID(pId);
|
||||
if (!pcb)
|
||||
return -EINVAL;
|
||||
TaskManager->KillProcess(pcb, (Tasking::KillCode)ExitCode);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int KillThread(dev_t MajorID, pid_t tId, int ExitCode)
|
||||
{
|
||||
dbg_api("%d, %d, %d", MajorID, tId, ExitCode);
|
||||
|
||||
Tasking::TCB *tcb = TaskManager->GetThreadByID(tId);
|
||||
if (!tcb)
|
||||
return -EINVAL;
|
||||
TaskManager->KillThread(tcb, (Tasking::KillCode)ExitCode);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Yield(dev_t MajorID)
|
||||
{
|
||||
dbg_api("%d", MajorID);
|
||||
|
||||
TaskManager->Yield();
|
||||
}
|
||||
|
||||
void Sleep(dev_t MajorID, uint64_t Milliseconds)
|
||||
{
|
||||
dbg_api("%d, %d", MajorID, Milliseconds);
|
||||
|
||||
TaskManager->Sleep(Milliseconds);
|
||||
}
|
||||
|
||||
/* --------- */
|
||||
|
||||
__PCIArray *GetPCIDevices(dev_t MajorID, uint16_t _Vendors[], uint16_t _Devices[])
|
||||
{
|
||||
dbg_api("%d, %#lx, %#lx", MajorID, _Vendors, _Devices);
|
||||
|
||||
std::unordered_map<dev_t, DriverObject> &Drivers =
|
||||
DriverManager->GetDrivers();
|
||||
|
||||
auto itr = Drivers.find(MajorID);
|
||||
if (itr == Drivers.end())
|
||||
return nullptr;
|
||||
|
||||
std::list<uint16_t> VendorIDs;
|
||||
for (int i = 0; _Vendors[i] != 0x0; i++)
|
||||
VendorIDs.push_back(_Vendors[i]);
|
||||
|
||||
std::list<uint16_t> DeviceIDs;
|
||||
for (int i = 0; _Devices[i] != 0x0; i++)
|
||||
DeviceIDs.push_back(_Devices[i]);
|
||||
|
||||
std::list<PCI::PCIDevice> Devices = PCIManager->FindPCIDevice(VendorIDs, DeviceIDs);
|
||||
if (Devices.empty())
|
||||
return nullptr;
|
||||
|
||||
Memory::VirtualMemoryArea *vma = itr->second.vma;
|
||||
__PCIArray *head = nullptr;
|
||||
__PCIArray *array = nullptr;
|
||||
|
||||
foreach (auto &dev in Devices)
|
||||
{
|
||||
/* TODO: optimize memory allocation */
|
||||
PCI::PCIDevice *dptr = (PCI::PCIDevice *)vma->RequestPages(TO_PAGES(sizeof(PCI::PCIDevice)));
|
||||
memcpy(dptr, &dev, sizeof(PCI::PCIDevice));
|
||||
|
||||
__PCIArray *newArray = (__PCIArray *)vma->RequestPages(TO_PAGES(sizeof(__PCIArray)));
|
||||
|
||||
if (unlikely(head == nullptr))
|
||||
{
|
||||
head = newArray;
|
||||
array = head;
|
||||
}
|
||||
else
|
||||
{
|
||||
array->Next = newArray;
|
||||
array = newArray;
|
||||
}
|
||||
|
||||
array->Device = dptr;
|
||||
array->Next = nullptr;
|
||||
|
||||
debug("Found %02x.%02x.%02x: %04x:%04x",
|
||||
dev.Bus, dev.Device, dev.Function,
|
||||
dev.Header->VendorID, dev.Header->DeviceID);
|
||||
}
|
||||
|
||||
return head;
|
||||
}
|
||||
|
||||
void InitializePCI(dev_t MajorID, void *_Header)
|
||||
{
|
||||
dbg_api("%d, %#lx", MajorID, _Header);
|
||||
|
||||
PCI::PCIDeviceHeader *Header = (PCI::PCIDeviceHeader *)_Header;
|
||||
|
||||
debug("Header Type: %d", Header->HeaderType);
|
||||
switch (Header->HeaderType)
|
||||
{
|
||||
case 128:
|
||||
warn("Unknown header type %d! Guessing PCI Header 0",
|
||||
Header->HeaderType);
|
||||
[[fallthrough]];
|
||||
case 0: /* PCI Header 0 */
|
||||
{
|
||||
PCI::PCIHeader0 *hdr0 = (PCI::PCIHeader0 *)Header;
|
||||
|
||||
uint32_t BAR[6];
|
||||
size_t BARsSize[6];
|
||||
|
||||
BAR[0] = hdr0->BAR0;
|
||||
BAR[1] = hdr0->BAR1;
|
||||
BAR[2] = hdr0->BAR2;
|
||||
BAR[3] = hdr0->BAR3;
|
||||
BAR[4] = hdr0->BAR4;
|
||||
BAR[5] = hdr0->BAR5;
|
||||
|
||||
debug("Type: %d; IOBase: %#lx; MemoryBase: %#lx",
|
||||
BAR[0] & 1, BAR[1] & (~3), BAR[0] & (~15));
|
||||
|
||||
/* BARs Size */
|
||||
for (short i = 0; i < 6; i++)
|
||||
{
|
||||
if (BAR[i] == 0)
|
||||
continue;
|
||||
|
||||
size_t size;
|
||||
if ((BAR[i] & 1) == 0) /* Memory Base */
|
||||
{
|
||||
hdr0->BAR0 = 0xFFFFFFFF;
|
||||
size = hdr0->BAR0;
|
||||
hdr0->BAR0 = BAR[i];
|
||||
BARsSize[i] = size & (~15);
|
||||
BARsSize[i] = ~BARsSize[i] + 1;
|
||||
BARsSize[i] = BARsSize[i] & 0xFFFFFFFF;
|
||||
debug("BAR%d %#lx size: %d",
|
||||
i, BAR[i], BARsSize[i]);
|
||||
}
|
||||
else if ((BAR[i] & 1) == 1) /* I/O Base */
|
||||
{
|
||||
hdr0->BAR1 = 0xFFFFFFFF;
|
||||
size = hdr0->BAR1;
|
||||
hdr0->BAR1 = BAR[i];
|
||||
BARsSize[i] = size & (~3);
|
||||
BARsSize[i] = ~BARsSize[i] + 1;
|
||||
BARsSize[i] = BARsSize[i] & 0xFFFF;
|
||||
debug("BAR%d %#lx size: %d",
|
||||
i, BAR[i], BARsSize[i]);
|
||||
}
|
||||
}
|
||||
|
||||
Memory::Virtual vmm(KernelPageTable);
|
||||
|
||||
/* Mapping the BARs */
|
||||
for (short i = 0; i < 6; i++)
|
||||
{
|
||||
if (BAR[i] == 0)
|
||||
continue;
|
||||
|
||||
if ((BAR[i] & 1) == 0) /* Memory Base */
|
||||
{
|
||||
uintptr_t BARBase = BAR[i] & (~15);
|
||||
size_t BARSize = BARsSize[i];
|
||||
|
||||
debug("Mapping BAR%d %#lx-%#lx",
|
||||
i, BARBase, BARBase + BARSize);
|
||||
|
||||
if (BARSize == 0)
|
||||
{
|
||||
warn("BAR%d size is zero!", i);
|
||||
BARSize++;
|
||||
}
|
||||
|
||||
vmm.Map((void *)BARBase, (void *)BARBase,
|
||||
BARSize, Memory::RW | Memory::PWT | Memory::PCD);
|
||||
}
|
||||
else if ((BAR[i] & 1) == 1) /* I/O Base */
|
||||
{
|
||||
uintptr_t BARBase = BAR[i] & (~3);
|
||||
size_t BARSize = BARsSize[i];
|
||||
|
||||
debug("Mapping BAR%d %#x-%#x",
|
||||
i, BARBase, BARBase + BARSize);
|
||||
|
||||
if (BARSize == 0)
|
||||
{
|
||||
warn("BAR%d size is zero!", i);
|
||||
BARSize++;
|
||||
}
|
||||
|
||||
vmm.Map((void *)BARBase, (void *)BARBase,
|
||||
BARSize, Memory::RW | Memory::PWT | Memory::PCD);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 1: /* PCI Header 1 (PCI-to-PCI Bridge) */
|
||||
{
|
||||
fixme("PCI Header 1 (PCI-to-PCI Bridge) not implemented yet");
|
||||
break;
|
||||
}
|
||||
case 2: /* PCI Header 2 (PCI-to-CardBus Bridge) */
|
||||
{
|
||||
fixme("PCI Header 2 (PCI-to-CardBus Bridge) not implemented yet");
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
error("Unknown header type %d", Header->HeaderType);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Header->Command |= PCI_COMMAND_MASTER |
|
||||
PCI_COMMAND_IO |
|
||||
PCI_COMMAND_MEMORY;
|
||||
Header->Command &= ~PCI_COMMAND_INTX_DISABLE;
|
||||
}
|
||||
|
||||
uint32_t GetBAR(dev_t MajorID, uint8_t i, void *_Header)
|
||||
{
|
||||
dbg_api("%d, %d, %#lx", MajorID, i, _Header);
|
||||
|
||||
PCI::PCIDeviceHeader *Header = (PCI::PCIDeviceHeader *)_Header;
|
||||
|
||||
switch (Header->HeaderType)
|
||||
{
|
||||
case 128:
|
||||
warn("Unknown header type %d! Guessing PCI Header 0",
|
||||
Header->HeaderType);
|
||||
[[fallthrough]];
|
||||
case 0: /* PCI Header 0 */
|
||||
{
|
||||
PCI::PCIHeader0 *hdr0 =
|
||||
(PCI::PCIHeader0 *)Header;
|
||||
switch (i)
|
||||
{
|
||||
case 0:
|
||||
return hdr0->BAR0;
|
||||
case 1:
|
||||
return hdr0->BAR1;
|
||||
case 2:
|
||||
return hdr0->BAR2;
|
||||
case 3:
|
||||
return hdr0->BAR3;
|
||||
case 4:
|
||||
return hdr0->BAR4;
|
||||
case 5:
|
||||
return hdr0->BAR5;
|
||||
default:
|
||||
assert(!"Invalid BAR index");
|
||||
}
|
||||
}
|
||||
case 1: /* PCI Header 1 (PCI-to-PCI Bridge) */
|
||||
{
|
||||
PCI::PCIHeader1 *hdr1 =
|
||||
(PCI::PCIHeader1 *)Header;
|
||||
switch (i)
|
||||
{
|
||||
case 0:
|
||||
return hdr1->BAR0;
|
||||
case 1:
|
||||
return hdr1->BAR1;
|
||||
default:
|
||||
assert(!"Invalid BAR index");
|
||||
}
|
||||
}
|
||||
case 2: /* PCI Header 2 (PCI-to-CardBus Bridge) */
|
||||
{
|
||||
assert(!"PCI-to-CardBus Bridge not supported");
|
||||
}
|
||||
default:
|
||||
assert(!"Invalid PCI header type");
|
||||
}
|
||||
}
|
||||
|
||||
/* --------- */
|
||||
|
||||
void *api__memcpy(dev_t MajorID, void *Destination, const void *Source, size_t Length)
|
||||
{
|
||||
dbg_api("%d, %#lx, %#lx, %d", MajorID, Destination, Source, Length);
|
||||
|
||||
return memcpy(Destination, Source, Length);
|
||||
}
|
||||
|
||||
void *api__memset(dev_t MajorID, void *Destination, int Value, size_t Length)
|
||||
{
|
||||
dbg_api("%d, %#lx, %d, %d", MajorID, Destination, Value, Length);
|
||||
|
||||
return memset(Destination, Value, Length);
|
||||
}
|
||||
|
||||
void *api__memmove(dev_t MajorID, void *Destination, const void *Source, size_t Length)
|
||||
{
|
||||
dbg_api("%d, %#lx, %#lx, %d", MajorID, Destination, Source, Length);
|
||||
|
||||
return memmove(Destination, Source, Length);
|
||||
}
|
||||
|
||||
int api__memcmp(dev_t MajorID, const void *Left, const void *Right, size_t Length)
|
||||
{
|
||||
dbg_api("%d, %#lx, %#lx, %d", MajorID, Left, Right, Length);
|
||||
|
||||
return memcmp(Left, Right, Length);
|
||||
}
|
||||
|
||||
size_t api__strlen(dev_t MajorID, const char *String)
|
||||
{
|
||||
dbg_api("%d, %s", MajorID, String);
|
||||
|
||||
return strlen(String);
|
||||
}
|
||||
|
||||
char *api__strcpy(dev_t MajorID, char *Destination, const char *Source)
|
||||
{
|
||||
dbg_api("%d, %#lx, %s", MajorID, Destination, Source);
|
||||
|
||||
return strcpy(Destination, Source);
|
||||
}
|
||||
|
||||
char *api__strcat(dev_t MajorID, char *Destination, const char *Source)
|
||||
{
|
||||
dbg_api("%d, %#lx, %s", MajorID, Destination, Source);
|
||||
|
||||
return strcat(Destination, Source);
|
||||
}
|
||||
|
||||
int api__strcmp(dev_t MajorID, const char *Left, const char *Right)
|
||||
{
|
||||
dbg_api("%d, %s, %s", MajorID, Left, Right);
|
||||
|
||||
return strcmp(Left, Right);
|
||||
}
|
||||
|
||||
int api__strncmp(dev_t MajorID, const char *Left, const char *Right, size_t Length)
|
||||
{
|
||||
dbg_api("%d, %s, %s, %d", MajorID, Left, Right, Length);
|
||||
|
||||
return strncmp(Left, Right, Length);
|
||||
}
|
||||
|
||||
char *api__strchr(dev_t MajorID, const char *String, int Character)
|
||||
{
|
||||
dbg_api("%d, %s, %d", MajorID, String, Character);
|
||||
|
||||
return strchr(String, Character);
|
||||
}
|
||||
|
||||
char *api__strrchr(dev_t MajorID, const char *String, int Character)
|
||||
{
|
||||
dbg_api("%d, %s, %d", MajorID, String, Character);
|
||||
|
||||
stub;
|
||||
return nullptr;
|
||||
// return strrchr(String, Character);
|
||||
}
|
||||
|
||||
char *api__strstr(dev_t MajorID, const char *Haystack, const char *Needle)
|
||||
{
|
||||
dbg_api("%d, %s, %s", MajorID, Haystack, Needle);
|
||||
|
||||
return strstr(Haystack, Needle);
|
||||
}
|
||||
|
||||
/* --------- */
|
||||
|
||||
void PopulateDriverAPI(void *API)
|
||||
{
|
||||
__driverAPI *api = (__driverAPI *)API;
|
||||
|
||||
api->RegisterFunction = RegisterFunction;
|
||||
api->GetDriverInfo = GetDriverInfo;
|
||||
|
||||
api->RegisterInterruptHandler = RegisterInterruptHandler;
|
||||
api->OverrideInterruptHandler = OverrideInterruptHandler;
|
||||
api->UnregisterInterruptHandler = UnregisterInterruptHandler;
|
||||
api->UnregisterAllInterruptHandlers = UnregisterAllInterruptHandlers;
|
||||
|
||||
api->RegisterInputDevice = RegisterInputDevice;
|
||||
api->UnregisterInputDevice = UnregisterInputDevice;
|
||||
api->ReportKeyboardEvent = ReportKeyboardEvent;
|
||||
api->ReportRelativeMouseEvent = ReportRelativeMouseEvent;
|
||||
api->ReportAbsoluteMouseEvent = ReportAbsoluteMouseEvent;
|
||||
|
||||
api->RegisterBlockDevice = RegisterBlockDevice;
|
||||
api->UnregisterBlockDevice = UnregisterBlockDevice;
|
||||
|
||||
api->RegisterAudioDevice = RegisterAudioDevice;
|
||||
api->UnregisterAudioDevice = UnregisterAudioDevice;
|
||||
|
||||
api->RegisterNetDevice = RegisterNetDevice;
|
||||
api->UnregisterNetDevice = UnregisterNetDevice;
|
||||
api->ReportNetworkPacket = ReportNetworkPacket;
|
||||
|
||||
api->KPrint = d_KPrint;
|
||||
api->KernelLog = KernelLog;
|
||||
|
||||
api->RequestPages = RequestPages;
|
||||
api->FreePages = FreePages;
|
||||
|
||||
api->AppendMapFlag = AppendMapFlag;
|
||||
api->RemoveMapFlag = RemoveMapFlag;
|
||||
api->MapPages = MapPages;
|
||||
api->UnmapPages = UnmapPages;
|
||||
|
||||
api->CreateKernelProcess = CreateKernelProcess;
|
||||
api->CreateKernelThread = CreateKernelThread;
|
||||
api->KillProcess = KillProcess;
|
||||
api->KillThread = KillThread;
|
||||
api->Yield = Yield;
|
||||
api->Sleep = Sleep;
|
||||
|
||||
api->GetPCIDevices = GetPCIDevices;
|
||||
api->InitializePCI = InitializePCI;
|
||||
api->GetBAR = GetBAR;
|
||||
|
||||
api->memcpy = api__memcpy;
|
||||
api->memset = api__memset;
|
||||
api->memmove = api__memmove;
|
||||
api->memcmp = api__memcmp;
|
||||
api->strlen = api__strlen;
|
||||
api->strcpy = api__strcpy;
|
||||
api->strcat = api__strcat;
|
||||
api->strcmp = api__strcmp;
|
||||
api->strncmp = api__strncmp;
|
||||
api->strchr = api__strchr;
|
||||
api->strrchr = api__strrchr;
|
||||
api->strstr = api__strstr;
|
||||
}
|
||||
}
|
325
core/driver/devfile/master.cpp
Normal file
325
core/driver/devfile/master.cpp
Normal file
@ -0,0 +1,325 @@
|
||||
/*
|
||||
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 <memory.hpp>
|
||||
#include <ints.hpp>
|
||||
#include <task.hpp>
|
||||
#include <printf.h>
|
||||
#include <exec.hpp>
|
||||
#include <cwalk.h>
|
||||
#include <md5.h>
|
||||
|
||||
#include "../../../kernel.h"
|
||||
#include "../../../driver.h"
|
||||
|
||||
using namespace vfs;
|
||||
|
||||
namespace Driver
|
||||
{
|
||||
int MasterDeviceFile::open(int Flags, mode_t Mode)
|
||||
{
|
||||
switch (this->DeviceType)
|
||||
{
|
||||
default:
|
||||
if (this->SlavesMap.empty())
|
||||
return -ENOSYS;
|
||||
Slaves slave = this->SlavesMap.begin()->second;
|
||||
return slave->begin()->second->open(Flags, Mode);
|
||||
}
|
||||
}
|
||||
|
||||
int MasterDeviceFile::close()
|
||||
{
|
||||
switch (this->DeviceType)
|
||||
{
|
||||
default:
|
||||
if (this->SlavesMap.empty())
|
||||
return -ENOSYS;
|
||||
Slaves slave = this->SlavesMap.begin()->second;
|
||||
return slave->begin()->second->close();
|
||||
}
|
||||
}
|
||||
|
||||
size_t MasterDeviceFile::read(uint8_t *Buffer,
|
||||
size_t Size,
|
||||
off_t Offset)
|
||||
{
|
||||
switch (this->DeviceType)
|
||||
{
|
||||
case ddt_Keyboard:
|
||||
{
|
||||
while (KeyQueue.empty())
|
||||
TaskManager->Yield();
|
||||
|
||||
/* Request scancode */
|
||||
if (Size == 2 && Buffer[1] == 0x00)
|
||||
{
|
||||
if (RawKeyQueue.empty())
|
||||
return 0;
|
||||
|
||||
Buffer[0] = RawKeyQueue.front();
|
||||
RawKeyQueue.pop_front();
|
||||
return 1;
|
||||
}
|
||||
|
||||
Buffer[0] = KeyQueue.front();
|
||||
KeyQueue.pop_front();
|
||||
return 1;
|
||||
}
|
||||
default:
|
||||
if (this->SlavesMap.empty())
|
||||
return 0;
|
||||
Slaves slave = this->SlavesMap.begin()->second;
|
||||
return slave->begin()->second->read(Buffer, Size, Offset);
|
||||
}
|
||||
}
|
||||
|
||||
size_t MasterDeviceFile::write(uint8_t *Buffer,
|
||||
size_t Size,
|
||||
off_t Offset)
|
||||
{
|
||||
switch (this->DeviceType)
|
||||
{
|
||||
default:
|
||||
if (this->SlavesMap.empty())
|
||||
return 0;
|
||||
Slaves slave = this->SlavesMap.begin()->second;
|
||||
return slave->begin()->second->write(Buffer, Size, Offset);
|
||||
}
|
||||
}
|
||||
|
||||
int MasterDeviceFile::ioctl(unsigned long Request,
|
||||
void *Argp)
|
||||
{
|
||||
switch (this->DeviceType)
|
||||
{
|
||||
default:
|
||||
if (this->SlavesMap.empty())
|
||||
return -ENOSYS;
|
||||
Slaves slave = this->SlavesMap.begin()->second;
|
||||
return slave->begin()->second->ioctl(Request, Argp);
|
||||
}
|
||||
}
|
||||
|
||||
void MasterDeviceFile::ClearBuffers()
|
||||
{
|
||||
this->RawKeyQueue.clear();
|
||||
this->KeyQueue.clear();
|
||||
/* ... */
|
||||
|
||||
foreach (auto &sm in this->SlavesMap)
|
||||
{
|
||||
Slaves slave = sm.second;
|
||||
foreach (auto &sdf in *slave)
|
||||
sdf.second->ClearBuffers();
|
||||
}
|
||||
}
|
||||
|
||||
int MasterDeviceFile::ReportKeyEvent(maj_t ID, min_t MinorID, uint8_t ScanCode)
|
||||
{
|
||||
debug("New key event: %02x", ScanCode);
|
||||
if (this->SlavesMap.find(ID) == this->SlavesMap.end())
|
||||
return -EINVAL;
|
||||
|
||||
std::unordered_map<min_t, SlaveDeviceFile *> *slave = this->SlavesMap[ID];
|
||||
if ((*slave).find(MinorID) == (*slave).end())
|
||||
return -EINVAL;
|
||||
|
||||
/* We are master, keep a copy of the scancode and
|
||||
converted key */
|
||||
|
||||
if (RawKeyQueue.size() > 16)
|
||||
RawKeyQueue.pop_front();
|
||||
RawKeyQueue.push_back(ScanCode);
|
||||
|
||||
if (KeyQueue.size() > 16)
|
||||
KeyQueue.pop_front();
|
||||
|
||||
switch (ScanCode & ~KEY_PRESSED)
|
||||
{
|
||||
case KEY_LEFT_SHIFT:
|
||||
case KEY_RIGHT_SHIFT:
|
||||
{
|
||||
if (ScanCode & KEY_PRESSED)
|
||||
UpperCase = true;
|
||||
else
|
||||
UpperCase = false;
|
||||
break;
|
||||
}
|
||||
case KEY_CAPS_LOCK:
|
||||
{
|
||||
if (ScanCode & KEY_PRESSED)
|
||||
CapsLock = !CapsLock;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
KeyQueue.push_back(GetScanCode(ScanCode, UpperCase || CapsLock));
|
||||
|
||||
SlaveDeviceFile *sdf = (*slave)[MinorID];
|
||||
return sdf->ReportKeyEvent(ScanCode);
|
||||
}
|
||||
|
||||
int MasterDeviceFile::ReportMouseEvent(maj_t ID, min_t MinorID,
|
||||
bool LeftButton, bool RightButton, bool MiddleButton,
|
||||
bool Button4, bool Button5, bool Button6, bool Button7, bool Button8,
|
||||
uintptr_t X, uintptr_t Y, int8_t Z, bool Relative)
|
||||
{
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
int MasterDeviceFile::ReportNetworkPacket(maj_t ID, min_t MinorID, void *Buffer, size_t Size)
|
||||
{
|
||||
/* TODO: Buffer must be allocated by the kernel */
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
int MasterDeviceFile::NewBlock(maj_t ID, min_t MinorID, drvOpen_t Open, drvClose_t Close,
|
||||
drvRead_t Read, drvWrite_t Write, drvIoctl_t Ioctl)
|
||||
{
|
||||
assert(this->SlavesMap.find(ID) != this->SlavesMap.end());
|
||||
Slaves slave = this->SlavesMap[ID];
|
||||
assert((*slave).find(MinorID) != (*slave).end());
|
||||
SlaveDeviceFile *sdf = (*slave)[MinorID];
|
||||
sdf->Open = Open;
|
||||
sdf->Close = Close;
|
||||
sdf->Read = Read;
|
||||
sdf->Write = Write;
|
||||
sdf->Ioctl = Ioctl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int MasterDeviceFile::NewAudio(maj_t ID, min_t MinorID, drvOpen_t Open, drvClose_t Close,
|
||||
drvRead_t Read, drvWrite_t Write, drvIoctl_t Ioctl)
|
||||
{
|
||||
assert(this->SlavesMap.find(ID) != this->SlavesMap.end());
|
||||
Slaves slave = this->SlavesMap[ID];
|
||||
assert((*slave).find(MinorID) != (*slave).end());
|
||||
SlaveDeviceFile *sdf = (*slave)[MinorID];
|
||||
sdf->Open = Open;
|
||||
sdf->Close = Close;
|
||||
sdf->Read = Read;
|
||||
sdf->Write = Write;
|
||||
sdf->Ioctl = Ioctl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int MasterDeviceFile::NewNet(maj_t ID, min_t MinorID, drvOpen_t Open, drvClose_t Close,
|
||||
drvRead_t Read, drvWrite_t Write, drvIoctl_t Ioctl)
|
||||
{
|
||||
assert(this->SlavesMap.find(ID) != this->SlavesMap.end());
|
||||
Slaves slave = this->SlavesMap[ID];
|
||||
assert((*slave).find(MinorID) != (*slave).end());
|
||||
SlaveDeviceFile *sdf = (*slave)[MinorID];
|
||||
sdf->Open = Open;
|
||||
sdf->Close = Close;
|
||||
sdf->Read = Read;
|
||||
sdf->Write = Write;
|
||||
sdf->Ioctl = Ioctl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
dev_t MasterDeviceFile::Register(maj_t ID)
|
||||
{
|
||||
debug("Registering slave device %d", ID);
|
||||
Slaves slave;
|
||||
if (this->SlavesMap.find(ID) != this->SlavesMap.end())
|
||||
slave = this->SlavesMap[ID];
|
||||
else
|
||||
slave = new std::unordered_map<min_t, SlaveDeviceFile *>();
|
||||
|
||||
char name[24];
|
||||
sprintf(name, "%s%ld", this->SlaveName, this->SlaveIDCounter);
|
||||
SlaveDeviceFile *sdf = new SlaveDeviceFile(name,
|
||||
this->SlaveParent,
|
||||
this->DeviceType,
|
||||
this->Type);
|
||||
|
||||
sdf->DeviceMajor = ID;
|
||||
sdf->DeviceMinor = this->SlaveIDCounter;
|
||||
|
||||
(*slave)[this->SlaveIDCounter] = sdf;
|
||||
this->SlavesMap[ID] = slave;
|
||||
return this->SlaveIDCounter++;
|
||||
}
|
||||
|
||||
int MasterDeviceFile::Unregister(maj_t ID, min_t MinorID)
|
||||
{
|
||||
debug("Unregistering slave device %d:%d", ID, MinorID);
|
||||
if (this->SlavesMap.find(ID) == this->SlavesMap.end())
|
||||
return -EINVAL;
|
||||
|
||||
std::unordered_map<min_t, SlaveDeviceFile *> *slave = this->SlavesMap[ID];
|
||||
if ((*slave).find(MinorID) == (*slave).end())
|
||||
return -EINVAL;
|
||||
|
||||
SlaveDeviceFile *sdf = (*slave)[MinorID];
|
||||
delete sdf;
|
||||
slave->erase(MinorID);
|
||||
if (slave->empty())
|
||||
{
|
||||
delete slave;
|
||||
this->SlavesMap.erase(ID);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
MasterDeviceFile::MasterDeviceFile(const char *MasterName,
|
||||
const char *_SlaveName,
|
||||
Node *Parent,
|
||||
int Type)
|
||||
: Node(Parent, MasterName, NodeType::FILE)
|
||||
{
|
||||
strncpy(this->SlaveName, _SlaveName, sizeof(this->Name));
|
||||
this->DeviceType = Type;
|
||||
this->SlaveParent = Parent;
|
||||
|
||||
switch (Type)
|
||||
{
|
||||
case ddt_Keyboard:
|
||||
case ddt_Mouse:
|
||||
case ddt_Joystick:
|
||||
case ddt_Gamepad:
|
||||
case ddt_Touchpad:
|
||||
case ddt_Touchscreen:
|
||||
this->Type = NodeType::CHARDEVICE;
|
||||
break;
|
||||
case ddt_SATA:
|
||||
case ddt_ATA:
|
||||
case ddt_NVMe:
|
||||
this->Type = NodeType::BLOCKDEVICE;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
MasterDeviceFile::~MasterDeviceFile()
|
||||
{
|
||||
foreach (auto &sm in this->SlavesMap)
|
||||
{
|
||||
Slaves slave = sm.second;
|
||||
foreach (auto &sdf in *slave)
|
||||
delete sdf.second;
|
||||
delete slave;
|
||||
}
|
||||
this->SlavesMap.clear();
|
||||
}
|
||||
}
|
131
core/driver/devfile/slave.cpp
Normal file
131
core/driver/devfile/slave.cpp
Normal file
@ -0,0 +1,131 @@
|
||||
/*
|
||||
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 <memory.hpp>
|
||||
#include <ints.hpp>
|
||||
#include <task.hpp>
|
||||
#include <printf.h>
|
||||
#include <exec.hpp>
|
||||
#include <cwalk.h>
|
||||
#include <md5.h>
|
||||
|
||||
#include "../../../kernel.h"
|
||||
#include "../../../driver.h"
|
||||
|
||||
using namespace vfs;
|
||||
|
||||
namespace Driver
|
||||
{
|
||||
int SlaveDeviceFile::open(int Flags, mode_t Mode)
|
||||
{
|
||||
switch (this->DeviceType)
|
||||
{
|
||||
default:
|
||||
if (this->Open)
|
||||
return this->Open(this->DeviceMajor, this->DeviceMinor,
|
||||
Flags, Mode);
|
||||
return -ENOSYS;
|
||||
}
|
||||
}
|
||||
|
||||
int SlaveDeviceFile::close()
|
||||
{
|
||||
switch (this->DeviceType)
|
||||
{
|
||||
default:
|
||||
if (this->Close)
|
||||
return this->Close(this->DeviceMajor, this->DeviceMinor);
|
||||
return -ENOSYS;
|
||||
}
|
||||
}
|
||||
|
||||
size_t SlaveDeviceFile::read(uint8_t *Buffer,
|
||||
size_t Size,
|
||||
off_t Offset)
|
||||
{
|
||||
switch (this->DeviceType)
|
||||
{
|
||||
case ddt_Keyboard:
|
||||
{
|
||||
while (KeyQueue.empty())
|
||||
TaskManager->Yield();
|
||||
|
||||
Buffer[0] = KeyQueue.front();
|
||||
KeyQueue.pop_front();
|
||||
return 1;
|
||||
}
|
||||
default:
|
||||
if (this->Read)
|
||||
return this->Read(this->DeviceMajor, this->DeviceMinor,
|
||||
Buffer, Size, Offset);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
size_t SlaveDeviceFile::write(uint8_t *Buffer,
|
||||
size_t Size,
|
||||
off_t Offset)
|
||||
{
|
||||
switch (this->DeviceType)
|
||||
{
|
||||
default:
|
||||
if (this->Write)
|
||||
return this->Write(this->DeviceMajor, this->DeviceMinor,
|
||||
Buffer, Size, Offset);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int SlaveDeviceFile::ioctl(unsigned long Request,
|
||||
void *Argp)
|
||||
{
|
||||
switch (this->DeviceType)
|
||||
{
|
||||
default:
|
||||
if (this->Ioctl)
|
||||
return this->Ioctl(this->DeviceMajor, this->DeviceMinor,
|
||||
Request, Argp);
|
||||
return -ENOSYS;
|
||||
}
|
||||
}
|
||||
|
||||
void SlaveDeviceFile::ClearBuffers()
|
||||
{
|
||||
KeyQueue.clear();
|
||||
/* ... */
|
||||
}
|
||||
|
||||
int SlaveDeviceFile::ReportKeyEvent(uint8_t ScanCode)
|
||||
{
|
||||
if (KeyQueue.size() > 16)
|
||||
KeyQueue.pop_front();
|
||||
KeyQueue.push_back(ScanCode);
|
||||
return 0;
|
||||
}
|
||||
|
||||
SlaveDeviceFile::SlaveDeviceFile(const char *Name, vfs::Node *Parent, int Type, vfs::NodeType NType)
|
||||
: Node(Parent, Name, NType)
|
||||
{
|
||||
this->DeviceType = Type;
|
||||
}
|
||||
|
||||
SlaveDeviceFile::~SlaveDeviceFile()
|
||||
{
|
||||
}
|
||||
}
|
582
core/driver/driver.cpp
Normal file
582
core/driver/driver.cpp
Normal file
@ -0,0 +1,582 @@
|
||||
/*
|
||||
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 <memory.hpp>
|
||||
#include <ints.hpp>
|
||||
#include <task.hpp>
|
||||
#include <printf.h>
|
||||
#include <exec.hpp>
|
||||
#include <cwalk.h>
|
||||
#include <md5.h>
|
||||
|
||||
#include "../../kernel.h"
|
||||
#include "../../driver.h"
|
||||
|
||||
using namespace vfs;
|
||||
|
||||
namespace Driver
|
||||
{
|
||||
void Manager::LoadAllDrivers()
|
||||
{
|
||||
foreach (auto &var in Drivers)
|
||||
{
|
||||
DriverObject *Drv = &var.second;
|
||||
size_t dapiPgs = TO_PAGES(sizeof(__driverAPI));
|
||||
__driverAPI *dApi = (__driverAPI *)Drv->vma->RequestPages(dapiPgs);
|
||||
debug("Driver API at %#lx-%#lx", dApi, dApi + sizeof(__driverAPI));
|
||||
|
||||
fixme("api version");
|
||||
dApi->APIVersion.Major = 0;
|
||||
dApi->APIVersion.Minor = 0;
|
||||
dApi->APIVersion.Patch = 0;
|
||||
|
||||
dApi->MajorID = var.first;
|
||||
dApi->Base = Drv->BaseAddress;
|
||||
PopulateDriverAPI(dApi);
|
||||
|
||||
debug("Calling driver %s at %#lx", Drv->Path, Drv->EntryPoint);
|
||||
int (*DrvInit)(__driverAPI *) = (int (*)(__driverAPI *))Drv->EntryPoint;
|
||||
Drv->ErrorCode = DrvInit(dApi);
|
||||
if (Drv->ErrorCode < 0)
|
||||
{
|
||||
KPrint("FATAL: _start() failed for %s: %s",
|
||||
Drv->Name, strerror(Drv->ErrorCode));
|
||||
error("Failed to load driver %s: %s",
|
||||
Drv->Path, strerror(Drv->ErrorCode));
|
||||
|
||||
Drv->vma->FreeAllPages();
|
||||
continue;
|
||||
}
|
||||
|
||||
KPrint("Loading driver %s", Drv->Name);
|
||||
|
||||
debug("Calling Probe()=%#lx on driver %s",
|
||||
Drv->Probe, Drv->Path);
|
||||
Drv->ErrorCode = Drv->Probe();
|
||||
if (Drv->ErrorCode < 0)
|
||||
{
|
||||
KPrint("Probe() failed for %s: %s",
|
||||
Drv->Name, strerror(Drv->ErrorCode));
|
||||
error("Failed to probe driver %s: %s",
|
||||
Drv->Path, strerror(Drv->ErrorCode));
|
||||
|
||||
Drv->vma->FreeAllPages();
|
||||
continue;
|
||||
}
|
||||
|
||||
debug("Calling driver Entry()=%#lx function on driver %s",
|
||||
Drv->Entry, Drv->Path);
|
||||
Drv->ErrorCode = Drv->Entry();
|
||||
if (Drv->ErrorCode < 0)
|
||||
{
|
||||
KPrint("Entry() failed for %s: %s",
|
||||
Drv->Name, strerror(Drv->ErrorCode));
|
||||
error("Failed to initialize driver %s: %s",
|
||||
Drv->Path, strerror(Drv->ErrorCode));
|
||||
|
||||
Drv->vma->FreeAllPages();
|
||||
continue;
|
||||
}
|
||||
|
||||
debug("Loaded driver %s", Drv->Path);
|
||||
Drv->Initialized = true;
|
||||
}
|
||||
|
||||
InputMouseDev->ClearBuffers();
|
||||
InputKeyboardDev->ClearBuffers();
|
||||
|
||||
BlockSATADev->ClearBuffers();
|
||||
BlockHDDev->ClearBuffers();
|
||||
BlockNVMeDev->ClearBuffers();
|
||||
|
||||
AudioDev->ClearBuffers();
|
||||
|
||||
NetDev->ClearBuffers();
|
||||
/* ... */
|
||||
}
|
||||
|
||||
void Manager::UnloadAllDrivers()
|
||||
{
|
||||
foreach (auto &var in Drivers)
|
||||
{
|
||||
DriverObject *Drv = &var.second;
|
||||
if (!Drv->Initialized)
|
||||
continue;
|
||||
|
||||
debug("Unloading driver %s", Drv->Name);
|
||||
int err = Drv->Final();
|
||||
if (err < 0)
|
||||
{
|
||||
warn("Failed to unload driver %s: %s",
|
||||
Drv->Name, strerror(err));
|
||||
}
|
||||
|
||||
if (!Drv->InterruptHandlers->empty())
|
||||
{
|
||||
foreach (auto &rInt in * Drv->InterruptHandlers)
|
||||
{
|
||||
Interrupts::RemoveHandler((void (*)(CPU::TrapFrame *))rInt.second);
|
||||
}
|
||||
Drv->InterruptHandlers->clear();
|
||||
}
|
||||
|
||||
delete Drv->vma, Drv->vma = nullptr;
|
||||
delete Drv->InterruptHandlers, Drv->InterruptHandlers = nullptr;
|
||||
}
|
||||
Drivers.clear();
|
||||
}
|
||||
|
||||
void Manager::Panic()
|
||||
{
|
||||
Memory::Virtual vmm;
|
||||
foreach (auto Driver in Drivers)
|
||||
{
|
||||
if (!Driver.second.Initialized)
|
||||
continue;
|
||||
|
||||
trace("Panic on driver %s", Driver.second.Name);
|
||||
debug("%#lx", Driver.second.Panic);
|
||||
|
||||
/* Crash while probing? */
|
||||
if (Driver.second.Panic && vmm.Check((void *)Driver.second.Panic))
|
||||
Driver.second.Panic();
|
||||
else
|
||||
error("No panic function for driver %s",
|
||||
Driver.second.Name);
|
||||
}
|
||||
}
|
||||
|
||||
int Manager::LoadDriverFile(uintptr_t &EntryPoint,
|
||||
uintptr_t &BaseAddress,
|
||||
Memory::VirtualMemoryArea *dVma,
|
||||
RefNode *rDrv)
|
||||
{
|
||||
Elf64_Ehdr ELFHeader;
|
||||
rDrv->seek(0, SEEK_SET);
|
||||
rDrv->read((uint8_t *)&ELFHeader, sizeof(Elf64_Ehdr));
|
||||
if (ELFHeader.e_type != ET_DYN)
|
||||
{
|
||||
error("Driver %s is not a shared object", rDrv->node->FullPath);
|
||||
return -ENOEXEC;
|
||||
}
|
||||
|
||||
trace("Loading driver %s in memory", rDrv->node->Name);
|
||||
|
||||
BaseAddress = 0;
|
||||
{
|
||||
Elf64_Phdr ProgramBreakHeader{};
|
||||
Elf64_Phdr ProgramHeader;
|
||||
|
||||
size_t SegmentsSize = 0;
|
||||
for (Elf64_Half i = 0; i < ELFHeader.e_phnum; i++)
|
||||
{
|
||||
rDrv->seek(ELFHeader.e_phoff + (i * sizeof(Elf64_Phdr)), SEEK_SET);
|
||||
rDrv->read((uint8_t *)&ProgramHeader, sizeof(Elf64_Phdr));
|
||||
|
||||
if (ProgramHeader.p_type == PT_LOAD ||
|
||||
ProgramHeader.p_type == PT_DYNAMIC)
|
||||
{
|
||||
if (SegmentsSize < ProgramHeader.p_vaddr + ProgramHeader.p_memsz)
|
||||
{
|
||||
SegmentsSize = ProgramHeader.p_vaddr + ProgramHeader.p_memsz;
|
||||
ProgramBreakHeader = ProgramHeader;
|
||||
}
|
||||
}
|
||||
}
|
||||
debug("SegmentsSize: %#lx", SegmentsSize);
|
||||
|
||||
/* TODO: Check if this is correct and/or it needs more
|
||||
complex calculations & allocations */
|
||||
void *SegmentsAddress = dVma->RequestPages(TO_PAGES(SegmentsSize) + 1, true);
|
||||
BaseAddress = (uintptr_t)SegmentsAddress;
|
||||
debug("BaseAddress: %#lx, End: %#lx (%#lx)", BaseAddress,
|
||||
BaseAddress + FROM_PAGES(TO_PAGES(SegmentsSize)),
|
||||
SegmentsSize);
|
||||
|
||||
for (Elf64_Half i = 0; i < ELFHeader.e_phnum; i++)
|
||||
{
|
||||
rDrv->seek(ELFHeader.e_phoff + (i * sizeof(Elf64_Phdr)), SEEK_SET);
|
||||
rDrv->read((uint8_t *)&ProgramHeader, sizeof(Elf64_Phdr));
|
||||
|
||||
switch (ProgramHeader.p_type)
|
||||
{
|
||||
case PT_LOAD:
|
||||
{
|
||||
/* Because this is ET_DYN, we can load the segments
|
||||
anywhere we want. */
|
||||
uintptr_t SegmentDestination = BaseAddress + ProgramHeader.p_vaddr;
|
||||
|
||||
if (ProgramHeader.p_memsz == 0)
|
||||
continue;
|
||||
|
||||
debug("Copying PT_LOAD to %#lx-%#lx (%ld file bytes, %ld mem bytes)",
|
||||
SegmentDestination, SegmentDestination + ProgramHeader.p_memsz,
|
||||
ProgramHeader.p_filesz, ProgramHeader.p_memsz);
|
||||
|
||||
if (ProgramHeader.p_filesz > 0)
|
||||
{
|
||||
rDrv->seek(ProgramHeader.p_offset, SEEK_SET);
|
||||
rDrv->read((uint8_t *)SegmentDestination, ProgramHeader.p_filesz);
|
||||
}
|
||||
|
||||
if (ProgramHeader.p_memsz - ProgramHeader.p_filesz > 0)
|
||||
{
|
||||
void *zAddr = (void *)(SegmentDestination + ProgramHeader.p_filesz);
|
||||
memset(zAddr, 0, ProgramHeader.p_memsz - ProgramHeader.p_filesz);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case PT_DYNAMIC:
|
||||
{
|
||||
/* PT_DYNAMIC contains the dynamic linking information for the
|
||||
executable or shared library. */
|
||||
|
||||
uintptr_t DynamicSegmentDestination = BaseAddress + ProgramHeader.p_vaddr;
|
||||
|
||||
if (ProgramHeader.p_memsz == 0)
|
||||
continue;
|
||||
|
||||
debug("Copying PT_DYNAMIC to %#lx-%#lx (%ld file bytes, %ld mem bytes)",
|
||||
DynamicSegmentDestination, DynamicSegmentDestination + ProgramHeader.p_memsz,
|
||||
ProgramHeader.p_filesz, ProgramHeader.p_memsz);
|
||||
|
||||
if (ProgramHeader.p_filesz > 0)
|
||||
{
|
||||
rDrv->seek(ProgramHeader.p_offset, SEEK_SET);
|
||||
rDrv->read((uint8_t *)DynamicSegmentDestination, ProgramHeader.p_filesz);
|
||||
}
|
||||
|
||||
if (ProgramHeader.p_memsz - ProgramHeader.p_filesz > 0)
|
||||
{
|
||||
void *zAddr = (void *)(DynamicSegmentDestination + ProgramHeader.p_filesz);
|
||||
memset(zAddr, 0, ProgramHeader.p_memsz - ProgramHeader.p_filesz);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
fixme("Unhandled program header type: %#lx",
|
||||
ProgramHeader.p_type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Elf64_Phdr ProgramHeader;
|
||||
for (Elf64_Half i = 0; i < ELFHeader.e_phnum; i++)
|
||||
{
|
||||
rDrv->seek(ELFHeader.e_phoff + (i * sizeof(Elf64_Phdr)), SEEK_SET);
|
||||
rDrv->read((uint8_t *)&ProgramHeader, sizeof(Elf64_Phdr));
|
||||
|
||||
if (ProgramHeader.p_type == PT_DYNAMIC)
|
||||
{
|
||||
Elf64_Dyn *Dynamic = (Elf64_Dyn *)(BaseAddress + ProgramHeader.p_vaddr);
|
||||
Elf64_Dyn *RelaSize = nullptr;
|
||||
Elf64_Dyn *PltRelSize = nullptr;
|
||||
|
||||
while (Dynamic->d_tag != DT_NULL)
|
||||
{
|
||||
switch (Dynamic->d_tag)
|
||||
{
|
||||
case DT_RELASZ:
|
||||
RelaSize = Dynamic;
|
||||
debug("RELA Size: %d", RelaSize->d_un.d_val / sizeof(Elf64_Rela));
|
||||
|
||||
break;
|
||||
case DT_PLTRELSZ:
|
||||
PltRelSize = Dynamic;
|
||||
debug("PLTRELSZ: %d", PltRelSize->d_un.d_val / sizeof(Elf64_Rela));
|
||||
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
Dynamic++;
|
||||
}
|
||||
Dynamic = (Elf64_Dyn *)(BaseAddress + ProgramHeader.p_vaddr);
|
||||
|
||||
while (Dynamic->d_tag != DT_NULL)
|
||||
{
|
||||
switch (Dynamic->d_tag)
|
||||
{
|
||||
case DT_RELA: /* .rela.dyn */
|
||||
{
|
||||
if (!RelaSize)
|
||||
{
|
||||
error("DT_RELASZ is not set");
|
||||
break;
|
||||
}
|
||||
|
||||
Elf64_Rela *Rela = (Elf64_Rela *)(BaseAddress + Dynamic->d_un.d_ptr);
|
||||
for (size_t i = 0; i < (RelaSize->d_un.d_val / sizeof(Elf64_Rela)); i++)
|
||||
{
|
||||
Elf64_Rela *r = &Rela[i];
|
||||
uintptr_t *RelocationAddress = (uintptr_t *)(BaseAddress + r->r_offset);
|
||||
uintptr_t RelocationTarget = 0;
|
||||
|
||||
switch (ELF64_R_TYPE(r->r_info))
|
||||
{
|
||||
case R_X86_64_GLOB_DAT:
|
||||
case R_X86_64_JUMP_SLOT:
|
||||
{
|
||||
RelocationTarget = BaseAddress;
|
||||
break;
|
||||
}
|
||||
case R_X86_64_RELATIVE:
|
||||
case R_X86_64_64:
|
||||
{
|
||||
RelocationTarget = BaseAddress + r->r_addend;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
fixme("Unhandled relocation type: %#lx",
|
||||
ELF64_R_TYPE(r->r_info));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
*RelocationAddress = RelocationTarget;
|
||||
|
||||
debug("Relocated %#lx to %#lx",
|
||||
r->r_offset, *RelocationAddress);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DT_PLTREL:
|
||||
{
|
||||
if (Dynamic->d_un.d_val != DT_RELA)
|
||||
error("DT_PLTREL is not DT_RELA");
|
||||
break;
|
||||
}
|
||||
case DT_JMPREL: /* .rela.plt */
|
||||
{
|
||||
if (!PltRelSize)
|
||||
{
|
||||
error("DT_PLTRELSZ is not set");
|
||||
break;
|
||||
}
|
||||
|
||||
int fd = fopen(rDrv->node->FullPath, "r");
|
||||
|
||||
std::vector<Elf64_Dyn> SymTab = Execute::ELFGetDynamicTag_x86_64(fd, DT_SYMTAB);
|
||||
std::vector<Elf64_Dyn> StrTab = Execute::ELFGetDynamicTag_x86_64(fd, DT_STRTAB);
|
||||
Elf64_Sym *_SymTab = (Elf64_Sym *)((uintptr_t)BaseAddress + SymTab[0].d_un.d_ptr);
|
||||
char *DynStr = (char *)((uintptr_t)BaseAddress + StrTab[0].d_un.d_ptr);
|
||||
UNUSED(DynStr);
|
||||
fclose(fd);
|
||||
|
||||
Elf64_Rela *Rela = (Elf64_Rela *)(BaseAddress + Dynamic->d_un.d_ptr);
|
||||
for (size_t i = 0; i < (PltRelSize->d_un.d_val / sizeof(Elf64_Rela)); i++)
|
||||
{
|
||||
Elf64_Rela *r = &Rela[i];
|
||||
uintptr_t *RelocationAddress = (uintptr_t *)(BaseAddress + r->r_offset);
|
||||
uintptr_t RelocationTarget = 0;
|
||||
|
||||
switch (ELF64_R_TYPE(r->r_info))
|
||||
{
|
||||
case R_X86_64_JUMP_SLOT:
|
||||
{
|
||||
Elf64_Xword SymIndex = ELF64_R_SYM(r->r_info);
|
||||
Elf64_Sym *Sym = _SymTab + SymIndex;
|
||||
|
||||
#ifdef DEBUG
|
||||
const char *SymbolName = DynStr + Sym->st_name;
|
||||
debug("Symbol %s at %#lx", SymbolName, Sym->st_value);
|
||||
#endif
|
||||
|
||||
RelocationTarget = BaseAddress + Sym->st_value;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
fixme("Unhandled relocation type: %#lx",
|
||||
ELF64_R_TYPE(r->r_info));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
*RelocationAddress = RelocationTarget;
|
||||
|
||||
debug("Relocated %#lx to %#lx",
|
||||
r->r_offset, *RelocationAddress);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DT_SYMTAB:
|
||||
{
|
||||
fixme("DT_SYMTAB");
|
||||
break;
|
||||
int fd = fopen(rDrv->node->FullPath, "r");
|
||||
|
||||
std::vector<Elf64_Dyn> SymTab = Execute::ELFGetDynamicTag_x86_64(fd, DT_SYMTAB);
|
||||
std::vector<Elf64_Dyn> StrTab = Execute::ELFGetDynamicTag_x86_64(fd, DT_STRTAB);
|
||||
Elf64_Sym *_SymTab = (Elf64_Sym *)((uintptr_t)BaseAddress + SymTab[0].d_un.d_ptr);
|
||||
char *DynStr = (char *)((uintptr_t)BaseAddress + StrTab[0].d_un.d_ptr);
|
||||
UNUSED(DynStr);
|
||||
fclose(fd);
|
||||
|
||||
size_t symtabEntrySize = 0;
|
||||
Elf64_Dyn *entrySizeDyn = Dynamic;
|
||||
while (entrySizeDyn->d_tag != DT_NULL)
|
||||
{
|
||||
if (entrySizeDyn->d_tag == DT_SYMENT)
|
||||
{
|
||||
symtabEntrySize = entrySizeDyn->d_un.d_val;
|
||||
break;
|
||||
}
|
||||
entrySizeDyn++;
|
||||
}
|
||||
|
||||
if (symtabEntrySize == 0)
|
||||
{
|
||||
fixme("No information about symbol entry size");
|
||||
break;
|
||||
}
|
||||
|
||||
size_t numSymbols = Dynamic->d_un.d_val / symtabEntrySize;
|
||||
|
||||
for (size_t i = 0; i < numSymbols; i++)
|
||||
{
|
||||
Elf64_Sym *s = &_SymTab[i];
|
||||
if (s->st_name == 0)
|
||||
continue;
|
||||
|
||||
#ifdef DEBUG
|
||||
const char *SymbolName = (const char *)(DynStr + s->st_name);
|
||||
debug("%d: Symbol %s at %#lx", i, SymbolName, s->st_value);
|
||||
#endif
|
||||
/** TODO: search for symbols and link */
|
||||
/** good use but it will not work only
|
||||
* if we specify to default visibility but
|
||||
* this will create more issues :/ */
|
||||
// if (strcmp(SymbolName, "DriverProbe") == 0)
|
||||
// {
|
||||
// Drivers[MajorIDCounter].Probe = (int (*)())(BaseAddress + s->st_value);
|
||||
// debug("Found probe function at %#lx", Drivers[MajorIDCounter].Probe);
|
||||
// }
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
fixme("Unhandled dynamic tag: %#lx",
|
||||
Dynamic->d_tag);
|
||||
break;
|
||||
}
|
||||
}
|
||||
Dynamic++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
EntryPoint = ELFHeader.e_entry;
|
||||
EntryPoint += BaseAddress;
|
||||
|
||||
debug("Driver %s has entry point %#lx and base %#lx",
|
||||
rDrv->node->FullPath, EntryPoint, BaseAddress);
|
||||
|
||||
/* FIXME: Do not add to the KernelSymbolTable! */
|
||||
// Memory::SmartHeap sh(rDrv->Size);
|
||||
// rDrv->seek(0, SEEK_SET);
|
||||
// rDrv->read((uint8_t *)sh.Get(), rDrv->Size);
|
||||
// KernelSymbolTable->AppendSymbols((uintptr_t)sh.Get(), BaseAddress);
|
||||
return 0;
|
||||
}
|
||||
|
||||
Manager::Manager()
|
||||
{
|
||||
debug("Initializing driver manager");
|
||||
const char *DriverDirectory = Config.DriverDirectory;
|
||||
RefNode *rn = fs->Open(DriverDirectory);
|
||||
if (!rn)
|
||||
{
|
||||
error("Failed to open driver directory %s", DriverDirectory);
|
||||
KPrint("Failed to open driver directory %s", DriverDirectory);
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (auto drvNode in rn->node->Children)
|
||||
{
|
||||
if (drvNode->Type != vfs::FILE)
|
||||
continue;
|
||||
|
||||
if (Execute::GetBinaryType(drvNode->FullPath) != Execute::BinTypeELF)
|
||||
{
|
||||
error("Driver %s is not an ELF binary", drvNode->FullPath);
|
||||
continue;
|
||||
}
|
||||
|
||||
RefNode *rDrv = drvNode->CreateReference();
|
||||
|
||||
Memory::VirtualMemoryArea *dVma =
|
||||
new Memory::VirtualMemoryArea(thisProcess->PageTable);
|
||||
|
||||
uintptr_t EntryPoint, BaseAddress;
|
||||
int err = this->LoadDriverFile(EntryPoint, BaseAddress, dVma, rDrv);
|
||||
debug("err = %d (%s)", err, strerror(err));
|
||||
if (err != 0)
|
||||
{
|
||||
error("Failed to load driver %s: %s",
|
||||
drvNode->FullPath, strerror(err));
|
||||
|
||||
delete rDrv;
|
||||
delete dVma;
|
||||
continue;
|
||||
}
|
||||
delete rDrv;
|
||||
|
||||
Drivers[MajorIDCounter++] = {
|
||||
.BaseAddress = BaseAddress,
|
||||
.EntryPoint = EntryPoint,
|
||||
.vma = dVma,
|
||||
.Path = drvNode->FullPath,
|
||||
.InterruptHandlers = new std::unordered_map<uint8_t, void *>};
|
||||
|
||||
dev_t countr = MajorIDCounter - 1;
|
||||
const char *drvName;
|
||||
size_t drvNameLen;
|
||||
cwk_path_get_basename(drvNode->FullPath, &drvName, &drvNameLen);
|
||||
strncpy(Drivers[countr].Name, drvName, sizeof(Drivers[countr].Name));
|
||||
}
|
||||
|
||||
delete rn;
|
||||
|
||||
InputMouseDev = new MasterDeviceFile("mice", "mouse", DevFS, ddt_Mouse);
|
||||
InputKeyboardDev = new MasterDeviceFile("key", "kbd", DevFS, ddt_Keyboard);
|
||||
|
||||
BlockSATADev = new MasterDeviceFile("sd", "sd", DevFS, ddt_SATA);
|
||||
BlockHDDev = new MasterDeviceFile("hd", "hd", DevFS, ddt_ATA);
|
||||
BlockNVMeDev = new MasterDeviceFile("nvme", "nvme", DevFS, ddt_NVMe);
|
||||
|
||||
AudioDev = new MasterDeviceFile("audio", "snd", DevFS, ddt_Audio);
|
||||
|
||||
NetDev = new MasterDeviceFile("network", "net", DevFS, ddt_Network);
|
||||
}
|
||||
|
||||
Manager::~Manager()
|
||||
{
|
||||
debug("Unloading drivers");
|
||||
UnloadAllDrivers();
|
||||
delete InputMouseDev;
|
||||
delete InputKeyboardDev;
|
||||
}
|
||||
}
|
369
core/driver/scancode.cpp
Normal file
369
core/driver/scancode.cpp
Normal file
@ -0,0 +1,369 @@
|
||||
/*
|
||||
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 "../../driver.h"
|
||||
|
||||
static char ScanCodeConversionTableLower[] = {
|
||||
[KEY_1] = '1',
|
||||
[KEY_2] = '2',
|
||||
[KEY_3] = '3',
|
||||
[KEY_4] = '4',
|
||||
[KEY_5] = '5',
|
||||
[KEY_6] = '6',
|
||||
[KEY_7] = '7',
|
||||
[KEY_8] = '8',
|
||||
[KEY_9] = '9',
|
||||
[KEY_0] = '0',
|
||||
|
||||
[KEY_Q] = 'q',
|
||||
[KEY_W] = 'w',
|
||||
[KEY_E] = 'e',
|
||||
[KEY_R] = 'r',
|
||||
[KEY_T] = 't',
|
||||
[KEY_Y] = 'y',
|
||||
[KEY_U] = 'u',
|
||||
[KEY_I] = 'i',
|
||||
[KEY_O] = 'o',
|
||||
[KEY_P] = 'p',
|
||||
[KEY_A] = 'a',
|
||||
[KEY_S] = 's',
|
||||
[KEY_D] = 'd',
|
||||
[KEY_F] = 'f',
|
||||
[KEY_G] = 'g',
|
||||
[KEY_H] = 'h',
|
||||
[KEY_J] = 'j',
|
||||
[KEY_K] = 'k',
|
||||
[KEY_L] = 'l',
|
||||
[KEY_Z] = 'z',
|
||||
[KEY_X] = 'x',
|
||||
[KEY_C] = 'c',
|
||||
[KEY_V] = 'v',
|
||||
[KEY_B] = 'b',
|
||||
[KEY_N] = 'n',
|
||||
[KEY_M] = 'm',
|
||||
|
||||
[KEY_F1] = 0x00,
|
||||
[KEY_F2] = 0x00,
|
||||
[KEY_F3] = 0x00,
|
||||
[KEY_F4] = 0x00,
|
||||
[KEY_F5] = 0x00,
|
||||
[KEY_F6] = 0x00,
|
||||
[KEY_F7] = 0x00,
|
||||
[KEY_F8] = 0x00,
|
||||
[KEY_F9] = 0x00,
|
||||
[KEY_F10] = 0x00,
|
||||
[KEY_F11] = 0x00,
|
||||
[KEY_F12] = 0x00,
|
||||
|
||||
[KEYPAD_7] = '7',
|
||||
[KEYPAD_8] = '8',
|
||||
[KEYPAD_9] = '9',
|
||||
[KEYPAD_MINUS] = '-',
|
||||
[KEYPAD_4] = '4',
|
||||
[KEYPAD_5] = '5',
|
||||
[KEYPAD_6] = '6',
|
||||
[KEYPAD_PLUS] = '+',
|
||||
[KEYPAD_1] = '1',
|
||||
[KEYPAD_2] = '2',
|
||||
[KEYPAD_3] = '3',
|
||||
[KEYPAD_0] = '0',
|
||||
[KEYPAD_PERIOD] = '.',
|
||||
[KEYPAD_RETURN] = '\n',
|
||||
[KEYPAD_ASTERISK] = '*',
|
||||
[KEYPAD_SLASH] = '/',
|
||||
|
||||
[KEY_LEFT_CTRL] = 0x00,
|
||||
[KEY_RIGHT_CTRL] = 0x00,
|
||||
[KEY_LEFT_SHIFT] = 0x00,
|
||||
[KEY_RIGHT_SHIFT] = 0x00,
|
||||
[KEY_LEFT_ALT] = 0x00,
|
||||
[KEY_RIGHT_ALT] = 0x00,
|
||||
[KEY_ESCAPE] = '\e',
|
||||
[KEY_MINUS] = '-',
|
||||
[KEY_EQUAL] = '=',
|
||||
[KEY_BACKSPACE] = '\b',
|
||||
[KEY_TAB] = '\t',
|
||||
[KEY_LEFT_BRACKET] = '[',
|
||||
[KEY_RIGHT_BRACKET] = ']',
|
||||
[KEY_RETURN] = '\n',
|
||||
[KEY_SEMICOLON] = ';',
|
||||
[KEY_APOSTROPHE] = '\'',
|
||||
[KEY_BACK_TICK] = '`',
|
||||
[KEY_BACKSLASH] = '\\',
|
||||
[KEY_COMMA] = ',',
|
||||
[KEY_PERIOD] = '.',
|
||||
[KEY_SLASH] = '/',
|
||||
[KEY_SPACE] = ' ',
|
||||
[KEY_CAPS_LOCK] = 0x00,
|
||||
[KEY_NUM_LOCK] = 0x00,
|
||||
[KEY_SCROLL_LOCK] = 0x00,
|
||||
[KEY_PRINT_SCREEN] = 0x00,
|
||||
|
||||
[KEY_HOME] = 0x00,
|
||||
[KEY_UP_ARROW] = 0x00,
|
||||
[KEY_LEFT_ARROW] = 0x00,
|
||||
[KEY_RIGHT_ARROW] = 0x00,
|
||||
[KEY_DOWN_ARROW] = 0x00,
|
||||
[KEY_PAGE_UP] = 0x00,
|
||||
[KEY_PAGE_DOWN] = 0x00,
|
||||
[KEY_END] = 0x00,
|
||||
[KEY_INSERT] = 0x00,
|
||||
[KEY_DELETE] = 0x00,
|
||||
[KEY_LEFT_GUI] = 0x00,
|
||||
[KEY_RIGHT_GUI] = 0x00,
|
||||
[KEY_APPS] = 0x00,
|
||||
|
||||
[KEY_MULTIMEDIA_PREV_TRACK] = 0x00,
|
||||
[KEY_MULTIMEDIA_NEXT_TRACK] = 0x00,
|
||||
[KEY_MULTIMEDIA_MUTE] = 0x00,
|
||||
[KEY_MULTIMEDIA_CALCULATOR] = 0x00,
|
||||
[KEY_MULTIMEDIA_PLAY] = 0x00,
|
||||
[KEY_MULTIMEDIA_STOP] = 0x00,
|
||||
[KEY_MULTIMEDIA_VOL_DOWN] = 0x00,
|
||||
[KEY_MULTIMEDIA_VOL_UP] = 0x00,
|
||||
[KEY_MULTIMEDIA_WWW_HOME] = 0x00,
|
||||
[KEY_MULTIMEDIA_WWW_SEARCH] = 0x00,
|
||||
[KEY_MULTIMEDIA_WWW_FAVORITES] = 0x00,
|
||||
[KEY_MULTIMEDIA_WWW_REFRESH] = 0x00,
|
||||
[KEY_MULTIMEDIA_WWW_STOP] = 0x00,
|
||||
[KEY_MULTIMEDIA_WWW_FORWARD] = 0x00,
|
||||
[KEY_MULTIMEDIA_WWW_BACK] = 0x00,
|
||||
[KEY_MULTIMEDIA_MY_COMPUTER] = 0x00,
|
||||
[KEY_MULTIMEDIA_EMAIL] = 0x00,
|
||||
[KEY_MULTIMEDIA_MEDIA_SELECT] = 0x00,
|
||||
|
||||
[KEY_ACPI_POWER] = 0x00,
|
||||
[KEY_ACPI_SLEEP] = 0x00,
|
||||
[KEY_ACPI_WAKE] = 0x00};
|
||||
|
||||
static char ScanCodeConversionTableUpper[] = {
|
||||
[KEY_1] = '!',
|
||||
[KEY_2] = '@',
|
||||
[KEY_3] = '#',
|
||||
[KEY_4] = '$',
|
||||
[KEY_5] = '%',
|
||||
[KEY_6] = '^',
|
||||
[KEY_7] = '&',
|
||||
[KEY_8] = '*',
|
||||
[KEY_9] = '(',
|
||||
[KEY_0] = ')',
|
||||
|
||||
[KEY_Q] = 'Q',
|
||||
[KEY_W] = 'W',
|
||||
[KEY_E] = 'E',
|
||||
[KEY_R] = 'R',
|
||||
[KEY_T] = 'T',
|
||||
[KEY_Y] = 'Y',
|
||||
[KEY_U] = 'U',
|
||||
[KEY_I] = 'I',
|
||||
[KEY_O] = 'O',
|
||||
[KEY_P] = 'P',
|
||||
[KEY_A] = 'A',
|
||||
[KEY_S] = 'S',
|
||||
[KEY_D] = 'D',
|
||||
[KEY_F] = 'F',
|
||||
[KEY_G] = 'G',
|
||||
[KEY_H] = 'H',
|
||||
[KEY_J] = 'J',
|
||||
[KEY_K] = 'K',
|
||||
[KEY_L] = 'L',
|
||||
[KEY_Z] = 'Z',
|
||||
[KEY_X] = 'X',
|
||||
[KEY_C] = 'C',
|
||||
[KEY_V] = 'V',
|
||||
[KEY_B] = 'B',
|
||||
[KEY_N] = 'N',
|
||||
[KEY_M] = 'M',
|
||||
|
||||
[KEY_F1] = 0x00,
|
||||
[KEY_F2] = 0x00,
|
||||
[KEY_F3] = 0x00,
|
||||
[KEY_F4] = 0x00,
|
||||
[KEY_F5] = 0x00,
|
||||
[KEY_F6] = 0x00,
|
||||
[KEY_F7] = 0x00,
|
||||
[KEY_F8] = 0x00,
|
||||
[KEY_F9] = 0x00,
|
||||
[KEY_F10] = 0x00,
|
||||
[KEY_F11] = 0x00,
|
||||
[KEY_F12] = 0x00,
|
||||
|
||||
[KEYPAD_7] = '7',
|
||||
[KEYPAD_8] = '8',
|
||||
[KEYPAD_9] = '9',
|
||||
[KEYPAD_MINUS] = '-',
|
||||
[KEYPAD_4] = '4',
|
||||
[KEYPAD_5] = '5',
|
||||
[KEYPAD_6] = '6',
|
||||
[KEYPAD_PLUS] = '+',
|
||||
[KEYPAD_1] = '1',
|
||||
[KEYPAD_2] = '2',
|
||||
[KEYPAD_3] = '3',
|
||||
[KEYPAD_0] = '0',
|
||||
[KEYPAD_PERIOD] = '.',
|
||||
[KEYPAD_RETURN] = '\n',
|
||||
[KEYPAD_ASTERISK] = '*',
|
||||
[KEYPAD_SLASH] = '/',
|
||||
|
||||
[KEY_LEFT_CTRL] = 0x00,
|
||||
[KEY_RIGHT_CTRL] = 0x00,
|
||||
[KEY_LEFT_SHIFT] = 0x00,
|
||||
[KEY_RIGHT_SHIFT] = 0x00,
|
||||
[KEY_LEFT_ALT] = 0x00,
|
||||
[KEY_RIGHT_ALT] = 0x00,
|
||||
[KEY_ESCAPE] = '\e',
|
||||
[KEY_MINUS] = '_',
|
||||
[KEY_EQUAL] = '+',
|
||||
[KEY_BACKSPACE] = '\b',
|
||||
[KEY_TAB] = '\t',
|
||||
[KEY_LEFT_BRACKET] = '{',
|
||||
[KEY_RIGHT_BRACKET] = '}',
|
||||
[KEY_RETURN] = '\n',
|
||||
[KEY_SEMICOLON] = ':',
|
||||
[KEY_APOSTROPHE] = '\"',
|
||||
[KEY_BACK_TICK] = '~',
|
||||
[KEY_BACKSLASH] = '|',
|
||||
[KEY_COMMA] = '<',
|
||||
[KEY_PERIOD] = '>',
|
||||
[KEY_SLASH] = '/',
|
||||
[KEY_SPACE] = ' ',
|
||||
[KEY_CAPS_LOCK] = 0x00,
|
||||
[KEY_NUM_LOCK] = 0x00,
|
||||
[KEY_SCROLL_LOCK] = 0x00,
|
||||
[KEY_PRINT_SCREEN] = 0x00,
|
||||
|
||||
[KEY_HOME] = 0x00,
|
||||
[KEY_UP_ARROW] = 0x00,
|
||||
[KEY_LEFT_ARROW] = 0x00,
|
||||
[KEY_RIGHT_ARROW] = 0x00,
|
||||
[KEY_DOWN_ARROW] = 0x00,
|
||||
[KEY_PAGE_UP] = 0x00,
|
||||
[KEY_PAGE_DOWN] = 0x00,
|
||||
[KEY_END] = 0x00,
|
||||
[KEY_INSERT] = 0x00,
|
||||
[KEY_DELETE] = 0x00,
|
||||
[KEY_LEFT_GUI] = 0x00,
|
||||
[KEY_RIGHT_GUI] = 0x00,
|
||||
[KEY_APPS] = 0x00,
|
||||
|
||||
[KEY_MULTIMEDIA_PREV_TRACK] = 0x00,
|
||||
[KEY_MULTIMEDIA_NEXT_TRACK] = 0x00,
|
||||
[KEY_MULTIMEDIA_MUTE] = 0x00,
|
||||
[KEY_MULTIMEDIA_CALCULATOR] = 0x00,
|
||||
[KEY_MULTIMEDIA_PLAY] = 0x00,
|
||||
[KEY_MULTIMEDIA_STOP] = 0x00,
|
||||
[KEY_MULTIMEDIA_VOL_DOWN] = 0x00,
|
||||
[KEY_MULTIMEDIA_VOL_UP] = 0x00,
|
||||
[KEY_MULTIMEDIA_WWW_HOME] = 0x00,
|
||||
[KEY_MULTIMEDIA_WWW_SEARCH] = 0x00,
|
||||
[KEY_MULTIMEDIA_WWW_FAVORITES] = 0x00,
|
||||
[KEY_MULTIMEDIA_WWW_REFRESH] = 0x00,
|
||||
[KEY_MULTIMEDIA_WWW_STOP] = 0x00,
|
||||
[KEY_MULTIMEDIA_WWW_FORWARD] = 0x00,
|
||||
[KEY_MULTIMEDIA_WWW_BACK] = 0x00,
|
||||
[KEY_MULTIMEDIA_MY_COMPUTER] = 0x00,
|
||||
[KEY_MULTIMEDIA_EMAIL] = 0x00,
|
||||
[KEY_MULTIMEDIA_MEDIA_SELECT] = 0x00,
|
||||
|
||||
[KEY_ACPI_POWER] = 0x00,
|
||||
[KEY_ACPI_SLEEP] = 0x00,
|
||||
[KEY_ACPI_WAKE] = 0x00};
|
||||
|
||||
#ifdef DEBUG
|
||||
static const char *ScanCodeDebugNames[] = {
|
||||
"KEY_1", "KEY_2", "KEY_3", "KEY_4", "KEY_5", "KEY_6", "KEY_7", "KEY_8",
|
||||
"KEY_9", "KEY_0", "KEY_Q", "KEY_W", "KEY_E", "KEY_R", "KEY_T", "KEY_Y",
|
||||
"KEY_U", "KEY_I", "KEY_O", "KEY_P", "KEY_A", "KEY_S", "KEY_D", "KEY_F",
|
||||
"KEY_G", "KEY_H", "KEY_J", "KEY_K", "KEY_L", "KEY_Z", "KEY_X", "KEY_C",
|
||||
"KEY_V", "KEY_B", "KEY_N", "KEY_M", "KEY_F1", "KEY_F2", "KEY_F3", "KEY_F4",
|
||||
"KEY_F5", "KEY_F6", "KEY_F7", "KEY_F8", "KEY_F9", "KEY_F10", "KEY_F11",
|
||||
"KEY_F12", "KEYPAD_7", "KEYPAD_8", "KEYPAD_9", "KEYPAD_MINUS", "KEYPAD_4",
|
||||
"KEYPAD_5", "KEYPAD_6", "KEYPAD_PLUS", "KEYPAD_1", "KEYPAD_2", "KEYPAD_3",
|
||||
"KEYPAD_0", "KEYPAD_PERIOD", "KEYPAD_RETURN", "KEYPAD_ASTERISK", "KEYPAD_SLASH",
|
||||
"KEY_LEFT_CTRL", "KEY_RIGHT_CTRL", "KEY_LEFT_SHIFT", "KEY_RIGHT_SHIFT",
|
||||
"KEY_LEFT_ALT", "KEY_RIGHT_ALT", "KEY_ESCAPE", "KEY_MINUS", "KEY_EQUAL",
|
||||
"KEY_BACKSPACE", "KEY_TAB", "KEY_LEFT_BRACKET", "KEY_RIGHT_BRACKET",
|
||||
"KEY_RETURN", "KEY_SEMICOLON", "KEY_APOSTROPHE", "KEY_BACK_TICK",
|
||||
"KEY_BACKSLASH", "KEY_COMMA", "KEY_PERIOD", "KEY_SLASH", "KEY_SPACE",
|
||||
"KEY_CAPS_LOCK", "KEY_NUM_LOCK", "KEY_SCROLL_LOCK", "KEY_PRINT_SCREEN",
|
||||
"KEY_HOME", "KEY_UP_ARROW", "KEY_LEFT_ARROW", "KEY_RIGHT_ARROW",
|
||||
"KEY_DOWN_ARROW", "KEY_PAGE_UP", "KEY_PAGE_DOWN", "KEY_END", "KEY_INSERT",
|
||||
"KEY_DELETE", "KEY_LEFT_GUI", "KEY_RIGHT_GUI", "KEY_APPS",
|
||||
"KEY_MULTIMEDIA_PREV_TRACK", "KEY_MULTIMEDIA_NEXT_TRACK", "KEY_MULTIMEDIA_MUTE",
|
||||
"KEY_MULTIMEDIA_CALCULATOR", "KEY_MULTIMEDIA_PLAY", "KEY_MULTIMEDIA_STOP",
|
||||
"KEY_MULTIMEDIA_VOL_DOWN", "KEY_MULTIMEDIA_VOL_UP", "KEY_MULTIMEDIA_WWW_HOME",
|
||||
"KEY_MULTIMEDIA_WWW_SEARCH", "KEY_MULTIMEDIA_WWW_FAVORITES",
|
||||
"KEY_MULTIMEDIA_WWW_REFRESH", "KEY_MULTIMEDIA_WWW_STOP",
|
||||
"KEY_MULTIMEDIA_WWW_FORWARD", "KEY_MULTIMEDIA_WWW_BACK",
|
||||
"KEY_MULTIMEDIA_MY_COMPUTER", "KEY_MULTIMEDIA_EMAIL",
|
||||
"KEY_MULTIMEDIA_MEDIA_SELECT", "KEY_ACPI_POWER", "KEY_ACPI_SLEEP", "KEY_ACPI_WAKE"};
|
||||
#endif
|
||||
|
||||
namespace Driver
|
||||
{
|
||||
char GetScanCode(uint8_t ScanCode, bool Upper)
|
||||
{
|
||||
ScanCode &= 0x7F; /* Remove KEY_PRESSED bit */
|
||||
if (ScanCode >= sizeof(ScanCodeConversionTableLower))
|
||||
{
|
||||
warn("Unknown scancode %x", ScanCode);
|
||||
return 0x00;
|
||||
}
|
||||
|
||||
// debug("Scancode %x (%s)", ScanCode, ScanCodeDebugNames[ScanCode]);
|
||||
return Upper
|
||||
? ScanCodeConversionTableUpper[ScanCode]
|
||||
: ScanCodeConversionTableLower[ScanCode];
|
||||
}
|
||||
|
||||
bool IsValidChar(uint8_t ScanCode)
|
||||
{
|
||||
ScanCode &= 0x7F; /* Remove KEY_PRESSED bit */
|
||||
if (ScanCode >= sizeof(ScanCodeConversionTableLower))
|
||||
return false;
|
||||
|
||||
if (ScanCode > KEY_M)
|
||||
{
|
||||
if (ScanCode < KEYPAD_7)
|
||||
return false; /* F1 - F12 */
|
||||
|
||||
switch (ScanCode)
|
||||
{
|
||||
case KEY_MINUS:
|
||||
case KEY_EQUAL:
|
||||
case KEY_LEFT_BRACKET:
|
||||
case KEY_RIGHT_BRACKET:
|
||||
case KEY_RETURN:
|
||||
case KEY_SEMICOLON:
|
||||
case KEY_APOSTROPHE:
|
||||
case KEY_BACK_TICK:
|
||||
case KEY_BACKSLASH:
|
||||
case KEY_COMMA:
|
||||
case KEY_PERIOD:
|
||||
case KEY_SLASH:
|
||||
case KEY_SPACE:
|
||||
return true;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user