First of all in the osdev wiki article about it keyboard it says the following:
So i have implemented some resend code in my keyboard send data function like this:The command isn't completed until you've received an ACK for it. For example, if you send a command and the keyboard responds with "0xFE (resend)" then you have to send the command again (possibly limited to 3 retries before you give up and assume the keyboard doesn't support the command you're sending or there's been a hardware failure).
Code: Select all
enum
{
keyboard_data_port = 0x60,
keyboard_ack_port = 0x61,
keyboard_command_port= 0x64
} ports;
int keyboard_send_data(uint8_t data)
{
uint8_t response = 0;
keyboard_wait();
outport_byte(keyboard_data_port, data);
response = keyboard_read_buffer();
if(response == resend)
{
for(uint8_t i = 0; i < 3; i++)
{
keyboard_wait();
outport_byte(keyboard_data_port, data);
response = keyboard_read_buffer();
if(keyboard_read_buffer() != resend)
return response;
}
return -1;
}
else
return response;
}
bool keyboard_wait(void) //Wait until the keyboard is not busy, if the keyboard is still busy it will return false
{
for(uint32_t i = 0; i < 1000; i++)
{
if( ( keyboard_read_status() & keyboard_mask_input_buffer ) == 0 )
return true;
}
return false;
}
Also, i have implemented a handler for the keyboard IRQ:
Code: Select all
unsigned char read_key()
{
static unsigned char key_code, value;
key_code = keyboard_read_buffer();
value = inport_byte(keyboard_ack_port);
outport_byte(keyboard_ack_port, value | 0x80);
outport_byte(keyboard_ack_port, value );
return key_code;
}
void keyboard_handler()
{
unsigned char scancode = 0;
unsigned char character = 0;
key_pressed = false;
if( ( keyboard_read_status() & keyboard_mask_input_buffer ) == 0) //Only read a key if there is something to read
{
scancode = read_key();
if( scancode & 0x80) //If a key is released and it was a ****, control ot alt set the mode to false
{
switch(kbd_unshifted[scancode -128])
{
case KEY_LSHIFT:
case KEY_RSHIFT:
shift = false;
break;
case KEY_LCTRL:
case KEY_RCTRL:
control = false;
break;
case KEY_LALT:
case KEY_RALT:
alt = false;
break;
}
}
else
{
key_pressed = true;
switch(kbd_unshifted[scancode]) //Check the shift, control, caps lock and alt keyd
{
case KEY_CAPSLOCK:
caps_lock = !caps_lock;
break;
case KEY_LSHIFT:
case KEY_RSHIFT:
shift = true;
break;
case KEY_LCTRL:
case KEY_RCTRL:
control = true;
break;
case KEY_LALT:
case KEY_RALT:
alt = true;
break;
}
if(!control || !alt)
{
if(shift)
character = kbd_shifted[scancode];
else if(caps_lock)
character = kbd_caps[scancode];
else
character = kbd_unshifted[scancode];
}
if(buffer_end < 127)
{
buffer_end++;
}
keyboard_buffer[buffer_end] = character;
}
}
}
unsigned char keyboard_getch()
{
while(buffer_end == 0); //If there are no key strokes wait until we get one
disable_interrupts();
for(unsigned char i = 0; i < buffer_end; i++)
{
keyboard_buffer[i] = keyboard_buffer[i+1];
}
buffer_end--;
enable_interrupts();
return keyboard_buffer[0];
}
1. I have been thinking of declaring an array of bools that store what keys are being pressed and then use that information in my getch function to filter out the ones that can't be pressed (F2 or insert for example) Do you think this is a good idea?
2. Also in my current implementation every key stroke is stored in the keyboard buffer even if no process is reading from the keyboard so when a proccess starts reading from the keyboard it first gets values that aren't necesary, to fix that i have a function that simply changes the buffer end to 0 but i don't think that is a fancy way of doing it. Any ideas?
Thank you in advance and if you see something that is wrong or could be improved comment it please!