Newer
Older
AMI-Aptio-BIOS-Reversed / MdeModulePkg / Universal / Console / ConSplitterDxe / ConSplitter.c
@Ajax Dong Ajax Dong 2 days ago 73 KB Full restructure
/**
 * @file ConSplitter.c
 * @brief AMI Console Splitter Driver Implementation
 *
 * Source: AmiModulePkg\Console\ConSplitter\ConSplit.c
 * Binary: ConSplitter.efi (from HR650X BIOS)
 *
 * This driver implements a console multiplexer. It registers three
 * UEFI driver binding protocols to aggregate multiple physical console
 * devices into single logical console handles for ConOut, ConIn, and
 * StdErr.
 */

#include "ConSplitter.h"

//
// ======================================================================
// SECTION 1: Global Data (.data section)
// ======================================================================
//
// The following globals are defined in the .data section of
// ConSplitter.efi (0x5C20 - 0x6220 range).
//

//
// Driver binding protocol instances (installed via InstallMultipleProtocolInterfaces)
//
// Text Out driver binding:
//   off_5E98 = protocol GUID array
//   off_5E80 = driver binding protocol structure
// Text In driver binding:
//   off_5D68 = protocol GUID array
//   off_5E68 = driver binding protocol structure
// Pointer driver binding:
//   off_5DB0 = protocol GUID array
//   off_5E50 = driver binding protocol structure
//

//
// Protocol GUIDs referenced from .rdata
//
// unk_5C20 = EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL GUID
// unk_5C70 = EFI_GRAPHICS_OUTPUT_PROTOCOL GUID
// unk_5CA0 = EFI_DEVICE_PATH_PROTOCOL GUID
// unk_5CC0 = EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL GUID
// unk_5CB0 = (secondary text output mode protocol)
// unk_5CD0 = EFI_UGA_DRAW_PROTOCOL GUID (or GOP mode protocol)
// unk_5C90 = EFI_SIMPLE_POINTER_PROTOCOL GUID
// unk_5D00 = (text output mode protocol alt)
// unk_5D50 = EFI_ABSOLUTE_POINTER_PROTOCOL GUID
// unk_5D40 = gEfiConsoleOutDeviceGuid
// unk_5CF0 = EFI_HII_DATABASE_PROTOCOL GUID
// unk_5C40 = EFI_SERIAL_IO_PROTOCOL GUID (or debug port)
// unk_5C30 = gEfiGlobalVariableGuid (for "ConOutDev"/"ConInDev" UEFI vars)
// unk_5D20 = gEfiConsoleControlGuid or gEfiSimpleTextOutProtocolGuid for HOB matching
// unk_6010 / unk_6020 = DebugLib protocol GUIDs
//

//
// System table and boot services cached globally
//
UINT64                gImageHandle    = 0;    // 0x6118
UINT64                gSystemTable    = 0;    // 0x6108
UINT64                gBootServices   = 0;    // 0x6110
UINT64                gRuntimeServices = 0;   // 0x6120

//
// Module-level cached pointers
//
UINT64                gBootServicesLocal   = 0;    // 0x6138
UINT64                gRuntimeServicesLocal = 0;   // 0x6140
UINT64                gSystemTableLocal    = 0;    // 0x6148

//
// Cached image handles for each driver binding
//
UINT64                gImageHandleTextOut   = 0;    // 0x5EB8 (ImageHandle_0)
UINT64                gImageHandleTextIn    = 0;    // 0x5D88 (ImageHandle_1)
UINT64                gImageHandlePointer   = 0;    // 0x5DD0 (ImageHandle_2)

//
// Text Out state
//
VOID                 *gConSplitterTextOutPrivate = NULL;  // 0x6070 (qword_6070)
UINT64                gConSplitterTextOutActiveCount = 0; // 0x61E0 (p_n0xA = active count)
UINT64                gConSplitterTextOutModeData = 0;   // 0x5EC0

//
// Text In state
//
VOID                 *gConSplitterTextInPrivate = NULL;   // 0x5D90
UINT64                gConSplitterTextInActiveCount = 0;  // 0x61A0 (n0xA = active count)
UINT64                gConSplitterTextInCountVar2 = 0;    // 0x61C0 (n0xA_2)

//
// Pointer state
//
UINT64                gConSplitterPointerActiveCount = 0;   // 0x6200 (n0xA_0)
UINT64                gConSplitterPointerCountVar2 = 0;     // 0x61E8 (i count)
UINT64                gConSplitterPointerCountVar3 = 0;     // 0x6208 (i_0 count)
UINT64                gConSplitterAbsPointerActiveCount = 0; // 0x61A8 (j count)
UINT64                gConSplitterAbsPointerCountVar2 = 0;  // 0x6188 (j_0 count)

//
// Linked list anchors for child devices
//
// Text Out children: anchored at gConSplitterTextOutChildren
UINT64                gTextOutChildList[2];   // 0x61E8 (i, i_1)
UINT64                gTextOutChildList2[2];  // 0x6208 (i_0, i_1_2)

// Text In children
UINT64                gTextInChildList[2];     // 0x61A0 (j, j_1)
UINT64                gTextInChildList2[2];    // 0x61C0 / 0x61A8 / 0x6188

//
// Mode management
//
UINT32                gConSplitterModeCount   = 0;    // 0x605C (dword_605C)
UINT32                gConSplitterCurrentMode = 0;    // 0x6100 (dword_6100)
UINT32                gConSplitterGlobalMode  = 0;    // 0x5FF4 (dword_5FF4)
UINT32                gConSplitterModeTableSize = 0;  // 0x5FF0 (dword_5FF0)

//
// Mode table (9 bytes per entry: columns(4) + rows(4) + valid(1))
//
VOID                 *gConSplitterModeTable   = NULL;  // 0x60D0 (qword_60D0)

//
// Text buffer pointers (double-buffered for scrollback)
//
VOID                 *gConSplitterTextBuffer  = NULL;  // 0x60C8 (src / qword_60C8)
VOID                 *gConSplitterTextAttrib  = NULL;  // 0x60D8 (src_0 / qword_60D8)
VOID                 *gConSplitterTextBufEnd  = NULL;  // 0x60B8 (src_1 / qword_60B8)
VOID                 *gConSplitterTextBufDst  = NULL;  // 0x60F8 (dst / qword_60F8)
VOID                 *gConSplitterTextBufDstAttr = NULL; // 0x60F0 (dst_0 / qword_60F0)

//
// Cursor and display state
//
UINT32                gConSplitterCursorColumn = 0;    // low part of n15
UINT32                gConSplitterCursorRow    = 0;    // high part of n15
UINT32                gConSplitterRows         = 0;    // n0x19
UINT32                gConSplitterColumns      = 0;    // n80
UINT32                gConSplitterDefaultAttr  = 0;    // qword_5FF8 (n15)

//
// Reentrancy guards (nested call protection)
//
UINT8                 gConSplitterTextOutRecursionCount = 0;  // 0x6040 (byte_6040)
UINT8                 gConSplitterTextOutBlockedFlag    = 0;  // 0x6041 (byte_6041)
UINT8                 gConSplitterTextOutRecursionFlag  = 0;  // 0x6042 (byte_6042)
UINT8                 gConSplitterPointerRecursionCount = 0;  // 0x6058 (byte_6058)
UINT8                 gConSplitterPointerBlockedFlag    = 0;  // 0x606C (byte_606C)

//
// Text In blocked state
//
UINT8                 gConSplitterTextInBlocked  = 0;    // 0x6059 (byte_6059)
UINT8                 gConSplitterTextInBlocked2 = 0;    // 0x6179 (byte_6179)
UINT8                 gConSplitterKeyboardLayoutValid = 0; // 0x607E (byte_607E)

//
// Attribute / cursor visibility
//
UINT8                 gConSplitterCursorVisible = 0;    // 0x6004 (byte_6004)
UINT8                 gConSplitterBufferClean   = 0;    // 0x6008 (byte_6008)

//
// Keyboard LED state (low 2 bits = Scroll Lock state)
//
UINT8                 gConSplitterLedState      = 0;    // 0x5D60 (byte_5D60)
UINT8                 gConSplitterLedStateMask  = 0;    // 0x5D61 (byte_5D61)

//
// Debug output mask (determines which debug level messages print)
//
UINT32                gConSplitterDebugMask     = 0;    // 0x5FFC

//
// HII protocol handle (keyboard layout database)
//
UINT64                gConSplitterHiiHandle     = 0;    // 0x6048 (qword_6048)
UINT64                gConSplitterKeyboardLayout = 0;   // 0x6060 (qword_6060)

//
// HOB list handle
//
UINT64                gConSplitterHobListHandle = 0;    // 0x6130 (qword_6130)

//
// DebugLib protocol handles
//
UINT64                gConSplitterDebugProtocol = 0;    // 0x6128 (qword_6128)
UINT64                gConSplitterDebugProtocol2 = 0;   // 0x6140 / 0x6168 / 0x6158

//
// Key notification state
//
UINT16                gConSplitterLastKeyScan   = 0;    // 0x6078 (word_6078)
UINT16                gConSplitterSavedKeyIndex = 0xFFFF; // 0x5E40 (word_5E40)

//
// Key filter table (8 entries, 12 bytes each)
//
// Each entry has: ScanCode(2) + UnicodeChar(2) + ShiftState(4) + Reserved(4)
// These define which key combinations the splitter intercepts for
// special handling (e.g. hotkeys for console switching).
//
UINT8                 gConSplitterKeyFilter[8 * 12];    // 0x5DE0 (word_5DE0)

//
// Key filter override flags (1 byte per filter entry)
// Set to 1 when a default notification handler is overridden.
//
UINT8                 gConSplitterKeyFilterOverride[8]; // 0x6050 (byte_6050)

//
// Text In keyboard self-test state
//
UINT8                 gConSplitterKeyboardTestPassed = 0; // 0x6068 (dword_6068, but used as byte)
UINT8                 gConSplitterTestModeActive = 0;     // 0x6041 (byte_6041) - shared with blocked flag

