[69501] | 1 | /* $Id: keyboard.c 98103 2023-01-17 14:15:46Z vboxsync $ */
|
---|
| 2 | /** @file
|
---|
| 3 | * PC BIOS - ???
|
---|
| 4 | */
|
---|
| 5 |
|
---|
[38699] | 6 | /*
|
---|
[98103] | 7 | * Copyright (C) 2006-2023 Oracle and/or its affiliates.
|
---|
[38699] | 8 | *
|
---|
[96407] | 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
|
---|
[69498] | 26 | * --------------------------------------------------------------------
|
---|
[38699] | 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 |
|
---|
[69501] | 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 | */
|
---|
[38699] | 64 |
|
---|
[69501] | 65 |
|
---|
[38699] | 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 |
|
---|
| 76 | extern void post(void);
|
---|
| 77 | #pragma aux post "*";
|
---|
| 78 |
|
---|
| 79 | void jmp_post(void);
|
---|
| 80 | #pragma aux jmp_post = "jmp far ptr post" aborts;
|
---|
| 81 |
|
---|
[59114] | 82 | extern 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 | */
|
---|
| 89 | void int_1b(void);
|
---|
| 90 | #pragma aux int_1b = \
|
---|
| 91 | "push bp" \
|
---|
| 92 | "int 1Bh" \
|
---|
| 93 | "pop bp" \
|
---|
| 94 | value [bp] modify [bp];
|
---|
| 95 |
|
---|
| 96 |
|
---|
[38699] | 97 | #define none 0
|
---|
| 98 | #define MAX_SCAN_CODE 0x58
|
---|
| 99 |
|
---|
| 100 | struct {
|
---|
| 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 | //--------------------------------------------------------------------------
|
---|
| 204 | void keyboard_panic(uint16_t status)
|
---|
| 205 | {
|
---|
| 206 | // If you're getting a 993 keyboard panic here,
|
---|
| 207 | // please see the comment in keyboard_init
|
---|
[48123] | 208 |
|
---|
[38699] | 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
|
---|
| 218 | void 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 |
|
---|
[50166] | 280 | /* Wait for reset to complete */
|
---|
| 281 | while ( (inb(0x64) & 0x01) == 0 ) outb(0x80, 0x31);
|
---|
[38699] | 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);
|
---|
[38833] | 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);
|
---|
[38699] | 346 | }
|
---|
| 347 |
|
---|
| 348 |
|
---|
| 349 | unsigned 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;
|
---|
[48123] | 352 |
|
---|
[74665] | 353 | #if VBOX_BIOS_CPU >= 80286
|
---|
| 354 | buffer_start = read_word(0x0040, 0x0080);
|
---|
| 355 | buffer_end = read_word(0x0040, 0x0082);
|
---|
| 356 | #else
|
---|
[38699] | 357 | buffer_start = 0x001E;
|
---|
| 358 | buffer_end = 0x003E;
|
---|
| 359 | #endif
|
---|
[48123] | 360 |
|
---|
[38699] | 361 | buffer_head = read_word(0x0040, 0x001A);
|
---|
| 362 | buffer_tail = read_word(0x0040, 0x001C);
|
---|
[48123] | 363 |
|
---|
[38699] | 364 | temp_tail = buffer_tail;
|
---|
| 365 | buffer_tail += 2;
|
---|
| 366 | if (buffer_tail >= buffer_end)
|
---|
| 367 | buffer_tail = buffer_start;
|
---|
[48123] | 368 |
|
---|
[38699] | 369 | if (buffer_tail == buffer_head)
|
---|
| 370 | return(0);
|
---|
[48123] | 371 |
|
---|
[38699] | 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. */
|
---|
[63562] | 380 | /// @todo should this be declared as taking arguments at all?
|
---|
[38699] | 381 | void 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;
|
---|
[40236] | 385 | uint8_t mf2_flags, mf2_state, flag;
|
---|
[48123] | 386 |
|
---|
[38699] | 387 | //
|
---|
| 388 | // DS has been set to F000 before call
|
---|
| 389 | //
|
---|
[48123] | 390 |
|
---|
| 391 |
|
---|
[38699] | 392 | scancode = GET_AL();
|
---|
[48123] | 393 |
|
---|
[38699] | 394 | if (scancode == 0) {
|
---|
| 395 | BX_INFO("KBD: int09 handler: AL=0\n");
|
---|
| 396 | return;
|
---|
| 397 | }
|
---|
[48123] | 398 |
|
---|
[59114] | 399 | mf2_flags = read_byte(0x0040, 0x18);
|
---|
| 400 | mf2_state = read_byte(0x0040, 0x96);
|
---|
[38699] | 401 | shift_flags = read_byte(0x0040, 0x17);
|
---|
| 402 | asciicode = 0;
|
---|
[48123] | 403 |
|
---|
[38699] | 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;
|
---|
[40236] | 415 |
|
---|
[38699] | 416 | case 0x2a: /* L Shift press */
|
---|
| 417 | case 0xaa: /* L Shift release */
|
---|
| 418 | case 0x36: /* R Shift press */
|
---|
| 419 | case 0xb6: /* R Shift release */
|
---|
[40236] | 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 | }
|
---|
[38699] | 429 | break;
|
---|
[40236] | 430 |
|
---|
[38699] | 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;
|
---|
[48123] | 457 |
|
---|
[38699] | 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;
|
---|
[48123] | 480 |
|
---|
[59114] | 481 | case 0x45: /* Num Lock/Pause press */
|
---|
[38699] | 482 | if ((mf2_state & 0x03) == 0) {
|
---|
[59114] | 483 | /* Num Lock */
|
---|
[38699] | 484 | mf2_flags |= 0x20;
|
---|
| 485 | write_byte(0x0040, 0x18, mf2_flags);
|
---|
| 486 | shift_flags ^= 0x20;
|
---|
| 487 | write_byte(0x0040, 0x17, shift_flags);
|
---|
[59114] | 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 |
|
---|
[63562] | 500 | /// @todo We will send EOI again (and enable keyboard) on the way out; we shouldn't
|
---|
[38699] | 501 | }
|
---|
| 502 | break;
|
---|
[59114] | 503 | case 0xc5: /* Num Lock/Pause release */
|
---|
[38699] | 504 | if ((mf2_state & 0x03) == 0) {
|
---|
| 505 | mf2_flags &= ~0x20;
|
---|
| 506 | write_byte(0x0040, 0x18, mf2_flags);
|
---|
| 507 | }
|
---|
| 508 | break;
|
---|
[48123] | 509 |
|
---|
[59114] | 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 | }
|
---|
[38699] | 525 | break;
|
---|
[48123] | 526 |
|
---|
[59114] | 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 | }
|
---|
[38699] | 532 | break;
|
---|
[48123] | 533 |
|
---|
[59766] | 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);
|
---|
[63562] | 538 | /// @todo EOI/enable kbd/enable interrupts/call INT 15h/8500h
|
---|
[59766] | 539 | }
|
---|
| 540 | break;
|
---|
| 541 |
|
---|
| 542 | case 0xd4: /* SysRq release */
|
---|
| 543 | mf2_flags &= ~0x04;
|
---|
| 544 | write_byte(0x0040, 0x18, mf2_flags);
|
---|
[63562] | 545 | /// @todo EOI/enable kbd/enable interrupts/call INT 15h/8501h
|
---|
[59766] | 546 | break;
|
---|
| 547 |
|
---|
[38699] | 548 | case 0x53: /* Del press */
|
---|
[51058] | 549 | if ((shift_flags & 0x0c) == 0x0c) {
|
---|
| 550 | /* Indicate a warm boot. */
|
---|
| 551 | write_word(0x0040,0x0072, 0x1234);
|
---|
[38699] | 552 | jmp_post();
|
---|
[51058] | 553 | }
|
---|
[38699] | 554 | /* fall through */
|
---|
[48123] | 555 |
|
---|
[38699] | 556 | default:
|
---|
[59116] | 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 |
|
---|
[38699] | 565 | if (scancode & 0x80) {
|
---|
[50599] | 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 | }
|
---|
[38699] | 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 */
|
---|
[48123] | 593 |
|
---|
[38699] | 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 |
|
---|
| 624 | unsigned 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;
|
---|
[48123] | 628 |
|
---|
[74665] | 629 | #if VBOX_BIOS_CPU >= 80286
|
---|
| 630 | buffer_start = read_word(0x0040, 0x0080);
|
---|
| 631 | buffer_end = read_word(0x0040, 0x0082);
|
---|
| 632 | #else
|
---|
[38699] | 633 | buffer_start = 0x001E;
|
---|
| 634 | buffer_end = 0x003E;
|
---|
| 635 | #endif
|
---|
[48123] | 636 |
|
---|
[38699] | 637 | buffer_head = read_word(0x0040, 0x001a);
|
---|
| 638 | buffer_tail = read_word(0x0040, 0x001c);
|
---|
[48123] | 639 |
|
---|
[38699] | 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;
|
---|
[40236] | 645 | BX_DEBUG_INT16("dequeue_key: ascii=%02x scan=%02x \n", acode, scode);
|
---|
| 646 |
|
---|
[38699] | 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 |
|
---|
[63562] | 661 | /// @todo move somewhere else?
|
---|
[38699] | 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
|
---|
[40721] | 670 | #define FLAGS r.ra.flags.u.r16.flags
|
---|
[67785] | 671 | #define IFLGS r.ifl
|
---|
[38699] | 672 |
|
---|
| 673 | /* Interrupt 16h service implementation. */
|
---|
| 674 |
|
---|
| 675 | void 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;
|
---|
[48123] | 679 |
|
---|
[38699] | 680 | BX_DEBUG_INT16("int16: AX=%04x BX=%04x CX=%04x DX=%04x \n", AX, BX, CX, DX);
|
---|
[48123] | 681 |
|
---|
[38699] | 682 | shift_flags = read_byte(0x0040, 0x17);
|
---|
| 683 | led_flags = read_byte(0x0040, 0x97);
|
---|
| 684 | if ((((shift_flags >> 4) & 0x07) ^ (led_flags & 0x07)) != 0) {
|
---|
[63562] | 685 | int_disable(); /// @todo interrupts should be disabled already??
|
---|
[38699] | 686 | outb(0x60, 0xed);
|
---|
| 687 | while ((inb(0x64) & 0x01) == 0) outb(0x80, 0x21);
|
---|
| 688 | if ((inb(0x60) == 0xfa)) {
|
---|
[50599] | 689 | led_flags &= 0xc8;
|
---|
[38699] | 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 | }
|
---|
[48123] | 699 |
|
---|
[38699] | 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;
|
---|
[48123] | 711 |
|
---|
[38699] | 712 | case 0x01: /* check keyboard status */
|
---|
[67785] | 713 | /* Enable interrupts, preserve most flags. Some callers depend on that! */
|
---|
| 714 | FLAGS = IFLGS;
|
---|
[38699] | 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;
|
---|
[48123] | 726 |
|
---|
[38699] | 727 | case 0x02: /* get shift flag status */
|
---|
| 728 | shift_flags = read_byte(0x0040, 0x17);
|
---|
| 729 | SET_AL(shift_flags);
|
---|
| 730 | break;
|
---|
[48123] | 731 |
|
---|
[38699] | 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;
|
---|
[48123] | 740 |
|
---|
[38699] | 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;
|
---|
[48123] | 754 |
|
---|
[38699] | 755 | case 0x0A: /* GET KEYBOARD ID */
|
---|
| 756 | count = 2;
|
---|
| 757 | kbd_code = 0x0;
|
---|
[63562] | 758 | /// @todo Might be better to just mask the KB interrupt
|
---|
[39946] | 759 | int_disable();
|
---|
[38699] | 760 | outb(0x60, 0xf2);
|
---|
| 761 | /* Wait for data */
|
---|
| 762 | max=0xffff;
|
---|
[39946] | 763 | while ( ((inb(0x64) & 0x01) == 0) && (--max>0) )
|
---|
| 764 | inb(0x80);
|
---|
[38699] | 765 | if (max>0x0) {
|
---|
| 766 | if ((inb(0x60) == 0xfa)) {
|
---|
| 767 | do {
|
---|
| 768 | max=0xffff;
|
---|
[39946] | 769 | while ( ((inb(0x64) & 0x01) == 0) && (--max>0) )
|
---|
| 770 | inb(0x80);
|
---|
[38699] | 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;
|
---|
[48123] | 780 |
|
---|
[38699] | 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;
|
---|
[48123] | 789 |
|
---|
[38699] | 790 | case 0x11: /* check MF-II keyboard status */
|
---|
[67785] | 791 | /* Enable interrupts, preserve most flags. Some callers depend on that! */
|
---|
| 792 | FLAGS = IFLGS;
|
---|
[38699] | 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;
|
---|
[48123] | 802 |
|
---|
[38699] | 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;
|
---|
[48123] | 811 |
|
---|
[38699] | 812 | case 0x92: /* keyboard capability check called by DOS 5.0+ keyb */
|
---|
| 813 | SET_AH(0x80); // function int16 ah=0x10-0x12 supported
|
---|
| 814 | break;
|
---|
[48123] | 815 |
|
---|
[38699] | 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;
|
---|
[48123] | 819 |
|
---|
[63562] | 820 | /// @todo what's the point of handling this??
|
---|
[38699] | 821 | #if 0
|
---|
| 822 | case 0x6F:
|
---|
| 823 | if (GET_AL() == 0x08)
|
---|
| 824 | SET_AH(0x02); // unsupported, aka normal keyboard
|
---|
| 825 | #endif
|
---|
[48123] | 826 |
|
---|
[38699] | 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 | }
|
---|