Files
uiuc-ece391-mp3/student-distrib/devices/keyboard.c
2018-10-29 14:34:12 -05:00

268 lines
6.4 KiB
C

#include "keyboard.h"
#include "../data/keyboard-scancode.h"
// keyboard buffer, one addition place for newline character
static uint8_t keyboard_buffer[KEYBOARD_BUFFER_SIZE + 1];
// next available index in (i.e. top of) the keyboard buffer
// (default: 0 -- empty)
static int keyboard_buffer_top = 0;
// flag variable used to indicate whether writting to the keyborad buffer
// is enable or not (default: 0 -- disable)
static volatile int keyboard_buffer_enable = 0;
// Keyboard flags, tracking whether shift, ctrl, capslock are pressed or not.
// Added by jinghua3.
uint8_t shift_pressed = 0;
uint8_t ctrl_pressed = 0;
uint8_t capslock_pressed = 0;
uint8_t capslock = 0;
/* void keyboard_init()
* @effects: Make the system ready to receive keyboard interrupts
* @description: Enable the keyboard IRQ so that we can receive its interrupts
*/
void keyboard_init() {
cli();
enable_irq(KEYBOARD_IRQ);
sti();
}
/* void keyboard_interrupt()
* @input: PORT(KEYBOARD_PORT) - scancode sent from keyboard.
* @description: Handle keyboard interrupt
*/
void keyboard_interrupt() {
uint8_t scancode_idx = inb(KEYBOARD_PORT);
char key;
int is_special_key;
is_special_key = update_special_key_stat(scancode_idx);
if (is_special_key == 1){
// send End Of Interrupt
send_eoi(KEYBOARD_IRQ);
return;
}
if(ctrl_pressed==1){
key = scancode[scancode_idx][0];
if(key == 'l'){
// Ctrl+L or Ctrl+l received, clear screen and put cursor at the top.
clear();
// clear the keyboard buffer.
keyboard_buffer_top = 0;
}
// send End Of Interrupt
send_eoi(KEYBOARD_IRQ);
return;
}
// echo the keyboard input to the screen
if(scancode_idx < SCANCODE_TABLE_SIZE)
{
// Caps check, modified by jinghua3.
if(((capslock) != (shift_pressed)) && is_alphabet(scancode_idx)){
key = scancode[scancode_idx][1];
}
else if(!is_alphabet(scancode_idx) && shift_pressed){
key = scancode[scancode_idx][1];
}
else{
key = scancode[scancode_idx][0];
}
cli();
keyboard_echo(key);
sti();
// if keyboard buffer is enable
if (keyboard_buffer_enable == 1)
{
if (key == BACKSPACE)
{
keyboard_buffer_top = (keyboard_buffer_top - 1) < 0 ? 0 : keyboard_buffer_top - 1;\
}
else if (key == '\n')
{
// put newline character
keyboard_buffer[keyboard_buffer_top] = '\n';
// increment keyboard_buffer_top
keyboard_buffer_top++;
// disable keyboard buffer
keyboard_buffer_enable = 0;
}
else if (keyboard_buffer_top >= KEYBOARD_BUFFER_SIZE)
{
cli();
keyboard_echo('\n');
sti();
// put newline character
keyboard_buffer[keyboard_buffer_top] = '\n';
// increment keyboard_buffer_top
keyboard_buffer_top++;
// disable keyboard buffer
keyboard_buffer_enable = 0;
}
else
{
// record current key
keyboard_buffer[keyboard_buffer_top] = key;
// increment keyboard_buffer_top
keyboard_buffer_top++;
}
}
}
// send End Of Interrupt
send_eoi(KEYBOARD_IRQ);
}
/* terminal Driver */
/* terminal_open */
int32_t terminal_open(const uint8_t* filename)
{
// clear the buffer
keyboard_buffer_top = 0;
// disable keyboard buffer
keyboard_buffer_enable = 0;
return 0;
}
/* terminal_read */
int32_t terminal_read(int32_t fd, void* buf, int32_t nbytes)
{
// invalid input
if (buf == NULL)
{
return -1;
}
// loop index
int index;
// return value
int min_size;
// enable keyboard buffer
keyboard_buffer_enable = 1;
/* printf("keyboard_read starts\n"); */
// wait for keyboard inputs
while (keyboard_buffer_enable == 1) {}
/* printf("keyboard_read ends\n"); */
for (index = 0; index < nbytes; index++)
{
if (index < keyboard_buffer_top)
{
*(uint8_t *)(buf + index) = keyboard_buffer[index];
}
else
{
*(uint8_t *)(buf + index) = 0;
}
}
min_size = keyboard_buffer_top < nbytes ? keyboard_buffer_top : nbytes;
keyboard_buffer_top = 0;
return min_size;
}
/* terminal_write */
int32_t terminal_write(int32_t fd, const void* buf, int32_t nbytes)
{
// invalid input
if (buf == NULL)
{
return -1;
}
// loop index
int index;
cli();
// all data in the buffer are displayed to the screen
for (index = 0; index < nbytes; index++)
{
if (*(uint8_t *)(buf + index) == 0)
{
break;
}
putc(*(uint8_t *)(buf +index));
}
sti();
return index;
}
/* terminal_close */
int32_t terminal_close(int32_t fd)
{
// clear the buffer
keyboard_buffer_top = 0;
// disable keyboard buffer
keyboard_buffer_enable = 0;
return 0;
}
/* update_special_key_stat - Added by jinghua3.
*
* update the status: (pressed/not pressed) of Shift, Ctrl, Capslock
* INPUT: data from keyboard port.
* OUTPUT: updates special key status.
* RETURN: 0 if the scancode from keyboard is not a special key like Shift, Ctrl and Capslock,
* otherwise 1.
*/
int update_special_key_stat(uint8_t keyboard_input){
switch(keyboard_input){
case CAPSLOCK_PRESS:
capslock_pressed = 1;
if (capslock==0){
capslock = 1;
}
else{
capslock = 0;
}
return 1;
case CAPSLOCK_RELEASE:
capslock_pressed = 0;
return 1;
case LEFT_SHIFT_PRESS:
case RIGHT_SHIFT_PRESS:
shift_pressed = 1;
return 1;
case LEFT_SHIFT_RELEASE:
case RIGHT_SHIFT_RELEASE:
shift_pressed = 0;
return 1;
case LEFT_CTRL_PRESS:
ctrl_pressed = 1;
return 1;
case LEFT_CTRL_RELEASE:
ctrl_pressed = 0;
return 1;
default:
return 0;
}
}
/* is_alphabet - Added by jinghua3.
*
* check if keyboard input is an alphabet
* INPUT: scancode from keyboard.
* OUTPUT:none
* RETURN: 1 if is alphabet, 0 if not.
*/
int is_alphabet(uint8_t scancode_idx){
char key;
if (scancode_idx < SCANCODE_TABLE_SIZE){
key = scancode[scancode_idx][0];
}
else{
return 0;
}
if(key>='a' && key<='z'){
return 1;
}
else {
return 0;
}
}