#define NDEBUG
+#include "ntvdm.h"
#include "emulator.h"
-#include "io.h"
#include "ps2.h"
+
+#include "io.h"
#include "pic.h"
+#include "clock.h"
/* PRIVATE VARIABLES **********************************************************/
#define PS2_PORTS 2
static PS2_PORT Ports[PS2_PORTS];
-#define PS2_DEFAULT_CONFIG 0x47
+#define PS2_DEFAULT_CONFIG 0x45
static BYTE ControllerConfig = PS2_DEFAULT_CONFIG;
static BYTE ControllerCommand = 0x00;
// static BYTE InputBuffer = 0x00; // PS/2 Input Buffer
static BYTE OutputBuffer = 0x00; // PS/2 Output Buffer
+static PHARDWARE_TIMER IrqTimer = NULL;
+
/* PRIVATE FUNCTIONS **********************************************************/
static VOID PS2SendCommand(PPS2_PORT Port, BYTE Command)
/* Read controller output port */
case 0xD0:
{
- // TODO: Not implemented
+ /* Bit 0 always set, and bit 1 is the A20 gate state */
+ OutputBuffer = (!!EmulatorGetA20() << 1) | 0x01;
+ // FIXME: Set the status of IRQ1 and IRQ12
+
+ StatusRegister |= (1 << 0); // There is something to read
break;
}
/* Update the A20 line setting */
EmulatorSetA20(Data & (1 << 1));
+ // FIXME: Add the status of IRQ1 and IRQ12
+
break;
}
}
}
-static BOOLEAN PS2PortQueueRead(BYTE PS2Port)
+static VOID FASTCALL GeneratePS2Irq(ULONGLONG ElapsedTime)
+{
+ UNREFERENCED_PARAMETER(ElapsedTime);
+
+ /* Generate an IRQ 1 if there is data ready in the output queue */
+ if (PS2PortQueueRead(0))
+ {
+ /* Generate an interrupt if interrupts for the first PS/2 port are enabled */
+ if (ControllerConfig & 0x01) PicInterruptRequest(1);
+ return;
+ }
+
+ /* Generate an IRQ 12 if there is data ready in the output queue */
+ if (PS2PortQueueRead(1))
+ {
+ /* Generate an interrupt if interrupts for the second PS/2 port are enabled */
+ if (ControllerConfig & 0x02) PicInterruptRequest(12);
+ return;
+ }
+}
+
+/* PUBLIC FUNCTIONS ***********************************************************/
+
+BOOLEAN PS2PortQueueRead(BYTE PS2Port)
{
BOOLEAN Result = TRUE;
PPS2_PORT Port;
return Result;
}
-/* PUBLIC FUNCTIONS ***********************************************************/
-
VOID PS2SetDeviceCmdProc(BYTE PS2Port, LPVOID Param, PS2_DEVICE_CMDPROC DeviceCommand)
{
if (PS2Port >= PS2_PORTS) return;
/* The queue is not empty anymore */
Port->QueueEmpty = FALSE;
-/*
- // Get the data
- OutputBuffer = Port->Queue[Port->QueueStart];
- StatusRegister |= (1 << 0); // There is something to read
- // FIXME: Sometimes StatusRegister |= (1 << 5); for the second PS/2 port
-
- if (PS2Port == 0)
- PicInterruptRequest(1);
- else if (PS2Port == 1)
- PicInterruptRequest(12);
-*/
+ /* Schedule the IRQ */
+ EnableHardwareTimer(IrqTimer);
Done:
ReleaseMutex(Port->QueueMutex);
return Result;
}
-VOID GenerateIrq1(VOID)
-{
- /* Generate an interrupt if interrupts for the first PS/2 port are enabled */
- if (ControllerConfig & 0x01)
- {
- /* Generate an IRQ 1 if there is data ready in the output queue */
- if (PS2PortQueueRead(0)) PicInterruptRequest(1);
- }
-}
-
-VOID GenerateIrq12(VOID)
-{
- /* Generate an interrupt if interrupts for the second PS/2 port are enabled */
- if (ControllerConfig & 0x02)
- {
- /* Generate an IRQ 12 if there is data ready in the output queue */
- if (PS2PortQueueRead(1)) PicInterruptRequest(12);
- }
-}
-
BOOLEAN PS2Initialize(VOID)
{
/* Initialize the PS/2 ports */
RegisterIoPort(PS2_CONTROL_PORT, PS2ReadPort, PS2WritePort);
RegisterIoPort(PS2_DATA_PORT , PS2ReadPort, PS2WritePort);
+ IrqTimer = CreateHardwareTimer(HARDWARE_TIMER_ONESHOT,
+ HZ_TO_NS(100),
+ GeneratePS2Irq);
+
return TRUE;
}
VOID PS2Cleanup(VOID)
{
+ DestroyHardwareTimer(IrqTimer);
+
CloseHandle(Ports[1].QueueMutex);
CloseHandle(Ports[0].QueueMutex);
}