From f6fbd8378336ad581f6e2cd1fec3dcf3b0736fd5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Herm=C3=A8s=20B=C3=A9lusca-Ma=C3=AFto?= Date: Fri, 7 Aug 2015 16:10:18 +0000 Subject: [PATCH] [NTVDM] PS2: - By default all the PS/2 ports are disabled. They become enabled by the BIOS at the POST step. - Similarly it is the BIOS POST that sets up the PS/2 controller configuration byte. - Synchronize the value of bit 2 "System flag" and bit 4 "Keyboard enable flag" in the status register, according to what is set in the controller configuration register. What is the "keyboard enable flag" ? See http://www.os2museum.com/wp/the-dos-4-0-shell-mouse-mystery/ for more details... HW MOUSE: - Resetting the mouse sends also an ACKnowledge byte too... BIOS32: - Fix the reported number of bytes in the BIOS configuration table. - Enable the PS/2 ports in the POST. - Implement the "Pointing Device BIOS Interface" INT 15h, AH=C2h, AL=00h...09h based on VBox OSE & SeaBIOS; we should make our PS/2 mouse driver use it. The real call to INT 15h, AH=C2h function is still disabled because our mouse driver doesn't react well with it, when we run some applications like MS Diagnostics. PS2 MOUSE DRV: - Update copyright notice; - Remove 2 useless functions; - I've put in comments in the code the places where calls to the BIOS ps/2 mouse interface are needed. svn path=/trunk/; revision=68613 --- reactos/subsystems/mvdm/ntvdm/bios/bios.h | 2 +- .../mvdm/ntvdm/bios/bios32/bios32.c | 31 +- .../mvdm/ntvdm/bios/bios32/moubios32.c | 471 ++++++++++++++++-- reactos/subsystems/mvdm/ntvdm/dos/mouse32.c | 304 +++++++---- reactos/subsystems/mvdm/ntvdm/dos/mouse32.h | 6 +- .../subsystems/mvdm/ntvdm/hardware/mouse.c | 21 +- reactos/subsystems/mvdm/ntvdm/hardware/ps2.c | 44 +- 7 files changed, 721 insertions(+), 158 deletions(-) diff --git a/reactos/subsystems/mvdm/ntvdm/bios/bios.h b/reactos/subsystems/mvdm/ntvdm/bios/bios.h index 1fe7b14b927..34a6d6c6ef7 100644 --- a/reactos/subsystems/mvdm/ntvdm/bios/bios.h +++ b/reactos/subsystems/mvdm/ntvdm/bios/bios.h @@ -142,7 +142,7 @@ C_ASSERT(sizeof(USER_DATA_AREA) == 0x34); */ typedef struct _BIOS_CONFIG_TABLE { - WORD Length; // 0x00 + WORD Length; // 0x00 - Number of bytes following BYTE Model; // 0x02 BYTE SubModel; // 0x03 BYTE Revision; // 0x04 diff --git a/reactos/subsystems/mvdm/ntvdm/bios/bios32/bios32.c b/reactos/subsystems/mvdm/ntvdm/bios/bios32/bios32.c index 29a457c9202..19b621096e2 100644 --- a/reactos/subsystems/mvdm/ntvdm/bios/bios32/bios32.c +++ b/reactos/subsystems/mvdm/ntvdm/bios/bios32/bios32.c @@ -4,6 +4,7 @@ * FILE: bios32.c * PURPOSE: VDM 32-bit BIOS * PROGRAMMERS: Aleksandar Andrejevic + * Hermes Belusca-Maito (hermes.belusca@sfr.fr) */ /* INCLUDES *******************************************************************/ @@ -109,7 +110,7 @@ $fffe ; System Model ID static const BIOS_CONFIG_TABLE BiosConfigTable = { - sizeof(BIOS_CONFIG_TABLE), // Length + sizeof(BIOS_CONFIG_TABLE) - sizeof(((BIOS_CONFIG_TABLE*)0)->Length), // Length: Number of bytes following BIOS_MODEL, // BIOS Model BIOS_SUBMODEL, // BIOS Sub-Model @@ -325,7 +326,6 @@ static VOID WINAPI BiosMiscService(LPWORD Stack) { setAX(0x80); Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF; - break; } @@ -394,8 +394,11 @@ static VOID WINAPI BiosMiscService(LPWORD Stack) /* Pointing Device BIOS Interface (PS) */ case 0xC2: { - BiosMousePs2Interface(Stack); - UNIMPLEMENTED; // Remove it when BiosMousePs2Interface is implemented! + // FIXME: Reenable this call when we understand why + // our included mouse driver doesn't correctly reeanble + // mouse reporting! + // BiosMousePs2Interface(Stack); + // break; goto Default; } @@ -429,7 +432,7 @@ static VOID WINAPI BiosMiscService(LPWORD Stack) ULONG Above1M = (min(MAX_ADDRESS, 0x01000000) - 0x00100000) >> 10; /* The amount of memory above 16M, in 64K blocks */ - ULONG Above16M = (MAX_ADDRESS > 0x01000000) ? (MAX_ADDRESS - 0x01000000) >> 16: 0; + ULONG Above16M = (MAX_ADDRESS > 0x01000000) ? ((MAX_ADDRESS - 0x01000000) >> 16) : 0; setAX(Above1M); setBX(Above16M); @@ -476,8 +479,7 @@ static VOID WINAPI BiosMiscService(LPWORD Stack) else { DPRINT1("BIOS Function INT 15h, AH = 0xE8 - unexpected AL = %02X, EDX = %08X\n", - getAL(), - getEDX()); + getAL(), getEDX()); } break; @@ -773,6 +775,16 @@ static VOID BiosHwSetup(VOID) IOWriteB(PIT_DATA_PORT(2), 0x97); IOWriteB(PIT_DATA_PORT(2), 0x0A); + + /* Initialize PS/2 keyboard port */ + // Enable the port + IOWriteB(PS2_CONTROL_PORT, 0xAE); + IOWriteB(PS2_CONTROL_PORT, 0x60); + // Port interrupts and clock enabled, + // enable keyboard scancode translation. + // POST passed, force keyboard unlocking. + IOWriteB(PS2_DATA_PORT , 0x4D); + EnableHwIRQ(0, BiosTimerIrq); } @@ -785,7 +797,10 @@ static VOID InitializeBiosInt32(VOID) /* Register the default BIOS interrupt vectors */ - /* Zero out all of the IVT (0x00 -- 0xFF) */ + /* + * Zero out all of the IVT (0x00 -- 0xFF). Some applications + * indeed expect to have free vectors at the end of the IVT. + */ RtlZeroMemory(BaseAddress, 0x0100 * sizeof(ULONG)); #if defined(ADVANCED_DEBUGGING) && (ADVANCED_DEBUGGING_LEVEL >= 3) diff --git a/reactos/subsystems/mvdm/ntvdm/bios/bios32/moubios32.c b/reactos/subsystems/mvdm/ntvdm/bios/bios32/moubios32.c index a044a21b59f..7d1a07cd0ad 100644 --- a/reactos/subsystems/mvdm/ntvdm/bios/bios32/moubios32.c +++ b/reactos/subsystems/mvdm/ntvdm/bios/bios32/moubios32.c @@ -2,8 +2,11 @@ * COPYRIGHT: GPL - See COPYING in the top level directory * PROJECT: ReactOS Virtual DOS Machine * FILE: moubios32.c - * PURPOSE: VDM Mouse 32-bit BIOS + * PURPOSE: VDM 32-bit PS/2 Mouse BIOS * PROGRAMMERS: Aleksandar Andrejevic + * Hermes Belusca-Maito (hermes.belusca@sfr.fr) + * + * NOTE: Based from VirtualBox OSE ROM BIOS, and SeaBIOS. */ /* INCLUDES *******************************************************************/ @@ -12,118 +15,512 @@ #include "ntvdm.h" #include "emulator.h" +#include "cpu/cpu.h" // for EMULATOR_FLAG_CF #include "moubios32.h" #include "bios32p.h" #include "io.h" +#include "hardware/mouse.h" #include "hardware/ps2.h" /* PRIVATE VARIABLES **********************************************************/ +#define MOUSE_IRQ_INT 0x74 + +static BOOLEAN MouseEnabled = FALSE; +static DWORD OldIrqHandler; + +/* + * Far pointer to a device handler. In compatible PS/2, it is stored in the EBDA. + * + * See Ralf Brown: http://www.ctyme.com/intr/rb-1603.htm + * for more information. In particular: + * when the subroutine is called, it is given 4 WORD values on the stack; + * the handler should return with a FAR return without popping the stack. + */ +static ULONG DeviceHandler = 0; + /* PRIVATE FUNCTIONS **********************************************************/ +static VOID DisableMouseInt(VOID) +{ + BYTE ControllerConfig; + + /* Clear the mouse queue */ + while (PS2PortQueueRead(1)) ; // NOTE: Should be a IOReadB! But see r67231 + + /* Disable mouse interrupt and events */ + IOWriteB(PS2_CONTROL_PORT, 0x20); + ControllerConfig = IOReadB(PS2_DATA_PORT); + ControllerConfig &= ~0x02; // Turn off IRQ12 + ControllerConfig |= 0x20; // Disable mouse clock line + IOWriteB(PS2_CONTROL_PORT, 0x60); + IOWriteB(PS2_DATA_PORT, ControllerConfig); +} + +static VOID EnableMouseInt(VOID) +{ + BYTE ControllerConfig; + + /* Clear the mouse queue */ + while (PS2PortQueueRead(1)) ; // NOTE: Should be a IOReadB! But see r67231 + + /* Enable mouse interrupt and events */ + IOWriteB(PS2_CONTROL_PORT, 0x20); + ControllerConfig = IOReadB(PS2_DATA_PORT); + ControllerConfig |= 0x02; // Turn on IRQ12 + ControllerConfig &= ~0x20; // Enable mouse clock line + IOWriteB(PS2_CONTROL_PORT, 0x60); + IOWriteB(PS2_DATA_PORT, ControllerConfig); +} + +static inline +VOID SendMouseCommand(UCHAR Command) +{ + /* Clear the mouse queue */ + while (PS2PortQueueRead(1)) ; // NOTE: Should be a IOReadB! But see r67231 + + /* Send the command */ + IOWriteB(PS2_CONTROL_PORT, 0xD4); + IOWriteB(PS2_DATA_PORT, Command); +} + +static inline +UCHAR ReadMouseData(VOID) +{ + PS2PortQueueRead(1); // NOTE: Should be a IOReadB! But see r67231 + return IOReadB(PS2_DATA_PORT); +} + + +static +VOID BiosMouseEnable(VOID) +{ + if (MouseEnabled) return; + + MouseEnabled = TRUE; + + /* Get the old IRQ handler */ + OldIrqHandler = ((PDWORD)BaseAddress)[MOUSE_IRQ_INT]; + + /* Set the IRQ handler */ + //RegisterInt32(MAKELONG(FIELD_OFFSET(MOUSE_DRIVER, MouseIrqInt16Stub), MouseDataSegment), + // MOUSE_IRQ_INT, DosMouseIrq, NULL); +} + +static +VOID BiosMouseDisable(VOID) +{ + if (!MouseEnabled) return; + + /* Restore the old IRQ handler */ + // ((PDWORD)BaseAddress)[MOUSE_IRQ_INT] = OldIrqHandler; + + MouseEnabled = FALSE; +} + + // Mouse IRQ 12 static VOID WINAPI BiosMouseIrq(LPWORD Stack) { + DPRINT1("PS/2 Mouse IRQ! DeviceHandler = 0x%04X:0x%04X\n", + HIWORD(DeviceHandler), LOWORD(DeviceHandler)); + + if (DeviceHandler != 0) + { + /* + * Prepare the stack for the mouse device handler: + * push Status, X and Y data, and a zero word. + */ + setSP(getSP() - sizeof(WORD)); + *((LPWORD)SEG_OFF_TO_PTR(getSS(), getSP())) = 0; // Status + setSP(getSP() - sizeof(WORD)); + *((LPWORD)SEG_OFF_TO_PTR(getSS(), getSP())) = 0; // X data (high byte = 0) + setSP(getSP() - sizeof(WORD)); + *((LPWORD)SEG_OFF_TO_PTR(getSS(), getSP())) = 0; // Y data (high byte = 0) + setSP(getSP() - sizeof(WORD)); + *((LPWORD)SEG_OFF_TO_PTR(getSS(), getSP())) = 0; // Zero + + /* Call the device handler */ + RunCallback16(&BiosContext, DeviceHandler); + + /* Pop the stack */ + setSP(getSP() + 4*sizeof(WORD)); + } + PicIRQComplete(LOBYTE(Stack[STACK_INT_NUM])); } VOID BiosMousePs2Interface(LPWORD Stack) { - DPRINT1("INT 15h, AH = C2h must be implemented in order to support vendor mouse drivers\n"); + /* Disable mouse interrupt and events */ + DisableMouseInt(); switch (getAL()) { /* Enable / Disable */ case 0x00: { - break; - } + UCHAR State = getBH(); - /* Reset */ - case 0x01: - { - break; - } + if (State > 2) + { + /* Invalid function */ + setAH(0x01); + Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF; + break; + } - /* Set Sampling Rate */ - case 0x02: - { - break; - } + if (State == 0x00) + { + BiosMouseDisable(); - /* Set Resolution */ - case 0x03: - { - break; - } + /* Disable packet reporting */ + SendMouseCommand(0xF5); + } + else // if (State == 0x01) + { + /* Check for the presence of the device handler */ + if (DeviceHandler == 0) + { + /* No device handler installed */ + setAH(0x05); + Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF; + break; + } - /* Get Type */ - case 0x04: - { + BiosMouseEnable(); + + /* Enable packet reporting */ + SendMouseCommand(0xF4); + } + + if (ReadMouseData() != MOUSE_ACK) + { + /* Failure */ + setAH(0x03); + Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF; + break; + } + + /* Success */ + setAH(0x00); + Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF; break; } /* Initialize */ case 0x05: { + // Fall through + } + + /* Reset */ + case 0x01: + { + UCHAR Answer; + + SendMouseCommand(0xFF); + Answer = ReadMouseData(); + /* A "Resend" (0xFE) signal is sent if no mouse is attached */ + if (Answer == 0xFE) + { + /* Resend */ + setAH(0x04); + Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF; + break; + } + else if (Answer != MOUSE_ACK) + { + /* Failure */ + setAH(0x03); + Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF; + break; + } + + setBL(ReadMouseData()); // Should be MOUSE_BAT_SUCCESS + setBH(ReadMouseData()); // Mouse ID + + /* Success */ + setAH(0x00); + Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF; break; } - /* Extended Commands */ + /* Set Sampling Rate */ + case 0x02: + { + UCHAR SampleRate = 0; + + switch (getBH()) + { + case 0x00: SampleRate = 10; break; // 10 reports/sec + case 0x01: SampleRate = 20; break; // 20 " " + case 0x02: SampleRate = 40; break; // 40 " " + case 0x03: SampleRate = 60; break; // 60 " " + case 0x04: SampleRate = 80; break; // 80 " " + case 0x05: SampleRate = 100; break; // 100 " " + case 0x06: SampleRate = 200; break; // 200 " " + default: SampleRate = 0; + } + + if (SampleRate == 0) + { + /* Invalid input */ + setAH(0x02); + Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF; + break; + } + + SendMouseCommand(0xF3); + if (ReadMouseData() != MOUSE_ACK) + { + /* Failure */ + setAH(0x03); + Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF; + break; + } + + SendMouseCommand(SampleRate); + if (ReadMouseData() != MOUSE_ACK) + { + /* Failure */ + setAH(0x03); + Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF; + break; + } + + /* Success */ + setAH(0x00); + Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF; + break; + } + + /* Set Resolution */ + case 0x03: + { + UCHAR Resolution = getBH(); + + /* + * 0: 25 dpi, 1 count per millimeter + * 1: 50 dpi, 2 counts per millimeter + * 2: 100 dpi, 4 counts per millimeter + * 3: 200 dpi, 8 counts per millimeter + */ + if (Resolution > 3) + { + /* Invalid input */ + setAH(0x02); + Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF; + break; + } + + SendMouseCommand(0xE8); + if (ReadMouseData() != MOUSE_ACK) + { + /* Failure */ + setAH(0x03); + Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF; + break; + } + + SendMouseCommand(Resolution); + if (ReadMouseData() != MOUSE_ACK) + { + /* Failure */ + setAH(0x03); + Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF; + break; + } + + /* Success */ + setAH(0x00); + Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF; + break; + } + + /* Get Type */ + case 0x04: + { + SendMouseCommand(0xF2); + if (ReadMouseData() != MOUSE_ACK) + { + /* Failure */ + setAH(0x03); + Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF; + break; + } + + setBH(ReadMouseData()); + + /* Success */ + setAH(0x00); + Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF; + break; + } + + /* Extended Commands (Return Status and Set Scaling Factor) */ case 0x06: { + UCHAR Command = getBH(); + + switch (Command) + { + /* Return Status */ + case 0x00: + { + SendMouseCommand(0xE9); + if (ReadMouseData() != MOUSE_ACK) + { + /* Failure */ + setAH(0x03); + Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF; + } + + setBL(ReadMouseData()); // Status + setCL(ReadMouseData()); // Resolution + setDL(ReadMouseData()); // Sample rate + + /* Success */ + setAH(0x00); + Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF; + break; + } + + /* Set Scaling Factor to 1:1 */ + case 0x01: + /* Set Scaling Factor to 2:1 */ + case 0x02: + { + SendMouseCommand(Command == 0x01 ? 0xE6 : 0xE7); + if (ReadMouseData() != MOUSE_ACK) + { + /* Failure */ + setAH(0x03); + Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF; + } + + /* Success */ + setAH(0x00); + Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF; + break; + } + + default: + { + /* Invalid function */ + setAH(0x01); + Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF; + break; + } + } + break; } /* Set Device Handler Address */ case 0x07: { + /* ES:BX == 0000h:0000h removes the device handler */ + DeviceHandler = MAKELONG(getBX(), getES()); + + /* Success */ + setAH(0x00); + Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF; break; } /* Write to Pointer Port */ case 0x08: { + SendMouseCommand(getBL()); + if (ReadMouseData() != MOUSE_ACK) + { + /* Failure */ + setAH(0x03); + Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF; + break; + } + + /* Success */ + setAH(0x00); + Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF; break; } /* Read from Pointer Port */ case 0x09: { + setBL(ReadMouseData()); + setCL(ReadMouseData()); + setDL(ReadMouseData()); + + /* Success */ + setAH(0x00); + Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF; break; } default: { - DPRINT1("INT 15h, AH = C2h, AL = 0x%02X NOT IMPLEMENTED\n", + DPRINT1("INT 15h, AH = C2h, AL = %02Xh NOT IMPLEMENTED\n", getAL()); + + /* Unknown function */ + setAH(0x01); + Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF; } } + + /* Reenable mouse interrupt and events */ + EnableMouseInt(); } /* PUBLIC FUNCTIONS ***********************************************************/ VOID MouseBios32Post(VOID) { - BYTE ControllerConfig; + UCHAR Answer; - /* Clear the mouse queue */ - while (PS2PortQueueRead(1)) continue; + /* Initialize PS/2 mouse port */ + // Enable the port + IOWriteB(PS2_CONTROL_PORT, 0xA8); - /* Enable packet reporting */ - IOWriteB(PS2_CONTROL_PORT, 0xD4); - IOWriteB(PS2_DATA_PORT, 0xF4); + /* Detect mouse presence by attempting a reset */ + SendMouseCommand(0xFF); + Answer = ReadMouseData(); + /* If no mouse attached, it will return RESEND (0xFE) */ + if (Answer == 0xFE) + { + DPRINT1("No mouse present!\n"); + } + else if (Answer != MOUSE_ACK) + { + DPRINT1("Mouse reset failure!\n"); + } + else + { + /* Mouse present, try to completely enable it */ - /* Read the mouse ACK reply */ - PS2PortQueueRead(1); + // FIXME: The following is temporary until + // this is moved into the mouse driver!! - /* Enable IRQ12 */ - IOWriteB(PS2_CONTROL_PORT, 0x20); - ControllerConfig = IOReadB(PS2_DATA_PORT); - IOWriteB(PS2_CONTROL_PORT, 0x60); - IOWriteB(PS2_DATA_PORT, ControllerConfig | 0x02); + /* Enable packet reporting */ + SendMouseCommand(0xF4); + if (ReadMouseData() != MOUSE_ACK) + { + DPRINT1("Failed to enable mouse!\n"); + } + else + { + /* Enable mouse interrupt and events */ + EnableMouseInt(); + } + } + + /* No mouse driver available so far */ + RegisterBiosInt32(0x33, NULL); /* Set up the HW vector interrupts */ EnableHwIRQ(12, BiosMouseIrq); diff --git a/reactos/subsystems/mvdm/ntvdm/dos/mouse32.c b/reactos/subsystems/mvdm/ntvdm/dos/mouse32.c index 7f8580ba810..4f181ae5030 100644 --- a/reactos/subsystems/mvdm/ntvdm/dos/mouse32.c +++ b/reactos/subsystems/mvdm/ntvdm/dos/mouse32.c @@ -2,7 +2,7 @@ * COPYRIGHT: GPL - See COPYING in the top level directory * PROJECT: ReactOS Virtual DOS Machine * FILE: mouse32.c - * PURPOSE: VDM 32-bit compatible MOUSE.COM driver + * PURPOSE: VDM 32-bit compatible PS/2 MOUSE.COM driver * PROGRAMMERS: Aleksandar Andrejevic */ @@ -10,6 +10,10 @@ #define NDEBUG +/* Driver Version number and Copyright */ +#include +#include + #include "ntvdm.h" #include "emulator.h" @@ -30,7 +34,10 @@ /* PRIVATE VARIABLES **********************************************************/ -static const CHAR MouseCopyright[] = "ROS PS/2 16/32-bit Mouse Driver Compatible MS-MOUSE 6.26 Copyright (C) ReactOS Team 1996-2015\0"; +static const CHAR MouseCopyright[] = + "ReactOS PS/2 16/32-bit Mouse Driver Compatible MS-MOUSE 6.26\r\n" + "Version "KERNEL_VERSION_STR" (Build "KERNEL_VERSION_BUILD_STR")\r\n" + "Copyright (C) ReactOS Team 1996-"COPYRIGHT_YEAR"\0"; #pragma pack(push, 1) @@ -58,8 +65,80 @@ static MOUSE_DRIVER_STATE DriverState; static DWORD OldIrqHandler; static DWORD OldIntHandler; +static WORD DefaultGfxScreenMask[16] = +{ + 0xC3FF, // 1100001111111111 + 0xC0FF, // 1100000011111111 + 0xC07F, // 1100000001111111 + 0xC01F, // 1100000000011111 + 0xC00F, // 1100000000001111 + 0xC007, // 1100000000000111 + 0xC003, // 1100000000000011 + 0xC007, // 1100000000000111 + 0xC01F, // 1100000000011111 + 0xC01F, // 1100000000011111 + 0xC00F, // 1100000000001111 + 0xC60F, // 1100011000001111 + 0xFF07, // 1111111100000111 + 0xFF07, // 1111111100000111 + 0xFF87, // 1111111110000111 + 0xFFCF, // 1111111111001111 +}; + +static WORD DefaultGfxCursorMask[16] = +{ + 0x0000, // 0000000000000000 + 0x1C00, // 0001110000000000 + 0x1F00, // 0001111100000000 + 0x1F80, // 0001111110000000 + 0x1FE0, // 0001111111100000 + 0x1FF0, // 0001111111110000 + 0x1FF8, // 0001111111111000 + 0x1FE0, // 0001111111100000 + 0x1FC0, // 0001111111000000 + 0x1FC0, // 0001111111000000 + 0x19E0, // 0001100111100000 + 0x00E0, // 0000000011100000 + 0x0070, // 0000000001110000 + 0x0070, // 0000000001110000 + 0x0030, // 0000000000110000 + 0x0000, // 0000000000000000 +}; + /* PRIVATE FUNCTIONS **********************************************************/ +/* static */ +VOID BiosPs2Service(UCHAR Function) +{ + /* Save AX and BX */ + USHORT AX = getAX(); + // USHORT BX = getBX(); + + /* + * Set the parameters: + * AL contains the character to print (already set), + * BL contains the character attribute, + * BH contains the video page to use. + */ + // setBL(DOS_CHAR_ATTRIBUTE); + // setBH(Bda->VideoPage); + setAL(Function); + + /* Call the BIOS INT 15h, AH=C2h "Pointing Device BIOS Interface (PS)" */ + setAH(0xC2); + Int32Call(&MouseContext, BIOS_MISC_INTERRUPT); + + /* Restore AX and BX */ + // setBX(BX); + setAX(AX); +} + + + +static VOID DosMouseEnable(VOID); +static VOID DosMouseDisable(VOID); + + static VOID PaintMouseCursor(VOID) { COORD Position = DriverState.Position; @@ -273,7 +352,7 @@ static inline VOID DosUpdatePosition(PCOORD NewPosition) CallMouseUserHandlers(0x0001); // We use MS MOUSE v1.0+ format } -static inline VOID DosUpdateButtons(BYTE ButtonState) +static inline VOID DosUpdateButtons(BYTE ButtonState) // WORD ButtonState { USHORT i; USHORT CallMask = 0x0000; // We use MS MOUSE v1.0+ format @@ -316,9 +395,9 @@ static VOID WINAPI DosMouseIrq(LPWORD Stack) /* Read the whole packet at once */ Flags = IOReadB(PS2_DATA_PORT); - PS2PortQueueRead(1); + PS2PortQueueRead(1); // NOTE: Should be a IOReadB! But see r67231 DeltaX = IOReadB(PS2_DATA_PORT); - PS2PortQueueRead(1); + PS2PortQueueRead(1); // NOTE: Should be a IOReadB! But see r67231 DeltaY = IOReadB(PS2_DATA_PORT); /* Adjust the sign */ @@ -369,39 +448,13 @@ static VOID WINAPI DosMouseService(LPWORD Stack) DriverState.GraphicsCursor.HotSpot.X = 3; DriverState.GraphicsCursor.HotSpot.Y = 1; - DriverState.GraphicsCursor.ScreenMask[0] = 0xC3FF; // 1100001111111111 - DriverState.GraphicsCursor.ScreenMask[1] = 0xC0FF; // 1100000011111111 - DriverState.GraphicsCursor.ScreenMask[2] = 0xC07F; // 1100000001111111 - DriverState.GraphicsCursor.ScreenMask[3] = 0xC01F; // 1100000000011111 - DriverState.GraphicsCursor.ScreenMask[4] = 0xC00F; // 1100000000001111 - DriverState.GraphicsCursor.ScreenMask[5] = 0xC007; // 1100000000000111 - DriverState.GraphicsCursor.ScreenMask[6] = 0xC003; // 1100000000000011 - DriverState.GraphicsCursor.ScreenMask[7] = 0xC007; // 1100000000000111 - DriverState.GraphicsCursor.ScreenMask[8] = 0xC01F; // 1100000000011111 - DriverState.GraphicsCursor.ScreenMask[9] = 0xC01F; // 1100000000011111 - DriverState.GraphicsCursor.ScreenMask[10] = 0xC00F; // 1100000000001111 - DriverState.GraphicsCursor.ScreenMask[11] = 0xC60F; // 1100011000001111 - DriverState.GraphicsCursor.ScreenMask[12] = 0xFF07; // 1111111100000111 - DriverState.GraphicsCursor.ScreenMask[13] = 0xFF07; // 1111111100000111 - DriverState.GraphicsCursor.ScreenMask[14] = 0xFF87; // 1111111110000111 - DriverState.GraphicsCursor.ScreenMask[15] = 0xFFCF; // 1111111111001111 + RtlCopyMemory(DriverState.GraphicsCursor.ScreenMask, + DefaultGfxScreenMask, + sizeof(DriverState.GraphicsCursor.ScreenMask)); - DriverState.GraphicsCursor.CursorMask[0] = 0x0000; // 0000000000000000 - DriverState.GraphicsCursor.CursorMask[1] = 0x1C00; // 0001110000000000 - DriverState.GraphicsCursor.CursorMask[2] = 0x1F00; // 0001111100000000 - DriverState.GraphicsCursor.CursorMask[3] = 0x1F80; // 0001111110000000 - DriverState.GraphicsCursor.CursorMask[4] = 0x1FE0; // 0001111111100000 - DriverState.GraphicsCursor.CursorMask[5] = 0x1FF0; // 0001111111110000 - DriverState.GraphicsCursor.CursorMask[6] = 0x1FF8; // 0001111111111000 - DriverState.GraphicsCursor.CursorMask[7] = 0x1FE0; // 0001111111100000 - DriverState.GraphicsCursor.CursorMask[8] = 0x1FC0; // 0001111111000000 - DriverState.GraphicsCursor.CursorMask[9] = 0x1FC0; // 0001111111000000 - DriverState.GraphicsCursor.CursorMask[10] = 0x19E0; // 0001100111100000 - DriverState.GraphicsCursor.CursorMask[11] = 0x00E0; // 0000000011100000 - DriverState.GraphicsCursor.CursorMask[12] = 0x0070; // 0000000001110000 - DriverState.GraphicsCursor.CursorMask[13] = 0x0070; // 0000000001110000 - DriverState.GraphicsCursor.CursorMask[14] = 0x0030; // 0000000000110000 - DriverState.GraphicsCursor.CursorMask[15] = 0x0000; // 0000000000000000 + RtlCopyMemory(DriverState.GraphicsCursor.CursorMask, + DefaultGfxCursorMask, + sizeof(DriverState.GraphicsCursor.CursorMask)); /* Initialize the counters */ DriverState.HorizCount = DriverState.VertCount = 0; @@ -436,7 +489,7 @@ static VOID WINAPI DosMouseService(LPWORD Stack) break; } - /* Return Position And Button Status */ + /* Return Position and Button Status */ case 0x03: { COORD Position = DriverState.Position; @@ -610,6 +663,13 @@ static VOID WINAPI DosMouseService(LPWORD Stack) break; } + /* Set Exclusion Area */ + // http://www.ctyme.com/intr/rb-5972.htm + // http://www.techhelpmanual.com/849-int_33h_0010h__set_exclusion_area.html + //case 0x10: + //{ + //} + /* Define Double-Speed Threshold */ case 0x13: { @@ -625,12 +685,18 @@ static VOID WINAPI DosMouseService(LPWORD Stack) DriverState.Handler0.CallMask = getCX(); DriverState.Handler0.Callback = MAKELONG(getDX(), getES()); // Far pointer to the callback + DPRINT1("Exchange old callback 0x%04X, %04X:%04X with new callback 0x%04X, %04X:%04X\n", + OldCallMask, + HIWORD(OldCallback), + LOWORD(OldCallback), + DriverState.Handler0.CallMask, + HIWORD(DriverState.Handler0.Callback), + LOWORD(DriverState.Handler0.Callback)); /* Return old callmask in CX and callback vector in ES:DX */ setCX(OldCallMask); setES(HIWORD(OldCallback)); setDX(LOWORD(OldCallback)); - break; } @@ -644,6 +710,9 @@ static VOID WINAPI DosMouseService(LPWORD Stack) /* Save Driver State */ case 0x16: { + /* Check whether the user buffer has correct size and fail if not */ + if (getBX() != sizeof(MOUSE_DRIVER_STATE)) break; + *((PMOUSE_DRIVER_STATE)SEG_OFF_TO_PTR(getES(), getDX())) = DriverState; break; } @@ -651,6 +720,9 @@ static VOID WINAPI DosMouseService(LPWORD Stack) /* Restore Driver State */ case 0x17: { + /* Check whether the user buffer has correct size and fail if not */ + if (getBX() != sizeof(MOUSE_DRIVER_STATE)) break; + DriverState = *((PMOUSE_DRIVER_STATE)SEG_OFF_TO_PTR(getES(), getDX())); break; } @@ -803,6 +875,15 @@ static VOID WINAPI DosMouseService(LPWORD Stack) case 0x1A: { DPRINT1("INT 33h, AH=1Ah: Mouse sensitivity is UNSUPPORTED\n"); + + // FIXME: Do that at runtime! + + // UCHAR BH = getBH(); + // setBH(0x00); + // BiosPs2Service(0x00); + // FIXME: Check for return status in AH and CF + // setBH(BH); + break; } @@ -815,6 +896,15 @@ static VOID WINAPI DosMouseService(LPWORD Stack) setBX(50); // Horizontal speed setCX(50); // Vertical speed setDX(50); // Double speed threshold + + // FIXME: Get that at runtime! + + // UCHAR BH = getBH(); + // setBH(0x00); + // BiosPs2Service(0x00); + // FIXME: Check for return status in AH and CF + // setBH(BH); + break; } @@ -826,6 +916,11 @@ static VOID WINAPI DosMouseService(LPWORD Stack) setBX(LOWORD(OldIntHandler)); DosMouseDisable(); + // UCHAR BH = getBH(); + // setBH(0x00); + // BiosPs2Service(0x00); + // FIXME: Check for return status in AH and CF + // setBH(BH); break; } @@ -833,6 +928,11 @@ static VOID WINAPI DosMouseService(LPWORD Stack) case 0x20: { DosMouseEnable(); + // UCHAR BH = getBH(); + // setBH(0x01); + // BiosPs2Service(0x00); + // FIXME: Check for return status in AH and CF + // setBH(BH); break; } @@ -876,6 +976,10 @@ static VOID WINAPI DosMouseService(LPWORD Stack) { setBX(MOUSE_VERSION); // Version Number + /* + * See Ralf Brown: http://www.ctyme.com/intr/rb-5993.htm + * for the list of possible values. + */ // FIXME: To be determined at runtime! setCH(0x04); // PS/2 Type setCL(0x00); // PS/2 Interrupt @@ -883,6 +987,60 @@ static VOID WINAPI DosMouseService(LPWORD Stack) break; } + // BIOS Function INT 33h, AX = 0x0025 NOT IMPLEMENTED + case 0x25: + { + setAX(0); + setBX(0); + setCX(0); + setDX(0); + UNIMPLEMENTED; + break; + } + + /* Get Maximum Virtual Coordinates */ + case 0x26: + { + setBX(!DriverEnabled); + // FIXME: In fact the MaxX and MaxY here are + // theoretical values for the current video mode. + // They therefore can be different from the current + // min/max values. + // See http://www.ctyme.com/intr/rb-5995.htm + // for more details. + setCX(DriverState.MaxX); + setDX(DriverState.MaxY); + break; + } + + /* Get Current Minimum/Maximum Virtual Coordinates */ + case 0x31: + { + setAX(DriverState.MinX); + setBX(DriverState.MinY); + setCX(DriverState.MaxX); + setDX(DriverState.MaxY); + break; + } + +#if 0 + case 0x33: + { + /* + * Related to http://www.ctyme.com/intr/rb-5985.htm + * INT 33h, AX=001Ch "SET INTERRUPT RATE": + + * Values for mouse interrupt rate: + * BX = rate + 00h no interrupts allowed + 01h 30 per second + 02h 50 per second + 03h 100 per second + 04h 200 per second + */ + } +#endif + /* Return Pointer to Copyright String */ case 0x4D: { @@ -914,6 +1072,7 @@ static VOID WINAPI DosMouseService(LPWORD Stack) /* PUBLIC FUNCTIONS ***********************************************************/ +static VOID DosMouseEnable(VOID) { if (DriverEnabled) return; @@ -928,6 +1087,7 @@ VOID DosMouseEnable(VOID) MOUSE_IRQ_INT, DosMouseIrq, NULL); } +static VOID DosMouseDisable(VOID) { if (!DriverEnabled) return; @@ -938,61 +1098,6 @@ VOID DosMouseDisable(VOID) DriverEnabled = FALSE; } -VOID DosMouseUpdatePosition(PCOORD NewPosition) -{ - SHORT DeltaX = NewPosition->X - DriverState.Position.X; - SHORT DeltaY = NewPosition->Y - DriverState.Position.Y; - - if (!DriverEnabled) return; - - DriverState.HorizCount += (DeltaX * MICKEYS_PER_CELL_HORIZ) / 8; - DriverState.VertCount += (DeltaY * MICKEYS_PER_CELL_VERT) / 8; - - if (DriverState.ShowCount > 0) EraseMouseCursor(); - DriverState.Position = *NewPosition; - if (DriverState.ShowCount > 0) PaintMouseCursor(); - - /* Call the mouse handlers */ - // if (DeltaX || DeltaY) - CallMouseUserHandlers(0x0001); // We use MS MOUSE v1.0+ format -} - -VOID DosMouseUpdateButtons(WORD ButtonState) -{ - USHORT i; - USHORT CallMask = 0x0000; // We use MS MOUSE v1.0+ format - - if (!DriverEnabled) return; - - for (i = 0; i < NUM_MOUSE_BUTTONS; i++) - { - BOOLEAN OldState = (DriverState.ButtonState >> i) & 1; - BOOLEAN NewState = (ButtonState >> i) & 1; - - if (NewState > OldState) - { - /* Mouse press */ - DriverState.PressCount[i]++; - DriverState.LastPress[i] = DriverState.Position; - - CallMask |= (1 << (2 * i + 1)); - } - else if (NewState < OldState) - { - /* Mouse release */ - DriverState.ReleaseCount[i]++; - DriverState.LastRelease[i] = DriverState.Position; - - CallMask |= (1 << (2 * i + 2)); - } - } - - DriverState.ButtonState = ButtonState; - - /* Call the mouse handlers */ - CallMouseUserHandlers(CallMask); -} - BOOLEAN DosMouseInitialize(VOID) { /* Initialize some memory for storing our data that should be available to DOS */ @@ -1020,6 +1125,12 @@ BOOLEAN DosMouseInitialize(VOID) DOS_MOUSE_INTERRUPT, DosMouseService, NULL); DosMouseEnable(); + // UCHAR BH = getBH(); + // setBH(0x01); + // BiosPs2Service(0x00); + // FIXME: Check for return status in AH and CF + // setBH(BH); + return TRUE; } @@ -1027,6 +1138,11 @@ VOID DosMouseCleanup(VOID) { if (DriverState.ShowCount > 0) EraseMouseCursor(); DosMouseDisable(); + // UCHAR BH = getBH(); + // setBH(0x00); + // BiosPs2Service(0x00); + // FIXME: Check for return status in AH and CF + // setBH(BH); /* Restore the old mouse service interrupt handler */ ((PDWORD)BaseAddress)[DOS_MOUSE_INTERRUPT] = OldIntHandler; diff --git a/reactos/subsystems/mvdm/ntvdm/dos/mouse32.h b/reactos/subsystems/mvdm/ntvdm/dos/mouse32.h index 828023e1920..aff1b835786 100644 --- a/reactos/subsystems/mvdm/ntvdm/dos/mouse32.h +++ b/reactos/subsystems/mvdm/ntvdm/dos/mouse32.h @@ -2,7 +2,7 @@ * COPYRIGHT: GPL - See COPYING in the top level directory * PROJECT: ReactOS Virtual DOS Machine * FILE: mouse32.h - * PURPOSE: VDM 32-bit compatible MOUSE.COM driver + * PURPOSE: VDM 32-bit compatible PS/2 MOUSE.COM driver * PROGRAMMERS: Aleksandar Andrejevic */ @@ -12,7 +12,7 @@ /* DEFINES ********************************************************************/ // -// We are ROS PS/2 Mouse Driver Version 6.26, compatible MS-MOUSE 6.26 +// We are ReactOS PS/2 Mouse Driver Version 6.26, compatible MS-MOUSE 6.26 // #define MOUSE_VERSION MAKEWORD(0x26, 0x06) @@ -75,8 +75,6 @@ typedef struct _MOUSE_DRIVER_STATE /* FUNCTIONS ******************************************************************/ -VOID DosMouseEnable(VOID); -VOID DosMouseDisable(VOID); BOOLEAN DosMouseInitialize(VOID); VOID DosMouseCleanup(VOID); diff --git a/reactos/subsystems/mvdm/ntvdm/hardware/mouse.c b/reactos/subsystems/mvdm/ntvdm/hardware/mouse.c index 3936c7bf1cb..a2b1ae41b0c 100644 --- a/reactos/subsystems/mvdm/ntvdm/hardware/mouse.c +++ b/reactos/subsystems/mvdm/ntvdm/hardware/mouse.c @@ -2,7 +2,7 @@ * COPYRIGHT: GPL - See COPYING in the top level directory * PROJECT: ReactOS Virtual DOS Machine * FILE: mouse.c - * PURPOSE: Mouse emulation + * PURPOSE: PS/2 Mouse emulation * PROGRAMMERS: Aleksandar Andrejevic */ @@ -39,12 +39,12 @@ static BOOLEAN EventsOccurred = FALSE; static BYTE DataByteWait = 0; static BYTE ScrollMagicCounter = 0, ExtraButtonMagicCounter = 0; +static UINT MouseCycles = 10; + static BYTE PS2Port = 1; /* PUBLIC VARIABLES ***********************************************************/ -UINT MouseCycles = 10; - /* PRIVATE FUNCTIONS **********************************************************/ static VOID MouseResetConfig(VOID) @@ -73,6 +73,8 @@ static VOID MouseReset(VOID) MouseId = 0; ScrollMagicCounter = ExtraButtonMagicCounter = 0; + PS2QueuePush(PS2Port, MOUSE_ACK); + /* Send the Basic Assurance Test success code and the device ID */ PS2QueuePush(PS2Port, MOUSE_BAT_SUCCESS); PS2QueuePush(PS2Port, MouseId); @@ -118,7 +120,7 @@ static VOID MouseGetPacket(PMOUSE_PACKET Packet) /* Set the button flags */ if (ButtonState & FROM_LEFT_1ST_BUTTON_PRESSED) Packet->Flags |= MOUSE_LEFT_BUTTON; if (ButtonState & FROM_LEFT_2ND_BUTTON_PRESSED) Packet->Flags |= MOUSE_MIDDLE_BUTTON; - if (ButtonState & RIGHTMOST_BUTTON_PRESSED) Packet->Flags |= MOUSE_RIGHT_BUTTON; + if (ButtonState & RIGHTMOST_BUTTON_PRESSED) Packet->Flags |= MOUSE_RIGHT_BUTTON; if (MouseId == 4) { @@ -250,8 +252,8 @@ static VOID WINAPI MouseCommand(LPVOID Param, BYTE Command) /* Set Sample Rate */ case 0xF3: { - PS2QueuePush(PS2Port, MOUSE_ACK); DataByteWait = Command; + PS2QueuePush(PS2Port, MOUSE_ACK); break; } @@ -259,12 +261,12 @@ static VOID WINAPI MouseCommand(LPVOID Param, BYTE Command) case 0xE9: { BYTE Status = ButtonState & 7; - PS2QueuePush(PS2Port, MOUSE_ACK); if (Scaling) Status |= 1 << 4; if (Reporting) Status |= 1 << 5; if (Mode == MOUSE_REMOTE_MODE) Status |= 1 << 6; + PS2QueuePush(PS2Port, MOUSE_ACK); PS2QueuePush(PS2Port, Status); PS2QueuePush(PS2Port, Resolution); PS2QueuePush(PS2Port, (BYTE)(1000 / MouseCycles)); @@ -290,7 +292,7 @@ static VOID WINAPI MouseCommand(LPVOID Param, BYTE Command) break; } - /* Return From Wrap Mode */ + /* Return from Wrap Mode */ case 0xEC: { if (Mode == MOUSE_WRAP_MODE) @@ -300,7 +302,10 @@ static VOID WINAPI MouseCommand(LPVOID Param, BYTE Command) Mode = PreviousMode; PS2QueuePush(PS2Port, MOUSE_ACK); } - else PS2QueuePush(PS2Port, MOUSE_ERROR); + else + { + PS2QueuePush(PS2Port, MOUSE_ERROR); + } break; } diff --git a/reactos/subsystems/mvdm/ntvdm/hardware/ps2.c b/reactos/subsystems/mvdm/ntvdm/hardware/ps2.c index b52f20fb1e6..2013422444e 100644 --- a/reactos/subsystems/mvdm/ntvdm/hardware/ps2.c +++ b/reactos/subsystems/mvdm/ntvdm/hardware/ps2.c @@ -45,8 +45,7 @@ typedef struct _PS2_PORT #define PS2_PORTS 2 static PS2_PORT Ports[PS2_PORTS]; -#define PS2_DEFAULT_CONFIG 0x45 -static BYTE ControllerConfig = PS2_DEFAULT_CONFIG; +static BYTE ControllerConfig = 0x00; static BYTE ControllerCommand = 0x00; static BYTE StatusRegister = 0x00; @@ -69,8 +68,16 @@ static BYTE WINAPI PS2ReadPort(USHORT Port) { if (Port == PS2_CONTROL_PORT) { - /* Be sure bit 2 is always set */ - StatusRegister |= 1 << 2; + /* + * Be sure bit 4 "Keyboard enable flag" is always set. + * Keyboard enable (or keyboard lock) flag values are: + * 0: Locked; 1: Not locked. + * On IBM PC-ATs this is the state of the hardware keyboard + * lock mechanism. It is not widely used, but some programs + * still use it: see for example: + * http://www.os2museum.com/wp/the-dos-4-0-shell-mouse-mystery/ + */ + StatusRegister |= (1 << 4); // FIXME: Should clear bits 6 and 7 because there are // no timeouts and no parity errors. @@ -220,6 +227,31 @@ static VOID WINAPI PS2WritePort(USHORT Port, BYTE Data) case 0x60: { ControllerConfig = Data; + + /* + * Update bit 2 "System flag" of the status register + * with bit 2 of the controller configuration byte. + * See: http://www.win.tue.nl/~aeb/linux/kbd/scancodes-11.html#kccb2 + * for more details. + */ + if (ControllerConfig & (1 << 2)) + StatusRegister |= (1 << 2); + else + StatusRegister &= ~(1 << 2); + + /* + * Update bit 4 "Keyboard enable flag" of the status register + * with bit 3 "Ignore keyboard lock" of the controller + * configuration byte (if set), then reset the latter one. + * See: http://www.win.tue.nl/~aeb/linux/kbd/scancodes-11.html#kccb3 + * for more details. + */ + if (ControllerConfig & (1 << 3)) + { + StatusRegister |= (1 << 4); + ControllerConfig &= ~(1 << 3); + } + break; } @@ -399,13 +431,13 @@ Done: BOOLEAN PS2Initialize(VOID) { /* Initialize the PS/2 ports */ - Ports[0].IsEnabled = TRUE; + Ports[0].IsEnabled = FALSE; Ports[0].QueueEmpty = TRUE; Ports[0].QueueStart = 0; Ports[0].QueueEnd = 0; Ports[0].QueueMutex = CreateMutex(NULL, FALSE, NULL); - Ports[1].IsEnabled = TRUE; + Ports[1].IsEnabled = FALSE; Ports[1].QueueEmpty = TRUE; Ports[1].QueueStart = 0; Ports[1].QueueEnd = 0;