CS318 - Pintos
Pintos source browser for JHU CS318 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. */
16 static bool left_shift, right_shift; /**< Left and right Shift keys. */
17 static bool left_alt, right_alt; /**< Left and right Alt keys. */
18 static bool left_ctrl, right_ctrl; /**< Left and right Ctl keys. */
19 
20 /** Status of Caps Lock.
21  True when on, false when off. */
22 static bool caps_lock;
23 
24 /** Number of keys pressed. */
26 
28 
29 /** Initializes the keyboard. */
30 void
31 kbd_init (void)
32 {
33  intr_register_ext (0x21, keyboard_interrupt, "8042 Keyboard");
34 }
35 
36 /** Prints keyboard statistics. */
37 void
39 {
40  printf ("Keyboard: %lld keys pressed\n", key_cnt);
41 }
42 
43 /** Maps a set of contiguous scancodes into characters. */
44 struct 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. */
55 static 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. */
71 static 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. */
83 static const struct keymap shifted_keymap[] =
84  {
85  {0x02, "!@#$%^&*()_+"},
86  {0x1a, "{}"},
87  {0x27, ":\"~"},
88  {0x2b, "|"},
89  {0x33, "<>?"},
90  {0, NULL},
91  };
92 
93 static bool map_key (const struct keymap[], unsigned scancode, uint8_t *);
94 
95 static 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)
127  caps_lock = !caps_lock;
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)
138  shutdown_reboot ();
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. */
201 static bool
202 map_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 }
right_alt
static bool right_alt
Left and right Alt keys.
Definition: kbd.c:17
left_alt
static bool left_alt
Definition: kbd.c:17
left_shift
static bool left_shift
Current state of shift keys.
Definition: kbd.c:16
keymap
Maps a set of contiguous scancodes into characters.
Definition: kbd.c:44
uint8_t
unsigned char uint8_t
Definition: stdint.h:20
tolower
static int tolower(int c)
Definition: ctype.h:25
key_cnt
static int64_t key_cnt
Number of keys pressed.
Definition: kbd.c:25
NULL
#define NULL
Definition: stddef.h:4
string.h
keymap::first_scancode
uint8_t first_scancode
First scancode.
Definition: kbd.c:46
kbd_print_stats
void kbd_print_stats(void)
Prints keyboard statistics.
Definition: kbd.c:38
caps_lock
static bool caps_lock
Status of Caps Lock.
Definition: kbd.c:22
kbd.h
UNUSED
#define UNUSED
GCC lets us add "attributes" to functions, function parameters, etc.
Definition: debug.h:7
shutdown_reboot
void shutdown_reboot(void)
Reboots the machine via the keyboard controller.
Definition: shutdown.c:57
DATA_REG
#define DATA_REG
Keyboard data register port.
Definition: kbd.c:12
shutdown.h
right_ctrl
static bool right_ctrl
Left and right Ctl keys.
Definition: kbd.c:18
right_shift
static bool right_shift
Left and right Shift keys.
Definition: kbd.c:16
input_full
bool input_full(void)
Returns true if the input buffer is full, false otherwise.
Definition: input.c:48
ctype.h
int64_t
signed long long int int64_t
Definition: stdint.h:16
interrupt.h
shifted_keymap
static const struct keymap shifted_keymap[]
Characters for keys pressed with Shift, for those keys where it matters.
Definition: kbd.c:83
printf
int printf(const char *format,...)
Writes formatted output to the console.
Definition: stdio.c:79
keyboard_interrupt
static intr_handler_func keyboard_interrupt
Definition: kbd.c:27
map_key
static bool map_key(const struct keymap[], unsigned scancode, uint8_t *)
Scans the array of keymaps K for SCANCODE.
Definition: kbd.c:202
intr_handler_func
void intr_handler_func(struct intr_frame *)
Definition: interrupt.h:58
left_ctrl
static bool left_ctrl
Definition: kbd.c:18
keymap::chars
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
strlen
size_t strlen(const char *string)
Returns the length of STRING.
Definition: string.c:293
inb
static uint8_t inb(uint16_t port)
Reads and returns a byte from PORT.
Definition: io.h:9
io.h
invariant_keymap
static const struct keymap invariant_keymap[]
Keys that produce the same characters regardless of whether the Shift keys are down.
Definition: kbd.c:55
intr_register_ext
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
intr_frame
Interrupt stack frame.
Definition: interrupt.h:20
input_putc
void input_putc(uint8_t key)
Adds a key to the input buffer.
Definition: input.c:19
kbd_init
void kbd_init(void)
Initializes the keyboard.
Definition: kbd.c:31
input.h
unshifted_keymap
static const struct keymap unshifted_keymap[]
Characters for keys pressed without Shift, for those keys where it matters.
Definition: kbd.c:71
debug.h