462 lines
12 KiB
C
462 lines
12 KiB
C
/** @file
|
|
Serial driver for standard UARTS on an ISA bus.
|
|
|
|
;******************************************************************************
|
|
;* Copyright (c) 2013, Insyde Software Corp. All Rights Reserved.
|
|
;*
|
|
;* You may not reproduce, distribute, publish, display, perform, modify, adapt,
|
|
;* transmit, broadcast, present, recite, release, license or otherwise exploit
|
|
;* any part of this publication in any form, by any means, without the prior
|
|
;* written permission of Insyde Software Corporation.
|
|
;*
|
|
;******************************************************************************
|
|
*/
|
|
|
|
#include <IsaUartDxe.h>
|
|
|
|
#define ISA_DEVICE_NAME_SIZE 50
|
|
#define ISA_DEVICE_NAME L"ISA_UART"
|
|
#define ISA_UART_REGISTER_BYTE_WIDTH sizeof(UINT8)
|
|
#define ISA_UART_FIFO_DEPTH 16
|
|
#define ISA_UART_SERIAL_CLOCK_FREQUENCY (1 * 115200 * 16)
|
|
#define ISA_UART_SIMPLE_RATE 16
|
|
|
|
#define ISA_16550_DEV_SIGNATURE SIGNATURE_32 ('I', 'S', 'A', 'U')
|
|
#define ISA_16550_DEV_FROM_THIS(a) CR (a, ISA_UART_DEVICE_DATA, U16550Access, ISA_16550_DEV_SIGNATURE)
|
|
|
|
//
|
|
// data type definitions
|
|
//
|
|
typedef struct {
|
|
UINT32 Signature;
|
|
EFI_ISA_IO_PROTOCOL *IsaIo;
|
|
UART_16550_DEVICE_INFO DeviceInfo;
|
|
H2O_UART_16550_ACCESS_PROTOCOL U16550Access;
|
|
} ISA_UART_DEVICE_DATA;
|
|
|
|
//
|
|
// ISA Serial Driver Global Variables
|
|
//
|
|
EFI_DRIVER_BINDING_PROTOCOL gIsaUartControllerDriver = {
|
|
Isa16550ControllerDriverSupported,
|
|
Isa16550ControllerDriverStart,
|
|
Isa16550ControllerDriverStop,
|
|
0x0A,
|
|
NULL,
|
|
NULL
|
|
};
|
|
|
|
extern EFI_COMPONENT_NAME_PROTOCOL gIsaUartComponentName;
|
|
extern EFI_COMPONENT_NAME2_PROTOCOL gIsaUartComponentName2;
|
|
|
|
/**
|
|
Use IsaIo protocol to read serial port.
|
|
|
|
@param IsaIo Pointer to EFI_ISA_IO_PROTOCOL instance
|
|
@param BaseAddress Serial port register group base address
|
|
@param Offset Offset in register group
|
|
|
|
@return Data read from serial port
|
|
|
|
**/
|
|
STATIC
|
|
UINT8
|
|
IsaSerialReadPort (
|
|
IN EFI_ISA_IO_PROTOCOL *IsaIo,
|
|
IN UINT16 BaseAddress,
|
|
IN UINT32 Offset
|
|
)
|
|
{
|
|
UINT8 Data;
|
|
|
|
//
|
|
// Use IsaIo to access IO
|
|
//
|
|
IsaIo->Io.Read (
|
|
IsaIo,
|
|
EfiIsaIoWidthUint8,
|
|
BaseAddress + Offset,
|
|
1,
|
|
&Data
|
|
);
|
|
return Data;
|
|
}
|
|
|
|
/**
|
|
Use IsaIo protocol to write serial port.
|
|
|
|
@param IsaIo Pointer to EFI_ISA_IO_PROTOCOL instance
|
|
@param BaseAddress Serial port register group base address
|
|
@param Offset Offset in register group
|
|
@param Data data which is to be written to some serial port register
|
|
|
|
**/
|
|
STATIC
|
|
VOID
|
|
IsaSerialWritePort (
|
|
IN EFI_ISA_IO_PROTOCOL *IsaIo,
|
|
IN UINT16 BaseAddress,
|
|
IN UINT32 Offset,
|
|
IN UINT8 Data
|
|
)
|
|
{
|
|
//
|
|
// Use IsaIo to access IO
|
|
//
|
|
IsaIo->Io.Write (
|
|
IsaIo,
|
|
EfiIsaIoWidthUint8,
|
|
BaseAddress + Offset,
|
|
1,
|
|
&Data
|
|
);
|
|
}
|
|
|
|
/**
|
|
The user Entry Point for module IsaSerial. The user code starts with this function.
|
|
|
|
@param[in] ImageHandle The firmware allocated handle for the EFI image.
|
|
@param[in] SystemTable A pointer to the EFI System Table.
|
|
|
|
@retval EFI_SUCCESS The entry point is executed successfully.
|
|
@retval other Some error occurs when executing this entry point.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
IsaUartEntryPoint (
|
|
IN EFI_HANDLE ImageHandle,
|
|
IN EFI_SYSTEM_TABLE *SystemTable
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
|
|
//
|
|
// Install driver model protocol(s).
|
|
//
|
|
Status = EfiLibInstallDriverBindingComponentName2 (
|
|
ImageHandle,
|
|
SystemTable,
|
|
&gIsaUartControllerDriver,
|
|
ImageHandle,
|
|
&gIsaUartComponentName,
|
|
&gIsaUartComponentName2
|
|
);
|
|
ASSERT_EFI_ERROR (Status);
|
|
|
|
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
Check to see if this driver supports the given controller
|
|
|
|
@param This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
|
|
@param Controller The handle of the controller to test.
|
|
@param RemainingDevicePath A pointer to the remaining portion of a device path.
|
|
|
|
@return EFI_SUCCESS This driver can support the given controller
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
Isa16550ControllerDriverSupported (
|
|
IN EFI_DRIVER_BINDING_PROTOCOL *This,
|
|
IN EFI_HANDLE Controller,
|
|
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
|
|
)
|
|
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_ISA_IO_PROTOCOL *IsaIo;
|
|
|
|
//
|
|
// Open the IO Abstraction(s) needed to perform the supported test
|
|
//
|
|
Status = gBS->OpenProtocol (
|
|
Controller,
|
|
&gEfiIsaIoProtocolGuid,
|
|
(VOID **) &IsaIo,
|
|
This->DriverBindingHandle,
|
|
Controller,
|
|
EFI_OPEN_PROTOCOL_BY_DRIVER
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// Use the ISA I/O Protocol to see if Controller is standard ISA UART that
|
|
// can be managed by this driver.
|
|
//
|
|
Status = EFI_SUCCESS;
|
|
if (IsaIo->ResourceList->Device.HID != EISA_PNP_ID (0x501)) {
|
|
Status = EFI_UNSUPPORTED;
|
|
}
|
|
|
|
//
|
|
// Close the I/O Abstraction(s) used to perform the supported test
|
|
//
|
|
gBS->CloseProtocol (
|
|
Controller,
|
|
&gEfiIsaIoProtocolGuid,
|
|
This->DriverBindingHandle,
|
|
Controller
|
|
);
|
|
|
|
return Status;
|
|
}
|
|
|
|
EFI_STATUS
|
|
InitIsa16550DeviceData (
|
|
ISA_UART_DEVICE_DATA *Isa16550Device,
|
|
EFI_ISA_IO_PROTOCOL *IsaIo
|
|
)
|
|
{
|
|
UART_16550_DEVICE_INFO *DevInfo;
|
|
UINT16 UID;
|
|
CHAR16 *Name;
|
|
UINT8 IsaIRQ;
|
|
UINTN Index;
|
|
UINTN NameSize;
|
|
UINTN BaseAddress;
|
|
|
|
IsaIRQ = 0;
|
|
BaseAddress = 0;
|
|
|
|
for (Index = 0; IsaIo->ResourceList->ResourceItem[Index].Type != EfiIsaAcpiResourceEndOfList; Index++) {
|
|
if (IsaIo->ResourceList->ResourceItem[Index].Type == EfiIsaAcpiResourceIo) {
|
|
BaseAddress = (UINTN)IsaIo->ResourceList->ResourceItem[Index].StartRange;
|
|
} else if (IsaIo->ResourceList->ResourceItem[Index].Type == EfiIsaAcpiResourceInterrupt) {
|
|
IsaIRQ = (UINT8)IsaIo->ResourceList->ResourceItem[Index].StartRange;
|
|
}
|
|
}
|
|
|
|
UID = (UINT16)IsaIo->ResourceList->Device.UID;
|
|
|
|
//
|
|
// Set Device Name
|
|
//
|
|
NameSize = ISA_DEVICE_NAME_SIZE;
|
|
Name = AllocateZeroPool (NameSize);
|
|
|
|
UnicodeSPrint (
|
|
Name,
|
|
NameSize,
|
|
L"%s (COM%d)",
|
|
ISA_DEVICE_NAME,
|
|
(UID+1)
|
|
);
|
|
|
|
//
|
|
// Initialize PCI_HS_UART_DEVICE_DATA structure
|
|
//
|
|
Isa16550Device->Signature = ISA_16550_DEV_SIGNATURE;
|
|
Isa16550Device->IsaIo = IsaIo;
|
|
|
|
DevInfo = &Isa16550Device->DeviceInfo;
|
|
DevInfo->DeviceName = Name;
|
|
DevInfo->DeviceType = ISA_SERIAL_DEVICE;
|
|
DevInfo->UID = UID;
|
|
DevInfo->RegisterByteWidth = ISA_UART_REGISTER_BYTE_WIDTH;
|
|
DevInfo->BaseAddressType = UBAT_IO;
|
|
DevInfo->BaseAddress = BaseAddress;
|
|
DevInfo->DevIRQ = IsaIRQ;
|
|
DevInfo->FifoSize = ISA_UART_FIFO_DEPTH;
|
|
DevInfo->SerialClockFreq = ISA_UART_SERIAL_CLOCK_FREQUENCY;
|
|
DevInfo->SampleRate = ISA_UART_SIMPLE_RATE;
|
|
DevInfo->LegacySupport = TRUE;
|
|
DevInfo->UartUid = 0; // Set at uart16550serial driver.
|
|
|
|
Isa16550Device->U16550Access.RegRead = Isa16550DeviceRegRead;
|
|
Isa16550Device->U16550Access.RegWrite = Isa16550DeviceRegWrite;
|
|
Isa16550Device->U16550Access.DeviceInfo = DevInfo;
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
|
|
/**
|
|
Start to management the controller passed in
|
|
|
|
@param This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
|
|
@param Controller The handle of the controller to test.
|
|
@param RemainingDevicePath A pointer to the remaining portion of a device path.
|
|
|
|
@return EFI_SUCCESS Driver is started successfully
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
Isa16550ControllerDriverStart (
|
|
IN EFI_DRIVER_BINDING_PROTOCOL *This,
|
|
IN EFI_HANDLE Controller,
|
|
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
|
|
)
|
|
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_ISA_IO_PROTOCOL *IsaIo;
|
|
ISA_UART_DEVICE_DATA *Isa16550Device;
|
|
|
|
Isa16550Device = NULL;
|
|
|
|
//
|
|
// Grab the IO abstraction we need to get any work done
|
|
//
|
|
Status = gBS->OpenProtocol (
|
|
Controller,
|
|
&gEfiIsaIoProtocolGuid,
|
|
(VOID **) &IsaIo,
|
|
This->DriverBindingHandle,
|
|
Controller,
|
|
EFI_OPEN_PROTOCOL_BY_DRIVER
|
|
);
|
|
if (EFI_ERROR(Status)) {
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// Initialize the serial device instance
|
|
//
|
|
Isa16550Device = AllocateZeroPool (sizeof (ISA_UART_DEVICE_DATA));
|
|
if (Isa16550Device == NULL) {
|
|
Status = EFI_OUT_OF_RESOURCES;
|
|
goto Error;
|
|
}
|
|
|
|
//
|
|
// Initialize the device Private data
|
|
//
|
|
Status = InitIsa16550DeviceData (Isa16550Device, IsaIo);
|
|
if (EFI_ERROR(Status)) {
|
|
goto Error;
|
|
}
|
|
|
|
//
|
|
// Install Uart16550Access protocol on the contorller handle
|
|
//
|
|
Status = gBS->InstallProtocolInterface (
|
|
&Controller,
|
|
&gH2OCrUart16550AccessProtocolGuid,
|
|
EFI_NATIVE_INTERFACE,
|
|
&Isa16550Device->U16550Access
|
|
);
|
|
if (EFI_ERROR(Status)) {
|
|
goto Error;
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
|
|
Error:
|
|
|
|
if (Isa16550Device != NULL) {
|
|
FreePool (Isa16550Device);
|
|
}
|
|
|
|
gBS->CloseProtocol (
|
|
Controller,
|
|
&gEfiIsaIoProtocolGuid,
|
|
This->DriverBindingHandle,
|
|
Controller
|
|
);
|
|
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
Disconnect this driver with the controller, uninstall related protocol instance
|
|
|
|
@param This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
|
|
@param Controller The handle of the controller to test.
|
|
@param NumberOfChildren Number of child device.
|
|
@param ChildHandleBuffer A pointer to the remaining portion of a device path.
|
|
|
|
@retval EFI_SUCCESS Operation successfully
|
|
@retval EFI_DEVICE_ERROR Cannot stop the driver successfully
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
Isa16550ControllerDriverStop (
|
|
IN EFI_DRIVER_BINDING_PROTOCOL *This,
|
|
IN EFI_HANDLE Controller,
|
|
IN UINTN NumberOfChildren,
|
|
IN EFI_HANDLE *ChildHandleBuffer
|
|
)
|
|
|
|
{
|
|
EFI_STATUS Status;
|
|
H2O_UART_16550_ACCESS_PROTOCOL *Protocol;
|
|
ISA_UART_DEVICE_DATA *Isa16550Device;
|
|
|
|
Status = gBS->OpenProtocol (
|
|
Controller,
|
|
&gH2OCrUart16550AccessProtocolGuid,
|
|
(VOID**)&Protocol,
|
|
This->DriverBindingHandle,
|
|
Controller,
|
|
EFI_OPEN_PROTOCOL_GET_PROTOCOL
|
|
);
|
|
|
|
if (EFI_ERROR(Status)) {
|
|
return Status;
|
|
}
|
|
|
|
Isa16550Device = ISA_16550_DEV_FROM_THIS (Protocol);
|
|
|
|
Status = gBS->UninstallProtocolInterface (
|
|
Controller,
|
|
&gH2OCrUart16550AccessProtocolGuid,
|
|
&Isa16550Device->U16550Access
|
|
);
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
gBS->CloseProtocol (
|
|
Controller,
|
|
&gEfiIsaIoProtocolGuid,
|
|
This->DriverBindingHandle,
|
|
Controller
|
|
);
|
|
|
|
gBS->FreePool (Isa16550Device);
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
EFI_STATUS
|
|
Isa16550DeviceRegRead (
|
|
H2O_UART_16550_ACCESS_PROTOCOL *This,
|
|
UINT16 Index,
|
|
UINT8 *Data
|
|
)
|
|
{
|
|
ISA_UART_DEVICE_DATA *Isa16550Device;
|
|
|
|
Isa16550Device = ISA_16550_DEV_FROM_THIS (This);
|
|
|
|
*Data = IsaSerialReadPort (Isa16550Device->IsaIo, (UINT16)Isa16550Device->DeviceInfo.BaseAddress, (UINT16)Index);
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
EFI_STATUS
|
|
Isa16550DeviceRegWrite (
|
|
H2O_UART_16550_ACCESS_PROTOCOL *This,
|
|
UINT16 Index,
|
|
UINT8 Data
|
|
)
|
|
{
|
|
ISA_UART_DEVICE_DATA *Isa16550Device;
|
|
|
|
Isa16550Device = ISA_16550_DEV_FROM_THIS (This);
|
|
|
|
IsaSerialWritePort (Isa16550Device->IsaIo, (UINT16)Isa16550Device->DeviceInfo.BaseAddress, (UINT16)Index, Data);
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|