summaryrefslogtreecommitdiff
path: root/src/keyboard.c
blob: c591c6ac404e80a75ed1ed48a5128a6b5de27a4b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
#include <stdbool.h>

#include "keyboard.h"

#include "stdio.h"

// status register on command port (read)
#define STATUS_REG_OUTPUT_BUF_FULL 0x01
#define STATUS_REG_INPUT_BUF_FULL 0x02

// generic PS/2 commands
#define COMMAND_GET_STATE 0x20
#define COMMAND_SET_STATE 0x60
#define COMMAND_DISABLE_PORT1 0xAD 
#define COMMAND_ENABLE_PORT1 0xAE 

// keyboard specific commands, PSAUX1
#define KBD_COMMAND_SET_LEDS 0xED
#define KBD_SET_SCANCODE 0xF0
#define KBD_ACTIVATE 0xF4

#define STATUS_CONTROL_CONFIG_ENABLE_IRQ_PORT1 0x01
#define STATUS_CONTROL_CONFIG_CLOCK_PORT1 0x10

// keyboard LED status codes
#define KBD_LED_SCROLL_LOCK_ON 0x01
#define KBD_LED_NUM_LOCK_ON 0x02
#define KBD_LED_CAPS_LOCK_ON 0x04
#define KBD_LED_ALL_OFF 0x00
#define KBD_LED_ALL_ON KBD_LED_SCROLL_LOCK_ON | KBD_LED_NUM_LOCK_ON | KBD_LED_CAPS_LOCK_ON

// keyboard scan codes
#define KBD_SCANCODE_1 0x01
#define KBD_SCANCODE_2 0x02
#define KBD_SCANCODE_3 0x03

static bool has_data( keyboard_t *keyboard )
{
	return ( port8_read( &keyboard->command_port ) & STATUS_REG_OUTPUT_BUF_FULL ) == STATUS_REG_OUTPUT_BUF_FULL;
}

static uint8_t read_data( keyboard_t *keyboard )
{
	while( ( port8_read( &keyboard->command_port ) & STATUS_REG_OUTPUT_BUF_FULL ) == 0 ) { }
	return port8_read( &keyboard->data_port );
}

static void send_command( keyboard_t *keyboard, uint8_t command )
{
	while( port8_read( &keyboard->command_port ) & STATUS_REG_INPUT_BUF_FULL ) { }
	port8_write( &keyboard->command_port, command );
}

static void write_data( keyboard_t *keyboard, uint8_t data )
{
	while( port8_read( &keyboard->command_port ) & STATUS_REG_INPUT_BUF_FULL ) { }
	port8_write( &keyboard->data_port, data );
}

void keyboard_init( keyboard_t *keyboard )
{
	memset( keyboard, 0, sizeof( keyboard_t ) );
	
	port8_init( &keyboard->command_port, 0x64 );
	port8_init( &keyboard->data_port, 0x60 );
	
	// first switch off port 1
	send_command( keyboard, COMMAND_DISABLE_PORT1 );
	
	// consume character pressed before executing the kernel
	while( port8_read( &keyboard->command_port ) & STATUS_REG_OUTPUT_BUF_FULL ) {
		port8_read( &keyboard->data_port );
	}
	
	// enable port 1
	send_command( keyboard, COMMAND_ENABLE_PORT1 );
	
	// enable interrupts for port 1
	send_command( keyboard, COMMAND_GET_STATE );
	uint8_t status = read_data( keyboard );
	status |= STATUS_CONTROL_CONFIG_ENABLE_IRQ_PORT1;
	status &= ~STATUS_CONTROL_CONFIG_CLOCK_PORT1;
	send_command( keyboard, COMMAND_SET_STATE );
	write_data( keyboard, status );
	
	// disable all LEDs on keyboard
	//~ send_command( keyboard, KBD_COMMAND_SET_LEDS );
	//~ write_data( keyboard, KBD_LED_ALL_ON );
	
	// set scan code
	//~ send_command( keyboard, KBD_SET_SCANCODE );
	//~ write_data( keyboard, KBD_SCANCODE_2 );
	
	// activate keyboard
	//~ send_command( keyboard, KBD_ACTIVATE );
}
 
uint32_t keyboard_handle_interrupt( interrupt_handler_t *handler, uint32_t esp )
{
	keyboard_t *keyboard = (keyboard_t *)handler->driver;
	
	if( has_data( keyboard ) ) {
		uint8_t scancode = read_data( keyboard );
		printf( "KBD 0x%X ", scancode );
	} else {
		printf( "SPURIOUS KBD INTERRUPT " );
	}
	
	return esp;
}