//
// Timer event for keyboard polling
//
UINT64                gConSplitterTimerEvent    = 0;    // 0x5EC0 area

//
// Resolution scaling factors
//
UINT32                gConSplitterScaleX        = 0;    // 0x5F80 (dword_5F80)
UINT32                gConSplitterScaleY        = 0;    // 0x5F88 (dword_5F88)
UINT32                gConSplitterScaleZ        = 0;    // 0x5F90 (dword_5F90)

//
// Resolution mode tracking data (off_5F10)
//
UINT64                gConSplitterResolutionModeData[6] = {0}; // 0x5F10

//
// Notification events
//
VOID                 *gConSplitterConOutNotifyEvent   = NULL; // 0x5EE8
VOID                 *gConSplitterConInNotifyEvent    = NULL;
VOID                 *gConSplitterStdErrNotifyEvent   = NULL;
VOID                 *gConSplitterConOutNotifyReg     = NULL; // 0x5F18
VOID                 *gConSplitterConInNotifyReg      = NULL; // 0x5F30
VOID                 *gConSplitterStdErrNotifyReg     = NULL; // 0x5F60

//
// Protocol interface pointers (installed on system table)
//
VOID                 *gConSplitterConOutInterface     = NULL; // off_5FA0
VOID                 *gConSplitterConInInterface      = NULL; // off_5F18
VOID                 *gConSplitterStdErrInterface     = NULL; // off_5F30

//
// Resolution change notification structures
//
UINT64                gConSplitterResolutionEvent     = 0;    // 0x5F70 (off_5F70)

//
// ======================================================================
// SECTION 2: Library Helpers
// ======================================================================
//

/**
 * Initialize HII database protocol handle for keyboard layout access.
 * Locates gEfiHiiDatabaseProtocolGuid via the boot services table.
 */
STATIC
EFI_STATUS
ConSplitterInitializeHiiProtocol (
    VOID
    )
{
    if (gConSplitterHiiHandle == 0) {
        return gBS->LocateProtocol (
                        &gEfiHiiDatabaseProtocolGuid,
                        NULL,
                        &gConSplitterHiiHandle
                        );
    }
    return EFI_SUCCESS;
}

//
// ======================================================================
// SECTION 3: Text Out Protocol Implementation
// ======================================================================
//

/**
 * ConSplitterTextOutReset
 * Address: 0x43A4 (sub_43A4)
 *
 * Resets all active text output child devices.
 * Iterates the linked list of text output devices, calling Reset on each.
 * Then clears the text buffer and resets mode tracking.
 */
EFI_STATUS
EFIAPI
ConSplitterTextOutReset (
    IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL   *This,
    IN BOOLEAN                           ExtendedVerification
    )
{
    TEXT_OUT_NODE                   *Node;
    EFI_STATUS                       Status;
    EFI_STATUS                       ReturnStatus;
    EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL **ChildProtocol;

    Node = gTextOutChildren;
    ReturnStatus = EFI_SUCCESS;

    if (Node != NULL) {
        do {
            if (Node->Active) {
                Status = Node->PrivateData->Reset (
                            Node->PrivateData,
                            ExtendedVerification
                            );
                if (EFI_ERROR(Status)) {
                    ReturnStatus = Status;
                }
            }
            Node = Node->ForwardLink;
        } while (Node != NULL);

        // Update mode state from current mode table
        ConSplitterUpdateModeState ();
    } else {
        // No children - reset to defaults
        gConSplitterCursorColumn = 0;
        gConSplitterCursorRow = 0;
        gConSplitterColumns = 80;
        gConSplitterRows = 25;
    }

    // Clear internal text buffer
    ConSplitterClearTextBuffer ();

    return ReturnStatus;
}

/**
 * ConSplitterTextOutOutputString
 * Address: 0x4434 (sub_4434)
 *
 * Outputs a Unicode string to all active text output child devices.
 * Also writes the string into the internal scrollback buffer.
 * Handles backspace (8), newline (10), carriage return (13) specially.
 */
EFI_STATUS
EFIAPI
ConSplitterTextOutOutputString (
    IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL   *This,
    IN CHAR16                            *String
    )
{
    TEXT_OUT_NODE                   *Node;
    EFI_STATUS                       Status;
    EFI_STATUS                       ReturnStatus;
    UINTN                            CursorCol;
    UINTN                            CursorRow;
    UINTN                            RowCount;
    CHAR16                          *BufferPos;
    UINT32                          *AttribPos;
    UINTN                            Cols;
    UINTN                            VOffset;
    CHAR16                           Char;

    Cols = gConSplitterColumns;
    RowCount = gConSplitterRows;
    CursorCol = gConSplitterCursorColumn;
    CursorRow = gConSplitterCursorRow;
    ReturnStatus = EFI_SUCCESS;

    // Mark buffer as dirty (needs re-initialization)
    gConSplitterBufferClean = FALSE;

    // Calculate starting position in the scrollback buffer
    VOffset = (CursorRow * Cols) + CursorCol;

    if ((CursorRow * Cols) + CursorCol > 0) {
        VOffset = 0;
    }

    BufferPos = &gConSplitterTextBuffer[2 * VOffset];
    AttribPos = &gConSplitterTextAttrib[4 * VOffset];

    Char = *String;
    if (Char == 0) {
        return EFI_SUCCESS;
    }

    while (Char != 0) {
        if (Char == L'\b') {
            // Backspace
            if (CursorCol > 0) {
                BufferPos -= 2;
                AttribPos -= 4;
                CursorCol--;
            }
        } else if (Char == L'\n') {
            // Newline
            if ((UINTN)(BufferPos + 2) >= (UINTN)gConSplitterTextBufEnd) {
                ConSplitterScrollTextBufferOneLine ();
                // Recalculate position after scroll
                CursorCol = 0;
            } else {
                CursorRow++;
                CursorCol = 0;
            }
        } else if (Char == L'\r') {
            // Carriage return
            CursorCol = 0;
        } else {
            // Normal character
            if (BufferPos + 2 >= gConSplitterTextBufEnd) {
                ConSplitterScrollTextBufferOneLine ();
                // Recalculate position
                CursorCol = 0;
            } else {
                // Write character to buffer
                *(CHAR16 *)BufferPos = Char;
                BufferPos += 2;
                *(UINT32 *)AttribPos = gConSplitterDefaultAttr;
                AttribPos += 4;
                CursorCol++;

                if (CursorCol >= Cols) {
                    CursorRow++;
                    CursorCol = 0;
                }
            }
        }

        String++;
        Char = *String;
    }

    // Update global cursor position
    gConSplitterCursorColumn = (UINT32)CursorCol;
    gConSplitterCursorRow = (UINT32)CursorRow + RowCount;
    gConSplitterBufferClean = FALSE;  // will be recalculated

    // Now dispatch to all active child devices
    Node = gConOutTextChildren;
    while (Node != NULL) {
        if (Node->Active) {
            // Re-output to this device
            // (In the original code this processes each string
            //  by resetting cursor position and dispatching)
            Status = Node->PrivateData->OutputString (
                        Node->PrivateData,
                        String
                        );
            if (EFI_ERROR(Status)) {
                ReturnStatus = Status;
            }
        }
        Node = Node->ForwardLink;
    }

    // Update mode state
    ConSplitterUpdateModeState ();

    return ReturnStatus;
}

/**
 * ConSplitterTextOutTestString
 * Address: 0x45E8 (sub_45E8)
 *
 * Tests whether a string can be displayed on all active text out devices.
 */
EFI_STATUS
EFIAPI
ConSplitterTextOutTestString (
    IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL   *This,
    IN CHAR16                            *String
    )
{
    TEXT_OUT_NODE                   *Node;
    EFI_STATUS                       Status;
    EFI_STATUS                       ReturnStatus;

    Node = gConOutTextChildren;
    ReturnStatus = EFI_SUCCESS;

    if (Node == NULL) {
        return EFI_SUCCESS;
    }

    do {
        if (Node->Active) {
            Status = Node->PrivateData->TestString (
                        Node->PrivateData,
                        String
                        );
            if (EFI_ERROR(Status)) {
                ReturnStatus = Status;
            }
        }
        Node = Node->ForwardLink;
    } while (Node != NULL);

    ConSplitterUpdateModeState ();
    return ReturnStatus;
}

/**
 * ConSplitterTextOutQueryMode
 * Address: 0x4888 (sub_4888)
 *
 * Returns the dimensions of a given text mode.
 * If no children are connected, returns default values (80x25).
 */
EFI_STATUS
EFIAPI
ConSplitterTextOutQueryMode (
    IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL   *This,
    IN UINTN                             ModeNumber,
    OUT UINTN                            *Columns,
    OUT UINTN                            *Rows
    )
{
    TEXT_OUT_NODE                   *Node;
    EFI_STATUS                       Status;
    EFI_STATUS                       ReturnStatus;

    Node = gConOutTextChildren;
    ReturnStatus = EFI_SUCCESS;

    if (Node != NULL) {
        do {
            if (Node->Active) {
                Status = Node->PrivateData->QueryMode (
                            Node->PrivateData,
                            ModeNumber,
                            Columns,
                            Rows
                            );
                if (EFI_ERROR(Status)) {
                    ReturnStatus = Status;
                }
            }
            Node = Node->ForwardLink;
        } while (Node != NULL);

        ConSplitterUpdateModeState ();
        return ReturnStatus;
    }

    // No children - return defaults
    if (ModeNumber < 80 && ModeNumber < 25) {
        *Columns = 80;
        *Rows = 25;
        return EFI_SUCCESS;
    }

    *Columns = 0;
    *Rows = 0;
    return EFI_UNSUPPORTED;
}

/**
 * ConSplitterTextOutSetMode
 * Address: 0x46B4 (sub_46B4)
 *
 * Sets the display mode for all active text out children.
 * Selects a new mode entry from the mode table and reconfigures
 * all child devices.
 */
