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