VirtualBox

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

Last change on this file was 98103, checked in by vboxsync, 16 months ago

Copyright year updates by scm.

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

© 2023 Oracle
ContactPrivacy policyTerms of Use