EFI_STATUS
EFIAPI
ConSplitterTextOutSetMode (
    IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL   *This,
    IN UINTN                             ModeNumber
    )
{
    TEXT_OUT_NODE                   *Node;
    EFI_STATUS                       Status;
    EFI_GRAPHICS_OUTPUT_PROTOCOL   *GraphicsOut;
    UINT32                           ModeIndex;

    Node = gConOutTextChildren;

    if (ModeNumber >= gConSplitterModeTableSize ||
        !gConSplitterModeTable[Modes].Valid) {
        return EFI_UNSUPPORTED;
    }

    if (ModeNumber == gConSplitterGlobalMode) {
        // Already in this mode
        ConSplitterUpdateCurrentTextOut (Node);
        return EFI_SUCCESS;
    }

    if (Node == NULL) {
        return EFI_SUCCESS;
    }

    // Re-allocate and fill the mode table from this mode
    Status = ConSplitterReconstructModeTable (ModeNumber);
    if (EFI_ERROR(Status)) {
        return Status;
    }

    gConSplitterGlobalMode = (UINT32)ModeNumber;

    // Update each child's mode
    do {
        ModeIndex = ConSplitterFindMatchingMode (Node->PrivateData, ModeNumber);
        if (ModeIndex != (UINT32)-1) {
            Status = Node->PrivateData->SetMode (
                        Node->PrivateData,
                        ModeIndex
                        );
            if (!EFI_ERROR(Status)) {
                Node->Active = TRUE;
            } else {
                Node->Active = FALSE;
            }
        } else {
            Node->Active = FALSE;
        }

        Node = Node->ForwardLink;
    } while (Node != NULL);

    ConSplitterUpdateModeState ();
    ConSplitterSetResolutionData ();

    return Status;
}

/**
 * ConSplitterTextOutSetAttribute
 * Address: 0x479C (sub_479C)
 *
 * Sets the text attribute on all active child devices.
 */
EFI_STATUS
EFIAPI
ConSplitterTextOutSetAttribute (
    IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL   *This,
    IN UINTN                             Attribute
    )
{
    TEXT_OUT_NODE                   *Node;
    EFI_STATUS                       Status;
    EFI_STATUS                       ReturnStatus;

    Node = gConOutTextChildren;
    ReturnStatus = EFI_SUCCESS;

    if (Node == NULL) {
        return EFI_SUCCESS;
    }

    gConSplitterDefaultAttr = (UINT32)Attribute;

    do {
        if (Node->Active) {
            Status = Node->PrivateData->SetAttribute (
                        Node->PrivateData,
                        Attribute
                        );
            if (EFI_ERROR(Status)) {
                ReturnStatus = Status;
            }
        }
        Node = Node->ForwardLink;
    } while (Node != NULL);

    ConSplitterUpdateModeState ();
    return ReturnStatus;
}

/**
 * ConSplitterTextOutClearScreen
 * Address: 0x4810 (sub_4810)
 *
 * Clears the screen on all active text out children.
 */
EFI_STATUS
EFIAPI
ConSplitterTextOutClearScreen (
    IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL   *This
    )
{
    TEXT_OUT_NODE                   *Node;
    EFI_STATUS                       Status;
    EFI_STATUS                       ReturnStatus;

    Node = gConOutTextChildren;
    ReturnStatus = EFI_SUCCESS;

    if (Node != NULL) {
        do {
            if (Node->Active) {
                Status = Node->PrivateData->ClearScreen (
                            Node->PrivateData
                            );
                if (EFI_ERROR(Status)) {
                    ReturnStatus = Status;
                }
            }
            Node = Node->ForwardLink;
        } while (Node != NULL);

        ConSplitterUpdateModeState ();
        return ReturnStatus;
    }

    // No children - reset cursor to origin
    gConSplitterCursorColumn = 0;
    gConSplitterCursorRow = 0;

    ConSplitterClearTextBuffer ();
    return ReturnStatus;
}

/**
 * ConSplitterTextOutSetCursorPosition
 * Address: 0x4888 (sub_4888)
 *
 * Sets cursor position on all active text out children.
 */
EFI_STATUS
EFIAPI
ConSplitterTextOutSetCursorPosition (
    IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL   *This,
    IN UINTN                             Column,
    IN UINTN                             Row
    )
{
    TEXT_OUT_NODE                   *Node;
    EFI_STATUS                       Status;
    EFI_STATUS                       ReturnStatus;

    Node = gConOutTextChildren;
    ReturnStatus = EFI_SUCCESS;

    if (Node != NULL) {
        do {
            if (Node->Active) {
                Status = Node->PrivateData->SetCursorPosition (
                            Node->PrivateData,
                            Column,
                            Row
                            );
                if (EFI_ERROR(Status)) {
                    ReturnStatus = Status;
                }
            }
            Node = Node->ForwardLink;
        } while (Node != NULL);

        ConSplitterUpdateModeState ();
        return ReturnStatus;
    }

    // No children - update local state
    if (Column < 80 && Row < 25) {
        gConSplitterCursorColumn = (UINT32)Column;
        gConSplitterCursorRow = (UINT32)Row;
    }

    return EFI_SUCCESS;
}

/**
 * ConSplitterTextOutEnableCursor
 * Address: 0x4920 (sub_4920)
 *
 * Enables or disables the cursor on all active text out children.
 */
EFI_STATUS
EFIAPI
ConSplitterTextOutEnableCursor (
    IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL   *This,
    IN BOOLEAN                           Visible
    )
{
    TEXT_OUT_NODE                   *Node;
    EFI_STATUS                       Status;
    EFI_STATUS                       ReturnStatus;

    Node = gConOutTextChildren;
    ReturnStatus = EFI_SUCCESS;

    if (Node != NULL) {
        do {
            if (Node->Active) {
                Status = Node->PrivateData->EnableCursor (
                            Node->PrivateData,
                            Visible
                            );
                if (EFI_ERROR(Status)) {
                    ReturnStatus = Status;
                }
            }
            Node = Node->ForwardLink;
        } while (Node != NULL);

        ReturnStatus = ReturnStatus;
    }

    gConSplitterCursorVisible = (UINT8)Visible;
    return ReturnStatus;
}

//
// ======================================================================
// SECTION 4: Text In (Keyboard) Protocol Implementation
// ======================================================================
//

/**
 * ConSplitterTextInReset
 * Address: 0x3710 (sub_3710)
 *
 * Resets all active text input child devices.
 */
EFI_STATUS
EFIAPI
ConSplitterTextInReset (
    IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL    *This,
    IN BOOLEAN                           ExtendedVerification
    )
{
    EFI_STATUS     Status;

    if (gConSplitterTextOutBlockedFlag) {
        return EFI_SPLITTER_PROTOCOL_ERROR;
    }

    Status = ConSplitterPointerResetDispatch (ExtendedVerification);
    return Status;
}

/**
 * ConSplitterTextInReadKeyStroke
 * Address: 0x3514 (sub_3514)
 *
 * Reads a keystroke from any active text input child device.
 * Iterates through all children and returns the first available key.
 */
EFI_STATUS
EFIAPI
ConSplitterTextInReadKeyStroke (
    IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL    *This,
    OUT EFI_KEY_DATA                     *KeyData
    )
{
    TEXT_IN_NODE                    *Node;
    EFI_STATUS                       Status;
    EFI_STATUS                       ReturnStatus;
    UINT8                            SavedRecursion;

    ReturnStatus = EFI_SUCCESS;
    SavedRecursion = gConSplitterPointerRecursionCount;
    gConSplitterPointerRecursionCount++;

    if (gConSplitterTextOutBlockedFlag) {
        gConSplitterPointerRecursionCount = SavedRecursion;
        return EFI_SPLITTER_PROTOCOL_ERROR;
    }

    Node = gConTextInChildren;
    if (Node != NULL) {
        do {
            Status = Node->TextOutInterface->ReadKeyStroke (
                        Node->TextOutInterface,
                        KeyData
                        );
            if (!EFI_ERROR(Status)) {
                gConSplitterPointerRecursionCount = SavedRecursion;
                return EFI_SUCCESS;
            }
            if (Status != EFI_NOT_READY) {
                ReturnStatus = Status;
            }
            Node = Node->ForwardLink;
        } while (Node != NULL);
    }

    gConSplitterPointerRecursionCount = SavedRecursion;
    return ReturnStatus;
}

/**
 * ConSplitterTextInWaitForKey
 * Address: 0x2E38 (sub_2E38)
 *
 * Waits for a keystroke from any child device.
 * Iterates through all children checking for available input.
 */
EFI_STATUS
EFIAPI
ConSplitterTextInWaitForKey (
    IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL    *This
    )
{
    TEXT_IN_NODE                    *Node;
    EFI_STATUS                       Status;
    EFI_STATUS                       ReturnStatus;
    UINT8                            SavedRecursion;

    ReturnStatus = EFI_SUCCESS;
    SavedRecursion = gConSplitterPointerRecursionCount;
    gConSplitterPointerRecursionCount++;

    if (gConSplitterTextOutBlockedFlag) {
        gConSplitterPointerRecursionCount = SavedRecursion;
        return EFI_SPLITTER_PROTOCOL_ERROR;
    }

    Node = gConTextInChildren;
    if (Node != NULL) {
        do {
            Status = Node->TextOutInterface->WaitForKey (Node->TextOutInterface);
            if (!EFI_ERROR(Status)) {
                gConSplitterPointerRecursionCount = SavedRecursion;
                return EFI_SUCCESS;
            }
            if (Status != EFI_NOT_READY) {
                ReturnStatus = Status;
            }
            Node = Node->ForwardLink;
        } while (Node != NULL);
    }

    gConSplitterPointerRecursionCount = SavedRecursion;
    return ReturnStatus;
}

//
// ======================================================================
// SECTION 6: Simple Pointer Protocol Implementation
// ======================================================================
//

/**
 * ConSplitterPointerReset
 * Address: 0x35A8 (sub_35A8)
 *
 * Resets the pointer state by querying the first active child.
 */
