Kernel/Drivers/VMware/Mouse.cpp
2023-05-19 07:27:42 +03:00

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;
}
}