consplitter.c
来自「Next BIOS Source code : Extensible Firmw」· C语言 代码 · 共 2,473 行 · 第 1/5 页
C
2,473 行
//
while ( Index < Private->TextOutMode.MaxMode ) {
EfiCopyMem (TextOutModeMap, SrcAddress, Size);
TextOutModeMap += NewSize;
SrcAddress += Size;
Index ++;
}
//
// Free the old buffer
//
gBS->FreePool (OldTextOutModeMap);
}
return EFI_SUCCESS;
}
EFI_STATUS
ConSplitterAddOutputMode (
IN TEXT_OUT_SPLITTER_PRIVATE_DATA *Private,
IN EFI_SIMPLE_TEXT_OUT_PROTOCOL *TextOut
)
/*++
Routine Description:
Arguments:
Returns:
None
--*/
{
EFI_STATUS Status;
INT32 MaxMode;
INT32 Mode;
UINTN Index;
MaxMode = TextOut->Mode->MaxMode;
Private->TextOutMode.MaxMode = MaxMode;
//
// Grow the buffer if query data buffer is not large enough to
// hold all the mode supported by the first console.
//
while ( MaxMode > (INT32)Private->TextOutQueryDataCount ) {
Status = ConSplitterGrowBuffer (
sizeof (TEXT_OUT_SPLITTER_QUERY_DATA),
&Private->TextOutQueryDataCount,
(VOID **)&Private->TextOutQueryData
);
if ( EFI_ERROR (Status) ) {
return EFI_OUT_OF_RESOURCES;
}
}
//
// Allocate buffer for the output mode map
//
Status = ConSplitterGrowMapTable (Private);
if ( EFI_ERROR (Status) ) {
return EFI_OUT_OF_RESOURCES;
}
//
// As the first textout device, directly add the mode in to QueryData
// and at the same time record the mapping between QueryData and TextOut.
//
Mode = 0;
Index = 0;
while ( Mode < MaxMode ) {
TextOut->QueryMode (
TextOut,
Mode,
&Private->TextOutQueryData[Mode].Columns,
&Private->TextOutQueryData[Mode].Rows
);
Private->TextOutModeMap[Index] = Mode;
Mode ++;
Index += Private->TextOutListCount;
}
return EFI_SUCCESS;
}
VOID
ConSplitterGetIntersection (
IN INT32 *TextOutModeMap,
IN INT32 *NewlyAddedMap,
IN UINTN MapStepSize,
IN UINTN NewMapStepSize,
OUT INT32 *MaxMode,
OUT INT32 *CurrentMode
)
{
INT32 Index;
INT32 *CurrentMapEntry, *NextMapEntry;
INT32 CurrentMaxMode, Mode;
Index = 0;
CurrentMapEntry = TextOutModeMap;
NextMapEntry = TextOutModeMap;
CurrentMaxMode = *MaxMode;
Mode = *CurrentMode;
while ( Index < CurrentMaxMode ) {
if ( *NewlyAddedMap == -1 ) {
//
// This mode is not supported any more. Remove it. Special care
// must be taken as this remove will also affect current mode;
//
if ( Index == *CurrentMode ) {
Mode = -1;
} else if ( Index < *CurrentMode ) {
Mode --;
}
(*MaxMode) --;
} else {
if ( CurrentMapEntry != NextMapEntry ) {
EfiCopyMem (NextMapEntry, CurrentMapEntry, MapStepSize * sizeof (INT32));
}
NextMapEntry += MapStepSize;
}
CurrentMapEntry += MapStepSize;
NewlyAddedMap += NewMapStepSize;
Index ++;
}
*CurrentMode = Mode;
return;
}
VOID
ConSplitterSyncOutputMode (
IN TEXT_OUT_SPLITTER_PRIVATE_DATA *Private,
IN EFI_SIMPLE_TEXT_OUT_PROTOCOL *TextOut
)
/*++
Routine Description:
Arguments:
Returns:
None
--*/
{
INT32 CurrentMode;
INT32 CurrentMaxMode, Mode;
INT32 Index;
INT32 *TextOutModeMap, *MapTable;
TEXT_OUT_SPLITTER_QUERY_DATA *TextOutQueryData;
UINTN Rows;
UINTN Columns;
UINTN StepSize;
//
// Must make sure that current mode won't change even if mode number changes
//
CurrentMode = Private->TextOutMode.Mode;
CurrentMaxMode = Private->TextOutMode.MaxMode;
TextOutModeMap = Private->TextOutModeMap;
StepSize = Private->TextOutListCount;
TextOutQueryData = Private->TextOutQueryData;
//
// Query all the mode that the newly added TextOut supports
//
Mode = 0;
MapTable = TextOutModeMap + Private->CurrentNumberOfConsoles;
while ( Mode < TextOut->Mode->MaxMode ) {
TextOut->QueryMode (TextOut, Mode, &Columns, &Rows);
//
// Search the QueryData database to see if they intersects
//
Index = 0;
while ( Index < CurrentMaxMode ) {
if ( ( TextOutQueryData[Index].Rows == Rows )
&& ( TextOutQueryData[Index].Columns == Columns ) ) {
MapTable[Index * StepSize] = Mode;
break;
}
Index ++;
}
Mode ++;
}
//
// Now search the TextOutModeMap table to find the intersection of supported
// mode between ConSplitter and the newly added device.
//
ConSplitterGetIntersection (
TextOutModeMap,
MapTable,
StepSize,
StepSize,
&Private->TextOutMode.MaxMode,
&Private->TextOutMode.Mode
);
return;
}
EFI_STATUS
ConSplitterGetIntersectionBetweenConOutAndStrErr (
)
/*++
Routine Description:
Arguments:
Returns:
None
--*/
{
UINTN ConOutNumOfConsoles, StdErrNumOfConsoles;
TEXT_OUT_AND_UGA_DATA *ConOutTextOutList, *StdErrTextOutList;
UINTN Indexi, Indexj;
UINTN Rows, Columns;
INT32 ConOutCurrentMode, StdErrCurrentMode;
INT32 ConOutMaxMode, StdErrMaxMode;
INT32 Mode, Index;
INT32 *ConOutModeMap, *StdErrModeMap;
INT32 *ConOutMapTable, *StdErrMapTable;
TEXT_OUT_SPLITTER_QUERY_DATA *ConOutQueryData, *StdErrQueryData;
UINTN ConOutStepSize, StdErrStepSize;
BOOLEAN FoundTheSameTextOut;
UINTN ConOutMapTableSize, StdErrMapTableSize;
ConOutNumOfConsoles = mConOut.CurrentNumberOfConsoles;
StdErrNumOfConsoles = mStdErr.CurrentNumberOfConsoles;
ConOutTextOutList = mConOut.TextOutList;
StdErrTextOutList = mStdErr.TextOutList;
Indexi = 0;
FoundTheSameTextOut = FALSE;
while ( ( Indexi < ConOutNumOfConsoles ) && ( !FoundTheSameTextOut ) ) {
Indexj = 0;
while ( Indexj < StdErrNumOfConsoles ) {
if ( ConOutTextOutList->TextOut == StdErrTextOutList->TextOut ) {
FoundTheSameTextOut = TRUE;
break;
}
Indexj ++;
StdErrTextOutList ++;
}
Indexi ++;
ConOutTextOutList ++;
}
if ( !FoundTheSameTextOut ) {
return EFI_SUCCESS;
}
//
// Must make sure that current mode won't change even if mode number changes
//
ConOutCurrentMode = mConOut.TextOutMode.Mode;
ConOutMaxMode = mConOut.TextOutMode.MaxMode;
ConOutModeMap = mConOut.TextOutModeMap;
ConOutStepSize = mConOut.TextOutListCount;
ConOutQueryData = mConOut.TextOutQueryData;
StdErrCurrentMode = mStdErr.TextOutMode.Mode;
StdErrMaxMode = mStdErr.TextOutMode.MaxMode;
StdErrModeMap = mStdErr.TextOutModeMap;
StdErrStepSize = mStdErr.TextOutListCount;
StdErrQueryData = mStdErr.TextOutQueryData;
//
// Allocate the map table and set the map table's index to -1.
//
ConOutMapTableSize = ConOutMaxMode * sizeof (INT32);
ConOutMapTable = EfiLibAllocateZeroPool (ConOutMapTableSize);
if ( ConOutMapTable == NULL ) {
return EFI_OUT_OF_RESOURCES;
}
EfiSetMem (ConOutMapTable, ConOutMapTableSize, 0xFF);
StdErrMapTableSize = StdErrMaxMode * sizeof (INT32);
StdErrMapTable = EfiLibAllocateZeroPool (StdErrMapTableSize);
if ( StdErrMapTable == NULL ) {
return EFI_OUT_OF_RESOURCES;
}
EfiSetMem (StdErrMapTable, StdErrMapTableSize, 0xFF);
//
// Find the intersection of the two set of modes. If they actually intersect, the
// correponding entry in the map table is set to 1.
//
Mode = 0;
while ( Mode < ConOutMaxMode ) {
//
// Search the other's QueryData database to see if they intersect
//
Index = 0;
Rows = ConOutQueryData[Mode].Rows;
Columns = ConOutQueryData[Mode].Columns;
while ( Index < StdErrMaxMode ) {
if ( ( StdErrQueryData[Index].Rows == Rows )
&& ( StdErrQueryData[Index].Columns == Columns ) ) {
ConOutMapTable[Mode] = 1;
StdErrMapTable[Index] = 1;
break;
}
Index ++;
}
Mode ++;
}
//
// Now search the TextOutModeMap table to find the intersection of supported
// mode between ConSplitter and the newly added device.
//
ConSplitterGetIntersection (
ConOutModeMap,
ConOutMapTable,
mConOut.TextOutListCount,
1,
&(mConOut.TextOutMode.MaxMode),
&(mConOut.TextOutMode.Mode)
);
if ( mConOut.TextOutMode.Mode < 0 ) {
mConOut.TextOut.SetMode (&(mConOut.TextOut), 0);
}
ConSplitterGetIntersection (
StdErrModeMap,
StdErrMapTable,
mStdErr.TextOutListCount,
1,
&(mStdErr.TextOutMode.MaxMode),
&(mStdErr.TextOutMode.Mode)
);
if ( mStdErr.TextOutMode.Mode < 0 ) {
mStdErr.TextOut.SetMode (&(mStdErr.TextOut), 0);
}
gBS->FreePool (ConOutMapTable);
gBS->FreePool (StdErrMapTable);
return EFI_SUCCESS;
}
EFI_STATUS
ConSplitterTextOutAddDevice (
IN TEXT_OUT_SPLITTER_PRIVATE_DATA *Private,
IN EFI_SIMPLE_TEXT_OUT_PROTOCOL *TextOut,
IN EFI_UGA_DRAW_PROTOCOL *UgaDraw
)
/*++
Routine Description:
Arguments:
Returns:
None
--*/
{
EFI_STATUS Status;
UINTN CurrentNumOfConsoles;
INT32 CurrentMode, MaxMode;
TEXT_OUT_AND_UGA_DATA *TextAndUga;
Status = EFI_SUCCESS;
CurrentNumOfConsoles = Private->CurrentNumberOfConsoles;
//
// If the Text Out List is full, enlarge it by calling growbuffer().
//
while ( CurrentNumOfConsoles >= Private->TextOutListCount ) {
Status = ConSplitterGrowBuffer (
sizeof (TEXT_OUT_AND_UGA_DATA),
&Private->TextOutListCount,
(VOID **)&Private->TextOutList
);
if (EFI_ERROR (Status)) {
return EFI_OUT_OF_RESOURCES;
}
//
// Also need to reallocate the TextOutModeMap table
//
Status = ConSplitterGrowMapTable (Private);
if (EFI_ERROR (Status)) {
return EFI_OUT_OF_RESOURCES;
}
}
TextAndUga = &Private->TextOutList[CurrentNumOfConsoles];
TextAndUga->TextOut = TextOut;
TextAndUga->UgaDraw = UgaDraw;
if (UgaDraw == NULL) {
//
// If No UGA device then use the ConOut device
//
TextAndUga->TextOutEnabled = TRUE;
} else {
//
// If UGA device use ConOut device only used if UGA screen is in Text mode
//
TextAndUga->TextOutEnabled = (BOOLEAN)(Private->UgaMode == EfiScreenText);
}
if ( CurrentNumOfConsoles == 0 ) {
//
// Add the first device's output mode to console splitter's mode list
//
Status = ConSplitterAddOutputMode (Private, TextOut);
} else {
ConSplitterSyncOutputMode (Private, TextOut);
}
Private->CurrentNumberOfConsoles ++;
//
// Scan both TextOutList, for the intersection TextOut device
// maybe both ConOut and StdErr incorporate the same Text Out
// device in them, thus the output of both should be synced.
//
ConSplitterGetIntersectionBetweenConOutAndStrErr();
CurrentMode = Private->TextOutMode.Mode;
MaxMode = Private->TextOutMode.MaxMode;
ASSERT (MaxMode >= 1);
if (Private->UgaMode == EfiScreenGraphics && UgaDraw != NULL) {
//
// We just added a new UGA device in graphics mode
//
DevNullUgaSync (Private, UgaDraw);
} else if ( ( CurrentMode >= 0 ) && ( UgaDraw != NULL ) &&
( CurrentMode < Private->TextOutMode.MaxMode ) ) {
//
// The new console supports the same mode of the current console so sync up
//
DevNullSyncUgaStdOut (Private);
} else {
//
// If ConOut, then set the mode to Mode #0 which us 80 x 25
//
Private->TextOut.SetMode (&Private->TextOut, 0);
}
return Status;
}
EFI_STATUS
ConSplitterTextOutDeleteDevice (
IN TEXT_OUT_SPLITTER_PRIVATE_DATA *Private,
IN EFI_SIMPLE_TEXT_OUT_PROTOCOL *TextOut
)
/*++
Routine Description:
Arguments:
Returns:
None
--*/
{
INT32 Index;
UINTN CurrentNumOfConsoles;
TEXT_OUT_AND_UGA_DATA *TextOutList;
EFI_STATUS Status;
//
// Remove the specified text-out device data structure from the Text out List,
// and rearrange the remaining data structures in the Text out List.
//
CurrentNumOfConsoles = Private->CurrentNumberOfConsoles;
Index = (INT32)CurrentNumOfConsoles - 1;
TextOutList = Private->TextOutList;
while ( Index >= 0 ) {
if (TextOutList->TextOut == TextOut) {
EfiCopyMem (TextOutList, TextOutList + 1, sizeof (TEXT_OUT_AND_UGA_DATA) * Index);
CurrentNumOfConsoles --;
break;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?