10 #include <hardware/io/ps2.h> 11 #include <hardware/pit.h> 12 #include <hardware/io/keyboard.h> 13 #include <hardware/io/mouse.h> 16 #define PS2_DATA 0x60 // write device commands, read device/PS/2 results 17 #define PS2_CMD 0x64 // write PS/2 commands, read ps2_status_t 21 #define READ_CONFIG 0x20 // see ps2_config_t 22 #define WRITE_CONFIG 0x60 23 #define READ_OUTPUT_PORT 0xD0 // see ps2_output_port_t 24 #define WRITE_OUTPUT_PORT 0xD1 25 #define DISABLE_PORT_1 0xAD 26 #define DISABLE_PORT_2 0xA7 27 #define ENABLE_PORT_1 0xAE 28 #define ENABLE_PORT_2 0xA8 29 #define TEST_PORT_1 0xAB 30 #define TEST_PORT_2 0xA9 31 #define SEND_TO_PORT_2 0xD4 // indicates we want to send to port 2 via PS2_DATA 32 #define PULSE_OUTPUT_LINES(b3, b2, b1, b0) \ 33 (0xF0 + !(b3) * 0b1000 + !(b2) * 0b100 + !(b1) * 0b10 + !(b0) * 0b1) 36 #define TEST_PS2_PASSED 0x55 37 #define TEST_PORT_PASSED 0x00 40 #define DEVICE_RESET 0xFF 41 #define DEVICE_IDENTIFY 0xF2 42 #define DEVICE_ENABLE 0xF4 43 #define DEVICE_DISABLE 0xF5 46 #define DEVICE_ACK 0xFA 47 #define DEVICE_TEST_PASSED 0xAA 49 #define PS2_TIMEOUT 1000 50 #define HAS_PORT1 1 // every PS/2 controller has port 1, but port 2 51 #define HAS_PORT2 port2_supported // needs to be detected first 55 uint8_t outbuf_full : 1;
56 uint8_t inbuf_full : 1;
60 uint8_t outbuf_port2 : 1;
61 uint8_t timeout_err : 1;
62 uint8_t parity_err : 1;
63 } __attribute__((packed)) bits;
72 uint8_t outbuf_port1 : 1;
73 uint8_t outbuf_port2 : 1;
75 } __attribute__((packed)) bits;
79 static uint8_t init_done = 0;
80 static uint8_t port2_supported = 1;
81 static ps2_error_t err = 0;
83 static inline uint8_t ps2_ready() {
87 static inline int8_t ps2_available(ps2_port_t port) {
89 if (port == PS2_ANY_PORT)
90 return status.bits.outbuf_full;
91 if (port == PS2_PORT_1)
92 return status.bits.outbuf_full && !status.bits.outbuf_port2;
93 if (port == PS2_PORT_2)
94 return status.bits.outbuf_full && status.bits.outbuf_port2;
98 static inline uint8_t ps2_write(uint8_t io_port, uint8_t command) {
101 while (!ps2_ready() && !pit_timed_out(&timeout));
102 if (pit_timed_out(&timeout)) {
103 println(
"%4aPS/2 write timeout (%02x,%02x)%a", io_port, command);
106 outb(io_port, command);
110 static inline uint8_t ps2_read(ps2_port_t port, ps2_error_t* err) {
113 while (!ps2_available(port) && !pit_timed_out(&timeout));
114 if (pit_timed_out(&timeout)) {
115 println(
"%4aPS/2 port %d read timeout%a", port);
116 *err = PS2_TIMEOUT_ERR;
120 return inb(PS2_DATA);
124 ps2_write(PS2_CMD, READ_CONFIG);
129 ps2_write(PS2_CMD, WRITE_CONFIG);
130 ps2_write(PS2_DATA, config.byte);
133 static uint8_t ps2_test(uint8_t test_command, uint8_t expected_result,
const char* name) {
134 ps2_write(PS2_CMD, test_command);
135 uint8_t res = ps2_read(PS2_ANY_PORT, &err);
136 if (res != expected_result) {
137 print(
"%4awarning%a. %s test failed (%02x). ", name, res);
142 static inline uint8_t ps2_valid_port(ps2_port_t port) {
143 if ((port != PS2_PORT_1 && port != PS2_PORT_2) || (port == PS2_PORT_2 && !HAS_PORT2)) {
144 println(
"%4aPS/2 port %d not supported%a", port);
150 while (ps2_available(PS2_ANY_PORT))
151 ps2_read(PS2_ANY_PORT, &err);
154 static uint8_t ps2_write_device_no_ack(ps2_port_t port, uint8_t command) {
155 if (!ps2_valid_port(port))
return 0;
156 if (port == PS2_PORT_2)
157 ps2_write(PS2_CMD, SEND_TO_PORT_2);
158 ps2_write(PS2_DATA, command);
162 uint8_t ps2_write_device(ps2_port_t port, uint8_t command) {
163 if (!ps2_write_device_no_ack(port, command))
165 return ps2_read_device(port, &err) == DEVICE_ACK;
168 uint8_t ps2_read_device(ps2_port_t port, ps2_error_t* err) {
169 if (!ps2_valid_port(port)) {
170 *err = PS2_INVALID_PORT_ERR;
173 return ps2_read(port, err);
176 static uint8_t ps2_reset_device(ps2_port_t port) {
177 ps2_write_device_no_ack(port, DEVICE_RESET);
179 while (ps2_read_device(port, &err) != DEVICE_TEST_PASSED && !pit_timed_out(&timeout));
180 if (pit_timed_out(&timeout)) {
181 print(
"%4afail%a. Port %d reset failed. ", port);
186 static void ps2_init_controller() {
187 ps2_write(PS2_CMD, DISABLE_PORT_1);
188 ps2_write(PS2_CMD, DISABLE_PORT_2);
192 if (!config.bits.port2_clock)
195 config.bits.port1_intr = config.bits.port2_intr = config.bits.port1_transl = 0;
196 ps2_write_config(config);
198 ps2_test(TEST_PS2, TEST_PS2_PASSED,
"PS/2");
202 ps2_write(PS2_CMD, ENABLE_PORT_2);
204 if (config.bits.port2_clock)
207 ps2_write(PS2_CMD, DISABLE_PORT_2);
210 if (HAS_PORT1) ps2_test(TEST_PORT_1, TEST_PORT_PASSED,
"Port 1");
211 if (HAS_PORT2) ps2_test(TEST_PORT_2, TEST_PORT_PASSED,
"Port 2");
212 if (HAS_PORT1) ps2_write(PS2_CMD, ENABLE_PORT_1);
213 if (HAS_PORT2) ps2_write(PS2_CMD, ENABLE_PORT_2);
215 config = ps2_read_config();
216 if (HAS_PORT1) config.bits.port1_intr = 1;
217 if (HAS_PORT2) config.bits.port2_intr = 1;
218 ps2_write_config(config);
221 static void ps2_init_devices() {
222 if (HAS_PORT1) ps2_reset_device(PS2_PORT_1);
223 if (HAS_PORT2) ps2_reset_device(PS2_PORT_2);
225 if (HAS_PORT1) ps2_write_device(PS2_PORT_1, DEVICE_DISABLE);
227 if (HAS_PORT2) ps2_write_device(PS2_PORT_2, DEVICE_DISABLE);
229 if (HAS_PORT1) keyboard_init(PS2_PORT_1);
230 if (HAS_PORT2) mouse_init(PS2_PORT_2);
231 if (HAS_PORT1) ps2_write_device(PS2_PORT_1, DEVICE_ENABLE);
232 if (HAS_PORT2) ps2_write_device(PS2_PORT_2, DEVICE_ENABLE);
238 if (!init_done)
return cpu;
240 println(
"%4aIRQ12: not a PS/2 device%a");
243 uint8_t data = inb(PS2_DATA);
244 if (data == DEVICE_ACK)
247 keyboard_handle_data(data);
249 mouse_handle_data(data);
254 print(
"PS/2 init ... ");
259 ps2_init_controller();
261 println(
"%2aok%a. %s channel, keyboard %s.",
262 HAS_PORT2 ?
"Dual" :
"Single", HAS_PORT2 ?
"and mouse" :
"only");
267 ps2_write(PS2_CMD, PULSE_OUTPUT_LINES(0, 0, 0, 1));
The CPU's state when an interrupt occurs.
#define ISR_IRQ(irq)
the interrupt vector for an IRQ
void isr_register_handler(size_t intr, isr_handler_t handler)
Registers a handler to call whenever a given interrupt is fired.
uint32_t intr
the interrupt vector of the fired interrupt