https://git.reactos.org/?p=reactos.git;a=commitdiff;h=ffbc81fdf2f8c203d28cb554605a6a099a916265

commit ffbc81fdf2f8c203d28cb554605a6a099a916265
Author:     Dmitry Borisov <[email protected]>
AuthorDate: Tue Jul 25 22:12:08 2023 +0600
Commit:     Stanislav Motylkov <[email protected]>
CommitDate: Sat Aug 5 16:40:13 2023 +0300

    [FREELDR] Implement bus mouse detection
    
    This allows to automatically install the inport device driver
    (it's now possible since 7d5e1591313), which can be used on 86Box.
    
    References:
    - 
https://raw.githubusercontent.com/86Box/86Box/master/src/device/mouse_bus.c
    - https://bochs.sourceforge.io/cgi-bin/lxr/source/iodev/busmouse.cc
---
 boot/freeldr/freeldr/arch/i386/irqsup.S    |  33 +++++
 boot/freeldr/freeldr/arch/i386/pc/machpc.c | 214 +++++++++++++++++++++++++++++
 boot/freeldr/freeldr/pcat.cmake            |   1 +
 3 files changed, 248 insertions(+)

diff --git a/boot/freeldr/freeldr/arch/i386/irqsup.S 
b/boot/freeldr/freeldr/arch/i386/irqsup.S
new file mode 100644
index 00000000000..7c35ef383ec
--- /dev/null
+++ b/boot/freeldr/freeldr/arch/i386/irqsup.S
@@ -0,0 +1,33 @@
+/*
+ * PROJECT:     FreeLoader
+ * LICENSE:     GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
+ * PURPOSE:     Interrupt handling
+ * COPYRIGHT:   Copyright 2023 Dmitry Borisov <[email protected]>
+ */
+
+#include <asm.inc>
+
+#define PIC1_CONTROL_PORT   HEX(20)
+#define PIC_EOI             HEX(20)
+
+.code32
+
+PUBLIC _HwIrqHandler
+_HwIrqHandler:
+    push ax
+
+    /* Increment the interrupt count */
+    inc dword ptr ds:[_HwIrqCount]
+
+    /* Dismiss the interrupt */
+    mov al, PIC_EOI
+    out PIC1_CONTROL_PORT, al
+
+    pop ax
+    iret
+
+PUBLIC _HwIrqCount
+_HwIrqCount:
+    .long 0
+
+END
diff --git a/boot/freeldr/freeldr/arch/i386/pc/machpc.c 
b/boot/freeldr/freeldr/arch/i386/pc/machpc.c
index f20fa2b9a52..4bef802f667 100644
--- a/boot/freeldr/freeldr/arch/i386/pc/machpc.c
+++ b/boot/freeldr/freeldr/arch/i386/pc/machpc.c
@@ -38,6 +38,20 @@ DBG_DEFAULT_CHANNEL(HWDETECT);
 /* Mouse Systems Mouse */
 #define MOUSE_TYPE_MOUSESYSTEMS    4
 
+#define INPORT_REGISTER_CONTROL    0x00
+#define INPORT_REGISTER_DATA       0x01
+#define INPORT_REGISTER_SIGNATURE  0x02
+
+#define INPORT_REG_MODE            0x07
+#define INPORT_RESET               0x80
+#define INPORT_MODE_BASE           0x10
+#define INPORT_TEST_IRQ            0x16
+#define INPORT_SIGNATURE           0xDE
+
+#define PIC1_CONTROL_PORT          0x20
+#define PIC1_DATA_PORT             0x21
+#define PIC2_CONTROL_PORT          0xA0
+#define PIC2_DATA_PORT             0xA1
 
 /* PS2 stuff */
 
@@ -1291,6 +1305,203 @@ DetectPS2Mouse(PCONFIGURATION_COMPONENT_DATA BusKey)
     }
 }
 
