summaryrefslogtreecommitdiffstats
path: root/src/ps2.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/ps2.rs')
-rw-r--r--src/ps2.rs64
1 files changed, 56 insertions, 8 deletions
diff --git a/src/ps2.rs b/src/ps2.rs
index 3a42c1a..4ea8b7a 100644
--- a/src/ps2.rs
+++ b/src/ps2.rs
@@ -158,9 +158,64 @@ static mut KBD: KbdState = KbdState {
158 got_e0: false, 158 got_e0: false,
159}; 159};
160 160
161/// Initialise the PS/2 port for the keyboard — just drain stale bytes. 161/// Initialise the PS/2 port: drain stale bytes + enable keyboard interrupt.
162pub fn init() { 162pub fn init() {
163 drain_input(); 163 drain_input();
164
165 // Enable the keyboard interrupt on the PS/2 controller.
166 // Read Configuration Byte (command 0x20), set bit 0 (IRQ1 enable),
167 // write back (command 0x60).
168 unsafe {
169 // Tell the keyboard controller we want to read the config byte.
170 // Need to wait for the controller to be ready first.
171 wait_write();
172 core::arch::asm!("out dx, al", in("dx") 0x64u16, in("al") 0x20u8,
173 options(nostack, preserves_flags));
174 wait_read();
175 let mut cfg: u8;
176 core::arch::asm!("in al, dx", out("al") cfg, in("dx") 0x60u16,
177 options(nostack, preserves_flags));
178
179 cfg |= 0x01; // enable keyboard interrupt
180
181 // Write config byte back
182 wait_write();
183 core::arch::asm!("out dx, al", in("dx") 0x64u16, in("al") 0x60u8,
184 options(nostack, preserves_flags));
185 wait_write();
186 core::arch::asm!("out dx, al", in("dx") 0x60u16, in("al") cfg,
187 options(nostack, preserves_flags));
188 }
189}
190
191/// Wait until the PS/2 controller is ready to receive a command.
192fn wait_write() {
193 unsafe {
194 loop {
195 let status: u8;
196 core::arch::asm!("in al, dx", out("al") status, in("dx") 0x64u16,
197 options(nostack, preserves_flags));
198 if status & 0x02 == 0 {
199 // Input buffer empty — controller ready to receive
200 break;
201 }
202 }
203 }
204}
205
206/// Wait until the PS/2 controller has data available to read.
207fn wait_read() {
208 unsafe {
209 loop {
210 let status: u8;
211 core::arch::asm!("in al, dx", out("al") status, in("dx") 0x64u16,
212 options(nostack, preserves_flags));
213 if status & 0x01 != 0 {
214 // Output buffer full — data ready to read
215 break;
216 }
217 }
218 }
164} 219}
165 220
166fn drain_input() { 221fn drain_input() {
@@ -184,18 +239,11 @@ fn drain_input() {
184/// this function pops and decodes them. 239/// this function pops and decodes them.
185pub fn poll_key() -> KeyEvent { 240pub fn poll_key() -> KeyEvent {
186 loop { 241 loop {
187 // Disable interrupts so the buffer-empty → hlt window is atomic.
188 unsafe { core::arch::asm!("cli", options(nostack, preserves_flags)); }
189
190 if let Some(byte) = crate::interrupts::read_scancode() { 242 if let Some(byte) = crate::interrupts::read_scancode() {
191 unsafe { core::arch::asm!("sti", options(nostack, preserves_flags)); }
192 if let Some(ev) = process_byte(byte) { 243 if let Some(ev) = process_byte(byte) {
193 return ev; 244 return ev;
194 } 245 }
195 } else { 246 } else {
196 // Re-enable and halt. If a keyboard IRQ arrived between the
197 // buffer check and `sti`, the CPU sees a pending interrupt
198 // and `hlt` returns immediately.
199 unsafe { 247 unsafe {
200 core::arch::asm!("sti; hlt", options(nostack, preserves_flags)); 248 core::arch::asm!("sti; hlt", options(nostack, preserves_flags));
201 } 249 }