5. Testing Code

So that we can grade your work, you are required to implement the test functions described in this section. We will develop the code that will call them, so make sure that your implementation matches their prototypes.

Rather than implement the required functionality directly in these functions, you should design and implement functions that may be useful to interface with the keyboard in your integration project, i.e. functions that read the scancodes sent by the keyboard and that may be of use to configure or to find the status of the keyboard. You should try to implement a layered solution as suggested in the lectures. You will score points for the quality of the design of your functions. We will grade not only how you structure the required functionality in functions, but also how do you group these functions in compilation modules, i.e. in the source files.

5.1 kbd_test_scan(unsigned short asm)

The purpose of this function is to test that your code is able to read the scancodes from the KBC using an interrupt handler (IH). Depending on whether its argument is zero or not, it should use the IH written in C or the IH written in assembly.

Independently of the implementation language of the IH, it should first subscribe the KBC interrupts, as described in the previous section.

Then, as the IH receives the scancodes from the keyboard, it should print them on the console, indicating whether or not the scancode is a make or a break code. The output should look like the following:

Makecode: 0x12 Breakcode: 0x92 Makecode: 0xeO 0x49 Breakcode: 0xe0 0xc9

The kbd_test_scan() function should exit when the user releases the Esc key, whose break code is 0x81. For the reasons described in the previous section, it should cancel the subscription of the KBC interrupt before terminating. Also, before returning, this function should print the number of sys_inb kernel calls.

IMP. If you do not cancel the subscription of the KBC interrupt, Minix's keyboard interrupt handler will not be notified of interrupts on the keyboard and therefore you will not be able to use any of the virtual terminals on the virtual machine. However, you will be able to use the command line interface (CLI) via a remote shell, for example on a Linux terminal, or in Eclipse. The remote shell uses the keyboard on a system different from Minix.

ASM Implementation

You must use the linked assembly approach to mix C and assembly code, i.e. your assembly code and your C code should be in separate files. Furthermore, your ASM implementation of the IH should use the GNU assembler syntax.

Note that in this case, kbd_test_scan() should not print the number of sys_inb() kernel calls.

IMP. The variables used to pass information between the interrupt handler and the rest of your program should be defined in the assembly file.

IMP. If you use directives of the C preprocessor, e.g. #include or #define, your file must have the .S (upper case s) extension, otherwise the C preprocessor will not be invoked (check gcc's documentation).

5.2 kbd_test_poll()

The purpose of this function is to test that your code is able to read the scancodes from the KBC using polling, i.e. you cannot use interrupts.

Like kbd_test_scan(), kbd_test_poll() should read the scan codes sent by the keyboard and print them on the console, indicating whether or not the scancode is a make or a break code. The output should look like the following:

Makecode: 0x01 Breakcode: 0x81

Likewise, kbd_test_poll() function should exit when the user releases the Esc key, whose break code is 0x81, and print the number of sys_inb() kernel calls.

Food for thought Can you explain the large difference between the numbers of sys_inb() kernel calls displayed by kbd_test_poll() and by kbd_test_scan()?

To prevent Minix's keyboard IH from stealing the scancodes from your program, you must execute the kbc_cmdr utility as follows before running kbd_test_poll():

service run `pwd`/kbc_cmdr -args "disable"

This priviledged program will disable interrupts, by writing the appropriate command byte. Thus, before exiting, kbd_test_poll() must enable interrupts, also by writing the appropriate command byte.

IMP: You can use the configuration file for lab3 for kbc_cmdr as well, but make sure to rename it accordingly and to change the string after service, in the first line, to kbc_cmdr.

Because writing to the command byte may leave the KBC in an unusable state, kbc_cmdr provides the following options that allow you to reset the KBC to a proper state, without having to reboot Minix:

read
Prints the command byte, read using the 0x20 (Read Command Byte) KBC command. You should use this option, before disabling interrupts. The value printed, may be later used with the next option, if the keyboard is not usable after running kbd_test_poll()
write <command byte in hexadecimal>
Writes the hexadecimal value provided as argument to the command byte, using the 0x60 (Write Command Byte) KBC command. You should use this option, using the value printed using the read option, if the keyboard is not usable after running kbd_test_poll()
flush
Flushes the KBC output buffer. This may be helpful, if the keyboard is not usable after running your code.

5.3 kbd_test_timed_scan(unsigned short n)

The purpose of this function is to test whether your program is able to handle interrupts from more than one device.

Essentially, this test program should be similar to kbd_test_scan() in that it should print in the console the scancodes received from the keyboard (here, you can use only the C-version of the IH). The difference is that in this function, your program should exit not only when the user releases the ESC key, but also if it does not receive a scancode for a number seconds equal to its argument, n.

To measure this time interval you must use the interrupts of the PC's Timer 0. Note that you need not change the configuration of PC's Timer 0, only subscribe its interrupts, as done in timer_test_square() of Lab 2.