PKUOS - Pintos
Pintos source browser for PKU Operating System course
kbd.c
Go to the documentation of this file.
1#include "devices/kbd.h"
2#include <ctype.h>
3#include <debug.h>
4#include <stdio.h>
5#include <string.h>
6#include "devices/input.h"
7#include "devices/shutdown.h"
8#include "threads/interrupt.h"
9#include "threads/io.h"
10
11/** Keyboard data register port. */
12#define DATA_REG 0x60
13
14/** Current state of shift keys.
15 True if depressed, false otherwise. */
16static bool left_shift, right_shift; /**< Left and right Shift keys. */
17static bool left_alt, right_alt; /**< Left and right Alt keys. */
18static bool left_ctrl, right_ctrl; /**< Left and right Ctl keys. */
19
20/** Status of Caps Lock.
21 True when on, false when off. */
22static bool caps_lock;
23
24/** Number of keys pressed. */
26
28
29/** Initializes the keyboard. */
30void
31kbd_init (void)
32{
33 intr_register_ext (0x21, keyboard_interrupt, "8042 Keyboard");
34}
35
36/** Prints keyboard statistics. */
37void
39{
40 printf ("Keyboard: %lld keys pressed\n", key_cnt);
41}
42
43/** Maps a set of contiguous scancodes into characters. */
44struct keymap
45 {
46 uint8_t first_scancode; /**< First scancode. */
47 const char *chars; /**< chars[0] has scancode first_scancode,
48 chars[1] has scancode first_scancode + 1,
49 and so on to the end of the string. */
50 };
51
52/** Keys that produce the same characters regardless of whether
53 the Shift keys are down. Case of letters is an exception
54 that we handle elsewhere. */
55static const struct keymap invariant_keymap[] =
56 {
57 {0x01, "\033"}, /**< Escape. */
58 {0x0e, "\b"},
59 {0x0f, "\tQWERTYUIOP"},
60 {0x1c, "\r"},
61 {0x1e, "ASDFGHJKL"},
62 {0x2c, "ZXCVBNM"},
63 {0x37, "*"},
64 {0x39, " "},
65 {0x53, "\177"}, /**< Delete. */
66 {0, NULL},
67 };
68
69/** Characters for keys pressed without Shift, for those keys
70 where it matters. */
71static const struct keymap unshifted_keymap[] =
72 {
73 {0x02, "1234567890-="},
74 {0x1a, "[]"},
75 {0x27, ";'`"},
76 {0x2b, "\\"},
77 {0x33, ",./"},
78 {0, NULL},
79 };
80
81/** Characters for keys pressed with Shift, for those keys where
82 it matters. */
83static const struct keymap shifted_keymap[] =
84 {
85 {0x02, "!@#$%^&*()_+"},
86 {0x1a, "{}"},
87 {0x27, ":\"~"},
88 {0x2b, "|"},
89 {0x33, "<>?"},
90 {0, NULL},
91 };
92
93static bool map_key (const struct keymap[], unsigned scancode, uint8_t *);
94
95static void
97{
98 /* Status of shift keys. */
99 bool shift = left_shift || right_shift;
100 bool alt = left_alt || right_alt;
101 bool ctrl = left_ctrl || right_ctrl;
102
103 /* Keyboard scancode. */
104 unsigned code;
105
106 /* False if key pressed, true if key released. */
107 bool release;
108
109 /* Character that corresponds to `code'. */
110 uint8_t c;
111
112 /* Read scancode, including second byte if prefix code. */
113 code = inb (DATA_REG);
114 if (code == 0xe0)
115 code = (code << 8) | inb (DATA_REG);
116
117 /* Bit 0x80 distinguishes key press from key release
118 (even if there's a prefix). */
119 release = (code & 0x80) != 0;
120 code &= ~0x80u;
121
122 /* Interpret key. */
123 if (code == 0x3a)
124 {
125 /* Caps Lock. */
126 if (!release)
128 }
129 else if (map_key (invariant_keymap, code, &c)
130 || (!shift && map_key (unshifted_keymap, code, &c))
131 || (shift && map_key (shifted_keymap, code, &c)))
132 {
133 /* Ordinary character. */
134 if (!release)
135 {
136 /* Reboot if Ctrl+Alt+Del pressed. */
137 if (c == 0177 && ctrl && alt)
139
140 /* Handle Ctrl, Shift.
141 Note that Ctrl overrides Shift. */
142 if (ctrl && c >= 0x40 && c < 0x60)
143 {
144 /* A is 0x41, Ctrl+A is 0x01, etc. */
145 c -= 0x40;
146 }
147 else if (shift == caps_lock)
148 c = tolower (c);
149
150 /* Handle Alt by setting the high bit.
151 This 0x80 is unrelated to the one used to
152 distinguish key press from key release. */
153 if (alt)
154 c += 0x80;
155
156 /* Append to keyboard buffer. */
157 if (!input_full ())
158 {
159 key_cnt++;
160 input_putc (c);
161 }
162 }
163 }
164 else
165 {
166 /* Maps a keycode into a shift state variable. */
167 struct shift_key
168 {
169 unsigned scancode;
170 bool *state_var;
171 };
172
173 /* Table of shift keys. */
174 static const struct shift_key shift_keys[] =
175 {
176 { 0x2a, &left_shift},
177 { 0x36, &right_shift},
178 { 0x38, &left_alt},
179 {0xe038, &right_alt},
180 { 0x1d, &left_ctrl},
181 {0xe01d, &right_ctrl},
182 {0, NULL},
183 };
184
185 const struct shift_key *key;
186
187 /* Scan the table. */
188 for (key = shift_keys; key->scancode != 0; key++)
189 if (key->scancode == code)
190 {
191 *key->state_var = !release;
192 break;
193 }
194 }
195}
196
197/** Scans the array of keymaps K for SCANCODE.
198 If found, sets *C to the corresponding character and returns
199 true.
200 If not found, returns false and C is ignored. */
201static bool
202map_key (const struct keymap k[], unsigned scancode, uint8_t *c)
203{
204 for (; k->first_scancode != 0; k++)
205 if (scancode >= k->first_scancode
206 && scancode < k->first_scancode + strlen (k->chars))
207 {
208 *c = k->chars[scancode - k->first_scancode];
209 return true;
210 }
211
212 return false;
213}
static int tolower(int c)
Definition: ctype.h:25
#define UNUSED
GCC lets us add "attributes" to functions, function parameters, etc.
Definition: debug.h:7
bool input_full(void)
Returns true if the input buffer is full, false otherwise.
Definition: input.c:48
void input_putc(uint8_t key)
Adds a key to the input buffer.
Definition: input.c:19
void intr_register_ext(uint8_t vec_no, intr_handler_func *handler, const char *name)
Registers external interrupt VEC_NO to invoke HANDLER, which is named NAME for debugging purposes.
Definition: interrupt.c:181
void intr_handler_func(struct intr_frame *)
Definition: interrupt.h:58
static uint8_t inb(uint16_t port)
Reads and returns a byte from PORT.
Definition: io.h:9
static bool left_ctrl
Definition: kbd.c:18
void kbd_init(void)
Initializes the keyboard.
Definition: kbd.c:31
static bool right_shift
Left and right Shift keys.
Definition: kbd.c:16
static const struct keymap unshifted_keymap[]
Characters for keys pressed without Shift, for those keys where it matters.
Definition: kbd.c:71
static intr_handler_func keyboard_interrupt
Definition: kbd.c:27
static bool caps_lock
Status of Caps Lock.
Definition: kbd.c:22
static bool left_shift
Current state of shift keys.
Definition: kbd.c:16
#define DATA_REG
Keyboard data register port.
Definition: kbd.c:12
static int64_t key_cnt
Number of keys pressed.
Definition: kbd.c:25
static const struct keymap invariant_keymap[]
Keys that produce the same characters regardless of whether the Shift keys are down.
Definition: kbd.c:55
static bool right_ctrl
Left and right Ctl keys.
Definition: kbd.c:18
void kbd_print_stats(void)
Prints keyboard statistics.
Definition: kbd.c:38
static bool map_key(const struct keymap[], unsigned scancode, uint8_t *)
Scans the array of keymaps K for SCANCODE.
Definition: kbd.c:202
static bool left_alt
Definition: kbd.c:17
static const struct keymap shifted_keymap[]
Characters for keys pressed with Shift, for those keys where it matters.
Definition: kbd.c:83
static bool right_alt
Left and right Alt keys.
Definition: kbd.c:17
int printf(const char *format,...)
Writes formatted output to the console.
Definition: stdio.c:79
void shutdown_reboot(void)
Reboots the machine via the keyboard controller.
Definition: shutdown.c:57
#define NULL
Definition: stddef.h:4
signed long long int int64_t
Definition: stdint.h:16
unsigned char uint8_t
Definition: stdint.h:20
size_t strlen(const char *string)
Returns the length of STRING.
Definition: string.c:293
Interrupt stack frame.
Definition: interrupt.h:21
Maps a set of contiguous scancodes into characters.
Definition: kbd.c:45
const char * chars
chars[0] has scancode first_scancode, chars[1] has scancode first_scancode + 1, and so on to the end ...
Definition: kbd.c:47
uint8_t first_scancode
First scancode.
Definition: kbd.c:46