VirtualBox

source: vbox/trunk/src/VBox/Devices/PC/BIOS/keyboard.c@ 69496

最後變更 在這個檔案從69496是 69496,由 vboxsync 提交於 7 年 前

*: scm --update-copyright-year

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Author Date Id Revision
檔案大小: 26.8 KB
 
1/*
2 * Copyright (C) 2006-2017 Oracle Corporation
3 *
4 * This file is part of VirtualBox Open Source Edition (OSE), as
5 * available from http://www.alldomusa.eu.org. This file is free software;
6 * you can redistribute it and/or modify it under the terms of the GNU
7 * General Public License (GPL) as published by the Free Software
8 * Foundation, in version 2 as it comes in the "COPYING" file of the
9 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
10 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
11 *
12 * This code is based on:
13 *
14 * ROM BIOS for use with Bochs/Plex86/QEMU emulation environment
15 *
16 * Copyright (C) 2002 MandrakeSoft S.A.
17 *
18 * MandrakeSoft S.A.
19 * 43, rue d'Aboukir
20 * 75002 Paris - France
21 * http://www.linux-mandrake.com/
22 * http://www.mandrakesoft.com/
23 *
24 * This library is free software; you can redistribute it and/or
25 * modify it under the terms of the GNU Lesser General Public
26 * License as published by the Free Software Foundation; either
27 * version 2 of the License, or (at your option) any later version.
28 *
29 * This library is distributed in the hope that it will be useful,
30 * but WITHOUT ANY WARRANTY; without even the implied warranty of
31 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
32 * Lesser General Public License for more details.
33 *
34 * You should have received a copy of the GNU Lesser General Public
35 * License along with this library; if not, write to the Free Software
36 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
37 *
38 */
39
40
41#include <stdint.h>
42#include "inlines.h"
43#include "biosint.h"
44
45#if DEBUG_INT16
46# define BX_DEBUG_INT16(...) BX_DEBUG(__VA_ARGS__)
47#else
48# define BX_DEBUG_INT16(...)
49#endif
50
51extern void post(void);
52#pragma aux post "*";
53
54void jmp_post(void);
55#pragma aux jmp_post = "jmp far ptr post" aborts;
56
57extern void eoi_master_pic(void); /* in assembly code */
58#pragma aux eoi_master_pic "*";
59
60/* Manually save/restore BP around invoking user Ctrl-Break handler.
61 * The handler could conceivably clobber BP and the compiler does not
62 * believe us when we say 'modify [bp]' (BP is considered unalterable).
63 */
64void int_1b(void);
65#pragma aux int_1b = \
66 "push bp" \
67 "int 1Bh" \
68 "pop bp" \
69 value [bp] modify [bp];
70
71
72#define none 0
73#define MAX_SCAN_CODE 0x58
74
75struct {
76 uint16_t normal;
77 uint16_t shift;
78 uint16_t control;
79 uint16_t alt;
80 uint8_t lock_flags;
81} static const scan_to_scanascii[MAX_SCAN_CODE + 1] = {
82 { none, none, none, none, none },
83 { 0x011b, 0x011b, 0x011b, 0x0100, none }, /* escape */
84 { 0x0231, 0x0221, none, 0x7800, none }, /* 1! */
85 { 0x0332, 0x0340, 0x0300, 0x7900, none }, /* 2@ */
86 { 0x0433, 0x0423, none, 0x7a00, none }, /* 3# */
87 { 0x0534, 0x0524, none, 0x7b00, none }, /* 4$ */
88 { 0x0635, 0x0625, none, 0x7c00, none }, /* 5% */
89 { 0x0736, 0x075e, 0x071e, 0x7d00, none }, /* 6^ */
90 { 0x0837, 0x0826, none, 0x7e00, none }, /* 7& */
91 { 0x0938, 0x092a, none, 0x7f00, none }, /* 8* */
92 { 0x0a39, 0x0a28, none, 0x8000, none }, /* 9( */
93 { 0x0b30, 0x0b29, none, 0x8100, none }, /* 0) */
94 { 0x0c2d, 0x0c5f, 0x0c1f, 0x8200, none }, /* -_ */
95 { 0x0d3d, 0x0d2b, none, 0x8300, none }, /* =+ */
96 { 0x0e08, 0x0e08, 0x0e7f, none, none }, /* backspace */
97 { 0x0f09, 0x0f00, none, none, none }, /* tab */
98 { 0x1071, 0x1051, 0x1011, 0x1000, 0x40 }, /* Q */
99 { 0x1177, 0x1157, 0x1117, 0x1100, 0x40 }, /* W */
100 { 0x1265, 0x1245, 0x1205, 0x1200, 0x40 }, /* E */
101 { 0x1372, 0x1352, 0x1312, 0x1300, 0x40 }, /* R */
102 { 0x1474, 0x1454, 0x1414, 0x1400, 0x40 }, /* T */
103 { 0x1579, 0x1559, 0x1519, 0x1500, 0x40 }, /* Y */
104 { 0x1675, 0x1655, 0x1615, 0x1600, 0x40 }, /* U */
105 { 0x1769, 0x1749, 0x1709, 0x1700, 0x40 }, /* I */
106 { 0x186f, 0x184f, 0x180f, 0x1800, 0x40 }, /* O */
107 { 0x1970, 0x1950, 0x1910, 0x1900, 0x40 }, /* P */
108 { 0x1a5b, 0x1a7b, 0x1a1b, none, none }, /* [{ */
109 { 0x1b5d, 0x1b7d, 0x1b1d, none, none }, /* ]} */
110 { 0x1c0d, 0x1c0d, 0x1c0a, none, none }, /* Enter */
111 { none, none, none, none, none }, /* L Ctrl */
112 { 0x1e61, 0x1e41, 0x1e01, 0x1e00, 0x40 }, /* A */
113 { 0x1f73, 0x1f53, 0x1f13, 0x1f00, 0x40 }, /* S */
114 { 0x2064, 0x2044, 0x2004, 0x2000, 0x40 }, /* D */
115 { 0x2166, 0x2146, 0x2106, 0x2100, 0x40 }, /* F */
116 { 0x2267, 0x2247, 0x2207, 0x2200, 0x40 }, /* G */
117 { 0x2368, 0x2348, 0x2308, 0x2300, 0x40 }, /* H */
118 { 0x246a, 0x244a, 0x240a, 0x2400, 0x40 }, /* J */
119 { 0x256b, 0x254b, 0x250b, 0x2500, 0x40 }, /* K */
120 { 0x266c, 0x264c, 0x260c, 0x2600, 0x40 }, /* L */
121 { 0x273b, 0x273a, none, none, none }, /* ;: */
122 { 0x2827, 0x2822, none, none, none }, /* '" */
123 { 0x2960, 0x297e, none, none, none }, /* `~ */
124 { none, none, none, none, none }, /* L shift */
125 { 0x2b5c, 0x2b7c, 0x2b1c, none, none }, /* |\ */
126 { 0x2c7a, 0x2c5a, 0x2c1a, 0x2c00, 0x40 }, /* Z */
127 { 0x2d78, 0x2d58, 0x2d18, 0x2d00, 0x40 }, /* X */
128 { 0x2e63, 0x2e43, 0x2e03, 0x2e00, 0x40 }, /* C */
129 { 0x2f76, 0x2f56, 0x2f16, 0x2f00, 0x40 }, /* V */
130 { 0x3062, 0x3042, 0x3002, 0x3000, 0x40 }, /* B */
131 { 0x316e, 0x314e, 0x310e, 0x3100, 0x40 }, /* N */
132 { 0x326d, 0x324d, 0x320d, 0x3200, 0x40 }, /* M */
133 { 0x332c, 0x333c, none, none, none }, /* ,< */
134 { 0x342e, 0x343e, none, none, none }, /* .> */
135 { 0x352f, 0x353f, none, none, none }, /* /? */
136 { none, none, none, none, none }, /* R Shift */
137 { 0x372a, 0x372a, none, none, none }, /* * */
138 { none, none, none, none, none }, /* L Alt */
139 { 0x3920, 0x3920, 0x3920, 0x3920, none }, /* space */
140 { none, none, none, none, none }, /* caps lock */
141 { 0x3b00, 0x5400, 0x5e00, 0x6800, none }, /* F1 */
142 { 0x3c00, 0x5500, 0x5f00, 0x6900, none }, /* F2 */
143 { 0x3d00, 0x5600, 0x6000, 0x6a00, none }, /* F3 */
144 { 0x3e00, 0x5700, 0x6100, 0x6b00, none }, /* F4 */
145 { 0x3f00, 0x5800, 0x6200, 0x6c00, none }, /* F5 */
146 { 0x4000, 0x5900, 0x6300, 0x6d00, none }, /* F6 */
147 { 0x4100, 0x5a00, 0x6400, 0x6e00, none }, /* F7 */
148 { 0x4200, 0x5b00, 0x6500, 0x6f00, none }, /* F8 */
149 { 0x4300, 0x5c00, 0x6600, 0x7000, none }, /* F9 */
150 { 0x4400, 0x5d00, 0x6700, 0x7100, none }, /* F10 */
151 { none, none, none, none, none }, /* Num Lock */
152 { none, none, none, none, none }, /* Scroll Lock */
153 { 0x4700, 0x4737, 0x7700, none, 0x20 }, /* 7 Home */
154 { 0x4800, 0x4838, none, none, 0x20 }, /* 8 UP */
155 { 0x4900, 0x4939, 0x8400, none, 0x20 }, /* 9 PgUp */
156 { 0x4a2d, 0x4a2d, none, none, none }, /* - */
157 { 0x4b00, 0x4b34, 0x7300, none, 0x20 }, /* 4 Left */
158 { 0x4c00, 0x4c35, none, none, 0x20 }, /* 5 */
159 { 0x4d00, 0x4d36, 0x7400, none, 0x20 }, /* 6 Right */
160 { 0x4e2b, 0x4e2b, none, none, none }, /* + */
161 { 0x4f00, 0x4f31, 0x7500, none, 0x20 }, /* 1 End */
162 { 0x5000, 0x5032, none, none, 0x20 }, /* 2 Down */
163 { 0x5100, 0x5133, 0x7600, none, 0x20 }, /* 3 PgDn */
164 { 0x5200, 0x5230, none, none, 0x20 }, /* 0 Ins */
165 { 0x5300, 0x532e, none, none, 0x20 }, /* Del */
166 { none, none, none, none, none },
167 { none, none, none, none, none },
168 { 0x565c, 0x567c, none, none, none }, /* \| */
169 { 0x8500, 0x8700, 0x8900, 0x8b00, none }, /* F11 */
170 { 0x8600, 0x8800, 0x8a00, 0x8c00, none } /* F12 */
171};
172
173
174/* Keyboard initialization. */
175
176//--------------------------------------------------------------------------
177// keyboard_panic
178//--------------------------------------------------------------------------
179void keyboard_panic(uint16_t status)
180{
181 // If you're getting a 993 keyboard panic here,
182 // please see the comment in keyboard_init
183
184 BX_PANIC("Keyboard error:%u\n",status);
185}
186
187
188//--------------------------------------------------------------------------
189// keyboard_init
190//--------------------------------------------------------------------------
191// this file is based on LinuxBIOS implementation of keyboard.c
192// could convert to #asm to gain space
193void BIOSCALL keyboard_init(void)
194{
195 uint16_t max;
196
197 /* ------------------- controller side ----------------------*/
198 /* send cmd = 0xAA, self test 8042 */
199 outb(0x64, 0xaa);
200
201 /* Wait until buffer is empty */
202 max=0xffff;
203 while ( (inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x00);
204 if (max==0x0) keyboard_panic(00);
205
206 /* Wait for data */
207 max=0xffff;
208 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x01);
209 if (max==0x0) keyboard_panic(01);
210
211 /* read self-test result, 0x55 should be returned from 0x60 */
212 if ((inb(0x60) != 0x55)){
213 keyboard_panic(991);
214 }
215
216 /* send cmd = 0xAB, keyboard interface test */
217 outb(0x64,0xab);
218
219 /* Wait until buffer is empty */
220 max=0xffff;
221 while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x10);
222 if (max==0x0) keyboard_panic(10);
223
224 /* Wait for data */
225 max=0xffff;
226 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x11);
227 if (max==0x0) keyboard_panic(11);
228
229 /* read keyboard interface test result, */
230 /* 0x00 should be returned form 0x60 */
231 if ((inb(0x60) != 0x00)) {
232 keyboard_panic(992);
233 }
234
235 /* ------------------- keyboard side ------------------------*/
236 /* reset keyboard and self test (keyboard side) */
237 /* also enables the keyboard interface */
238 outb(0x60, 0xff);
239
240 /* Wait until buffer is empty */
241 max=0xffff;
242 while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x20);
243 if (max==0x0) keyboard_panic(20);
244
245 /* Wait for data */
246 max=0xffff;
247 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x21);
248 if (max==0x0) keyboard_panic(21);
249
250 /* keyboard should return ACK */
251 if ((inb(0x60) != 0xfa)) {
252 keyboard_panic(993);
253 }
254
255 /* Wait for reset to complete */
256 while ( (inb(0x64) & 0x01) == 0 ) outb(0x80, 0x31);
257
258 if ((inb(0x60) != 0xaa && inb(0x60) != 0xaa)) {
259 keyboard_panic(994);
260 }
261
262 /* Disable keyboard */
263 outb(0x60, 0xf5);
264
265 /* Wait until buffer is empty */
266 max=0xffff;
267 while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x40);
268 if (max==0x0) keyboard_panic(40);
269
270 /* Wait for data */
271 max=0xffff;
272 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x41);
273 if (max==0x0) keyboard_panic(41);
274
275 /* keyboard should return ACK */
276 if ((inb(0x60) != 0xfa)) {
277 keyboard_panic(995);
278 }
279
280 /* Write Keyboard Mode */
281 outb(0x64, 0x60);
282
283 /* Wait until buffer is empty */
284 max=0xffff;
285 while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x50);
286 if (max==0x0) keyboard_panic(50);
287
288 /* send cmd: scan code convert, disable mouse, enable IRQ 1 */
289 outb(0x60, 0x65);
290
291 /* Wait until buffer is empty */
292 max=0xffff;
293 while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x60);
294 if (max==0x0) keyboard_panic(60);
295
296 /* Enable keyboard */
297 outb(0x60, 0xf4);
298
299 /* Wait until buffer is empty */
300 max=0xffff;
301 while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x70);
302 if (max==0x0) keyboard_panic(70);
303
304 /* Wait for data */
305 max=0xffff;
306 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x71);
307 if (max==0x0) keyboard_panic(70);
308
309 /* keyboard should return ACK */
310 if ((inb(0x60) != 0xfa)) {
311 keyboard_panic(996);
312 }
313
314 /* Enable aux interface */
315 outb(0x64,0xa8);
316
317 /* While we're here, disable the A20 gate. Required for
318 * compatibility with the IBM PC and DOS.
319 */
320 set_enable_a20(0);
321}
322
323
324unsigned int enqueue_key(uint8_t scan_code, uint8_t ascii_code)
325{
326 uint16_t buffer_start, buffer_end, buffer_head, buffer_tail, temp_tail;
327
328#if BX_CPU < 2
329 buffer_start = 0x001E;
330 buffer_end = 0x003E;
331#else
332 buffer_start = read_word(0x0040, 0x0080);
333 buffer_end = read_word(0x0040, 0x0082);
334#endif
335
336 buffer_head = read_word(0x0040, 0x001A);
337 buffer_tail = read_word(0x0040, 0x001C);
338
339 temp_tail = buffer_tail;
340 buffer_tail += 2;
341 if (buffer_tail >= buffer_end)
342 buffer_tail = buffer_start;
343
344 if (buffer_tail == buffer_head)
345 return(0);
346
347 write_byte(0x0040, temp_tail, ascii_code);
348 write_byte(0x0040, temp_tail+1, scan_code);
349 write_word(0x0040, 0x001C, buffer_tail);
350 return(1);
351}
352
353
354/* Keyboard hardware interrupt handler. */
355/// @todo should this be declared as taking arguments at all?
356void BIOSCALL int09_function(uint16_t ES, uint16_t DI, uint16_t SI, uint16_t BP, uint16_t SP,
357 uint16_t BX, uint16_t DX, uint16_t CX, uint16_t AX)
358{
359 uint8_t scancode, asciicode, shift_flags;
360 uint8_t mf2_flags, mf2_state, flag;
361
362 //
363 // DS has been set to F000 before call
364 //
365
366
367 scancode = GET_AL();
368
369 if (scancode == 0) {
370 BX_INFO("KBD: int09 handler: AL=0\n");
371 return;
372 }
373
374 mf2_flags = read_byte(0x0040, 0x18);
375 mf2_state = read_byte(0x0040, 0x96);
376 shift_flags = read_byte(0x0040, 0x17);
377 asciicode = 0;
378
379 switch (scancode) {
380 case 0x3a: /* Caps Lock press */
381 shift_flags ^= 0x40;
382 write_byte(0x0040, 0x17, shift_flags);
383 mf2_flags |= 0x40;
384 write_byte(0x0040, 0x18, mf2_flags);
385 break;
386 case 0xba: /* Caps Lock release */
387 mf2_flags &= ~0x40;
388 write_byte(0x0040, 0x18, mf2_flags);
389 break;
390
391 case 0x2a: /* L Shift press */
392 case 0xaa: /* L Shift release */
393 case 0x36: /* R Shift press */
394 case 0xb6: /* R Shift release */
395 /* If this was an extended (i.e. faked) key, leave flags alone. */
396 if (!(mf2_state & 0x02)) {
397 flag = (scancode & 0x7f) == 0x2a ? 0x02 : 0x01;
398 if (scancode & 0x80)
399 shift_flags &= ~flag;
400 else
401 shift_flags |= flag;
402 write_byte(0x0040, 0x17, shift_flags);
403 }
404 break;
405
406 case 0x1d: /* Ctrl press */
407 if ((mf2_state & 0x01) == 0) {
408 shift_flags |= 0x04;
409 write_byte(0x0040, 0x17, shift_flags);
410 if (mf2_state & 0x02) {
411 mf2_state |= 0x04;
412 write_byte(0x0040, 0x96, mf2_state);
413 } else {
414 mf2_flags |= 0x01;
415 write_byte(0x0040, 0x18, mf2_flags);
416 }
417 }
418 break;
419 case 0x9d: /* Ctrl release */
420 if ((mf2_state & 0x01) == 0) {
421 shift_flags &= ~0x04;
422 write_byte(0x0040, 0x17, shift_flags);
423 if (mf2_state & 0x02) {
424 mf2_state &= ~0x04;
425 write_byte(0x0040, 0x96, mf2_state);
426 } else {
427 mf2_flags &= ~0x01;
428 write_byte(0x0040, 0x18, mf2_flags);
429 }
430 }
431 break;
432
433 case 0x38: /* Alt press */
434 shift_flags |= 0x08;
435 write_byte(0x0040, 0x17, shift_flags);
436 if (mf2_state & 0x02) {
437 mf2_state |= 0x08;
438 write_byte(0x0040, 0x96, mf2_state);
439 } else {
440 mf2_flags |= 0x02;
441 write_byte(0x0040, 0x18, mf2_flags);
442 }
443 break;
444 case 0xb8: /* Alt release */
445 shift_flags &= ~0x08;
446 write_byte(0x0040, 0x17, shift_flags);
447 if (mf2_state & 0x02) {
448 mf2_state &= ~0x08;
449 write_byte(0x0040, 0x96, mf2_state);
450 } else {
451 mf2_flags &= ~0x02;
452 write_byte(0x0040, 0x18, mf2_flags);
453 }
454 break;
455
456 case 0x45: /* Num Lock/Pause press */
457 if ((mf2_state & 0x03) == 0) {
458 /* Num Lock */
459 mf2_flags |= 0x20;
460 write_byte(0x0040, 0x18, mf2_flags);
461 shift_flags ^= 0x20;
462 write_byte(0x0040, 0x17, shift_flags);
463 } else {
464 /* Pause */
465 mf2_flags |= 0x08; /* Set the suspend flag */
466 write_byte(0x0040, 0x18, mf2_flags);
467
468 /* Enable keyboard and send EOI. */
469 outp(0x64, 0xae);
470 eoi_master_pic();
471
472 while (read_byte(0x0040, 0x18) & 0x08)
473 ; /* Hold on and wait... */
474
475 /// @todo We will send EOI again (and enable keyboard) on the way out; we shouldn't
476 }
477 break;
478 case 0xc5: /* Num Lock/Pause release */
479 if ((mf2_state & 0x03) == 0) {
480 mf2_flags &= ~0x20;
481 write_byte(0x0040, 0x18, mf2_flags);
482 }
483 break;
484
485 case 0x46: /* Scroll Lock/Break press */
486 if (mf2_state & 0x02) { /* E0 prefix? */
487 /* Zap the keyboard buffer. */
488 write_word(0x0040, 0x001c, read_word(0x0040, 0x001a));
489
490 write_byte(0x0040, 0x71, 0x80); /* Set break flag */
491 outp(0x64, 0xae); /* Enable keyboard */
492 int_1b(); /* Invoke user handler */
493 enqueue_key(0, 0); /* Dummy key press*/
494 } else {
495 mf2_flags |= 0x10;
496 write_byte(0x0040, 0x18, mf2_flags);
497 shift_flags ^= 0x10;
498 write_byte(0x0040, 0x17, shift_flags);
499 }
500 break;
501
502 case 0xc6: /* Scroll Lock/Break release */
503 if (!(mf2_state & 0x02)) { /* Only if no E0 prefix */
504 mf2_flags &= ~0x10;
505 write_byte(0x0040, 0x18, mf2_flags);
506 }
507 break;
508
509 case 0x54: /* SysRq press */
510 if (!(mf2_flags & 0x04)) { /* If not already down */
511 mf2_flags |= 0x04;
512 write_byte(0x0040, 0x18, mf2_flags);
513 /// @todo EOI/enable kbd/enable interrupts/call INT 15h/8500h
514 }
515 break;
516
517 case 0xd4: /* SysRq release */
518 mf2_flags &= ~0x04;
519 write_byte(0x0040, 0x18, mf2_flags);
520 /// @todo EOI/enable kbd/enable interrupts/call INT 15h/8501h
521 break;
522
523 case 0x53: /* Del press */
524 if ((shift_flags & 0x0c) == 0x0c) {
525 /* Indicate a warm boot. */
526 write_word(0x0040,0x0072, 0x1234);
527 jmp_post();
528 }
529 /* fall through */
530
531 default:
532 /* Check if suspend flag set. */
533 if (mf2_flags & 0x08) {
534 /* Pause had been pressed. Clear suspend flag and do nothing. */
535 mf2_flags &= ~0x08;
536 write_byte(0x0040, 0x18, mf2_flags);
537 return;
538 }
539
540 if (scancode & 0x80) {
541 /* Set ack/resend flags if appropriate. */
542 if (scancode == 0xFA) {
543 flag = read_byte(0x0040, 0x97) | 0x10;
544 write_byte(0x0040, 0x97, flag);
545 } else if (scancode == 0xFE) {
546 flag = read_byte(0x0040, 0x97) | 0x20;
547 write_byte(0x0040, 0x97, flag);
548 }
549 break; /* toss key releases ... */
550 }
551 if (scancode > MAX_SCAN_CODE) {
552 BX_INFO("KBD: int09h_handler(): unknown scancode read: 0x%02x!\n", scancode);
553 return;
554 }
555 if (shift_flags & 0x08) { /* ALT */
556 asciicode = scan_to_scanascii[scancode].alt;
557 scancode = scan_to_scanascii[scancode].alt >> 8;
558 } else if (shift_flags & 0x04) { /* CONTROL */
559 asciicode = scan_to_scanascii[scancode].control;
560 scancode = scan_to_scanascii[scancode].control >> 8;
561 } else if (((mf2_state & 0x02) > 0) && ((scancode >= 0x47) && (scancode <= 0x53))) {
562 /* extended keys handling */
563 asciicode = 0xe0;
564 scancode = scan_to_scanascii[scancode].normal >> 8;
565 } else if (shift_flags & 0x03) { /* LSHIFT + RSHIFT */
566 /* check if lock state should be ignored
567 * because a SHIFT key are pressed */
568
569 if (shift_flags & scan_to_scanascii[scancode].lock_flags) {
570 asciicode = scan_to_scanascii[scancode].normal;
571 scancode = scan_to_scanascii[scancode].normal >> 8;
572 } else {
573 asciicode = scan_to_scanascii[scancode].shift;
574 scancode = scan_to_scanascii[scancode].shift >> 8;
575 }
576 } else {
577 /* check if lock is on */
578 if (shift_flags & scan_to_scanascii[scancode].lock_flags) {
579 asciicode = scan_to_scanascii[scancode].shift;
580 scancode = scan_to_scanascii[scancode].shift >> 8;
581 } else {
582 asciicode = scan_to_scanascii[scancode].normal;
583 scancode = scan_to_scanascii[scancode].normal >> 8;
584 }
585 }
586 if (scancode==0 && asciicode==0) {
587 BX_INFO("KBD: int09h_handler(): scancode & asciicode are zero?\n");
588 }
589 enqueue_key(scancode, asciicode);
590 break;
591 }
592 if ((scancode & 0x7f) != 0x1d) {
593 mf2_state &= ~0x01;
594 }
595 mf2_state &= ~0x02;
596 write_byte(0x0040, 0x96, mf2_state);
597}
598
599unsigned int dequeue_key(uint8_t __far *scan_code, uint8_t __far *ascii_code, unsigned incr)
600{
601 uint16_t buffer_start, buffer_end, buffer_head, buffer_tail;
602 uint8_t acode, scode;
603
604#if BX_CPU < 2
605 buffer_start = 0x001E;
606 buffer_end = 0x003E;
607#else
608 buffer_start = read_word(0x0040, 0x0080);
609 buffer_end = read_word(0x0040, 0x0082);
610#endif
611
612 buffer_head = read_word(0x0040, 0x001a);
613 buffer_tail = read_word(0x0040, 0x001c);
614
615 if (buffer_head != buffer_tail) {
616 acode = read_byte(0x0040, buffer_head);
617 scode = read_byte(0x0040, buffer_head+1);
618 *ascii_code = acode;
619 *scan_code = scode;
620 BX_DEBUG_INT16("dequeue_key: ascii=%02x scan=%02x \n", acode, scode);
621
622 if (incr) {
623 buffer_head += 2;
624 if (buffer_head >= buffer_end)
625 buffer_head = buffer_start;
626 write_word(0x0040, 0x001a, buffer_head);
627 }
628 return(1);
629 }
630 else {
631 return(0);
632 }
633}
634
635
636/// @todo move somewhere else?
637#define AX r.gr.u.r16.ax
638#define BX r.gr.u.r16.bx
639#define CX r.gr.u.r16.cx
640#define DX r.gr.u.r16.dx
641#define SI r.gr.u.r16.si
642#define DI r.gr.u.r16.di
643#define BP r.gr.u.r16.bp
644#define SP r.gr.u.r16.sp
645#define FLAGS r.ra.flags.u.r16.flags
646#define IFLGS r.ifl
647
648/* Interrupt 16h service implementation. */
649
650void BIOSCALL int16_function(volatile kbd_regs_t r)
651{
652 uint8_t scan_code, ascii_code, shift_flags, led_flags, count;
653 uint16_t kbd_code, max;
654
655 BX_DEBUG_INT16("int16: AX=%04x BX=%04x CX=%04x DX=%04x \n", AX, BX, CX, DX);
656
657 shift_flags = read_byte(0x0040, 0x17);
658 led_flags = read_byte(0x0040, 0x97);
659 if ((((shift_flags >> 4) & 0x07) ^ (led_flags & 0x07)) != 0) {
660 int_disable(); /// @todo interrupts should be disabled already??
661 outb(0x60, 0xed);
662 while ((inb(0x64) & 0x01) == 0) outb(0x80, 0x21);
663 if ((inb(0x60) == 0xfa)) {
664 led_flags &= 0xc8;
665 led_flags |= ((shift_flags >> 4) & 0x07);
666 outb(0x60, led_flags & 0x07);
667 while ((inb(0x64) & 0x01) == 0)
668 outb(0x80, 0x21);
669 inb(0x60);
670 write_byte(0x0040, 0x97, led_flags);
671 }
672 int_enable();
673 }
674
675 switch (GET_AH()) {
676 case 0x00: /* read keyboard input */
677 if ( !dequeue_key(&scan_code, &ascii_code, 1) ) {
678 BX_PANIC("KBD: int16h: out of keyboard input\n");
679 }
680 if (scan_code !=0 && ascii_code == 0xF0)
681 ascii_code = 0;
682 else if (ascii_code == 0xE0)
683 ascii_code = 0;
684 AX = (scan_code << 8) | ascii_code;
685 break;
686
687 case 0x01: /* check keyboard status */
688 /* Enable interrupts, preserve most flags. Some callers depend on that! */
689 FLAGS = IFLGS;
690 if ( !dequeue_key(&scan_code, &ascii_code, 0) ) {
691 SET_ZF();
692 return;
693 }
694 if (scan_code !=0 && ascii_code == 0xF0)
695 ascii_code = 0;
696 else if (ascii_code == 0xE0)
697 ascii_code = 0;
698 AX = (scan_code << 8) | ascii_code;
699 CLEAR_ZF();
700 break;
701
702 case 0x02: /* get shift flag status */
703 shift_flags = read_byte(0x0040, 0x17);
704 SET_AL(shift_flags);
705 break;
706
707 case 0x05: /* store key-stroke into buffer */
708 if ( !enqueue_key(GET_CH(), GET_CL()) ) {
709 SET_AL(1);
710 }
711 else {
712 SET_AL(0);
713 }
714 break;
715
716 case 0x09: /* GET KEYBOARD FUNCTIONALITY */
717 // bit Bochs Description
718 // 7 0 reserved
719 // 6 0 INT 16/AH=20h-22h supported (122-key keyboard support)
720 // 5 1 INT 16/AH=10h-12h supported (enhanced keyboard support)
721 // 4 1 INT 16/AH=0Ah supported
722 // 3 0 INT 16/AX=0306h supported
723 // 2 0 INT 16/AX=0305h supported
724 // 1 0 INT 16/AX=0304h supported
725 // 0 0 INT 16/AX=0300h supported
726 //
727 SET_AL(0x30);
728 break;
729
730 case 0x0A: /* GET KEYBOARD ID */
731 count = 2;
732 kbd_code = 0x0;
733 /// @todo Might be better to just mask the KB interrupt
734 int_disable();
735 outb(0x60, 0xf2);
736 /* Wait for data */
737 max=0xffff;
738 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) )
739 inb(0x80);
740 if (max>0x0) {
741 if ((inb(0x60) == 0xfa)) {
742 do {
743 max=0xffff;
744 while ( ((inb(0x64) & 0x01) == 0) && (--max>0) )
745 inb(0x80);
746 if (max>0x0) {
747 kbd_code >>= 8;
748 kbd_code |= (inb(0x60) << 8);
749 }
750 } while (--count>0);
751 }
752 }
753 BX=kbd_code;
754 break;
755
756 case 0x10: /* read MF-II keyboard input */
757 if ( !dequeue_key(&scan_code, &ascii_code, 1) ) {
758 BX_PANIC("KBD: int16h: out of keyboard input\n");
759 }
760 if (scan_code !=0 && ascii_code == 0xF0)
761 ascii_code = 0;
762 AX = (scan_code << 8) | ascii_code;
763 break;
764
765 case 0x11: /* check MF-II keyboard status */
766 /* Enable interrupts, preserve most flags. Some callers depend on that! */
767 FLAGS = IFLGS;
768 if ( !dequeue_key(&scan_code, &ascii_code, 0) ) {
769 SET_ZF();
770 return;
771 }
772 if (scan_code !=0 && ascii_code == 0xF0)
773 ascii_code = 0;
774 AX = (scan_code << 8) | ascii_code;
775 CLEAR_ZF();
776 break;
777
778 case 0x12: /* get extended keyboard status */
779 shift_flags = read_byte(0x0040, 0x17);
780 SET_AL(shift_flags);
781 shift_flags = read_byte(0x0040, 0x18) & 0x73;
782 shift_flags |= read_byte(0x0040, 0x96) & 0x0c;
783 SET_AH(shift_flags);
784 BX_DEBUG_INT16("int16: func 12 sending %04x\n",AX);
785 break;
786
787 case 0x92: /* keyboard capability check called by DOS 5.0+ keyb */
788 SET_AH(0x80); // function int16 ah=0x10-0x12 supported
789 break;
790
791 case 0xA2: /* 122 keys capability check called by DOS 5.0+ keyb */
792 // don't change AH : function int16 ah=0x20-0x22 NOT supported
793 break;
794
795 /// @todo what's the point of handling this??
796#if 0
797 case 0x6F:
798 if (GET_AL() == 0x08)
799 SET_AH(0x02); // unsupported, aka normal keyboard
800#endif
801
802 default:
803 BX_INFO("KBD: unsupported int 16h function %02x\n", GET_AH());
804 BX_INFO("AX=%04x BX=%04x CX=%04x DX=%04x \n", AX, BX, CX, DX);
805 }
806 BX_DEBUG_INT16("int16ex: AX=%04x BX=%04x CX=%04x DX=%04x \n", AX, BX, CX, DX);
807}
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette