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