1 00:00:01,380 --> 00:00:08,730 Hello, in this section we will add ps/2 keyboard support and then we can interact with kernel in the console. 2 00:00:09,450 --> 00:00:15,240 In this lecture, we are going to write a keyboard driver. If you want to test it on the real machine, 3 00:00:15,270 --> 00:00:17,270 be sure to use ps/2 keyboard. 4 00:00:17,970 --> 00:00:19,300 OK, let's get started. 5 00:00:19,980 --> 00:00:25,100 As you see, the keyboard is connected to the PIC using irq1. 6 00:00:25,830 --> 00:00:31,910 So the keyboard uses interrupt signal 1. We should enable it in the PIC chip 7 00:00:31,920 --> 00:00:33,620 so that the keyboard interrupt 8 00:00:33,630 --> 00:00:35,010 will be sent to the cpu. 9 00:00:36,170 --> 00:00:41,810 Generally, the keyboard should be initialized before we use it. But in this example, we assume that 10 00:00:41,810 --> 00:00:46,130 the initialization of the keyboard is done before the kernel is running. 11 00:00:46,980 --> 00:00:49,890 So we only configure the PIC in the kernel file. 12 00:00:56,470 --> 00:01:03,070 As you see here, here we masked all the interrupts except the timer interrupt in the previous lectures, and now we can 13 00:01:03,220 --> 00:01:06,340 unmask the second one which is the irq1. 14 00:01:07,490 --> 00:01:12,940 The next thing we are going to do is install the keyboard interrupt service routine so 15 00:01:13,010 --> 00:01:15,970 that the handler will be called when the keyboard interrupt is fired. 16 00:01:16,790 --> 00:01:18,920 We have done this several times before. 17 00:01:20,290 --> 00:01:22,330 So in the trap.asm file, 18 00:01:27,260 --> 00:01:34,750 we define vector33, push 0 which means there is no error code and index number 33 19 00:01:34,760 --> 00:01:35,510 , 20 00:01:36,020 --> 00:01:37,190 Then we jump to trap. 21 00:01:38,840 --> 00:01:42,400 Declare it global so that we can reference it in other files. 22 00:01:45,450 --> 00:01:50,890 In the trap.h file, we add the declaration of the vector33 23 00:01:50,990 --> 00:01:57,060 and now we can set the corresponding idt entry 33 in this case in the trap.c file. 24 00:02:00,970 --> 00:02:05,540 Ok now we can receive the keyboard requests in the interrupt handler. 25 00:02:06,540 --> 00:02:08,130 In the function handler, 26 00:02:09,789 --> 00:02:16,330 if the index number is 33, it means that this is the keyboard interrupt and we call keyboard handler 27 00:02:16,330 --> 00:02:19,120 to process this request. 28 00:02:19,150 --> 00:02:21,070 In the end, don’t forget to send end of interrupt 29 00:02:21,190 --> 00:02:24,700 otherwise we will not receive keyboard interrupts after we return. 30 00:02:25,570 --> 00:02:30,340 So let’s focus on the keyboard handler which is defined in the keyboard.c file. 31 00:02:34,220 --> 00:02:41,320 As you see, we defined these arrays. Let’s first look at the keymap. These are the characters we have 32 00:02:41,330 --> 00:02:42,110 in the keyboard. 33 00:02:43,230 --> 00:02:49,440 Note that the data sent from keyboard to the handler is not the data we see here. The data is called 34 00:02:49,440 --> 00:02:55,500 scan code, which means we need to convert the scan code to ascii code for the keyboard character 35 00:02:55,500 --> 00:02:56,660 and print it on the screen. 36 00:02:57,330 --> 00:02:59,810 So we define the keymap arrays to do that. 37 00:03:00,420 --> 00:03:02,100 We have normal key map array 38 00:03:02,100 --> 00:03:03,330 and shift key map array. 39 00:03:04,530 --> 00:03:10,770 The shift map is used when we hold shift key and press other keys. As you see, the characters in this array 40 00:03:10,770 --> 00:03:16,890 are the keys we get when we use shift key or capslock key. The shift code and lock code 41 00:03:16,890 --> 00:03:20,230 include the scan code for shift and capslock. 42 00:03:20,250 --> 00:03:26,340 Here we initialize the array with shift constants to the corresponding elements specified by the hexadecimal numbers 43 00:03:26,340 --> 00:03:27,020 , 44 00:03:27,030 --> 00:03:30,460 and other elements are set to 0. 45 00:03:31,290 --> 00:03:34,290 The caps lock array is initialized in the same way. 46 00:03:34,830 --> 00:03:38,340 The index numbers here are the scan codes of the left shift key, 47 00:03:38,340 --> 00:03:41,490 right shift key and capslock key. 48 00:03:42,470 --> 00:03:47,900 In this course, the console we will implement is simple which doesn’t support the numeric keypad 49 00:03:47,900 --> 00:03:51,560 and function keys except capslock and shift keys. 50 00:03:52,480 --> 00:03:59,530 Ok now let’s talk about how to read a key from keyboard. We do it in function keyboard read. 51 00:03:59,530 --> 00:04:00,730 To read a scan code, 52 00:04:01,770 --> 00:04:03,780 we read from port 60. 53 00:04:04,900 --> 00:04:07,720 The in byte function is defined in the assembly code. 54 00:04:09,880 --> 00:04:11,470 In the trap assembly file, 55 00:04:13,590 --> 00:04:21,300 we define the in byte here. As you see, we save the argument which is port number in rdx register 56 00:04:21,300 --> 00:04:26,700 and then read the data to register al using instruction in, and then we simply return. 57 00:04:28,160 --> 00:04:29,660 Ok back to the c file. 58 00:04:31,100 --> 00:04:37,940 After we return from in byte function, the variable scan code saves the data. 59 00:04:37,940 --> 00:04:44,260 Before we move on, we need to talk a little bit about scan code. The scan code is sent to the handler when we press a key and release a key 60 00:04:44,260 --> 00:04:44,700 . 61 00:04:45,530 --> 00:04:47,270 So we have two scenarios. 62 00:04:47,390 --> 00:04:56,180 key down and key up or make code and break code. The break code is the code of corresponding make code ors with 80 63 00:04:56,180 --> 00:04:56,610 . 64 00:04:58,480 --> 00:05:04,620 We have 3 sets of scan code. In this course, the keyboard driver works with scan code set 1 65 00:05:04,620 --> 00:05:05,350 . 66 00:05:06,720 --> 00:05:13,770 We have one byte code for a key, multiple-byte code used for function keys which will be sent one byte at a time 67 00:05:13,770 --> 00:05:14,480 . 68 00:05:15,150 --> 00:05:19,000 Most of the multiple-byte key code comes with E0 first. 69 00:05:19,620 --> 00:05:20,990 So here we do the test. 70 00:05:21,600 --> 00:05:28,260 So here we do the test. If the scan code starts with e0, we will add the e0 sign to the flag and return 0 71 00:05:28,260 --> 00:05:29,670 meaning that the key is not valid. 72 00:05:31,040 --> 00:05:38,970 If the key is not equal to e0, but the e0 is set in the flag, it means that the last scan code is e0, 73 00:05:39,110 --> 00:05:42,610 so this key is a function key which is not used in the system 74 00:05:43,400 --> 00:05:47,030 and we also clear the e0 flag for testing the following keys. 75 00:05:48,670 --> 00:05:55,240 There is pause key which start with code e1. In this example, we don’t handle this case 76 00:05:55,240 --> 00:05:59,500 and we should be fine since other codes in this key are not defined in the key map. 77 00:06:00,070 --> 00:06:01,290 Alright, let’s move on. 78 00:06:02,700 --> 00:06:10,140 The next if statement is for handling the key up. We will see it later. After we pass the check, 79 00:06:10,140 --> 00:06:13,390 we can convert the key to the ascii code. All the code here 80 00:06:13,410 --> 00:06:15,010 is handling the cases 81 00:06:15,030 --> 00:06:17,910 where we press capslock key or hold the shift key. 82 00:06:17,910 --> 00:06:22,950 We first check the shift status using shift code array. 83 00:06:23,920 --> 00:06:30,750 Suppose the key is shift key, the scan code is used as an index into the array. So the shift constant 84 00:06:30,750 --> 00:06:31,450 is selected in this case. 85 00:06:31,470 --> 00:06:35,460 The constants are defined in the header file. 86 00:06:36,060 --> 00:06:37,210 OK, let's move on. 87 00:06:38,040 --> 00:06:44,730 Now if the key is shift key, the shift flag will be set in the flag variable. The next if statement 88 00:06:44,730 --> 00:06:45,630 will find the shift flag is set 89 00:06:45,630 --> 00:06:51,030 and we will get the key character in the shift key map which we want. 90 00:06:52,210 --> 00:06:55,420 Otherwise we will get the character in the normal key map. 91 00:06:56,420 --> 00:07:01,880 We know that when we hold the shift key and press other keys, the shift key is working as we expect. 92 00:07:01,880 --> 00:07:08,660 But if we press the shift key and release it before we press other keys, the shift key will not work, 93 00:07:08,660 --> 00:07:14,310 which means we need to check to see if the shift key is pressed when we receive other keys. 94 00:07:14,810 --> 00:07:22,310 So this is what the code here actually does. To check the key up, we simply test the scan code with 80. 95 00:07:23,330 --> 00:07:25,820 What it does here is just checking the bit 7. 96 00:07:25,820 --> 00:07:31,950 If the bit 7 is set, it means this is a key up and we will find the key in the shift key array. 97 00:07:31,950 --> 00:07:38,030 If the key we receive at this point is actually shift key, we will clear the shift flag 98 00:07:38,030 --> 00:07:43,010 because after we release the shift key, it will not be working for the following keys. 99 00:07:43,710 --> 00:07:46,700 Otherwise, it is a normal key 100 00:07:46,700 --> 00:07:48,110 and the shift flag remains unchanged. 101 00:07:49,250 --> 00:07:53,120 Ok now we have handled both the key down and key up cases. 102 00:07:54,050 --> 00:07:56,570 That is what we do regarding to the shift key. 103 00:07:58,000 --> 00:08:03,680 As you see, there is the capslock key we need to deal with as well. We know that the capslock key 104 00:08:03,730 --> 00:08:06,550 doesn’t work in the same way as shift key does. 105 00:08:07,090 --> 00:08:12,550 For example, after we press and release the caps lock, it will work until the next time we press and release it 106 00:08:12,550 --> 00:08:13,210 . 107 00:08:13,840 --> 00:08:17,110 So what we do here is we xor the capslock flag. 108 00:08:17,590 --> 00:08:23,230 If the flag has no capslock flag, then doing xor will set the capslock flag in the variable flag 109 00:08:23,230 --> 00:08:24,010 . 110 00:08:24,730 --> 00:08:28,360 If the flag has capslock set, then it will clear the capslock flag. 111 00:08:28,360 --> 00:08:30,940 It’s like toggle the key. 112 00:08:31,980 --> 00:08:37,830 As for other keys, the lock code array simply returns 0 and xors with 0 doesn’t change the value. 113 00:08:37,830 --> 00:08:40,659 With capslock case handled, 114 00:08:40,830 --> 00:08:42,570 then we get to the last part. 115 00:08:43,380 --> 00:08:50,420 If the capslock is on, we will change the capitalized English character to the lower-case one, and vice versa. 116 00:08:50,840 --> 00:08:54,900 The lower-case letter is 32 larger than the corresponding upper case one. 117 00:08:55,350 --> 00:08:59,450 So here we convert between these two sets of characters using 32. 118 00:09:00,300 --> 00:09:03,360 The last thing we do is return the character and we are done. 119 00:09:04,540 --> 00:09:09,520 In the keyboard handler, we just print the character on the screen if the return value is larger than 0 120 00:09:09,520 --> 00:09:10,090 . 121 00:09:11,130 --> 00:09:15,000 Here you can see we define array ch with 2 elements. 122 00:09:15,970 --> 00:09:21,280 The reason we define the array is that the print function doesn’t support printing single character. 123 00:09:21,570 --> 00:09:27,360 So instead we save it as a string with the second element being null character 124 00:09:27,360 --> 00:09:28,590 and now we can print the character. 125 00:09:29,750 --> 00:09:35,930 Before we test the project. There is one special case that is when we press backspace to delete characters. 126 00:09:36,800 --> 00:09:39,230 We handle this case in the print.c file. 127 00:09:41,780 --> 00:09:47,310 As you can see, in the function write screen, we can interpret enter key correctly. 128 00:09:47,870 --> 00:09:52,820 Now we add another if statement to handle the backspace key which is this character. 129 00:09:54,310 --> 00:10:00,240 The first thing we will do is check the current position. If we are at the beginning of the screen, 130 00:10:00,280 --> 00:10:02,230 we do nothing and continue the loop. 131 00:10:03,290 --> 00:10:08,460 Otherwise, we will check the column, if we are at the start of the line, we decrement the row 132 00:10:08,750 --> 00:10:10,770 and change the column to the end of the previous line. 133 00:10:11,360 --> 00:10:17,220 After all this is done, we can decrement the column value and write 0 in the current position 134 00:10:17,240 --> 00:10:18,220 which will clear the character. 135 00:10:19,000 --> 00:10:21,530 Let’s build the project and test it out. 136 00:10:28,350 --> 00:10:33,520 Here we have program exception message because we just use the programs in the last lecture. 137 00:10:34,350 --> 00:10:34,790 Alright, 138 00:10:34,830 --> 00:10:36,630 we press some keys to do the test. 139 00:10:41,180 --> 00:10:48,230 This is what we get when we just press key. If I hold shift key and press other keys, 140 00:10:48,230 --> 00:10:53,030 you can see the key changes accordingly. Let’s test caps lock as well. 141 00:10:57,260 --> 00:10:59,330 ok we get correct characters. 142 00:11:00,400 --> 00:11:03,010 When we hold the shift key, you can see, 143 00:11:04,560 --> 00:11:08,400 we print lowercase English letters when capslock is on. 144 00:11:14,240 --> 00:11:17,840 Now, let's test the backspace key. You can see, 145 00:11:19,490 --> 00:11:21,380 We're just delete the characters. 146 00:11:21,980 --> 00:11:25,310 Alright, that's it for this lecture and see you in the next video.