Update drivers

This commit is contained in:
EnderIce2
2024-01-19 06:44:00 +02:00
parent 2ee57b9756
commit da4a6317ea
83 changed files with 9425 additions and 598 deletions

5
input/Makefile Normal file
View File

@ -0,0 +1,5 @@
build:
make -C aip build
clean:
make -C aip clean

83
input/aip/Makefile Normal file
View File

@ -0,0 +1,83 @@
# Config file
include ../../../Makefile.conf
FILENAME = aip.drv
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
S_SOURCES = $(shell find ./ -type f -name '*.S')
C_SOURCES = $(shell find ./ -type f -name '*.c')
CPP_SOURCES = $(shell find ./ -type f -name '*.cpp')
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)
STACK_USAGE_OBJ = $(C_SOURCES:.c=.su) $(CPP_SOURCES:.cpp=.su)
INCLUDE_DIR = ../../include
LIBS := ../../out/dcrt0.o -L../../out -ldriver
LDFLAGS := \
-fPIC -fPIE -pie \
-Wl,--no-dynamic-linker,-ztext,--no-warn-rwx-segment \
-nostdlib -nodefaultlibs -nolibc \
-zmax-page-size=0x1000 \
-Wl,-Map file.map -shared -fvisibility=hidden
WARNCFLAG = -Wall -Wextra
CFLAGS := -I$(INCLUDE_DIR) -fvisibility=hidden
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), i386)
CFLAGS += -fPIC -fPIE -pie -mno-80387 -mno-mmx -mno-3dnow \
-mno-red-zone -mno-sse -mno-sse2 -ffunction-sections \
-march=i386 -pipe -msoft-float -fno-builtin
else ifeq ($(OSARCH), aarch64)
CFLAGS += -pipe -fno-builtin -fPIC
endif
ifeq ($(DEBUG), 1)
CFLAGS += -DDEBUG -ggdb3 -O0 -fdiagnostics-color=always -fstack-usage
ifeq ($(OSARCH), amd64)
CFLAGS += -fverbose-asm
endif
ifneq ($(OSARCH), aarch64)
CFLAGS += -fstack-check
endif
LDFLAGS += -ggdb3 -O0
endif
build: $(FILENAME)
mv $(FILENAME) ../../out/$(FILENAME)
$(FILENAME): $(OBJ)
$(info Linking $@)
$(CC) $(LDFLAGS) $(OBJ) $(LIBS) -o $@
%.o: %.c $(HEADERS)
$(info Compiling $<)
$(CC) $(CFLAGS) $(WARNCFLAG) -std=c17 -c $< -o $@
%.o: %.cpp $(HEADERS)
$(info Compiling $<)
$(CPP) $(CFLAGS) $(WARNCFLAG) -std=c++20 -fno-exceptions -fno-rtti -c $< -o $@
%.o: %.S
$(info Compiling $<)
$(AS) -o $@ $<
clean:
rm -f file.map $(OBJ) $(STACK_USAGE_OBJ)

38
input/aip/aip.h Normal file
View File

