#include "mouse.h" #include "isr.h" #include "common.h" #include "device.h" #include "alloc.h" #include "devfs.h" #include "list.h" #include "fifobuffer.h" #include "spinlock.h" static void handleMouseInterrupt(Registers *regs); static uint8 gMouseByteCounter = 0; static void prepareForRead(); static void prepareForWrite(); static void writeMouse(uint8 data); static void handleMouseInterrupt(Registers *regs); static BOOL mouse_open(File *file, uint32 flags); static void mouse_close(File *file); static int32 mouse_read(File *file, uint32 size, uint8 *buffer); #define MOUSE_PACKET_SIZE 3 uint8 gMousePacket[MOUSE_PACKET_SIZE]; static List* gReaders = NULL; static Spinlock gReadersLock; void initializeMouse() { Device device; memset((uint8*)&device, 0, sizeof(Device)); strcpy(device.name, "psaux"); device.deviceType = FT_CharacterDevice; device.open = mouse_open; device.close = mouse_close; device.read = mouse_read; registerInterruptHandler(IRQ12, handleMouseInterrupt); registerDevice(&device); memset(gMousePacket, 0, MOUSE_PACKET_SIZE); gReaders = List_Create(); Spinlock_Init(&gReadersLock); prepareForWrite(); outb(0x64, 0x20); //get status command uint8 status = inb(0x60); status = status | 2; //enable IRQ12 outb(0x64, 0x60); //set status command outb(0x60, status); outb(0x64, 0xA8); //enable Auxiliary Device command writeMouse(0xF4); //0xF4: Enable Packet Streaming } static BOOL mouse_open(File *file, uint32 flags) { FifoBuffer* fifo = FifoBuffer_create(60); file->privateData = (void*)fifo; Spinlock_Lock(&gReadersLock); List_Append(gReaders, file); Spinlock_Unlock(&gReadersLock); return TRUE; } static void mouse_close(File *file) { Spinlock_Lock(&gReadersLock); List_RemoveFirstOccurrence(gReaders, file); Spinlock_Unlock(&gReadersLock); FifoBuffer* fifo = (FifoBuffer*)file->privateData; FifoBuffer_destroy(fifo); } static int32 mouse_read(File *file, uint32 size, uint8 *buffer) { FifoBuffer* fifo = (FifoBuffer*)file->privateData; while (FifoBuffer_getSize(fifo) < MOUSE_PACKET_SIZE) { file->thread->state = TS_WAITIO; file->thread->state_privateData = mouse_read; enableInterrupts(); halt(); } disableInterrupts(); uint32 available = FifoBuffer_getSize(fifo); uint32 smaller = MIN(available, size); FifoBuffer_dequeue(fifo, buffer, smaller); return smaller; } static void prepareForRead() { //https://wiki.osdev.org/Mouse_Input //Bytes cannot be read from port 0x60 until bit 0 (value=1) of port 0x64 is set int32 tryCount = 1000; uint8 data = 0; do { data = inb(0x64); } while (((data & 0x01) == 0) && --tryCount > 0); } static void prepareForWrite() { //https://wiki.osdev.org/Mouse_Input //All output to port 0x60 or 0x64 must be preceded by waiting for bit 1 (value=2) of port 0x64 to become clear int32 tryCount = 1000; uint8 data = 0; do { data = inb(0x64); } while (((data & 0x02) != 0) && --tryCount > 0); } static void writeMouse(uint8 data) { prepareForWrite(); outb(0x64, 0xD4); prepareForWrite(); outb(0x60, data); } static void handleMouseInterrupt(Registers *regs) { uint8 status = 0; //0x20 (5th bit is mouse bit) //read from 0x64, if its mouse bit is 1 then data is available at 0x60! int32 tryCount = 1000; do { status = inb(0x64); } while (((status & 0x20) == 0) && --tryCount > 0); uint8 data = inb(0x60); gMousePacket[gMouseByteCounter] = data; gMouseByteCounter += 1; if (gMouseByteCounter == MOUSE_PACKET_SIZE) { gMouseByteCounter = 0; Spinlock_Lock(&gReadersLock); //Wake readers List_Foreach(n, gReaders) { File* file = n->data; FifoBuffer* fifo = (FifoBuffer*)file->privateData; FifoBuffer_enqueue(fifo, gMousePacket, MOUSE_PACKET_SIZE); if (file->thread->state == TS_WAITIO) { if (file->thread->state_privateData == mouse_read) { file->thread->state = TS_RUN; file->thread->state_privateData = NULL; } } } Spinlock_Unlock(&gReadersLock); } //printkf("mouse:%d\n", data); }