Page 1 of 1

Trouble reading multi-byte scan codes from 8042 Controller

Posted: Sun Mar 28, 2021 8:01 pm
by martmichals
I was recently working on enhancing my keyboard driver, providing support for more than alphanumeric and symbol keys (arrow keys, etc.), and ran into this problem. When reading from port 60h, I could only read the last N - 1 bytes of a scan code that I know should be N bytes, e.g. pressing the left arrow key results in the read code 6Bh 6Bh, as opposed to the expected E0h 6Bh.

Below is the code I put in to my handler instead of my usual code, for debugging purposes.

Code: Select all

void _handle_keyboard() {
    // Send EOI to PIC
    send_eoi(KEYBOARD_IRQ_PIN);

    // Read and print value from 60h
    printf("%#x ", inb(KEYBOARD_IN_PORT));
    printf("%#x\n", inb(KEYBOARD_IN_PORT));
}
In debugging, I have done a couple of things. I have changed the 8042 configuration byte to disable translation (bit 6). This changed the scan code from code set 1 to code set 2, although I was still unable to read all the bytes of the scan code sequence using multiple I/O reads with print statements, as shown above. I have also tried explicitly setting the scan code sent from the keyboard, via command F0h set to the keyboard, but still get the same behavior, just with byte values printed corresponding to different scan code sets.

Here is the code I use to initialize the keyboard. This is where I added commands to disable translation and set the scan code set when debugging (code not shown for those settings).

Code: Select all

// Initialization function
int init_keyboard() {
    // Disable interrupts
    uint32_t flags;
    cli_and_save(flags);

    // Route interrupts to handler
    if(set_int(KEYBOARD_IRQ_PIN, _handle_keyboard)) return -1;

    // Intialize state
    device_state.r_shift   = 0;
    device_state.l_shift   = 0;
    device_state.caps      = 0;
    device_state.alt       = 0;
    device_state.status    = FREE;
    device_state.enable    = ENABLED;

    // Enable interrupts on the proper pin
    enable_irq(KEYBOARD_IRQ_PIN);

    // Restore flags, enable interrupts
    restore_flags(flags);
    sti();

    return 0;
}
Is this the proper way to read in scan codes, via multiple port 60h reads? If so, what could be possible causes of this issue?

Re: Trouble reading multi-byte scan codes from 8042 Controll

Posted: Sun Mar 28, 2021 9:26 pm
by Octocontrabass
The keyboard controller sends one byte per IRQ, not one scan code per IRQ. Read only one byte in the IRQ handler.

Re: Trouble reading multi-byte scan codes from 8042 Controll

Posted: Sun Mar 28, 2021 10:13 pm
by martmichals
Octocontrabass wrote:The keyboard controller sends one byte per IRQ, not one scan code per IRQ. Read only one byte in the IRQ handler.
Even reading one byte per IRQ, I have the same behavior. On a left arrow key (make code E0 6B), I only get one IRQ on the button press, and that is for 6B. On release (break code E0 F0 6B) I get interrupts only for 6B, F0, in that order. I am never able to read the E0 byte for some reason.

Re: Trouble reading multi-byte scan codes from 8042 Controll

Posted: Sun Mar 28, 2021 10:33 pm
by Octocontrabass
The interrupts can't arrive in the wrong order.

Do you have your interrupt handler configured as a trap gate or an interrupt gate?

Re: Trouble reading multi-byte scan codes from 8042 Controll

Posted: Mon Mar 29, 2021 12:40 am
by martmichals
Octocontrabass wrote:The interrupts can't arrive in the wrong order.

Do you have your interrupt handler configured as a trap gate or an interrupt gate?
I have it configured as an interrupt gate. Your comment gave me food for thought however, and I found that I was turning on interrupts in a set_cursor function, as I was calling sti() as opposed to restore_flags(). I fixed that issue, and made sure interrupts were off for the duration of the handler execution.

Since addressing that, bytes come in the right order, but I am still unable to read off the first byte, the E0 byte for left arrow.

What is even more puzzling is that this only seems to happen for scan codes with E0 included as a byte. Here are a few byte sequences as an example:

Code: Select all

                   Expected (M/B)                          Received (M/B)
Left Arrow:        E0 6B/E0 F0 6B                          6B/F0 6B
Print Screen:      E0 12 E0 7C/E0 F0 7C E0 F0 12           7C/F0 7C
Delete:            E0 71/E0 F0 71                          71/F0 71
All scan codes w/o E0 seem to be behaving as expected.

Re: Trouble reading multi-byte scan codes from 8042 Controll

Posted: Mon Mar 29, 2021 12:47 am
by Octocontrabass
What hardware or virtual machine are you using? Perhaps it doesn't support the extended scan codes, for whatever reason.

Re: Trouble reading multi-byte scan codes from 8042 Controll

Posted: Tue Mar 30, 2021 1:13 am
by martmichals
Octocontrabass wrote:What hardware or virtual machine are you using? Perhaps it doesn't support the extended scan codes, for whatever reason.
I am using QEMU. Was unable to find any documentation/people with the same issue in searching.

Re: Trouble reading multi-byte scan codes from 8042 Controll

Posted: Tue Mar 30, 2021 1:44 am
by Octocontrabass
Are you connecting to QEMU using VNC? QEMU may not be able to determine the appropriate scan codes to give to your OS when using VNC.

Re: Trouble reading multi-byte scan codes from 8042 Controll

Posted: Tue Mar 30, 2021 3:23 am
by pvc
I don't know if that's the source of your problem, but you are supposed to send EOI after reading data from the controller. Otherwise, you may get spurious interrupts and other weird behaviour.

Re: Trouble reading multi-byte scan codes from 8042 Controll

Posted: Wed Mar 31, 2021 9:06 pm
by martmichals
pvc wrote:I don't know if that's the source of your problem, but you are supposed to send EOI after reading data from the controller. Otherwise, you may get spurious interrupts and other weird behaviour.
Ah yes, this is something I forgot about as well. Thank you. Changing this did not resolve my issue with incorrect byte sequences.

Re: Trouble reading multi-byte scan codes from 8042 Controll

Posted: Wed Mar 31, 2021 9:20 pm
by martmichals
Octocontrabass wrote:Are you connecting to QEMU using VNC? QEMU may not be able to determine the appropriate scan codes to give to your OS when using VNC.
I am not connecting to QEMU using VNC. Your comment, however, prompted me to look into my QEMU settings, and I found the following in their documentation (https://qemu-project.gitlab.io/qemu/sys ... ation.html):
QEMU Documentation wrote:-k language
Use keyboard layout language (for example fr for French). This option is only needed where it is not easy to get raw PC keycodes (e.g. on Macs, with some X11 servers or with a VNC or curses display). You don’t normally need to use it on PC/Linux or PC/Windows hosts.
I found that explicitly setting the flag "-k en-us" resolved the issue, and I am now able to received all bytes for all scan codes. I am using neither curses, VNC, or a Mac OS, so something else must have caused this issue. Thank you for all the help and tips!