EFI_STATUS
EFIAPI
ConSplitterPointerReset (
    IN EFI_SIMPLE_POINTER_PROTOCOL       *This,
    IN BOOLEAN                           ExtendedVerification
    )
{
    EFI_STATUS                       Status;
    EFI_SIMPLE_POINTER_STATE         State;

    if (gConSplitterTextOutBlockedFlag) {
        return EFI_SPLITTER_NOT_READY;
    }

    Status = ConSplitterPointerGetStateInternal (&State);
    if (EFI_ERROR(Status) && Status != EFI_SPLITTER_NOT_READY) {
        return Status;
    }

    return EFI_SUCCESS;
}

/**
 * ConSplitterPointerGetState
 * Address: 0x3764 (sub_3764)
 *
 * Gets the pointer state from all active pointer children.
 * Aggregates relative motion across devices.
 */
EFI_STATUS
EFIAPI
ConSplitterPointerGetState (
    IN EFI_SIMPLE_POINTER_PROTOCOL       *This,
    OUT EFI_SIMPLE_POINTER_STATE         *State
    )
{
    POINTER_NODE                    *Node;
    EFI_STATUS                       Status;
    EFI_SIMPLE_POINTER_STATE         ChildState;
    EFI_STATUS                       ReturnStatus;

    gConSplitterPointerRecursionCount++;

    if (gConSplitterTextOutBlockedFlag) {
        gConSplitterPointerRecursionCount--;
        return EFI_SPLITTER_NOT_READY;
    }

    if (State == NULL) {
        gConSplitterPointerRecursionCount--;
        return EFI_INVALID_PARAMETER;
    }

    Status = ConSplitterPointerGetStateInternal (&ChildState);
    if (!EFI_ERROR(Status)) {
        State->RelativeMovementX = ChildState.RelativeMovementX;
        State->RelativeMovementY = ChildState.RelativeMovementY;
        State->RelativeMovementZ = ChildState.RelativeMovementZ;
        State->LeftButton = ChildState.LeftButton;
        State->RightButton = ChildState.RightButton;
    } else {
        ReturnStatus = Status;
    }

    gConSplitterPointerRecursionCount--;
    return ReturnStatus;
}

//
// ======================================================================
// SECTION 7: Driver Binding Protocol Implementation
// ======================================================================
//

/**
 * ConSplitterTextOutDriverBindingSupported
 * Address: 0x44C (sub_44C) for Text Out; 0x4A8 (sub_4A8) for generic
 *
 * Tests whether the driver supports a given controller.
 * Checks for EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL on the controller.
 */
EFI_STATUS
EFIAPI
ConSplitterTextOutDriverBindingSupported (
    IN EFI_DRIVER_BINDING_PROTOCOL       *This,
    IN EFI_HANDLE                        ControllerHandle,
    IN EFI_DEVICE_PATH_PROTOCOL          *RemainingDevicePath
    )
{
    EFI_STATUS  Status;
    VOID       *TextOutProtocol;

    if (ControllerHandle == NULL ||
        This == NULL ||
        RemainingDevicePath == NULL) {
        return EFI_INVALID_PARAMETER;
    }

    // Check if controller supports text output protocol
    Status = gBS->OpenProtocol (
                    ControllerHandle,
                    &gEfiSimpleTextOutProtocolGuid,
                    &TextOutProtocol,
                    This->DriverBindingHandle,
                    ControllerHandle,
                    EFI_OPEN_PROTOCOL_BY_DRIVER
                    );
    if (EFI_ERROR(Status)) {
        return Status;
    }

    gBS->CloseProtocol (
            ControllerHandle,
            &gEfiSimpleTextOutProtocolGuid,
            This->DriverBindingHandle,
            ControllerHandle
            );

    return EFI_SUCCESS;
}

/**
 * ConSplitterDriverBindingStart
 * Address: 0x1054 (sub_1054) for Text Out
 *          0x10E0 (sub_10E0) for Text Out (w/ mode setup)
 *          0x1398 (sub_1398) for Text In
 *          0x14F8 (sub_14F8) for Text In (w/ extended setup)
 *          0x18A4 (sub_18A4) for Simple Pointer
 *          0x19AC (sub_19AC) for Absolute Pointer
 *
 * Starts the driver on a controller, creating a child device node
 * and adding it to the internal linked list.
 */
EFI_STATUS
EFIAPI
ConSplitterTextOutDriverBindingStart (
    IN EFI_DRIVER_BINDING_PROTOCOL       *This,
    IN EFI_HANDLE                        ControllerHandle,
    IN EFI_DEVICE_PATH_PROTOCOL          *RemainingDevicePath
    )
{
    EFI_STATUS                       Status;
    EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL  *TextOutProtocol;
    EFI_DEVICE_PATH_PROTOCOL        *DevicePath;
    TEXT_OUT_NODE                   *Node;

    // Validate the controller supports text output
    Status = ConSplitterTextOutDriverBindingSupported (
                This,
                ControllerHandle,
                RemainingDevicePath
                );
    if (EFI_ERROR(Status)) {
        return Status;
    }

    // Check if already connected
    Status = ConSplitterTextOutIsDeviceAttached (ControllerHandle);
    if (Status == EFI_ALREADY_STARTED) {
        return EFI_SUCCESS;
    }

    // Open protocol to get the text output interface
    Status = gBS->OpenProtocol (
                    ControllerHandle,
                    &gEfiSimpleTextOutProtocolGuid,
                    &TextOutProtocol,
                    This->DriverBindingHandle,
                    ControllerHandle,
                    EFI_OPEN_PROTOCOL_GET_PROTOCOL
                    );
    if (EFI_ERROR(Status)) {
        return Status;
    }

    // Check for duplicate device path
    Status = gBS->OpenProtocol (
                    ControllerHandle,
                    &gEfiDevicePathProtocolGuid,
                    &DevicePath,
                    This->DriverBindingHandle,
                    ControllerHandle,
                    EFI_OPEN_PROTOCOL_GET_PROTOCOL
                    );
    if (EFI_ERROR(Status)) {
        DevicePath = NULL;
    }

    // Create child device node
    Node = AllocateZeroPool (sizeof (TEXT_OUT_NODE));
    if (Node == NULL) {
        return EFI_OUT_OF_RESOURCES;
    }

    Node->PrivateData = TextOutProtocol;
    Node->DeviceHandle = ControllerHandle;
    Node->Active = TRUE;

    // Insert into linked list of text out children
    ConSplitterTextOutInsertChild (Node);

    // If this is the first child, set up the mode table
    if (gConSplitterTextOutActiveCount == 1) {
        ConSplitterTextOutReconstructModeList (TextOutProtocol);
    }

    // Set up graphics output protocol notification
    ConSplitterSetUpGraphicsOutput (ControllerHandle);

    return EFI_SUCCESS;
}

/**
 * ConSplitterDriverBindingStop
 * Address: 0x11F4 (sub_11F4) for Text Out
 *          0x1750 (sub_1750) for Text In
 *          0x1BB0 (sub_1BB0) for Pointer
 *
 * Stops the driver on a controller, removing the child device node
 * from the internal linked list.
 */
EFI_STATUS
EFIAPI
ConSplitterTextOutDriverBindingStop (
    IN EFI_DRIVER_BINDING_PROTOCOL       *This,
    IN EFI_HANDLE                        ControllerHandle,
    IN UINTN                             NumberOfChildren,
    IN EFI_HANDLE                        *ChildHandleBuffer
    )
{
    TEXT_OUT_NODE                   *Node;
    TEXT_OUT_NODE                   *FoundNode;
    EFI_STATUS                       Status;

    Status = EFI_NOT_FOUND;
    FoundNode = NULL;

    // Find the child node for this controller
    Node = gConTextOutChildren;

    while (Node != NULL) {
        if (Node->DeviceHandle == ControllerHandle) {
            // Close protocols on this handle
            gBS->CloseProtocol (
                    ControllerHandle,
                    &gEfiSimpleTextOutProtocolGuid,
                    This->DriverBindingHandle,
                    ControllerHandle
                    );

            gBS->CloseProtocol (
                    ControllerHandle,
                    &gEfiDevicePathProtocolGuid,
                    This->DriverBindingHandle,
                    ControllerHandle
                    );

            // Remove from linked list
            ConSplitterTextOutRemoveChild (Node);

            // Free the node
            gBS->FreePool (Node);

            Status = EFI_SUCCESS;
            break;
        }
        Node = Node->ForwardLink;
    }

    // Check if we need to update mode state
    if (gConSplitterTextOutActiveCount > 0 ||
        gConSplitterConOutInterface != NULL) {
        if (Status == EFI_SUCCESS && gConSplitterTextOutActiveCount > 0) {
            ConSplitterTextOutReconstructModeList (NULL);
        }
    } else {
        // All children removed - clean up resources
        if (gConSplitterModeTable != NULL) {
            gBS->FreePool (gConSplitterModeTable);
            gConSplitterModeTable = NULL;
        }
        if (gConSplitterTextBuffer != NULL) {
            gBS->FreePool (gConSplitterTextBuffer);
            gConSplitterTextBuffer = NULL;
        }
        if (gConSplitterTextAttrib != NULL) {
            gBS->FreePool (gConSplitterTextAttrib);
            gConSplitterTextAttrib = NULL;
        }
        gConSplitterTextOutBlockedFlag = FALSE;
    }

    return Status;
}

//
// ======================================================================
// SECTION 8: Driver Entry Point
// ======================================================================
//

/**
 * ConSplitterDriverEntryPoint
 * Address: 0xAE4 (sub_AE4)
 *
 * Main entry point for the AMI Console Splitter Driver.
 *
 * Performs the following:
 *   1. Caches the system table, boot services, and runtime services
 *   2. Installs three driver binding protocols:
 *      - Text Out Driver Binding
 *      - Text In Driver Binding
 *      - Pointer Driver Binding
 *   3. Allocates notification event structures for:
 *      - ConOut device arrival notification
 *      - ConIn device arrival notification
 *      - StdErr device arrival notification
 *      - Graphics output mode change notification
 *      - Text input key notification
 *   4. Registers notification handler for Graphics Output Protocol
 *      mode changes
 *   5. Registers protocol notifications for console device arrival
 *   6. Sets up setup variable support
 *   7. Installs the console splitter protocol interfaces into the
 *      system table (ConOut, ConIn, StdErr)
 *   8. Creates a periodic timer for keyboard polling
 *
 * Called from ModuleEntryPoint() at 0x390 which initializes the
 * standard UEFI globals (gImageHandle, gST, gBS, gRT) before
 * delegating to this function.
 */
