about summary refs log blame commit diff stats
path: root/kernel.soso/mouse.c
blob: 235d931de00ac61e96fa1d1a34a4cab61295ffc9 (plain) (tree)






























                                                                
                        































                                                          
                                                  












                                             
                                     










                                                      
                                                                 

                                                      
                                                          
















                                                     
                              





                                                                                   
        



                                                     
                               





                                                                                                                  
        



                                                     
                                    








                      
                                                   




                                                                           
        








                                                       
                                                 




                                     
                                   





                                                                      

                                                                    










                                                           
#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);
}