serial.c

来自「EFI BIOS是Intel提出的下一代的BIOS标准。这里上传的Edk源代码是」· C语言 代码 · 共 2,023 行 · 第 1/4 页

C
2,023
字号
  SerialDevice->SerialIo.GetControl     = IsaSerialGetControl;
  SerialDevice->SerialIo.Write          = IsaSerialWrite;
  SerialDevice->SerialIo.Read           = IsaSerialRead;
  SerialDevice->SerialIo.Mode           = &(SerialDevice->SerialMode);

  if (RemainingDevicePath != NULL) {
    //
    // Match the configuration of the RemainingDevicePath. IsHandleSupported()
    // already checked to make sure the RemainingDevicePath contains settings
    // that we can support.
    //
    EfiCopyMem (&SerialDevice->UartDevicePath, RemainingDevicePath, sizeof (UART_DEVICE_PATH));
  } else {
    //
    // Build the device path by appending the UART node to the ParentDevicePath
    // from the WinNtIo handle. The Uart setings are zero here, since
    // SetAttribute() will update them to match the default setings.
    //
    EfiZeroMem (&SerialDevice->UartDevicePath, sizeof (UART_DEVICE_PATH));
    SerialDevice->UartDevicePath.Header.Type    = MESSAGING_DEVICE_PATH;
    SerialDevice->UartDevicePath.Header.SubType = MSG_UART_DP;
    SetDevicePathNodeLength ((EFI_DEVICE_PATH_PROTOCOL *) &SerialDevice->UartDevicePath, sizeof (UART_DEVICE_PATH));
  }
  //
  // Build the device path by appending the UART node to the ParentDevicePath
  // from the WinNtIo handle. The Uart setings are zero here, since
  // SetAttribute() will update them to match the current setings.
  //
  SerialDevice->DevicePath = EfiAppendDevicePathNode (
                               ParentDevicePath,
                               (EFI_DEVICE_PATH_PROTOCOL *) &SerialDevice->UartDevicePath
                               );

  if (SerialDevice->DevicePath == NULL) {
    Status = EFI_DEVICE_ERROR;
    goto Error;
  }
  //
  // Fill in Serial I/O Mode structure based on either the RemainingDevicePath or defaults.
  //
  SerialDevice->SerialMode.ControlMask      = SERIAL_PORT_DEFAULT_CONTROL_MASK;
  SerialDevice->SerialMode.Timeout          = SERIAL_PORT_DEFAULT_TIMEOUT;
  SerialDevice->SerialMode.BaudRate         = SerialDevice->UartDevicePath.BaudRate;
  SerialDevice->SerialMode.ReceiveFifoDepth = SERIAL_PORT_DEFAULT_RECEIVE_FIFO_DEPTH;
  SerialDevice->SerialMode.DataBits         = SerialDevice->UartDevicePath.DataBits;
  SerialDevice->SerialMode.Parity           = SerialDevice->UartDevicePath.Parity;
  SerialDevice->SerialMode.StopBits         = SerialDevice->UartDevicePath.StopBits;

  //
  // Issue a reset to initialize the COM port
  //
  Status = SerialDevice->SerialIo.Reset (&SerialDevice->SerialIo);
  if (EFI_ERROR (Status)) {
    Status = ReportStatusCodeWithDevicePath (
               EFI_ERROR_CODE,
               EFI_P_EC_CONTROLLER_ERROR | EFI_PERIPHERAL_SERIAL_PORT,
               0,
               &gEfiSerialIoProtocolGuid,
               ParentDevicePath
               );
    goto Error;
  }
  //
  // Install protocol interfaces for the serial device.
  //
  Status = gBS->InstallMultipleProtocolInterfaces (
                  &SerialDevice->Handle,
                  &gEfiDevicePathProtocolGuid,
                  SerialDevice->DevicePath,
                  &gEfiSerialIoProtocolGuid,
                  &SerialDevice->SerialIo,
                  NULL
                  );
  if (EFI_ERROR (Status)) {
    goto Error;
  }
  //
  // Open For Child Device
  //
  Status = gBS->OpenProtocol (
                  Controller,
                  EFI_ISA_IO_PROTOCOL_VERSION,
                  (VOID **) &IsaIo,
                  This->DriverBindingHandle,
                  SerialDevice->Handle,
                  EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
                  );

