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