+#if defined(_M_IX86)
+static VOID
+CreateBusMousePeripheralKey(
+    _Inout_ PCONFIGURATION_COMPONENT_DATA BusKey,
+    _In_ ULONG IoBase,
+    _In_ ULONG Irq)
+{
+    PCM_PARTIAL_RESOURCE_LIST PartialResourceList;
+    PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptor;
+    PCONFIGURATION_COMPONENT_DATA ControllerKey;
+    PCONFIGURATION_COMPONENT_DATA PeripheralKey;
+    ULONG Size;
+
+    /* Set 'Configuration Data' value */
+    Size = FIELD_OFFSET(CM_PARTIAL_RESOURCE_LIST, PartialDescriptors[2]);
+    PartialResourceList = FrLdrHeapAlloc(Size, TAG_HW_RESOURCE_LIST);
+    if (PartialResourceList == NULL)
+    {
+        ERR("Failed to allocate resource descriptor\n");
+        return;
+    }
+
+    /* Initialize resource descriptor */
+    RtlZeroMemory(PartialResourceList, Size);
+    PartialResourceList->Version = 1;
+    PartialResourceList->Revision = 1;
+    PartialResourceList->Count = 2;
+
+    /* Set IO Port */
+    PartialDescriptor = &PartialResourceList->PartialDescriptors[0];
+    PartialDescriptor->Type = CmResourceTypePort;
+    PartialDescriptor->ShareDisposition = CmResourceShareDeviceExclusive;
+    PartialDescriptor->Flags = CM_RESOURCE_PORT_IO;
+    PartialDescriptor->u.Port.Start.LowPart = IoBase;
+    PartialDescriptor->u.Port.Start.HighPart = 0;
+    PartialDescriptor->u.Port.Length = 4;
+
+    /* Set Interrupt */
+    PartialDescriptor = &PartialResourceList->PartialDescriptors[1];
+    PartialDescriptor->Type = CmResourceTypeInterrupt;
+    PartialDescriptor->ShareDisposition = CmResourceShareUndetermined;
+    PartialDescriptor->Flags = CM_RESOURCE_INTERRUPT_LATCHED;
+    PartialDescriptor->u.Interrupt.Level = Irq;
+    PartialDescriptor->u.Interrupt.Vector = Irq;
+    PartialDescriptor->u.Interrupt.Affinity = (KAFFINITY)-1;
+
+    /* Create controller key */
+    FldrCreateComponentKey(BusKey,
+                           ControllerClass,
+                           PointerController,
+                           Input,
+                           0,
+                           0xFFFFFFFF,
+                           NULL,
+                           PartialResourceList,
+                           Size,
+                           &ControllerKey);
+
+    /* Set 'Configuration Data' value */
+    Size = FIELD_OFFSET(CM_PARTIAL_RESOURCE_LIST, PartialDescriptors);
+    PartialResourceList = FrLdrHeapAlloc(Size, TAG_HW_RESOURCE_LIST);
+    if (PartialResourceList == NULL)
+    {
+        ERR("Failed to allocate resource descriptor\n");
+        return;
+    }
+
+    /* Initialize resource descriptor */
+    RtlZeroMemory(PartialResourceList, Size);
+    PartialResourceList->Version = 1;
+    PartialResourceList->Revision = 1;
+    PartialResourceList->Count = 0;
+
+    /* Create peripheral key */
+    FldrCreateComponentKey(ControllerKey,
+                           ControllerClass,
+                           PointerPeripheral,
+                           Input,
+                           0,
+                           0xFFFFFFFF,
+                           "MICROSOFT INPORT MOUSE",
+                           PartialResourceList,
+                           Size,
+                           &PeripheralKey);
+}
+
+extern KIDTENTRY DECLSPEC_ALIGN(4) i386Idt[32];
+VOID __cdecl HwIrqHandler(VOID);
+extern volatile ULONG HwIrqCount;
+
+static ULONG
+DetectBusMouseTestIrq(
+    _In_ ULONG IoBase,
+    _In_ ULONG Irq)
+{
+    USHORT OldOffset, OldExtendedOffset;
+    ULONG Vector, i;
+
+    HwIrqCount = 0;
+
+    /* Reset the device */
+    WRITE_PORT_UCHAR((PUCHAR)IoBase + INPORT_REGISTER_CONTROL, INPORT_RESET);
+    WRITE_PORT_UCHAR((PUCHAR)IoBase + INPORT_REGISTER_CONTROL, 
INPORT_REG_MODE);
+
+    Vector = Irq + 8;
+
+    /* Save the old interrupt vector and replace it by ours */
+    OldOffset = i386Idt[Vector].Offset;
+    OldExtendedOffset = i386Idt[Vector].ExtendedOffset;
+
+    i386Idt[Vector].Offset = (ULONG)HwIrqHandler & 0xFFFF;
+    i386Idt[Vector].ExtendedOffset = (ULONG)HwIrqHandler >> 16;
+
+    /* Enable the requested IRQ on the master PIC */
+    WRITE_PORT_UCHAR((PUCHAR)PIC1_DATA_PORT, ~(1 << Irq));
+
+    _enable();
+
+    /* Configure the device to generate interrupts */
+    for (i = 0; i < 15; i++)
+    {
+        WRITE_PORT_UCHAR((PUCHAR)IoBase + INPORT_REGISTER_DATA, 
INPORT_MODE_BASE);
+        WRITE_PORT_UCHAR((PUCHAR)IoBase + INPORT_REGISTER_DATA, 
INPORT_TEST_IRQ);
+    }
+
+    /* Disable the device */
+    WRITE_PORT_UCHAR((PUCHAR)IoBase + INPORT_REGISTER_DATA, 0);
+
+    _disable();
+
+    i386Idt[Vector].Offset = OldOffset;
+    i386Idt[Vector].ExtendedOffset = OldExtendedOffset;
+
+    return (HwIrqCount != 0) ? Irq : 0;
+}
+
+static ULONG
+DetectBusMouseIrq(
+    _In_ ULONG IoBase)
+{
+    UCHAR Mask1, Mask2;
+    ULONG Irq, Result;
+
+    /* Save the current interrupt mask */
+    Mask1 = READ_PORT_UCHAR(PIC1_DATA_PORT);
+    Mask2 = READ_PORT_UCHAR(PIC2_DATA_PORT);
+
+    /* Mask the interrupts on the slave PIC */
+    WRITE_PORT_UCHAR(PIC2_DATA_PORT, 0xFF);
+
+    /* Process IRQ detection: IRQ 5, 4, 3 */
+    for (Irq = 5; Irq >= 3; Irq--)
+    {
+        Result = DetectBusMouseTestIrq(IoBase, Irq);
+        if (Result != 0)
+            break;
+    }
+
+    /* Restore the mask */
+    WRITE_PORT_UCHAR(PIC1_DATA_PORT, Mask1);
+    WRITE_PORT_UCHAR(PIC2_DATA_PORT, Mask2);
+
+    return Result;
+}
+
+static VOID
+DetectBusMouse(
+    _Inout_ PCONFIGURATION_COMPONENT_DATA BusKey)
+{
+    ULONG IoBase, Irq, Signature1, Signature2, Signature3;
+
+    /*
+     * The bus mouse lives at one of these addresses: 0x230, 0x234, 0x238, 
0x23C.
+     * The 0x23C port is the most common I/O setting.
+     */
+    for (IoBase = 0x23C; IoBase >= 0x230; IoBase -= 4)
+    {
+        Signature1 = READ_PORT_UCHAR((PUCHAR)IoBase + 
INPORT_REGISTER_SIGNATURE);
+        Signature2 = READ_PORT_UCHAR((PUCHAR)IoBase + 
INPORT_REGISTER_SIGNATURE);
+        if (Signature1 == Signature2)
+            continue;
+        if (Signature1 != INPORT_SIGNATURE && Signature2 != INPORT_SIGNATURE)
+            continue;
+
+        Signature3 = READ_PORT_UCHAR((PUCHAR)IoBase + 
INPORT_REGISTER_SIGNATURE);
+        if (Signature1 != Signature3)
+            continue;
+
+        Irq = DetectBusMouseIrq(IoBase);
+        if (Irq == 0)
+            continue;
+
+        CreateBusMousePeripheralKey(BusKey, IoBase, Irq);
+        break;
+    }
+}
+#endif /* _M_IX86 */
 
 // Implemented in pcvesa.c, returns the VESA version
 USHORT  BiosIsVesaSupported(VOID);
@@ -1393,6 +1604,9 @@ DetectIsaBios(PCONFIGURATION_COMPONENT_DATA SystemKey, 
ULONG *BusNumber)
     DetectParallelPorts(BusKey);
     DetectKeyboardController(BusKey);
     DetectPS2Mouse(BusKey);
+#if defined(_M_IX86)
+    DetectBusMouse(BusKey);
+#endif
     DetectDisplayController(BusKey);
 
     /* FIXME: Detect more ISA devices */
diff --git a/boot/freeldr/freeldr/pcat.cmake b/boot/freeldr/freeldr/pcat.cmake
index 24c8e3627f0..5ea6f9b8aa7 100644
--- a/boot/freeldr/freeldr/pcat.cmake
+++ b/boot/freeldr/freeldr/pcat.cmake
@@ -42,6 +42,7 @@ if(ARCH STREQUAL "i386")
         arch/i386/drvmap.S
         arch/i386/entry.S
         arch/i386/int386.S
+        arch/i386/irqsup.S
         arch/i386/pnpbios.S
         # arch/i386/i386trap.S
         arch/i386/linux.S)

Reply via email to