Error:
  if (EFI_ERROR (Status)) {
    gBS->CloseProtocol (
           Controller,
           &gEfiDevicePathProtocolGuid,
           This->DriverBindingHandle,
           Controller
           );
    gBS->CloseProtocol (
           Controller,
           EFI_ISA_IO_PROTOCOL_VERSION,
           This->DriverBindingHandle,
           Controller
           );
    if (SerialDevice) {
      if (SerialDevice->DevicePath) {
        gBS->FreePool (SerialDevice->DevicePath);
      }

      EfiLibFreeUnicodeStringTable (SerialDevice->ControllerNameTable);
      gBS->FreePool (SerialDevice);
    }
  }

  return Status;
}

EFI_STATUS
EFIAPI
SerialControllerDriverStop (
  IN  EFI_DRIVER_BINDING_PROTOCOL    *This,
  IN  EFI_HANDLE                     Controller,
  IN  UINTN                          NumberOfChildren,
  IN  EFI_HANDLE                     *ChildHandleBuffer
  )
/*++

  Routine Description:
  
    Disconnect this driver with the controller, uninstall related protocol instance

  Arguments:
  
    This                - A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
    Controller          - The handle of the controller to test.
    NumberOfChildren    - Number of child device.
    RemainingDevicePath - A pointer to the remaining portion of a device path.

  Returns:
  
    EFI_SUCCESS         - Operation successfully
    EFI_DEVICE_ERROR    - Cannot stop the driver successfully

--*/
{
  EFI_STATUS                          Status;
  UINTN                               Index;
  BOOLEAN                             AllChildrenStopped;
  EFI_SERIAL_IO_PROTOCOL              *SerialIo;
  SERIAL_DEV                          *SerialDevice;
  EFI_INTERFACE_DEFINITION_FOR_ISA_IO *IsaIo;
  EFI_DEVICE_PATH_PROTOCOL            *DevicePath;

  Status = gBS->HandleProtocol (
                  Controller,
                  &gEfiDevicePathProtocolGuid,
                  &DevicePath
                  );

  //
  // Report the status code disable the serial
  //
  Status = ReportStatusCodeWithDevicePath (
             EFI_PROGRESS_CODE,
             EFI_P_PC_DISABLE | EFI_PERIPHERAL_SERIAL_PORT,
             0,
             &gEfiSerialIoProtocolGuid,
             DevicePath
             );

  //
  // Complete all outstanding transactions to Controller.
  // Don't allow any new transaction to Controller to be started.
  //
  if (NumberOfChildren == 0) {
    //
    // Close the bus driver
    //
    Status = gBS->CloseProtocol (
                    Controller,
                    EFI_ISA_IO_PROTOCOL_VERSION,
                    This->DriverBindingHandle,
                    Controller
                    );

    Status = gBS->CloseProtocol (
                    Controller,
                    &gEfiDevicePathProtocolGuid,
                    This->DriverBindingHandle,
                    Controller
                    );
    return Status;
  }

  AllChildrenStopped = TRUE;

  for (Index = 0; Index < NumberOfChildren; Index++) {

    Status = gBS->OpenProtocol (
                    ChildHandleBuffer[Index],
                    &gEfiSerialIoProtocolGuid,
                    (VOID **) &SerialIo,
                    This->DriverBindingHandle,
                    Controller,
                    EFI_OPEN_PROTOCOL_GET_PROTOCOL
                    );
    if (!EFI_ERROR (Status)) {

      SerialDevice = SERIAL_DEV_FROM_THIS (SerialIo);

      Status = gBS->CloseProtocol (
                      Controller,
                      EFI_ISA_IO_PROTOCOL_VERSION,
                      This->DriverBindingHandle,
                      ChildHandleBuffer[Index]
                      );

      Status = gBS->UninstallMultipleProtocolInterfaces (
                      ChildHandleBuffer[Index],
                      &gEfiDevicePathProtocolGuid,
                      SerialDevice->DevicePath,
                      &gEfiSerialIoProtocolGuid,
                      &SerialDevice->SerialIo,
                      NULL
                      );
      if (EFI_ERROR (Status)) {
        gBS->OpenProtocol (
               Controller,
               EFI_ISA_IO_PROTOCOL_VERSION,
               (VOID **) &IsaIo,
               This->DriverBindingHandle,
               ChildHandleBuffer[Index],
               EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
               );
      } else {
        if (SerialDevice->DevicePath) {
          gBS->FreePool (SerialDevice->DevicePath);
        }

        EfiLibFreeUnicodeStringTable (SerialDevice->ControllerNameTable);
        gBS->FreePool (SerialDevice);
      }
    }

    if (EFI_ERROR (Status)) {
      AllChildrenStopped = FALSE;
    }
  }

  if (!AllChildrenStopped) {
    return EFI_DEVICE_ERROR;
  }

  return EFI_SUCCESS;
}

