about summary refs log blame commit diff stats
path: root/kernel.soso/keyboard.c
blob: 8bb7ed817b38b11fb14366522beb22e103265292 (plain) (tree)





















                                                                    
                       



                   
                       







                                                     
                           


















                                                            
                                                     



                                                      
                                   








                                                 
                                        
                                  







                                                
                                                                    



                                                

                                                   








                                                            
                                            












                                      
                                                                     



                                                
                      




                                            
                       



                                        
                            










                                           
                                                      
                       
        









                                                
                               

                             

                                                                   







                                                       
#include "keyboard.h"
#include "isr.h"
#include "common.h"
#include "screen.h"
#include "ttydriver.h"
#include "fs.h"
#include "device.h"
#include "alloc.h"
#include "devfs.h"
#include "list.h"

static uint8* gKeyBuffer = NULL;
static uint32 gKeyBufferWriteIndex = 0;
static uint32 gKeyBufferReadIndex = 0;

#define KEYBUFFER_SIZE 128

static BOOL keyboard_open(File *file, uint32 flags);
static void keyboard_close(File *file);
static int32 keyboard_read(File *file, uint32 size, uint8 *buffer);
static int32 keyboard_ioctl(File *file, int32 request, void * argp);

typedef enum ReadMode {
    Blocking = 0,
    NonBlocking = 1
} ReadMode;

typedef struct Reader {
    uint32 readIndex;
    ReadMode readMode;
} Reader;

static List* gReaders = NULL;

static void handleKeyboardInterrupt(Registers *regs);

void initializeKeyboard() {
    Device device;
    memset((uint8*)&device, 0, sizeof(Device));
    strcpy(device.name, "keyboard");
    device.deviceType = FT_CharacterDevice;
    device.open = keyboard_open;
    device.close = keyboard_close;
    device.read = keyboard_read;
    device.ioctl = keyboard_ioctl;

    gKeyBuffer = kmalloc(KEYBUFFER_SIZE);
    memset((uint8*)gKeyBuffer, 0, KEYBUFFER_SIZE);

    gReaders = List_Create();

    registerDevice(&device);

    registerInterruptHandler(IRQ1, handleKeyboardInterrupt);
}

static BOOL keyboard_open(File *file, uint32 flags) {
    Reader* reader = (Reader*)kmalloc(sizeof(Reader));
    reader->readIndex = 0;
    reader->readMode = Blocking;

    if (gKeyBufferWriteIndex > 0) {
        reader->readIndex = gKeyBufferWriteIndex;
    }
    file->privateData = (void*)reader;

    List_Append(gReaders, file);

    return TRUE;
}

static void keyboard_close(File *file) {
    //printkf("keyboard_close\n");

    Reader* reader = (Reader*)file->privateData;

    kfree(reader);

    List_RemoveFirstOccurrence(gReaders, file);
}

static int32 keyboard_read(File *file, uint32 size, uint8 *buffer) {
    Reader* reader = (Reader*)file->privateData;

    uint32 readIndex = reader->readIndex;

    if (reader->readMode == Blocking) {
        while (readIndex == gKeyBufferWriteIndex) {
            file->thread->state = TS_WAITIO;
            file->thread->state_privateData = keyboard_read;
            enableInterrupts();
            halt();
        }
    }

    disableInterrupts();

    if (readIndex == gKeyBufferWriteIndex) {
        //non-blocking return here
        return -1;
    }

    buffer[0] = gKeyBuffer[readIndex];
    readIndex++;
    readIndex %= KEYBUFFER_SIZE;

    reader->readIndex = readIndex;

    return 1;
}

static int32 keyboard_ioctl(File *file, int32 request, void * argp) {
    Reader* reader = (Reader*)file->privateData;

    int cmd = (int)argp;

    switch (request) {
    case 0: //get
        *(int*)argp = (int)reader->readMode;
        return 0;
        break;
    case 1: //set
        if (cmd == 0) {
            reader->readMode = Blocking;

            return 0;
        }
        else if (cmd == 1) {
            reader->readMode = NonBlocking;
            return 0;
        }
        break;
    default:
        break;
    }

    return -1;
}

static void handleKeyboardInterrupt(Registers *regs) {
    uint8 scancode = 0;
    do {
        scancode = inb(0x64);
    } while ((scancode & 0x01) == 0);

    scancode = inb(0x60);

    gKeyBuffer[gKeyBufferWriteIndex] = scancode;
    gKeyBufferWriteIndex++;
    gKeyBufferWriteIndex %= KEYBUFFER_SIZE;

    //Wake readers
    List_Foreach(n, gReaders) {
        File* file = n->data;

        if (file->thread->state == TS_WAITIO) {
            if (file->thread->state_privateData == keyboard_read) {
                file->thread->state = TS_RUN;
                file->thread->state_privateData = NULL;
            }
        }
    }

    sendKeyInputToTTY(getActiveTTY(), scancode);
}