VirtualBox

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

Last change on this file since 55998 was 51058, checked in by vboxsync, 11 years ago

BIOS: Set warm boot flag on Ctrl-Alt-Del.

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

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