BOOLEAN
IsaSerialFifoFull (
  IN SERIAL_DEV_FIFO *Fifo
  )
/*++

  Routine Description:
  
    Detect whether specific FIFO is full or not
  
  Arguments:
  
    Fifo  - A pointer to the Data Structure SERIAL_DEV_FIFO
    
  Returns:
  
    TRUE  - the FIFO is full
    FALSE - the FIFO is not full

--*/
{
  if (Fifo->Surplus == 0) {
    return TRUE;
  }

  return FALSE;
}

BOOLEAN
IsaSerialFifoEmpty (
  IN SERIAL_DEV_FIFO *Fifo
  )
/*++

  Routine Description:
  
    Detect whether specific FIFO is empty or not
  
  Arguments:
  
    Fifo  - A pointer to the Data Structure SERIAL_DEV_FIFO
    
  Returns:
  
    TRUE  - the FIFO is empty
    FALSE - the FIFO is not empty

--*/
{
  if (Fifo->Surplus == SERIAL_MAX_BUFFER_SIZE) {
    return TRUE;
  }

  return FALSE;
}

EFI_STATUS
IsaSerialFifoAdd (
  IN SERIAL_DEV_FIFO *Fifo,
  IN UINT8           Data
  )
/*++

  Routine Description:
  
    Add data to specific FIFO
  
  Arguments:
  
    Fifo                - A pointer to the Data Structure SERIAL_DEV_FIFO
    Data                - the data added to FIFO  
  
  Returns:
  
    EFI_SUCCESS         - Add data to specific FIFO successfully
    EFI_OUT_OF_RESOURCE - Failed to add data because FIFO is already full 

--*/
{
  //
  // if FIFO full can not add data
  //
  if (IsaSerialFifoFull (Fifo)) {
    return EFI_OUT_OF_RESOURCES;
  }
  //
  // FIFO is not full can add data
  //
  Fifo->Data[Fifo->Last] = Data;
  Fifo->Surplus--;
  Fifo->Last++;
  if (Fifo->Last == SERIAL_MAX_BUFFER_SIZE) {
    Fifo->Last = 0;
  }

  return EFI_SUCCESS;
}

EFI_STATUS
IsaSerialFifoRemove (
  IN  SERIAL_DEV_FIFO *Fifo,
  OUT UINT8           *Data
  )
/*++

  Routine Description:
  
    Remove data from specific FIFO
  
  Arguments:
  
    Fifo                - A pointer to the Data Structure SERIAL_DEV_FIFO
    Data                - the data removed from FIFO  
  
  Returns:
    EFI_SUCCESS         - Remove data from specific FIFO successfully
    EFI_OUT_OF_RESOURCE - Failed to remove data because FIFO is empty

--*/
{
  //
  // if FIFO is empty, no data can remove
  //
  if (IsaSerialFifoEmpty (Fifo)) {
    return EFI_OUT_OF_RESOURCES;
  }
  //
  // FIFO is not empty, can remove data
  //
  *Data = Fifo->Data[Fifo->First];
  Fifo->Surplus++;
  Fifo->First++;
  if (Fifo->First == SERIAL_MAX_BUFFER_SIZE) {
    Fifo->First = 0;
  }

  return EFI_SUCCESS;
}

EFI_STATUS
IsaSerialReceiveTransmit (
  IN SERIAL_DEV *SerialDevice
  )