@ -0,0 +1,38 @@
/*
This file is part of Fennix Drivers.
Fennix Drivers 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 Drivers 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 Drivers. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef __FENNIX_DRIVER_AIP_H__
#define __FENNIX_DRIVER_AIP_H__
#include <types.h>
#include <aip.h>
#include <regs.h>
extern uint8_t Device1ID[];
extern uint8_t Device2ID[];
void PS2KbdInterruptHandler(TrapFrame *);
int InitializeKeyboard();
int FinalizeKeyboard();
int DetectPS2Keyboard();
void PS2MouseInterruptHandler(TrapFrame *);
int InitializeMouse();
int FinalizeMouse();
int DetectPS2Mouse();
#endif // !__FENNIX_DRIVER_AIP_H__

309
input/aip/keyboard.c Normal file
View File

@ -0,0 +1,309 @@
/*
This file is part of Fennix Drivers.
Fennix Drivers 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 Drivers 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 Drivers. If not, see <https://www.gnu.org/licenses/>.
*/
#include "aip.h"
#include <driver.h>
#include <errno.h>
#include <input.h>
#include <base.h>
#include <io.h>
uint8_t KeyboardScanCodeSet = 0;
dev_t KeyboardDevID = -1;
const unsigned short ScanCodeSet1[] =
{KEY_NULL, KEY_ESCAPE,
KEY_1, KEY_2, KEY_3, KEY_4, KEY_5, KEY_6, KEY_7, KEY_8, KEY_9, KEY_0,
KEY_MINUS, KEY_EQUAL, KEY_BACKSPACE, KEY_TAB,
KEY_Q, KEY_W, KEY_E, KEY_R, KEY_T, KEY_Y, KEY_U, KEY_I, KEY_O, KEY_P,
KEY_LEFT_BRACKET, KEY_RIGHT_BRACKET, KEY_RETURN, KEY_LEFT_CTRL,
KEY_A, KEY_S, KEY_D, KEY_F, KEY_G, KEY_H, KEY_J, KEY_K, KEY_L,
KEY_SEMICOLON, KEY_APOSTROPHE, KEY_BACK_TICK, KEY_LEFT_SHIFT, KEY_BACKSLASH,
KEY_Z, KEY_X, KEY_C, KEY_V, KEY_B, KEY_N, KEY_M,
KEY_COMMA, KEY_PERIOD, KEY_SLASH, KEY_RIGHT_SHIFT,
KEYPAD_ASTERISK, KEY_LEFT_ALT, KEY_SPACE, KEY_CAPS_LOCK,
KEY_F1, KEY_F2, KEY_F3, KEY_F4, KEY_F5, KEY_F6, KEY_F7, KEY_F8, KEY_F9, KEY_F10,
KEY_NUM_LOCK, KEY_SCROLL_LOCK,
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,
KEY_NULL, KEY_NULL, KEY_NULL,
KEY_F11, KEY_F12};
const unsigned short ScanCodeSet1mm[] = {
[0x10] = KEY_MULTIMEDIA_PREV_TRACK,
[0x19] = KEY_MULTIMEDIA_NEXT_TRACK,
[0x1C] = KEYPAD_RETURN,
[0x1D] = KEY_RIGHT_CTRL,
[0x20] = KEY_MULTIMEDIA_MUTE,
[0x21] = KEY_MULTIMEDIA_CALCULATOR,
[0x22] = KEY_MULTIMEDIA_PLAY,
[0x24] = KEY_MULTIMEDIA_STOP,
[0x2A] = KEY_PRINT_SCREEN,
[0x2E] = KEY_MULTIMEDIA_VOL_DOWN,
[0x30] = KEY_MULTIMEDIA_VOL_UP,
[0x32] = KEY_MULTIMEDIA_WWW_HOME,
[0x35] = KEYPAD_SLASH,
[0x37] = KEY_PRINT_SCREEN,
[0x38] = KEY_RIGHT_ALT,
[0x47] = KEY_HOME,
[0x48] = KEY_UP_ARROW,
[0x49] = KEY_PAGE_UP,
[0x4B] = KEY_LEFT_ARROW,
[0x4D] = KEY_RIGHT_ARROW,
[0x4F] = KEY_END,
[0x50] = KEY_DOWN_ARROW,
[0x51] = KEY_PAGE_DOWN,
[0x52] = KEY_INSERT,
[0x53] = KEY_DELETE,
[0x5B] = KEY_LEFT_GUI,
[0x5C] = KEY_RIGHT_GUI,
[0x5D] = KEY_APPS,
[0x5E] = KEY_ACPI_POWER,
[0x5F] = KEY_ACPI_SLEEP,
[0x63] = KEY_ACPI_WAKE,
[0x65] = KEY_MULTIMEDIA_WWW_SEARCH,
[0x66] = KEY_MULTIMEDIA_WWW_FAVORITES,
[0x67] = KEY_MULTIMEDIA_WWW_REFRESH,
[0x68] = KEY_MULTIMEDIA_WWW_STOP,
[0x69] = KEY_MULTIMEDIA_WWW_FORWARD,
[0x6A] = KEY_MULTIMEDIA_WWW_BACK,
[0x6B] = KEY_MULTIMEDIA_MY_COMPUTER,
[0x6C] = KEY_MULTIMEDIA_EMAIL,
[0x6D] = KEY_MULTIMEDIA_MEDIA_SELECT,
/* RELEASED */
[0x90] = KEY_MULTIMEDIA_PREV_TRACK,
[0x99] = KEY_MULTIMEDIA_NEXT_TRACK,
[0x9C] = KEYPAD_RETURN,
[0x9D] = KEY_RIGHT_CTRL,
[0xA0] = KEY_MULTIMEDIA_MUTE,
[0xA1] = KEY_MULTIMEDIA_CALCULATOR,
[0xA2] = KEY_MULTIMEDIA_PLAY,
[0xA4] = KEY_MULTIMEDIA_STOP,
[0xAA] = KEY_PRINT_SCREEN,
[0xAE] = KEY_MULTIMEDIA_VOL_DOWN,
[0xB0] = KEY_MULTIMEDIA_VOL_UP,
[0xB2] = KEY_MULTIMEDIA_WWW_HOME,
[0xB5] = KEYPAD_SLASH,
[0xB7] = KEY_PRINT_SCREEN,
[0xB8] = KEY_RIGHT_ALT,
[0xC7] = KEY_HOME,
[0xC8] = KEY_UP_ARROW,
[0xC9] = KEY_PAGE_UP,
[0xCB] = KEY_LEFT_ARROW,
[0xCD] = KEY_RIGHT_ARROW,
[0xCF] = KEY_END,
[0xD0] = KEY_DOWN_ARROW,
[0xD1] = KEY_PAGE_DOWN,
[0xD2] = KEY_INSERT,
[0xD3] = KEY_DELETE,
[0xDB] = KEY_LEFT_GUI,
[0xDC] = KEY_RIGHT_GUI,
[0xDD] = KEY_APPS,
[0xDE] = KEY_ACPI_POWER,
[0xDF] = KEY_ACPI_SLEEP,
[0xE3] = KEY_ACPI_WAKE,
[0xE5] = KEY_MULTIMEDIA_WWW_SEARCH,
[0xE6] = KEY_MULTIMEDIA_WWW_FAVORITES,
[0xE7] = KEY_MULTIMEDIA_WWW_REFRESH,
[0xE8] = KEY_MULTIMEDIA_WWW_STOP,
[0xE9] = KEY_MULTIMEDIA_WWW_FORWARD,
[0xEA] = KEY_MULTIMEDIA_WWW_BACK,
[0xEB] = KEY_MULTIMEDIA_MY_COMPUTER,
[0xEC] = KEY_MULTIMEDIA_EMAIL,
[0xED] = KEY_MULTIMEDIA_MEDIA_SELECT};
const unsigned short ScanCodeSet3[] = {
[0x15] = KEY_Q,
[0x1A] = KEY_Z,
[0x1B] = KEY_S,
[0x1C] = KEY_A,
[0x1D] = KEY_W,
[0x21] = KEY_C,
[0x22] = KEY_X,
[0x23] = KEY_D,
[0x24] = KEY_E,
[0x2A] = KEY_V,
[0x2B] = KEY_F,
[0x2C] = KEY_T,
[0x2D] = KEY_R,
[0x31] = KEY_N,
[0x32] = KEY_B,
[0x33] = KEY_H,
[0x34] = KEY_G,
[0x35] = KEY_Y,
[0x3A] = KEY_M,
[0x3B] = KEY_J,
[0x3C] = KEY_U,
[0x42] = KEY_K,
[0x43] = KEY_I,
[0x44] = KEY_O,
[0x4B] = KEY_L,
[0x4D] = KEY_P};
bool IsE0 = false;
bool IsE1 = false;
void PS2KbdInterruptHandler(TrapFrame *)
{
uint8_t sc = inb(PS2_DATA);
if (sc == PS2_KBD_RESP_ACK ||
sc == PS2_KBD_RESP_ECHO ||
sc == PS2_KBD_RESP_RESEND)
return;
if (sc == 0xE0)
{
IsE0 = true;
return;
}
if (sc == 0xE1)
{
IsE1 = true;
return;
}
switch (KeyboardScanCodeSet)
{
case PS2_KBD_SC_SET_1:
case PS2_KBD_SC_SET_2:
{
if (IsE0)
{
IsE0 = false;
ReportKeyboardEvent(KeyboardDevID, ScanCodeSet1mm[sc], sc < 0x90);
return;
}
else
{
bool released = sc & 0x80;
uint8_t scFinal = released ? sc & 0x7F : sc;
ReportKeyboardEvent(KeyboardDevID, ScanCodeSet1[scFinal], !released);
return;
}
}
/* FIXME: https://wiki.osdev.org/PS/2_Keyboard */
// case PS2_KBD_SC_SET_2:
// {
// break;
// }
case PS2_KBD_SC_SET_3:
{
ReportKeyboardEvent(KeyboardDevID, ScanCodeSet3[sc], true);
ReportKeyboardEvent(KeyboardDevID, ScanCodeSet3[sc], false);
break;
}
default:
{
if (IsE0)
IsE0 = false;
Log("Unknown PS/2 Keyboard Scan Code Set: %#x", KeyboardScanCodeSet);
break;
}
}
}
int InitializeKeyboard()
{
// PS2WriteData(PS2_KBD_CMD_RESET);
// uint8_t test = PS2ReadData();
// if (test != PS2_KBD_RESP_TEST_PASSED &&
// test != PS2_KBD_RESP_ACK)
// {
// Log("PS/2 keyboard reset failed (%#x)", test);
// return -EFAULT;
// }
PS2WriteData(PS2_KBD_CMD_DEFAULTS);
if (PS2ACKTimeout() != 0)
Log("PS/2 keyboard failed to set defaults");
PS2WriteData(PS2_KBD_CMD_SCAN_CODE_SET);
if (PS2ACKTimeout() != 0)
Log("PS/2 keyboard failed to set scan code set");
/* We want Scan Code Set 1 */
PS2WriteData(PS2_KBD_SCAN_CODE_SET_2); /* It will set to 1 but with translation? */
if (PS2ACKTimeout() != 0)
Log("PS/2 keyboard failed to set scan code set 2");
PS2WriteData(PS2_KBD_CMD_SCAN_CODE_SET);
if (PS2ACKTimeout() != 0)
Log("PS/2 keyboard failed to set scan code set");
PS2WriteData(PS2_KBD_SCAN_CODE_GET_CURRENT);
if (PS2ACKTimeout() != 0)
Log("PS/2 keyboard failed to get current scan code set");
KeyboardScanCodeSet = PS2ReadAfterACK();
Log("PS/2 Keyboard Scan Code Set: 0x%X", KeyboardScanCodeSet);
PS2ClearOutputBuffer();
PS2WriteData(PS2_KBD_CMD_ENABLE_SCANNING);
RegisterInterruptHandler(1, PS2KbdInterruptHandler);
KeyboardDevID = RegisterInputDevice(ddt_Keyboard);
return 0;
}
int FinalizeKeyboard()
{
UnregisterInputDevice(KeyboardDevID, ddt_Keyboard);
return 0;
}
int DetectPS2Keyboard()
{
PS2WriteData(PS2_KBD_CMD_DISABLE_SCANNING);
if (PS2ACKTimeout() != 0)
Log("PS/2 keyboard failed to disable scanning");
PS2WriteData(PS2_KBD_CMD_IDENTIFY);
if (PS2ACKTimeout() != 0)
Log("PS/2 keyboard failed to identify");
uint8_t recByte;
int timeout = 1000000;
while (timeout--)
{
recByte = PS2ReadData();
if (recByte != PS2_ACK)
break;
}
Device1ID[0] = recByte;
timeout = 1000000;
while (timeout--)
{
recByte = PS2ReadData();
if (recByte != PS2_ACK)
break;
}
if (timeout == 0)
Log("PS/2 keyboard second byte timed out");
else
Device1ID[1] = recByte;
Log("PS2 Keyboard Device: 0x%X 0x%X", Device1ID[0], Device1ID[1]);
return 0;
}

