diff --git a/Input/Makefile b/Input/Makefile index bd74364f..a0d840d2 100644 --- a/Input/Makefile +++ b/Input/Makefile @@ -1,7 +1,9 @@ build: + make --quiet -C PS2Mouse build make --quiet -C VMwareMouse build make --quiet -C VirtualBoxMouse build clean: + make -C PS2Mouse clean make -C VMwareMouse clean make -C VirtualBoxMouse clean diff --git a/Input/PS2Mouse/Makefile b/Input/PS2Mouse/Makefile new file mode 100644 index 00000000..989dca3b --- /dev/null +++ b/Input/PS2Mouse/Makefile @@ -0,0 +1,98 @@ +# Config file +include ../../../Makefile.conf + +FILENAME = PS2Mouse.fex + +CC = ../../../$(COMPILER_PATH)/$(COMPILER_ARCH)gcc +CPP = ../../../$(COMPILER_PATH)/$(COMPILER_ARCH)g++ +LD = ../../../$(COMPILER_PATH)/$(COMPILER_ARCH)ld +AS = ../../../$(COMPILER_PATH)/$(COMPILER_ARCH)as +OBJDUMP = ../../../$(COMPILER_PATH)/$(COMPILER_ARCH)objdump + +GIT_COMMIT = $(shell git rev-parse HEAD) +GIT_COMMIT_SHORT = $(shell git rev-parse --short HEAD) + +ifeq ($(OSARCH), amd64) +S_SOURCES = $(shell find ./ -type f -name '*.S' -not -path "./arch/i686/*" -not -path "./arch/aarch64/*") +C_SOURCES = $(shell find ./ -type f -name '*.c' -not -path "./arch/i686/*" -not -path "./arch/aarch64/*") +CPP_SOURCES = $(shell find ./ -type f -name '*.cpp' -not -path "./arch/i686/*" -not -path "./arch/aarch64/*") +else ifeq ($(OSARCH), i686) +S_SOURCES = $(shell find ./ -type f -name '*.S' -not -path "./arch/amd64/*" -not -path "./arch/aarch64/*") +C_SOURCES = $(shell find ./ -type f -name '*.c' -not -path "./arch/amd64/*" -not -path "./arch/aarch64/*") +CPP_SOURCES = $(shell find ./ -type f -name '*.cpp' -not -path "./arch/amd64/*" -not -path "./arch/aarch64/*") +else ifeq ($(OSARCH), aarch64) +S_SOURCES = $(shell find ./ -type f -name '*.S' -not -path "./arch/amd64/*" -not -path "./arch/i686/*") +C_SOURCES = $(shell find ./ -type f -name '*.c' -not -path "./arch/amd64/*" -not -path "./arch/i686/*") +CPP_SOURCES = $(shell find ./ -type f -name '*.cpp' -not -path "./arch/amd64/*" -not -path "./arch/i686/*") +endif +HEADERS = $(sort $(dir $(wildcard ../../include/*))) +OBJ = $(C_SOURCES:.c=.o) $(CPP_SOURCES:.cpp=.o) $(ASM_SOURCES:.asm=.o) $(S_SOURCES:.S=.o) $(PSF_SOURCES:.psf=.o) $(BMP_SOURCES:.bmp=.o) +INCLUDE_DIR = ../../include + +LDFLAGS := \ + -fPIC -fPIE -pie -Wl,-eDriverEntry \ + -Wl,-static,--no-dynamic-linker,-ztext,--no-warn-rwx-segment \ + -nostdlib -nodefaultlibs -nolibc \ + -zmax-page-size=0x1000 \ + -Wl,-Map file.map -static -Tlinker.ld + +WARNCFLAG = -Wall -Wextra + +CFLAGS := \ + -I$(INCLUDE_DIR) \ + -DGIT_COMMIT='"$(GIT_COMMIT)"' \ + -DGIT_COMMIT_SHORT='"$(GIT_COMMIT_SHORT)"' + +ifeq ($(OSARCH), amd64) + +CFLAGS += -fPIC -fPIE -pie -mno-80387 -mno-mmx -mno-3dnow \ + -mno-red-zone -mno-sse -mno-sse2 \ + -march=x86-64 -pipe -ffunction-sections \ + -msoft-float -fno-builtin + +else ifeq ($(OSARCH), i686) + +CFLAGS += -fPIC -fPIE -pie -mno-80387 -mno-mmx -mno-3dnow \ + -mno-red-zone -mno-sse -mno-sse2 -ffunction-sections \ + -march=i686 -pipe -msoft-float -fno-builtin + +else ifeq ($(OSARCH), aarch64) + +CFLAGS += -pipe -fno-builtin -fPIC + +endif + +build: $(FILENAME) +ifeq ($(OSARCH), amd64) + $(OBJDUMP) -b binary -D -m i386:x86-64 -d $(FILENAME) > file_dump.map +else ifeq ($(OSARCH), i686) + +else ifeq ($(OSARCH), aarch64) + +endif + mv $(FILENAME) ../../out/$(FILENAME) + +$(FILENAME): $(OBJ) + $(info Linking $@) + $(CC) $(LDFLAGS) $(OBJ) -o $@ + +%.o: %.c $(HEADERS) + $(info Compiling $<) + $(CC) $(CFLAGS) $(WARNCFLAG) -std=c17 -c $< -o $@ + +%.o: %.cpp $(HEADERS) + $(info Compiling $<) + $(CPP) $(CFLAGS) $(WARNCFLAG) -std=c++20 -fexceptions -c $< -o $@ + +%.o: %.S + $(info Compiling $<) +ifeq ($(OSARCH), amd64) + $(AS) -o $@ $< +else ifeq ($(OSARCH), i686) + $(AS) -o $@ $< +else ifeq ($(OSARCH), aarch64) + $(AS) -o $@ $< +endif + +clean: + rm -f *.o file.map file_dump.map $(OBJ) diff --git a/Input/PS2Mouse/PS2MouseDriver.cpp b/Input/PS2Mouse/PS2MouseDriver.cpp new file mode 100644 index 00000000..4d2b5102 --- /dev/null +++ b/Input/PS2Mouse/PS2MouseDriver.cpp @@ -0,0 +1,275 @@ +#include +#include + +#include "../../../Kernel/DAPI.hpp" +#include "../../../Kernel/Fex.hpp" + +extern "C" int DriverEntry(void *Data); +int CallbackHandler(KernelCallback *Data); + +HEAD(FexFormatType_Driver, FexOSType_Fennix, DriverEntry); + +#pragma GCC diagnostic ignored "-Wmissing-field-initializers" + +__attribute__((section(".extended"))) FexExtended ExtendedHeader = { + .Driver = { + .Name = "PS/2 Mouse Driver", + .Type = FexDriverType_Input, + .TypeFlags = FexDriverInputTypes_Mouse, + .OverrideOnConflict = false, + .Callback = CallbackHandler, + .Bind = { + .Type = BIND_INTERRUPT, + .Interrupt = { + .Vector = {0xC}, // IRQ12 + }}}}; + +KernelAPI *KAPI; + +#define print(msg) KAPI->Util.DebugPrint((char *)(msg), KAPI->Info.DriverUID) + +/* --------------------------------------------------------------------------------------------------------- */ + +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) +}; + +#define PS2LeftButton 0b00000001 +#define PS2MiddleButton 0b00000100 +#define PS2RightButton 0b00000010 +#define PS2XSign 0b00010000 +#define PS2YSign 0b00100000 +#define PS2XOverflow 0b01000000 +#define PS2YOverflow 0b10000000 + +int MouseX = 0, MouseY = 0, MouseZ = 0; +int MouseLeft = 0, MouseMiddle = 0, MouseRight = 0; + +uint8_t Packet[4]; +bool PacketReady = false; +uint8_t Cycle = 0; + +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; +} + +uint8_t Read() +{ + WaitRead(); + return inb(Ports::DATA); +} + +void Write(uint16_t Port, uint8_t Value) +{ + WaitWrite(); + outb(Port, Value); +} + +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; + + return OK; +} + +int CallbackHandler(KernelCallback *Data) +{ + switch (Data->Reason) + { + case AcknowledgeReason: + { + print("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(); + + print("PS/2 mouse configured."); + break; + } + case FetchReason: + { + Data->InputCallback.Mouse.X = MouseX; + Data->InputCallback.Mouse.Y = MouseY; + Data->InputCallback.Mouse.Z = MouseZ; + Data->InputCallback.Mouse.Buttons.Left = MouseLeft; + Data->InputCallback.Mouse.Buttons.Right = MouseRight; + Data->InputCallback.Mouse.Buttons.Middle = MouseMiddle; + break; + } + case StopReason: + { + 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(); + + print("Driver stopped."); + break; + } + case InterruptReason: + { + uint8_t Data = inb(0x60); + + if (__builtin_expect(!!(PacketReady), 0)) + { + bool XNegative, YNegative, XOverflow, YOverflow; + + if (Packet[0] & PS2XSign) + XNegative = true; + else + XNegative = false; + + if (Packet[0] & PS2YSign) + YNegative = true; + else + YNegative = false; + + if (Packet[0] & PS2XOverflow) + XOverflow = true; + else + XOverflow = false; + + if (Packet[0] & PS2YOverflow) + YOverflow = true; + else + YOverflow = false; + + if (!XNegative) + { + MouseX += Packet[1]; + if (XOverflow) + MouseX += 255; + } + else + { + Packet[1] = 256 - Packet[1]; + MouseX -= Packet[1]; + if (XOverflow) + MouseX -= 255; + } + + if (!YNegative) + { + MouseY -= Packet[2]; + if (YOverflow) + MouseY -= 255; + } + else + { + Packet[2] = 256 - Packet[2]; + MouseY += Packet[2]; + if (YOverflow) + MouseY += 255; + } + + uint32_t Width = KAPI->Display.GetWidth(); + uint32_t Height = KAPI->Display.GetHeight(); + + if (MouseX < 0) + MouseX = 0; + + if ((uint32_t)MouseX > Width - 1) + MouseX = Width - 1; + + if (MouseY < 0) + MouseY = 0; + if ((uint32_t)MouseY > Height - 1) + MouseY = Height - 1; + + MouseLeft = 0; + MouseMiddle = 0; + MouseRight = 0; + + if (Packet[0] & PS2LeftButton) + MouseLeft = 1; + if (Packet[0] & PS2MiddleButton) + MouseMiddle = 1; + if (Packet[0] & PS2RightButton) + MouseRight = 1; + PacketReady = false; + } + + switch (Cycle) + { + case 0: + { + if ((Data & 0b00001000) == 0) + break; + Packet[0] = Data; + Cycle++; + break; + } + case 1: + { + Packet[1] = Data; + Cycle++; + break; + } + case 2: + { + Packet[2] = Data; + PacketReady = true; + Cycle = 0; + break; + } + } + break; + } + default: + { + print("Unknown reason."); + break; + } + } + return OK; +} diff --git a/Input/PS2Mouse/linker.ld b/Input/PS2Mouse/linker.ld new file mode 100644 index 00000000..29cd11cd --- /dev/null +++ b/Input/PS2Mouse/linker.ld @@ -0,0 +1,40 @@ +OUTPUT_FORMAT(binary) +OUTPUT_ARCH(i386:x86-64) + +ENTRY(DriverEntry) + +SECTIONS +{ + .header : + { + *(.header .header.*) + *(.extended .extended.*) + } + + .text : + { + *(.text .text.*) + } + + .data : + { + *(.data .data.*) + } + + .rodata : + { + *(.rodata .rodata.*) + } + + .bss : + { + *(COMMON) + *(.bss .bss.*) + } + + /DISCARD/ : + { + *(.eh_frame) + *(.note .note.*) + } +}