Palacios Public Git Repository

To checkout Palacios execute

  git clone http://v3vee.org/palacios/palacios.web/palacios.git
This will give you the master branch. You probably want the devel branch or one of the release branches. To switch to the devel branch, simply execute
  cd palacios
  git checkout --track -b devel origin/devel
The other branches are similar.


imported SEABIOS source tree
[palacios.git] / bios / seabios / src / kbd.c
1 // 16bit code to handle keyboard requests.
2 //
3 // Copyright (C) 2008  Kevin O'Connor <kevin@koconnor.net>
4 // Copyright (C) 2002  MandrakeSoft S.A.
5 //
6 // This file may be distributed under the terms of the GNU LGPLv3 license.
7
8 #include "biosvar.h" // GET_BDA
9 #include "util.h" // debug_enter
10 #include "config.h" // CONFIG_*
11 #include "bregs.h" // struct bregs
12 #include "ps2port.h" // ps2_kbd_command
13 #include "usb-hid.h" // usb_kbd_command
14
15 // Bit definitions for BDA kbd_flag[012]
16 #define KF0_RSHIFT       (1<<0)
17 #define KF0_LSHIFT       (1<<1)
18 #define KF0_CTRLACTIVE   (1<<2)
19 #define KF0_ALTACTIVE    (1<<3)
20 #define KF0_SCROLLACTIVE (1<<4)
21 #define KF0_NUMACTIVE    (1<<5)
22 #define KF0_CAPSACTIVE   (1<<6)
23
24 #define KF1_LCTRL        (1<<0)
25 #define KF1_LALT         (1<<1)
26 #define KF1_PAUSEACTIVE  (1<<3)
27 #define KF1_SCROLL       (1<<4)
28 #define KF1_NUM          (1<<5)
29 #define KF1_CAPS         (1<<6)
30
31 #define KF2_LAST_E1    (1<<0)
32 #define KF2_LAST_E0    (1<<1)
33 #define KF2_RCTRL      (1<<2)
34 #define KF2_RALT       (1<<3)
35 #define KF2_101KBD     (1<<4)
36
37 void
38 kbd_setup(void)
39 {
40     dprintf(3, "init keyboard\n");
41     u16 x = offsetof(struct bios_data_area_s, kbd_buf);
42     SET_BDA(kbd_flag2, KF2_101KBD);
43     SET_BDA(kbd_buf_head, x);
44     SET_BDA(kbd_buf_tail, x);
45     SET_BDA(kbd_buf_start_offset, x);
46
47     SET_BDA(kbd_buf_end_offset
48             , x + FIELD_SIZEOF(struct bios_data_area_s, kbd_buf));
49 }
50
51 static u8
52 enqueue_key(u8 scan_code, u8 ascii_code)
53 {
54     u16 buffer_start = GET_BDA(kbd_buf_start_offset);
55     u16 buffer_end   = GET_BDA(kbd_buf_end_offset);
56
57     u16 buffer_head = GET_BDA(kbd_buf_head);
58     u16 buffer_tail = GET_BDA(kbd_buf_tail);
59
60     u16 temp_tail = buffer_tail;
61     buffer_tail += 2;
62     if (buffer_tail >= buffer_end)
63         buffer_tail = buffer_start;
64
65     if (buffer_tail == buffer_head)
66         return 0;
67
68     SET_FARVAR(SEG_BDA, *(u8*)(temp_tail+0), ascii_code);
69     SET_FARVAR(SEG_BDA, *(u8*)(temp_tail+1), scan_code);
70     SET_BDA(kbd_buf_tail, buffer_tail);
71     return 1;
72 }
73
74 static void
75 dequeue_key(struct bregs *regs, int incr, int extended)
76 {
77     yield();
78     u16 buffer_head;
79     u16 buffer_tail;
80     for (;;) {
81         buffer_head = GET_BDA(kbd_buf_head);
82         buffer_tail = GET_BDA(kbd_buf_tail);
83
84         if (buffer_head != buffer_tail)
85             break;
86         if (!incr) {
87             regs->flags |= F_ZF;
88             return;
89         }
90         wait_irq();
91     }
92
93     u8 ascii_code = GET_FARVAR(SEG_BDA, *(u8*)(buffer_head+0));
94     u8 scan_code  = GET_FARVAR(SEG_BDA, *(u8*)(buffer_head+1));
95     if ((ascii_code == 0xF0 && scan_code != 0)
96         || (ascii_code == 0xE0 && !extended))
97         ascii_code = 0;
98     regs->ax = (scan_code << 8) | ascii_code;
99
100     if (!incr) {
101         regs->flags &= ~F_ZF;
102         return;
103     }
104     u16 buffer_start = GET_BDA(kbd_buf_start_offset);
105     u16 buffer_end   = GET_BDA(kbd_buf_end_offset);
106
107     buffer_head += 2;
108     if (buffer_head >= buffer_end)
109         buffer_head = buffer_start;
110     SET_BDA(kbd_buf_head, buffer_head);
111 }
112
113 static inline int
114 kbd_command(int command, u8 *param)
115 {
116     if (usb_kbd_active())
117         return usb_kbd_command(command, param);
118     return ps2_kbd_command(command, param);
119 }
120
121 // read keyboard input
122 static void
123 handle_1600(struct bregs *regs)
124 {
125     dequeue_key(regs, 1, 0);
126 }
127
128 // check keyboard status
129 static void
130 handle_1601(struct bregs *regs)
131 {
132     dequeue_key(regs, 0, 0);
133 }
134
135 // get shift flag status
136 static void
137 handle_1602(struct bregs *regs)
138 {
139     yield();
140     regs->al = GET_BDA(kbd_flag0);
141 }
142
143 // store key-stroke into buffer
144 static void
145 handle_1605(struct bregs *regs)
146 {
147     regs->al = !enqueue_key(regs->ch, regs->cl);
148 }
149
150 // GET KEYBOARD FUNCTIONALITY
151 static void
152 handle_1609(struct bregs *regs)
153 {
154     // bit Bochs Description
155     //  7    0   reserved
156     //  6    0   INT 16/AH=20h-22h supported (122-key keyboard support)
157     //  5    1   INT 16/AH=10h-12h supported (enhanced keyboard support)
158     //  4    1   INT 16/AH=0Ah supported
159     //  3    0   INT 16/AX=0306h supported
160     //  2    0   INT 16/AX=0305h supported
161     //  1    0   INT 16/AX=0304h supported
162     //  0    0   INT 16/AX=0300h supported
163     //
164     regs->al = 0x30;
165 }
166
167 // GET KEYBOARD ID
168 static void
169 handle_160a(struct bregs *regs)
170 {
171     u8 param[2];
172     int ret = kbd_command(ATKBD_CMD_GETID, param);
173     if (ret) {
174         regs->bx = 0;
175         return;
176     }
177     regs->bx = (param[1] << 8) | param[0];
178 }
179
180 // read MF-II keyboard input
181 static void
182 handle_1610(struct bregs *regs)
183 {
184     dequeue_key(regs, 1, 1);
185 }
186
187 // check MF-II keyboard status
188 static void
189 handle_1611(struct bregs *regs)
190 {
191     dequeue_key(regs, 0, 1);
192 }
193
194 // get extended keyboard status
195 static void
196 handle_1612(struct bregs *regs)
197 {
198     yield();
199     regs->al = GET_BDA(kbd_flag0);
200     regs->ah = ((GET_BDA(kbd_flag1) & ~(KF2_RCTRL|KF2_RALT))
201                 | (GET_BDA(kbd_flag2) & (KF2_RCTRL|KF2_RALT)));
202     //BX_DEBUG_INT16("int16: func 12 sending %04x\n",AX);
203 }
204
205 static void
206 handle_166f(struct bregs *regs)
207 {
208     if (regs->al == 0x08)
209         // unsupported, aka normal keyboard
210         regs->ah = 2;
211 }
212
213 // keyboard capability check called by DOS 5.0+ keyb
214 static void
215 handle_1692(struct bregs *regs)
216 {
217     // function int16 ah=0x10-0x12 supported
218     regs->ah = 0x80;
219 }
220
221 // 122 keys capability check called by DOS 5.0+ keyb
222 static void
223 handle_16a2(struct bregs *regs)
224 {
225     // don't change AH : function int16 ah=0x20-0x22 NOT supported
226 }
227
228 static void
229 handle_16XX(struct bregs *regs)
230 {
231     warn_unimplemented(regs);
232 }
233
234 static void
235 set_leds(void)
236 {
237     u8 shift_flags = (GET_BDA(kbd_flag0) >> 4) & 0x07;
238     u8 kbd_led = GET_BDA(kbd_led);
239     u8 led_flags = kbd_led & 0x07;
240     if (shift_flags == led_flags)
241         return;
242
243     int ret = kbd_command(ATKBD_CMD_SETLEDS, &shift_flags);
244     if (ret)
245         // Error
246         return;
247     kbd_led = (kbd_led & ~0x07) | shift_flags;
248     SET_BDA(kbd_led, kbd_led);
249 }
250
251 // INT 16h Keyboard Service Entry Point
252 void VISIBLE16
253 handle_16(struct bregs *regs)
254 {
255     debug_enter(regs, DEBUG_HDL_16);
256     if (! CONFIG_KEYBOARD)
257         return;
258
259     // XXX - set_leds should be called from irq handler
260     set_leds();
261
262     switch (regs->ah) {
263     case 0x00: handle_1600(regs); break;
264     case 0x01: handle_1601(regs); break;
265     case 0x02: handle_1602(regs); break;
266     case 0x05: handle_1605(regs); break;
267     case 0x09: handle_1609(regs); break;
268     case 0x0a: handle_160a(regs); break;
269     case 0x10: handle_1610(regs); break;
270     case 0x11: handle_1611(regs); break;
271     case 0x12: handle_1612(regs); break;
272     case 0x92: handle_1692(regs); break;
273     case 0xa2: handle_16a2(regs); break;
274     case 0x6f: handle_166f(regs); break;
275     default:   handle_16XX(regs); break;
276     }
277 }
278
279 #define none 0
280 #define MNUM KF0_NUMACTIVE
281 #define MCAP KF0_CAPSACTIVE
282
283 static struct scaninfo {
284     u16 normal;
285     u16 shift;
286     u16 control;
287     u16 alt;
288     u8 lock_flags;
289 } scan_to_scanascii[] VAR16 = {
290     {   none,   none,   none,   none, none },
291     { 0x011b, 0x011b, 0x011b, 0x0100, none }, /* escape */
292     { 0x0231, 0x0221,   none, 0x7800, none }, /* 1! */
293     { 0x0332, 0x0340, 0x0300, 0x7900, none }, /* 2@ */
294     { 0x0433, 0x0423,   none, 0x7a00, none }, /* 3# */
295     { 0x0534, 0x0524,   none, 0x7b00, none }, /* 4$ */
296     { 0x0635, 0x0625,   none, 0x7c00, none }, /* 5% */
297     { 0x0736, 0x075e, 0x071e, 0x7d00, none }, /* 6^ */
298     { 0x0837, 0x0826,   none, 0x7e00, none }, /* 7& */
299     { 0x0938, 0x092a,   none, 0x7f00, none }, /* 8* */
300     { 0x0a39, 0x0a28,   none, 0x8000, none }, /* 9( */
301     { 0x0b30, 0x0b29,   none, 0x8100, none }, /* 0) */
302     { 0x0c2d, 0x0c5f, 0x0c1f, 0x8200, none }, /* -_ */
303     { 0x0d3d, 0x0d2b,   none, 0x8300, none }, /* =+ */
304     { 0x0e08, 0x0e08, 0x0e7f,   none, none }, /* backspace */
305     { 0x0f09, 0x0f00,   none,   none, none }, /* tab */
306     { 0x1071, 0x1051, 0x1011, 0x1000, MCAP }, /* Q */
307     { 0x1177, 0x1157, 0x1117, 0x1100, MCAP }, /* W */
308     { 0x1265, 0x1245, 0x1205, 0x1200, MCAP }, /* E */
309     { 0x1372, 0x1352, 0x1312, 0x1300, MCAP }, /* R */
310     { 0x1474, 0x1454, 0x1414, 0x1400, MCAP }, /* T */
311     { 0x1579, 0x1559, 0x1519, 0x1500, MCAP }, /* Y */
312     { 0x1675, 0x1655, 0x1615, 0x1600, MCAP }, /* U */
313     { 0x1769, 0x1749, 0x1709, 0x1700, MCAP }, /* I */
314     { 0x186f, 0x184f, 0x180f, 0x1800, MCAP }, /* O */
315     { 0x1970, 0x1950, 0x1910, 0x1900, MCAP }, /* P */
316     { 0x1a5b, 0x1a7b, 0x1a1b,   none, none }, /* [{ */
317     { 0x1b5d, 0x1b7d, 0x1b1d,   none, none }, /* ]} */
318     { 0x1c0d, 0x1c0d, 0x1c0a,   none, none }, /* Enter */
319     {   none,   none,   none,   none, none }, /* L Ctrl */
320     { 0x1e61, 0x1e41, 0x1e01, 0x1e00, MCAP }, /* A */
321     { 0x1f73, 0x1f53, 0x1f13, 0x1f00, MCAP }, /* S */
322     { 0x2064, 0x2044, 0x2004, 0x2000, MCAP }, /* D */
323     { 0x2166, 0x2146, 0x2106, 0x2100, MCAP }, /* F */
324     { 0x2267, 0x2247, 0x2207, 0x2200, MCAP }, /* G */
325     { 0x2368, 0x2348, 0x2308, 0x2300, MCAP }, /* H */
326     { 0x246a, 0x244a, 0x240a, 0x2400, MCAP }, /* J */
327     { 0x256b, 0x254b, 0x250b, 0x2500, MCAP }, /* K */
328     { 0x266c, 0x264c, 0x260c, 0x2600, MCAP }, /* L */
329     { 0x273b, 0x273a,   none,   none, none }, /* ;: */
330     { 0x2827, 0x2822,   none,   none, none }, /* '" */
331     { 0x2960, 0x297e,   none,   none, none }, /* `~ */
332     {   none,   none,   none,   none, none }, /* L shift */
333     { 0x2b5c, 0x2b7c, 0x2b1c,   none, none }, /* |\ */
334     { 0x2c7a, 0x2c5a, 0x2c1a, 0x2c00, MCAP }, /* Z */
335     { 0x2d78, 0x2d58, 0x2d18, 0x2d00, MCAP }, /* X */
336     { 0x2e63, 0x2e43, 0x2e03, 0x2e00, MCAP }, /* C */
337     { 0x2f76, 0x2f56, 0x2f16, 0x2f00, MCAP }, /* V */
338     { 0x3062, 0x3042, 0x3002, 0x3000, MCAP }, /* B */
339     { 0x316e, 0x314e, 0x310e, 0x3100, MCAP }, /* N */
340     { 0x326d, 0x324d, 0x320d, 0x3200, MCAP }, /* M */
341     { 0x332c, 0x333c,   none,   none, none }, /* ,< */
342     { 0x342e, 0x343e,   none,   none, none }, /* .> */
343     { 0x352f, 0x353f,   none,   none, none }, /* /? */
344     {   none,   none,   none,   none, none }, /* R Shift */
345     { 0x372a, 0x372a,   none,   none, none }, /* * */
346     {   none,   none,   none,   none, none }, /* L Alt */
347     { 0x3920, 0x3920, 0x3920, 0x3920, none }, /* space */
348     {   none,   none,   none,   none, none }, /* caps lock */
349     { 0x3b00, 0x5400, 0x5e00, 0x6800, none }, /* F1 */
350     { 0x3c00, 0x5500, 0x5f00, 0x6900, none }, /* F2 */
351     { 0x3d00, 0x5600, 0x6000, 0x6a00, none }, /* F3 */
352     { 0x3e00, 0x5700, 0x6100, 0x6b00, none }, /* F4 */
353     { 0x3f00, 0x5800, 0x6200, 0x6c00, none }, /* F5 */
354     { 0x4000, 0x5900, 0x6300, 0x6d00, none }, /* F6 */
355     { 0x4100, 0x5a00, 0x6400, 0x6e00, none }, /* F7 */
356     { 0x4200, 0x5b00, 0x6500, 0x6f00, none }, /* F8 */
357     { 0x4300, 0x5c00, 0x6600, 0x7000, none }, /* F9 */
358     { 0x4400, 0x5d00, 0x6700, 0x7100, none }, /* F10 */
359     {   none,   none,   none,   none, none }, /* Num Lock */
360     {   none,   none,   none,   none, none }, /* Scroll Lock */
361     { 0x4700, 0x4737, 0x7700,   none, MNUM }, /* 7 Home */
362     { 0x4800, 0x4838,   none,   none, MNUM }, /* 8 UP */
363     { 0x4900, 0x4939, 0x8400,   none, MNUM }, /* 9 PgUp */
364     { 0x4a2d, 0x4a2d,   none,   none, none }, /* - */
365     { 0x4b00, 0x4b34, 0x7300,   none, MNUM }, /* 4 Left */
366     { 0x4c00, 0x4c35,   none,   none, MNUM }, /* 5 */
367     { 0x4d00, 0x4d36, 0x7400,   none, MNUM }, /* 6 Right */
368     { 0x4e2b, 0x4e2b,   none,   none, none }, /* + */
369     { 0x4f00, 0x4f31, 0x7500,   none, MNUM }, /* 1 End */
370     { 0x5000, 0x5032,   none,   none, MNUM }, /* 2 Down */
371     { 0x5100, 0x5133, 0x7600,   none, MNUM }, /* 3 PgDn */
372     { 0x5200, 0x5230,   none,   none, MNUM }, /* 0 Ins */
373     { 0x5300, 0x532e,   none,   none, MNUM }, /* Del */
374     {   none,   none,   none,   none, none },
375     {   none,   none,   none,   none, none },
376     { 0x565c, 0x567c,   none,   none, none }, /* \| */
377     { 0x8500, 0x8700, 0x8900, 0x8b00, none }, /* F11 */
378     { 0x8600, 0x8800, 0x8a00, 0x8c00, none }, /* F12 */
379 };
380
381 // Handle a scancode read from the ps2 port.  Note that "noinline" is
382 // used to make sure the call to call16_simpint in process_key doesn't
383 // have the overhead of this function's stack.
384 static void noinline
385 __process_key(u8 scancode)
386 {
387     u8 flags0 = GET_BDA(kbd_flag0);
388     u8 flags1 = GET_BDA(kbd_flag1);
389     u8 flags2 = GET_BDA(kbd_flag2);
390
391     if (flags2 & KF2_LAST_E1) {
392         // Part of "pause" key (sequence is e1 1d 45 e1 9d c5)
393         if ((scancode & ~0x80) == 0x1d)
394             // Second key of sequence
395             return;
396         // Third key of sequence - clear flag.
397         flags2 &= ~KF2_LAST_E1;
398         SET_BDA(kbd_flag2, flags2);
399
400         if (scancode == 0xc5) {
401             // Final key in sequence.
402
403             // XXX - do actual pause.
404         }
405         return;
406     }
407
408     // XXX - PrtScr should cause int 0x05
409     // XXX - Ctrl+Break should cause int 0x1B
410     // XXX - SysReq should cause int 0x15/0x85
411
412     switch (scancode) {
413     case 0x00:
414         dprintf(1, "KBD: int09 handler: AL=0\n");
415         return;
416
417     case 0x3a: /* Caps Lock press */
418         flags0 ^= KF0_CAPSACTIVE;
419         flags1 |= KF1_CAPS;
420         break;
421     case 0xba: /* Caps Lock release */
422         flags1 &= ~KF1_CAPS;
423         break;
424
425     case 0x2a: /* L Shift press */
426         flags0 |= KF0_LSHIFT;
427         break;
428     case 0xaa: /* L Shift release */
429         flags0 &= ~KF0_LSHIFT;
430         break;
431
432     case 0x36: /* R Shift press */
433         flags0 |= KF0_RSHIFT;
434         break;
435     case 0xb6: /* R Shift release */
436         flags0 &= ~KF0_RSHIFT;
437         break;
438
439     case 0x1d: /* Ctrl press */
440         flags0 |= KF0_CTRLACTIVE;
441         if (flags2 & KF2_LAST_E0)
442             flags2 |= KF2_RCTRL;
443         else
444             flags1 |= KF1_LCTRL;
445         break;
446     case 0x9d: /* Ctrl release */
447         flags0 &= ~KF0_CTRLACTIVE;
448         if (flags2 & KF2_LAST_E0)
449             flags2 &= ~KF2_RCTRL;
450         else
451             flags1 &= ~KF1_LCTRL;
452         break;
453
454     case 0x38: /* Alt press */
455         flags0 |= KF0_ALTACTIVE;
456         if (flags2 & KF2_LAST_E0)
457             flags2 |= KF2_RALT;
458         else
459             flags1 |= KF1_LALT;
460         break;
461     case 0xb8: /* Alt release */
462         flags0 &= ~KF0_ALTACTIVE;
463         if (flags2 & KF2_LAST_E0)
464             flags2 &= ~KF2_RALT;
465         else
466             flags1 &= ~KF1_LALT;
467         break;
468
469     case 0x45: /* Num Lock press */
470         flags1 |= KF1_NUM;
471         flags0 ^= KF0_NUMACTIVE;
472         break;
473     case 0xc5: /* Num Lock release */
474         flags1 &= ~KF1_NUM;
475         break;
476
477     case 0x46: /* Scroll Lock press */
478         flags1 |= KF1_SCROLL;
479         flags0 ^= KF0_SCROLLACTIVE;
480         break;
481     case 0xc6: /* Scroll Lock release */
482         flags1 &= ~KF1_SCROLL;
483         break;
484
485     case 0xe0:
486         // Extended key
487         flags2 |= KF2_LAST_E0;
488         SET_BDA(kbd_flag2, flags2);
489         return;
490     case 0xe1:
491         // Start of pause key sequence
492         flags2 |= KF2_LAST_E1;
493         break;
494
495     default:
496         if (scancode & 0x80)
497             // toss key releases
498             break;
499         if (scancode == 0x53
500             && ((flags0 & (KF0_CTRLACTIVE|KF0_ALTACTIVE))
501                 == (KF0_CTRLACTIVE|KF0_ALTACTIVE))) {
502             // Ctrl+alt+del - reset machine.
503             SET_BDA(soft_reset_flag, 0x1234);
504             reset_vector();
505         }
506         if (scancode >= ARRAY_SIZE(scan_to_scanascii)) {
507             dprintf(1, "KBD: int09h_handler(): unknown scancode read: 0x%02x!\n"
508                     , scancode);
509             return;
510         }
511         u8 asciicode;
512         struct scaninfo *info = &scan_to_scanascii[scancode];
513         if (flags0 & KF0_ALTACTIVE) {
514             asciicode = GET_GLOBAL(info->alt);
515             scancode = GET_GLOBAL(info->alt) >> 8;
516         } else if (flags0 & KF0_CTRLACTIVE) {
517             asciicode = GET_GLOBAL(info->control);
518             scancode = GET_GLOBAL(info->control) >> 8;
519         } else if (flags2 & KF2_LAST_E0
520                    && scancode >= 0x47 && scancode <= 0x53) {
521             /* extended keys handling */
522             asciicode = 0xe0;
523             scancode = GET_GLOBAL(info->normal) >> 8;
524         } else if (flags0 & (KF0_RSHIFT|KF0_LSHIFT)) {
525             /* check if lock state should be ignored because a SHIFT
526              * key is pressed */
527
528             if (flags0 & GET_GLOBAL(info->lock_flags)) {
529                 asciicode = GET_GLOBAL(info->normal);
530                 scancode = GET_GLOBAL(info->normal) >> 8;
531             } else {
532                 asciicode = GET_GLOBAL(info->shift);
533                 scancode = GET_GLOBAL(info->shift) >> 8;
534             }
535         } else {
536             /* check if lock is on */
537             if (flags0 & GET_GLOBAL(info->lock_flags)) {
538                 asciicode = GET_GLOBAL(info->shift);
539                 scancode = GET_GLOBAL(info->shift) >> 8;
540             } else {
541                 asciicode = GET_GLOBAL(info->normal);
542                 scancode = GET_GLOBAL(info->normal) >> 8;
543             }
544         }
545         if (scancode==0 && asciicode==0)
546             dprintf(1, "KBD: scancode & asciicode are zero?\n");
547         enqueue_key(scancode, asciicode);
548         break;
549     }
550     flags2 &= ~KF2_LAST_E0;
551
552     SET_BDA(kbd_flag0, flags0);
553     SET_BDA(kbd_flag1, flags1);
554     SET_BDA(kbd_flag2, flags2);
555 }
556
557 void
558 process_key(u8 key)
559 {
560     if (!CONFIG_KEYBOARD)
561         return;
562
563     if (CONFIG_KBD_CALL_INT15_4F) {
564         // allow for keyboard intercept
565         u32 eax = (0x4f << 8) | key;
566         u32 flags;
567         call16_simpint(0x15, &eax, &flags);
568         if (!(flags & F_CF))
569             return;
570         key = eax;
571     }
572     __process_key(key);
573 }