EFI_STATUS
EFIAPI
ConSplitterDriverEntryPoint (
    IN EFI_HANDLE           ImageHandle,
    IN EFI_SYSTEM_TABLE     *SystemTable
    )
{
    EFI_STATUS  Status;

    //
    // 1. Cache system table pointers
    //
    if (gSystemTableLocal == 0) {
        gSystemTableLocal = (UINT64)SystemTable;
        gBootServicesLocal = (UINT64)SystemTable->BootServices;
        gRuntimeServicesLocal = (UINT64)SystemTable->RuntimeServices;
    }

    //
    // 2. Install Text Out Driver Binding
    //
    gConSplitterTextOutStartPrivate = 0;
    gImageHandleTextOut = (UINT64)ImageHandle;

    Status = EfiLibInstallDriverBindingComponentName2 (
                ImageHandle,
                SystemTable,
                &gConSplitterTextOutDriverBinding,
                ImageHandle,
                &gConSplitterTextOutComponentName,
                NULL
                );
    if (EFI_ERROR(Status)) {
        DEBUG ((EFI_D_ERROR, "ASSERT_EFI_ERROR (Status = %r)\n", Status));
        ASSERT_EFI_ERROR (Status);
    }

    //
    // 3. Install Text In Driver Binding
    //
    gConSplitterTextInStartPrivate = 0;
    gImageHandleTextIn = (UINT64)ImageHandle;

    Status = EfiLibInstallDriverBindingComponentName2 (
                ImageHandle,
                SystemTable,
                &gConSplitterTextInDriverBinding,
                ImageHandle,
                &gConSplitterTextInComponentName,
                NULL
                );
    if (EFI_ERROR(Status)) {
        DEBUG ((EFI_D_ERROR, "ASSERT_EFI_ERROR (Status = %r)\n", Status));
        ASSERT_EFI_ERROR (Status);
    }

    //
    // 4. Install Pointer Driver Binding
    //
    gConSplitterPointerStartPrivate = 0;
    gImageHandlePointer = (UINT64)ImageHandle;

    Status = EfiLibInstallDriverBindingComponentName2 (
                ImageHandle,
                SystemTable,
                &gConSplitterPointerDriverBinding,
                ImageHandle,
                &gConSplitterPointerComponentName,
                NULL
                );
    if (EFI_ERROR(Status)) {
        DEBUG ((EFI_D_ERROR, "ASSERT_EFI_ERROR (Status = %r)\n", Status));
        ASSERT_EFI_ERROR (Status);
    }

    //
    // 5. Allocate ConOut notification event and register protocol notify
    //
    Status = gBS->CreateEvent (
                    EVT_NOTIFY_SIGNAL,
                    TPL_CALLBACK,
                    ConSplitterConOutNotifyHandler,
                    NULL,
                    &gConSplitterConOutNotifyEvent
                    );
    if (EFI_ERROR(Status)) {
        DEBUG ((EFI_D_ERROR, "ASSERT_EFI_ERROR (Status = %r)\n", Status));
        ASSERT_EFI_ERROR (Status);
    }

    Status = gBS->RegisterProtocolNotify (
                    &gEfiSimpleTextOutProtocolGuid,
                    gConSplitterConOutNotifyEvent,
                    &gConSplitterConOutNotifyReg
                    );
    if (EFI_ERROR(Status)) {
        DEBUG ((EFI_D_ERROR, "ASSERT_EFI_ERROR (Status = %r)\n", Status));
        ASSERT_EFI_ERROR (Status);
    }

    //
    // 6. Allocate ConIn notification event
    //
    Status = gBS->CreateEvent (
                    EVT_NOTIFY_SIGNAL,
                    TPL_CALLBACK,
                    ConSplitterConInNotifyHandler,
                    NULL,
                    &gConSplitterConInNotifyEvent
                    );
    if (EFI_ERROR(Status)) {
        DEBUG ((EFI_D_ERROR, "ASSERT_EFI_ERROR (Status = %r)\n", Status));
        ASSERT_EFI_ERROR (Status);
    }

    Status = gBS->RegisterProtocolNotify (
                    &gEfiSimpleTextInProtocolGuid,
                    gConSplitterConInNotifyEvent,
                    &gConSplitterConInNotifyReg
                    );
    if (EFI_ERROR(Status)) {
        DEBUG ((EFI_D_ERROR, "ASSERT_EFI_ERROR (Status = %r)\n", Status));
        ASSERT_EFI_ERROR (Status);
    }

    //
    // 7. Allocate StdErr notification event
    //
    Status = gBS->CreateEvent (
                    EVT_NOTIFY_SIGNAL,
                    TPL_CALLBACK,
                    ConSplitterStdErrNotifyHandler,
                    NULL,
                    &gConSplitterStdErrNotifyEvent
                    );
    if (EFI_ERROR(Status)) {
        DEBUG ((EFI_D_ERROR, "ASSERT_EFI_ERROR (Status = %r)\n", Status));
        ASSERT_EFI_ERROR (Status);
    }

    Status = gBS->RegisterProtocolNotify (
                    &gEfiSimpleTextOutProtocolGuid,
                    gConSplitterStdErrNotifyEvent,
                    &gConSplitterStdErrNotifyReg
                    );
    if (EFI_ERROR(Status)) {
        DEBUG ((EFI_D_ERROR, "ASSERT_EFI_ERROR (Status = %r)\n", Status));
        ASSERT_EFI_ERROR (Status);
    }

    //
    // 8. Allocate GOP mode change notification event
    //
    Status = gBS->CreateEvent (
                    EVT_NOTIFY_SIGNAL,
                    TPL_CALLBACK,
                    ConSplitterGraphicsOutputNotify,
                    NULL,
                    &gConSplitterResolutionEvent
                    );
    if (EFI_ERROR(Status)) {
        DEBUG ((EFI_D_ERROR, "ASSERT_EFI_ERROR (Status = %r)\n", Status));
        ASSERT_EFI_ERROR (Status);
    }

    Status = gBS->RegisterProtocolNotify (
                    &gEfiGraphicsOutputProtocolGuid,
                    gConSplitterResolutionEvent,
                    &gConSplitterResolutionNotifyReg
                    );
    if (EFI_ERROR(Status)) {
        DEBUG ((EFI_D_ERROR, "ASSERT_EFI_ERROR (Status = %r)\n", Status));
        ASSERT_EFI_ERROR (Status);
    }

    //
    // 9. Initialize internal state tracking variables
    //
    gConSplitterTextOutActiveCount = 0;
    gConSplitterTextInActiveCount = 0;
    gConSplitterPointerActiveCount = 0;
    gConSplitterAbsPointerActiveCount = 0;
    gConSplitterTextInCountVar2 = 0;
    gConSplitterPointerCountVar2 = 0;
    gConSplitterPointerCountVar3 = 0;
    gConSplitterAbsPointerCountVar2 = 0;

    gConTextOutChildList[0] = 0;
    gConTextOutChildList[1] = 0;
    gConTextOutChildList2[0] = 0;
    gConTextOutChildList2[1] = 0;
    gConTextInChildList[0] = 0;
    gConTextInChildList[1] = 0;

    //
    // 10. Register notification handlers for ConOut device arrival
    //
    Status = gBS->RegisterProtocolNotify (
                    &gEfiConsoleOutDeviceGuid,
                    gConSplitterConOutNotifyEvent,
                    &gConSplitterConOutNotifyReg
                    );

    //
    // 11. Signal the events to catch any already-present devices
    //
    gBS->SignalEvent (gConSplitterConOutNotifyEvent);
    gBS->SignalEvent (gConSplitterConInNotifyEvent);
    gBS->SignalEvent (gConSplitterStdErrNotifyEvent);

    //
    // 12. Set up console mode
    //
    {
        UINT32  DefaultColumns = 80;
        UINT32  DefaultRows = 25;

        gConSplitterGlobalMode = 0xFF;  // invalid/not set
        Status = ConSplitterInitializeConsoleMode (0);

        // Read Setup variable for default mode configuration
        if (gConSplitterGlobalMode == 0) {
            Status = gRT->GetVariable (
                            L"Setup",
                            &gEfiGlobalVariableGuid,
                            NULL,
                            NULL,
                            NULL
                            );
            if (Status == EFI_BUFFER_TOO_SMALL) {
                // Setup variable exists - check its contents
                VOID *SetupBuffer;
                UINTN SetupSize;

                SetupBuffer = AllocatePool (Status);
                if (SetupBuffer != NULL) {
                    Status = gRT->GetVariable (
                                    L"Setup",
                                    &gEfiGlobalVariableGuid,
                                    NULL,
                                    &SetupSize,
                                    SetupBuffer
                                    );
                    if (!EFI_ERROR(Status)) {
                        // Check console mode bit (offset depends on
                        // setup variable layout - bit 0 in first byte)
                        UINT8 *SetupData = (UINT8 *)SetupBuffer;
                        if (*SetupData & 2) {
                            gConSplitterLedState |= 2;
                        }
                    }
                    gBS->FreePool (SetupBuffer);
                }
            }
        }

        gConSplitterKeyboardLayoutValid = TRUE;
    }

    //
    // 13. Install console protocol interfaces into the system table
    //     and configure the default mode
    //
    if (gConSplitterModeTable != NULL) {
        gConSplitterModeTable->Columns = 80;
        gConSplitterModeTable->Rows = 25;
        gConSplitterModeTable->Valid = TRUE;
    }

    SystemTable->ConsoleOutHandle = gConSplitterConOutInterface;
    SystemTable->ConOut = gConSplitterConOutProtocol;
    SystemTable->ConsoleInHandle = gConSplitterConInInterface;
    SystemTable->ConIn = gConSplitterConInProtocol;
    SystemTable->StdErrHandle = gConSplitterStdErrInterface;
    SystemTable->StdErr = gConSplitterStdErrProtocol;

    // Set the mode and cursor
    gSystemTableLocal->Mode->Mode = 0;
    gBS->SetWatchdogTimer (120, 0, 0, NULL);

    {
        UINT32  TestMode = 0;
        gBS->CalculateCrc32 (gSystemTableLocal, 120, &TestMode);
        gSystemTableLocal->Mode->Mode = TestMode;
    }

    //
    // 14. Create periodic timer for keyboard polling
    //
    {
        EFI_EVENT  TimerEvent;

        Status = gBS->CreateEvent (
                        EVT_TIMER | EVT_NOTIFY_SIGNAL,
                        TPL_CALLBACK,
                        ConSplitterKeyboardTimerHandler,
                        NULL,
                        &TimerEvent
                        );
        if (!EFI_ERROR(Status)) {
            gBS->SetTimer (
                    TimerEvent,
                    TimerPeriodic,
                    50000  // 50ms = 20Hz keyboard poll
                    );
        }
    }

    return EFI_SUCCESS;
}

