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