void KEYBOARD_Reset() { /* Init the keyb struct */ keyb.active=true; keyb.scanning=true; keyb.pending_key=-1; keyb.auxactive=false; keyb.pending_key_state=false; keyb.command=CMD_NONE; keyb.aux_command=ACMD_NONE; keyb.p60changed=false; keyb.auxchanged=false; keyb.led_state = 0x00; keyb.repeat.key=KBD_NONE; keyb.repeat.pause=200; keyb.repeat.rate=33; keyb.repeat.wait=0; keyb.leftctrl_pressed=false; keyb.rightctrl_pressed=false; keyb.scanset=1; /* command byte */ keyb.cb_override_inhibit=false; keyb.cb_irq12=false; keyb.cb_irq1=true; keyb.cb_xlat=true; keyb.cb_sys=true; keyb.reset=false; /* OK */ KEYBOARD_ClrBuffer(); KEYBOARD_SetLEDs(0); }
static void KEYBOARD_AddBuffer(Bit16u data) { if (keyb.used>=KEYBUFSIZE) { LOG(LOG_KEYBOARD,LOG_NORMAL)("Buffer full, dropping code"); KEYBOARD_ClrBuffer(); return; } Bitu start=keyb.pos+keyb.used; if (start>=KEYBUFSIZE) start-=KEYBUFSIZE; keyb.buffer[start]=data; keyb.used++; /* Start up an event to start the first IRQ */ if (!keyb.scheduled && !keyb.p60changed) { keyb.scheduled=true; PIC_AddEvent(KEYBOARD_TransferBuffer,KEYDELAY); } }
static void KEYBOARD_Add8042Response(Bit8u data) { if(!keyb.enable_aux) return; if (keyb.buf8042_pos >= keyb.buf8042_len) keyb.buf8042_pos = keyb.buf8042_len = 0; else if (keyb.buf8042_len == 0) keyb.buf8042_pos = 0; if (keyb.buf8042_pos >= sizeof(keyb.buf8042)) { LOG(LOG_KEYBOARD,LOG_NORMAL)("8042 Buffer full, dropping code"); KEYBOARD_ClrBuffer(); return; } keyb.buf8042[keyb.buf8042_len++] = data; PIC_AddEvent(KEYBOARD_TransferBuffer,KEYDELAY); }
void KEYBOARD_Init(Section* sec) { IO_RegisterWriteHandler(0x60,write_p60,IO_MB); IO_RegisterReadHandler(0x60,read_p60,IO_MB); IO_RegisterWriteHandler(0x61,write_p61,IO_MB); IO_RegisterReadHandler(0x61,read_p61,IO_MB); IO_RegisterWriteHandler(0x64,write_p64,IO_MB); IO_RegisterReadHandler(0x64,read_p64,IO_MB); TIMER_AddTickHandler(&KEYBOARD_TickHandler); write_p61(0,0,0); /* Init the keyb struct */ keyb.active=true; keyb.scanning=true; keyb.command=CMD_NONE; keyb.p60changed=false; keyb.repeat.key=KBD_NONE; keyb.repeat.pause=500; keyb.repeat.rate=33; keyb.repeat.wait=0; KEYBOARD_ClrBuffer(); }
static void write_p60(Bitu port,Bitu val,Bitu iolen) { switch (keyb.command) { case CMD_NONE: /* None */ /* No active command this would normally get sent to the keyboard then */ KEYBOARD_ClrBuffer(); switch (val) { case 0xed: /* Set Leds */ keyb.command=CMD_SETLEDS; KEYBOARD_AddBuffer(0xfa); /* Acknowledge */ break; case 0xee: /* Echo */ KEYBOARD_AddBuffer(0xfa); /* Acknowledge */ break; case 0xf2: /* Identify keyboard */ /* AT's just send acknowledge */ KEYBOARD_AddBuffer(0xfa); /* Acknowledge */ break; case 0xf3: /* Typematic rate programming */ keyb.command=CMD_SETTYPERATE; KEYBOARD_AddBuffer(0xfa); /* Acknowledge */ break; case 0xf4: /* Enable keyboard,clear buffer, start scanning */ LOG(LOG_KEYBOARD,LOG_NORMAL)("Clear buffer,enable Scaning"); KEYBOARD_AddBuffer(0xfa); /* Acknowledge */ keyb.scanning=true; break; case 0xf5: /* Reset keyboard and disable scanning */ LOG(LOG_KEYBOARD,LOG_NORMAL)("Reset, disable scanning"); keyb.scanning=false; KEYBOARD_AddBuffer(0xfa); /* Acknowledge */ break; case 0xf6: /* Reset keyboard and enable scanning */ LOG(LOG_KEYBOARD,LOG_NORMAL)("Reset, enable scanning"); KEYBOARD_AddBuffer(0xfa); /* Acknowledge */ keyb.scanning=false; break; case 0xff: KEYBOARD_AddBuffer(0xfa); /* Acknowledge */ KEYBOARD_AddBuffer(0xaa); break; default: /* Just always acknowledge strange commands */ LOG(LOG_KEYBOARD,LOG_ERROR)("60:Unhandled command %X",val); KEYBOARD_AddBuffer(0xfa); /* Acknowledge */ } return; case CMD_SETOUTPORT: MEM_A20_Enable((val & 2)>0); keyb.outport = val; if (!(val & 1)) { x86_init_reset(); } keyb.command = CMD_NONE; break; case CMD_SETTYPERATE: { static const int delay[] = { 250, 500, 750, 1000 }; static const int repeat[] = { 33,37,42,46,50,54,58,63,67,75,83,92,100, 109,118,125,133,149,167,182,200,217,233, 250,270,303,333,370,400,435,476,500 }; keyb.repeat.pause = delay[(val>>5)&3]; keyb.repeat.rate = repeat[val&0x1f]; keyb.command=CMD_NONE; } /* Fallthrough! as setleds does what we want */ case CMD_SETLEDS: keyb.command=CMD_NONE; KEYBOARD_ClrBuffer(); KEYBOARD_AddBuffer(0xfa); /* Acknowledge */ break; } }
static void write_p60(Bitu port,Bitu val,Bitu iolen) { switch (keyb.command) { case CMD_NONE: /* None */ if (keyb.reset) return; /* No active command this would normally get sent to the keyboard then */ KEYBOARD_ClrBuffer(); switch (val) { case 0xed: /* Set Leds */ keyb.command=CMD_SETLEDS; KEYBOARD_AddBuffer(0xfa); /* Acknowledge */ break; case 0xee: /* Echo */ KEYBOARD_AddBuffer(0xee); /* JC: The correct response is 0xEE, not 0xFA */ break; case 0xf0: /* set scancode set */ keyb.command=CMD_SETSCANSET; KEYBOARD_AddBuffer(0xfa); /* Acknowledge */ break; case 0xf2: /* Identify keyboard */ KEYBOARD_AddBuffer(0xfa); /* Acknowledge */ KEYBOARD_AddBuffer(0xab); /* ID */ KEYBOARD_AddBuffer(0x83); break; case 0xf3: /* Typematic rate programming */ keyb.command=CMD_SETTYPERATE; KEYBOARD_AddBuffer(0xfa); /* Acknowledge */ break; case 0xf4: /* Enable keyboard,clear buffer, start scanning */ LOG(LOG_KEYBOARD,LOG_NORMAL)("Clear buffer, enable scanning"); KEYBOARD_AddBuffer(0xfa); /* Acknowledge */ keyb.scanning=true; break; case 0xf5: /* Reset keyboard and disable scanning */ LOG(LOG_KEYBOARD,LOG_NORMAL)("Reset, disable scanning"); keyb.scanning=false; KEYBOARD_AddBuffer(0xfa); /* Acknowledge */ break; case 0xf6: /* Reset keyboard and enable scanning */ LOG(LOG_KEYBOARD,LOG_NORMAL)("Reset, enable scanning"); keyb.scanning=true; /* JC: Original DOSBox code was wrong, this command enables scanning */ KEYBOARD_AddBuffer(0xfa); /* Acknowledge */ break; case 0xff: /* keyboard resets take a long time (about 250ms), most keyboards flash the LEDs during reset */ KEYBOARD_Reset(); KEYBOARD_Add8042Response(0xFA); /* ACK */ KEYBOARD_Add8042Response(0xAA); /* SELF TEST OK (TODO: Need delay!) */ keyb.reset=true; KEYBOARD_SetLEDs(7); /* most keyboard I test with tend to flash the LEDs during reset */ PIC_AddEvent(KEYBOARD_ResetDelay,RESETDELAY); break; default: /* Just always acknowledge strange commands */ LOG(LOG_KEYBOARD,LOG_ERROR)("60:Unhandled command %X",(int)val); KEYBOARD_AddBuffer(0xfa); /* Acknowledge */ } return; case CMD_SETSCANSET: keyb.command=CMD_NONE; if (val == 0) { /* just asking */ if (keyb.cb_xlat) { switch (keyb.scanset) { case 1: KEYBOARD_AddBuffer(0x43); break; case 2: KEYBOARD_AddBuffer(0x41); break; case 3: KEYBOARD_AddBuffer(0x3F); break; } } else { KEYBOARD_AddBuffer(keyb.scanset); } KEYBOARD_AddBuffer(0xfa); /* Acknowledge */ } else { KEYBOARD_AddBuffer(0xfa); /* Acknowledge */ KEYBOARD_AddBuffer(0xfa); /* Acknowledge again */ if (val > 3) val = 3; keyb.scanset = val; } break; case CMD_WRITEAUX: keyb.command=CMD_NONE; KEYBOARD_AUX_Write(val); break; case CMD_WRITEOUTPUT: keyb.command=CMD_NONE; KEYBOARD_ClrBuffer(); KEYBOARD_AddBuffer(val); /* and now you return the byte as if it were typed in */ break; case CMD_WRITEAUXOUT: KEYBOARD_AddBuffer(AUX|val); /* stuff into AUX output */ break; case CMD_SETOUTPORT: if (!(val & 1)) { if (allow_keyb_reset) { LOG_MSG("Restart by keyboard controller requested\n"); On_Software_CPU_Reset(); } else { LOG_MSG("WARNING: Keyboard output port written with bit 1 clear. Is the guest OS or application attempting to reset the system?\n"); } } MEM_A20_Enable((val & 2)>0); keyb.command = CMD_NONE; break; case CMD_SETTYPERATE: if (keyb.reset) return; { static const int delay[] = { 250, 500, 750, 1000 }; static const int repeat[] = { 33,37,42,46,50,54,58,63,67,75,83,92,100, 109,118,125,133,149,167,182,200,217,233, 250,270,303,333,370,400,435,476,500 }; keyb.repeat.pause = delay[(val >> 5) & 3]; keyb.repeat.rate = repeat[val & 0x1f]; keyb.command = CMD_NONE; KEYBOARD_ClrBuffer(); KEYBOARD_AddBuffer(0xfa); /* Acknowledge */ } break; case CMD_SETLEDS: if (keyb.reset) return; keyb.command=CMD_NONE; KEYBOARD_ClrBuffer(); KEYBOARD_AddBuffer(0xfa); /* Acknowledge */ KEYBOARD_SetLEDs(val&7); break; case CMD_SETCOMMAND: /* 8042 command, not keyboard */ /* TODO: If biosps2=true and aux=false, disallow the guest OS from changing AUX port parameters including IRQ */ keyb.command=CMD_NONE; keyb.cb_xlat = (val >> 6) & 1; keyb.auxactive = !((val >> 5) & 1); keyb.active = !((val >> 4) & 1); keyb.cb_sys = (val >> 2) & 1; keyb.cb_irq12 = (val >> 1) & 1; keyb.cb_irq1 = (val >> 0) & 1; if (keyb.used && !keyb.scheduled && !keyb.p60changed && keyb.active) { keyb.scheduled=true; PIC_AddEvent(KEYBOARD_TransferBuffer,KEYDELAY); } break; } }