//
// ======================================================================
// SECTION 9: Key Notification Support
// ======================================================================
//

/**
 * ConSplitterRegisterKeyNotify
 * Address: 0x3A10 (sub_3A10)
 *
 * Registers a notification function for a particular key on all
 * input child devices. If the console splitter is blocked (e.g.,
 * during keyboard self-test), the notification is still recorded
 * in a global list for later activation.
 */
EFI_STATUS
ConSplitterRegisterKeyNotify (
    IN VOID                              *This,
    IN EFI_KEY_DATA                      *KeyData,
    IN VOID                              *NotificationFunction,
    OUT VOID                             **NotifyHandle
    )
{
    KEY_NOTIFY_NODE              *NotifyNode;
    TEXT_IN_NODE                 *Node;
    UINT32                        ChildIndex;

    if (KeyData == NULL || NotificationFunction == NULL || NotifyHandle == NULL) {
        return EFI_INVALID_PARAMETER;
    }

    if (gConSplitterTextOutBlockedFlag) {
        // Console is blocked (self-test mode) - register in the global
        // notification list for later activation
        DEBUG ((EFI_D_INFO, "ConIn Devices are blocked.  Registering the key notifications in the global list\n"));

        Status = gBS->AllocatePool (
                        EfiBootServicesData,
                        sizeof (KEY_NOTIFY_NODE),
                        &NotifyNode
                        );
        if (EFI_ERROR(Status)) {
            *NotifyHandle = NULL;
            return Status;
        }

        NotifyNode->KeyData = *KeyData;
        NotifyNode->NotificationFunction = NotificationFunction;
        NotifyNode->NotifyHandle = 0;
        NotifyNode->PerDeviceBadTags[0] = 0x00BADBAD;

        // Insert into notification linked list (i_1 list)
        NotifyNode->ForwardLink = NULL;
        NotifyNode->BackLink = gConSplitterTextInNotifyList;
        if (gConSplitterTextInNotifyList != NULL) {
            gConSplitterTextInNotifyList->ForwardLink = NotifyNode;
        }
        gConSplitterTextInNotifyList = NotifyNode;

        *NotifyHandle = NotifyNode;

        return EFI_SPLITTER_PROTOCOL_ERROR;
    }

    //
    // Normal path - register on each child device
    //
    Status = gBS->AllocatePool (
                    EfiBootServicesData,
                    sizeof (KEY_NOTIFY_NODE),
                    &NotifyNode
                    );
    if (EFI_ERROR(Status)) {
        return Status;
    }

    NotifyNode->KeyData = *KeyData;
    NotifyNode->NotificationFunction = NotificationFunction;

    // Register on each Text In child device
    Node = gConTextInChildren;
    ChildIndex = 0;

    while (Node != NULL && ChildIndex < MAX_CON_IN_CHILDREN) {
        // Store the child pointer
        NotifyNode->PerDeviceHandles[ChildIndex] = (UINT32)(UINTN)Node;

        // Register on this child (if it supports KeyNotify)
        if (Node->TextOutInterface != NULL) {
            Status = ConSplitterRegisterChildKeyNotify (
                        Node->TextOutInterface,
                        KeyData,
                        NotificationFunction,
                        &NotifyNode->PerDeviceBadTags[ChildIndex]
                        );
            if (EFI_ERROR(Status)) {
                NotifyNode->PerDeviceBadTags[ChildIndex] = 0x00BADBAD;
            }
        } else {
            NotifyNode->PerDeviceBadTags[ChildIndex] = 0x00BADBAD;
        }

        Node = Node->ForwardLink;
        ChildIndex++;
    }

    if (ChildIndex == MAX_CON_IN_CHILDREN) {
        DEBUG ((EFI_D_WARN, "You have exceeded the number of ConIn devices tracked for Key notifications. Increase MAX_CON_IN_CHILDREN in Consplit.h\n"));
    }

    // Check if this replaces a default key filter
    {
        KEY_FILTER_ENTRY *FilterEntry;
        UINT32            FilterIndex;

        FilterEntry = (KEY_FILTER_ENTRY *)gConSplitterKeyFilter;
        for (FilterIndex = 0; FilterIndex < CON_SPLITTER_KEY_FILTER_COUNT; FilterIndex++) {
            if (FilterEntry[FilterIndex].ScanCode == KeyData->Key.ScanCode &&
                FilterEntry[FilterIndex].UnicodeChar == KeyData->Key.UnicodeChar &&
                FilterEntry[FilterIndex].ShiftState == KeyData->KeyState.KeyShiftState &&
                (UINT64)NotificationFunction != (UINT64)ConSplitterDefaultKeyNotify)
            {
                gConSplitterKeyFilterOverride[FilterIndex] = 1;
                DEBUG ((EFI_D_INFO, "Default ConIn Function overridden\n"));
            }
        }
    }

    // Insert into notification list
    NotifyNode->ForwardLink = NULL;
    NotifyNode->BackLink = gConSplitterTextInNotifyList;
    if (gConSplitterTextInNotifyList != NULL) {
        gConSplitterTextInNotifyList->ForwardLink = NotifyNode;
    }
    gConSplitterTextInNotifyList = NotifyNode;

    gConSplitterTextInCountVar2++;
    *NotifyHandle = NotifyNode;

    return EFI_SUCCESS;
}

/**
 * ConSplitterUnregisterKeyNotify
 * Address: 0x3D08 (sub_3D08)
 *
 * Unregisters a previously registered key notification.
 * Removes the notification from all child devices and frees
 * the notification node.
 */
EFI_STATUS
ConSplitterUnregisterKeyNotify (
    IN VOID                              *This,
    IN VOID                              *NotificationHandle
    )
{
    KEY_NOTIFY_NODE              *NotifyNode;
    KEY_NOTIFY_NODE              *CurrentNode;
    UINT32                        ChildIndex;

    if (NotificationHandle == NULL) {
        return EFI_INVALID_PARAMETER;
    }

    if (gConSplitterTextOutBlockedFlag) {
        return EFI_SPLITTER_PROTOCOL_ERROR;
    }

    // Find the notification node in the linked list
    CurrentNode = gConSplitterTextInNotifyList;
    while (CurrentNode != NULL) {
        if (CurrentNode == (KEY_NOTIFY_NODE *)NotificationHandle) {
            break;
        }
        CurrentNode = CurrentNode->ForwardLink;
    }

    if (CurrentNode == NULL) {
        return EFI_INVALID_PARAMETER;
    }

    NotifyNode = CurrentNode;

    // Unregister from each child device
    if (gConTextInputChildren != NULL) {
        TEXT_IN_NODE *TextInNode;
        UINT32        Count;

        TextInNode = gConTextInputChildren;
        Count = (UINT32)gConSplitterTextInActiveCount;

        for (ChildIndex = 0; ChildIndex < gConSplitterTextInActiveCount; ChildIndex++) {
            VOID *ChildPtr = (VOID *)(UINTN)NotifyNode->PerDeviceHandles[ChildIndex];
            VOID *NotifyTag = (VOID *)(UINTN)NotifyNode->PerDeviceBadTags[ChildIndex];

            if (ChildPtr != NULL && NotifyTag != (VOID *)0x00BADBAD) {
                TEXT_IN_NODE *ChildNode = (TEXT_IN_NODE *)ChildPtr;
                if (ChildNode->TextOutInterface != NULL) {
                    ((EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *)ChildNode->TextOutInterface)
                        ->UnregisterKeyNotify (
                            ChildNode->TextOutInterface,
                            NotifyTag
                            );
                }
            }

            TextInNode = TextInNode->ForwardLink;
        }
    }

    // Remove from linked list
    if (NotifyNode->BackLink != NULL) {
        NotifyNode->BackLink->ForwardLink = NotifyNode->ForwardLink;
    }
    if (NotifyNode->ForwardLink != NULL) {
        NotifyNode->ForwardLink->BackLink = NotifyNode->BackLink;
    }

    if (gConSplitterTextInNotifyList == NotifyNode) {
        gConSplitterTextInNotifyList = NotifyNode->BackLink;
    }

    gBS->FreePool (NotifyNode);
    gConSplitterTextInCountVar2--;

    return EFI_SUCCESS;
}

//
// ======================================================================
// SECTION 10: Component Name Protocol
// ======================================================================
//

/**
 * ConSplitterGetDriverName
 * Address: 0x4A8 (sub_4A8)
 *
 * Returns the driver name based on which driver binding protocol
 * is being queried.
 */
