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