234
input/aip/main.c Normal file
View File

@ -0,0 +1,234 @@
/*
This file is part of Fennix Drivers.
Fennix Drivers 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 Drivers 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 Drivers. If not, see <https://www.gnu.org/licenses/>.
*/
#include "aip.h"
#include <errno.h>
#include <base.h>
bool IsKeyboard(uint8_t ID)
{
/* Common keyboard IDs */
return ID == 0xAB || ID == 0xAC || ID == 0x5D ||
ID == 0x2B || ID == 0x47 || ID == 0x60;
}
bool IsMouse(uint8_t ID)
{
/* Common mouse IDs */
return ID == 0x00 || ID == 0x03 || ID == 0x04;
}
const char *GetPS2DeviceName(uint8_t ID, uint8_t SubID)
{
switch (ID)
{
case 0x00:
return "Standard PS/2 Mouse";
case 0x03:
return "Mouse with scroll wheel";
case 0x04:
return "Mouse 5 buttons";
case 0xAB:
{
switch (SubID)
{
case 0x83: /* Normal */
case 0x41: /* Translated */
case 0xC1: /* Normal + Translated */
return "Standard PS/2 Keyboard";
case 0x84:
case 0x54:
return "IBM Thinkpad/Spacesaver Keyboard";
case 0x85:
return "NCD N-97/122-Key Host Connect(ed) Keyboard";
case 0x86:
return "122-Key Keyboard";
case 0x90:
return "Japanese \"G\" Keyboard";
case 0x91:
return "Japanese \"P\" Keyboard";
case 0x92:
return "Japanese \"A\" Keyboard";
default:
return "Unknown PS/2 Keyboard";
}
}
case 0xAC:
{
switch (SubID)
{
case 0xA1:
return "NCD Sun Keyboard";
default:
return "Unknown NCD Sun Keyboard";
}
}
case 0x5D:
case 0x2B:
return "Trust Keyboard";
case 0x47:
case 0x60:
return "NMB SGI Keyboard";
default:
return "Unknown PS/2 Device";
}
}
uint8_t Device1ID[2] = {0x00, 0x00};
uint8_t Device2ID[2] = {0x00, 0x00};
bool DualChannel = false;
int DriverEntry()
{
PS2WriteCommand(PS2_CMD_DISABLE_PORT_1);
PS2WriteCommand(PS2_CMD_DISABLE_PORT_2);
PS2ClearOutputBuffer();
PS2WriteCommand(PS2_CMD_READ_CONFIG);
PS2_CONFIGURATION cfg = {.Raw = PS2ReadData()};
DualChannel = cfg.Port2Clock;
if (DualChannel)
Log("Dual channel PS/2 controller detected");
cfg.Port1Interrupt = 1;
cfg.Port2Interrupt = 1;
cfg.Port1Translation = 1;
PS2WriteCommand(PS2_CMD_WRITE_CONFIG);
PS2WriteData(cfg.Raw);
PS2WriteCommand(PS2_CMD_TEST_CONTROLLER);
uint8_t test = PS2ReadData();
if (test != PS2_TEST_PASSED)
{
Log("PS/2 controller self test failed (%#x)", test);
return -EFAULT;
}
PS2WriteCommand(PS2_CMD_WRITE_CONFIG);
PS2WriteData(cfg.Raw);
// bool port2avail = false;
// if (DualChannel)
// {
// PS2WriteCommand(PS2_CMD_ENABLE_PORT_1);
// PS2WriteCommand(PS2_CMD_READ_CONFIG);
// cfg.Raw = PS2ReadData();
// port2avail = cfg.Port2Clock;
// PS2WriteCommand(PS2_CMD_DISABLE_PORT_1);
// }
PS2WriteCommand(PS2_CMD_TEST_PORT_1);
test = PS2ReadData();
if (test != 0x00)
{
Log("PS/2 Port 1 self test failed (%#x)", test);
return -EFAULT;
}
if (DualChannel)
{
PS2WriteCommand(PS2_CMD_TEST_PORT_2);
test = PS2ReadData();
if (test != 0x00)
{
Log("PS/2 Port 2 self test failed (%#x)", test);
return -EFAULT;
}
}
PS2WriteCommand(PS2_CMD_ENABLE_PORT_1);
if (DualChannel)
PS2WriteCommand(PS2_CMD_ENABLE_PORT_2);
int errK = InitializeKeyboard();
int errM = 0;
if (DualChannel)
errM = InitializeMouse();
/** A device may fail, but if the other one works,
* we can still use it.
*/
if (errK != 0 && errM != 0)
return -ENODEV;
return 0;
}
int DriverFinal()
{
FinalizeKeyboard();
FinalizeMouse();
PS2WriteCommand(PS2_CMD_DISABLE_PORT_1);
PS2WriteCommand(PS2_CMD_DISABLE_PORT_2);
return 0;
}
int DriverPanic()
{
PS2WriteCommand(PS2_CMD_DISABLE_PORT_1);
PS2WriteCommand(PS2_CMD_DISABLE_PORT_2);
return 0;
}
void __intStub() {}
int DriverProbe()
{
RegisterInterruptHandler(1, __intStub);
RegisterInterruptHandler(12, __intStub);
int kbd = DetectPS2Keyboard();
int mouse = DetectPS2Mouse();
UnregisterAllInterruptHandlers(__intStub);
if (kbd != 0 && mouse != 0)
return -ENODEV;
if (kbd == 0)
{
if (!IsKeyboard(Device1ID[0]))
{
Log("PS/2 Port 1 is not a keyboard");
// return -EINVAL;
}
}
if (mouse == 0)
{
if (!IsMouse(Device2ID[0]))
{
Log("PS/2 Port 2 is not a mouse");
// return -EINVAL;
}
}
KPrint("PS/2 Port 1: %s (0x%X 0x%X)",
GetPS2DeviceName(Device1ID[0], Device1ID[1]),
Device1ID[0], Device1ID[1]);
KPrint("PS/2 Port 2: %s (0x%X 0x%X)",
GetPS2DeviceName(Device2ID[0], Device2ID[1]),
Device2ID[0], Device2ID[1]);
return 0;
}
DriverInfo("aip",
"Advanced Integrated Peripheral Driver",
"EnderIce2",
"0.1",
"GPLv3");