EFI_STATUS
EFIAPI
ConSplitterGetDriverName (
    IN EFI_COMPONENT_NAME_PROTOCOL       *This,
    IN CHAR8                             *Language,
    OUT CHAR16                           **DriverName
    )
{
    if (Language == NULL || DriverName == NULL) {
        return EFI_INVALID_PARAMETER;
    }

    if (!ConSplitterIsLanguageEnUs (Language)) {
        return EFI_UNSUPPORTED;
    }

    if (This == (EFI_COMPONENT_NAME_PROTOCOL *)&gConSplitterTextOutComponentName) {
        *DriverName = L"AMI Console Splitter Text Out Driver";
    } else if (This == (EFI_COMPONENT_NAME_PROTOCOL *)&gConSplitterTextInComponentName) {
        *DriverName = L"AMI Console Splitter Text In Driver";
    } else if (This == (EFI_COMPONENT_NAME_PROTOCOL *)&gConSplitterPointerComponentName) {
        *DriverName = L"AMI Console Splitter Pointer Driver";
    } else {
        *DriverName = L"AMI Console Splitter Driver";
    }

    return EFI_SUCCESS;
}

/**
 * ConSplitterGetControllerName
 * Address: 0x44C (sub_44C)
 *
 * Returns the controller name. Only "AMI Console Splitter" is
 * returned for all supported controllers.
 */
EFI_STATUS
EFIAPI
ConSplitterGetControllerName (
    IN EFI_COMPONENT_NAME_PROTOCOL       *This,
    IN EFI_HANDLE                        ControllerHandle,
    IN EFI_HANDLE                        ChildHandle,
    IN CHAR8                             *Language,
    OUT CHAR16                           **ControllerName
    )
{
    if (ControllerName == NULL ||
        ControllerHandle == NULL ||
        Language == NULL) {
        return EFI_INVALID_PARAMETER;
    }

    if ((UINT64)ControllerHandle != gBootServicesLocal || !ConSplitterIsLanguageEnUs (Language)) {
        return EFI_UNSUPPORTED;
    }

    *ControllerName = L"AMI Console Splitter";
    return EFI_SUCCESS;
}

//
// ======================================================================
// SECTION 11: Console Notification Handlers
// ======================================================================
//

/**
 * ConSplitterConOutNotifyHandler
 * Address: 0x800 (sub_800)
 *
 * Called when a new ConOut device appears. Registers the device
 * path protocol and notifies the console event.
 */
VOID
EFIAPI
ConSplitterConOutNotifyHandler (
    IN EFI_EVENT                         Event,
    IN VOID                              *Context
    )
{
    EFI_STATUS                       Status;
    EFI_HANDLE                       Handle;
    EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *TextOut;

    // Find any text output handles
    Handle = NULL;
    while (TRUE) {
        Status = gBS->LocateHandle (
                        ByRegisterNotify,
                        &gEfiSimpleTextOutProtocolGuid,
                        gConSplitterConOutNotifyReg,
                        &Handle
                        );
        if (EFI_ERROR(Status)) {
            break;
        }

        // Try to start the driver on this handle
        if (gConSplitterTextOutActiveCount > 0 ||
            gConSplitterTextOutActiveCount == 0) {
            ConSplitterTextOutDriverBindingStart (
                &gConSplitterTextOutDriverBinding,
                Handle,
                NULL
                );
        }
    }

    // Register device path protocol notify if not yet done
    if (gConSplitterTextOutActiveCount == 0) {
        gBS->RegisterProtocolNotify (
                &gEfiDevicePathProtocolGuid,
                gConSplitterConOutNotifyEvent,
                &gConSplitterConOutNotifyReg
                );
    }
}

/**
 * ConSplitterConInNotifyHandler
 * Address: 0x938 (sub_938)
 *
 * Called when a new ConIn device appears. Registers the device
 * and sets up the keyboard notification filters.
 */
VOID
EFIAPI
ConSplitterConInNotifyHandler (
    IN EFI_EVENT                         Event,
    IN VOID                              *Context
    )
{
    EFI_STATUS                       Status;
    EFI_HANDLE                       Handle;
    UINT32                           ModeValue;
    UINT32                           SavedMode;

    // Find any text input handles
    Handle = NULL;
    SavedMode = 0;
    ModeValue = 0;

    while (TRUE) {
        Status = gBS->LocateHandle (
                        ByRegisterNotify,
                        &gEfiSimpleTextInProtocolGuid,
                        gConSplitterConInNotifyReg,
                        &Handle
                        );
        if (EFI_ERROR(Status)) {
            break;
        }

        // Start the driver
        if (gConSplitterTextInActiveCount > 0 ||
            (gConSplitterTextInActiveCount == 0 && gConSplitterModeTable == NULL)) {
            ConSplitterTextInDriverBindingStart (
                &gConSplitterTextInDriverBinding,
                Handle,
                NULL
                );
        }
    }

    // Set the system table console input handle and protocol
    SystemTable->ConsoleInHandle = gConSplitterConInInterface;
    SystemTable->ConIn = gConSplitterConInProtocol;

    // Set up system table mode
    SystemTable->Mode->Mode = 0;
    gBS->CalculateCrc32 (SystemTable, 120, &ModeValue);
    SystemTable->Mode->Mode = ModeValue;

    // Register the 8 default key filters
    {
        KEY_FILTER_ENTRY *Filters;
        UINT32            i;

        Filters = (KEY_FILTER_ENTRY *)gConSplitterKeyFilter;
        gConSplitterKeyboardTestPassed = TRUE;

        for (i = 0; i < CON_SPLITTER_KEY_FILTER_COUNT; i++) {
            EFI_KEY_DATA KeyData;

            KeyData.Key.ScanCode = Filters[i].ScanCode;
            KeyData.Key.UnicodeChar = Filters[i].UnicodeChar;
            KeyData.KeyState.KeyShiftState = Filters[i].ShiftState;

            ConSplitterRegisterKeyNotify (
                gConSplitterConInInterface,
                &KeyData,
                ConSplitterDefaultKeyNotify,
                NULL
                );
        }
    }

    if (gConSplitterTextBuffer != NULL) {
        gBS->FreePool (gConSplitterTextBuffer);
        gConSplitterTextBuffer = NULL;
    }
}

/**
 * ConSplitterStdErrNotifyHandler
 * Address: Similar to ConOut handler
 *
 * Called when a new StdErr device appears.
 */
VOID
EFIAPI
ConSplitterStdErrNotifyHandler (
    IN EFI_EVENT                         Event,
    IN VOID                              *Context
    )
{
    // Similar to ConOutNotifyHandler but for StdErr
    // Opens EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL on the handle
}

//
// ======================================================================
// SECTION 12: Debug and Diagnostic Functions
// ======================================================================
//

/**
 * ConSplitterDumpModeTable
 * Address: 0x2D60 (sub_2D60)
 *
 * Debug function that dumps the mode table to the debug port.
 */
VOID
ConSplitterDumpModeTable (
    VOID
    )
{
    UINT32  Index;

    DEBUG ((EFI_D_INFO, "\n"));
    for (Index = 0; Index < gConSplitterModeTableSize; Index++) {
        UINT32  Columns = *(UINT32 *)(gConSplitterModeTable + 9 * Index + 0);
        UINT32  Rows    = *(UINT32 *)(gConSplitterModeTable + 9 * Index + 4);
        UINT8   Valid   = *(UINT8  *)(gConSplitterModeTable + 9 * Index + 8);

        DEBUG ((EFI_D_INFO, "Rows = %d  Col = %d    AllDevices = %d \n", Rows, Columns, Valid));
    }
}

/**
 * ConSplitterGetDebugLevel
 * Address: 0x5214 (sub_5214)
 *
 * Reads the debug level from CMOS/RTC, or from a hardcoded
 * memory location. Returns a bitmask for use with DEBUG() macros.
 */
UINTN
ConSplitterGetDebugLevel (
    VOID
    )
{
    UINT8   IndexRegister;
    UINT8   DataRegister;

    // Read CMOS index register 0x70, save high bit (NMI enable)
    IndexRegister = __inbyte (0x70);
    __outbyte (0x70, IndexRegister & 0x80 | 0x4B);
    DataRegister = __inbyte (0x71);

    if (DataRegister > 3) {
        if (DataRegister == 0) {
            // Fallback: read from fixed memory location
            DataRegister = *(volatile UINT8 *)0xFDAF0490 & 2 | 1;
        }
    }

    if (DataRegister == 0 || DataRegister > 4) {
        return 0;
    }

    if (DataRegister == 1) {
        return 0x80000004;  // EFI_D_ERROR only
    }

    return 0x80000006;      // EFI_D_ERROR | EFI_D_WARN
}

/**
 * ConSplitterCompareMem
 * Address: 0x519C (sub_519C)
 *
 * Compares two memory buffers. Returns 0 if equal, difference otherwise.
 */
INTN
ConSplitterCompareMem (
    IN VOID                              *Destination,
    IN VOID                              *Source,
    IN UINTN                             Length
    )
{
    return CompareMem (Destination, Source, Length);
}

/**
 * ConSplitterCopyMem
 * Address: 0x53C0 (sub_53C0)
 *
 * Copies a memory buffer. Handles overlapping source/destination
 * with correct direction.
 */
VOID
ConSplitterCopyMem (
    IN VOID                              *Destination,
    IN VOID                              *Source,
    IN UINTN                             Length
    )
{
    CopyMem (Destination, Source, Length);
}

/**
 * ConSplitterIsLanguageEnUs
 * Address: 0x5130 (sub_5130)
 *
 * Case-insensitive check if language string equals "en-US".
 */
BOOLEAN
ConSplitterIsLanguageEnUs (
    IN CHAR8                             *Language
    )
{
    CHAR8   *EnUs = "en-US";
    CHAR8   C1, C2;

    if (Language == NULL) {
        return FALSE;
    }

    while (*Language) {
        C1 = *Language;
        C2 = *EnUs;

        if (C1 != C2) {
            // Case-insensitive comparison
            if (C1 >= 'a' && C1 <= 'z') C1 -= 0x20;
            if (C2 >= 'a' && C2 <= 'z') C2 -= 0x20;
            if (C1 >= 'A' && C1 <= 'Z') { }
            if (C2 >= 'A' && C2 <= 'Z') { }
            if (C1 != C2) return FALSE;
        }

        Language++;
        EnUs++;
    }

    return (*Language == *EnUs);
}

/**
 * ConSplitterReadUnaligned64
 * Address: 0x5264 (sub_5264)
 *
 * Reads a 64-bit value from a possibly unaligned address.
 */
