Demilade Sonuga's blog

All posts

The Keyboard Interrupt I

2023-03-03 · 6 min read

When a key on the keyboard is pressed, two things occur:

  1. An interrupt request is sent to the first PIC on line 1 (the second line).
  2. A byte of data (also called a scancode) describing the key event is written to a port with the number 0x60.

So, in the keyboard's interrupt service routine, we need to first read the scancode from port 0x60 and act according to what that byte tells us the user did with the keyboard.

Before we get into the specific nuances of interpreting the keyboard's scancodes, let's first get down a dummy service routine for the keyboard.

Keyboard Service Routine

For now, our keyboard's service routine will just print a "keyboard was pressed" message.

First, we have to change the PIC's interrupt mask to allow interrupts from line 1. For the purpose of isolating the effects of the keyboard interrupt, we'll also mask interrupts from the timer.

In pics.rs

impl PICs {
// ...Others

pub fn init(&mut self) {
// ...Others

// DELETED: self.first.data.write(0b11111110);
// Setting the interrupt masks
// Line 1 on the first PIC is for the keyboard,
// so setting it to 0
self.first.data.write(0b11111101); // NEW
self.second.data.write(0b11111111);
}
}

Since line 1 corresponds to bit 1 in the first PIC's interrupt mask, we set that bit to 0 to allow interrupts on this line.

In main.rs

extern "x86-interrupt" fn keyboard_handler(frame: interrupts::InterruptStackFrame) {
let port = port::Port::new(0x60);
let scancode = port.read();
let screen = get_screen().unwrap();
write!(screen, "keyboard was pressed {} ", scancode);
// Signalling that the keyboard interrupt has been handled
get_pics().unwrap().end_of_interrupt(1);
}
fn setup_idt(sel: SegmentSelector) {
// ...Others
idt.interrupts[0] = Entry::exception(ServiceRoutine(timer_handler), sel);
idt.interrupts[1] = Entry::exception(ServiceRoutine(keyboard_handler), sel); // NEW
let pointer = idt.as_pointer();
// ...Others
}

If you run the code now and press a key on the keyboard, you'll notice that the "keyboard was pressed" message is printed twice for every press, with different scancodes. For example, pressing the spacebar gives this output:

Spacebar Pressed

A scancode set is a specification that associates scancodes with key actions. There are 3: set 1, set 2 and set 3. In our case, the one we'll be paying attention to is scancode set 1. For the full specification of the scancode set, check the references.

Scancode set 1 and using it to deduce which key was pressed will be the subject of the next post.

Take Away

  • When a key is pressed/released, an interrupt is generated and an 8-bit number (scancode) is written to port 0x60.
  • A scancode set is a specification that associates scancodes with keys pressed/released.

For the full code, go to the repo

In The Next Post

We'll be digging into scancode set 1 and starting with the keyboard driver.

References