mirror of
https://github.com/Fennix-Project/Kernel.git
synced 2025-05-28 15:34:33 +00:00
226 lines
4.4 KiB
C++
226 lines
4.4 KiB
C++
#include "mouse.hpp"
|
|
|
|
#include <debug.h>
|
|
#include <io.h>
|
|
|
|
#include "../../DAPI.hpp"
|
|
#include "../drv.hpp"
|
|
|
|
/* https://wiki.osdev.org/VMware_tools */
|
|
|
|
namespace VMwareMouse
|
|
{
|
|
KernelAPI KAPI;
|
|
|
|
void CommandSend(VMwareCommand *cmd)
|
|
{
|
|
cmd->magic = VMWARE_MAGIC;
|
|
cmd->port = VMWARE_PORT;
|
|
asm volatile("in %%dx, %0"
|
|
: "+a"(cmd->ax), "+b"(cmd->bx), "+c"(cmd->cx), "+d"(cmd->dx), "+S"(cmd->si), "+D"(cmd->di));
|
|
}
|
|
|
|
bool IsVMwareBackdoorAvailable(void)
|
|
{
|
|
VMwareCommand cmd;
|
|
cmd.bx = ~VMWARE_MAGIC;
|
|
cmd.command = CMD_GETVERSION;
|
|
CommandSend(&cmd);
|
|
if (cmd.bx != VMWARE_MAGIC || cmd.ax == 0xFFFFFFFF)
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
int DriverEntry(void *Data)
|
|
{
|
|
if (!Data)
|
|
return INVALID_KERNEL_API;
|
|
KAPI = *(KernelAPI *)Data;
|
|
if (KAPI.Version.Major < 0 || KAPI.Version.Minor < 0 || KAPI.Version.Patch < 0)
|
|
return KERNEL_API_VERSION_NOT_SUPPORTED;
|
|
|
|
if (!IsVMwareBackdoorAvailable())
|
|
return SYSTEM_NOT_SUPPORTED;
|
|
|
|
return OK;
|
|
}
|
|
|
|
void Absolute(void)
|
|
{
|
|
VMwareCommand cmd;
|
|
|
|
/* Enable */
|
|
cmd.bx = ABSPOINTER_ENABLE;
|
|
cmd.command = CMD_ABSPOINTER_COMMAND;
|
|
CommandSend(&cmd);
|
|
|
|
/* Status */
|
|
cmd.bx = 0;
|
|
cmd.command = CMD_ABSPOINTER_STATUS;
|
|
CommandSend(&cmd);
|
|
|
|
/* Read data (1) */
|
|
cmd.bx = 1;
|
|
cmd.command = CMD_ABSPOINTER_DATA;
|
|
CommandSend(&cmd);
|
|
|
|
/* Enable absolute */
|
|
cmd.bx = ABSPOINTER_ABSOLUTE;
|
|
cmd.command = CMD_ABSPOINTER_COMMAND;
|
|
CommandSend(&cmd);
|
|
}
|
|
|
|
void Relative(void)
|
|
{
|
|
VMwareCommand cmd;
|
|
cmd.bx = ABSPOINTER_RELATIVE;
|
|
cmd.command = CMD_ABSPOINTER_COMMAND;
|
|
CommandSend(&cmd);
|
|
}
|
|
|
|
enum Config
|
|
{
|
|
READ_CONFIG = 0x20,
|
|
WRITE_CONFIG = 0x60
|
|
};
|
|
|
|
enum Ports
|
|
{
|
|
DATA = 0x60,
|
|
STATUS = 0x64,
|
|
COMMAND = 0x64,
|
|
};
|
|
|
|
enum State
|
|
{
|
|
OUTPUT_FULL = (1 << 0),
|
|
INPUT_FULL = (1 << 1),
|
|
MOUSE_BYTE = (1 << 5)
|
|
};
|
|
|
|
void WaitRead()
|
|
{
|
|
uint64_t Timeout = 100000;
|
|
while (Timeout--)
|
|
if (inb(Ports::STATUS) & State::OUTPUT_FULL)
|
|
return;
|
|
}
|
|
|
|
void WaitWrite()
|
|
{
|
|
uint64_t Timeout = 100000;
|
|
while (Timeout--)
|
|
if ((inb(Ports::STATUS) & State::INPUT_FULL) == 0)
|
|
return;
|
|
}
|
|
|
|
void Write(uint16_t Port, uint8_t Value)
|
|
{
|
|
WaitWrite();
|
|
outb(Port, Value);
|
|
}
|
|
|
|
uint8_t Read()
|
|
{
|
|
WaitRead();
|
|
return inb(Ports::DATA);
|
|
}
|
|
|
|
int MouseX = 0, MouseY = 0, MouseZ = 0;
|
|
int MouseButton = 0;
|
|
|
|
int CallbackHandler(KernelCallback *Data)
|
|
{
|
|
switch (Data->Reason)
|
|
{
|
|
case AcknowledgeReason:
|
|
{
|
|
debug("Kernel acknowledged the driver.");
|
|
break;
|
|
}
|
|
case ConfigurationReason:
|
|
{
|
|
outb(COMMAND, 0xA8);
|
|
Write(COMMAND, READ_CONFIG);
|
|
uint8_t Status = Read();
|
|
Status |= 0b10;
|
|
Write(COMMAND, WRITE_CONFIG);
|
|
Write(DATA, Status);
|
|
Write(COMMAND, 0xD4);
|
|
Write(DATA, 0xF6);
|
|
Read();
|
|
Write(COMMAND, 0xD4);
|
|
Write(DATA, 0xF4);
|
|
Read();
|
|
Absolute();
|
|
trace("VMware mouse configured.");
|
|
break;
|
|
}
|
|
case FetchReason:
|
|
{
|
|
Data->InputCallback.Mouse.X = (MouseX * KAPI.Display.GetWidth()) / 0xFFFF;
|
|
Data->InputCallback.Mouse.Y = (MouseY * KAPI.Display.GetHeight()) / 0xFFFF;
|
|
Data->InputCallback.Mouse.Z = MouseZ;
|
|
Data->InputCallback.Mouse.Buttons.Left = MouseButton & 0x20;
|
|
Data->InputCallback.Mouse.Buttons.Right = MouseButton & 0x10;
|
|
Data->InputCallback.Mouse.Buttons.Middle = MouseButton & 0x08;
|
|
break;
|
|
}
|
|
case StopReason:
|
|
{
|
|
Relative();
|
|
// TODO: UNTESTED!!!
|
|
outb(COMMAND, 0xA8);
|
|
Write(COMMAND, READ_CONFIG);
|
|
uint8_t Status = Read();
|
|
Status &= ~0b10;
|
|
Write(COMMAND, WRITE_CONFIG);
|
|
Write(DATA, Status);
|
|
Write(COMMAND, 0xD4);
|
|
Write(DATA, 0xF5);
|
|
Read();
|
|
debug("Driver stopped.");
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
warn("Unknown reason.");
|
|
break;
|
|
}
|
|
}
|
|
return OK;
|
|
}
|
|
|
|
int InterruptCallback(CPURegisters *)
|
|
{
|
|
uint8_t Data = inb(0x60);
|
|
(void)Data;
|
|
VMwareCommand cmd;
|
|
cmd.bx = 0;
|
|
cmd.command = CMD_ABSPOINTER_STATUS;
|
|
CommandSend(&cmd);
|
|
|
|
if (cmd.ax == 0xFFFF0000)
|
|
{
|
|
warn("VMware mouse is not connected?");
|
|
Relative();
|
|
Absolute();
|
|
return ERROR;
|
|
}
|
|
if ((cmd.ax & 0xFFFF) < 4)
|
|
return ERROR;
|
|
|
|
cmd.bx = 4;
|
|
cmd.command = CMD_ABSPOINTER_DATA;
|
|
CommandSend(&cmd);
|
|
|
|
int flags = (cmd.ax & 0xFFFF0000) >> 16; /* Not important */
|
|
(void)flags;
|
|
MouseButton = (cmd.ax & 0xFFFF); /* 0x10 = Right, 0x20 = Left, 0x08 = Middle */
|
|
MouseX = cmd.bx; /* Both X and Y are scaled from 0 to 0xFFFF */
|
|
MouseY = cmd.cx; /* You should map these somewhere to the actual resolution. */
|
|
MouseZ = (int8_t)cmd.dx; /* Z is a single signed byte indicating scroll direction. */
|
|
return OK;
|
|
}
|
|
}
|