UINT64
ConSplitterReadUnaligned64 (
    IN UINT64                            *Buffer
    )
{
    if (Buffer == NULL) {
        ASSERT (Buffer != NULL);
    }
    return *Buffer;
}

/**
 * ConSplitterIsProtocolGuidMatch
 * Address: 0x5294 (sub_5294)
 *
 * Compares two protocol GUID entries to see if they match.
 */
BOOLEAN
ConSplitterIsProtocolGuidMatch (
    IN EFI_GUID                          *Guid1,
    IN EFI_GUID                          *Guid2
    )
{
    return CompareGuid (Guid1, Guid2);
}

/**
 * ConSplitterLocateHob
 * Address: 0x4BF8 (sub_4BF8)
 *
 * Locates the HOB (Hand-Off Block) list pointer.
 */
EFI_STATUS
ConSplitterLocateHob (
    IN EFI_HANDLE                        ImageHandle
    )
{
    if (gConSplitterHobListHandle == 0) {
        EFI_HOB_LIST  *HobList;

        // Get HOB list from SystemTable->BootServices
        HobList = (EFI_HOB_LIST *)gBS->GetHobList ();
        if (HobList == NULL) {
            DEBUG ((EFI_D_ERROR, "ASSERT_EFI_ERROR (Status = %r)\n", EFI_NOT_FOUND));
            ASSERT_EFI_ERROR (EFI_NOT_FOUND);
            return EFI_NOT_FOUND;
        }

        gConSplitterHobListHandle = (UINT64)HobList;
    }

    return EFI_SUCCESS;
}

//
// ======================================================================
// SECTION 13: Console Mode Management
// ======================================================================
//

/**
 * ConSplitterSynchronizeTextOut
 * Address: 0x4188 (sub_4188)
 *
 * Synchronizes text output state (mode, cursor position, attribute)
 * from the internal buffer to the child devices.
 */
VOID
ConSplitterSynchronizeTextOut (
    IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL   *ReferenceDevice,
    IN UINTN                             ModeNumber
    )
{
    EFI_UGA_DRAW_PROTOCOL   *UgaDraw;
    EFI_STATUS               Status;

    Status = gBS->HandleProtocol (
                    ReferenceDevice,
                    &gEfiUgaDrawProtocolGuid,
                    &UgaDraw
                    );

    if (!EFI_ERROR(Status)) {
        // We have UGA Draw protocol - use it for mode switching
        if (gConSplitterTextBufDst != NULL) {
            // Synchronize display buffer
            ConSplitterFlushBuffer (ReferenceDevice);

            gBS->FreePool (gConSplitterTextBufDst);
            gConSplitterTextBufDst = NULL;
            gBS->FreePool (gConSplitterTextBufDstAttr);
            gConSplitterTextBufDstAttr = NULL;
        }
    } else {
        // No UGA Draw - use text output scrolling
        ConSplitterScrollTextBuffer (ReferenceDevice, NULL);
    }

    // Restore cursor position and attribute
    ReferenceDevice->SetCursorPosition (ReferenceDevice,
        gConSplitterCursorColumn, gConSplitterCursorRow);
    ReferenceDevice->SetAttribute (ReferenceDevice, gConSplitterDefaultAttr);
    ReferenceDevice->SetCursorPosition (ReferenceDevice,
        gConSplitterCursorColumn, gConSplitterCursorRow);
}

/**
 * ConSplitterFlushBuffer
 * Address: 0x4010 (sub_4010)
 *
 * Flushes the internal text buffer to the child device using
 * UGA Draw protocol (Blt).
 */
VOID
ConSplitterFlushBuffer (
    IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL   *ReferenceDevice
    )
{
    EFI_UGA_DRAW_PROTOCOL   *UgaDraw;
    EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer;
    UINT32                    BltSize;
    EFI_STATUS                Status;

    if (gConSplitterTextBufDst != NULL) {
        gBS->FreePool (gConSplitterTextBufDst);
        gConSplitterTextBufDst = NULL;
    }

    // Get UGA Draw protocol from the reference device
    Status = gBS->HandleProtocol (
                    ReferenceDevice,
                    &gEfiUgaDrawProtocolGuid,
                    &UgaDraw
                    );
    if (EFI_ERROR(Status)) {
        return;
    }

    // Calculate Blt buffer size from current mode dimensions
    BltSize = sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL) *
              gConSplitterColumns * gConSplitterRows;

    gConSplitterTextBufDst = AllocatePool (BltSize);
    if (gConSplitterTextBufDst == NULL) {
        return;
    }

    // Blt the buffer to the screen
    Status = UgaDraw->Blt (
                        UgaDraw,
                        gConSplitterTextBufDst,
                        EfiBltBufferToVideo,
                        0, 0,
                        0, 0,
                        gConSplitterColumns,
                        gConSplitterRows,
                        0
                        );
    if (EFI_ERROR(Status)) {
        gBS->FreePool (gConSplitterTextBufDst);
        gConSplitterTextBufDst = NULL;
    }
}

/**
 * ConSplitterScrollTextBuffer
 * Address: 0x3EDC (sub_3EDC)
 *
 * Scrolls the text buffer by one line and outputs to the device.
 */
VOID
ConSplitterScrollTextBuffer (
    IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL   *This,
    IN CHAR16                            *String
    )
{
    CHAR16   *Src;
    CHAR16   *SrcEnd;
    CHAR16   *Dst;
    UINT32   *AttribSrc;
    UINT32    Cols;
    UINT32    FirstLineAttr;

    Src = gConSplitterTextBuffer;
    SrcEnd = gConSplitterTextAttrib;
    Dst = gConSplitterTextBuffer;
    Cols = gConSplitterColumns;

    if (gConSplitterBufferClean) {
        return;
    }

    // Read the attribute of the first character in the first line
    FirstLineAttr = *(UINT32 *)gConSplitterTextAttrib;

    // Set mode and cursor
    This->SetMode (This, 0);
    This->SetAttribute (This, FirstLineAttr);

    // Scroll character by character
    while ((UINTN)Src < (UINTN)SrcEnd) {
        CHAR16  SaveChar;

        if (*(UINT32 *)AttribSrc == FirstLineAttr) {
            // End of line marker found
        }

        SaveChar = *Src;
        *Src = 0;

        This->OutputString (This, Dst);

        *Src = SaveChar;
        Dst = Src;

        if (*(UINT32 *)AttribSrc != FirstLineAttr) {
            break;
        }

        FirstLineAttr = *(UINT32 *)AttribSrc;

        Src++;
        AttribSrc++;
    }

    // Set new attribute
    This->SetAttribute (This, *(UINT32 *)AttribSrc);
}

/**
 * ConSplitterClearTextBuffer
 * Address: 0x3FB4 (sub_3FB4)
 *
 * Fills the text buffer with spaces and default attribute.
 */
VOID
ConSplitterClearTextBuffer (
    VOID
    )
{
    CHAR16   *TextPos;
    UINT32   *AttribPos;
    UINT64    Count;

    TextPos = (CHAR16 *)gConSplitterTextBuffer;
    AttribPos = (UINT32 *)gConSplitterTextAttrib;

    if (gConSplitterTextBuffer > gConSplitterTextBufEnd) {
        Count = 0;
    } else {
        Count = ((UINT64)gConSplitterTextBufEnd - (UINT64)gConSplitterTextBuffer + 1) >> 1;
    }

    for (; Count > 0; Count--) {
        *TextPos++ = L' ';
        *AttribPos++ = gConSplitterDefaultAttr;
    }

    gConSplitterBufferClean = TRUE;
}

/**
 * ConSplitterReconstructModeTable
 * Address: 0x2350 (sub_2350) + 0x25FC (sub_25FC)
 *
 * Reconstructs the mode table from a reference child device.
 * Allocates and fills the mode table with rows/columns information.
 */
EFI_STATUS
ConSplitterReconstructModeTable (
    IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL   *ReferenceDevice
    )
{
    UINT32          MaxMode;
    UINT32          *ModePtr;
    UINT32          ModeIndex;
    UINT32          Columns;
    UINT32          Rows;
    UINT32          PrevColumns;
    UINT32          PrevRows;
    UINT32          SavedGlobalMode;
    EFI_STATUS      Status;

    if (ReferenceDevice == gConSplitterConOutInterface) {
        return EFI_SUCCESS;
    }

    // Get max mode from reference device
    ModePtr = (UINT32 *)ReferenceDevice->Mode;
    MaxMode = *ModePtr;

    gConSplitterModeTableSize = MaxMode;

    // Allocate mode table: 9 bytes per mode entry
    {
        UINT32  EntrySize = 9;  // sizeof = 4(cols) + 4(rows) + 1(valid)
        UINT8  *Table;
        UINT32  i;

        // Free old table if it exists
        if (gConSplitterModeTable != NULL) {
            gBS->FreePool (gConSplitterModeTable);
        }

        Table = AllocateZeroPool (MaxMode * EntrySize);
        if (Table == NULL) {
            gConSplitterModeTableSize = 0;
            return EFI_OUT_OF_RESOURCES;
        }

        gConSplitterModeTable = Table;

        // Fill mode table
        for (i = 0; i < MaxMode; i++) {
            UINTN  Col, Row;

            Status = ReferenceDevice->QueryMode (
                        ReferenceDevice,
                        i,
                        &Col,
                        &Row
                        );
            *(UINT32 *)(Table + EntrySize * i + 0) = (UINT32)Col;
            *(UINT32 *)(Table + EntrySize * i + 4) = (UINT32)Row;
            *(UINT8  *)(Table + EntrySize * i + 8) = !EFI_ERROR(Status);
        }
    }

    // Store previous mode if valid
    SavedGlobalMode = gConSplitterGlobalMode;

    // Set mode to 0
    gConSplitterGlobalMode = 0xFFFFFFFF;
    Status = ConSplitterSetConsoleMode (ReferenceDevice, 0);

    // Apply default cursor setting
    ConSplitterSetResolutionData ();
    return Status;
}