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
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
|
#include <io.h>
#include <stdint.h>
#include <stdio.h>
#include <arch/i386/ps2_controller.h>
#define PS2_DATA 0x60 // data port
#define PS2_STATUS 0x64 // status register
#define PS2_COMMAND 0x64 // command register
// set to true if 2nd ps2 port is available
bool ps2SecondaryEnabled = false;
void initialize_ps2_controller() {
inputbuffer_wait();
outb(PS2_COMMAND, 0xAD); // disable devices
inputbuffer_wait();
outb(PS2_COMMAND, 0xA7);
outputbuffer_wait();
inb(PS2_DATA); // flush output buffer
inb(PS2_DATA);
inb(PS2_DATA);
inb(PS2_DATA);
inb(PS2_DATA);
inb(PS2_DATA);
inb(PS2_DATA);
inb(PS2_DATA);
inb(PS2_DATA);
inb(PS2_DATA);
inputbuffer_wait();
outb(PS2_COMMAND, 0x20); // set controller configuration byte
outputbuffer_wait();
uint8_t conconfig = inb(PS2_DATA);
conconfig &= 0b00110100;
inputbuffer_wait();
outb(PS2_COMMAND, 0x60);
inputbuffer_wait();
outb(PS2_DATA, conconfig);
inputbuffer_wait();
outb(PS2_COMMAND, 0xAA); // performs controller self test
outputbuffer_wait();
if (inb(PS2_DATA) == 0xFC) {
printf("PS/2 controller failed self test\n");
}
inputbuffer_wait();
outb(PS2_COMMAND, 0x60); // in case the controller resets from the test
inputbuffer_wait();
outb(PS2_DATA, conconfig);
int portcount = 1;
inputbuffer_wait();
outb(PS2_COMMAND, 0xA8); // check if ps2 controller is dual channel
inputbuffer_wait();
outb(PS2_COMMAND, 0x20);
outputbuffer_wait();
conconfig = inb(PS2_DATA);
if ((conconfig & 0b00100000) == 0b00000000) { // checks if bit 5 is cleared
ps2SecondaryEnabled = true;
//printf("Dual channel PS/2\n");
portcount = 2;
} else {
//printf("Single channel PS/2\n");
}
inputbuffer_wait();
outb(PS2_COMMAND, 0xAB); // tests ps2 ports
outputbuffer_wait();
if (inb(PS2_DATA) != 0x00) {
printf("PS/2 port 1 failed self test\n");
--portcount;
}
if (ps2SecondaryEnabled) {
inputbuffer_wait();
outb(PS2_COMMAND, 0xA9);
outputbuffer_wait();
if (inb(PS2_DATA) != 0x00) {
printf("PS/2 port 2 failed self test\n");
--portcount;
}
}
if (!portcount) {
printf("PS/2 initialization failed\n");
return;
}
conconfig |= 0b00000011;
inputbuffer_wait();
outb(PS2_COMMAND, 0xAE); // enable ps2 ports
conconfig |= 0b00000001;
if (ps2SecondaryEnabled) {
inputbuffer_wait();
outb(PS2_COMMAND, 0xA8);
outb(PS2_COMMAND, 0x60);
conconfig |= 0b00000011;
outb(PS2_DATA, conconfig);
} else {
inputbuffer_wait();
outb(PS2_COMMAND, 0x60);
conconfig |= 0b00000001;
outb(PS2_DATA, conconfig);
}
//ps2_dev_send_command(0, 0xFF); // reset devices
//inb(PS2_DATA);
//io_wait();
if (ps2SecondaryEnabled) {
//ps2_dev_send_command(1, 0xFF);
//inb(PS2_DATA);
//io_wait();
}
//printf("PS/2 controller initialized\n");
}
// waits for input buffer (write) to be filled
void inputbuffer_wait() {
for (int i = 0; i < 15; i++) {
uint8_t status_reg = inb(PS2_STATUS);
if ((status_reg & 0b00000010)) {
return;
}
io_wait();
}
}
// waits for outbut buffer (read) to be filled
void outputbuffer_wait() {
for (int i = 0; i < 15; i++) {
uint8_t status_reg = inb(PS2_STATUS);
if ((status_reg & 0b00000001)) {
return;
}
io_wait();
}
}
// checks if inpbut buffer is set
bool inputbuffer_check() {
uint8_t status_reg = inb(PS2_STATUS);
if ((status_reg & 0b00000010)) {
return true;
} else {
return false;
}
}
bool outputbuffer_check() {
uint8_t status_reg = inb(PS2_STATUS);
if ((status_reg & 0b00000001)) {
return true;
} else {
return false;
}
}
/* Sends a command byte to a ps2 device
Port numbers start from 0 */
int ps2_dev_send_command(int port, unsigned char command) {
//bool commandRecieved = false;
switch (port)
{
case 0:
for (int i = 0; i < 5; i++) {
uint8_t status_reg = inb(PS2_STATUS);
if ((status_reg & 0b00000010) == 0b00000000) {
outb(PS2_DATA, command);
return 0;
}
inb(PS2_DATA);
io_wait();
}
return 1; // error returned if timeout expires
case 1:
outb(PS2_COMMAND, 0xD4);
for (int i = 0; i < 5; i++) {
uint8_t status_reg = inb(PS2_STATUS);
if ((status_reg & 0b00000010) == 0b00000000) {
outb(PS2_DATA, command);
return 0;
}
inb(PS2_DATA);
io_wait();
}
return 1;
default:
return 2; // out of port range
}
}
|