233
input/aip/mouse.c Normal file
View File

@ -0,0 +1,233 @@
/*
This file is part of Fennix Drivers.
Fennix Drivers 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 Drivers 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 Drivers. If not, see <https://www.gnu.org/licenses/>.
*/
#include "aip.h"
#include <errno.h>
#include <input.h>
#include <base.h>
dev_t MouseDevID = -1;
bool PacketReady = false;
bool FourPackets = false;
bool MouseButton45 = false;
uint8_t Cycle = 0;
PS2_MOUSE_PACKET Packet = {0};
void PS2MouseInterruptHandler(TrapFrame *)
{
uint8_t data = PS2ReadData();
if (data == PS2_MOUSE_RESP_ACK ||
data == PS2_MOUSE_RESP_RESEND)
return;
if (!PacketReady)
{
switch (Cycle)
{
case 0:
{
if ((data & 0b00001000 /* Always 1 */) == 0)
return;
Packet.Base.Raw = data;
Cycle++;
break;
}
case 1:
{
Packet.XMovement = data;
Cycle++;
break;
}
case 2:
{
Packet.YMovement = data;
if (FourPackets)
Cycle++;
else
{
Cycle = 0;
PacketReady = true;
}
break;
}
case 3:
{
Packet.ZMovement.Raw = data;
Cycle = 0;
PacketReady = true;
break;
}
default:
break;
}
return;
}
/* https://stackoverflow.com/a/3208376/9352057 */
#define BYTE_TO_BINARY_PATTERN "%c%c%c%c%c%c%c%c"
#define BYTE_TO_BINARY(byte) \
((byte) & 0x80 ? '1' : '0'), \
((byte) & 0x40 ? '1' : '0'), \
((byte) & 0x20 ? '1' : '0'), \
((byte) & 0x10 ? '1' : '0'), \
((byte) & 0x08 ? '1' : '0'), \
((byte) & 0x04 ? '1' : '0'), \
((byte) & 0x02 ? '1' : '0'), \
((byte) & 0x01 ? '1' : '0')
DebugLog("PS/2 Mouse Packet: [" BYTE_TO_BINARY_PATTERN ":" BYTE_TO_BINARY_PATTERN ":" BYTE_TO_BINARY_PATTERN ":" BYTE_TO_BINARY_PATTERN "] LB:%d RB:%d MB:%d A1:%d XS:%d YS:%d XO:%d YO:%d | X:%03d Y:%03d | Z:%d B4:%d B5:%d A0:%d A0:%d",
BYTE_TO_BINARY(Packet.Base.Raw),
BYTE_TO_BINARY(Packet.XMovement),
BYTE_TO_BINARY(Packet.YMovement),
BYTE_TO_BINARY(Packet.ZMovement.Raw),
Packet.Base.LeftButton, Packet.Base.RightButton, Packet.Base.MiddleButton,
Packet.Base.Always1,
Packet.Base.XSign, Packet.Base.YSign,
Packet.Base.XOverflow, Packet.Base.YOverflow,
Packet.XMovement, Packet.YMovement,
Packet.ZMovement.Z, Packet.ZMovement.Button4, Packet.ZMovement.Button5,
Packet.ZMovement.Always0, Packet.ZMovement.Always0_2);
int X, Y;
X = Packet.XMovement - (Packet.Base.XSign ? 256 : 0);
Y = Packet.YMovement - (Packet.Base.YSign ? 256 : 0);
if (Packet.Base.XOverflow)
X = 0;
if (Packet.Base.YOverflow)
Y = 0;
MouseReport mr = {
.LeftButton = Packet.Base.LeftButton,
.RightButton = Packet.Base.RightButton,
.MiddleButton = Packet.Base.MiddleButton,
.Button4 = Packet.ZMovement.Button4,
.Button5 = Packet.ZMovement.Button5,
.X = X,
.Y = -Y,
.Z = Packet.ZMovement.Z,
};
ReportRelativeMouseEvent(MouseDevID, mr);
PacketReady = false;
}
void MouseSampleRate(uint8_t SampleRate)
{
PS2WriteCommand(PS2_CMD_WRITE_NEXT_BYTE_TO_PS2_PORT_2_INPUT);
PS2WriteData(PS2_MOUSE_CMD_SET_SAMPLE_RATE);
PS2ReadData();
PS2WriteCommand(PS2_CMD_WRITE_NEXT_BYTE_TO_PS2_PORT_2_INPUT);
PS2WriteData(SampleRate);
PS2ReadData();
}
int InitializeMouse()
{
PS2WriteData(PS2_CMD_WRITE_NEXT_BYTE_TO_PS2_PORT_2_INPUT);
PS2WriteData(PS2_MOUSE_CMD_RESET);
uint8_t test = PS2ReadData();
if (test != PS2_MOUSE_RESP_TEST_PASSED &&
test != PS2_MOUSE_RESP_ACK)
{
Log("PS/2 mouse reset failed! (%#x)", test);
return -EFAULT;
}
RegisterInterruptHandler(12, PS2MouseInterruptHandler);
MouseDevID = RegisterInputDevice(ddt_Mouse);
PS2WriteCommand(PS2_CMD_WRITE_NEXT_BYTE_TO_PS2_PORT_2_INPUT);
PS2WriteData(PS2_MOUSE_CMD_SET_DEFAULTS);
PS2ReadData();
PS2WriteCommand(PS2_CMD_WRITE_NEXT_BYTE_TO_PS2_PORT_2_INPUT);
PS2WriteData(PS2_MOUSE_CMD_ENABLE_DATA_REPORTING);
MouseSampleRate(200);
MouseSampleRate(100);
MouseSampleRate(80);
PS2WriteCommand(PS2_CMD_WRITE_NEXT_BYTE_TO_PS2_PORT_2_INPUT);
PS2WriteData(PS2_MOUSE_CMD_READ_ID);
uint8_t Device2ID = PS2ReadData();
Log("PS/2 Mouse ID: %#x", Device2ID);
MouseSampleRate(200);
MouseSampleRate(200);
MouseSampleRate(80);
PS2WriteCommand(PS2_CMD_WRITE_NEXT_BYTE_TO_PS2_PORT_2_INPUT);
PS2WriteData(PS2_MOUSE_CMD_READ_ID);
Device2ID = PS2ReadData();
Log("PS/2 Mouse ID: %#x", Device2ID);
if (Device2ID >= 3 && Device2ID <= 4)
FourPackets = true;
if (Device2ID == 4)
MouseButton45 = true;
return 0;
}
int FinalizeMouse()
{
UnregisterInputDevice(MouseDevID, ddt_Mouse);
PS2WriteCommand(PS2_CMD_WRITE_NEXT_BYTE_TO_PS2_PORT_2_INPUT);
PS2WriteData(PS2_MOUSE_CMD_DISABLE_DATA_REPORTING);
return 0;
}
int DetectPS2Mouse()
{
PS2WriteCommand(PS2_CMD_WRITE_NEXT_BYTE_TO_PS2_PORT_2_INPUT);
PS2WriteData(PS2_MOUSE_CMD_DISABLE_DATA_REPORTING);
if (PS2ACKTimeout() != 0)
Log("PS/2 mouse failed to disable data reporting!");
PS2WriteCommand(PS2_CMD_WRITE_NEXT_BYTE_TO_PS2_PORT_2_INPUT);
PS2WriteData(PS2_MOUSE_CMD_READ_ID);
if (PS2ACKTimeout() != 0)
Log("PS/2 mouse failed to read ID!");
uint8_t recByte;
int timeout = 1000000;
while (timeout--)
{
recByte = PS2ReadData();
if (recByte != PS2_ACK)
break;
}
Device2ID[0] = recByte;
timeout = 1000000;
while (timeout--)
{
recByte = PS2ReadData();
if (recByte != PS2_ACK)
break;
}
Device2ID[1] = recByte;
Log("PS2 Mouse Device: 0x%X 0x%X", Device2ID[0], Device2ID[1]);
return 0;
}