/*++

  Routine Description:
  
    Reads and writes all avaliable data.
  
  Arguments:
  
    SerialDevice        - The device to flush
  
  Returns:
  
    EFI_SUCCESS         - Data was read/written successfully.
    EFI_OUT_OF_RESOURCE - Failed because software receive FIFO is full.  Note, when
                          this happens, pending writes are not done.

--*/
{
  SERIAL_PORT_LSR Lsr;
  UINT8           Data;
  BOOLEAN         ReceiveFifoFull;
  SERIAL_PORT_MSR Msr;
  SERIAL_PORT_MCR Mcr;
  UINTN           TimeOut;

  Data = 0;

  //
  // Begin the read or write
  //
  if (SerialDevice->SoftwareLoopbackEnable) {
    do {
      ReceiveFifoFull = IsaSerialFifoFull (&SerialDevice->Receive);
      if (!IsaSerialFifoEmpty (&SerialDevice->Transmit)) {
        IsaSerialFifoRemove (&SerialDevice->Transmit, &Data);
        if (ReceiveFifoFull) {
          return EFI_OUT_OF_RESOURCES;
        }

        IsaSerialFifoAdd (&SerialDevice->Receive, Data);
      }
    } while (!IsaSerialFifoEmpty (&SerialDevice->Transmit));
  } else {
    ReceiveFifoFull = IsaSerialFifoFull (&SerialDevice->Receive);
    do {
      Lsr.Data = READ_LSR (SerialDevice->IsaIo, SerialDevice->BaseAddress);
#ifdef EFI_NT_EMULATOR
      //
      // This is required for NT to avoid a forever-spin...
      // This would be better if READ_LSR was a polling operation
      // that would timeout.
      //
      Lsr.Bits.THRE = 1;
#endif
      //
      // Flush incomming data to prevent a an overrun during a long write
      //
      if (Lsr.Bits.DR && !ReceiveFifoFull) {
        ReceiveFifoFull = IsaSerialFifoFull (&SerialDevice->Receive);
        if (!ReceiveFifoFull) {
          if (Lsr.Bits.FIFOE || Lsr.Bits.OE || Lsr.Bits.PE || Lsr.Bits.FE || Lsr.Bits.BI) {
            ReportStatusCodeWithDevicePath (
              EFI_ERROR_CODE,
              EFI_P_EC_INPUT_ERROR | EFI_PERIPHERAL_SERIAL_PORT,
              0,
              &gEfiSerialIoProtocolGuid,
              SerialDevice->DevicePath
              );
            if (Lsr.Bits.FIFOE || Lsr.Bits.PE || Lsr.Bits.FE || Lsr.Bits.BI) {
              Data = READ_RBR (SerialDevice->IsaIo, SerialDevice->BaseAddress);
              continue;
            }
          }
          //
          // Make sure the receive data will not be missed, Assert DTR
          //
          if (SerialDevice->HardwareFlowControl) {
            Mcr.Data = READ_MCR (SerialDevice->IsaIo, SerialDevice->BaseAddress);
            Mcr.Bits.DTRC &= 0;
            WRITE_MCR (SerialDevice->IsaIo, SerialDevice->BaseAddress, Mcr.Data);
          }

          Data = READ_RBR (SerialDevice->IsaIo, SerialDevice->BaseAddress);

          //
          // Deassert DTR
          //
          if (SerialDevice->HardwareFlowControl) {
            Mcr.Data = READ_MCR (SerialDevice->IsaIo, SerialDevice->BaseAddress);
            Mcr.Bits.DTRC |= 1;
            WRITE_MCR (SerialDevice->IsaIo, SerialDevice->BaseAddress, Mcr.Data);
          }

          IsaSerialFifoAdd (&SerialDevice->Receive, Data);

          continue;
        } else {
          ReportStatusCodeWithDevicePath (
            EFI_PROGRESS_CODE,
            EFI_P_SERIAL_PORT_PC_CLEAR_BUFFER | EFI_PERIPHERAL_SERIAL_PORT,
            0,
            &gEfiSerialIoProtocolGuid,
            SerialDevice->DevicePath
            );
        }
      }
      //
      // Do the write
      //

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?