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 + -
显示快捷键?