Series catalog

keyboard input

This kernel series project has completed the construction of all the basic functions here. The last two articles are considered as extended and perfect. We will add the keyboard function and implement a shell command line interface on this basis.

Keyboard code

The detailed principles and implementation of the keyboard are tedious and boring. I don’t want to waste time explaining here. If you are interested, you can find information on the Internet to study. This article will simplify the processing as much as possible, omit many low-level details, and only focus on the core implementation principles.

Generally speaking, if you press a key on the keyboard and then release it, it will generate two electrical signals:

  • The signal generated by pressing the key is called the pass code ( make code ), which means to connect;
  • The signal generated by releasing the key is called broken code ( break code ), which means disconnected;

Both the pass code and the break code are called scan codes ( scan code ), which are treated the same for the keyboard, which is to send a signal to the host. After the operating system receives this series of signals, it needs to translate them into corresponding output characters . It is necessary for a key to have two codes on and off. For example, on the user interface, you can decide whether to press the key to print the character, or you must press and release it to print the character. This is different in the user experience For example, some key combinations, Shift + a, will be translated into a pass code of A after the system continuously receives the pass code of Shfit and the pass code of a, and there can be no Shfit break codes in the middle, otherwise it means Shift has been release.

Interrupt trigger

The keyboard signal is triggered by an interrupt, the interrupt number is 33, so we first register an interrupt handler for it:

register_interrupt_handler(IRQ1_INT_NUM,
                           &keyboard_interrupt_handler);

In the keyboard_interrupt_handler function, the 0x60 , and then it will be added to the buffer for temporary storage. Here we use a ring buffer ( ring buffer ), which is a queue with limited capacity. The keyboard interrupt handler keeps adding the newly input scan code to the end of the buffer, while the consumer keeps reading from the head of the buffer. Consume scan code and translate it into characters.

Consumption blocking waiting

The scan code buffer queue consumer is the function read_keyboard_char_impl , its core logic is in the function process_scancode , its function is to translate the read scan code into characters. However, its implementation details do not need to be delved into, it is very boring and lengthy, just translating the scan code table.

int32 read_keyboard_char_impl() {
  if (queue.size == 0) {
    return -1;
  }

  int32 augchar = process_scancode((int)dequeue());
  while (!(KH_HASDATA(augchar) && KH_ISMAKE(augchar))) {
    if (queue.size == 0) {
      return -1;
    }
    augchar = process_scancode((int)dequeue());
  }
  return KH_GETCHAR(augchar);
}

If the buffer is empty, or the current scan code is not enough to translate into a valid character (for example, it can only read a Shfit pass code), then it will not return a valid character. Pay attention to its exit judgment conditions:

(KH_HASDATA(augchar) && KH_ISMAKE(augchar))

That is, what is translated is a valid character and a pass code, which is regarded as a legal key input and needs to be returned to the upper layer for feedback.

read_char system call

Let's look at how the user gets the characters entered by the keyboard from top to bottom. The keyboard input is processed in the kernel. As the user layer, it needs to use system calls to obtain keyboard input. We define a new system call read_char , the specific implementation is read_keyboard_char function, it calls the above read_keyboard_char_impl function. If there are no valid characters that can be translated, it will block the current thread, and the user side seems to be the program will be stuck here, waiting for keyboard input.

If a new keyboard interrupt comes in, indicating that there is a new scan code, the kernel will wake up read_keyboard_char , let it continue to consume the scan code buffer queue, and try to continue to translate valid characters.

You can use the following test program, and you will get a shell-like command line on the screen, or the feedback output character effect of the keys in a text editor:

void test_read_char() {
    while (1) {
        int8 c = read_char();
        printf("%c", c);
    }
}

navi
612 声望191 粉丝

naive