DOSBox-X
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines
src/hardware/keyboard.cpp
00001 /*
00002  *  Copyright (C) 2002-2020  The DOSBox Team
00003  *
00004  *  This program is free software; you can redistribute it and/or modify
00005  *  it under the terms of the GNU General Public License as published by
00006  *  the Free Software Foundation; either version 2 of the License, or
00007  *  (at your option) any later version.
00008  *
00009  *  This program is distributed in the hope that it will be useful,
00010  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  *  GNU General Public License for more details.
00013  *
00014  *  You should have received a copy of the GNU General Public License along
00015  *  with this program; if not, write to the Free Software Foundation, Inc.,
00016  *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00017  */
00018 
00019 
00020 #include "dosbox.h"
00021 #include "keyboard.h"
00022 #include "support.h"
00023 #include "setup.h"
00024 #include "inout.h"
00025 #include "mouse.h"
00026 #include "pic.h"
00027 #include "mem.h"
00028 #include "cpu.h"
00029 #include "mixer.h"
00030 #include "timer.h"
00031 #include <math.h>
00032 #include "8255.h"
00033 
00034 #if defined(_MSC_VER)
00035 # pragma warning(disable:4244) /* const fmath::local::uint64_t to double possible loss of data */
00036 #endif
00037 
00038 #define KEYBUFSIZE 32*3
00039 #define RESETDELAY 400
00040 #define KEYDELAY 0.300f         //Considering 20-30 khz serial clock and 11 bits/char
00041 
00042 #define AUX 0x100
00043 
00044 void AUX_Reset();
00045 void KEYBOARD_Reset();
00046 static void KEYBOARD_SetPort60(Bit16u val);
00047 void KEYBOARD_AddBuffer(Bit16u data);
00048 static void KEYBOARD_Add8042Response(Bit8u data);
00049 void KEYBOARD_SetLEDs(Bit8u bits);
00050 
00051 bool enable_pc98_bus_mouse = true;
00052 
00053 static unsigned int aux_warning = 0;
00054 
00055 enum AuxCommands {
00056     ACMD_NONE,
00057     ACMD_SET_RATE,
00058     ACMD_SET_RESOLUTION
00059 };
00060 
00061 enum KeyCommands {
00062     CMD_NONE,
00063     CMD_SETLEDS,
00064     CMD_SETTYPERATE,
00065     CMD_SETOUTPORT,
00066     CMD_SETCOMMAND,
00067     CMD_WRITEOUTPUT,
00068     CMD_WRITEAUXOUT,
00069     CMD_SETSCANSET,
00070     CMD_WRITEAUX
00071 };
00072 
00073 enum MouseMode {
00074     MM_REMOTE=0,
00075     MM_WRAP,
00076     MM_STREAM
00077 };
00078 
00079 enum MouseType {
00080     MOUSE_NONE=0,
00081     MOUSE_2BUTTON,
00082     MOUSE_3BUTTON,
00083     MOUSE_INTELLIMOUSE,
00084     MOUSE_INTELLIMOUSE45
00085 };
00086 
00087 struct ps2mouse {
00088     MouseType   type;           /* what kind of mouse we are emulating */
00089     MouseMode   mode;           /* current mode */
00090     MouseMode   reset_mode;     /* mode to change to on reset */
00091     Bit8u       samplerate;     /* current sample rate */
00092     Bit8u       resolution;     /* current resolution */
00093     Bit8u       last_srate[3];      /* last 3 "set sample rate" values */
00094     float       acx,acy;        /* accumulator */
00095     bool        reporting;      /* reporting */
00096     bool        scale21;        /* 2:1 scaling */
00097     bool        intellimouse_mode;  /* intellimouse scroll wheel */
00098     bool        intellimouse_btn45; /* 4th & 5th buttons */
00099     bool        int33_taken;        /* for compatability with existing DOSBox code: allow INT 33H emulation to "take over" and disable us */
00100     bool        l,m,r;          /* mouse button states */
00101 };
00102 
00103 static struct {
00104     Bit8u buf8042[8];       /* for 8042 responses, taking priority over keyboard responses */
00105     Bitu buf8042_len;
00106     Bitu buf8042_pos;
00107     int pending_key;
00108 
00109     Bit16u buffer[KEYBUFSIZE];
00110     Bitu used;
00111     Bitu pos;
00112 
00113     struct {
00114         KBD_KEYS key;
00115         Bitu wait;
00116         Bitu pause,rate;
00117     } repeat;
00118     struct ps2mouse ps2mouse;
00119     KeyCommands command;
00120     AuxCommands aux_command;
00121     Bitu led_state;
00122     Bit8u p60data;
00123     Bit8u scanset;
00124     bool enable_aux;
00125     bool reset;
00126     bool active;
00127     bool scanning;
00128     bool auxactive;
00129     bool scheduled;
00130     bool p60changed;
00131     bool auxchanged;
00132     bool pending_key_state;
00133     /* command byte related */
00134     bool cb_override_inhibit;
00135     bool cb_irq12;          /* PS/2 mouse */
00136     bool cb_irq1;
00137     bool cb_xlat;
00138     bool cb_sys;
00139     bool leftctrl_pressed;
00140     bool rightctrl_pressed;
00141 } keyb;
00142 
00143 void PCjr_stuff_scancode(const unsigned char c) {
00144     keyb.p60data = c;
00145 }
00146 
00147 uint8_t Mouse_GetButtonState(void);
00148 
00149 uint32_t Keyb_ig_status() {
00150     uint8_t mousebtn = Mouse_GetButtonState() & 7;
00151 
00152     return  ((uint32_t)keyb.led_state     << (uint32_t)0 ) |
00153         ((uint32_t)keyb.scanset       << (uint32_t)8 ) |
00154         ((uint32_t)keyb.reset         << (uint32_t)10) |
00155         ((uint32_t)keyb.active        << (uint32_t)11) |
00156         ((uint32_t)keyb.scanning      << (uint32_t)12) |
00157         ((uint32_t)keyb.auxactive     << (uint32_t)13) |
00158         ((uint32_t)keyb.scheduled     << (uint32_t)14) |
00159         ((uint32_t)keyb.p60changed    << (uint32_t)15) |
00160         ((uint32_t)keyb.auxchanged    << (uint32_t)16) |
00161         ((uint32_t)keyb.cb_xlat       << (uint32_t)17) |
00162         ((uint32_t)keyb.ps2mouse.l    << (uint32_t)18) |
00163         ((uint32_t)keyb.ps2mouse.m    << (uint32_t)19) |
00164         ((uint32_t)keyb.ps2mouse.r    << (uint32_t)20) |
00165         ((uint32_t)keyb.ps2mouse.reporting << (uint32_t)21) |
00166         ((uint32_t)(keyb.ps2mouse.mode == MM_STREAM ? 1 : 0) << (uint32_t)22) |
00167         ((uint32_t)mousebtn           << (uint32_t)23);
00168 }
00169 
00170 bool MouseTypeNone() {
00171     return (keyb.ps2mouse.type == MOUSE_NONE);
00172 }
00173 
00174 /* NTS: INT33H emulation is coded to call this ONLY if it hasn't taken over the role of mouse input */
00175 void KEYBOARD_AUX_Event(float x,float y,Bitu buttons,int scrollwheel) {
00176     if (IS_PC98_ARCH) {
00177         LOG_MSG("WARNING: KEYBOARD_AUX_Event called in PC-98 emulation mode. This is a bug.");
00178         return;
00179     }
00180 
00181     keyb.ps2mouse.acx += x;
00182     keyb.ps2mouse.acy += y;
00183     keyb.ps2mouse.l = (buttons & 1)>0;
00184     keyb.ps2mouse.r = (buttons & 2)>0;
00185     keyb.ps2mouse.m = (buttons & 4)>0;
00186 
00187     /* "Valid ranges are -8 to 7"
00188      * http://www.computer-engineering.org/ps2mouse/ */
00189     if (scrollwheel < -8)
00190         scrollwheel = -8;
00191     else if (scrollwheel > 7)
00192         scrollwheel = 7;
00193 
00194     if (keyb.ps2mouse.reporting && keyb.ps2mouse.mode == MM_STREAM) {
00195         if ((keyb.used+4) < KEYBUFSIZE) {
00196             int x2,y2;
00197 
00198             x2 = (int)(keyb.ps2mouse.acx * (1 << keyb.ps2mouse.resolution));
00199             x2 /= 16; /* FIXME: Or else the cursor is WAY too sensitive in Windows 3.1 */
00200             if (x2 < -256) x2 = -256;
00201             else if (x2 > 255) x2 = 255;
00202 
00203             y2 = -((int)(keyb.ps2mouse.acy * (1 << keyb.ps2mouse.resolution)));
00204             y2 /= 16; /* FIXME: Or else the cursor is WAY too sensitive in Windows 3.1 */
00205             if (y2 < -256) y2 = -256;
00206             else if (y2 > 255) y2 = 255;
00207 
00208             KEYBOARD_AddBuffer(AUX|
00209                 ((y2 == -256 || y2 == 255) ? 0x80 : 0x00) |   /* Y overflow */
00210                 ((x2 == -256 || x2 == 255) ? 0x40 : 0x00) |   /* X overflow */
00211                 ((y2 & 0x100) ? 0x20 : 0x00) |         /* Y sign bit */
00212                 ((x2 & 0x100) ? 0x10 : 0x00) |         /* X sign bit */
00213                 0x08 |                      /* always 1? */
00214                 (keyb.ps2mouse.m ? 4 : 0) |         /* M */
00215                 (keyb.ps2mouse.r ? 2 : 0) |         /* R */
00216                 (keyb.ps2mouse.l ? 1 : 0));         /* L */
00217             KEYBOARD_AddBuffer(AUX|(x2&0xFF));
00218             KEYBOARD_AddBuffer(AUX|(y2&0xFF));
00219             if (keyb.ps2mouse.intellimouse_btn45) {
00220                 KEYBOARD_AddBuffer(AUX|(scrollwheel&0xFF)); /* TODO: 4th & 5th buttons */
00221             }
00222             else if (keyb.ps2mouse.intellimouse_mode) {
00223                 KEYBOARD_AddBuffer(AUX|(scrollwheel&0xFF));
00224             }
00225         }
00226 
00227         keyb.ps2mouse.acx = 0;
00228         keyb.ps2mouse.acy = 0;
00229     }
00230 }
00231 
00232 int KEYBOARD_AUX_Active() {
00233     /* NTS: We want to allow software to read by polling, which doesn't
00234      *      require interrupts to be enabled. Whether or not IRQ12 is
00235      *      unmasked is irrelevent */
00236     return keyb.auxactive && !keyb.ps2mouse.int33_taken;
00237 }
00238 
00239 static void KEYBOARD_SetPort60(Bit16u val) {
00240     keyb.auxchanged=(val&AUX)>0;
00241     keyb.p60changed=true;
00242     keyb.p60data=(Bit8u)val;
00243     if (keyb.auxchanged) {
00244         if (keyb.cb_irq12) {
00245             PIC_ActivateIRQ(12);
00246         }
00247     }
00248     else {
00249         if (keyb.cb_irq1) {
00250             if (machine == MCH_PCJR) CPU_Raise_NMI(); /* NTS: PCjr apparently hooked the keyboard to NMI */
00251             else PIC_ActivateIRQ(1);
00252         }
00253     }
00254 }
00255 
00256 static void KEYBOARD_ResetDelay(Bitu val) {
00257     (void)val;//UNUSED
00258     keyb.reset=false;
00259     KEYBOARD_SetLEDs(0);
00260     KEYBOARD_Add8042Response(0x00); /* BAT */
00261 }
00262 
00263 static void KEYBOARD_TransferBuffer(Bitu val) {
00264     (void)val;//UNUSED
00265     /* 8042 responses take priority over the keyboard */
00266     if (keyb.enable_aux && keyb.buf8042_len != 0) {
00267         KEYBOARD_SetPort60(keyb.buf8042[keyb.buf8042_pos]);
00268         if (++keyb.buf8042_pos >= keyb.buf8042_len)
00269             keyb.buf8042_len = keyb.buf8042_pos = 0;
00270         return;
00271     }
00272 
00273     keyb.scheduled=false;
00274     if (!keyb.used) {
00275         LOG(LOG_KEYBOARD,LOG_NORMAL)("Transfer started with empty buffer");
00276         return;
00277     }
00278     KEYBOARD_SetPort60(keyb.buffer[keyb.pos]);
00279     if (++keyb.pos>=KEYBUFSIZE) keyb.pos-=KEYBUFSIZE;
00280     keyb.used--;
00281 }
00282 
00283 void KEYBOARD_ClrBuffer(void) {
00284     keyb.buf8042_len=0;
00285     keyb.buf8042_pos=0;
00286     keyb.used=0;
00287     keyb.pos=0;
00288     PIC_RemoveEvents(KEYBOARD_TransferBuffer);
00289     keyb.scheduled=false;
00290 }
00291 
00292 size_t KEYBOARD_BufferSpaceAvail()   // emendelson from dbDOS
00293 {
00294     return (KEYBUFSIZE - keyb.used);
00295 }                                   // end emendelson from dbDOS
00296 
00297 static void KEYBOARD_Add8042Response(Bit8u data) {
00298     if (keyb.buf8042_pos >= keyb.buf8042_len)
00299         keyb.buf8042_pos = keyb.buf8042_len = 0;
00300     else if (keyb.buf8042_len == 0)
00301         keyb.buf8042_pos = 0;
00302 
00303     if (keyb.buf8042_pos >= sizeof(keyb.buf8042)) {
00304         LOG(LOG_KEYBOARD,LOG_NORMAL)("8042 Buffer full, dropping code");
00305         KEYBOARD_ClrBuffer(); return;
00306     }
00307 
00308     keyb.buf8042[keyb.buf8042_len++] = data;
00309     PIC_AddEvent(KEYBOARD_TransferBuffer,KEYDELAY);
00310 }
00311 
00312 void KEYBOARD_AddBuffer(Bit16u data) {
00313     if (keyb.used>=KEYBUFSIZE) {
00314         LOG(LOG_KEYBOARD,LOG_NORMAL)("Buffer full, dropping code");
00315         KEYBOARD_ClrBuffer(); return;
00316     }
00317     Bitu start=keyb.pos+keyb.used;
00318     if (start>=KEYBUFSIZE) start-=KEYBUFSIZE;
00319     keyb.buffer[start]=data;
00320     keyb.used++;
00321     /* Start up an event to start the first IRQ */
00322     if (!keyb.scheduled && !keyb.p60changed) {
00323         keyb.scheduled=true;
00324         PIC_AddEvent(KEYBOARD_TransferBuffer,KEYDELAY);
00325     }
00326 }
00327 
00328 Bitu Keyboard_Guest_LED_State() {
00329     return keyb.led_state;
00330 }
00331 
00332 void UpdateKeyboardLEDState(Bitu led_state/* in the same bitfield arrangement as using command 0xED on PS/2 keyboards */);
00333 
00334 void KEYBOARD_SetLEDs(Bit8u bits) {
00335     /* Some OSes we have control of the LEDs if keyboard+mouse capture */
00336     keyb.led_state = bits;
00337     UpdateKeyboardLEDState(bits);
00338 
00339     /* TODO: Maybe someday you could have DOSBox show the LEDs */
00340 
00341     /* log for debug info */
00342     LOG(LOG_KEYBOARD,LOG_DEBUG)("Keyboard LEDs: SCR=%u NUM=%u CAPS=%u",bits&1,(bits>>1)&1,(bits>>2)&1);
00343 }
00344 
00345 static Bitu read_p60(Bitu port,Bitu iolen) {
00346     (void)port;//UNUSED
00347     (void)iolen;//UNUSED
00348     keyb.p60changed=false;
00349     keyb.auxchanged=false;
00350     if (!keyb.scheduled && keyb.used) {
00351         keyb.scheduled=true;
00352         PIC_AddEvent(KEYBOARD_TransferBuffer,KEYDELAY);
00353     }
00354     return keyb.p60data;
00355 }
00356 
00357 unsigned char KEYBOARD_AUX_GetType() {
00358     /* and then the ID */
00359     if (keyb.ps2mouse.intellimouse_btn45)
00360         return 0x04;
00361     else if (keyb.ps2mouse.intellimouse_mode)
00362         return 0x03;
00363     else
00364         return 0x00;
00365 }
00366 
00367 unsigned char KEYBOARD_AUX_DevStatus() {
00368     return  (keyb.ps2mouse.mode == MM_REMOTE ? 0x40 : 0x00)|
00369         (keyb.ps2mouse.reporting << 5)|
00370         (keyb.ps2mouse.scale21 << 4)|
00371         (keyb.ps2mouse.m << 2)|
00372         (keyb.ps2mouse.r << 1)|
00373         (keyb.ps2mouse.l << 0);
00374 }
00375 
00376 unsigned char KEYBOARD_AUX_Resolution() {
00377     return keyb.ps2mouse.resolution;
00378 }
00379 
00380 unsigned char KEYBOARD_AUX_SampleRate() {
00381     return keyb.ps2mouse.samplerate;
00382 }
00383 
00384 void KEYBOARD_AUX_Write(Bitu val) {
00385     if (keyb.ps2mouse.type == MOUSE_NONE)
00386         return;
00387 
00388     if (keyb.ps2mouse.mode == MM_WRAP) {
00389         if (val != 0xFF && val != 0xEC) {
00390             KEYBOARD_AddBuffer(AUX|val);
00391             return;
00392         }
00393     }
00394 
00395     switch (keyb.aux_command) {
00396         case ACMD_NONE:
00397             switch (val) {
00398                 case 0xff:  /* reset */
00399                     LOG(LOG_KEYBOARD,LOG_NORMAL)("AUX reset");
00400                     KEYBOARD_AddBuffer(AUX|0xfa);   /* ack */
00401                     KEYBOARD_AddBuffer(AUX|0xaa);   /* reset */
00402                     KEYBOARD_AddBuffer(AUX|0x00);   /* i am mouse */
00403                     Mouse_AutoLock(false);
00404                     AUX_Reset();
00405                     break;
00406                 case 0xf6:  /* set defaults */
00407                     KEYBOARD_AddBuffer(AUX|0xfa);   /* ack */
00408                     AUX_Reset();
00409                     break;
00410                 case 0xf5:  /* disable data reporting */
00411                     KEYBOARD_AddBuffer(AUX|0xfa);   /* ack */
00412                     keyb.ps2mouse.reporting = false;
00413                     break;
00414                 case 0xf4:  /* enable data reporting */
00415                     KEYBOARD_AddBuffer(AUX|0xfa);   /* ack */
00416                     keyb.ps2mouse.reporting = true;
00417                     Mouse_AutoLock(true);
00418                     break;
00419                 case 0xf3:  /* set sample rate */
00420                     KEYBOARD_AddBuffer(AUX|0xfa);   /* ack */
00421                     keyb.aux_command = ACMD_SET_RATE;
00422                     break;
00423                 case 0xf2:  /* get device ID */
00424                     KEYBOARD_AddBuffer(AUX|0xfa);   /* ack */
00425 
00426                     /* and then the ID */
00427                     if (keyb.ps2mouse.intellimouse_btn45)
00428                         KEYBOARD_AddBuffer(AUX|0x04);
00429                     else if (keyb.ps2mouse.intellimouse_mode)
00430                         KEYBOARD_AddBuffer(AUX|0x03);
00431                     else
00432                         KEYBOARD_AddBuffer(AUX|0x00);
00433                     break;
00434                 case 0xf0:  /* set remote mode */
00435                     KEYBOARD_AddBuffer(AUX|0xfa);   /* ack */
00436                     keyb.ps2mouse.mode = MM_REMOTE;
00437                     break;
00438                 case 0xee:  /* set wrap mode */
00439                     KEYBOARD_AddBuffer(AUX|0xfa);   /* ack */
00440                     keyb.ps2mouse.mode = MM_WRAP;
00441                     break;
00442                 case 0xec:  /* reset wrap mode */
00443                     KEYBOARD_AddBuffer(AUX|0xfa);   /* ack */
00444                     keyb.ps2mouse.mode = MM_REMOTE;
00445                     break;
00446                 case 0xeb:  /* read data */
00447                     KEYBOARD_AddBuffer(AUX|0xfa);   /* ack */
00448                     KEYBOARD_AUX_Event(0,0,
00449                         ((unsigned int)keyb.ps2mouse.m << 2u) |
00450                         ((unsigned int)keyb.ps2mouse.r << 1u) |
00451                         ((unsigned int)keyb.ps2mouse.l << 0u),
00452                         0);
00453                     break;
00454                 case 0xea:  /* set stream mode */
00455                     KEYBOARD_AddBuffer(AUX|0xfa);   /* ack */
00456                     keyb.ps2mouse.mode = MM_STREAM;
00457                     break;
00458                 case 0xe9:  /* status request */
00459                     KEYBOARD_AddBuffer(AUX|0xfa);   /* ack */
00460                     KEYBOARD_AddBuffer(AUX|KEYBOARD_AUX_DevStatus());
00461                     KEYBOARD_AddBuffer(AUX|keyb.ps2mouse.resolution);
00462                     KEYBOARD_AddBuffer(AUX|keyb.ps2mouse.samplerate);
00463                     break;
00464                 case 0xe8:  /* set resolution */
00465                     KEYBOARD_AddBuffer(AUX|0xfa);   /* ack */
00466                     keyb.aux_command = ACMD_SET_RESOLUTION;
00467                     break;
00468                 case 0xe7:  /* set scaling 2:1 */
00469                     KEYBOARD_AddBuffer(AUX|0xfa);   /* ack */
00470                     keyb.ps2mouse.scale21 = true;
00471                     LOG(LOG_KEYBOARD,LOG_NORMAL)("PS/2 mouse scaling 2:1");
00472                     break;
00473                 case 0xe6:  /* set scaling 1:1 */
00474                     KEYBOARD_AddBuffer(AUX|0xfa);   /* ack */
00475                     keyb.ps2mouse.scale21 = false;
00476                     LOG(LOG_KEYBOARD,LOG_NORMAL)("PS/2 mouse scaling 1:1");
00477                     break;
00478             }
00479             break;
00480         case ACMD_SET_RATE:
00481             KEYBOARD_AddBuffer(AUX|0xfa);   /* ack */
00482             memmove(keyb.ps2mouse.last_srate,keyb.ps2mouse.last_srate+1,2);
00483             keyb.ps2mouse.last_srate[2] = val;
00484             keyb.ps2mouse.samplerate = val;
00485             keyb.aux_command = ACMD_NONE;
00486             LOG(LOG_KEYBOARD,LOG_NORMAL)("PS/2 mouse sample rate set to %u",(int)val);
00487             if (keyb.ps2mouse.type >= MOUSE_INTELLIMOUSE) {
00488                 if (keyb.ps2mouse.last_srate[0] == 200 && keyb.ps2mouse.last_srate[2] == 80) {
00489                     if (keyb.ps2mouse.last_srate[1] == 100) {
00490                         if (!keyb.ps2mouse.intellimouse_mode) {
00491                             LOG(LOG_KEYBOARD,LOG_NORMAL)("Intellimouse mode enabled");
00492                             keyb.ps2mouse.intellimouse_mode=true;
00493                         }
00494                     }
00495                     else if (keyb.ps2mouse.last_srate[1] == 200 && keyb.ps2mouse.type >= MOUSE_INTELLIMOUSE45) {
00496                         if (!keyb.ps2mouse.intellimouse_btn45) {
00497                             LOG(LOG_KEYBOARD,LOG_NORMAL)("Intellimouse 4/5-button mode enabled");
00498                             keyb.ps2mouse.intellimouse_btn45=true;
00499                         }
00500                     }
00501                 }
00502             }
00503             break;
00504         case ACMD_SET_RESOLUTION:
00505             keyb.aux_command = ACMD_NONE;
00506             KEYBOARD_AddBuffer(AUX|0xfa);   /* ack */
00507             keyb.ps2mouse.resolution = val & 3;
00508             LOG(LOG_KEYBOARD,LOG_NORMAL)("PS/2 mouse resolution set to %u",(int)(1 << (val&3)));
00509             break;
00510     }
00511 }
00512 
00513 #include "control.h"
00514 
00515 bool allow_keyb_reset = true;
00516 
00517 void On_Software_CPU_Reset();
00518 
00519 static void write_p60(Bitu port,Bitu val,Bitu iolen) {
00520     (void)port;//UNUSED
00521     (void)iolen;//UNUSED
00522     switch (keyb.command) {
00523     case CMD_NONE:  /* None */
00524         if (keyb.reset)
00525             return;
00526 
00527         /* No active command this would normally get sent to the keyboard then */
00528         KEYBOARD_ClrBuffer();
00529         switch (val) {
00530         case 0xed:  /* Set Leds */
00531             keyb.command=CMD_SETLEDS;
00532             KEYBOARD_AddBuffer(0xfa);   /* Acknowledge */
00533             break;
00534         case 0xee:  /* Echo */
00535             KEYBOARD_AddBuffer(0xee);   /* Echo */
00536             break;
00537         case 0xf0:  /* set scancode set */
00538             keyb.command=CMD_SETSCANSET;
00539             KEYBOARD_AddBuffer(0xfa);   /* Acknowledge */
00540             break;
00541         case 0xf2:  /* Identify keyboard */
00542             KEYBOARD_AddBuffer(0xfa);   /* Acknowledge */
00543             KEYBOARD_AddBuffer(0xab);   /* ID */
00544             KEYBOARD_AddBuffer(0x83);
00545             break;
00546         case 0xf3: /* Typematic rate programming */
00547             keyb.command=CMD_SETTYPERATE;
00548             KEYBOARD_AddBuffer(0xfa);   /* Acknowledge */
00549             break;
00550         case 0xf4:  /* Enable keyboard,clear buffer, start scanning */
00551             LOG(LOG_KEYBOARD,LOG_NORMAL)("Clear buffer, enable scanning");
00552             KEYBOARD_AddBuffer(0xfa);   /* Acknowledge */
00553             keyb.scanning=true;
00554             break;
00555         case 0xf5:   /* Reset keyboard and disable scanning */
00556             LOG(LOG_KEYBOARD,LOG_NORMAL)("Reset, disable scanning");            
00557             keyb.scanning=false;
00558             KEYBOARD_AddBuffer(0xfa);   /* Acknowledge */
00559             break;
00560         case 0xf6:  /* Reset keyboard and enable scanning */
00561             LOG(LOG_KEYBOARD,LOG_NORMAL)("Reset, enable scanning");
00562             keyb.scanning=true;     /* JC: Original DOSBox code was wrong, this command enables scanning */
00563             KEYBOARD_AddBuffer(0xfa);   /* Acknowledge */
00564             break;
00565         case 0xff:      /* keyboard resets take a long time (about 250ms), most keyboards flash the LEDs during reset */
00566             KEYBOARD_Reset();
00567             KEYBOARD_Add8042Response(0xFA); /* ACK */
00568             KEYBOARD_Add8042Response(0xAA); /* SELF TEST OK (TODO: Need delay!) */
00569             keyb.reset=true;
00570             KEYBOARD_SetLEDs(7); /* most keyboard I test with tend to flash the LEDs during reset */
00571             PIC_AddEvent(KEYBOARD_ResetDelay,RESETDELAY);
00572             break;
00573         default:
00574             /* Just always acknowledge strange commands */
00575             LOG(LOG_KEYBOARD,LOG_ERROR)("60:Unhandled command %X",(int)val);
00576             KEYBOARD_AddBuffer(0xfa);   /* Acknowledge */
00577         }
00578         return;
00579     case CMD_SETSCANSET:
00580         keyb.command=CMD_NONE;
00581         KEYBOARD_AddBuffer(0xfa);   /* Acknowledge */
00582         if (val == 0) { /* just asking */
00583             if (keyb.cb_xlat) {
00584                 switch (keyb.scanset) {
00585                     case 1: KEYBOARD_AddBuffer(0x43); break;
00586                     case 2: KEYBOARD_AddBuffer(0x41); break;
00587                     case 3: KEYBOARD_AddBuffer(0x3F); break;
00588                 }
00589             }
00590             else {
00591                 KEYBOARD_AddBuffer(keyb.scanset);
00592             }
00593         }
00594         else {
00595             if (val > 3) val = 3;
00596             keyb.scanset = val;
00597         }
00598         break;
00599     case CMD_WRITEAUX:
00600         keyb.command=CMD_NONE;
00601         KEYBOARD_AUX_Write(val);
00602         break;
00603     case CMD_WRITEOUTPUT:
00604         keyb.command=CMD_NONE;
00605         KEYBOARD_ClrBuffer();
00606         KEYBOARD_AddBuffer(val);    /* and now you return the byte as if it were typed in */
00607         break;
00608     case CMD_WRITEAUXOUT:
00609         KEYBOARD_AddBuffer(AUX|val); /* stuff into AUX output */
00610         break;
00611     case CMD_SETOUTPORT:
00612         if (!(val & 1)) {
00613             if (allow_keyb_reset) {
00614                 LOG_MSG("Restart by keyboard controller requested\n");
00615                 On_Software_CPU_Reset();
00616             }
00617             else {
00618                 LOG_MSG("WARNING: Keyboard output port written with bit 1 clear. Is the guest OS or application attempting to reset the system?\n");
00619             }
00620         }
00621         MEM_A20_Enable((val & 2)>0);
00622         keyb.command = CMD_NONE;
00623         break;
00624     case CMD_SETTYPERATE: 
00625         if (keyb.reset)
00626             return;
00627 
00628         {
00629             static const unsigned int delay[] = { 250, 500, 750, 1000 };
00630             static const unsigned int repeat[] =
00631             { 33,37,42,46,50,54,58,63,67,75,83,92,100,
00632               109,118,125,133,149,167,182,200,217,233,
00633               250,270,303,333,370,400,435,476,500 };
00634             keyb.repeat.pause = delay[(val >> 5) & 3];
00635             keyb.repeat.rate = repeat[val & 0x1f];
00636             keyb.command = CMD_NONE;
00637             KEYBOARD_ClrBuffer();
00638             KEYBOARD_AddBuffer(0xfa);   /* Acknowledge */
00639         }
00640         break;
00641     case CMD_SETLEDS:
00642         if (keyb.reset)
00643             return;
00644 
00645         keyb.command=CMD_NONE;
00646         KEYBOARD_ClrBuffer();
00647         KEYBOARD_AddBuffer(0xfa);   /* Acknowledge */
00648         KEYBOARD_SetLEDs(val&7);
00649         break;
00650     case CMD_SETCOMMAND: /* 8042 command, not keyboard */
00651         /* TODO: If biosps2=true and aux=false, disallow the guest OS from changing AUX port parameters including IRQ */
00652         keyb.command=CMD_NONE;
00653         keyb.cb_xlat = (val >> 6) & 1;
00654         keyb.auxactive = !((val >> 5) & 1);
00655         keyb.active = !((val >> 4) & 1);
00656         keyb.cb_sys = (val >> 2) & 1;
00657         keyb.cb_irq12 = (val >> 1) & 1;
00658         keyb.cb_irq1 = (val >> 0) & 1;
00659         if (keyb.used && !keyb.scheduled && !keyb.p60changed && keyb.active) {
00660             keyb.scheduled=true;
00661             PIC_AddEvent(KEYBOARD_TransferBuffer,KEYDELAY);
00662         }
00663         break;
00664     }
00665 }
00666 
00667 static Bit8u port_61_data = 0;
00668 
00669 static Bitu read_p61(Bitu, Bitu) {
00670     unsigned char dbg;
00671     dbg = ((port_61_data & 0xF) |
00672         ((TIMER_GetOutput2() || (port_61_data&1) == 0)? 0x20:0) | // NTS: Timer 2 doesn't cycle if Port 61 gate turned off, and it becomes '1' when turned off
00673         ((fmod(PIC_FullIndex(),0.030) > 0.015)? 0x10:0));
00674     return dbg;
00675 }
00676 
00677 static void write_p61(Bitu, Bitu val, Bitu) {
00678     Bit8u diff = port_61_data ^ (Bit8u)val;
00679     if (diff & 0x1) TIMER_SetGate2(val & 0x1);
00680     if ((diff & 0x3) && !IS_PC98_ARCH) {
00681         bool pit_clock_gate_enabled = !!(val & 0x1);
00682         bool pit_output_enabled = !!(val & 0x2);
00683         PCSPEAKER_SetType(pit_clock_gate_enabled, pit_output_enabled);
00684     }
00685     port_61_data = val;
00686 }
00687 
00688 static Bitu read_p62(Bitu /*port*/,Bitu /*iolen*/) {
00689     Bit8u ret = Bit8u(~0x20u);
00690     if (TIMER_GetOutput2()) ret|=0x20u;
00691     return ret;
00692 }
00693 
00694 static void write_p64(Bitu port,Bitu val,Bitu iolen) {
00695     (void)port;//UNUSED
00696     (void)iolen;//UNUSED
00697     if (keyb.reset)
00698         return;
00699 
00700     switch (val) {
00701     case 0x20:      /* read command byte */
00702         /* TODO: If biosps2=true and aux=false, mask AUX port bits as if AUX isn't there */
00703         KEYBOARD_Add8042Response(
00704             (keyb.cb_xlat << 6)      | ((!keyb.auxactive) << 5) |
00705             ((!keyb.active) << 4)    | (keyb.cb_sys << 2) |
00706             (keyb.cb_irq12 << 1)     | (keyb.cb_irq1?1:0));
00707         break;
00708     case 0x60:
00709         keyb.command=CMD_SETCOMMAND;
00710         break;
00711     case 0x90: case 0x91: case 0x92: case 0x93: case 0x94: case 0x95: case 0x96: case 0x97:
00712     case 0x98: case 0x99: case 0x9a: case 0x9b: case 0x9c: case 0x9d: case 0x9e: case 0x9f:
00713         /* TODO: If bit 0 == 0, trigger system reset */
00714         break;
00715     case 0xa7:      /* disable aux */
00716         /* TODO: If biosps2=true and aux=false do not respond */
00717         if (keyb.enable_aux) {
00718             //keyb.auxactive=false;
00719             //LOG(LOG_KEYBOARD,LOG_NORMAL)("AUX De-Activated");
00720         }
00721         break;
00722     case 0xa8:      /* enable aux */
00723         /* TODO: If biosps2=true and aux=false do not respond */
00724         if (keyb.enable_aux) {
00725             keyb.auxactive=true;
00726             if (keyb.used && !keyb.scheduled && !keyb.p60changed) {
00727                 keyb.scheduled=true;
00728                 PIC_AddEvent(KEYBOARD_TransferBuffer,KEYDELAY);
00729             }
00730             LOG(LOG_KEYBOARD,LOG_NORMAL)("AUX Activated");
00731         }
00732         break;
00733     case 0xa9:      /* mouse interface test */
00734         /* TODO: If biosps2=true and aux=false do not respond */
00735         KEYBOARD_Add8042Response(0x00); /* OK */
00736         break;
00737     case 0xaa:      /* Self test */
00738         keyb.active=false; /* on real h/w it also seems to disable the keyboard */
00739         KEYBOARD_Add8042Response(0xaa); /* OK */
00740         break;
00741     case 0xab:      /* interface test */
00742         keyb.active=false; /* on real h/w it also seems to disable the keyboard */
00743         KEYBOARD_Add8042Response(0x00); /* no error */
00744         break;
00745     case 0xae:      /* Activate keyboard */
00746         keyb.active=true;
00747         if (keyb.used && !keyb.scheduled && !keyb.p60changed) {
00748             keyb.scheduled=true;
00749             PIC_AddEvent(KEYBOARD_TransferBuffer,KEYDELAY);
00750         }
00751         LOG(LOG_KEYBOARD,LOG_NORMAL)("Activated");
00752         break;
00753     case 0xad:      /* Deactivate keyboard */
00754         keyb.active=false;
00755         LOG(LOG_KEYBOARD,LOG_NORMAL)("De-Activated");
00756         break;
00757     case 0xc0:      /* read input buffer */
00758         KEYBOARD_Add8042Response(0x40);
00759         break;
00760     case 0xd0:      /* Outport on buffer */
00761         KEYBOARD_SetPort60((MEM_A20_Enabled() ? 0x02 : 0) | 0x01/*some programs read the output port then write it back*/);
00762         break;
00763     case 0xd1:      /* Write to outport */
00764         keyb.command=CMD_SETOUTPORT;
00765         break;
00766     case 0xd2:      /* write output register */
00767         keyb.command=CMD_WRITEOUTPUT;
00768         break;
00769     case 0xd3:      /* write AUX output */
00770         if (keyb.enable_aux)
00771             keyb.command=CMD_WRITEAUXOUT;
00772         else if (aux_warning++ == 0)
00773             LOG(LOG_KEYBOARD,LOG_ERROR)("Program is writing 8042 AUX. If you intend to use PS/2 mouse emulation you may consider adding aux=1 to your dosbox.conf");
00774         break;
00775     case 0xd4:      /* send byte to AUX */
00776         if (keyb.enable_aux)
00777             keyb.command=CMD_WRITEAUX;
00778         else if (aux_warning++ == 0)
00779             LOG(LOG_KEYBOARD,LOG_ERROR)("Program is writing 8042 AUX. If you intend to use PS/2 mouse emulation you may consider adding aux=1 to your dosbox.conf");
00780         break;
00781     case 0xe0:      /* read test port */
00782         KEYBOARD_Add8042Response(0x00);
00783         break;
00784     case 0xf0: case 0xf1: case 0xf2: case 0xf3: case 0xf4: case 0xf5: case 0xf6: case 0xf7:
00785     case 0xf8: case 0xf9: case 0xfa: case 0xfb: case 0xfc: case 0xfd: case 0xfe: case 0xff:
00786         /* pulse output register */
00787         if (!(val & 1)) {
00788             if (allow_keyb_reset) {
00789                 LOG_MSG("Restart by keyboard controller requested\n");
00790                 On_Software_CPU_Reset();
00791             }
00792             else {
00793                 LOG_MSG("WARNING: Keyboard output port written (pulsed) with bit 1 clear. Is the guest OS or application attempting to reset the system?\n");
00794             }
00795         }
00796         break;
00797     default:
00798         LOG(LOG_KEYBOARD,LOG_ERROR)("Port 64 write with val %d",(int)val);
00799         break;
00800     }
00801 }
00802 
00803 static Bitu read_p64(Bitu port,Bitu iolen) {
00804     (void)port;//UNUSED
00805     (void)iolen;//UNUSED
00806     Bit8u status= 0x1c | (keyb.p60changed?0x1:0x0) | (keyb.auxchanged?0x20:0x00);
00807     return status;
00808 }
00809 
00810 void KEYBOARD_AddKey3(KBD_KEYS keytype,bool pressed) {
00811     Bit8u ret=0,ret2=0;
00812 
00813     if (keyb.reset)
00814         return;
00815 
00816     /* if the keyboard is disabled, then store the keystroke but don't transmit yet */
00817     /*
00818     if (!keyb.active || !keyb.scanning) {
00819         keyb.pending_key = keytype;
00820         keyb.pending_key_state = pressed;
00821         return;
00822     }
00823     */
00824 
00825     switch (keytype) {
00826     case KBD_kor_hancha:
00827         keyb.repeat.key=KBD_NONE;
00828         keyb.repeat.wait=0;
00829         if (!pressed) return;
00830         KEYBOARD_AddBuffer(0xF1);
00831         break;
00832     case KBD_kor_hanyong:
00833         keyb.repeat.key=KBD_NONE;
00834         keyb.repeat.wait=0;
00835         if (!pressed) return;
00836         KEYBOARD_AddBuffer(0xF2);
00837         break;
00838     case KBD_esc:ret=0x08;break;
00839     case KBD_1:ret=0x16;break;
00840     case KBD_2:ret=0x1E;break;
00841     case KBD_3:ret=0x26;break;      
00842     case KBD_4:ret=0x25;break;
00843     case KBD_5:ret=0x2e;break;
00844     case KBD_6:ret=0x36;break;      
00845     case KBD_7:ret=0x3d;break;
00846     case KBD_8:ret=0x3e;break;
00847     case KBD_9:ret=0x46;break;      
00848     case KBD_0:ret=0x45;break;
00849 
00850     case KBD_minus:ret=0x4e;break;
00851     case KBD_equals:ret=0x55;break;
00852     case KBD_kpequals:ret=0x0F;break; /* According to Battler */
00853     case KBD_backspace:ret=0x66;break;
00854     case KBD_tab:ret=0x0d;break;
00855 
00856     case KBD_q:ret=0x15;break;      
00857     case KBD_w:ret=0x1d;break;
00858     case KBD_e:ret=0x24;break;      
00859     case KBD_r:ret=0x2d;break;
00860     case KBD_t:ret=0x2c;break;      
00861     case KBD_y:ret=0x35;break;
00862     case KBD_u:ret=0x3c;break;      
00863     case KBD_i:ret=0x43;break;
00864     case KBD_o:ret=0x44;break;      
00865     case KBD_p:ret=0x4d;break;
00866 
00867     case KBD_leftbracket:ret=0x54;break;
00868     case KBD_rightbracket:ret=0x5b;break;
00869     case KBD_enter:ret=0x5a;break;
00870     case KBD_leftctrl:ret=0x11;break;
00871 
00872     case KBD_a:ret=0x1c;break;
00873     case KBD_s:ret=0x1b;break;
00874     case KBD_d:ret=0x23;break;
00875     case KBD_f:ret=0x2b;break;
00876     case KBD_g:ret=0x34;break;      
00877     case KBD_h:ret=0x33;break;      
00878     case KBD_j:ret=0x3b;break;
00879     case KBD_k:ret=0x42;break;      
00880     case KBD_l:ret=0x4b;break;
00881 
00882     case KBD_semicolon:ret=0x4c;break;
00883     case KBD_quote:ret=0x52;break;
00884     case KBD_jp_hankaku:ret=0x0e;break;
00885     case KBD_grave:ret=0x0e;break;
00886     case KBD_leftshift:ret=0x12;break;
00887     case KBD_backslash:ret=0x5c;break;
00888     case KBD_z:ret=0x1a;break;
00889     case KBD_x:ret=0x22;break;
00890     case KBD_c:ret=0x21;break;
00891     case KBD_v:ret=0x2a;break;
00892     case KBD_b:ret=0x32;break;
00893     case KBD_n:ret=0x31;break;
00894     case KBD_m:ret=0x3a;break;
00895 
00896     case KBD_comma:ret=0x41;break;
00897     case KBD_period:ret=0x49;break;
00898     case KBD_slash:ret=0x4a;break;
00899     case KBD_rightshift:ret=0x59;break;
00900     case KBD_kpmultiply:ret=0x7e;break;
00901     case KBD_leftalt:ret=0x19;break;
00902     case KBD_space:ret=0x29;break;
00903     case KBD_capslock:ret=0x14;break;
00904 
00905     case KBD_f1:ret=0x07;break;
00906     case KBD_f2:ret=0x0f;break;
00907     case KBD_f3:ret=0x17;break;
00908     case KBD_f4:ret=0x1f;break;
00909     case KBD_f5:ret=0x27;break;
00910     case KBD_f6:ret=0x2f;break;
00911     case KBD_f7:ret=0x37;break;
00912     case KBD_f8:ret=0x3f;break;
00913     case KBD_f9:ret=0x47;break;
00914     case KBD_f10:ret=0x4f;break;
00915     case KBD_f11:ret=0x56;break;
00916     case KBD_f12:ret=0x5e;break;
00917 
00918     /* IBM F13-F24 = Shift F1-F12 */
00919     case KBD_f13:ret=0x12;ret2=0x07;break;
00920     case KBD_f14:ret=0x12;ret2=0x0F;break;
00921     case KBD_f15:ret=0x12;ret2=0x17;break;
00922     case KBD_f16:ret=0x12;ret2=0x1F;break;
00923     case KBD_f17:ret=0x12;ret2=0x27;break;
00924     case KBD_f18:ret=0x12;ret2=0x2F;break;
00925     case KBD_f19:ret=0x12;ret2=0x37;break;
00926     case KBD_f20:ret=0x12;ret2=0x3F;break;
00927     case KBD_f21:ret=0x12;ret2=0x47;break;
00928     case KBD_f22:ret=0x12;ret2=0x4F;break;
00929     case KBD_f23:ret=0x12;ret2=0x56;break;
00930     case KBD_f24:ret=0x12;ret2=0x5E;break;
00931 
00932     case KBD_numlock:ret=0x76;break;
00933     case KBD_scrolllock:ret=0x5f;break;
00934 
00935     case KBD_kp7:ret=0x6c;break;
00936     case KBD_kp8:ret=0x75;break;
00937     case KBD_kp9:ret=0x7d;break;
00938     case KBD_kpminus:ret=0x84;break;
00939     case KBD_kp4:ret=0x6b;break;
00940     case KBD_kp5:ret=0x73;break;
00941     case KBD_kp6:ret=0x74;break;
00942     case KBD_kpplus:ret=0x7c;break;
00943     case KBD_kp1:ret=0x69;break;
00944     case KBD_kp2:ret=0x72;break;
00945     case KBD_kp3:ret=0x7a;break;
00946     case KBD_kp0:ret=0x70;break;
00947     case KBD_kpperiod:ret=0x71;break;
00948 
00949 /*  case KBD_extra_lt_gt:ret=;break; */
00950 
00951     //The Extended keys
00952 
00953     case KBD_kpenter:ret=0x79;break;
00954     case KBD_rightctrl:ret=0x58;break;
00955     case KBD_kpdivide:ret=0x77;break;
00956     case KBD_rightalt:ret=0x39;break;
00957     case KBD_home:ret=0x6e;break;
00958     case KBD_up:ret=0x63;break;
00959     case KBD_pageup:ret=0x6f;break;
00960     case KBD_left:ret=0x61;break;
00961     case KBD_right:ret=0x6a;break;
00962     case KBD_end:ret=0x65;break;
00963     case KBD_down:ret=0x60;break;
00964     case KBD_pagedown:ret=0x6d;break;
00965     case KBD_insert:ret=0x67;break;
00966     case KBD_delete:ret=0x64;break;
00967     case KBD_pause:ret=0x62;break;
00968     case KBD_printscreen:ret=0x57;break;
00969     case KBD_lwindows:ret=0x8B;break;
00970     case KBD_rwindows:ret=0x8C;break;
00971     case KBD_rwinmenu:ret=0x8D;break;
00972     case KBD_jp_muhenkan:ret=0x85;break;
00973     case KBD_jp_henkan:ret=0x86;break;
00974     case KBD_jp_hiragana:ret=0x87;break;/*also Katakana */
00975     default:
00976         LOG(LOG_MISC, LOG_WARN)("Unsupported key press %lu", (unsigned long)keytype);
00977         return;
00978     }
00979 
00980     /* Add the actual key in the keyboard queue */
00981     if (pressed) {
00982         if (keyb.repeat.key==keytype) keyb.repeat.wait=keyb.repeat.rate;        
00983         else keyb.repeat.wait=keyb.repeat.pause;
00984         keyb.repeat.key=keytype;
00985     } else {
00986         if (keytype >= KBD_f13 && keytype <= KBD_f24) {
00987             unsigned int t = ret;
00988             ret = ret2;
00989             ret2 = t;
00990         }
00991 
00992         keyb.repeat.key=KBD_NONE;
00993         keyb.repeat.wait=0;
00994     }
00995 
00996     if (!pressed) KEYBOARD_AddBuffer(0xf0);
00997     KEYBOARD_AddBuffer(ret);
00998     if (ret2 != 0) {
00999         if (!pressed) KEYBOARD_AddBuffer(0xf0);
01000         KEYBOARD_AddBuffer(ret2);
01001     }
01002 }
01003 
01004 void KEYBOARD_AddKey2(KBD_KEYS keytype,bool pressed) {
01005     Bit8u ret=0,ret2=0;bool extend=false;
01006 
01007     if (keyb.reset)
01008         return;
01009 
01010     /* if the keyboard is disabled, then store the keystroke but don't transmit yet */
01011     /*if (!keyb.active || !keyb.scanning) {
01012         keyb.pending_key = keytype;
01013         keyb.pending_key_state = pressed;
01014         return;
01015     }*/
01016 
01017     switch (keytype) {
01018     case KBD_kor_hancha:
01019         keyb.repeat.key=KBD_NONE;
01020         keyb.repeat.wait=0;
01021         if (!pressed) return;
01022         KEYBOARD_AddBuffer(0xF1);
01023         break;
01024     case KBD_kor_hanyong:
01025         keyb.repeat.key=KBD_NONE;
01026         keyb.repeat.wait=0;
01027         if (!pressed) return;
01028         KEYBOARD_AddBuffer(0xF2);
01029         break;
01030     case KBD_esc:ret=0x76;break;
01031     case KBD_1:ret=0x16;break;
01032     case KBD_2:ret=0x1e;break;
01033     case KBD_3:ret=0x26;break;      
01034     case KBD_4:ret=0x25;break;
01035     case KBD_5:ret=0x2e;break;
01036     case KBD_6:ret=0x36;break;      
01037     case KBD_7:ret=0x3d;break;
01038     case KBD_8:ret=0x3e;break;
01039     case KBD_9:ret=0x46;break;      
01040     case KBD_0:ret=0x45;break;
01041 
01042     case KBD_minus:ret=0x4e;break;
01043     case KBD_equals:ret=0x55;break;
01044     case KBD_kpequals:ret=0x0F;break; /* According to Battler */
01045     case KBD_backspace:ret=0x66;break;
01046     case KBD_tab:ret=0x0d;break;
01047 
01048     case KBD_q:ret=0x15;break;      
01049     case KBD_w:ret=0x1d;break;
01050     case KBD_e:ret=0x24;break;      
01051     case KBD_r:ret=0x2d;break;
01052     case KBD_t:ret=0x2c;break;      
01053     case KBD_y:ret=0x35;break;
01054     case KBD_u:ret=0x3c;break;      
01055     case KBD_i:ret=0x43;break;
01056     case KBD_o:ret=0x44;break;      
01057     case KBD_p:ret=0x4d;break;
01058 
01059     case KBD_leftbracket:ret=0x54;break;
01060     case KBD_rightbracket:ret=0x5b;break;
01061     case KBD_enter:ret=0x5a;break;
01062     case KBD_leftctrl:ret=0x14;break;
01063 
01064     case KBD_a:ret=0x1c;break;
01065     case KBD_s:ret=0x1b;break;
01066     case KBD_d:ret=0x23;break;
01067     case KBD_f:ret=0x2b;break;
01068     case KBD_g:ret=0x34;break;      
01069     case KBD_h:ret=0x33;break;      
01070     case KBD_j:ret=0x3b;break;
01071     case KBD_k:ret=0x42;break;      
01072     case KBD_l:ret=0x4b;break;
01073 
01074     case KBD_semicolon:ret=0x4c;break;
01075     case KBD_quote:ret=0x52;break;
01076     case KBD_jp_hankaku:ret=0x0e;break;
01077     case KBD_grave:ret=0x0e;break;
01078     case KBD_leftshift:ret=0x12;break;
01079     case KBD_backslash:ret=0x5d;break;
01080     case KBD_z:ret=0x1a;break;
01081     case KBD_x:ret=0x22;break;
01082     case KBD_c:ret=0x21;break;
01083     case KBD_v:ret=0x2a;break;
01084     case KBD_b:ret=0x32;break;
01085     case KBD_n:ret=0x31;break;
01086     case KBD_m:ret=0x3a;break;
01087 
01088     case KBD_comma:ret=0x41;break;
01089     case KBD_period:ret=0x49;break;
01090     case KBD_slash:ret=0x4a;break;
01091     case KBD_rightshift:ret=0x59;break;
01092     case KBD_kpmultiply:ret=0x7c;break;
01093     case KBD_leftalt:ret=0x11;break;
01094     case KBD_space:ret=0x29;break;
01095     case KBD_capslock:ret=0x58;break;
01096 
01097     case KBD_f1:ret=0x05;break;
01098     case KBD_f2:ret=0x06;break;
01099     case KBD_f3:ret=0x04;break;
01100     case KBD_f4:ret=0x0c;break;
01101     case KBD_f5:ret=0x03;break;
01102     case KBD_f6:ret=0x0b;break;
01103     case KBD_f7:ret=0x83;break;
01104     case KBD_f8:ret=0x0a;break;
01105     case KBD_f9:ret=0x01;break;
01106     case KBD_f10:ret=0x09;break;
01107     case KBD_f11:ret=0x78;break;
01108     case KBD_f12:ret=0x07;break;
01109 
01110     /* IBM F13-F24 = Shift F1-F12 */
01111     case KBD_f13:ret=0x12;ret2=0x05;break;
01112     case KBD_f14:ret=0x12;ret2=0x06;break;
01113     case KBD_f15:ret=0x12;ret2=0x04;break;
01114     case KBD_f16:ret=0x12;ret2=0x0c;break;
01115     case KBD_f17:ret=0x12;ret2=0x03;break;
01116     case KBD_f18:ret=0x12;ret2=0x0b;break;
01117     case KBD_f19:ret=0x12;ret2=0x83;break;
01118     case KBD_f20:ret=0x12;ret2=0x0a;break;
01119     case KBD_f21:ret=0x12;ret2=0x01;break;
01120     case KBD_f22:ret=0x12;ret2=0x09;break;
01121     case KBD_f23:ret=0x12;ret2=0x78;break;
01122     case KBD_f24:ret=0x12;ret2=0x07;break;
01123 
01124     case KBD_numlock:ret=0x77;break;
01125     case KBD_scrolllock:ret=0x7e;break;
01126 
01127     case KBD_kp7:ret=0x6c;break;
01128     case KBD_kp8:ret=0x75;break;
01129     case KBD_kp9:ret=0x7d;break;
01130     case KBD_kpminus:ret=0x7b;break;
01131     case KBD_kp4:ret=0x6b;break;
01132     case KBD_kp5:ret=0x73;break;
01133     case KBD_kp6:ret=0x74;break;
01134     case KBD_kpplus:ret=0x79;break;
01135     case KBD_kp1:ret=0x69;break;
01136     case KBD_kp2:ret=0x72;break;
01137     case KBD_kp3:ret=0x7a;break;
01138     case KBD_kp0:ret=0x70;break;
01139     case KBD_kpperiod:ret=0x71;break;
01140 
01141 /*  case KBD_extra_lt_gt:ret=;break; */
01142 
01143     //The Extended keys
01144 
01145     case KBD_kpenter:extend=true;ret=0x5a;break;
01146     case KBD_rightctrl:extend=true;ret=0x14;break;
01147     case KBD_kpdivide:extend=true;ret=0x4a;break;
01148     case KBD_rightalt:extend=true;ret=0x11;break;
01149     case KBD_home:extend=true;ret=0x6c;break;
01150     case KBD_up:extend=true;ret=0x75;break;
01151     case KBD_pageup:extend=true;ret=0x7d;break;
01152     case KBD_left:extend=true;ret=0x6b;break;
01153     case KBD_right:extend=true;ret=0x74;break;
01154     case KBD_end:extend=true;ret=0x69;break;
01155     case KBD_down:extend=true;ret=0x72;break;
01156     case KBD_pagedown:extend=true;ret=0x7a;break;
01157     case KBD_insert:extend=true;ret=0x70;break;
01158     case KBD_delete:extend=true;ret=0x71;break;
01159     case KBD_pause:
01160         KEYBOARD_AddBuffer(0xe1);
01161         KEYBOARD_AddBuffer(0x14);
01162         KEYBOARD_AddBuffer(0x77);
01163         KEYBOARD_AddBuffer(0xe1);
01164         KEYBOARD_AddBuffer(0xf0);
01165         KEYBOARD_AddBuffer(0x14);
01166         KEYBOARD_AddBuffer(0xf0);
01167         KEYBOARD_AddBuffer(0x77);
01168         return;
01169     case KBD_printscreen:
01170         extend=true;
01171         if (pressed) { ret=0x12; ret2=0x7c; }
01172         else         { ret=0x7c; ret2=0x12; }
01173         return;
01174     case KBD_lwindows:extend=true;ret=0x1f;break;
01175     case KBD_rwindows:extend=true;ret=0x27;break;
01176     case KBD_rwinmenu:extend=true;ret=0x2f;break;
01177     case KBD_jp_muhenkan:ret=0x67;break;
01178     case KBD_jp_henkan:ret=0x64;break;
01179     case KBD_jp_hiragana:ret=0x13;break;/*also Katakana */
01180     default:
01181         LOG(LOG_MISC, LOG_WARN)("Unsupported key press %lu", (unsigned long)keytype);
01182         return;
01183     }
01184     /* Add the actual key in the keyboard queue */
01185     if (pressed) {
01186         if (keyb.repeat.key==keytype) keyb.repeat.wait=keyb.repeat.rate;        
01187         else keyb.repeat.wait=keyb.repeat.pause;
01188         keyb.repeat.key=keytype;
01189     } else {
01190         if (keytype >= KBD_f13 && keytype <= KBD_f24) {
01191             unsigned int t = ret;
01192             ret = ret2;
01193             ret2 = t;
01194         }
01195 
01196         keyb.repeat.key=KBD_NONE;
01197         keyb.repeat.wait=0;
01198     }
01199 
01200     if (extend) KEYBOARD_AddBuffer(0xe0);
01201     if (!pressed) KEYBOARD_AddBuffer(0xf0);
01202     KEYBOARD_AddBuffer(ret);
01203     if (ret2 != 0) {
01204         if (extend) KEYBOARD_AddBuffer(0xe0); 
01205         if (!pressed) KEYBOARD_AddBuffer(0xf0);
01206         KEYBOARD_AddBuffer(ret2);
01207     }
01208 }
01209 
01210 bool pc98_caps(void);
01211 bool pc98_kana(void);
01212 void pc98_caps_toggle(void);
01213 void pc98_kana_toggle(void);
01214 void pc98_numlock_toggle(void);
01215 void pc98_keyboard_send(const unsigned char b);
01216 bool pc98_force_ibm_layout = false;
01217 
01218 /* this version sends to the PC-98 8251 emulation NOT the AT 8042 emulation */
01219 void KEYBOARD_PC98_AddKey(KBD_KEYS keytype,bool pressed) {
01220     Bit8u ret=0;
01221 
01222     switch (keytype) {                          // NAME or
01223                                                 // NM SH KA KA+SH       NM=no-mod SH=shift KA=kana KA+SH=kana+shift
01224     case KBD_esc:           ret=0x00;break;     // ESC
01225     case KBD_1:             ret=0x01;break;     // 1  !  ヌ
01226     case KBD_2:             ret=0x02;break;     // 2  "  フ
01227     case KBD_3:             ret=0x03;break;     // 3  #  ア ァ
01228     case KBD_4:             ret=0x04;break;     // 4  $  ウ ゥ
01229     case KBD_5:             ret=0x05;break;     // 5  %  エ ェ
01230     case KBD_6:             ret=0x06;break;     // 6  &  オ ォ
01231     case KBD_7:             ret=0x07;break;     // 7  '  ヤ ャ
01232     case KBD_8:             ret=0x08;break;     // 8  (  ユ ュ
01233     case KBD_9:             ret=0x09;break;     // 9  )  ヨ ョ
01234     case KBD_0:             ret=0x0A;break;     // 0     ワ ヲ
01235     case KBD_minus:         ret=0x0B;break;     // -  =  ホ
01236     case KBD_equals:        ret=0x0C;break;     // ^  `  ヘ             US keyboard layout hack
01237     case KBD_caret:         ret=0x0C;break;     // ^  `  ヘ
01238     case KBD_backslash:     ret=0x0D;break;     // ¥  |  ー
01239     case KBD_jp_yen:        ret=0x0D;break;     // ¥  |  ー
01240     case KBD_backspace:     ret=0x0E;break;     // BS (BACKSPACE)
01241     case KBD_tab:           ret=0x0F;break;     // TAB
01242     case KBD_q:             ret=0x10;break;     // q  Q  タ
01243     case KBD_w:             ret=0x11;break;     // w  W  テ
01244     case KBD_e:             ret=0x12;break;     // e  E  イ ィ
01245     case KBD_r:             ret=0x13;break;     // r  R  ス
01246     case KBD_t:             ret=0x14;break;     // t  T  カ
01247     case KBD_y:             ret=0x15;break;     // y  Y  ン
01248     case KBD_u:             ret=0x16;break;     // u  U  ナ
01249     case KBD_i:             ret=0x17;break;     // i  I  ニ
01250     case KBD_o:             ret=0x18;break;     // o  O  ラ
01251     case KBD_p:             ret=0x19;break;     // p  P  セ
01252     case KBD_atsign:        ret=0x1A;break;     // @  ~  ゙
01253     case KBD_leftbracket:   ret=0x1B;break;     // [  {  ゚  「
01254     case KBD_enter:         ret=0x1C;break;     // ENTER/RETURN
01255     case KBD_kpenter:       ret=0x1C;break;     // ENTER/RETURN (KEYPAD)
01256     case KBD_a:             ret=0x1D;break;     // a  A  チ
01257     case KBD_s:             ret=0x1E;break;     // s  S  ト
01258     case KBD_d:             ret=0x1F;break;     // d  D  シ
01259     case KBD_f:             ret=0x20;break;     // f  F  ハ
01260     case KBD_g:             ret=0x21;break;     // g  G  キ
01261     case KBD_h:             ret=0x22;break;     // h  H  ク
01262     case KBD_j:             ret=0x23;break;     // j  J  マ
01263     case KBD_k:             ret=0x24;break;     // k  K  ノ
01264     case KBD_l:             ret=0x25;break;     // l  L  リ
01265     case KBD_semicolon:     ret=0x26;break;     // ;  +  レ
01266     case KBD_quote:         ret=0x27;break;     // :  *  ケ         American US keyboard layout hack
01267     case KBD_colon:         ret=0x27;break;     // :  *  ケ
01268     case KBD_rightbracket:  ret=0x28;break;     // ]  }  ム 」
01269     case KBD_z:             ret=0x29;break;     // z  Z  ツ ッ
01270     case KBD_x:             ret=0x2A;break;     // x  X  サ
01271     case KBD_c:             ret=0x2B;break;     // c  C  ソ
01272     case KBD_v:             ret=0x2C;break;     // v  V  ヒ
01273     case KBD_b:             ret=0x2D;break;     // b  B  コ
01274     case KBD_n:             ret=0x2E;break;     // n  N  ミ
01275     case KBD_m:             ret=0x2F;break;     // m  M  モ
01276     case KBD_comma:         ret=0x30;break;     // ,  <  ネ 、
01277     case KBD_period:        ret=0x31;break;     // .  >  ル 。
01278     case KBD_slash:         ret=0x32;break;     // /  ?  メ ・
01279     case KBD_jp_ro:         ret=0x33;break;     //    _  ロ
01280     case KBD_space:         ret=0x34;break;     // SPACEBAR
01281     case KBD_xfer:          ret=0x35;break;     // XFER
01282     case KBD_pageup:        ret=0x36;break;     // ROLL UP
01283     case KBD_pagedown:      ret=0x37;break;     // ROLL DOWN
01284     case KBD_insert:        ret=0x38;break;     // INS
01285     case KBD_delete:        ret=0x39;break;     // DEL
01286     case KBD_up:            ret=0x3A;break;     // UP ARROW
01287     case KBD_left:          ret=0x3B;break;     // LEFT ARROW
01288     case KBD_right:         ret=0x3C;break;     // RIGHT ARROW
01289     case KBD_down:          ret=0x3D;break;     // DOWN ARROW
01290     case KBD_home:          ret=0x3E;break;     // HOME / CLR
01291     case KBD_help:          ret=0x3F;break;     // HELP
01292     case KBD_kpminus:       ret=0x40;break;     // - (KEYPAD)
01293     case KBD_kpdivide:      ret=0x41;break;     // / (KEYPAD)
01294     case KBD_kp7:           ret=0x42;break;     // 7 (KEYPAD)
01295     case KBD_kp8:           ret=0x43;break;     // 8 (KEYPAD)
01296     case KBD_kp9:           ret=0x44;break;     // 9 (KEYPAD)
01297     case KBD_kpmultiply:    ret=0x45;break;     // * (KEYPAD)
01298     case KBD_kp4:           ret=0x46;break;     // 4 (KEYPAD)
01299     case KBD_kp5:           ret=0x47;break;     // 5 (KEYPAD)
01300     case KBD_kp6:           ret=0x48;break;     // 6 (KEYPAD)
01301     case KBD_kpplus:        ret=0x49;break;     // + (KEYPAD)
01302     case KBD_kp1:           ret=0x4A;break;     // 1 (KEYPAD)
01303     case KBD_kp2:           ret=0x4B;break;     // 2 (KEYPAD)
01304     case KBD_kp3:           ret=0x4C;break;     // 3 (KEYPAD)
01305     case KBD_kpequals:      ret=0x4D;break;     // = (KEYPAD)
01306     case KBD_kp0:           ret=0x4E;break;     // 0 (KEYPAD)
01307     case KBD_kpcomma:       ret=0x4F;break;     // , (KEYPAD)
01308     case KBD_kpperiod:      ret=0x50;break;     // . (KEYPAD)
01309     case KBD_nfer:          ret=0x51;break;     // NFER
01310     case KBD_vf1:           ret=0x52;break;     // vf・1
01311     case KBD_vf2:           ret=0x53;break;     // vf・2
01312     case KBD_vf3:           ret=0x54;break;     // vf・3
01313     case KBD_vf4:           ret=0x55;break;     // vf・4
01314     case KBD_vf5:           ret=0x56;break;     // vf・5
01315     case KBD_stop:          ret=0x60;break;     // STOP
01316     case KBD_copy:          ret=0x61;break;     // COPY
01317     case KBD_f1:            ret=0x62;break;     // f・1
01318     case KBD_f2:            ret=0x63;break;     // f・2
01319     case KBD_f3:            ret=0x64;break;     // f・3
01320     case KBD_f4:            ret=0x65;break;     // f・4
01321     case KBD_f5:            ret=0x66;break;     // f・5
01322     case KBD_f6:            ret=0x67;break;     // f・6
01323     case KBD_f7:            ret=0x68;break;     // f・7
01324     case KBD_f8:            ret=0x69;break;     // f・8
01325     case KBD_f9:            ret=0x6A;break;     // f・9
01326     case KBD_f10:           ret=0x6B;break;     // f・10
01327     case KBD_leftshift:     ret=0x70;break;     // SHIFT
01328     case KBD_rightshift:    ret=0x70;break;     // SHIFT
01329     case KBD_leftalt:       ret=0x73;break;     // GRPH (handled by Windows as if ALT key)
01330     case KBD_rightalt:      ret=0x73;break;     // GRPH (handled by Windows as if ALT key)
01331     case KBD_leftctrl:      ret=0x74;break;     // CTRL
01332     case KBD_rightctrl:     ret=0x74;break;     // CTRL
01333     case KBD_grave:
01334         if(pc98_force_ibm_layout)
01335             ret=0x1A; //HACK, reuse @ key
01336         break;
01337     
01338     case KBD_capslock:                          // CAPS
01339         if (pressed) {                          // sends only on keypress, does not resend if held down
01340             pc98_caps_toggle();
01341             pc98_keyboard_send(0x71 | (!pc98_caps() ? 0x80 : 0x00)); // make code if caps switched on, break if caps switched off
01342         }
01343         return;
01344 
01345     case KBD_numlock:                           // NUM
01346         pc98_numlock_toggle();
01347         return;
01348 
01349     case KBD_kana:                              // KANA
01350         if (pressed) {                          // sends only on keypress, does not resend if held down
01351             pc98_kana_toggle();
01352             pc98_keyboard_send(0x72 | (!pc98_kana() ? 0x80 : 0x00)); // make code if caps switched on, break if caps switched off
01353         }
01354         return;
01355 
01356     default: return;
01357     }
01358 
01359     /* PC-98 keyboards appear to repeat make/break codes when the key is held down */
01360     if (pressed && keyb.repeat.key == keytype)
01361         pc98_keyboard_send(ret | 0x80);
01362 
01363     /* Add the actual key in the keyboard queue */
01364     if (pressed) {
01365         if (keyb.repeat.key == keytype) keyb.repeat.wait = keyb.repeat.rate;        
01366         else keyb.repeat.wait = keyb.repeat.pause;
01367         keyb.repeat.key = keytype;
01368     } else {
01369         if (keyb.repeat.key == keytype) {
01370             /* repeated key being released */
01371             keyb.repeat.key  = KBD_NONE;
01372             keyb.repeat.wait = 0;
01373         }
01374     }
01375 
01376     if (!pressed) ret |= 0x80;
01377 
01378     pc98_keyboard_send(ret | (!pressed ? 0x80 : 0x00));
01379 }
01380 
01381 void KEYBOARD_AddKey1(KBD_KEYS keytype,bool pressed) {
01382     Bit8u ret=0,ret2=0;bool extend=false;
01383 
01384     if (keyb.reset)
01385         return;
01386 
01387     /* if the keyboard is disabled, then store the keystroke but don't transmit yet */
01388     /*if (!keyb.active || !keyb.scanning) {
01389         keyb.pending_key = keytype;
01390         keyb.pending_key_state = pressed;
01391         return;
01392     }*/
01393 
01394     switch (keytype) {
01395     case KBD_kor_hancha:
01396         keyb.repeat.key=KBD_NONE;
01397         keyb.repeat.wait=0;
01398         if (!pressed) return;
01399         KEYBOARD_AddBuffer(0xF1);
01400         break;
01401     case KBD_kor_hanyong:
01402         keyb.repeat.key=KBD_NONE;
01403         keyb.repeat.wait=0;
01404         if (!pressed) return;
01405         KEYBOARD_AddBuffer(0xF2);
01406         break;
01407     case KBD_esc:ret=1;break;
01408     case KBD_1:ret=2;break;
01409     case KBD_2:ret=3;break;
01410     case KBD_3:ret=4;break;     
01411     case KBD_4:ret=5;break;
01412     case KBD_5:ret=6;break;
01413     case KBD_6:ret=7;break;     
01414     case KBD_7:ret=8;break;
01415     case KBD_8:ret=9;break;
01416     case KBD_9:ret=10;break;        
01417     case KBD_0:ret=11;break;
01418 
01419     case KBD_minus:ret=12;break;
01420     case KBD_equals:ret=13;break;
01421     case KBD_kpequals:ret=0x59;break; /* According to Battler */
01422     case KBD_backspace:ret=14;break;
01423     case KBD_tab:ret=15;break;
01424 
01425     case KBD_q:ret=16;break;        
01426     case KBD_w:ret=17;break;
01427     case KBD_e:ret=18;break;        
01428     case KBD_r:ret=19;break;
01429     case KBD_t:ret=20;break;        
01430     case KBD_y:ret=21;break;
01431     case KBD_u:ret=22;break;        
01432     case KBD_i:ret=23;break;
01433     case KBD_o:ret=24;break;        
01434     case KBD_p:ret=25;break;
01435 
01436     case KBD_leftbracket:ret=26;break;
01437     case KBD_rightbracket:ret=27;break;
01438     case KBD_enter:ret=28;break;
01439     case KBD_leftctrl:
01440         ret=29;
01441         keyb.leftctrl_pressed=pressed;
01442         break;
01443 
01444     case KBD_a:ret=30;break;
01445     case KBD_s:ret=31;break;
01446     case KBD_d:ret=32;break;
01447     case KBD_f:ret=33;break;
01448     case KBD_g:ret=34;break;        
01449     case KBD_h:ret=35;break;        
01450     case KBD_j:ret=36;break;
01451     case KBD_k:ret=37;break;        
01452     case KBD_l:ret=38;break;
01453 
01454     case KBD_semicolon:ret=39;break;
01455     case KBD_quote:ret=40;break;
01456     case KBD_jp_hankaku:ret=41;break;
01457     case KBD_grave:ret=41;break;
01458     case KBD_leftshift:ret=42;break;
01459     case KBD_backslash:ret=43;break;
01460     case KBD_z:ret=44;break;
01461     case KBD_x:ret=45;break;
01462     case KBD_c:ret=46;break;
01463     case KBD_v:ret=47;break;
01464     case KBD_b:ret=48;break;
01465     case KBD_n:ret=49;break;
01466     case KBD_m:ret=50;break;
01467 
01468     case KBD_comma:ret=51;break;
01469     case KBD_period:ret=52;break;
01470     case KBD_slash:ret=53;break;
01471     case KBD_rightshift:ret=54;break;
01472     case KBD_kpmultiply:ret=55;break;
01473     case KBD_leftalt:ret=56;break;
01474     case KBD_space:ret=57;break;
01475     case KBD_capslock:ret=58;break;
01476 
01477     case KBD_f1:ret=59;break;
01478     case KBD_f2:ret=60;break;
01479     case KBD_f3:ret=61;break;
01480     case KBD_f4:ret=62;break;
01481     case KBD_f5:ret=63;break;
01482     case KBD_f6:ret=64;break;
01483     case KBD_f7:ret=65;break;
01484     case KBD_f8:ret=66;break;
01485     case KBD_f9:ret=67;break;
01486     case KBD_f10:ret=68;break;
01487     case KBD_f11:ret=87;break;
01488     case KBD_f12:ret=88;break;
01489 
01490     /* IBM F13-F24 apparently map to Shift + F1-F12 */
01491     case KBD_f13:ret=0x2A;ret2=59;break;
01492     case KBD_f14:ret=0x2A;ret2=60;break;
01493     case KBD_f15:ret=0x2A;ret2=61;break;
01494     case KBD_f16:ret=0x2A;ret2=62;break;
01495     case KBD_f17:ret=0x2A;ret2=63;break;
01496     case KBD_f18:ret=0x2A;ret2=64;break;
01497     case KBD_f19:ret=0x2A;ret2=65;break;
01498     case KBD_f20:ret=0x2A;ret2=66;break;
01499     case KBD_f21:ret=0x2A;ret2=67;break;
01500     case KBD_f22:ret=0x2A;ret2=68;break;
01501     case KBD_f23:ret=0x2A;ret2=87;break;
01502     case KBD_f24:ret=0x2A;ret2=88;break;
01503 
01504     case KBD_numlock:ret=69;break;
01505     case KBD_scrolllock:ret=70;break;
01506 
01507     case KBD_kp7:ret=71;break;
01508     case KBD_kp8:ret=72;break;
01509     case KBD_kp9:ret=73;break;
01510     case KBD_kpminus:ret=74;break;
01511     case KBD_kp4:ret=75;break;
01512     case KBD_kp5:ret=76;break;
01513     case KBD_kp6:ret=77;break;
01514     case KBD_kpplus:ret=78;break;
01515     case KBD_kp1:ret=79;break;
01516     case KBD_kp2:ret=80;break;
01517     case KBD_kp3:ret=81;break;
01518     case KBD_kp0:ret=82;break;
01519     case KBD_kpperiod:ret=83;break;
01520 
01521     case KBD_extra_lt_gt:ret=86;break;
01522 
01523     //The Extended keys
01524 
01525     case KBD_kpenter:extend=true;ret=28;break;
01526     case KBD_rightctrl:
01527         extend=true;ret=29;
01528         keyb.rightctrl_pressed=pressed;
01529         break;
01530     case KBD_kpdivide:extend=true;ret=53;break;
01531     case KBD_rightalt:extend=true;ret=56;break;
01532     case KBD_home:extend=true;ret=71;break;
01533     case KBD_up:extend=true;ret=72;break;
01534     case KBD_pageup:extend=true;ret=73;break;
01535     case KBD_left:extend=true;ret=75;break;
01536     case KBD_right:extend=true;ret=77;break;
01537     case KBD_end:extend=true;ret=79;break;
01538     case KBD_down:extend=true;ret=80;break;
01539     case KBD_pagedown:extend=true;ret=81;break;
01540     case KBD_insert:extend=true;ret=82;break;
01541     case KBD_delete:extend=true;ret=83;break;
01542     case KBD_pause:
01543         if (!pressed) {
01544             /* keyboards send both make&break codes for this key on
01545                key press and nothing on key release */
01546             return;
01547         }
01548         if (!keyb.leftctrl_pressed && !keyb.rightctrl_pressed) {
01549             /* neither leftctrl, nor rightctrl pressed -> PAUSE key */
01550             KEYBOARD_AddBuffer(0xe1);
01551             KEYBOARD_AddBuffer(29);
01552             KEYBOARD_AddBuffer(69);
01553             KEYBOARD_AddBuffer(0xe1);
01554             KEYBOARD_AddBuffer(29|0x80);
01555             KEYBOARD_AddBuffer(69|0x80);
01556         } else if (!keyb.leftctrl_pressed || !keyb.rightctrl_pressed) {
01557             /* exactly one of [leftctrl, rightctrl] is pressed -> Ctrl+BREAK */
01558             KEYBOARD_AddBuffer(0xe0);
01559             KEYBOARD_AddBuffer(70);
01560             KEYBOARD_AddBuffer(0xe0);
01561             KEYBOARD_AddBuffer(70|0x80);
01562         }
01563         /* pressing this key also disables any previous key repeat */
01564         keyb.repeat.key=KBD_NONE;
01565         keyb.repeat.wait=0;
01566         return;
01567     case KBD_printscreen:
01568         /* NTS: Check previous assertion that the Print Screen sent these bytes in
01569          *      one order when pressed and reverse order when released. Or perhaps
01570          *      that's only what some keyboards do. --J.C. */
01571         KEYBOARD_AddBuffer(0xe0);
01572         KEYBOARD_AddBuffer(0x2a | (pressed ? 0 : 0x80)); /* 0x2a == 42 */
01573         KEYBOARD_AddBuffer(0xe0);
01574         KEYBOARD_AddBuffer(0x37 | (pressed ? 0 : 0x80)); /* 0x37 == 55 */
01575         /* pressing this key also disables any previous key repeat */
01576         keyb.repeat.key = KBD_NONE;
01577         keyb.repeat.wait = 0;
01578         return;
01579     case KBD_lwindows:extend=true;ret=0x5B;break;
01580     case KBD_rwindows:extend=true;ret=0x5C;break;
01581     case KBD_rwinmenu:extend=true;ret=0x5D;break;
01582     case KBD_jp_muhenkan:ret=0x7B;break;
01583     case KBD_jp_henkan:ret=0x79;break;
01584     case KBD_jp_hiragana:ret=0x70;break;/*also Katakana */
01585     case KBD_jp_backslash:ret=0x73;break;/*JP 106-key: _ \ or ろ (ro)  <-- WARNING: UTF-8 unicode */
01586     case KBD_jp_yen:ret=0x7d;break;/*JP 106-key: | ¥ (yen) or ー (prolonged sound mark)  <-- WARNING: UTF-8 unicode */
01587     default:
01588         LOG(LOG_MISC, LOG_WARN)("Unsupported key press %lu", (unsigned long)keytype);
01589         return;
01590     }
01591 
01592     /* Add the actual key in the keyboard queue */
01593     if (pressed) {
01594         if (keyb.repeat.key == keytype) keyb.repeat.wait = keyb.repeat.rate;        
01595         else keyb.repeat.wait = keyb.repeat.pause;
01596         keyb.repeat.key = keytype;
01597     } else {
01598         if (keyb.repeat.key == keytype) {
01599             /* repeated key being released */
01600             keyb.repeat.key  = KBD_NONE;
01601             keyb.repeat.wait = 0;
01602         }
01603 
01604         if (keytype >= KBD_f13 && keytype <= KBD_f24) {
01605             unsigned int t = ret;
01606             ret = ret2;
01607             ret2 = t;
01608         }
01609 
01610         ret += 128;
01611         if (ret2 != 0) ret2 += 128;
01612     }
01613     if (extend) KEYBOARD_AddBuffer(0xe0);
01614     KEYBOARD_AddBuffer(ret);
01615     if (ret2 != 0) {
01616         if (extend) KEYBOARD_AddBuffer(0xe0); 
01617         KEYBOARD_AddBuffer(ret2);
01618     }
01619 }
01620 
01621 static void KEYBOARD_TickHandler(void) {
01622     if (keyb.reset)
01623         return;
01624 
01625     if (keyb.active && keyb.scanning) {
01626         if (keyb.pending_key >= 0) {
01627             KEYBOARD_AddKey((KBD_KEYS)keyb.pending_key,keyb.pending_key_state);
01628             keyb.pending_key = -1;
01629         }
01630         else if (keyb.repeat.wait) {
01631             keyb.repeat.wait--;
01632             if (!keyb.repeat.wait) KEYBOARD_AddKey(keyb.repeat.key,true);
01633         }
01634     }
01635 }
01636 
01637 void KEYBOARD_AddKey(KBD_KEYS keytype,bool pressed) {
01638     if (IS_PC98_ARCH) {
01639         KEYBOARD_PC98_AddKey(keytype,pressed);
01640     }
01641     else if (keyb.cb_xlat) {
01642         /* emulate typical setup where keyboard generates scan set 2 and controller translates to scan set 1 */
01643         /* yeah I know... yuck */
01644         KEYBOARD_AddKey1(keytype,pressed);
01645     }
01646     else {
01647         switch (keyb.scanset) {
01648             case 1: KEYBOARD_AddKey1(keytype,pressed); break;
01649             case 2: KEYBOARD_AddKey2(keytype,pressed); break;
01650             case 3: KEYBOARD_AddKey3(keytype,pressed); break;
01651         }
01652     }
01653 }
01654     
01655 static void KEYBOARD_ShutDown(Section * sec) {
01656     (void)sec;//UNUSED
01657     TIMER_DelTickHandler(&KEYBOARD_TickHandler);
01658 }
01659 
01660 bool KEYBOARD_Report_BIOS_PS2Mouse() {
01661     return keyb.enable_aux && (keyb.ps2mouse.type != MOUSE_NONE);
01662 }
01663 
01664 static IO_ReadHandleObject ReadHandler_8255_PC98[4];
01665 static IO_WriteHandleObject WriteHandler_8255_PC98[4];
01666 
01667 static IO_ReadHandleObject ReadHandler_8255prn_PC98[4];
01668 static IO_WriteHandleObject WriteHandler_8255prn_PC98[4];
01669 
01670 static IO_WriteHandleObject Reset_PC98;
01671 
01672 extern bool gdc_5mhz_mode;
01673 extern bool gdc_5mhz_mode_initial;
01674 
01697 class PC98_Printer_8255 : public Intel8255 {
01698 public:
01699     PC98_Printer_8255() : Intel8255() {
01700         ppiName = "Printer 8255";
01701         portNames[PortA] = "Printer output";
01702         portNames[PortB] = "System configuration";
01703         portNames[PortC] = "Strobe and controls";
01704         pinNames[PortA][0] = "Latch bit 0";
01705         pinNames[PortA][1] = "Latch bit 1";
01706         pinNames[PortA][2] = "Latch bit 2";
01707         pinNames[PortA][3] = "Latch bit 3";
01708         pinNames[PortA][4] = "Latch bit 4";
01709         pinNames[PortA][5] = "Latch bit 5";
01710         pinNames[PortA][6] = "Latch bit 6";
01711         pinNames[PortA][7] = "Latch bit 7";
01712         pinNames[PortB][0] = "VF VF flag";
01713         pinNames[PortB][1] = "CPUT operation CPU (V30 if set)";
01714         pinNames[PortB][2] = "Printer busy signal";
01715         pinNames[PortB][3] = "HGC graphics extension function DIP SW 1-8";
01716         pinNames[PortB][4] = "LCD plasma display usage condition DIP SW 1-3";
01717         pinNames[PortB][5] = "System clock (5/10mhz or 8mhz)";
01718         pinNames[PortB][6] = "System type, bit 0";
01719         pinNames[PortB][7] = "System type, bit 1";
01720         pinNames[PortC][0] = "unused";
01721         pinNames[PortC][1] = "Reset 287/387 by CPU reset if set";
01722         pinNames[PortC][2] = "unused";
01723         pinNames[PortC][3] = "IR8 interrupt request ON/OFF";
01724         pinNames[PortC][4] = "unused";
01725         pinNames[PortC][5] = "unused";
01726         pinNames[PortC][6] = "unused";
01727         pinNames[PortC][7] = "Printer strobe output";
01728     }
01729     virtual ~PC98_Printer_8255() {
01730     }
01731 public:
01732     /* TODO: Writes to Port A should go to printer emulation */
01733     /* TODO: Writes to bit 7, Port C should go to printer emulation (strobe pin) */
01734     /* port B is input */
01735     virtual uint8_t inPortB(void) const {
01736         return      0x80 +                                                          /* bits [7:6]   10 = other model */
01737                     ((PIT_TICK_RATE == PIT_TICK_RATE_PC98_8MHZ) ? 0x20 : 0x00) +    /* bit  [5:5]   1 = 8MHz  0 = 5/10MHz */
01738                     0x10 +                                                          /* bit  [4:4]   1 = LCD plasma display usage cond. not used */
01739                     0x04;                                                           /* bit  [2:2]   printer busy signal (1=inactive) */
01740         /* NTS: also returns:
01741          *       bit  [3:3]     0 = HGC graphics extension function extended mode
01742          *       bit  [1:1]     0 = 80x86 processor (not V30)
01743          *       bit  [0:0]     0 = other models (?) */
01744     }
01745 };
01746 
01747 static PC98_Printer_8255 pc98_prn_8255;
01748 
01749 bool PC98_SHUT0=true,PC98_SHUT1=true;
01750 
01789 class PC98_System_8255 : public Intel8255 {
01790 public:
01791     PC98_System_8255() : Intel8255() {
01792         ppiName = "System 8255";
01793         portNames[PortA] = "DIP switches 2-1 through 2-8";
01794         portNames[PortB] = "Various system status";
01795         portNames[PortC] = "System control bits";
01796         pinNames[PortA][0] = "DIP switch 2-1";
01797         pinNames[PortA][1] = "DIP switch 2-2";
01798         pinNames[PortA][2] = "DIP switch 2-3";
01799         pinNames[PortA][3] = "DIP switch 2-4";
01800         pinNames[PortA][4] = "DIP switch 2-5";
01801         pinNames[PortA][5] = "DIP switch 2-6";
01802         pinNames[PortA][6] = "DIP switch 2-7";
01803         pinNames[PortA][7] = "DIP switch 2-8";
01804         pinNames[PortB][0] = "Read data of calendar clock (CDAT)";
01805         pinNames[PortB][1] = "Expansion RAM parity error (EMCK)";
01806         pinNames[PortB][2] = "Internal RAM parity error (IMCK)";
01807         pinNames[PortB][3] = "DIP switch 1-1 High resolution CRT type";
01808         pinNames[PortB][4] = "Expansion bus INT 3 signal";
01809         pinNames[PortB][5] = "RS-232C CD signal";
01810         pinNames[PortB][6] = "RS-232C CS signal";
01811         pinNames[PortB][7] = "RS-232C CI signal";
01812         pinNames[PortC][0] = "RS-232C enable RXRDY interrupt";
01813         pinNames[PortC][1] = "RS-232C enable TXEMPTY interrupt";
01814         pinNames[PortC][2] = "RS-232C enable TXRDY interrupt";
01815         pinNames[PortC][3] = "Buzzer inhibit";
01816         pinNames[PortC][4] = "RAM parity check enable";
01817         pinNames[PortC][5] = "Shutdown flag 1"; /* <- 286 or later */
01818         pinNames[PortC][6] = "PSTB printer signal inhibit (mask if set)";
01819         pinNames[PortC][7] = "Shutdown flag 0"; /* <- 286 or later */
01820     }
01821     virtual ~PC98_System_8255() {
01822     }
01823 public:
01824     /* port A is input */
01825     virtual uint8_t inPortA(void) const {
01826         /* TODO: Improve this! What do the various 2-1 to 2-8 switches do?
01827          *       It might help to look at the BIOS setup menus of 1990s PC-98 systems
01828          *       that offer toggling virtual versions of these DIP switches to see
01829          *       what the BIOS menu text says. */
01830         /* NTS: Return the INITIAL setting of the GDC. Guest applications (like Windows 3.1)
01831          *      can and will change it later. This must reflect the initial setting as if
01832          *      what the BIOS had initially intended. */
01833         return 0x63 | (gdc_5mhz_mode_initial ? 0x00 : 0x80); // taken from a PC-9821 Lt2
01834     }
01835     /* port B is input */
01836     virtual uint8_t inPortB(void) const {
01837         /* TODO: Improve this! */
01838         return 0xF9; // taken from a PC-9821 Lt2
01839     }
01840     /* port C is output (both halves) */
01841     virtual void outPortC(const uint8_t mask) {
01842         if (mask & 0x80) /* Shutdown flag 0 */
01843             PC98_SHUT0 = !!(latchOutPortC & 0x80);
01844 
01845         if (mask & 0x20) /* Shutdown flag 1 */
01846             PC98_SHUT1 = !!(latchOutPortC & 0x20);
01847 
01848         if (mask & 0x08) { /* PC speaker aka "buzzer". Note this bit is an inhibit, set to zero to turn on */
01849             port_61_data = (latchOutPortC & 0x08) ? 0 : 3;
01850             TIMER_SetGate2(!!port_61_data);
01851             PCSPEAKER_SetType(!!port_61_data,!!port_61_data);
01852         }
01853     }
01854 };
01855 
01856 static PC98_System_8255 pc98_sys_8255;
01857 
01858 static void pc98_reset_write(Bitu port,Bitu val,Bitu /*iolen*/) {
01859     (void)port;//UNUSED
01860     LOG_MSG("Restart by port F0h requested: val=%02x SHUT0=%u SHUT1=%u\n",(unsigned int)val,PC98_SHUT0,PC98_SHUT1);
01861     On_Software_CPU_Reset();
01862 }
01863 
01864 static void pc98_8255_write(Bitu port,Bitu val,Bitu /*iolen*/) {
01865     /* 0x31-0x37 odd */
01866     pc98_sys_8255.writeByPort((port - 0x31) >> 1U,val);
01867 }
01868 
01869 static Bitu pc98_8255_read(Bitu port,Bitu /*iolen*/) {
01870     /* 0x31-0x37 odd */
01871     return pc98_sys_8255.readByPort((port - 0x31) >> 1U);
01872 }
01873 
01874 static void pc98_8255prn_write(Bitu port,Bitu val,Bitu /*iolen*/) {
01875     /* 0x31-0x37 odd */
01876     pc98_prn_8255.writeByPort((port - 0x40) >> 1U,val);
01877 }
01878 
01879 static Bitu pc98_8255prn_read(Bitu port,Bitu /*iolen*/) {
01880     /* 0x31-0x37 odd */
01881     return pc98_prn_8255.readByPort((port - 0x40) >> 1U);
01882 }
01883 
01884 static struct pc98_keyboard {
01885     pc98_keyboard() : caps(false), kana(false), num(false) {
01886     }
01887 
01888     bool                        caps;
01889     bool                        kana;
01890     bool                        num;
01891 } pc98_keyboard_state;
01892 
01893 bool pc98_caps(void) {
01894     return pc98_keyboard_state.caps;
01895 }
01896 
01897 bool pc98_kana(void) {
01898     return pc98_keyboard_state.kana;
01899 }
01900 
01901 void pc98_caps_toggle(void) {
01902     pc98_keyboard_state.caps = !pc98_keyboard_state.caps;
01903 }
01904 
01905 void pc98_kana_toggle(void) {
01906     pc98_keyboard_state.kana = !pc98_keyboard_state.kana;
01907 }
01908 
01909 void pc98_numlock_toggle(void) {
01910     pc98_keyboard_state.num = !pc98_keyboard_state.num;
01911 }
01912 
01913 void uart_rx_load(Bitu val);
01914 void uart_tx_load(Bitu val);
01915 void pc98_keyboard_recv_byte(Bitu val);
01916 
01917 static struct pc98_8251_keyboard_uart {
01918     enum cmdreg_state {
01919         MODE_STATE=0,
01920         SYNC_CHAR1,
01921         SYNC_CHAR2,
01922         COMMAND_STATE
01923     };
01924 
01925     unsigned char               data;
01926     unsigned char               txdata;
01927     enum cmdreg_state           state;
01928     unsigned char               mode_byte;
01929     bool                        keyboard_reset;
01930     bool                        rx_enable;
01931     bool                        tx_enable;
01932     bool                        valid_state;
01933 
01934     bool                        rx_busy;
01935     bool                        rx_ready;
01936     bool                        tx_busy;
01937     bool                        tx_empty;
01938 
01939     /* io_delay in milliseconds for use with PIC delay code */
01940     double                      io_delay_ms;
01941     double                      tx_load_ms;
01942 
01943     /* recv data from keyboard */
01944     unsigned char               recv_buffer[32] = {};
01945     unsigned char               recv_in,recv_out;
01946 
01947     pc98_8251_keyboard_uart() : data(0xFF), txdata(0xFF), state(MODE_STATE), mode_byte(0), keyboard_reset(false), rx_enable(false), tx_enable(false), valid_state(false), rx_busy(false), rx_ready(false), tx_busy(false), tx_empty(true), recv_in(0), recv_out(0) {
01948         io_delay_ms = (((1/*start*/+8/*data*/+1/*parity*/+1/*stop*/) * 1000.0) / 19200);
01949         tx_load_ms = (((1/*start*/+8/*data*/) * 1000.0) / 19200);
01950     }
01951 
01952     void reset(void) {
01953         PIC_RemoveEvents(uart_tx_load);
01954         PIC_RemoveEvents(uart_rx_load);
01955         PIC_RemoveEvents(pc98_keyboard_recv_byte);
01956 
01957         state = MODE_STATE;
01958         rx_busy = false;
01959         rx_ready = false;
01960         tx_empty = true;
01961         tx_busy = false;
01962         mode_byte = 0;
01963         recv_out = 0;
01964         recv_in = 0;
01965     }
01966 
01967     void device_send_data(unsigned char b) {
01968         unsigned char nidx;
01969 
01970         nidx = (recv_in + 1) % 32;
01971         if (nidx == recv_out) {
01972             LOG_MSG("8251 device send recv overrun");
01973         }
01974         else {
01975             recv_buffer[recv_in] = b;
01976             recv_in = nidx;
01977         }
01978 
01979         if (!rx_busy) {
01980             rx_busy = true;
01981             PIC_AddEvent(uart_rx_load,io_delay_ms,0);
01982         }
01983     }
01984 
01985     unsigned char read_data(void) {
01986         rx_ready = false;
01987         if (recv_in != recv_out && !rx_busy) {
01988             rx_busy = true;
01989             PIC_AddEvent(uart_rx_load,io_delay_ms,0);
01990         }
01991         return data;
01992     }
01993 
01994     void write_data(unsigned char b) {
01995         if (!valid_state)
01996             return;
01997 
01998         if (!tx_busy) {
01999             txdata = b;
02000             tx_busy = true;
02001 
02002             PIC_AddEvent(uart_tx_load,tx_load_ms,0);
02003             PIC_AddEvent(pc98_keyboard_recv_byte,io_delay_ms,txdata);
02004         }
02005     }
02006 
02007     void tx_load_complete(void) {
02008         tx_busy = false;
02009     }
02010 
02011     void rx_load_complete(void) {
02012         if (!rx_ready) {
02013             rx_ready = true;
02014             data = recv_buffer[recv_out];
02015             recv_out = (recv_out + 1) % 32;
02016 
02017 //            LOG_MSG("8251 recv %02X",data);
02018             PIC_ActivateIRQ(1);
02019 
02020             if (recv_out != recv_in) {
02021                 PIC_AddEvent(uart_rx_load,io_delay_ms,0);
02022                 rx_busy = true;
02023             }
02024             else {
02025                 rx_busy = false;
02026             }
02027         }
02028         else {
02029             LOG_MSG("8251 warning: RX overrun");
02030             rx_busy = false;
02031         }
02032     }
02033 
02034     void xmit_finish(void) {
02035         tx_empty = true;
02036         tx_busy = false;
02037     }
02038 
02039     unsigned char read_status(void) {
02040         unsigned char r = 0;
02041 
02042         /* bit[7:7] = DSR (1=DSR at zero level)
02043          * bit[6:6] = syndet/brkdet
02044          * bit[5:5] = framing error
02045          * bit[4:4] = overrun error
02046          * bit[3:3] = parity error
02047          * bit[2:2] = TxEMPTY
02048          * bit[1:1] = RxRDY
02049          * bit[0:0] = TxRDY */
02050         r |= (!tx_busy ? 0x01 : 0x00) |
02051              (rx_ready ? 0x02 : 0x00) |
02052              (tx_empty ? 0x04 : 0x00);
02053 
02054         return r;
02055     }
02056 
02057     void writecmd(const unsigned char b) { /* write to command register */
02058         if (state == MODE_STATE) {
02059             mode_byte = b;
02060 
02061             if ((b&3) != 0) {
02062                 /* bit[7:6] = number of stop bits  (0=invalid 1=1-bit 2=1.5-bit 3=2-bit)
02063                  * bit[5:5] = even/odd parity      (1=even 0=odd)
02064                  * bit[4:4] = parity enable        (1=enable 0=disable)
02065                  * bit[3:2] = character length     (0=5  1=6  2=7  3=8)
02066                  * bit[1:0] = baud rate factor     (0=sync mode   1=1X   2=16X   3=64X)
02067                  *
02068                  * note that "baud rate factor" means how much to divide the baud rate clock to determine
02069                  * the bit rate that bits are transmitted. Typical PC-98 programming practice is to set
02070                  * the baud rate clock fed to the chip at 16X the baud rate and then specify 16X baud rate factor. */
02071                 /* async mode */
02072                 state = COMMAND_STATE;
02073 
02074                 /* keyboard must operate at 19200 baud 8 bits odd parity 16X baud rate factor */
02075                 valid_state = (b == 0x5E); /* bit[7:0] = 01 0 1 11 10 */
02076                                            /*            |  | | |  |  */
02077                                            /*            |  | | |  +---- 16X baud rate factor */
02078                                            /*            |  | | +------- 8 bits per character */
02079                                            /*            |  | +--------- parity enable */
02080                                            /*            |  +----------- odd parity */
02081                                            /*            +-------------- 1 stop bit */
02082             }
02083             else {
02084                 /* bit[7:7] = single character sync(1=single  0=double)
02085                  * bit[6:6] = external sync detect (1=syndet is an input   0=syndet is an output)
02086                  * bit[5:5] = even/odd parity      (1=even 0=odd)
02087                  * bit[4:4] = parity enable        (1=enable 0=disable)
02088                  * bit[3:2] = character length     (0=5  1=6  2=7  3=8)
02089                  * bit[1:0] = baud rate factor     (0=sync mode)
02090                  *
02091                  * I don't think anything uses the keyboard in this manner, therefore, not supported in this emulation. */
02092                 LOG_MSG("8251 keyboard warning: Mode byte synchronous mode not supported");
02093                 state = SYNC_CHAR1;
02094                 valid_state = false;
02095             }
02096         }
02097         else if (state == COMMAND_STATE) {
02098             /* bit[7:7] = Enter hunt mode (not used here)
02099              * bit[6:6] = internal reset (8251 resets, prepares to accept mode byte)
02100              * bit[5:5] = RTS inhibit (1=force RTS to zero, else RTS reflects RxRDY state of the chip)
02101              * bit[4:4] = error reset
02102              * bit[3:3] = send break character (0=normal  1=force TxD low). On PC-98 keyboard this is wired to reset pin of the keyboard CPU.
02103              * bit[2:2] = receive enable
02104              * bit[1:1] = DTR inhibit (1=force DTR to zero). Connected to PC-98 RTY pin.
02105              * bit[0:0] = transmit enable */
02106             if (b & 0x40) {
02107                 /* internal reset, returns 8251 to mode state */
02108                 state = MODE_STATE;
02109             }
02110 
02111             /* TODO: Does the 8251 take any other bits if bit 6 was set to reset the 8251? */
02112             keyboard_reset = !!(b & 0x08);
02113             rx_enable = !!(b & 0x04);
02114             tx_enable = !!(b & 0x01);
02115         }
02116     }
02117 } pc98_8251_keyboard_uart_state;
02118 
02119 void uart_tx_load(Bitu val) {
02120     (void)val;//UNUSED
02121     pc98_8251_keyboard_uart_state.tx_load_complete();
02122 }
02123 
02124 void uart_rx_load(Bitu val) {
02125     (void)val;//UNUSED
02126     pc98_8251_keyboard_uart_state.rx_load_complete();
02127 }
02128 
02129 void pc98_keyboard_send(const unsigned char b) {
02130     pc98_8251_keyboard_uart_state.device_send_data(b);
02131 }
02132 
02133 void pc98_keyboard_recv_byte(Bitu val) {
02134     pc98_8251_keyboard_uart_state.xmit_finish();
02135     LOG_MSG("PC-98 recv 0x%02x",(unsigned int)val);
02136 }
02137 
02138 static Bitu keyboard_pc98_8251_uart_41_read(Bitu port,Bitu /*iolen*/) {
02139     (void)port;//UNUSED
02140     return pc98_8251_keyboard_uart_state.read_data();
02141 }
02142 
02143 static void keyboard_pc98_8251_uart_41_write(Bitu port,Bitu val,Bitu /*iolen*/) {
02144     (void)port;//UNUSED
02145     pc98_8251_keyboard_uart_state.write_data((unsigned char)val);
02146 }
02147 
02148 static Bitu keyboard_pc98_8251_uart_43_read(Bitu port,Bitu /*iolen*/) {
02149     (void)port;//UNUSED
02150     return pc98_8251_keyboard_uart_state.read_status();
02151 }
02152 
02153 static void keyboard_pc98_8251_uart_43_write(Bitu port,Bitu val,Bitu /*iolen*/) {
02154     (void)port;//UNUSED
02155     pc98_8251_keyboard_uart_state.writecmd((unsigned char)val);
02156 }
02157 
02158 /* called from INT 18h */
02159 void check_keyboard_fire_IRQ1(void) {
02160     if (pc98_8251_keyboard_uart_state.read_status() & 2/*RxRDY*/)
02161         PIC_ActivateIRQ(1);
02162 }
02163 
02164 int8_t p7fd9_8255_mouse_x = 0;
02165 int8_t p7fd9_8255_mouse_y = 0;
02166 int8_t p7fd9_8255_mouse_x_latch = 0;
02167 int8_t p7fd9_8255_mouse_y_latch = 0;
02168 uint8_t p7fd9_8255_mouse_sel = 0;
02169 uint8_t p7fd9_8255_mouse_latch = 0;
02170 uint8_t p7fd8_8255_mouse_int_enable = 0;
02171 
02172 void pc98_mouse_movement_apply(int x,int y) {
02173     x += p7fd9_8255_mouse_x; if (x < -128) x = -128; if (x > 127) x = 127;
02174     y += p7fd9_8255_mouse_y; if (y < -128) y = -128; if (y > 127) y = 127;
02175     p7fd9_8255_mouse_x = (int8_t)x;
02176     p7fd9_8255_mouse_y = (int8_t)y;
02177 }
02178 
02179 void MOUSE_DummyEvent(void);
02180 
02181 unsigned int pc98_mouse_rate_hz = 120;
02182 
02183 static double pc98_mouse_tick_interval_ms(void) {
02184     return 1000.0/*ms*/ / pc98_mouse_rate_hz;
02185 }
02186 
02187 static double pc98_mouse_time_to_next_tick_ms(void) {
02188     const double x = pc98_mouse_tick_interval_ms();
02189     return x - fmod(PIC_FullIndex(),x);
02190 }
02191 
02192 extern uint8_t MOUSE_IRQ;
02193 
02194 static bool pc98_mouse_tick_scheduled = false;
02195 
02196 static void pc98_mouse_tick_event(Bitu val) {
02197     (void)val;
02198 
02199     if (p7fd8_8255_mouse_int_enable) {
02200         /* Generate interrupt */
02201         PIC_ActivateIRQ(MOUSE_IRQ);
02202         /* keep the periodic interrupt going */
02203         PIC_AddEvent(pc98_mouse_tick_event,pc98_mouse_tick_interval_ms());
02204     }
02205     else
02206         pc98_mouse_tick_scheduled = false;
02207 }
02208 
02209 static void pc98_mouse_tick_schedule(void) {
02210     if (p7fd8_8255_mouse_int_enable) {
02211         if (!pc98_mouse_tick_scheduled) {
02212             pc98_mouse_tick_scheduled = true;
02213             PIC_AddEvent(pc98_mouse_tick_event,pc98_mouse_time_to_next_tick_ms());
02214         }
02215     }
02216     else {
02217         /* Don't unschedule the event, the game may un-inhibit the interrupt later.
02218          * The PIC event will not reschedule itself if inhibited at the time of the signal. */
02219     }
02220 }
02221 
02254 class PC98_Mouse_8255 : public Intel8255 {
02255 public:
02256     PC98_Mouse_8255() : Intel8255() {
02257         ppiName = "Mouse 8255";
02258         portNames[PortA] = "Mouse input";
02259         portNames[PortB] = "TODO";
02260         portNames[PortC] = "TODO";
02261         pinNames[PortA][0] = "MD0 (counter latch bit 0)";
02262         pinNames[PortA][1] = "MD1 (counter latch bit 1)";
02263         pinNames[PortA][2] = "MD2 (counter latch bit 2)";
02264         pinNames[PortA][3] = "MD3 (counter latch bit 3)";
02265         pinNames[PortA][4] = "?";
02266         pinNames[PortA][5] = "!Right mouse button";
02267         pinNames[PortA][6] = "!Middle mouse button";
02268         pinNames[PortA][7] = "!Left mouse button";
02269         pinNames[PortB][0] = "?";
02270         pinNames[PortB][1] = "?";
02271         pinNames[PortB][2] = "?";
02272         pinNames[PortB][3] = "?";
02273         pinNames[PortB][4] = "?";
02274         pinNames[PortB][5] = "?";
02275         pinNames[PortB][6] = "?";
02276         pinNames[PortB][7] = "?";
02277         pinNames[PortC][0] = "?";                               // read
02278         pinNames[PortC][1] = "?";                               // read
02279         pinNames[PortC][2] = "DIP SW 3-8 80286 select V30";     // read
02280         pinNames[PortC][3] = "?";                               // read
02281         pinNames[PortC][4] = "Mouse interrupt inhibit";         // write
02282         pinNames[PortC][5] = "SHL, Counter latch upper nibble"; // write
02283         pinNames[PortC][6] = "SXY, Counter latch Y (X if 0)";   // write
02284         pinNames[PortC][7] = "Counter latch and clear";         // write
02285     }
02286     virtual ~PC98_Mouse_8255() {
02287     }
02288 public:
02289     /* port A is input */
02290     virtual uint8_t inPortA(void) const {
02291         uint8_t bs;
02292         Bitu r;
02293 
02294         // bits [7:7] = !(LEFT BUTTON)
02295         // bits [6:6] = !(MIDDLE BUTTON)
02296         // bits [5:5] = !(RIGHT BUTTON)
02297         // bits [4:4] = 0 unused
02298         // bits [3:0] = 4 bit nibble latched via Port C
02299         bs = Mouse_GetButtonState();
02300         r = 0x00;
02301 
02302         if (!(bs & 1)) r |= 0x80;       // left button (inverted bit)
02303         if (!(bs & 2)) r |= 0x20;       // right button (inverted bit)
02304         if (!(bs & 4)) r |= 0x40;       // middle button (inverted bit)
02305 
02306         if (!p7fd9_8255_mouse_latch) {
02307             p7fd9_8255_mouse_x_latch = p7fd9_8255_mouse_x;
02308             p7fd9_8255_mouse_y_latch = p7fd9_8255_mouse_y;
02309         }
02310 
02311         switch (p7fd9_8255_mouse_sel) {
02312             case 0: // X delta
02313             case 1:
02314                 r |= (uint8_t)(p7fd9_8255_mouse_x_latch >> ((p7fd9_8255_mouse_sel & 1U) * 4U)) & 0xF; // sign extend is intentional
02315                 break;
02316             case 2: // Y delta
02317             case 3:
02318                 r |= (uint8_t)(p7fd9_8255_mouse_y_latch >> ((p7fd9_8255_mouse_sel & 1U) * 4U)) & 0xF; // sign extend is intentional
02319                 break;
02320         }
02321 
02322         return r;
02323     }
02324     /* port B is input */
02325     virtual uint8_t inPortB(void) const {
02326         /* TODO */
02327         return 0x00;
02328     }
02329     /* port C is input[3:0] and output[7:4] */
02330     virtual uint8_t inPortC(void) const {
02331         /* TODO */
02332         return 0x00;
02333     }
02334     /* port C is input[3:0] and output[7:4] */
02335     virtual void outPortC(const uint8_t mask) {
02336         if (!enable_pc98_bus_mouse)
02337             return;
02338 
02339         if (mask & 0x80) { /* bit 7 */
02340             /* changing from 0 to 1 latches counters and clears them */
02341             if ((latchOutPortC & 0x80) && !p7fd9_8255_mouse_latch) { // change from 0 to 1 latches counters and clears them
02342                 p7fd9_8255_mouse_x_latch = p7fd9_8255_mouse_x;
02343                 p7fd9_8255_mouse_y_latch = p7fd9_8255_mouse_y;
02344                 p7fd9_8255_mouse_x = 0;
02345                 p7fd9_8255_mouse_y = 0;
02346             }
02347 
02348             p7fd9_8255_mouse_latch = (latchOutPortC >> 7) & 1;
02349         }
02350         if (mask & 0x60) { /* bits 6-5 */
02351             p7fd9_8255_mouse_sel = (latchOutPortC >> 5) & 3;
02352         }
02353         if (mask & 0x10) { /* bit 4 */
02354             uint8_t p = p7fd8_8255_mouse_int_enable;
02355 
02356             p7fd8_8255_mouse_int_enable = ((latchOutPortC >> 4) & 1) ^ 1; // bit 4 is interrupt MASK
02357 
02358             /* Some games use the mouse interrupt as a periodic source by writing this from the interrupt handler.
02359              *
02360              * Does that work on real hardware?? Is this what real hardware does?
02361              *
02362              * Games that need this:
02363              * - Metal Force
02364              * - Amaranth
02365              */
02366 
02367             if (p != p7fd8_8255_mouse_int_enable) {
02368                 /* NTS: I'm guessing that if the mouse interrupt has fired, inhibiting the interrupt
02369                  *      does not remove the IRQ signal already sent.
02370                  *
02371                  *      Amaranth's mouse driver appears to rapidly toggle this bit. If we re-fire
02372                  *      and inhibit the interrupt in reaction the game will get an interrupt rate
02373                  *      far higher than normal and animation will run way too fast. */
02374                 pc98_mouse_tick_schedule();
02375             }
02376         }
02377     }
02378 };
02379 
02380 static PC98_Mouse_8255 pc98_mouse_8255;
02381 
02383 static void write_p7fd9_mouse(Bitu port,Bitu val,Bitu /*iolen*/) {
02384     /* 0x7FD9-0x7FDF odd */
02385     pc98_mouse_8255.writeByPort((port - 0x7FD9) >> 1U,val);
02386 }
02387 
02388 static Bitu read_p7fd9_mouse(Bitu port,Bitu /*iolen*/) {
02389     /* 0x7FD9-0x7FDF odd */
02390     return pc98_mouse_8255.readByPort((port - 0x7FD9) >> 1U);
02391 }
02392 
02393 static void write_pbfdb_mouse(Bitu port,Bitu val,Bitu /*iolen*/) {
02394     (void)port;
02395 
02396     unsigned int p_pc98_mouse_rate_hz = pc98_mouse_rate_hz;
02397 
02398     /* bits [7:2] = ??
02399      * bits [1:0] = 120hz clock divider
02400      *              00 = 120hz (at reset)
02401      *              01 = 60hz
02402      *              10 = 30hz
02403      *              11 = 15hz */
02404     pc98_mouse_rate_hz = 120u >> (val & 3u);
02405 
02406     if (pc98_mouse_rate_hz != p_pc98_mouse_rate_hz)
02407         LOG(LOG_MISC,LOG_DEBUG)("PC-98 mouse interrupt rate: %u",pc98_mouse_rate_hz);
02408 }
02410 
02411 void KEYBOARD_OnEnterPC98(Section *sec) {
02412     (void)sec;//UNUSED
02413 
02414         Section_prop * pc98_section=static_cast<Section_prop *>(control->GetSection("pc98"));
02415         assert(pc98_section != NULL);
02416         enable_pc98_bus_mouse = pc98_section->Get_bool("pc-98 bus mouse");
02417 
02418     /* TODO: Keyboard interface change, layout change. */
02419 
02420     /* PC-98 uses the 8255 programmable peripheral interface. Install that here.
02421      * Sometime in the future, move 8255 emulation to a separate file.
02422      *
02423      * The 8255 appears at I/O ports 0x31, 0x33, 0x35, 0x37 */
02424     if (IS_PC98_ARCH) {
02425         for (unsigned int i=0;i < 4;i++) {
02426             ReadHandler_8255_PC98[i].Uninstall();
02427             WriteHandler_8255_PC98[i].Uninstall();
02428 
02429             ReadHandler_8255prn_PC98[i].Uninstall();
02430             WriteHandler_8255prn_PC98[i].Uninstall();
02431         }
02432         
02433         pc98_force_ibm_layout = pc98_section->Get_bool("pc-98 force ibm keyboard layout");
02434         if(pc98_force_ibm_layout)
02435             LOG_MSG("Forcing PC-98 keyboard to use IBM US-English like default layout");
02436     }
02437 
02438     if (!IS_PC98_ARCH) {
02439         /* remove 60h-63h */
02440         IO_FreeWriteHandler(0x60,IO_MB);
02441         IO_FreeReadHandler(0x60,IO_MB);
02442         IO_FreeWriteHandler(0x61,IO_MB);
02443         IO_FreeReadHandler(0x61,IO_MB);
02444         IO_FreeWriteHandler(0x64,IO_MB);
02445         IO_FreeReadHandler(0x64,IO_MB);
02446     }   
02447 }
02448 
02449 void KEYBOARD_OnEnterPC98_phase2(Section *sec) {
02450     (void)sec;//UNUSED
02451     unsigned int i;
02452 
02453     /* Keyboard UART (8251) is at 0x41, 0x43. */
02454     IO_RegisterWriteHandler(0x41,keyboard_pc98_8251_uart_41_write,IO_MB);
02455     IO_RegisterReadHandler(0x41,keyboard_pc98_8251_uart_41_read,IO_MB);
02456     IO_RegisterWriteHandler(0x43,keyboard_pc98_8251_uart_43_write,IO_MB);
02457     IO_RegisterReadHandler(0x43,keyboard_pc98_8251_uart_43_read,IO_MB);
02458 
02459     /* PC-98 uses the 8255 programmable peripheral interface. Install that here.
02460      * Sometime in the future, move 8255 emulation to a separate file.
02461      *
02462      * The 8255 appears at I/O ports 0x31, 0x33, 0x35, 0x37 */
02463 
02464     /* Port A = input
02465      * Port B = input
02466      * Port C = output */
02467     /* bit[7:7] =  1 = mode set
02468      * bit[6:5] = 00 = port A mode 0
02469      * bit[4:4] =  1 = port A input
02470      * bit[3:3] =  0 = port C upper output              1001 0010 = 0x92
02471      * bit[2:2] =  0 = port B mode 0
02472      * bit[1:1] =  1 = port B input
02473      * bit[0:0] =  0 = port C lower output */
02474     pc98_sys_8255.writeControl(0x92);
02475     pc98_sys_8255.writePortC(0xF8); /* SHUT0=1 SHUT1=1 mask printer RAM parity check buzzer inhibit */
02476 
02477     /* Another 8255 is at 0x40-0x46 even for the printer interface */
02478     /* bit[7:7] =  1 = mode set
02479      * bit[6:5] = 00 = port A mode 0
02480      * bit[4:4] =  0 = port A output
02481      * bit[3:3] =  0 = port C upper output              1000 0010 = 0x82
02482      * bit[2:2] =  0 = port B mode 0
02483      * bit[1:1] =  1 = port B input
02484      * bit[0:0] =  0 = port C lower output */
02485     pc98_prn_8255.writeControl(0x82);
02486     pc98_prn_8255.writePortA(0x00); /* printer latch all 0s */
02487     pc98_prn_8255.writePortC(0x0A); /* 1=IR8 OFF, reset 287/387 by CPU reset */
02488 
02489     for (i=0;i < 4;i++) {
02490         /* system */
02491         ReadHandler_8255_PC98[i].Uninstall();
02492         ReadHandler_8255_PC98[i].Install(0x31 + (i * 2),pc98_8255_read,IO_MB);
02493 
02494         WriteHandler_8255_PC98[i].Uninstall();
02495         WriteHandler_8255_PC98[i].Install(0x31 + (i * 2),pc98_8255_write,IO_MB);
02496 
02497         /* printer */
02498         ReadHandler_8255prn_PC98[i].Uninstall();
02499         ReadHandler_8255prn_PC98[i].Install(0x40 + (i * 2),pc98_8255prn_read,IO_MB);
02500 
02501         WriteHandler_8255prn_PC98[i].Uninstall();
02502         WriteHandler_8255prn_PC98[i].Install(0x40 + (i * 2),pc98_8255prn_write,IO_MB);
02503     }
02504 
02505     /* reset port */
02506     Reset_PC98.Uninstall();
02507     Reset_PC98.Install(0xF0,pc98_reset_write,IO_MB);
02508 
02509     if (enable_pc98_bus_mouse) {
02510         /* Mouse */
02511         for (i=0;i < 4;i++) {
02512             IO_RegisterWriteHandler(0x7FD9+(i*2),write_p7fd9_mouse,IO_MB);
02513             IO_RegisterReadHandler(0x7FD9+(i*2),read_p7fd9_mouse,IO_MB);
02514         }
02515 
02516         /* Mouse control port at BFDB (which can be used to reduce the interrupt rate of the mouse) */
02517         IO_RegisterWriteHandler(0xBFDB,write_pbfdb_mouse,IO_MB);
02518     }
02519 
02520     /* Port A = input
02521      * Port B = input
02522      * Port C = output */
02523     /* bit[7:7] =  1 = mode set
02524      * bit[6:5] = 00 = port A mode 0
02525      * bit[4:4] =  1 = port A input
02526      * bit[3:3] =  0 = port C upper output              1001 0010 = 0x92
02527      * bit[2:2] =  0 = port B mode 0
02528      * bit[1:1] =  1 = port B input
02529      * bit[0:0] =  1 = port C lower input */
02530     pc98_mouse_8255.writeControl(0x93);
02531     pc98_mouse_8255.writePortC(0x10); /* start with interrupt inhibited. INT 33h emulation will enable it later */
02532 }
02533 
02534 extern bool enable_slave_pic;
02535 
02536 void KEYBOARD_OnReset(Section *sec) {
02537     (void)sec;//UNUSED
02538     Section_prop *section=static_cast<Section_prop *>(control->GetSection("keyboard"));
02539 
02540     LOG(LOG_MISC,LOG_DEBUG)("Keyboard reinitializing");
02541 
02542     if ((keyb.enable_aux=section->Get_bool("aux")) != false) {
02543         if (machine == MCH_PCJR) {
02544             keyb.enable_aux = false;
02545         }
02546         else {
02547             LOG(LOG_KEYBOARD,LOG_NORMAL)("Keyboard AUX emulation enabled");
02548         }
02549     }
02550 
02551     TIMER_DelTickHandler(&KEYBOARD_TickHandler);
02552 
02553     allow_keyb_reset = section->Get_bool("allow output port reset");
02554 
02555     keyb.ps2mouse.int33_taken = 0;
02556     keyb.ps2mouse.reset_mode = MM_STREAM; /* NTS: I was wrong: PS/2 mice default to streaming after reset */
02557 
02558     const char * sbtype=section->Get_string("auxdevice");
02559     keyb.ps2mouse.type = MOUSE_NONE;
02560     if (sbtype != NULL && machine != MCH_PCJR && enable_slave_pic) {
02561         if (!strcasecmp(sbtype,"2button"))
02562             keyb.ps2mouse.type=MOUSE_2BUTTON;
02563         else if (!strcasecmp(sbtype,"3button"))
02564             keyb.ps2mouse.type=MOUSE_3BUTTON;
02565         else if (!strcasecmp(sbtype,"intellimouse"))
02566             keyb.ps2mouse.type=MOUSE_INTELLIMOUSE;
02567         else if (!strcasecmp(sbtype,"intellimouse45"))
02568             keyb.ps2mouse.type=MOUSE_INTELLIMOUSE45;
02569         else if (!strcasecmp(sbtype,"none"))
02570             keyb.ps2mouse.type=MOUSE_NONE;
02571         else {
02572             keyb.ps2mouse.type=MOUSE_INTELLIMOUSE;
02573             LOG(LOG_KEYBOARD,LOG_ERROR)("Assuming PS/2 intellimouse, I don't know what '%s' is",sbtype);
02574         }
02575     }
02576 
02577     if (IS_PC98_ARCH) {
02578         KEYBOARD_OnEnterPC98(NULL);
02579         KEYBOARD_OnEnterPC98_phase2(NULL);
02580     }
02581     else {
02582         IO_RegisterWriteHandler(0x60,write_p60,IO_MB);
02583         IO_RegisterReadHandler(0x60,read_p60,IO_MB);
02584         IO_RegisterWriteHandler(0x61,write_p61,IO_MB);
02585         IO_RegisterReadHandler(0x61,read_p61,IO_MB);
02586         if (machine==MCH_CGA || machine==MCH_HERC) IO_RegisterReadHandler(0x62,read_p62,IO_MB);
02587         IO_RegisterWriteHandler(0x64,write_p64,IO_MB);
02588         IO_RegisterReadHandler(0x64,read_p64,IO_MB);
02589     }
02590 
02591     TIMER_AddTickHandler(&KEYBOARD_TickHandler);
02592     write_p61(0,0,0);
02593     KEYBOARD_Reset();
02594     AUX_Reset();
02595     keyb.p60data = 0xAA;
02596 }
02597 
02598 void KEYBOARD_Init() {
02599     LOG(LOG_MISC,LOG_DEBUG)("Initializing keyboard emulation");
02600 
02601     AddExitFunction(AddExitFunctionFuncPair(KEYBOARD_ShutDown));
02602 
02603     AddVMEventFunction(VM_EVENT_RESET,AddVMEventFunctionFuncPair(KEYBOARD_OnReset));
02604 }
02605 
02606 void AUX_Reset() {
02607     keyb.ps2mouse.mode = keyb.ps2mouse.reset_mode;
02608     keyb.ps2mouse.acx = 0;
02609     keyb.ps2mouse.acy = 0;
02610     keyb.ps2mouse.samplerate = 80;
02611     keyb.ps2mouse.last_srate[0] = keyb.ps2mouse.last_srate[1] = keyb.ps2mouse.last_srate[2] = 0;
02612     keyb.ps2mouse.intellimouse_btn45 = false;
02613     keyb.ps2mouse.intellimouse_mode = false;
02614     keyb.ps2mouse.reporting = false;
02615     keyb.ps2mouse.scale21 = false;
02616     keyb.ps2mouse.resolution = 1;
02617     if (keyb.ps2mouse.type != MOUSE_NONE && keyb.ps2mouse.int33_taken)
02618         LOG(LOG_KEYBOARD,LOG_NORMAL)("PS/2 mouse emulation: taking over from INT 33h");
02619     keyb.ps2mouse.int33_taken = 0;
02620     keyb.ps2mouse.l = keyb.ps2mouse.m = keyb.ps2mouse.r = false;
02621 }
02622 
02623 void AUX_INT33_Takeover() {
02624     if (keyb.ps2mouse.type != MOUSE_NONE && keyb.ps2mouse.int33_taken)
02625         LOG(LOG_KEYBOARD,LOG_NORMAL)("PS/2 mouse emulation: Program is using INT 33h, disabling direct AUX emulation");
02626     keyb.ps2mouse.int33_taken = 1;
02627 }
02628 
02629 void KEYBOARD_Reset() {
02630     /* Init the keyb struct */
02631     keyb.active=true;
02632     keyb.scanning=true;
02633     keyb.pending_key=-1;
02634     keyb.auxactive=false;
02635     keyb.pending_key_state=false;
02636     keyb.command=CMD_NONE;
02637     keyb.aux_command=ACMD_NONE;
02638     keyb.p60changed=false;
02639     keyb.auxchanged=false;
02640     keyb.led_state = 0x00;
02641     keyb.repeat.key=KBD_NONE;
02642     keyb.repeat.pause=500;
02643     keyb.repeat.rate=33;
02644     keyb.repeat.wait=0;
02645     keyb.leftctrl_pressed=false;
02646     keyb.rightctrl_pressed=false;
02647     keyb.scanset=1;
02648     /* command byte */
02649     keyb.cb_override_inhibit=false;
02650     keyb.cb_irq12=false;
02651     keyb.cb_irq1=true;
02652     keyb.cb_xlat=true;
02653     keyb.cb_sys=true;
02654     keyb.reset=false;
02655     /* OK */
02656     KEYBOARD_ClrBuffer();
02657     KEYBOARD_SetLEDs(0);
02658 }
02659 
02660 //save state support
02661 void *KEYBOARD_TransferBuffer_PIC_Event = (void*)((uintptr_t)KEYBOARD_TransferBuffer);
02662 void *KEYBOARD_TickHandler_PIC_Timer = (void*)((uintptr_t)KEYBOARD_TickHandler);
02663 
02664 namespace
02665 {
02666 class SerializeKeyboard : public SerializeGlobalPOD
02667 {
02668 public:
02669     SerializeKeyboard() : SerializeGlobalPOD("Keyboard")
02670     {
02671         registerPOD(keyb.buffer);
02672         registerPOD(keyb.used); 
02673         registerPOD(keyb.pos); 
02674         registerPOD(keyb.repeat.key); 
02675         registerPOD(keyb.repeat.wait); 
02676         registerPOD(keyb.repeat.pause); 
02677         registerPOD(keyb.repeat.rate); 
02678         registerPOD(keyb.command); 
02679         registerPOD(keyb.p60data); 
02680         registerPOD(keyb.p60changed); 
02681         registerPOD(keyb.active); 
02682         registerPOD(keyb.scanning); 
02683         registerPOD(keyb.scheduled);
02684         registerPOD(port_61_data);
02685     }
02686 } dummy;
02687 }