diff options
Diffstat (limited to 'tools/iso/kernel.soso/mouse.c')
-rw-r--r-- | tools/iso/kernel.soso/mouse.c | 187 |
1 files changed, 187 insertions, 0 deletions
diff --git a/tools/iso/kernel.soso/mouse.c b/tools/iso/kernel.soso/mouse.c new file mode 100644 index 00000000..235d931d --- /dev/null +++ b/tools/iso/kernel.soso/mouse.c @@ -0,0 +1,187 @@ +#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); +} |