1 /*
2 * Copyright (c) 2006-2021, RT-Thread Development Team
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * Change Logs:
7 * Date Author Notes
8 * 2006-09-15 QiuYi the first version
9 * 2017-08-16 Parai the 2nd version
10 */
11
12 #include <rtthread.h>
13 #include <rthw.h>
14
15 #include <bsp.h>
16 #include "keyboard.h"
17 #include "keymap.h"
18
19 #define FALSE RT_FALSE
20 #define TRUE RT_TRUE
21 #define PRIVATE static
22 #define PUBLIC
23 #define t_bool rt_bool_t
24 #define t_8 rt_uint8_t
25 #define t_32 rt_uint32_t
26
27 PRIVATE KB_INPUT kb_in;
28 PRIVATE t_bool code_with_E0 = FALSE;
29 PRIVATE t_bool shift_l; /* l shift state */
30 PRIVATE t_bool shift_r; /* r shift state */
31 PRIVATE t_bool alt_l; /* l alt state */
32 PRIVATE t_bool alt_r; /* r left state */
33 PRIVATE t_bool ctrl_l; /* l ctrl state */
34 PRIVATE t_bool ctrl_r; /* l ctrl state */
35 PRIVATE t_bool caps_lock; /* Caps Lock */
36 PRIVATE t_bool num_lock; /* Num Lock */
37 PRIVATE t_bool scroll_lock; /* Scroll Lock */
38 PRIVATE int column = 0; /* keyrow[column] is one value of keymap */
39
40 PRIVATE t_8 get_byte_from_kb_buf();
41 PRIVATE void set_leds();
42 PRIVATE void kb_wait();
43 PRIVATE void kb_ack();
44
init_keyboard()45 PUBLIC void init_keyboard()
46 {
47 kb_in.count = 0;
48 kb_in.p_head = kb_in.p_tail = kb_in.buf;
49
50 caps_lock = 0;
51 num_lock = 1;
52 scroll_lock = 0;
53
54 set_leds();
55 }
keyboard_read(rt_uint32_t * pkey)56 PUBLIC rt_bool_t keyboard_read(rt_uint32_t *pkey)
57 {
58 t_8 scan_code;
59 t_bool make; /* TRUE : make */
60 /* FALSE: break */
61 t_32 key = 0;
62 t_32* keyrow;
63
64 if(kb_in.count > 0){
65 code_with_E0 = FALSE;
66 scan_code = get_byte_from_kb_buf();
67
68 /* start scan */
69 if (scan_code == 0xE1) {
70 int i;
71 static const t_8 pausebreak_scan_code[] = {0xE1, 0x1D, 0x45, 0xE1, 0x9D, 0xC5};
72 t_bool is_pausebreak = TRUE;
73 for(i=1;i<6;i++){
74 if (get_byte_from_kb_buf() != pausebreak_scan_code[i]) {
75 is_pausebreak = FALSE;
76 break;
77 }
78 }
79 if (is_pausebreak) {
80 key = PAUSEBREAK;
81 }
82 }
83 else if (scan_code == 0xE0) {
84 code_with_E0 = TRUE;
85 scan_code = get_byte_from_kb_buf();
86
87 /* PrintScreen pressed */
88 if (scan_code == 0x2A) {
89 code_with_E0 = FALSE;
90 if ((scan_code = get_byte_from_kb_buf()) == 0xE0) {
91 code_with_E0 = TRUE;
92 if ((scan_code = get_byte_from_kb_buf()) == 0x37) {
93 key = PRINTSCREEN;
94 make = TRUE;
95 }
96 }
97 }
98 /* PrintScreen released */
99 else if (scan_code == 0xB7) {
100 code_with_E0 = FALSE;
101 if ((scan_code = get_byte_from_kb_buf()) == 0xE0) {
102 code_with_E0 = TRUE;
103 if ((scan_code = get_byte_from_kb_buf()) == 0xAA) {
104 key = PRINTSCREEN;
105 make = FALSE;
106 }
107 }
108 }
109 } /* if is not PrintScreen, scan_code is the one after 0xE0 */
110 if ((key != PAUSEBREAK) && (key != PRINTSCREEN)) {
111 /* is Make Code or Break Code */
112 make = (scan_code & FLAG_BREAK ? FALSE : TRUE);
113
114 keyrow = &keymap[(scan_code & 0x7F) * MAP_COLS];
115
116 column = 0;
117
118 t_bool caps = shift_l || shift_r;
119 if (caps_lock) {
120 if ((keyrow[0] >= 'a') && (keyrow[0] <= 'z')){
121 caps = !caps;
122 }
123 }
124 if (caps) {
125 column = 1;
126 }
127
128 if (code_with_E0) {
129 column = 2;
130 }
131
132 key = keyrow[column];
133
134 switch(key) {
135 case SHIFT_L:
136 shift_l = make;
137 break;
138 case SHIFT_R:
139 shift_r = make;
140 break;
141 case CTRL_L:
142 ctrl_l = make;
143 break;
144 case CTRL_R:
145 ctrl_r = make;
146 break;
147 case ALT_L:
148 alt_l = make;
149 break;
150 case ALT_R:
151 alt_l = make;
152 break;
153 case CAPS_LOCK:
154 if (make) {
155 caps_lock = !caps_lock;
156 set_leds();
157 }
158 break;
159 case NUM_LOCK:
160 if (make) {
161 num_lock = !num_lock;
162 set_leds();
163 }
164 break;
165 case SCROLL_LOCK:
166 if (make) {
167 scroll_lock = !scroll_lock;
168 set_leds();
169 }
170 break;
171 default:
172 break;
173 }
174 }
175
176 if(make){ /* ignore Break Code */
177 t_bool pad = FALSE;
178
179 /* handle the small pad first */
180 if ((key >= PAD_SLASH) && (key <= PAD_9)) {
181 pad = TRUE;
182 switch(key) { /* '/', '*', '-', '+', and 'Enter' in num pad */
183 case PAD_SLASH:
184 key = '/';
185 break;
186 case PAD_STAR:
187 key = '*';
188 break;
189 case PAD_MINUS:
190 key = '-';
191 break;
192 case PAD_PLUS:
193 key = '+';
194 break;
195 case PAD_ENTER:
196 key = ENTER;
197 break;
198 default: /* keys whose value depends on the NumLock */
199 if (num_lock) { /* '0' ~ '9' and '.' in num pad */
200 if ((key >= PAD_0) && (key <= PAD_9)) {
201 key = key - PAD_0 + '0';
202 }
203 else if (key == PAD_DOT) {
204 key = '.';
205 }
206 }
207 else{
208 switch(key) {
209 case PAD_HOME:
210 key = HOME;
211 break;
212 case PAD_END:
213 key = END;
214 break;
215 case PAD_PAGEUP:
216 key = PAGEUP;
217 break;
218 case PAD_PAGEDOWN:
219 key = PAGEDOWN;
220 break;
221 case PAD_INS:
222 key = INSERT;
223 break;
224 case PAD_UP:
225 key = UP;
226 break;
227 case PAD_DOWN:
228 key = DOWN;
229 break;
230 case PAD_LEFT:
231 key = LEFT;
232 break;
233 case PAD_RIGHT:
234 key = RIGHT;
235 break;
236 case PAD_DOT:
237 key = DELETE;
238 break;
239 default:
240 break;
241 }
242 }
243 break;
244 }
245 }
246 key |= shift_l ? FLAG_SHIFT_L : 0;
247 key |= shift_r ? FLAG_SHIFT_R : 0;
248 key |= ctrl_l ? FLAG_CTRL_L : 0;
249 key |= ctrl_r ? FLAG_CTRL_R : 0;
250 key |= alt_l ? FLAG_ALT_L : 0;
251 key |= alt_r ? FLAG_ALT_R : 0;
252 key |= pad ? FLAG_PAD : 0;
253
254 *pkey = key;
255 return TRUE;
256 }
257 }
258
259 return FALSE;
260 }
261
get_byte_from_kb_buf()262 PRIVATE t_8 get_byte_from_kb_buf()
263 {
264 t_8 scan_code;
265
266 RT_ASSERT(kb_in.count>0);
267 scan_code = *(kb_in.p_tail);
268 kb_in.p_tail++;
269 if (kb_in.p_tail == kb_in.buf + KB_IN_BYTES) {
270 kb_in.p_tail = kb_in.buf;
271 }
272 kb_in.count--;
273
274 return scan_code;
275 }
276
kb_wait()277 PRIVATE void kb_wait() /* wait inpit cache of 8042 */
278 {
279 t_8 kb_stat;
280
281 do {
282 kb_stat = inb(KB_CMD);
283 } while (kb_stat & 0x02);
284 }
285
kb_ack()286 PRIVATE void kb_ack()
287 {
288 t_8 kb_read;
289
290 do {
291 kb_read = inb(KB_DATA);
292 } while (kb_read != KB_ACK);
293 }
294
set_leds()295 PRIVATE void set_leds()
296 {
297 t_8 leds = (caps_lock << 2) | (num_lock << 1) | scroll_lock;
298
299 kb_wait();
300 outb(KB_DATA, LED_CODE);
301 kb_ack();
302
303 kb_wait();
304 outb(KB_DATA, leds);
305 kb_ack();
306 }
307
308 /**
309 * @addtogroup QEMU
310 */
311 /*@{*/
312
rt_keyboard_isr(void)313 void rt_keyboard_isr(void)
314 {
315 rt_uint8_t data;
316
317 if ((inb(KBSTATP) & KBS_DIB) == 0)
318 return ;
319
320 data = inb(KBDATAP);
321
322 if (kb_in.count < KB_IN_BYTES) {
323 *(kb_in.p_head) = data;
324 kb_in.p_head++;
325 if (kb_in.p_head == kb_in.buf + KB_IN_BYTES) {
326 kb_in.p_head = kb_in.buf;
327 }
328 kb_in.count++;
329 }
330 }
331 /* generally, this should be called in task level for all key inpit support,
332 but here only support a key that is composed of 2 bytes */
rt_keyboard_getc(char * c)333 rt_bool_t rt_keyboard_getc(char* c)
334 {
335 if(kb_in.count>=2)
336 {
337 rt_uint32_t key = 0;
338 rt_bool_t rv=keyboard_read(&key);
339
340 switch(key)
341 {
342 case TAB:
343 *c = '\t';
344 break;
345 case ENTER:
346 *c = '\n';
347 break;
348 case BACKSPACE:
349 *c = '\b';
350 break;
351 default:
352 *c = key;
353 break;
354 }
355
356 return rv;
357 }
358
359 return RT_FALSE;
360 }
361
362 /*@}*/
363