diff options
| author | cpplover0 <osdev555@yandex.com> | 2026-02-22 13:06:37 +0300 |
|---|---|---|
| committer | cpplover0 <osdev555@yandex.com> | 2026-02-22 13:06:37 +0300 |
| commit | 9f0c014b08f33f44eb7134969c0e7ed509e3adfc (patch) | |
| tree | 52b38e3a56fd8219b1d117f6cfc7525070f2b7d9 | |
| parent | a3a018cc1a66fa6c63c1758986d2faad23dd0d9f (diff) | |
ps2 driver
| -rw-r--r-- | GNUmakefile | 2 | ||||
| -rw-r--r-- | kernel/include/drivers/ps2.hpp | 19 | ||||
| -rw-r--r-- | kernel/src/drivers/ps2.cpp | 326 | ||||
| -rw-r--r-- | kernel/src/main.cpp | 4 |
4 files changed, 350 insertions, 1 deletions
diff --git a/GNUmakefile b/GNUmakefile index 4f645c2..1bb2758 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -3,7 +3,7 @@ MAKEFLAGS += -rR .SUFFIXES: # Default user QEMU flags. These are appended to the QEMU command calls. -QEMUFLAGS := -m 8G -d int -s -M q35 -smp 1 -enable-kvm -serial stdio -cpu host,+invtsc -device qemu-xhci -device usb-kbd -device usb-mouse +QEMUFLAGS := -m 8G -d int -s -M q35 -smp 1 -enable-kvm -serial stdio -cpu host,+invtsc override IMAGE_NAME := orange diff --git a/kernel/include/drivers/ps2.hpp b/kernel/include/drivers/ps2.hpp new file mode 100644 index 0000000..13e184c --- /dev/null +++ b/kernel/include/drivers/ps2.hpp @@ -0,0 +1,19 @@ + +namespace drivers { + + #define PS2_DATA 0x60 + #define PS2_STATUS 0x64 + #define PS2_CMD 0x64 + #define CMD_DISABLE_MOUSE 0xA7 + #define CMD_DISABLE_KEYBOARD 0xAD + #define CMD_READ_CONFIG 0x20 + #define CMD_WRITE_CONFIG 0x60 + #define CMD_SELF_TEST 0xAA + #define CMD_ENABLE_MOUSE 0xA8 + #define CMD_ENABLE_KEYBOARD 0xAE + + class ps2 { + public: + static void init(); + }; +};
\ No newline at end of file diff --git a/kernel/src/drivers/ps2.cpp b/kernel/src/drivers/ps2.cpp new file mode 100644 index 0000000..a0f5dbf --- /dev/null +++ b/kernel/src/drivers/ps2.cpp @@ -0,0 +1,326 @@ +#include <drivers/tsc.hpp> +#include <generic/mm/paging.hpp> +#include <generic/mm/pmm.hpp> +#include <generic/mm/heap.hpp> +#include <generic/vfs/vfs.hpp> +#include <etc/etc.hpp> +#include <etc/logging.hpp> + +#include <drivers/pci.hpp> +#include <generic/vfs/evdev.hpp> + +#include <arch/x86_64/scheduling.hpp> +#include <drivers/ps2.hpp> + +#include <etc/assembly.hpp> +#include <drivers/io.hpp> + +void ps2_wait_write() { + drivers::io io; + while (io.inb(PS2_STATUS) & (1 << 1)); +} + +void ps2_wait_read() { + drivers::io io; + while (!(io.inb(PS2_STATUS) & (1 << 0))); +} + +void ps2_writecmddata(char cmd, char data) { + drivers::io io; + ps2_wait_write(); + io.wait(); + io.outb(PS2_STATUS, cmd); + io.wait(); + io.outb(PS2_DATA, data); +} + +void ps2_writecmd(char cmd) { + drivers::io io; + ps2_wait_write(); + io.outb(PS2_STATUS, cmd); +} + +void ps2_writedata(char cmd) { + drivers::io io; + ps2_wait_write(); + io.outb(PS2_DATA, cmd); +} + +char ps2_not_empty() { + drivers::io io; + return (io.inb(PS2_STATUS) & 1) == 0; +} + +int ps2_is_timeout = 0; + +char ps2_read_data() { + drivers::io io; + int timeout = 0; + while(ps2_not_empty()) { + if(timeout++ == 100) { + ps2_is_timeout = 1; + return 0; + } + drivers::tsc::sleep(100); + } + return io.inb(PS2_DATA); +} + +void ps2_flush() { + drivers::io io; + while(io.inb(PS2_STATUS) & (1 << 0)) { + io.inb(PS2_DATA); + } +} + +#define STATUS 0x64 +#define COMMAND 0x64 +#define DATA 0x60 +#define RESEND 0xFE +#define ACK 0xFA +#define ECHO 0xEE + +void ps2_writeport(uint8_t port, uint8_t cmd) { + if(port == 2) + ps2_writecmd(0xD4); + + ps2_writedata(cmd); +} + +static inline char ps2_wait() { + drivers::io io; + return (io.inb(0x64) & 1) == 0; +} + +uint8_t ps2_readtimeout() { + drivers::io io; + int timeout = 100; + while(ps2_wait() && --timeout > 0) drivers::tsc::sleep(100); + if(timeout <= 0) + return 0; + return io.inb(0x60); +} + +void ps2_enableport(uint8_t port) { + ps2_writeport(port,0xF4); + int retry = 0; + while(1) { + uint8_t response = ps2_readtimeout(); + if(!response) + break; + else if(response == ACK) + break; + else if(response == RESEND) { + if(++retry == 10) + break; + ps2_writeport(port,0xF4); + } + } + ps2_flush(); +} + +#define MOUSE_LB (1 << 0) +#define MOUSE_RB (1 << 1) +#define MOUSE_MB (1 << 2) +#define MOUSE_B4 (1 << 3) +#define MOUSE_B5 (1 << 4) + +/* +input0_fd = open("/dev/masterps2keyboard",O_RDWR); + mouse_fd = open("/dev/mastermouse",O_RDWR); +*/ + +#define REL_X 0x00 +#define REL_Y 0x01 +#define REL_Z 0x02 +#define REL_RX 0x03 +#define REL_RY 0x04 +#define REL_RZ 0x05 +#define REL_HWHEEL 0x06 +#define REL_DIAL 0x07 +#define REL_WHEEL 0x08 +#define REL_MISC 0x09 + +typedef struct { + unsigned char buttons; + unsigned char x; + unsigned char y; + unsigned char z; +} __attribute__((packed)) mouse_packet_t; + +int mouse_evdev = 0; +int kbd_evdev = 0; + +mouse_packet_t last_pack = {0}; + +void ps2_process(void* arg) { + int mouse_seq = 0; + drivers::io io; + if(1) { + + uint8_t mouse_buffer[4] = {0,0,0,0}; + + while(1) { + + if(1) { + + int val = 1; + + uint8_t status = io.inb(0x64); + while(status & 1) { + int data = io.inb(DATA); + + if(status & (1 << 5)) { + mouse_buffer[mouse_seq++] = data; + + if(mouse_seq == 3) { + mouse_packet_t packet = {0,0,0,0}; + + packet.x = mouse_buffer[1] - (mouse_buffer[0] & 0x10 ? 0x100 : 0); + packet.y = mouse_buffer[2] - (mouse_buffer[0] & 0x20 ? 0x100 : 0); + packet.z = (mouse_buffer[3] & 0x7) * (mouse_buffer[3] & 0x8 ? -1 : 1); + + packet.buttons |= (mouse_buffer[0] & 1) ? MOUSE_LB : 0; + packet.buttons |= (mouse_buffer[0] & 2) ? MOUSE_RB : 0; + packet.buttons |= (mouse_buffer[0] & 4) ? MOUSE_MB : 0; + + packet.buttons |= (mouse_buffer[0] & 0x10) ? MOUSE_B4 : 0; + packet.buttons |= (mouse_buffer[0] & 0x20) ? MOUSE_B5 : 0; + + userspace_fd_t fd; + memset(&fd,0,sizeof(userspace_fd_t)); + memcpy(fd.path,"/dev/mastermouse",strlen("/dev/mastermouse")); + fd.is_cached_path = 1; + + asm volatile("cli"); + std::uint64_t current_nano = drivers::tsc::currentnano(); + input_event ev; + ev.time.tv_sec = current_nano / 1000000000; + ev.time.tv_usec = (current_nano & 1000000000) / 1000; + if(packet.x) { + ev.code = REL_X; + ev.type = 2; + ev.value = (packet.x & 0x80) ? (packet.x | 0xFFFFFF00) : packet.x; + vfs::evdev::submit(mouse_evdev,ev); + } + + if(packet.y) { + ev.code = REL_Y; + ev.type = 2; + ev.value = (packet.y & 0x80) ? (packet.y | 0xFFFFFF00) : packet.y; + vfs::evdev::submit(mouse_evdev,ev); + } + + if(packet.z) { + ev.code = REL_Z; + ev.type = 2; + ev.value = (packet.z & 0x80) ? (packet.z | 0xFFFFFF00) : packet.z; + vfs::evdev::submit(mouse_evdev,ev); + } + + if((packet.buttons & MOUSE_LB) && !(last_pack.buttons & MOUSE_LB)) { + ev.code = 272; + ev.type = 1; + ev.value = 1; + vfs::evdev::submit(mouse_evdev,ev); + } else if(!(packet.buttons & MOUSE_LB) && (last_pack.buttons & MOUSE_LB)) { + ev.code = 272; + ev.type = 1; + ev.value = 0; + vfs::evdev::submit(mouse_evdev,ev); + } + + if((packet.buttons & MOUSE_RB) && !(last_pack.buttons & MOUSE_RB)) { + ev.code = 273; + ev.type = 1; + ev.value = 1; + vfs::evdev::submit(mouse_evdev,ev); + } else if(!(packet.buttons & MOUSE_RB) && (last_pack.buttons & MOUSE_RB)) { + ev.code = 273; + ev.type = 1; + ev.value = 0; + vfs::evdev::submit(mouse_evdev,ev); + } + + if((packet.buttons & MOUSE_MB) && !(last_pack.buttons & MOUSE_MB)) { + ev.code = 274; + ev.type = 1; + ev.value = 1; + vfs::evdev::submit(mouse_evdev,ev); + } else if(!(packet.buttons & MOUSE_MB) && (last_pack.buttons & MOUSE_MB)) { + ev.code = 274; + ev.type = 1; + ev.value = 0; + vfs::evdev::submit(mouse_evdev,ev); + } + + asm volatile("sti"); + + last_pack = packet; + + mouse_seq = 0; + + } + + } else { + userspace_fd_t fd; + memset(&fd,0,sizeof(userspace_fd_t)); + memcpy(fd.path,"/dev/masterps2keyboard",strlen("/dev/masterps2keyboard")); + fd.is_cached_path = 1; + + std::uint64_t current_nano = drivers::tsc::currentnano(); + + asm volatile("cli"); + input_event ev; + ev.time.tv_sec = current_nano / 1000000000; + ev.time.tv_usec = (current_nano & 1000000000) / 1000; + ev.type = 1; + ev.code = data & ~(1 << 7); + ev.value = (data & (1 << 7)) ? 0 : 1; + vfs::evdev::submit(kbd_evdev,ev); + vfs::vfs::write(&fd,&data,1); + asm volatile("sti"); + } + + status = io.inb(0x64); + } + asm volatile("cli"); + yield(); + asm volatile("sti"); + } + } + } +} + +void drivers::ps2::init() { + ps2_flush(); + ps2_writecmd(CMD_READ_CONFIG); + std::uint8_t ctrl = (std::uint8_t)ps2_read_data(); + if(ps2_is_timeout) { + Log::Display(LEVEL_MESSAGE_FAIL,"ps2: there's no ps2 controller !\n"); + return; + } + + ps2_writecmd(0xAD); + ps2_writecmd(0xA7); + + ps2_writecmd(0x20); + uint8_t config = ps2_read_data(); + config |= (1 << 0) | (1 << 1) | (1 << 6); + ps2_writecmd(0x60); + ps2_writedata(config); + + ps2_enableport(1); + ps2_enableport(2); + + ps2_writecmd(0xAE); + ps2_writecmd(0xA8); + + ps2_flush(); + + mouse_evdev = vfs::evdev::create("Generic PS/2 Mouse",EVDEV_TYPE_MOUSE); + kbd_evdev = vfs::evdev::create("Generic PS/2 Keyboard",EVDEV_TYPE_KEYBOARD); + + arch::x86_64::scheduling::create_kernel_thread(ps2_process,0); + Log::Display(LEVEL_MESSAGE_INFO,"PS/2 Initializied\n"); +}
\ No newline at end of file diff --git a/kernel/src/main.cpp b/kernel/src/main.cpp index 321f7d9..292386e 100644 --- a/kernel/src/main.cpp +++ b/kernel/src/main.cpp @@ -29,6 +29,8 @@ #include <etc/etc.hpp> #include <limine.h> +#include <drivers/ps2.hpp> + #include <generic/vfs/fd.hpp> char is_shift_pressed = 0; @@ -207,6 +209,8 @@ extern "C" void main() { drivers::pci::initworkspace(); Log::Display(LEVEL_MESSAGE_OK,"PCI initializied\n"); + drivers::ps2::init(); + vfs::ustar::copy(); Log::Display(LEVEL_MESSAGE_OK,"USTAR parsed\n"); |
