Ray, This looks good. I tested the baud rate check and calculations.
Reviewed-by: Michael Kinney <[email protected]> Mike > -----Original Message----- > From: Ni, Ruiyu > Sent: Wednesday, December 9, 2015 6:21 PM > To: [email protected] > Cc: Ni, Ruiyu <[email protected]>; Tian, Feng <[email protected]>; Kinney, > Michael D <[email protected]> > Subject: [Patch] MdeModulePkg: Add PciSioSerialDxe driver > > PciSioSerialDxe driver can manages UARTs on a SIO chip or a PCI/PCIE > card. > It manages the SIO instance whose last device path node is a ACPI > device path and the HID in the ACPI device path node equals to > EISA_PNP_ID (0x501). > It also manages the PCI IO instance whose class code is 7/0/2 (16550 > UART). But when proper value is set to PcdPciSerialParameters, the > driver can also manage non-standard PCI serial cards by matching > the Vendor ID and Device ID specified in PcdPciSerialParameters. > The PCI BAR index, IO/MMIO offset, register stride, clock rate can > also be specified through the same PCD. > > Contributed-under: TianoCore Contribution Agreement 1.0 > Signed-off-by: Ruiyu Ni <[email protected]> > Cc: Feng Tian <[email protected]> > Cc: Michael Kinney <[email protected]> > --- > .../Bus/Pci/PciSioSerialDxe/ComponentName.c | 288 +++++ > .../Bus/Pci/PciSioSerialDxe/PciSioSerialDxe.inf | 81 ++ > .../Bus/Pci/PciSioSerialDxe/PciSioSerialDxe.uni | Bin 0 -> 1940 bytes > .../Pci/PciSioSerialDxe/PciSioSerialDxeExtra.uni | Bin 0 -> 1380 bytes > MdeModulePkg/Bus/Pci/PciSioSerialDxe/Serial.c | 1243 ++++++++++++++++++ > MdeModulePkg/Bus/Pci/PciSioSerialDxe/Serial.h | 789 ++++++++++++ > MdeModulePkg/Bus/Pci/PciSioSerialDxe/SerialIo.c | 1321 > ++++++++++++++++++++ > MdeModulePkg/MdeModulePkg.dec | 38 + > MdeModulePkg/MdeModulePkg.dsc | 1 + > 9 files changed, 3761 insertions(+) > create mode 100644 MdeModulePkg/Bus/Pci/PciSioSerialDxe/ComponentName.c > create mode 100644 MdeModulePkg/Bus/Pci/PciSioSerialDxe/PciSioSerialDxe.inf > create mode 100644 MdeModulePkg/Bus/Pci/PciSioSerialDxe/PciSioSerialDxe.uni > create mode 100644 > MdeModulePkg/Bus/Pci/PciSioSerialDxe/PciSioSerialDxeExtra.uni > create mode 100644 MdeModulePkg/Bus/Pci/PciSioSerialDxe/Serial.c > create mode 100644 MdeModulePkg/Bus/Pci/PciSioSerialDxe/Serial.h > create mode 100644 MdeModulePkg/Bus/Pci/PciSioSerialDxe/SerialIo.c > > diff --git a/MdeModulePkg/Bus/Pci/PciSioSerialDxe/ComponentName.c > b/MdeModulePkg/Bus/Pci/PciSioSerialDxe/ComponentName.c > new file mode 100644 > index 0000000..994dc84 > --- /dev/null > +++ b/MdeModulePkg/Bus/Pci/PciSioSerialDxe/ComponentName.c > @@ -0,0 +1,288 @@ > +/** @file > + UEFI Component Name and Name2 protocol for Isa serial driver. > + > +Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.<BR> > +This program and the accompanying materials > +are licensed and made available under the terms and conditions of the BSD > License > +which accompanies this distribution. The full text of the license may be > found at > +http://opensource.org/licenses/bsd-license.php > + > +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, > +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. > + > +**/ > + > +#include "Serial.h" > + > +// > +// EFI Component Name Protocol > +// > +GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL > gPciSioSerialComponentName = { > + SerialComponentNameGetDriverName, > + SerialComponentNameGetControllerName, > + "eng" > +}; > + > +// > +// EFI Component Name 2 Protocol > +// > +GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL > gPciSioSerialComponentName2 = { > + (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) SerialComponentNameGetDriverName, > + (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) > SerialComponentNameGetControllerName, > + "en" > +}; > + > + > +GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE > mSerialDriverNameTable[] = { > + { > + "eng;en", > + L"PCI SIO Serial Driver" > + }, > + { > + NULL, > + NULL > + } > +}; > + > +GLOBAL_REMOVE_IF_UNREFERENCED CHAR16 mSioSerialPortName[] = L"SIO Serial > Port #%d"; > +GLOBAL_REMOVE_IF_UNREFERENCED CHAR16 mPciSerialPortName[] = L"PCI Serial > Port #%d"; > + > +/** > + Retrieves a Unicode string that is the user readable name of the driver. > + > + This function retrieves the user readable name of a driver in the form of a > + Unicode string. If the driver specified by This has a user readable name in > + the language specified by Language, then a pointer to the driver name is > + returned in DriverName, and EFI_SUCCESS is returned. If the driver > specified > + by This does not support the language specified by Language, > + then EFI_UNSUPPORTED is returned. > + > + @param This[in] A pointer to the > EFI_COMPONENT_NAME2_PROTOCOL or > + EFI_COMPONENT_NAME_PROTOCOL instance. > + > + @param Language[in] A pointer to a Null-terminated ASCII string > + array indicating the language. This is the > + language of the driver name that the caller > is > + requesting, and it must match one of the > + languages specified in SupportedLanguages. > The > + number of languages supported by a driver is > up > + to the driver writer. Language is specified > + in RFC 4646 or ISO 639-2 language code > format. > + > + @param DriverName[out] A pointer to the Unicode string to return. > + This Unicode string is the name of the > + driver specified by This in the language > + specified by Language. > + > + @retval EFI_SUCCESS The Unicode string for the Driver specified > by > + This and the language specified by Language > was > + returned in DriverName. > + > + @retval EFI_INVALID_PARAMETER Language is NULL. > + > + @retval EFI_INVALID_PARAMETER DriverName is NULL. > + > + @retval EFI_UNSUPPORTED The driver specified by This does not support > + the language specified by Language. > + > +**/ > +EFI_STATUS > +EFIAPI > +SerialComponentNameGetDriverName ( > + IN EFI_COMPONENT_NAME_PROTOCOL *This, > + IN CHAR8 *Language, > + OUT CHAR16 **DriverName > + ) > +{ > + return LookupUnicodeString2 ( > + Language, > + This->SupportedLanguages, > + mSerialDriverNameTable, > + DriverName, > + (BOOLEAN)(This == &gPciSioSerialComponentName) > + ); > +} > + > +/** > + Retrieves a Unicode string that is the user readable name of the controller > + that is being managed by a driver. > + > + This function retrieves the user readable name of the controller specified > by > + ControllerHandle and ChildHandle in the form of a Unicode string. If the > + driver specified by This has a user readable name in the language > specified by > + Language, then a pointer to the controller name is returned in > ControllerName, > + and EFI_SUCCESS is returned. If the driver specified by This is not > currently > + managing the controller specified by ControllerHandle and ChildHandle, > + then EFI_UNSUPPORTED is returned. If the driver specified by This does not > + support the language specified by Language, then EFI_UNSUPPORTED is > returned. > + > + @param This[in] A pointer to the > EFI_COMPONENT_NAME2_PROTOCOL or > + EFI_COMPONENT_NAME_PROTOCOL instance. > + > + @param ControllerHandle[in] The handle of a controller that the driver > + specified by This is managing. This handle > + specifies the controller whose name is to be > + returned. > + > + @param ChildHandle[in] The handle of the child controller to > retrieve > + the name of. This is an optional parameter > that > + may be NULL. It will be NULL for device > + drivers. It will also be NULL for a bus > drivers > + that wish to retrieve the name of the bus > + controller. It will not be NULL for a bus > + driver that wishes to retrieve the name of a > + child controller. > + > + @param Language[in] A pointer to a Null-terminated ASCII string > + array indicating the language. This is the > + language of the driver name that the caller > is > + requesting, and it must match one of the > + languages specified in SupportedLanguages. > The > + number of languages supported by a driver is > up > + to the driver writer. Language is specified > in > + RFC 4646 or ISO 639-2 language code format. > + > + @param ControllerName[out] A pointer to the Unicode string to return. > + This Unicode string is the name of the > + controller specified by ControllerHandle and > + ChildHandle in the language specified by > + Language from the point of view of the driver > + specified by This. > + > + @retval EFI_SUCCESS The Unicode string for the user readable > name in > + the language specified by Language for the > + driver specified by This was returned in > + DriverName. > + > + @retval EFI_INVALID_PARAMETER ControllerHandle is NULL. > + > + @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid > + EFI_HANDLE. > + > + @retval EFI_INVALID_PARAMETER Language is NULL. > + > + @retval EFI_INVALID_PARAMETER ControllerName is NULL. > + > + @retval EFI_UNSUPPORTED The driver specified by This is not currently > + managing the controller specified by > + ControllerHandle and ChildHandle. > + > + @retval EFI_UNSUPPORTED The driver specified by This does not support > + the language specified by Language. > + > +**/ > +EFI_STATUS > +EFIAPI > +SerialComponentNameGetControllerName ( > + IN EFI_COMPONENT_NAME_PROTOCOL *This, > + IN EFI_HANDLE ControllerHandle, > + IN EFI_HANDLE ChildHandle > OPTIONAL, > + IN CHAR8 *Language, > + OUT CHAR16 **ControllerName > + ) > +{ > + EFI_STATUS Status; > + EFI_SERIAL_IO_PROTOCOL *SerialIo; > + SERIAL_DEV *SerialDevice; > + EFI_UNICODE_STRING_TABLE *ControllerNameTable; > + EFI_GUID *IoProtocolGuid; > + > + // > + // Make sure this driver is currently managing ControllerHandle > + // > + IoProtocolGuid = &gEfiSioProtocolGuid; > + Status = EfiTestManagedDevice ( > + ControllerHandle, > + gSerialControllerDriver.DriverBindingHandle, > + IoProtocolGuid > + ); > + if (EFI_ERROR (Status)) { > + IoProtocolGuid = &gEfiPciIoProtocolGuid; > + Status = EfiTestManagedDevice ( > + ControllerHandle, > + gSerialControllerDriver.DriverBindingHandle, > + IoProtocolGuid > + ); > + } > + > + if (EFI_ERROR (Status)) { > + return Status; > + } > + > + ControllerNameTable = NULL; > + if (ChildHandle != NULL) { > + Status = EfiTestChildHandle ( > + ControllerHandle, > + ChildHandle, > + IoProtocolGuid > + ); > + if (EFI_ERROR (Status)) { > + return Status; > + } > + > + // > + // Get the Serial I/O Protocol from the child handle > + // > + Status = gBS->OpenProtocol ( > + ChildHandle, > + &gEfiSerialIoProtocolGuid, > + (VOID **) &SerialIo, > + gSerialControllerDriver.DriverBindingHandle, > + ChildHandle, > + EFI_OPEN_PROTOCOL_GET_PROTOCOL > + ); > + if (EFI_ERROR (Status)) { > + return Status; > + } > + > + // > + // Get the Serial Controller's Device structure > + // > + SerialDevice = SERIAL_DEV_FROM_THIS (SerialIo); > + ControllerNameTable = SerialDevice->ControllerNameTable; > + } > + > + return LookupUnicodeString2 ( > + Language, > + This->SupportedLanguages, > + ControllerNameTable, > + ControllerName, > + (BOOLEAN)(This == &gPciSioSerialComponentName) > + ); > +} > + > +/** > + Add the ISO639-2 and RFC4646 component name both for the Serial IO device > + > + @param SerialDevice A pointer to the SERIAL_DEV instance. > + @param Instance Instance ID for the serial device. > +**/ > +VOID > +AddName ( > + IN SERIAL_DEV *SerialDevice, > + IN UINT32 Instance > + ) > +{ > + CHAR16 > SerialPortName[SERIAL_PORT_NAME_LEN]; > + UnicodeSPrint ( > + SerialPortName, > + sizeof (SerialPortName), > + (SerialDevice->PciDeviceInfo != NULL) ? PCI_SERIAL_PORT_NAME : > SIO_SERIAL_PORT_NAME, > + Instance > + ); > + AddUnicodeString2 ( > + "eng", > + gPciSioSerialComponentName.SupportedLanguages, > + &SerialDevice->ControllerNameTable, > + SerialPortName, > + TRUE > + ); > + AddUnicodeString2 ( > + "en", > + gPciSioSerialComponentName2.SupportedLanguages, > + &SerialDevice->ControllerNameTable, > + SerialPortName, > + FALSE > + ); > + > +} > diff --git a/MdeModulePkg/Bus/Pci/PciSioSerialDxe/PciSioSerialDxe.inf > b/MdeModulePkg/Bus/Pci/PciSioSerialDxe/PciSioSerialDxe.inf > new file mode 100644 > index 0000000..af92e02 > --- /dev/null > +++ b/MdeModulePkg/Bus/Pci/PciSioSerialDxe/PciSioSerialDxe.inf > @@ -0,0 +1,81 @@ > +## @file > +# Serial driver for standard UARTS on a SIO chip or PCI/PCIE card. > +# > +# Produces the Serial I/O protocol for standard UARTS using Super I/O or PCI > I/O. > +# > +# Copyright (c) 2007 - 2015, Intel Corporation. All rights reserved.<BR> > +# > +# This program and the accompanying materials > +# are licensed and made available under the terms and conditions of the BSD > License > +# which accompanies this distribution. The full text of the license may be > found at > +# http://opensource.org/licenses/bsd-license.php > +# > +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, > +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR > IMPLIED. > +# > +## > + > +[Defines] > + INF_VERSION = 0x00010005 > + BASE_NAME = PciSioSerialDxe > + MODULE_UNI_FILE = PciSioSerialDxe.uni > + FILE_GUID = E2775B47-D453-4EE3-ADA7-391A1B05AC17 > + MODULE_TYPE = UEFI_DRIVER > + VERSION_STRING = 1.0 > + ENTRY_POINT = InitializePciSioSerial > + > +# > +# The following information is for reference only and not required by the > build tools. > +# > +# VALID_ARCHITECTURES = IA32 X64 IPF EBC > +# > +# DRIVER_BINDING = gSerialControllerDriver > +# COMPONENT_NAME = gPciSioSerialComponentName > +# COMPONENT_NAME2 = gPciSioSerialComponentName2 > +# > + > +[Sources] > + ComponentName.c > + SerialIo.c > + Serial.h > + Serial.c > + > +[Packages] > + MdePkg/MdePkg.dec > + MdeModulePkg/MdeModulePkg.dec > + > +[LibraryClasses] > + PcdLib > + ReportStatusCodeLib > + UefiBootServicesTableLib > + MemoryAllocationLib > + BaseMemoryLib > + DevicePathLib > + UefiLib > + UefiDriverEntryPoint > + DebugLib > + IoLib > + > +[Guids] > + gEfiUartDevicePathGuid ## SOMETIMES_CONSUMES ## > GUID > + > +[Protocols] > + gEfiSioProtocolGuid ## TO_START > + gEfiDevicePathProtocolGuid ## TO_START > + gEfiPciIoProtocolGuid ## TO_START > + gEfiSerialIoProtocolGuid ## BY_START > + gEfiDevicePathProtocolGuid ## BY_START > + > +[FeaturePcd] > + gEfiMdeModulePkgTokenSpaceGuid.PcdSerialUseHalfHandshake|FALSE ## > CONSUMES > + > +[Pcd] > + gEfiMdePkgTokenSpaceGuid.PcdUartDefaultBaudRate|115200 ## CONSUMES > + gEfiMdePkgTokenSpaceGuid.PcdUartDefaultDataBits|8 ## CONSUMES > + gEfiMdePkgTokenSpaceGuid.PcdUartDefaultParity|1 ## CONSUMES > + gEfiMdePkgTokenSpaceGuid.PcdUartDefaultStopBits|1 ## CONSUMES > + gEfiMdeModulePkgTokenSpaceGuid.PcdSerialClockRate|1843200 ## CONSUMES > + gEfiMdeModulePkgTokenSpaceGuid.PcdPciSerialParameters ## CONSUMES > + > +[UserExtensions.TianoCore."ExtraFiles"] > + PciSioSerialDxeExtra.uni > diff --git a/MdeModulePkg/Bus/Pci/PciSioSerialDxe/PciSioSerialDxe.uni > b/MdeModulePkg/Bus/Pci/PciSioSerialDxe/PciSioSerialDxe.uni > new file mode 100644 > index > 0000000000000000000000000000000000000000..44ff6ef58285c0430c97e863d0daf9bbf39a9e66 > GIT binary patch > literal 1940 > zcmd6o-D?w35XI+N@PD|ZFDh-Kf(RmF+OE2&-H;EePqJ;=W}$7$CaLzHSAS<VyEh3D > z`=*5ZHFxfrbI;7({QB9kjs@Bie!<?_xfOP4XZFw@VAbA$Rf#pn9&GIMTek(gr>uj` > zY|j2QyE*GImXUR>Z$nN8e6Hzp+Q3rF7*A~i;*Ia=e9sQp=`6>@Ju0Mj!z4255o1b} > z1vqEK4n&_Y+vF-lMZ0nTIcH93y2br?FTgI~e&NUqaHK?Vroyf6UU9Fj+xQ;fd1H5+ > zEx?+<HrOM$JZ5}uPx-xMwzph8vlq6@JSFm+h~g`R5)Ab@)`Ho!wb|*iFOP^VJxbR_ > zY?Y}op0916e7xDB=FoGYQ<Y8^9^;C2mC>kf4reKNg{SuJ8g;ImRjiX)6Gtdw6JS|z > z`iyfk=M?dEdh9+qd~^IR=}+i&ZovudO8Gj^(xrrlSl2AYOrAxfk9MczI-c970uNb# > zTH_Kc>$_{A>J;w!Z3|)wQ5*`NDV8c<+MmF4H7`<C?9Z`R84~9o_-t}o*ClYP9AyKD > z)%odC0Wq4d=&CxJlZjXUPE}!*w(>7s={C17skqLD_A@LeFdtKM>(SewOlVP&I2+mr > zOW@U`jxu{s-?h)IQ-9-!J`S;_RN9D_pSaQ^J7P?*2W%BW%tA_KCwL4TIb)`ZR^MVA > zEYVwx`@UAJ-4%AnL=$S}5rZA$)puq`*i%r2k$Ln!D{+@iF^BldM^P)Uclav$SH_R* > zh`C;3vW!yQBC#(GPDD@9qDNgR<{|H`)~z0ce_=armrZS_sh;{9BmKUClz}k<En(H= > z?gN-g?*qp0$KMXw)N8n)0&;rQk7{BMEHQ1-$2a;fzU8gv{`b4PDrdm0RaLzvTiX=) > M``!QVe~qZjZ@CO8UH||9 > > literal 0 > HcmV?d00001 > > diff --git a/MdeModulePkg/Bus/Pci/PciSioSerialDxe/PciSioSerialDxeExtra.uni > b/MdeModulePkg/Bus/Pci/PciSioSerialDxe/PciSioSerialDxeExtra.uni > new file mode 100644 > index > 0000000000000000000000000000000000000000..1de340ac907d59af1d83c86f8a04f239742af182 > GIT binary patch > literal 1380 > zcmZXUTW`}q5QXO%iT|()FM!&Fi+Di@ku(M@N*(1Q;3;x0O)ce8ISDlUc;GwZ*lvm< > z@9fUboH=`THh=%LtYv}kIlo{Z?AkJ0+T0%7BfQ${*%aS^Z^JmZoLNdt*X~#ayTm_r > zPiDXI%<v6t=W%OW*p_u_YxiFeyJm0hV_BoL!L)yC2hUyD4Uxf~g8mHq%3jz@d(G^; > zTD`F|=J648$y^9I7#dUZ#d>W`cG_@Og!mWOVwS^Y%a_|v=ian;*0H|5uN0`+4Plh| > zd2Wf{fT9{JP|EY|h>#{JoTo&rV4}SPdD0@_5vy9oZB<8EViRDQku8nHOnR31%AR>l > z3g48tCF6uqd3!Rnn=>z&6tz|-w;*PU%qo4P#D=@C^E%vNm-Xcdms*QouEmt`|I=o0 > z5TZB~da2fywX~nW^Zva^Rk6RuU)+#5-x2eW)2S|nmItCH$NbGv0WsR$(^Y-6<0jsE > zN2|jMZ55xp(oIgEb3d&I+HdhpU_PVgPOCRTx#24nDQ&Q!eYOZzJ-R5dPmFE*$~s2T > zfTprTyfJ+?Vivj1BfG*z_-lmv4r2N`B4Xgk2{ZMx#s*fnLTz9>zSioj;uh>1`{I>& > zMXlRZ60<A(F{r{wyn3INxXY)SL!uO;szuaCVwL#=`-L4b*E@`kRf<zY_PxTX(POme > z(N(J1<z1G#l{WZ4QOo`EJ*oPpct3@9<D<GgQ2Nyg#$YF)j=+y>3@<6KyC{(KR)n(0 > yF1%;d2j|3#pJE!|UcgQNU^;PNPf88lQ@>j2y!RgOa!OU`dT;ALBnL%U<@XPs4%3VP > > literal 0 > HcmV?d00001 > > diff --git a/MdeModulePkg/Bus/Pci/PciSioSerialDxe/Serial.c > b/MdeModulePkg/Bus/Pci/PciSioSerialDxe/Serial.c > new file mode 100644 > index 0000000..3219cb4 > --- /dev/null > +++ b/MdeModulePkg/Bus/Pci/PciSioSerialDxe/Serial.c > @@ -0,0 +1,1243 @@ > +/** @file > + Serial driver for PCI or SIO UARTS. > + > +Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.<BR> > +This program and the accompanying materials > +are licensed and made available under the terms and conditions of the BSD > License > +which accompanies this distribution. The full text of the license may be > found at > +http://opensource.org/licenses/bsd-license.php > + > +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, > +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. > + > +**/ > + > +#include "Serial.h" > + > +// > +// ISA Serial Driver Global Variables > +// > + > +EFI_DRIVER_BINDING_PROTOCOL gSerialControllerDriver = { > + SerialControllerDriverSupported, > + SerialControllerDriverStart, > + SerialControllerDriverStop, > + 0xa, > + NULL, > + NULL > +}; > + > +CONTROLLER_DEVICE_PATH mControllerDevicePathTemplate = { > + { > + HARDWARE_DEVICE_PATH, > + HW_CONTROLLER_DP, > + sizeof (CONTROLLER_DEVICE_PATH), > + 0 > + }, > + 0 > +}; > + > +SERIAL_DEV gSerialDevTemplate = { > + SERIAL_DEV_SIGNATURE, > + NULL, > + { > + SERIAL_IO_INTERFACE_REVISION, > + SerialReset, > + SerialSetAttributes, > + SerialSetControl, > + SerialGetControl, > + SerialWrite, > + SerialRead, > + NULL > + }, // SerialIo > + { > + SERIAL_PORT_SUPPORT_CONTROL_MASK, > + SERIAL_PORT_DEFAULT_TIMEOUT, > + 0, > + 16, > + 0, > + 0, > + 0 > + }, // SerialMode > + NULL, // DevicePath > + NULL, // ParentDevicePath > + { > + { > + MESSAGING_DEVICE_PATH, > + MSG_UART_DP, > + { > + (UINT8) (sizeof (UART_DEVICE_PATH)), > + (UINT8) ((sizeof (UART_DEVICE_PATH)) >> 8) > + } > + }, > + 0, 0, 0, 0, 0 > + }, // UartDevicePath > + 0, // BaseAddress > + FALSE, // MmioAccess > + 1, // RegisterStride > + 0, // ClockRate > + 16, // ReceiveFifoDepth > + { 0, 0 }, // Receive; > + 16, // TransmitFifoDepth > + { 0, 0 }, // Transmit; > + FALSE, // SoftwareLoopbackEnable; > + FALSE, // HardwareFlowControl; > + NULL, // *ControllerNameTable; > + FALSE, // ContainsControllerNode; > + 0, // Instance; > + NULL // *PciDeviceInfo; > +}; > + > +/** > + Check the device path node whether it's the Flow Control node or not. > + > + @param[in] FlowControl The device path node to be checked. > + > + @retval TRUE It's the Flow Control node. > + @retval FALSE It's not. > + > +**/ > +BOOLEAN > +IsUartFlowControlDevicePathNode ( > + IN UART_FLOW_CONTROL_DEVICE_PATH *FlowControl > + ) > +{ > + return (BOOLEAN) ( > + (DevicePathType (FlowControl) == MESSAGING_DEVICE_PATH) && > + (DevicePathSubType (FlowControl) == MSG_VENDOR_DP) && > + (CompareGuid (&FlowControl->Guid, &gEfiUartDevicePathGuid)) > + ); > +} > + > +/** > + The user Entry Point for module PciSioSerial. 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 > +InitializePciSioSerial ( > + IN EFI_HANDLE ImageHandle, > + IN EFI_SYSTEM_TABLE *SystemTable > + ) > +{ > + EFI_STATUS Status; > + > + // > + // Install driver model protocol(s). > + // > + Status = EfiLibInstallDriverBindingComponentName2 ( > + ImageHandle, > + SystemTable, > + &gSerialControllerDriver, > + ImageHandle, > + &gPciSioSerialComponentName, > + &gPciSioSerialComponentName2 > + ); > + ASSERT_EFI_ERROR (Status); > + > + // > + // Initialize UART default setting in gSerialDevTempate > + // > + gSerialDevTemplate.SerialMode.BaudRate = PcdGet64 (PcdUartDefaultBaudRate); > + gSerialDevTemplate.SerialMode.DataBits = PcdGet8 (PcdUartDefaultDataBits); > + gSerialDevTemplate.SerialMode.Parity = PcdGet8 (PcdUartDefaultParity); > + gSerialDevTemplate.SerialMode.StopBits = PcdGet8 (PcdUartDefaultStopBits); > + gSerialDevTemplate.UartDevicePath.BaudRate = PcdGet64 > (PcdUartDefaultBaudRate); > + gSerialDevTemplate.UartDevicePath.DataBits = PcdGet8 > (PcdUartDefaultDataBits); > + gSerialDevTemplate.UartDevicePath.Parity = PcdGet8 > (PcdUartDefaultParity); > + gSerialDevTemplate.UartDevicePath.StopBits = PcdGet8 > (PcdUartDefaultStopBits); > + gSerialDevTemplate.ClockRate = PcdGet32 (PcdSerialClockRate); > + > + return Status; > +} > + > +/** > + Return whether the controller is a SIO serial controller. > + > + @param Controller The controller handle. > + > + @retval EFI_SUCCESS The controller is a SIO serial controller. > + @retval others The controller is not a SIO serial controller. > +**/ > +EFI_STATUS > +IsSioSerialController ( > + EFI_HANDLE Controller > + ) > +{ > + EFI_STATUS Status; > + EFI_SIO_PROTOCOL *Sio; > + EFI_DEVICE_PATH_PROTOCOL *DevicePath; > + ACPI_HID_DEVICE_PATH *Acpi; > + > + // > + // Open the IO Abstraction(s) needed to perform the supported test > + // > + Status = gBS->OpenProtocol ( > + Controller, > + &gEfiSioProtocolGuid, > + (VOID **) &Sio, > + gSerialControllerDriver.DriverBindingHandle, > + Controller, > + EFI_OPEN_PROTOCOL_BY_DRIVER > + ); > + if (Status == EFI_ALREADY_STARTED) { > + return EFI_SUCCESS; > + } > + > + if (!EFI_ERROR (Status)) { > + // > + // Close the I/O Abstraction(s) used to perform the supported test > + // > + gBS->CloseProtocol ( > + Controller, > + &gEfiSioProtocolGuid, > + gSerialControllerDriver.DriverBindingHandle, > + Controller > + ); > + > + Status = gBS->OpenProtocol ( > + Controller, > + &gEfiDevicePathProtocolGuid, > + (VOID **) &DevicePath, > + gSerialControllerDriver.DriverBindingHandle, > + Controller, > + EFI_OPEN_PROTOCOL_BY_DRIVER > + ); > + ASSERT (Status != EFI_ALREADY_STARTED); > + > + if (!EFI_ERROR (Status)) { > + do { > + Acpi = (ACPI_HID_DEVICE_PATH *) DevicePath; > + DevicePath = NextDevicePathNode (DevicePath); > + } while (!IsDevicePathEnd (DevicePath)); > + > + if (DevicePathType (Acpi) != ACPI_DEVICE_PATH || > + (DevicePathSubType (Acpi) != ACPI_DP && DevicePathSubType (Acpi) > != ACPI_EXTENDED_DP) || > + Acpi->HID != EISA_PNP_ID (0x501) > + ) { > + Status = EFI_UNSUPPORTED; > + } > + } > + > + // > + // Close protocol, don't use device path protocol in the Support() > function > + // > + gBS->CloseProtocol ( > + Controller, > + &gEfiDevicePathProtocolGuid, > + gSerialControllerDriver.DriverBindingHandle, > + Controller > + ); > + } > + return Status; > +} > + > +/** > + Return whether the controller is a PCI serial controller. > + > + @param Controller The controller handle. > + > + @retval EFI_SUCCESS The controller is a PCI serial controller. > + @retval others The controller is not a PCI serial controller. > +**/ > +EFI_STATUS > +IsPciSerialController ( > + EFI_HANDLE Controller > + ) > +{ > + EFI_STATUS Status; > + EFI_PCI_IO_PROTOCOL *PciIo; > + EFI_DEVICE_PATH_PROTOCOL *DevicePath; > + PCI_TYPE00 Pci; > + PCI_SERIAL_PARAMETER *PciSerialParameter; > + > + // > + // Open the IO Abstraction(s) needed to perform the supported test > + // > + Status = gBS->OpenProtocol ( > + Controller, > + &gEfiPciIoProtocolGuid, > + (VOID **) &PciIo, > + gSerialControllerDriver.DriverBindingHandle, > + Controller, > + EFI_OPEN_PROTOCOL_BY_DRIVER > + ); > + if (Status == EFI_ALREADY_STARTED) { > + return EFI_SUCCESS; > + } > + > + if (!EFI_ERROR (Status)) { > + Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint8, 0, sizeof (Pci), > &Pci); > + if (!EFI_ERROR (Status)) { > + if (!IS_PCI_16550_SERIAL (&Pci)) { > + for (PciSerialParameter = (PCI_SERIAL_PARAMETER *) PcdGetPtr > (PcdPciSerialParameters) > + ; PciSerialParameter->VendorId != 0xFFFF > + ; PciSerialParameter++ > + ) { > + if ((Pci.Hdr.VendorId == PciSerialParameter->VendorId) && > + (Pci.Hdr.DeviceId == PciSerialParameter->DeviceId) > + ) { > + break; > + } > + } > + if (PciSerialParameter->VendorId == 0xFFFF) { > + Status = EFI_UNSUPPORTED; > + } else { > + Status = EFI_SUCCESS; > + } > + } > + } > + > + // > + // Close the I/O Abstraction(s) used to perform the supported test > + // > + gBS->CloseProtocol ( > + Controller, > + &gEfiPciIoProtocolGuid, > + gSerialControllerDriver.DriverBindingHandle, > + Controller > + ); > + } > + if (EFI_ERROR (Status)) { > + return Status; > + } > + > + // > + // Open the EFI Device Path protocol needed to perform the supported test > + // > + Status = gBS->OpenProtocol ( > + Controller, > + &gEfiDevicePathProtocolGuid, > + (VOID **) &DevicePath, > + gSerialControllerDriver.DriverBindingHandle, > + Controller, > + EFI_OPEN_PROTOCOL_BY_DRIVER > + ); > + ASSERT (Status != EFI_ALREADY_STARTED); > + > + // > + // Close protocol, don't use device path protocol in the Support() function > + // > + gBS->CloseProtocol ( > + Controller, > + &gEfiDevicePathProtocolGuid, > + gSerialControllerDriver.DriverBindingHandle, > + Controller > + ); > + > + 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 > +SerialControllerDriverSupported ( > + IN EFI_DRIVER_BINDING_PROTOCOL *This, > + IN EFI_HANDLE Controller, > + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath > + ) > + > +{ > + EFI_STATUS Status; > + UART_DEVICE_PATH *Uart; > + UART_FLOW_CONTROL_DEVICE_PATH *FlowControl; > + > + // > + // Test RemainingDevicePath > + // > + if ((RemainingDevicePath != NULL) && !IsDevicePathEnd > (RemainingDevicePath)) { > + Status = EFI_UNSUPPORTED; > + > + Uart = SkipControllerDevicePathNode (RemainingDevicePath, NULL, NULL); > + if (DevicePathType (Uart) != MESSAGING_DEVICE_PATH || > + DevicePathSubType (Uart) != MSG_UART_DP || > + DevicePathNodeLength (Uart) != sizeof (UART_DEVICE_PATH) > + ) { > + return EFI_UNSUPPORTED; > + } > + > + // > + // Do a rough check because Clock Rate is unknown until > DriverBindingStart() > + // > + if (!VerifyUartParameters (0, Uart->BaudRate, Uart->DataBits, > Uart->Parity, Uart->StopBits, NULL, NULL)) { > + return EFI_UNSUPPORTED; > + } > + > + FlowControl = (UART_FLOW_CONTROL_DEVICE_PATH *) NextDevicePathNode > (Uart); > + if (IsUartFlowControlDevicePathNode (FlowControl)) { > + // > + // If the second node is Flow Control Node, > + // return error when it request other than hardware flow control. > + // > + if ((ReadUnaligned32 (&FlowControl->FlowControlMap) & > ~UART_FLOW_CONTROL_HARDWARE) != 0) { > + return EFI_UNSUPPORTED; > + } > + } > + } > + > + Status = IsSioSerialController (Controller); > + if (EFI_ERROR (Status)) { > + Status = IsPciSerialController (Controller); > + } > + return Status; > +} > + > +/** > + Create the child serial device instance. > + > + @param Controller The parent controller handle. > + @param Uart Pointer to the UART device path node in > RemainingDevicePath, > + or NULL if RemainingDevicePath is NULL. > + @param ParentDevicePath Pointer to the parent device path. > + @param CreateControllerNode TRUE to create the controller node. > + @param Instance Instance number of the serial device. > + The value will be set to the controller node > + if CreateControllerNode is TRUE. > + @param ParentIo A union type pointer to either Sio or PciIo. > + @param PciSerialParameter The PCI serial parameter to be used by current > serial device. > + NULL for SIO serial device. > + @param PciDeviceInfo The PCI device info for the current serial > device. > + NULL for SIO serial device. > + > + @retval EFI_SUCCESS The serial device was created successfully. > + @retval others The serial device wasn't created. > +**/ > +EFI_STATUS > +CreateSerialDevice ( > + IN EFI_HANDLE Controller, > + IN UART_DEVICE_PATH *Uart, > + IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath, > + IN BOOLEAN CreateControllerNode, > + IN UINT32 Instance, > + IN PARENT_IO_PROTOCOL_PTR ParentIo, > + IN PCI_SERIAL_PARAMETER *PciSerialParameter, OPTIONAL > + IN PCI_DEVICE_INFO *PciDeviceInfo OPTIONAL > + ) > +{ > + EFI_STATUS Status; > + SERIAL_DEV *SerialDevice; > + UINT8 BarIndex; > + UINT64 Offset; > + UART_FLOW_CONTROL_DEVICE_PATH *FlowControl; > + UINT32 FlowControlMap; > + ACPI_RESOURCE_HEADER_PTR Resources; > + EFI_ACPI_IO_PORT_DESCRIPTOR *Io; > + EFI_ACPI_FIXED_LOCATION_IO_PORT_DESCRIPTOR *FixedIo; > + EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *AddressSpace; > + EFI_DEVICE_PATH_PROTOCOL *TempDevicePath; > + > + BarIndex = 0; > + Offset = 0; > + FlowControl = NULL; > + FlowControlMap = 0; > + > + // > + // Initialize the serial device instance > + // > + SerialDevice = AllocateCopyPool (sizeof (SERIAL_DEV), &gSerialDevTemplate); > + ASSERT (SerialDevice != NULL); > + > + SerialDevice->SerialIo.Mode = &(SerialDevice->SerialMode); > + SerialDevice->ParentDevicePath = ParentDevicePath; > + SerialDevice->PciDeviceInfo = PciDeviceInfo; > + SerialDevice->Instance = Instance; > + > + if (Uart != NULL) { > + CopyMem (&SerialDevice->UartDevicePath, Uart, sizeof (UART_DEVICE_PATH)); > + FlowControl = (UART_FLOW_CONTROL_DEVICE_PATH *) NextDevicePathNode > (Uart); > + if (IsUartFlowControlDevicePathNode (FlowControl)) { > + FlowControlMap = ReadUnaligned32 (&FlowControl->FlowControlMap); > + } else { > + FlowControl = NULL; > + } > + } > + > + // > + // For PCI serial device, use the information from PCD > + // > + if (PciSerialParameter != NULL) { > + BarIndex = (PciSerialParameter->BarIndex == PCI_BAR_ALL) ? 0 : > PciSerialParameter->BarIndex; > + Offset = PciSerialParameter->Offset; > + if (PciSerialParameter->RegisterStride != 0) { > + SerialDevice->RegisterStride = PciSerialParameter->RegisterStride; > + } > + if (PciSerialParameter->ClockRate != 0) { > + SerialDevice->ClockRate = PciSerialParameter->ClockRate; > + } > + if (PciSerialParameter->ReceiveFifoDepth != 0) { > + SerialDevice->ReceiveFifoDepth = PciSerialParameter->ReceiveFifoDepth; > + } > + if (PciSerialParameter->TransmitFifoDepth != 0) { > + SerialDevice->TransmitFifoDepth = > PciSerialParameter->TransmitFifoDepth; > + } > + } > + > + // > + // Pass NULL ActualBaudRate to VerifyUartParameters to disallow baudrate > degrade. > + // DriverBindingStart() shouldn't create a handle with different UART > device path. > + // > + if (!VerifyUartParameters (SerialDevice->ClockRate, > SerialDevice->UartDevicePath.BaudRate, SerialDevice->UartDevicePath.DataBits, > + SerialDevice->UartDevicePath.Parity, > SerialDevice->UartDevicePath.StopBits, NULL, NULL > + )) { > + Status = EFI_INVALID_PARAMETER; > + goto CreateError; > + } > + > + if (PciSerialParameter == NULL) { > + Status = ParentIo.Sio->GetResources (ParentIo.Sio, &Resources); > + } else { > + Status = ParentIo.PciIo->GetBarAttributes (ParentIo.PciIo, BarIndex, > NULL, (VOID **) &Resources); > + } > + > + if (!EFI_ERROR (Status)) { > + // > + // Get the base address information from ACPI resource descriptor. > + // ACPI_IO_PORT_DESCRIPTOR and ACPI_FIXED_LOCATION_IO_PORT_DESCRIPTOR > are returned from Sio; > + // ACPI_ADDRESS_SPACE_DESCRIPTOR is returned from PciIo. > + // > + while ((Resources.SmallHeader->Byte != ACPI_END_TAG_DESCRIPTOR) && > (SerialDevice->BaseAddress == 0)) { > + switch (Resources.SmallHeader->Byte) { > + case ACPI_IO_PORT_DESCRIPTOR: > + Io = (EFI_ACPI_IO_PORT_DESCRIPTOR *) Resources.SmallHeader; > + if (Io->Length != 0) { > + SerialDevice->BaseAddress = Io->BaseAddressMin; > + } > + break; > + > + case ACPI_FIXED_LOCATION_IO_PORT_DESCRIPTOR: > + FixedIo = (EFI_ACPI_FIXED_LOCATION_IO_PORT_DESCRIPTOR *) > Resources.SmallHeader; > + if (FixedIo->Length != 0) { > + SerialDevice->BaseAddress = FixedIo->BaseAddress; > + } > + break; > + > + case ACPI_ADDRESS_SPACE_DESCRIPTOR: > + AddressSpace = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) > Resources.SmallHeader; > + if (AddressSpace->AddrLen != 0) { > + if (AddressSpace->ResType == ACPI_ADDRESS_SPACE_TYPE_MEM) { > + SerialDevice->MmioAccess = TRUE; > + } > + SerialDevice->BaseAddress = AddressSpace->AddrRangeMin + Offset; > + } > + break; > + } > + > + if (Resources.SmallHeader->Bits.Type == 0) { > + Resources.SmallHeader = (ACPI_SMALL_RESOURCE_HEADER *) ((UINT8 *) > Resources.SmallHeader > + + > Resources.SmallHeader->Bits.Length > + + sizeof > (*Resources.SmallHeader)); > + } else { > + Resources.LargeHeader = (ACPI_LARGE_RESOURCE_HEADER *) ((UINT8 *) > Resources.LargeHeader > + + > Resources.LargeHeader->Length > + + sizeof > (*Resources.LargeHeader)); > + } > + } > + } > + > + if (SerialDevice->BaseAddress == 0) { > + Status = EFI_INVALID_PARAMETER; > + goto CreateError; > + } > + > + SerialDevice->HardwareFlowControl = (BOOLEAN) (FlowControlMap == > UART_FLOW_CONTROL_HARDWARE); > + > + // > + // Report status code the serial present > + // > + REPORT_STATUS_CODE_WITH_DEVICE_PATH ( > + EFI_PROGRESS_CODE, > + EFI_P_PC_PRESENCE_DETECT | EFI_PERIPHERAL_SERIAL_PORT, > + SerialDevice->ParentDevicePath > + ); > + > + if (!SerialPresent (SerialDevice)) { > + Status = EFI_DEVICE_ERROR; > + REPORT_STATUS_CODE_WITH_DEVICE_PATH ( > + EFI_ERROR_CODE, > + EFI_P_EC_NOT_DETECTED | EFI_PERIPHERAL_SERIAL_PORT, > + SerialDevice->ParentDevicePath > + ); > + goto CreateError; > + } > + > + // > + // 1. Append Controller device path node. > + // > + if (CreateControllerNode) { > + mControllerDevicePathTemplate.ControllerNumber = SerialDevice->Instance; > + SerialDevice->DevicePath = AppendDevicePathNode ( > + SerialDevice->ParentDevicePath, > + (EFI_DEVICE_PATH_PROTOCOL *) > &mControllerDevicePathTemplate > + ); > + SerialDevice->ContainsControllerNode = TRUE; > + } > + > + // > + // 2. Append UART device path node. > + // The Uart setings are zero here. > + // SetAttribute() will update them to match the default setings. > + // > + TempDevicePath = SerialDevice->DevicePath; > + if (TempDevicePath != NULL) { > + SerialDevice->DevicePath = AppendDevicePathNode ( > + TempDevicePath, > + (EFI_DEVICE_PATH_PROTOCOL *) > &SerialDevice->UartDevicePath > + ); > + FreePool (TempDevicePath); > + } else { > + SerialDevice->DevicePath = AppendDevicePathNode ( > + SerialDevice->ParentDevicePath, > + (EFI_DEVICE_PATH_PROTOCOL *) > &SerialDevice->UartDevicePath > + ); > + } > + // > + // 3. Append the Flow Control device path node. > + // Only produce the Flow Control node when remaining device path has it > + // > + if (FlowControl != NULL) { > + TempDevicePath = SerialDevice->DevicePath; > + if (TempDevicePath != NULL) { > + SerialDevice->DevicePath = AppendDevicePathNode ( > + TempDevicePath, > + (EFI_DEVICE_PATH_PROTOCOL *) FlowControl > + ); > + FreePool (TempDevicePath); > + } > + } > + ASSERT (SerialDevice->DevicePath != NULL); > + > + // > + // Fill in Serial I/O Mode structure based on either the > RemainingDevicePath or defaults. > + // > + SerialDevice->SerialMode.BaudRate = SerialDevice->UartDevicePath.BaudRate; > + 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)) { > + REPORT_STATUS_CODE_WITH_DEVICE_PATH ( > + EFI_ERROR_CODE, > + EFI_P_EC_CONTROLLER_ERROR | EFI_PERIPHERAL_SERIAL_PORT, > + SerialDevice->DevicePath > + ); > + goto CreateError; > + } > + > + AddName (SerialDevice, Instance); > + // > + // Install protocol interfaces for the serial device. > + // > + Status = gBS->InstallMultipleProtocolInterfaces ( > + &SerialDevice->Handle, > + &gEfiDevicePathProtocolGuid, SerialDevice->DevicePath, > + &gEfiSerialIoProtocolGuid, &SerialDevice->SerialIo, > + NULL > + ); > + if (EFI_ERROR (Status)) { > + goto CreateError; > + } > + // > + // Open For Child Device > + // > + Status = gBS->OpenProtocol ( > + Controller, > + PciSerialParameter != NULL ? &gEfiPciIoProtocolGuid : > &gEfiSioProtocolGuid, > + (VOID **) &ParentIo, > + gSerialControllerDriver.DriverBindingHandle, > + SerialDevice->Handle, > + EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER > + ); > + > + if (EFI_ERROR (Status)) { > + gBS->UninstallMultipleProtocolInterfaces ( > + &SerialDevice->Handle, > + &gEfiDevicePathProtocolGuid, SerialDevice->DevicePath, > + &gEfiSerialIoProtocolGuid, &SerialDevice->SerialIo, > + NULL > + ); > + } > + > +CreateError: > + if (EFI_ERROR (Status)) { > + if (SerialDevice->DevicePath != NULL) { > + FreePool (SerialDevice->DevicePath); > + } > + if (SerialDevice->ControllerNameTable != NULL) { > + FreeUnicodeStringTable (SerialDevice->ControllerNameTable); > + } > + FreePool (SerialDevice); > + } > + return Status; > +} > + > +/** > + Returns an array of pointers containing all the child serial device > pointers. > + > + @param Controller The parent controller handle. > + @param IoProtocolGuid The protocol GUID, either equals to > gEfiSioProtocolGuid > + or equals to gEfiPciIoProtocolGuid. > + @param Count Count of the serial devices. > + > + @return An array of pointers containing all the child serial device > pointers. > +**/ > +SERIAL_DEV ** > +GetChildSerialDevices ( > + IN EFI_HANDLE Controller, > + IN EFI_GUID *IoProtocolGuid, > + OUT UINTN *Count > + ) > +{ > + EFI_STATUS Status; > + UINTN Index; > + EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *OpenInfoBuffer; > + UINTN EntryCount; > + SERIAL_DEV **SerialDevices; > + EFI_SERIAL_IO_PROTOCOL *SerialIo; > + BOOLEAN OpenByDriver; > + > + *Count = 0; > + // > + // If the SerialIo instance specified by RemainingDevicePath is already > created, > + // update the attributes/control. > + // > + Status = gBS->OpenProtocolInformation ( > + Controller, > + IoProtocolGuid, > + &OpenInfoBuffer, > + &EntryCount > + ); > + if (EFI_ERROR (Status)) { > + return NULL; > + } > + > + SerialDevices = AllocatePool (EntryCount * sizeof (SERIAL_DEV *)); > + ASSERT (SerialDevices != NULL); > + > + *Count = 0; > + OpenByDriver = FALSE; > + for (Index = 0; Index < EntryCount; Index++) { > + if ((OpenInfoBuffer[Index].Attributes & > EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) != 0) { > + Status = gBS->OpenProtocol ( > + OpenInfoBuffer[Index].ControllerHandle, > + &gEfiSerialIoProtocolGuid, > + (VOID **) &SerialIo, > + gSerialControllerDriver.DriverBindingHandle, > + Controller, > + EFI_OPEN_PROTOCOL_GET_PROTOCOL > + ); > + if (!EFI_ERROR (Status)) { > + SerialDevices[(*Count)++] = SERIAL_DEV_FROM_THIS (SerialIo); > + } > + } > + > + > + if ((OpenInfoBuffer[Index].Attributes & EFI_OPEN_PROTOCOL_BY_DRIVER) != > 0) { > + ASSERT (OpenInfoBuffer[Index].AgentHandle == > gSerialControllerDriver.DriverBindingHandle); > + OpenByDriver = TRUE; > + } > + } > + if (OpenInfoBuffer != NULL) { > + FreePool (OpenInfoBuffer); > + } > + > + ASSERT ((*Count == 0) || (OpenByDriver)); > + > + return SerialDevices; > +} > + > +/** > + 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 > +SerialControllerDriverStart ( > + IN EFI_DRIVER_BINDING_PROTOCOL *This, > + IN EFI_HANDLE Controller, > + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath > + ) > +{ > + EFI_STATUS Status; > + UINTN Index; > + EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath; > + EFI_DEVICE_PATH_PROTOCOL *Node; > + EFI_SERIAL_IO_PROTOCOL *SerialIo; > + UINT32 ControllerNumber; > + UART_DEVICE_PATH *Uart; > + UART_FLOW_CONTROL_DEVICE_PATH *FlowControl; > + UINT32 Control; > + PARENT_IO_PROTOCOL_PTR ParentIo; > + ACPI_HID_DEVICE_PATH *Acpi; > + EFI_GUID *IoProtocolGuid; > + PCI_SERIAL_PARAMETER *PciSerialParameter; > + PCI_SERIAL_PARAMETER DefaultPciSerialParameter; > + PCI_TYPE00 Pci; > + UINT32 PciSerialCount; > + SERIAL_DEV **SerialDevices; > + UINTN SerialDeviceCount; > + PCI_DEVICE_INFO *PciDeviceInfo; > + UINT64 Supports; > + BOOLEAN ContainsControllerNode; > + > + // > + // Get the Parent Device Path > + // > + Status = gBS->OpenProtocol ( > + Controller, > + &gEfiDevicePathProtocolGuid, > + (VOID **) &ParentDevicePath, > + This->DriverBindingHandle, > + Controller, > + EFI_OPEN_PROTOCOL_BY_DRIVER > + ); > + if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) { > + return Status; > + } > + // > + // Report status code enable the serial > + // > + REPORT_STATUS_CODE_WITH_DEVICE_PATH ( > + EFI_PROGRESS_CODE, > + EFI_P_PC_ENABLE | EFI_PERIPHERAL_SERIAL_PORT, > + ParentDevicePath > + ); > + > + // > + // Grab the IO abstraction we need to get any work done > + // > + IoProtocolGuid = &gEfiSioProtocolGuid; > + Status = gBS->OpenProtocol ( > + Controller, > + IoProtocolGuid, > + (VOID **) &ParentIo, > + This->DriverBindingHandle, > + Controller, > + EFI_OPEN_PROTOCOL_BY_DRIVER > + ); > + if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) { > + IoProtocolGuid = &gEfiPciIoProtocolGuid; > + Status = gBS->OpenProtocol ( > + Controller, > + IoProtocolGuid, > + (VOID **) &ParentIo, > + This->DriverBindingHandle, > + Controller, > + EFI_OPEN_PROTOCOL_BY_DRIVER > + ); > + } > + ASSERT (!EFI_ERROR (Status) || Status == EFI_ALREADY_STARTED); > + > + // > + // Do nothing for END device path node > + // > + if ((RemainingDevicePath != NULL) && IsDevicePathEnd > (RemainingDevicePath)) { > + return EFI_SUCCESS; > + } > + > + > + SerialDevices = GetChildSerialDevices (Controller, IoProtocolGuid, > &SerialDeviceCount); > + // > + // If the SerialIo instance specified by RemainingDevicePath is already > created, > + // update the attributes/control. > + // > + if ((SerialDeviceCount != 0) && (RemainingDevicePath != NULL)) { > + Uart = (UART_DEVICE_PATH *) SkipControllerDevicePathNode > (RemainingDevicePath, &ContainsControllerNode, > &ControllerNumber); > + for (Index = 0; Index < SerialDeviceCount; Index++) { > + if ((!SerialDevices[Index]->ContainsControllerNode && > !ContainsControllerNode) || > + (SerialDevices[Index]->ContainsControllerNode && > ContainsControllerNode && SerialDevices[Index]->Instance == > ControllerNumber) > + ) { > + Status = EFI_INVALID_PARAMETER; > + // > + // Pass NULL ActualBaudRate to VerifyUartParameters to disallow > baudrate degrade. > + // DriverBindingStart() shouldn't create a handle with different > UART device path. > + // > + if (VerifyUartParameters (SerialDevices[Index]->ClockRate, > Uart->BaudRate, Uart->DataBits, > + (EFI_PARITY_TYPE) Uart->Parity, > (EFI_STOP_BITS_TYPE) Uart->StopBits, NULL, NULL)) { > + SerialIo = &SerialDevices[Index]->SerialIo; > + Status = SerialIo->SetAttributes ( > + SerialIo, > + Uart->BaudRate, > + SerialIo->Mode->ReceiveFifoDepth, > + SerialIo->Mode->Timeout, > + (EFI_PARITY_TYPE) Uart->Parity, > + Uart->DataBits, > + (EFI_STOP_BITS_TYPE) Uart->StopBits > + ); > + } > + FlowControl = (UART_FLOW_CONTROL_DEVICE_PATH *) NextDevicePathNode > (Uart); > + if (!EFI_ERROR (Status) && IsUartFlowControlDevicePathNode > (FlowControl)) { > + Status = SerialIo->GetControl (SerialIo, &Control); > + if (!EFI_ERROR (Status)) { > + if (ReadUnaligned32 (&FlowControl->FlowControlMap) == > UART_FLOW_CONTROL_HARDWARE) { > + Control |= EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE; > + } else { > + Control &= ~EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE; > + } > + // > + // Clear the bits that are not allowed to pass to SetControl > + // > + Control &= (EFI_SERIAL_REQUEST_TO_SEND | > EFI_SERIAL_DATA_TERMINAL_READY | > + EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE | > EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE | > + EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE); > + Status = SerialIo->SetControl (SerialIo, Control); > + } > + } > + break; > + } > + } > + if (Index != SerialDeviceCount) { > + // > + // Directly return if the SerialIo instance specified by > RemainingDevicePath is found and updated. > + // Otherwise continue to create the instance specified by > RemainingDevicePath. > + // > + if (SerialDevices != NULL) { > + FreePool (SerialDevices); > + } > + return Status; > + } > + } > + > + if (RemainingDevicePath != NULL) { > + Uart = (UART_DEVICE_PATH *) SkipControllerDevicePathNode > (RemainingDevicePath, &ContainsControllerNode, > &ControllerNumber); > + } else { > + Uart = NULL; > + } > + > + PciDeviceInfo = NULL; > + if (IoProtocolGuid == &gEfiSioProtocolGuid) { > + Status = EFI_NOT_FOUND; > + if (RemainingDevicePath == NULL || !ContainsControllerNode) { > + Node = ParentDevicePath; > + do { > + Acpi = (ACPI_HID_DEVICE_PATH *) Node; > + Node = NextDevicePathNode (Node); > + } while (!IsDevicePathEnd (Node)); > + Status = CreateSerialDevice (Controller, Uart, ParentDevicePath, > FALSE, Acpi->UID, ParentIo, NULL, NULL); > + DEBUG ((EFI_D_INFO, "PciSioSerial: Create SIO child serial device - > %r\n", Status)); > + } > + } else { > + Status = ParentIo.PciIo->Pci.Read (ParentIo.PciIo, EfiPciIoWidthUint8, > 0, sizeof (Pci), &Pci); > + if (!EFI_ERROR (Status)) { > + // > + // PcdPciSerialParameters takes the higher priority. > + // > + PciSerialCount = 0; > + for (PciSerialParameter = PcdGetPtr (PcdPciSerialParameters); > PciSerialParameter->VendorId != 0xFFFF; PciSerialParameter++) { > + if ((PciSerialParameter->VendorId == Pci.Hdr.VendorId) && > + (PciSerialParameter->DeviceId == Pci.Hdr.DeviceId) > + ) { > + PciSerialCount++; > + } > + } > + > + if (SerialDeviceCount == 0) { > + // > + // Enable the IO & MEM decoding when creating the first child. > + // Restore the PCI attributes when all children is destroyed > (PciDeviceInfo->ChildCount == 0). > + // > + PciDeviceInfo = AllocatePool (sizeof (PCI_DEVICE_INFO)); > + PciDeviceInfo->ChildCount = 0; > + PciDeviceInfo->PciIo = ParentIo.PciIo; > + Status = ParentIo.PciIo->Attributes ( > + ParentIo.PciIo, > + EfiPciIoAttributeOperationGet, > + 0, > + &PciDeviceInfo->PciAttributes > + ); > + > + if (!EFI_ERROR (Status)) { > + Status = ParentIo.PciIo->Attributes ( > + ParentIo.PciIo, > + EfiPciIoAttributeOperationSupported, > + 0, > + &Supports > + ); > + if (!EFI_ERROR (Status)) { > + Supports &= EFI_PCI_IO_ATTRIBUTE_IO | > EFI_PCI_IO_ATTRIBUTE_MEMORY; > + Status = ParentIo.PciIo->Attributes ( > + ParentIo.PciIo, > + EfiPciIoAttributeOperationEnable, > + Supports, > + NULL > + ); > + } > + } > + } else { > + // > + // Re-use the PciDeviceInfo stored in existing children. > + // > + PciDeviceInfo = SerialDevices[0]->PciDeviceInfo; > + ASSERT (PciDeviceInfo != NULL); > + } > + > + Status = EFI_NOT_FOUND; > + if (PciSerialCount <= 1) { > + // > + // PCI serial device contains only one UART > + // > + if (RemainingDevicePath == NULL || !ContainsControllerNode) { > + // > + // This PCI serial device is matched by class code in Supported() > + // > + if (PciSerialCount == 0) { > + DefaultPciSerialParameter.VendorId = Pci.Hdr.VendorId; > + DefaultPciSerialParameter.DeviceId = Pci.Hdr.DeviceId; > + DefaultPciSerialParameter.BarIndex = 0; > + DefaultPciSerialParameter.Offset = 0; > + DefaultPciSerialParameter.RegisterStride = 0; > + DefaultPciSerialParameter.ClockRate = 0; > + PciSerialParameter = &DefaultPciSerialParameter; > + } else if (PciSerialCount == 1) { > + PciSerialParameter = PcdGetPtr (PcdPciSerialParameters); > + } > + > + Status = CreateSerialDevice (Controller, Uart, ParentDevicePath, > FALSE, 0, ParentIo, PciSerialParameter, PciDeviceInfo); > + DEBUG ((EFI_D_INFO, "PciSioSerial: Create PCI child serial device > (single) - %r\n", Status)); > + if (!EFI_ERROR (Status)) { > + PciDeviceInfo->ChildCount++; > + } > + } > + } else { > + // > + // PCI serial device contains multiple UARTs > + // > + if (RemainingDevicePath == NULL || ContainsControllerNode) { > + PciSerialCount = 0; > + for (PciSerialParameter = PcdGetPtr (PcdPciSerialParameters); > PciSerialParameter->VendorId != 0xFFFF; PciSerialParameter++) { > + if ((PciSerialParameter->VendorId == Pci.Hdr.VendorId) && > + (PciSerialParameter->DeviceId == Pci.Hdr.DeviceId) && > + ((RemainingDevicePath == NULL) || (ControllerNumber == > PciSerialCount)) > + ) { > + // > + // Create controller node when PCI serial device contains > multiple UARTs > + // > + Status = CreateSerialDevice (Controller, Uart, > ParentDevicePath, TRUE, PciSerialCount, ParentIo, PciSerialParameter, > PciDeviceInfo); > + PciSerialCount++; > + DEBUG ((EFI_D_INFO, "PciSioSerial: Create PCI child serial > device (multiple) - %r\n", Status)); > + if (!EFI_ERROR (Status)) { > + PciDeviceInfo->ChildCount++; > + } > + } > + } > + } > + } > + } > + } > + > + if (SerialDevices != NULL) { > + FreePool (SerialDevices); > + } > + > + // > + // For multiple PCI serial devices, set Status to SUCCESS if one child is > created successfully > + // > + if ((PciDeviceInfo != NULL) && (PciDeviceInfo->ChildCount != 0)) { > + Status = EFI_SUCCESS; > + } > + > + if (EFI_ERROR (Status) && (SerialDeviceCount == 0)) { > + if (PciDeviceInfo != NULL) { > + Status = ParentIo.PciIo->Attributes ( > + ParentIo.PciIo, > + EfiPciIoAttributeOperationSet, > + PciDeviceInfo->PciAttributes, > + NULL > + ); > + ASSERT_EFI_ERROR (Status); > + FreePool (PciDeviceInfo); > + } > + gBS->CloseProtocol ( > + Controller, > + &gEfiDevicePathProtocolGuid, > + This->DriverBindingHandle, > + Controller > + ); > + gBS->CloseProtocol ( > + Controller, > + IoProtocolGuid, > + 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 > +SerialControllerDriverStop ( > + IN EFI_DRIVER_BINDING_PROTOCOL *This, > + IN EFI_HANDLE Controller, > + IN UINTN NumberOfChildren, > + IN EFI_HANDLE *ChildHandleBuffer > + ) > + > +{ > + EFI_STATUS Status; > + UINTN Index; > + BOOLEAN AllChildrenStopped; > + EFI_SERIAL_IO_PROTOCOL *SerialIo; > + SERIAL_DEV *SerialDevice; > + VOID *IoProtocol; > + EFI_DEVICE_PATH_PROTOCOL *DevicePath; > + PCI_DEVICE_INFO *PciDeviceInfo; > + > + PciDeviceInfo = NULL; > + > + Status = gBS->HandleProtocol ( > + Controller, > + &gEfiDevicePathProtocolGuid, > + (VOID **) &DevicePath > + ); > + > + // > + // Report the status code disable the serial > + // > + REPORT_STATUS_CODE_WITH_DEVICE_PATH ( > + EFI_PROGRESS_CODE, > + EFI_P_PC_DISABLE | EFI_PERIPHERAL_SERIAL_PORT, > + DevicePath > + ); > + > + if (NumberOfChildren == 0) { > + // > + // Close the bus driver > + // > + Status = gBS->OpenProtocol ( > + Controller, > + &gEfiPciIoProtocolGuid, > + &IoProtocol, > + This->DriverBindingHandle, > + Controller, > + EFI_OPEN_PROTOCOL_TEST_PROTOCOL > + ); > + gBS->CloseProtocol ( > + Controller, > + !EFI_ERROR (Status) ? &gEfiPciIoProtocolGuid : > &gEfiSioProtocolGuid, > + This->DriverBindingHandle, > + Controller > + ); > + > + gBS->CloseProtocol ( > + Controller, > + &gEfiDevicePathProtocolGuid, > + This->DriverBindingHandle, > + Controller > + ); > + return EFI_SUCCESS; > + } > + > + 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); > + ASSERT ((PciDeviceInfo == NULL) || (PciDeviceInfo == > SerialDevice->PciDeviceInfo)); > + PciDeviceInfo = SerialDevice->PciDeviceInfo; > + > + Status = gBS->CloseProtocol ( > + Controller, > + PciDeviceInfo != NULL ? &gEfiPciIoProtocolGuid : > &gEfiSioProtocolGuid, > + This->DriverBindingHandle, > + ChildHandleBuffer[Index] > + ); > + > + Status = gBS->UninstallMultipleProtocolInterfaces ( > + ChildHandleBuffer[Index], > + &gEfiDevicePathProtocolGuid, SerialDevice->DevicePath, > + &gEfiSerialIoProtocolGuid, &SerialDevice->SerialIo, > + NULL > + ); > + if (EFI_ERROR (Status)) { > + gBS->OpenProtocol ( > + Controller, > + PciDeviceInfo != NULL ? &gEfiPciIoProtocolGuid : > &gEfiSioProtocolGuid, > + &IoProtocol, > + This->DriverBindingHandle, > + ChildHandleBuffer[Index], > + EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER > + ); > + } else { > + FreePool (SerialDevice->DevicePath); > + FreeUnicodeStringTable (SerialDevice->ControllerNameTable); > + FreePool (SerialDevice); > + > + if (PciDeviceInfo != NULL) { > + ASSERT (PciDeviceInfo->ChildCount != 0); > + PciDeviceInfo->ChildCount--; > + } > + } > + } > + > + if (EFI_ERROR (Status)) { > + AllChildrenStopped = FALSE; > + } > + } > + > + if (!AllChildrenStopped) { > + return EFI_DEVICE_ERROR; > + } else { > + // > + // If all children are destroyed, restore the PCI attributes. > + // > + if ((PciDeviceInfo != NULL) && (PciDeviceInfo->ChildCount == 0)) { > + ASSERT (PciDeviceInfo->PciIo != NULL); > + Status = PciDeviceInfo->PciIo->Attributes ( > + PciDeviceInfo->PciIo, > + EfiPciIoAttributeOperationSet, > + PciDeviceInfo->PciAttributes, > + NULL > + ); > + ASSERT_EFI_ERROR (Status); > + FreePool (PciDeviceInfo); > + } > + return EFI_SUCCESS; > + } > +} > + > diff --git a/MdeModulePkg/Bus/Pci/PciSioSerialDxe/Serial.h > b/MdeModulePkg/Bus/Pci/PciSioSerialDxe/Serial.h > new file mode 100644 > index 0000000..f147e69 > --- /dev/null > +++ b/MdeModulePkg/Bus/Pci/PciSioSerialDxe/Serial.h > @@ -0,0 +1,789 @@ > +/** @file > + Header file for PciSioSerial Driver > + > +Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.<BR> > +This program and the accompanying materials > +are licensed and made available under the terms and conditions of the BSD > License > +which accompanies this distribution. The full text of the license may be > found at > +http://opensource.org/licenses/bsd-license.php > + > +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, > +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. > + > +**/ > + > +#ifndef _SERIAL_H_ > +#define _SERIAL_H_ > + > + > +#include <Uefi.h> > + > +#include <IndustryStandard/Pci.h> > + > +#include <Protocol/SuperIo.h> > +#include <Protocol/PciIo.h> > +#include <Protocol/SerialIo.h> > +#include <Protocol/DevicePath.h> > + > +#include <Library/DebugLib.h> > +#include <Library/UefiDriverEntryPoint.h> > +#include <Library/UefiLib.h> > +#include <Library/DevicePathLib.h> > +#include <Library/BaseMemoryLib.h> > +#include <Library/MemoryAllocationLib.h> > +#include <Library/UefiBootServicesTableLib.h> > +#include <Library/ReportStatusCodeLib.h> > +#include <Library/PcdLib.h> > +#include <Library/IoLib.h> > +#include <Library/PrintLib.h> > + > +// > +// Driver Binding Externs > +// > +extern EFI_DRIVER_BINDING_PROTOCOL gSerialControllerDriver; > +extern EFI_COMPONENT_NAME_PROTOCOL gPciSioSerialComponentName; > +extern EFI_COMPONENT_NAME2_PROTOCOL gPciSioSerialComponentName2; > + > +#define SIO_SERIAL_PORT_NAME L"SIO Serial Port #%d" > +#define PCI_SERIAL_PORT_NAME L"PCI Serial Port #%d" > +#define SERIAL_PORT_NAME_LEN (sizeof (SIO_SERIAL_PORT_NAME) / sizeof > (CHAR16) + MAXIMUM_VALUE_CHARACTERS) > + > +// > +// Internal Data Structures > +// > +#define TIMEOUT_STALL_INTERVAL 10 > + > +#pragma pack(1) > +/// > +/// PcdPciSerialParameters contains zero or more instances of the below > structure. > +/// If a PCI device contains multiple UARTs, PcdPciSerialParameters needs to > contain > +/// two instances of the below structure, with the VendorId and DeviceId > equals to the > +/// device ID and vendor ID of the device. If the PCI device uses the first > two BARs > +/// to support multiple UARTs, BarIndex of first instance equals to 0 and > BarIndex of > +/// second one equals to 1; if the PCI device uses the first BAR to support > multiple > +/// UARTs, BarIndex of both instance equals to 0 and Offset of first > instance equals > +/// to 0 while Offset of second one equals to some value bigger or equal to > 8. > +/// For certain UART whose register needs to be accessed in DWORD aligned > address, > +/// RegisterStride equals to 4. > +/// > +typedef struct { > + UINT16 VendorId; ///< Vendor ID to match the PCI device. The > value 0xFFFF terminates the list of entries. > + UINT16 DeviceId; ///< Device ID to match the PCI device > + UINT32 ClockRate; ///< UART clock rate. Set to 0 for default > clock rate of 1843200 Hz > + UINT64 Offset; ///< The byte offset into to the BAR > + UINT8 BarIndex; ///< Which BAR to get the UART base address > + UINT8 RegisterStride; ///< UART register stride in bytes. Set to 0 > for default register stride of 1 byte. > + UINT16 ReceiveFifoDepth; ///< UART receive FIFO depth in bytes. Set to 0 > for a default FIFO depth of 16 bytes. > + UINT16 TransmitFifoDepth; ///< UART transmit FIFO depth in bytes. Set to > 0 for a default FIFO depth of 16 bytes. > + UINT8 Reserved[2]; > +} PCI_SERIAL_PARAMETER; > +#pragma pack() > + > +#define SERIAL_MAX_FIFO_SIZE 17 ///< Actual FIFO size is 16. FIFO > based on circular wastes one unit. > +typedef struct { > + UINT16 Head; ///< Head pointer of the FIFO. Empty > when (Head == Tail). > + UINT16 Tail; ///< Tail pointer of the FIFO. Full > when ((Tail + 1) % SERIAL_MAX_FIFO_SIZE == Head). > + UINT8 Data[SERIAL_MAX_FIFO_SIZE]; ///< Store the FIFO data. > +} SERIAL_DEV_FIFO; > + > +typedef union { > + EFI_PCI_IO_PROTOCOL *PciIo; > + EFI_SIO_PROTOCOL *Sio; > +} PARENT_IO_PROTOCOL_PTR; > + > +typedef struct { > + EFI_PCI_IO_PROTOCOL *PciIo; // Pointer to parent PciIo > instance. > + UINTN ChildCount; // Count of child SerialIo > instance. > + UINT64 PciAttributes; // Original PCI attributes. > +} PCI_DEVICE_INFO; > + > +typedef struct { > + UINT32 Signature; > + EFI_HANDLE Handle; > + EFI_SERIAL_IO_PROTOCOL SerialIo; > + EFI_SERIAL_IO_MODE SerialMode; > + EFI_DEVICE_PATH_PROTOCOL *DevicePath; > + > + EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath; > + UART_DEVICE_PATH UartDevicePath; > + > + EFI_PHYSICAL_ADDRESS BaseAddress; ///< UART base address > + BOOLEAN MmioAccess; ///< TRUE for MMIO, FALSE for > IO > + UINT8 RegisterStride; ///< UART Register Stride > + UINT32 ClockRate; ///< UART clock rate > + > + UINT16 ReceiveFifoDepth; ///< UART receive FIFO depth > in bytes. > + SERIAL_DEV_FIFO Receive; ///< The FIFO used to store > received data > + > + UINT16 TransmitFifoDepth; ///< UART transmit FIFO depth > in bytes. > + SERIAL_DEV_FIFO Transmit; ///< The FIFO used to store > to-transmit data > + > + BOOLEAN SoftwareLoopbackEnable; > + BOOLEAN HardwareFlowControl; > + EFI_UNICODE_STRING_TABLE *ControllerNameTable; > + BOOLEAN ContainsControllerNode; ///< TRUE if the device > produced contains Controller node > + UINT32 Instance; > + PCI_DEVICE_INFO *PciDeviceInfo; > +} SERIAL_DEV; > + > +#define SERIAL_DEV_SIGNATURE SIGNATURE_32 ('s', 'e', 'r', 'd') > +#define SERIAL_DEV_FROM_THIS(a) CR (a, SERIAL_DEV, SerialIo, > SERIAL_DEV_SIGNATURE) > + > +// > +// Serial Driver Defaults > +// > +#define SERIAL_PORT_DEFAULT_TIMEOUT 1000000 > +#define SERIAL_PORT_SUPPORT_CONTROL_MASK (EFI_SERIAL_CLEAR_TO_SEND > | \ > + EFI_SERIAL_DATA_SET_READY > | \ > + EFI_SERIAL_RING_INDICATE > | \ > + EFI_SERIAL_CARRIER_DETECT > | \ > + EFI_SERIAL_REQUEST_TO_SEND > | \ > + > EFI_SERIAL_DATA_TERMINAL_READY | \ > + > EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE | \ > + > EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE | \ > + > EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE | \ > + > EFI_SERIAL_OUTPUT_BUFFER_EMPTY | \ > + > EFI_SERIAL_INPUT_BUFFER_EMPTY) > + > +#define SERIAL_PORT_MIN_TIMEOUT 1 // 1 uS > +#define SERIAL_PORT_MAX_TIMEOUT 100000000 // 100 seconds > +// > +// UART Registers > +// > +#define SERIAL_REGISTER_THR 0 ///< WO Transmit Holding Register > +#define SERIAL_REGISTER_RBR 0 ///< RO Receive Buffer Register > +#define SERIAL_REGISTER_DLL 0 ///< R/W Divisor Latch LSB > +#define SERIAL_REGISTER_DLM 1 ///< R/W Divisor Latch MSB > +#define SERIAL_REGISTER_IER 1 ///< R/W Interrupt Enable Register > +#define SERIAL_REGISTER_IIR 2 ///< RO Interrupt Identification Register > +#define SERIAL_REGISTER_FCR 2 ///< WO FIFO Cotrol Register > +#define SERIAL_REGISTER_LCR 3 ///< R/W Line Control Register > +#define SERIAL_REGISTER_MCR 4 ///< R/W Modem Control Register > +#define SERIAL_REGISTER_LSR 5 ///< R/W Line Status Register > +#define SERIAL_REGISTER_MSR 6 ///< R/W Modem Status Register > +#define SERIAL_REGISTER_SCR 7 ///< R/W Scratch Pad Register > +#pragma pack(1) > + > +/// > +/// Interrupt Enable Register > +/// > +typedef union { > + struct { > + UINT8 Ravie : 1; ///< Receiver Data Available Interrupt Enable > + UINT8 Theie : 1; ///< Transmistter Holding Register Empty Interrupt > Enable > + UINT8 Rie : 1; ///< Receiver Interrupt Enable > + UINT8 Mie : 1; ///< Modem Interrupt Enable > + UINT8 Reserved : 4; > + } Bits; > + UINT8 Data; > +} SERIAL_PORT_IER; > + > +/// > +/// FIFO Control Register > +/// > +typedef union { > + struct { > + UINT8 TrFIFOE : 1; ///< Transmit and Receive FIFO Enable > + UINT8 ResetRF : 1; ///< Reset Reciever FIFO > + UINT8 ResetTF : 1; ///< Reset Transmistter FIFO > + UINT8 Dms : 1; ///< DMA Mode Select > + UINT8 Reserved : 1; > + UINT8 TrFIFO64 : 1; ///< Enable 64 byte FIFO > + UINT8 Rtb : 2; ///< Receive Trigger Bits > + } Bits; > + UINT8 Data; > +} SERIAL_PORT_FCR; > + > +/// > +/// Line Control Register > +/// > +typedef union { > + struct { > + UINT8 SerialDB : 2; ///< Number of Serial Data Bits > + UINT8 StopB : 1; ///< Number of Stop Bits > + UINT8 ParEn : 1; ///< Parity Enable > + UINT8 EvenPar : 1; ///< Even Parity Select > + UINT8 SticPar : 1; ///< Sticky Parity > + UINT8 BrCon : 1; ///< Break Control > + UINT8 DLab : 1; ///< Divisor Latch Access Bit > + } Bits; > + UINT8 Data; > +} SERIAL_PORT_LCR; > + > +/// > +/// Modem Control Register > +/// > +typedef union { > + struct { > + UINT8 DtrC : 1; ///< Data Terminal Ready Control > + UINT8 Rts : 1; ///< Request To Send Control > + UINT8 Out1 : 1; ///< Output1 > + UINT8 Out2 : 1; ///< Output2, used to disable interrupt > + UINT8 Lme : 1; ///< Loopback Mode Enable > + UINT8 Reserved : 3; > + } Bits; > + UINT8 Data; > +} SERIAL_PORT_MCR; > + > +/// > +/// Line Status Register > +/// > +typedef union { > + struct { > + UINT8 Dr : 1; ///< Receiver Data Ready Status > + UINT8 Oe : 1; ///< Overrun Error Status > + UINT8 Pe : 1; ///< Parity Error Status > + UINT8 Fe : 1; ///< Framing Error Status > + UINT8 Bi : 1; ///< Break Interrupt Status > + UINT8 Thre : 1; ///< Transmistter Holding Register Status > + UINT8 Temt : 1; ///< Transmitter Empty Status > + UINT8 FIFOe : 1; ///< FIFO Error Status > + } Bits; > + UINT8 Data; > +} SERIAL_PORT_LSR; > + > +/// > +/// Modem Status Register > +/// > +typedef union { > + struct { > + UINT8 DeltaCTS : 1; ///< Delta Clear To Send Status > + UINT8 DeltaDSR : 1; ///< Delta Data Set Ready Status > + UINT8 TrailingEdgeRI : 1; ///< Trailing Edge of Ring Indicator Status > + UINT8 DeltaDCD : 1; ///< Delta Data Carrier Detect Status > + UINT8 Cts : 1; ///< Clear To Send Status > + UINT8 Dsr : 1; ///< Data Set Ready Status > + UINT8 Ri : 1; ///< Ring Indicator Status > + UINT8 Dcd : 1; ///< Data Carrier Detect Status > + } Bits; > + UINT8 Data; > +} SERIAL_PORT_MSR; > + > +#pragma pack() > +// > +// Define serial register I/O macros > +// > +#define READ_RBR(S) SerialReadRegister (S, SERIAL_REGISTER_RBR) > +#define READ_DLL(S) SerialReadRegister (S, SERIAL_REGISTER_DLL) > +#define READ_DLM(S) SerialReadRegister (S, SERIAL_REGISTER_DLM) > +#define READ_IER(S) SerialReadRegister (S, SERIAL_REGISTER_IER) > +#define READ_IIR(S) SerialReadRegister (S, SERIAL_REGISTER_IIR) > +#define READ_LCR(S) SerialReadRegister (S, SERIAL_REGISTER_LCR) > +#define READ_MCR(S) SerialReadRegister (S, SERIAL_REGISTER_MCR) > +#define READ_LSR(S) SerialReadRegister (S, SERIAL_REGISTER_LSR) > +#define READ_MSR(S) SerialReadRegister (S, SERIAL_REGISTER_MSR) > +#define READ_SCR(S) SerialReadRegister (S, SERIAL_REGISTER_SCR) > + > +#define WRITE_THR(S, D) SerialWriteRegister (S, SERIAL_REGISTER_THR, D) > +#define WRITE_DLL(S, D) SerialWriteRegister (S, SERIAL_REGISTER_DLL, D) > +#define WRITE_DLM(S, D) SerialWriteRegister (S, SERIAL_REGISTER_DLM, D) > +#define WRITE_IER(S, D) SerialWriteRegister (S, SERIAL_REGISTER_IER, D) > +#define WRITE_FCR(S, D) SerialWriteRegister (S, SERIAL_REGISTER_FCR, D) > +#define WRITE_LCR(S, D) SerialWriteRegister (S, SERIAL_REGISTER_LCR, D) > +#define WRITE_MCR(S, D) SerialWriteRegister (S, SERIAL_REGISTER_MCR, D) > +#define WRITE_LSR(S, D) SerialWriteRegister (S, SERIAL_REGISTER_LSR, D) > +#define WRITE_MSR(S, D) SerialWriteRegister (S, SERIAL_REGISTER_MSR, D) > +#define WRITE_SCR(S, D) SerialWriteRegister (S, SERIAL_REGISTER_SCR, D) > + > +// > +// Prototypes > +// Driver model protocol interface > +// > +/** > + 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 > +SerialControllerDriverSupported ( > + IN EFI_DRIVER_BINDING_PROTOCOL *This, > + IN EFI_HANDLE Controller, > + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath > + ); > + > +/** > + 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 > +SerialControllerDriverStart ( > + IN EFI_DRIVER_BINDING_PROTOCOL *This, > + IN EFI_HANDLE Controller, > + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath > + ); > + > +/** > + 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 > +SerialControllerDriverStop ( > + IN EFI_DRIVER_BINDING_PROTOCOL *This, > + IN EFI_HANDLE Controller, > + IN UINTN NumberOfChildren, > + IN EFI_HANDLE *ChildHandleBuffer > + ); > + > +// > +// Serial I/O Protocol Interface > +// > +/** > + Reset serial device. > + > + @param This Pointer to EFI_SERIAL_IO_PROTOCOL > + > + @retval EFI_SUCCESS Reset successfully > + @retval EFI_DEVICE_ERROR Failed to reset > + > +**/ > +EFI_STATUS > +EFIAPI > +SerialReset ( > + IN EFI_SERIAL_IO_PROTOCOL *This > + ); > + > +/** > + Set new attributes to a serial device. > + > + @param This Pointer to EFI_SERIAL_IO_PROTOCOL > + @param BaudRate The baudrate of the serial device > + @param ReceiveFifoDepth The depth of receive FIFO buffer > + @param Timeout The request timeout for a single char > + @param Parity The type of parity used in serial device > + @param DataBits Number of databits used in serial device > + @param StopBits Number of stopbits used in serial device > + > + @retval EFI_SUCCESS The new attributes were set > + @retval EFI_INVALID_PARAMETERS One or more attributes have an > unsupported value > + @retval EFI_UNSUPPORTED Data Bits can not set to 5 or 6 > + @retval EFI_DEVICE_ERROR The serial device is not functioning > correctly (no return) > + > +**/ > +EFI_STATUS > +EFIAPI > +SerialSetAttributes ( > + IN EFI_SERIAL_IO_PROTOCOL *This, > + IN UINT64 BaudRate, > + IN UINT32 ReceiveFifoDepth, > + IN UINT32 Timeout, > + IN EFI_PARITY_TYPE Parity, > + IN UINT8 DataBits, > + IN EFI_STOP_BITS_TYPE StopBits > + ); > + > +/** > + Set Control Bits. > + > + @param This Pointer to EFI_SERIAL_IO_PROTOCOL > + @param Control Control bits that can be settable > + > + @retval EFI_SUCCESS New Control bits were set successfully > + @retval EFI_UNSUPPORTED The Control bits wanted to set are not supported > + > +**/ > +EFI_STATUS > +EFIAPI > +SerialSetControl ( > + IN EFI_SERIAL_IO_PROTOCOL *This, > + IN UINT32 Control > + ); > + > +/** > + Get ControlBits. > + > + @param This Pointer to EFI_SERIAL_IO_PROTOCOL > + @param Control Control signals of the serial device > + > + @retval EFI_SUCCESS Get Control signals successfully > + > +**/ > +EFI_STATUS > +EFIAPI > +SerialGetControl ( > + IN EFI_SERIAL_IO_PROTOCOL *This, > + OUT UINT32 *Control > + ); > + > +/** > + Write the specified number of bytes to serial device. > + > + @param This Pointer to EFI_SERIAL_IO_PROTOCOL > + @param BufferSize On input the size of Buffer, on output the > amount of > + data actually written > + @param Buffer The buffer of data to write > + > + @retval EFI_SUCCESS The data were written successfully > + @retval EFI_DEVICE_ERROR The device reported an error > + @retval EFI_TIMEOUT The write operation was stopped due to timeout > + > +**/ > +EFI_STATUS > +EFIAPI > +SerialWrite ( > + IN EFI_SERIAL_IO_PROTOCOL *This, > + IN OUT UINTN *BufferSize, > + IN VOID *Buffer > + ); > + > +/** > + Read the specified number of bytes from serial device. > + > + @param This Pointer to EFI_SERIAL_IO_PROTOCOL > + @param BufferSize On input the size of Buffer, on output the > amount of > + data returned in buffer > + @param Buffer The buffer to return the data into > + > + @retval EFI_SUCCESS The data were read successfully > + @retval EFI_DEVICE_ERROR The device reported an error > + @retval EFI_TIMEOUT The read operation was stopped due to timeout > + > +**/ > +EFI_STATUS > +EFIAPI > +SerialRead ( > + IN EFI_SERIAL_IO_PROTOCOL *This, > + IN OUT UINTN *BufferSize, > + OUT VOID *Buffer > + ); > + > +// > +// Internal Functions > +// > +/** > + Use scratchpad register to test if this serial port is present. > + > + @param SerialDevice Pointer to serial device structure > + > + @return if this serial port is present > +**/ > +BOOLEAN > +SerialPresent ( > + IN SERIAL_DEV *SerialDevice > + ); > + > +/** > + Detect whether specific FIFO is full or not. > + > + @param Fifo A pointer to the Data Structure SERIAL_DEV_FIFO > + > + @return whether specific FIFO is full or not > + > +**/ > +BOOLEAN > +SerialFifoFull ( > + IN SERIAL_DEV_FIFO *Fifo > + ); > + > +/** > + Detect whether specific FIFO is empty or not. > + > + @param Fifo A pointer to the Data Structure SERIAL_DEV_FIFO > + > + @return whether specific FIFO is empty or not > + > +**/ > +BOOLEAN > +SerialFifoEmpty ( > + IN SERIAL_DEV_FIFO *Fifo > + ); > + > +/** > + Add data to specific FIFO. > + > + @param Fifo A pointer to the Data Structure > SERIAL_DEV_FIFO > + @param Data the data added to FIFO > + > + @retval EFI_SUCCESS Add data to specific FIFO successfully > + @retval EFI_OUT_OF_RESOURCE Failed to add data because FIFO is already > full > + > +**/ > +EFI_STATUS > +SerialFifoAdd ( > + IN SERIAL_DEV_FIFO *Fifo, > + IN UINT8 Data > + ); > + > +/** > + Remove data from specific FIFO. > + > + @param Fifo A pointer to the Data Structure > SERIAL_DEV_FIFO > + @param Data the data removed from FIFO > + > + @retval EFI_SUCCESS Remove data from specific FIFO successfully > + @retval EFI_OUT_OF_RESOURCE Failed to remove data because FIFO is empty > + > +**/ > +EFI_STATUS > +SerialFifoRemove ( > + IN SERIAL_DEV_FIFO *Fifo, > + OUT UINT8 *Data > + ); > + > +/** > + Reads and writes all avaliable data. > + > + @param SerialDevice The device to flush > + > + @retval EFI_SUCCESS Data was read/written successfully. > + @retval EFI_OUT_OF_RESOURCE Failed because software receive FIFO is > full. Note, when > + this happens, pending writes are not done. > + > +**/ > +EFI_STATUS > +SerialReceiveTransmit ( > + IN SERIAL_DEV *SerialDevice > + ); > + > +/** > + Read serial port. > + > + @param SerialDev Pointer to serial device > + @param Offset Offset in register group > + > + @return Data read from serial port > +**/ > +UINT8 > +SerialReadRegister ( > + IN SERIAL_DEV *SerialDev, > + IN UINT32 Offset > + ); > + > +/** > + Write serial port. > + > + @param SerialDev Pointer to serial device > + @param Offset Offset in register group > + @param Data data which is to be written to some serial port > register > +**/ > +VOID > +SerialWriteRegister ( > + IN SERIAL_DEV *SerialDev, > + IN UINT32 Offset, > + IN UINT8 Data > + ); > + > + > +// > +// EFI Component Name Functions > +// > +/** > + Retrieves a Unicode string that is the user readable name of the driver. > + > + This function retrieves the user readable name of a driver in the form of a > + Unicode string. If the driver specified by This has a user readable name in > + the language specified by Language, then a pointer to the driver name is > + returned in DriverName, and EFI_SUCCESS is returned. If the driver > specified > + by This does not support the language specified by Language, > + then EFI_UNSUPPORTED is returned. > + > + @param This[in] A pointer to the > EFI_COMPONENT_NAME2_PROTOCOL or > + EFI_COMPONENT_NAME_PROTOCOL instance. > + > + @param Language[in] A pointer to a Null-terminated ASCII string > + array indicating the language. This is the > + language of the driver name that the caller > is > + requesting, and it must match one of the > + languages specified in SupportedLanguages. > The > + number of languages supported by a driver is > up > + to the driver writer. Language is specified > + in RFC 4646 or ISO 639-2 language code > format. > + > + @param DriverName[out] A pointer to the Unicode string to return. > + This Unicode string is the name of the > + driver specified by This in the language > + specified by Language. > + > + @retval EFI_SUCCESS The Unicode string for the Driver specified > by > + This and the language specified by Language > was > + returned in DriverName. > + > + @retval EFI_INVALID_PARAMETER Language is NULL. > + > + @retval EFI_INVALID_PARAMETER DriverName is NULL. > + > + @retval EFI_UNSUPPORTED The driver specified by This does not support > + the language specified by Language. > + > +**/ > +EFI_STATUS > +EFIAPI > +SerialComponentNameGetDriverName ( > + IN EFI_COMPONENT_NAME_PROTOCOL *This, > + IN CHAR8 *Language, > + OUT CHAR16 **DriverName > + ); > + > + > +/** > + Retrieves a Unicode string that is the user readable name of the controller > + that is being managed by a driver. > + > + This function retrieves the user readable name of the controller specified > by > + ControllerHandle and ChildHandle in the form of a Unicode string. If the > + driver specified by This has a user readable name in the language > specified by > + Language, then a pointer to the controller name is returned in > ControllerName, > + and EFI_SUCCESS is returned. If the driver specified by This is not > currently > + managing the controller specified by ControllerHandle and ChildHandle, > + then EFI_UNSUPPORTED is returned. If the driver specified by This does not > + support the language specified by Language, then EFI_UNSUPPORTED is > returned. > + > + @param This[in] A pointer to the > EFI_COMPONENT_NAME2_PROTOCOL or > + EFI_COMPONENT_NAME_PROTOCOL instance. > + > + @param ControllerHandle[in] The handle of a controller that the driver > + specified by This is managing. This handle > + specifies the controller whose name is to be > + returned. > + > + @param ChildHandle[in] The handle of the child controller to > retrieve > + the name of. This is an optional parameter > that > + may be NULL. It will be NULL for device > + drivers. It will also be NULL for a bus > drivers > + that wish to retrieve the name of the bus > + controller. It will not be NULL for a bus > + driver that wishes to retrieve the name of a > + child controller. > + > + @param Language[in] A pointer to a Null-terminated ASCII string > + array indicating the language. This is the > + language of the driver name that the caller > is > + requesting, and it must match one of the > + languages specified in SupportedLanguages. > The > + number of languages supported by a driver is > up > + to the driver writer. Language is specified > in > + RFC 4646 or ISO 639-2 language code format. > + > + @param ControllerName[out] A pointer to the Unicode string to return. > + This Unicode string is the name of the > + controller specified by ControllerHandle and > + ChildHandle in the language specified by > + Language from the point of view of the driver > + specified by This. > + > + @retval EFI_SUCCESS The Unicode string for the user readable > name in > + the language specified by Language for the > + driver specified by This was returned in > + DriverName. > + > + @retval EFI_INVALID_PARAMETER ControllerHandle is NULL. > + > + @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid > + EFI_HANDLE. > + > + @retval EFI_INVALID_PARAMETER Language is NULL. > + > + @retval EFI_INVALID_PARAMETER ControllerName is NULL. > + > + @retval EFI_UNSUPPORTED The driver specified by This is not currently > + managing the controller specified by > + ControllerHandle and ChildHandle. > + > + @retval EFI_UNSUPPORTED The driver specified by This does not support > + the language specified by Language. > + > +**/ > +EFI_STATUS > +EFIAPI > +SerialComponentNameGetControllerName ( > + IN EFI_COMPONENT_NAME_PROTOCOL *This, > + IN EFI_HANDLE ControllerHandle, > + IN EFI_HANDLE ChildHandle > OPTIONAL, > + IN CHAR8 *Language, > + OUT CHAR16 **ControllerName > + ); > + > +/** > + Add the component name for the serial io device > + > + @param SerialDevice A pointer to the SERIAL_DEV instance. > + @param Uid Unique ID for the serial device. > +**/ > +VOID > +AddName ( > + IN SERIAL_DEV *SerialDevice, > + IN UINT32 Uid > + ); > + > +/** > + Checks whether the UART parameters are valid and computes the Divisor. > + > + @param ClockRate The clock rate of the serial device used to verify > + the BaudRate. Do not verify the BaudRate if it's 0. > + @param BaudRate The requested baudrate of the serial device. > + @param DataBits Number of databits used in serial device. > + @param Parity The type of parity used in serial device. > + @param StopBits Number of stopbits used in serial device. > + @param Divisor Return the divisor if ClockRate is not 0. > + @param ActualBaudRate Return the actual supported baudrate without > + exceeding BaudRate. NULL means baudrate degradation > + is not allowed. > + If the requested BaudRate is not supported, the > routine > + returns TRUE and the Actual Baud Rate when > ActualBaudRate > + is not NULL, returns FALSE when ActualBaudRate is > NULL. > + > + @retval TRUE The UART parameters are valid. > + @retval FALSE The UART parameters are not valid. > +**/ > +BOOLEAN > +VerifyUartParameters ( > + IN UINT32 ClockRate, > + IN UINT64 BaudRate, > + IN UINT8 DataBits, > + IN EFI_PARITY_TYPE Parity, > + IN EFI_STOP_BITS_TYPE StopBits, > + OUT UINT64 *Divisor, > + OUT UINT64 *ActualBaudRate > + ); > + > +/** > + Skip the optional Controller device path node and return the > + pointer to the next device path node. > + > + @param DevicePath Pointer to the device path. > + @param ContainsControllerNode Returns TRUE if the Controller device path > exists. > + @param ControllerNumber Returns the Controller Number if Controller > device path exists. > + > + @return Pointer to the next device path node. > +**/ > +UART_DEVICE_PATH * > +SkipControllerDevicePathNode ( > + EFI_DEVICE_PATH_PROTOCOL *DevicePath, > + BOOLEAN *ContainsControllerNode, > + UINT32 *ControllerNumber > + ); > + > +/** > + Check the device path node whether it's the Flow Control node or not. > + > + @param[in] FlowControl The device path node to be checked. > + > + @retval TRUE It's the Flow Control node. > + @retval FALSE It's not. > + > +**/ > +BOOLEAN > +IsUartFlowControlDevicePathNode ( > + IN UART_FLOW_CONTROL_DEVICE_PATH *FlowControl > + ); > +#endif > diff --git a/MdeModulePkg/Bus/Pci/PciSioSerialDxe/SerialIo.c > b/MdeModulePkg/Bus/Pci/PciSioSerialDxe/SerialIo.c > new file mode 100644 > index 0000000..6adf7e3 > --- /dev/null > +++ b/MdeModulePkg/Bus/Pci/PciSioSerialDxe/SerialIo.c > @@ -0,0 +1,1321 @@ > +/** @file > + SerialIo implementation for PCI or SIO UARTs. > + > +Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.<BR> > +This program and the accompanying materials > +are licensed and made available under the terms and conditions of the BSD > License > +which accompanies this distribution. The full text of the license may be > found at > +http://opensource.org/licenses/bsd-license.php > + > +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, > +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. > + > +**/ > + > +#include "Serial.h" > + > +/** > + Skip the optional Controller device path node and return the > + pointer to the next device path node. > + > + @param DevicePath Pointer to the device path. > + @param ContainsControllerNode Returns TRUE if the Controller device path > exists. > + @param ControllerNumber Returns the Controller Number if Controller > device path exists. > + > + @return Pointer to the next device path node. > +**/ > +UART_DEVICE_PATH * > +SkipControllerDevicePathNode ( > + EFI_DEVICE_PATH_PROTOCOL *DevicePath, > + BOOLEAN *ContainsControllerNode, > + UINT32 *ControllerNumber > + ) > +{ > + if ((DevicePathType (DevicePath) == HARDWARE_DEVICE_PATH) && > + (DevicePathSubType (DevicePath) == HW_CONTROLLER_DP) > + ) { > + if (ContainsControllerNode != NULL) { > + *ContainsControllerNode = TRUE; > + } > + if (ControllerNumber != NULL) { > + *ControllerNumber = ((CONTROLLER_DEVICE_PATH *) > DevicePath)->ControllerNumber; > + } > + DevicePath = NextDevicePathNode (DevicePath); > + } else { > + if (ContainsControllerNode != NULL) { > + *ContainsControllerNode = FALSE; > + } > + } > + return (UART_DEVICE_PATH *) DevicePath; > +} > + > +/** > + Checks whether the UART parameters are valid and computes the Divisor. > + > + @param ClockRate The clock rate of the serial device used to verify > + the BaudRate. Do not verify the BaudRate if it's 0. > + @param BaudRate The requested baudrate of the serial device. > + @param DataBits Number of databits used in serial device. > + @param Parity The type of parity used in serial device. > + @param StopBits Number of stopbits used in serial device. > + @param Divisor Return the divisor if ClockRate is not 0. > + @param ActualBaudRate Return the actual supported baudrate without > + exceeding BaudRate. NULL means baudrate degradation > + is not allowed. > + If the requested BaudRate is not supported, the > routine > + returns TRUE and the Actual Baud Rate when > ActualBaudRate > + is not NULL, returns FALSE when ActualBaudRate is > NULL. > + > + @retval TRUE The UART parameters are valid. > + @retval FALSE The UART parameters are not valid. > +**/ > +BOOLEAN > +VerifyUartParameters ( > + IN UINT32 ClockRate, > + IN UINT64 BaudRate, > + IN UINT8 DataBits, > + IN EFI_PARITY_TYPE Parity, > + IN EFI_STOP_BITS_TYPE StopBits, > + OUT UINT64 *Divisor, > + OUT UINT64 *ActualBaudRate > + ) > +{ > + UINT64 Remainder; > + UINT32 ComputedBaudRate; > + UINT64 ComputedDivisor; > + UINT64 Percent; > + > + if ((DataBits < 5) || (DataBits > 8) || > + (Parity < NoParity) || (Parity > SpaceParity) || > + (StopBits < OneStopBit) || (StopBits > TwoStopBits) || > + ((DataBits == 5) && (StopBits == TwoStopBits)) || > + ((DataBits >= 6) && (DataBits <= 8) && (StopBits == OneFiveStopBits)) > + ) { > + return FALSE; > + } > + > + // > + // Do not verify the baud rate if clock rate is unknown (0). > + // > + if (ClockRate == 0) { > + return TRUE; > + } > + > + // > + // Compute divisor use to program the baud rate using a round determination > + // Divisor = ClockRate / 16 / BaudRate = ClockRate / (16 * BaudRate) > + // = ClockRate / (BaudRate << 4) > + // > + ComputedDivisor = DivU64x64Remainder (ClockRate, LShiftU64 (BaudRate, 4), > &Remainder); > + // > + // Round Divisor up by 1 if the Remainder is more than half (16 * BaudRate) > + // BaudRate * 16 / 2 = BaudRate * 8 = (BaudRate << 3) > + // > + if (Remainder >= LShiftU64 (BaudRate, 3)) { > + ComputedDivisor++; > + } > + // > + // If the computed divisor is larger than the maximum value that can be > programmed > + // into the UART, then the requested baud rate can not be supported. > + // > + if (ComputedDivisor > MAX_UINT16) { > + return FALSE; > + } > + > + // > + // If the computed divisor is 0, then use a computed divisor of 1, which > will select > + // the maximum supported baud rate. > + // > + if (ComputedDivisor == 0) { > + ComputedDivisor = 1; > + } > + > + // > + // Actual baud rate that the serial port will be programmed for > + // should be with in 4% of requested one. > + // > + ComputedBaudRate = ClockRate / ((UINT16) ComputedDivisor << 4); > + if (ComputedBaudRate == 0) { > + return FALSE; > + } > + > + Percent = DivU64x32 (MultU64x32 (BaudRate, 100), ComputedBaudRate); > + DEBUG ((EFI_D_INFO, "ClockRate = %d\n", ClockRate)); > + DEBUG ((EFI_D_INFO, "Divisor = %ld\n", ComputedDivisor)); > + DEBUG ((EFI_D_INFO, "BaudRate/Actual (%ld/%d) = %d%%\n", BaudRate, > ComputedBaudRate, Percent)); > + > + // > + // If the requested BaudRate is not supported: > + // Returns TRUE and the Actual Baud Rate when ActualBaudRate is not NULL; > + // Returns FALSE when ActualBaudRate is NULL. > + // > + if ((Percent >= 96) && (Percent <= 104)) { > + if (ActualBaudRate != NULL) { > + *ActualBaudRate = BaudRate; > + } > + if (Divisor != NULL) { > + *Divisor = ComputedDivisor; > + } > + return TRUE; > + } > + if (ComputedBaudRate < BaudRate) { > + if (ActualBaudRate != NULL) { > + *ActualBaudRate = ComputedBaudRate; > + } > + if (Divisor != NULL) { > + *Divisor = ComputedDivisor; > + } > + return TRUE; > + } > + > + // > + // ActualBaudRate is higher than requested baud rate and more than 4% > + // higher than the requested value. Increment Divisor if it is less > + // than MAX_UINT16 and computed baud rate with new divisor. > + // > + if (ComputedDivisor == MAX_UINT16) { > + return FALSE; > + } > + ComputedDivisor++; > + ComputedBaudRate = ClockRate / ((UINT16) ComputedDivisor << 4); > + if (ComputedBaudRate == 0) { > + return FALSE; > + } > + > + DEBUG ((EFI_D_INFO, "ClockRate = %d\n", ClockRate)); > + DEBUG ((EFI_D_INFO, "Divisor = %ld\n", ComputedDivisor)); > + DEBUG ((EFI_D_INFO, "BaudRate/Actual (%ld/%d) = %d%%\n", BaudRate, > ComputedBaudRate, Percent)); > + > + if (ActualBaudRate != NULL) { > + *ActualBaudRate = ComputedBaudRate; > + } > + if (Divisor != NULL) { > + *Divisor = ComputedDivisor; > + } > + return TRUE; > +} > + > +/** > + Detect whether specific FIFO is full or not. > + > + @param Fifo A pointer to the Data Structure SERIAL_DEV_FIFO > + > + @return whether specific FIFO is full or not > +**/ > +BOOLEAN > +SerialFifoFull ( > + IN SERIAL_DEV_FIFO *Fifo > + ) > +{ > + return (BOOLEAN) (((Fifo->Tail + 1) % SERIAL_MAX_FIFO_SIZE) == Fifo->Head); > +} > + > +/** > + Detect whether specific FIFO is empty or not. > + > + @param Fifo A pointer to the Data Structure SERIAL_DEV_FIFO > + > + @return whether specific FIFO is empty or not > +**/ > +BOOLEAN > +SerialFifoEmpty ( > + IN SERIAL_DEV_FIFO *Fifo > + ) > + > +{ > + return (BOOLEAN) (Fifo->Head == Fifo->Tail); > +} > + > +/** > + Add data to specific FIFO. > + > + @param Fifo A pointer to the Data Structure > SERIAL_DEV_FIFO > + @param Data the data added to FIFO > + > + @retval EFI_SUCCESS Add data to specific FIFO successfully > + @retval EFI_OUT_OF_RESOURCE Failed to add data because FIFO is already > full > +**/ > +EFI_STATUS > +SerialFifoAdd ( > + IN OUT SERIAL_DEV_FIFO *Fifo, > + IN UINT8 Data > + ) > +{ > + // > + // if FIFO full can not add data > + // > + if (SerialFifoFull (Fifo)) { > + return EFI_OUT_OF_RESOURCES; > + } > + // > + // FIFO is not full can add data > + // > + Fifo->Data[Fifo->Tail] = Data; > + Fifo->Tail = (Fifo->Tail + 1) % SERIAL_MAX_FIFO_SIZE; > + return EFI_SUCCESS; > +} > + > +/** > + Remove data from specific FIFO. > + > + @param Fifo A pointer to the Data Structure > SERIAL_DEV_FIFO > + @param Data the data removed from FIFO > + > + @retval EFI_SUCCESS Remove data from specific FIFO successfully > + @retval EFI_OUT_OF_RESOURCE Failed to remove data because FIFO is empty > + > +**/ > +EFI_STATUS > +SerialFifoRemove ( > + IN OUT SERIAL_DEV_FIFO *Fifo, > + OUT UINT8 *Data > + ) > +{ > + // > + // if FIFO is empty, no data can remove > + // > + if (SerialFifoEmpty (Fifo)) { > + return EFI_OUT_OF_RESOURCES; > + } > + // > + // FIFO is not empty, can remove data > + // > + *Data = Fifo->Data[Fifo->Head]; > + Fifo->Head = (Fifo->Head + 1) % SERIAL_MAX_FIFO_SIZE; > + return EFI_SUCCESS; > +} > + > +/** > + Reads and writes all avaliable data. > + > + @param SerialDevice The device to transmit. > + > + @retval EFI_SUCCESS Data was read/written successfully. > + @retval EFI_OUT_OF_RESOURCE Failed because software receive FIFO is > full. Note, when > + this happens, pending writes are not done. > + > +**/ > +EFI_STATUS > +SerialReceiveTransmit ( > + IN SERIAL_DEV *SerialDevice > + ) > + > +{ > + 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 = SerialFifoFull (&SerialDevice->Receive); > + if (!SerialFifoEmpty (&SerialDevice->Transmit)) { > + SerialFifoRemove (&SerialDevice->Transmit, &Data); > + if (ReceiveFifoFull) { > + return EFI_OUT_OF_RESOURCES; > + } > + > + SerialFifoAdd (&SerialDevice->Receive, Data); > + } > + } while (!SerialFifoEmpty (&SerialDevice->Transmit)); > + } else { > + ReceiveFifoFull = SerialFifoFull (&SerialDevice->Receive); > + // > + // For full handshake flow control, tell the peer to send data > + // if receive buffer is available. > + // > + if (SerialDevice->HardwareFlowControl && > + !FeaturePcdGet(PcdSerialUseHalfHandshake)&& > + !ReceiveFifoFull > + ) { > + Mcr.Data = READ_MCR (SerialDevice); > + Mcr.Bits.Rts = 1; > + WRITE_MCR (SerialDevice, Mcr.Data); > + } > + do { > + Lsr.Data = READ_LSR (SerialDevice); > + > + // > + // Flush incomming data to prevent a an overrun during a long write > + // > + if ((Lsr.Bits.Dr == 1) && !ReceiveFifoFull) { > + ReceiveFifoFull = SerialFifoFull (&SerialDevice->Receive); > + if (!ReceiveFifoFull) { > + if (Lsr.Bits.FIFOe == 1 || Lsr.Bits.Oe == 1 || Lsr.Bits.Pe == 1 || > Lsr.Bits.Fe == 1 || Lsr.Bits.Bi == 1) { > + REPORT_STATUS_CODE_WITH_DEVICE_PATH ( > + EFI_ERROR_CODE, > + EFI_P_EC_INPUT_ERROR | EFI_PERIPHERAL_SERIAL_PORT, > + SerialDevice->DevicePath > + ); > + if (Lsr.Bits.FIFOe == 1 || Lsr.Bits.Pe == 1|| Lsr.Bits.Fe == 1 > || Lsr.Bits.Bi == 1) { > + Data = READ_RBR (SerialDevice); > + continue; > + } > + } > + > + Data = READ_RBR (SerialDevice); > + > + SerialFifoAdd (&SerialDevice->Receive, Data); > + > + // > + // For full handshake flow control, if receive buffer full > + // tell the peer to stop sending data. > + // > + if (SerialDevice->HardwareFlowControl && > + !FeaturePcdGet(PcdSerialUseHalfHandshake) && > + SerialFifoFull (&SerialDevice->Receive) > + ) { > + Mcr.Data = READ_MCR (SerialDevice); > + Mcr.Bits.Rts = 0; > + WRITE_MCR (SerialDevice, Mcr.Data); > + } > + > + > + continue; > + } else { > + REPORT_STATUS_CODE_WITH_DEVICE_PATH ( > + EFI_PROGRESS_CODE, > + EFI_P_SERIAL_PORT_PC_CLEAR_BUFFER | EFI_PERIPHERAL_SERIAL_PORT, > + SerialDevice->DevicePath > + ); > + } > + } > + // > + // Do the write > + // > + if (Lsr.Bits.Thre == 1 && !SerialFifoEmpty (&SerialDevice->Transmit)) { > + // > + // Make sure the transmit data will not be missed > + // > + if (SerialDevice->HardwareFlowControl) { > + // > + // For half handshake flow control assert RTS before sending. > + // > + if (FeaturePcdGet(PcdSerialUseHalfHandshake)) { > + Mcr.Data = READ_MCR (SerialDevice); > + Mcr.Bits.Rts= 0; > + WRITE_MCR (SerialDevice, Mcr.Data); > + } > + // > + // Wait for CTS > + // > + TimeOut = 0; > + Msr.Data = READ_MSR (SerialDevice); > + while ((Msr.Bits.Dcd == 1) && ((Msr.Bits.Cts == 0) ^ > FeaturePcdGet(PcdSerialUseHalfHandshake))) { > + gBS->Stall (TIMEOUT_STALL_INTERVAL); > + TimeOut++; > + if (TimeOut > 5) { > + break; > + } > + > + Msr.Data = READ_MSR (SerialDevice); > + } > + > + if ((Msr.Bits.Dcd == 0) || ((Msr.Bits.Cts == 1) ^ > FeaturePcdGet(PcdSerialUseHalfHandshake))) { > + SerialFifoRemove (&SerialDevice->Transmit, &Data); > + WRITE_THR (SerialDevice, Data); > + } > + > + // > + // For half handshake flow control, tell DCE we are done. > + // > + if (FeaturePcdGet(PcdSerialUseHalfHandshake)) { > + Mcr.Data = READ_MCR (SerialDevice); > + Mcr.Bits.Rts = 1; > + WRITE_MCR (SerialDevice, Mcr.Data); > + } > + } else { > + SerialFifoRemove (&SerialDevice->Transmit, &Data); > + WRITE_THR (SerialDevice, Data); > + } > + } > + } while (Lsr.Bits.Thre == 1 && !SerialFifoEmpty > (&SerialDevice->Transmit)); > + } > + > + return EFI_SUCCESS; > +} > + > +/** > + Flush the serial hardware transmit FIFO and shift register. > + > + @param SerialDevice The device to flush. > +**/ > +VOID > +SerialFlushTransmitFifo ( > + SERIAL_DEV *SerialDevice > + ) > +{ > + SERIAL_PORT_LSR Lsr; > + > + // > + // Wait for the serial port to be ready, to make sure both the transmit > FIFO > + // and shift register empty. > + // > + do { > + Lsr.Data = READ_LSR (SerialDevice); > + } while (Lsr.Bits.Temt == 0); > +} > + > +// > +// Interface Functions > +// > +/** > + Reset serial device. > + > + @param This Pointer to EFI_SERIAL_IO_PROTOCOL > + > + @retval EFI_SUCCESS Reset successfully > + @retval EFI_DEVICE_ERROR Failed to reset > + > +**/ > +EFI_STATUS > +EFIAPI > +SerialReset ( > + IN EFI_SERIAL_IO_PROTOCOL *This > + ) > +{ > + EFI_STATUS Status; > + SERIAL_DEV *SerialDevice; > + SERIAL_PORT_LCR Lcr; > + SERIAL_PORT_IER Ier; > + SERIAL_PORT_MCR Mcr; > + SERIAL_PORT_FCR Fcr; > + EFI_TPL Tpl; > + UINT32 Control; > + > + SerialDevice = SERIAL_DEV_FROM_THIS (This); > + > + // > + // Report the status code reset the serial > + // > + REPORT_STATUS_CODE_WITH_DEVICE_PATH ( > + EFI_PROGRESS_CODE, > + EFI_P_PC_RESET | EFI_PERIPHERAL_SERIAL_PORT, > + SerialDevice->DevicePath > + ); > + > + Tpl = gBS->RaiseTPL (TPL_NOTIFY); > + > + SerialFlushTransmitFifo (SerialDevice); > + > + // > + // Make sure DLAB is 0. > + // > + Lcr.Data = READ_LCR (SerialDevice); > + Lcr.Bits.DLab = 0; > + WRITE_LCR (SerialDevice, Lcr.Data); > + > + // > + // Turn off all interrupts > + // > + Ier.Data = READ_IER (SerialDevice); > + Ier.Bits.Ravie = 0; > + Ier.Bits.Theie = 0; > + Ier.Bits.Rie = 0; > + Ier.Bits.Mie = 0; > + WRITE_IER (SerialDevice, Ier.Data); > + > + // > + // Reset the FIFO > + // > + Fcr.Data = 0; > + Fcr.Bits.TrFIFOE = 0; > + WRITE_FCR (SerialDevice, Fcr.Data); > + > + // > + // Turn off loopback and disable device interrupt. > + // > + Mcr.Data = READ_MCR (SerialDevice); > + Mcr.Bits.Out1 = 0; > + Mcr.Bits.Out2 = 0; > + Mcr.Bits.Lme = 0; > + WRITE_MCR (SerialDevice, Mcr.Data); > + > + // > + // Clear the scratch pad register > + // > + WRITE_SCR (SerialDevice, 0); > + > + // > + // Enable FIFO > + // > + Fcr.Bits.TrFIFOE = 1; > + if (SerialDevice->ReceiveFifoDepth > 16) { > + Fcr.Bits.TrFIFO64 = 1; > + } > + Fcr.Bits.ResetRF = 1; > + Fcr.Bits.ResetTF = 1; > + WRITE_FCR (SerialDevice, Fcr.Data); > + > + // > + // Go set the current attributes > + // > + Status = This->SetAttributes ( > + This, > + This->Mode->BaudRate, > + This->Mode->ReceiveFifoDepth, > + This->Mode->Timeout, > + (EFI_PARITY_TYPE) This->Mode->Parity, > + (UINT8) This->Mode->DataBits, > + (EFI_STOP_BITS_TYPE) This->Mode->StopBits > + ); > + > + if (EFI_ERROR (Status)) { > + gBS->RestoreTPL (Tpl); > + return EFI_DEVICE_ERROR; > + } > + // > + // Go set the current control bits > + // > + Control = 0; > + if (SerialDevice->HardwareFlowControl) { > + Control |= EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE; > + } > + if (SerialDevice->SoftwareLoopbackEnable) { > + Control |= EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE; > + } > + Status = This->SetControl ( > + This, > + Control > + ); > + > + if (EFI_ERROR (Status)) { > + gBS->RestoreTPL (Tpl); > + return EFI_DEVICE_ERROR; > + } > + > + // > + // Reset the software FIFO > + // > + SerialDevice->Receive.Head = SerialDevice->Receive.Tail = 0; > + SerialDevice->Transmit.Head = SerialDevice->Transmit.Tail = 0; > + gBS->RestoreTPL (Tpl); > + > + // > + // Device reset is complete > + // > + return EFI_SUCCESS; > +} > + > +/** > + Set new attributes to a serial device. > + > + @param This Pointer to EFI_SERIAL_IO_PROTOCOL > + @param BaudRate The baudrate of the serial device > + @param ReceiveFifoDepth The depth of receive FIFO buffer > + @param Timeout The request timeout for a single char > + @param Parity The type of parity used in serial device > + @param DataBits Number of databits used in serial device > + @param StopBits Number of stopbits used in serial device > + > + @retval EFI_SUCCESS The new attributes were set > + @retval EFI_INVALID_PARAMETERS One or more attributes have an > unsupported value > + @retval EFI_UNSUPPORTED Data Bits can not set to 5 or 6 > + @retval EFI_DEVICE_ERROR The serial device is not functioning > correctly (no return) > + > +**/ > +EFI_STATUS > +EFIAPI > +SerialSetAttributes ( > + IN EFI_SERIAL_IO_PROTOCOL *This, > + IN UINT64 BaudRate, > + IN UINT32 ReceiveFifoDepth, > + IN UINT32 Timeout, > + IN EFI_PARITY_TYPE Parity, > + IN UINT8 DataBits, > + IN EFI_STOP_BITS_TYPE StopBits > + ) > +{ > + EFI_STATUS Status; > + SERIAL_DEV *SerialDevice; > + UINT64 Divisor; > + SERIAL_PORT_LCR Lcr; > + UART_DEVICE_PATH *Uart; > + EFI_TPL Tpl; > + > + SerialDevice = SERIAL_DEV_FROM_THIS (This); > + > + // > + // Check for default settings and fill in actual values. > + // > + if (BaudRate == 0) { > + BaudRate = PcdGet64 (PcdUartDefaultBaudRate); > + } > + > + if (ReceiveFifoDepth == 0) { > + ReceiveFifoDepth = SerialDevice->ReceiveFifoDepth; > + } > + > + if (Timeout == 0) { > + Timeout = SERIAL_PORT_DEFAULT_TIMEOUT; > + } > + > + if (Parity == DefaultParity) { > + Parity = (EFI_PARITY_TYPE) PcdGet8 (PcdUartDefaultParity); > + } > + > + if (DataBits == 0) { > + DataBits = PcdGet8 (PcdUartDefaultDataBits); > + } > + > + if (StopBits == DefaultStopBits) { > + StopBits = (EFI_STOP_BITS_TYPE) PcdGet8 (PcdUartDefaultStopBits); > + } > + > + if (!VerifyUartParameters (SerialDevice->ClockRate, BaudRate, DataBits, > Parity, StopBits, &Divisor, &BaudRate)) { > + return EFI_INVALID_PARAMETER; > + } > + > + if ((ReceiveFifoDepth == 0) || (ReceiveFifoDepth > > SerialDevice->ReceiveFifoDepth)) { > + return EFI_INVALID_PARAMETER; > + } > + > + if ((Timeout < SERIAL_PORT_MIN_TIMEOUT) || (Timeout > > SERIAL_PORT_MAX_TIMEOUT)) { > + return EFI_INVALID_PARAMETER; > + } > + > + Tpl = gBS->RaiseTPL (TPL_NOTIFY); > + > + SerialFlushTransmitFifo (SerialDevice); > + > + // > + // Put serial port on Divisor Latch Mode > + // > + Lcr.Data = READ_LCR (SerialDevice); > + Lcr.Bits.DLab = 1; > + WRITE_LCR (SerialDevice, Lcr.Data); > + > + // > + // Write the divisor to the serial port > + // > + WRITE_DLL (SerialDevice, (UINT8) Divisor); > + WRITE_DLM (SerialDevice, (UINT8) ((UINT16) Divisor >> 8)); > + > + // > + // Put serial port back in normal mode and set remaining attributes. > + // > + Lcr.Bits.DLab = 0; > + > + switch (Parity) { > + case NoParity: > + Lcr.Bits.ParEn = 0; > + Lcr.Bits.EvenPar = 0; > + Lcr.Bits.SticPar = 0; > + break; > + > + case EvenParity: > + Lcr.Bits.ParEn = 1; > + Lcr.Bits.EvenPar = 1; > + Lcr.Bits.SticPar = 0; > + break; > + > + case OddParity: > + Lcr.Bits.ParEn = 1; > + Lcr.Bits.EvenPar = 0; > + Lcr.Bits.SticPar = 0; > + break; > + > + case SpaceParity: > + Lcr.Bits.ParEn = 1; > + Lcr.Bits.EvenPar = 1; > + Lcr.Bits.SticPar = 1; > + break; > + > + case MarkParity: > + Lcr.Bits.ParEn = 1; > + Lcr.Bits.EvenPar = 0; > + Lcr.Bits.SticPar = 1; > + break; > + > + default: > + break; > + } > + > + switch (StopBits) { > + case OneStopBit: > + Lcr.Bits.StopB = 0; > + break; > + > + case OneFiveStopBits: > + case TwoStopBits: > + Lcr.Bits.StopB = 1; > + break; > + > + default: > + break; > + } > + // > + // DataBits > + // > + Lcr.Bits.SerialDB = (UINT8) ((DataBits - 5) & 0x03); > + WRITE_LCR (SerialDevice, Lcr.Data); > + > + // > + // Set the Serial I/O mode > + // > + This->Mode->BaudRate = BaudRate; > + This->Mode->ReceiveFifoDepth = ReceiveFifoDepth; > + This->Mode->Timeout = Timeout; > + This->Mode->Parity = Parity; > + This->Mode->DataBits = DataBits; > + This->Mode->StopBits = StopBits; > + > + // > + // See if Device Path Node has actually changed > + // > + if (SerialDevice->UartDevicePath.BaudRate == BaudRate && > + SerialDevice->UartDevicePath.DataBits == DataBits && > + SerialDevice->UartDevicePath.Parity == Parity && > + SerialDevice->UartDevicePath.StopBits == StopBits > + ) { > + gBS->RestoreTPL (Tpl); > + return EFI_SUCCESS; > + } > + // > + // Update the device path > + // > + SerialDevice->UartDevicePath.BaudRate = BaudRate; > + SerialDevice->UartDevicePath.DataBits = DataBits; > + SerialDevice->UartDevicePath.Parity = (UINT8) Parity; > + SerialDevice->UartDevicePath.StopBits = (UINT8) StopBits; > + > + Status = EFI_SUCCESS; > + if (SerialDevice->Handle != NULL) { > + > + // > + // Skip the optional Controller device path node > + // > + Uart = SkipControllerDevicePathNode ( > + (EFI_DEVICE_PATH_PROTOCOL *) ( > + (UINT8 *) SerialDevice->DevicePath + GetDevicePathSize > (SerialDevice->ParentDevicePath) - END_DEVICE_PATH_LENGTH > + ), > + NULL, > + NULL > + ); > + CopyMem (Uart, &SerialDevice->UartDevicePath, sizeof (UART_DEVICE_PATH)); > + Status = gBS->ReinstallProtocolInterface ( > + SerialDevice->Handle, > + &gEfiDevicePathProtocolGuid, > + SerialDevice->DevicePath, > + SerialDevice->DevicePath > + ); > + } > + > + gBS->RestoreTPL (Tpl); > + > + return Status; > +} > + > +/** > + Set Control Bits. > + > + @param This Pointer to EFI_SERIAL_IO_PROTOCOL > + @param Control Control bits that can be settable > + > + @retval EFI_SUCCESS New Control bits were set successfully > + @retval EFI_UNSUPPORTED The Control bits wanted to set are not supported > + > +**/ > +EFI_STATUS > +EFIAPI > +SerialSetControl ( > + IN EFI_SERIAL_IO_PROTOCOL *This, > + IN UINT32 Control > + ) > +{ > + SERIAL_DEV *SerialDevice; > + SERIAL_PORT_MCR Mcr; > + EFI_TPL Tpl; > + UART_FLOW_CONTROL_DEVICE_PATH *FlowControl; > + EFI_STATUS Status; > + > + // > + // The control bits that can be set are : > + // EFI_SERIAL_DATA_TERMINAL_READY: 0x0001 // WO > + // EFI_SERIAL_REQUEST_TO_SEND: 0x0002 // WO > + // EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE: 0x1000 // RW > + // EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE: 0x2000 // RW > + // EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE: 0x4000 // RW > + // > + SerialDevice = SERIAL_DEV_FROM_THIS (This); > + > + // > + // first determine the parameter is invalid > + // > + if ((Control & (~(EFI_SERIAL_REQUEST_TO_SEND | > EFI_SERIAL_DATA_TERMINAL_READY | > + EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE | > EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE | > + EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE))) != 0) { > + return EFI_UNSUPPORTED; > + } > + > + Tpl = gBS->RaiseTPL (TPL_NOTIFY); > + > + Mcr.Data = READ_MCR (SerialDevice); > + Mcr.Bits.DtrC = 0; > + Mcr.Bits.Rts = 0; > + Mcr.Bits.Lme = 0; > + SerialDevice->SoftwareLoopbackEnable = FALSE; > + SerialDevice->HardwareFlowControl = FALSE; > + > + if ((Control & EFI_SERIAL_DATA_TERMINAL_READY) == > EFI_SERIAL_DATA_TERMINAL_READY) { > + Mcr.Bits.DtrC = 1; > + } > + > + if ((Control & EFI_SERIAL_REQUEST_TO_SEND) == EFI_SERIAL_REQUEST_TO_SEND) { > + Mcr.Bits.Rts = 1; > + } > + > + if ((Control & EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE) == > EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE) { > + Mcr.Bits.Lme = 1; > + } > + > + if ((Control & EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE) == > EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE) { > + SerialDevice->HardwareFlowControl = TRUE; > + } > + > + WRITE_MCR (SerialDevice, Mcr.Data); > + > + if ((Control & EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE) == > EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE) { > + SerialDevice->SoftwareLoopbackEnable = TRUE; > + } > + > + Status = EFI_SUCCESS; > + if (SerialDevice->Handle != NULL) { > + FlowControl = (UART_FLOW_CONTROL_DEVICE_PATH *) ( > + (UINTN) SerialDevice->DevicePath > + + GetDevicePathSize (SerialDevice->ParentDevicePath) > + - END_DEVICE_PATH_LENGTH > + + sizeof (UART_DEVICE_PATH) > + ); > + if (IsUartFlowControlDevicePathNode (FlowControl) && > + ((BOOLEAN) (ReadUnaligned32 (&FlowControl->FlowControlMap) == > UART_FLOW_CONTROL_HARDWARE) != SerialDevice- > >HardwareFlowControl)) { > + // > + // Flow Control setting is changed, need to reinstall device path > protocol > + // > + WriteUnaligned32 (&FlowControl->FlowControlMap, > SerialDevice->HardwareFlowControl ? UART_FLOW_CONTROL_HARDWARE : > 0); > + Status = gBS->ReinstallProtocolInterface ( > + SerialDevice->Handle, > + &gEfiDevicePathProtocolGuid, > + SerialDevice->DevicePath, > + SerialDevice->DevicePath > + ); > + } > + } > + > + gBS->RestoreTPL (Tpl); > + > + return Status; > +} > + > +/** > + Get ControlBits. > + > + @param This Pointer to EFI_SERIAL_IO_PROTOCOL > + @param Control Control signals of the serial device > + > + @retval EFI_SUCCESS Get Control signals successfully > + > +**/ > +EFI_STATUS > +EFIAPI > +SerialGetControl ( > + IN EFI_SERIAL_IO_PROTOCOL *This, > + OUT UINT32 *Control > + ) > +{ > + SERIAL_DEV *SerialDevice; > + SERIAL_PORT_MSR Msr; > + SERIAL_PORT_MCR Mcr; > + EFI_TPL Tpl; > + > + Tpl = gBS->RaiseTPL (TPL_NOTIFY); > + > + SerialDevice = SERIAL_DEV_FROM_THIS (This); > + > + *Control = 0; > + > + // > + // Read the Modem Status Register > + // > + Msr.Data = READ_MSR (SerialDevice); > + > + if (Msr.Bits.Cts == 1) { > + *Control |= EFI_SERIAL_CLEAR_TO_SEND; > + } > + > + if (Msr.Bits.Dsr == 1) { > + *Control |= EFI_SERIAL_DATA_SET_READY; > + } > + > + if (Msr.Bits.Ri == 1) { > + *Control |= EFI_SERIAL_RING_INDICATE; > + } > + > + if (Msr.Bits.Dcd == 1) { > + *Control |= EFI_SERIAL_CARRIER_DETECT; > + } > + // > + // Read the Modem Control Register > + // > + Mcr.Data = READ_MCR (SerialDevice); > + > + if (Mcr.Bits.DtrC == 1) { > + *Control |= EFI_SERIAL_DATA_TERMINAL_READY; > + } > + > + if (Mcr.Bits.Rts == 1) { > + *Control |= EFI_SERIAL_REQUEST_TO_SEND; > + } > + > + if (Mcr.Bits.Lme == 1) { > + *Control |= EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE; > + } > + > + if (SerialDevice->HardwareFlowControl) { > + *Control |= EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE; > + } > + // > + // Update FIFO status > + // > + SerialReceiveTransmit (SerialDevice); > + > + // > + // See if the Transmit FIFO is empty > + // > + if (SerialFifoEmpty (&SerialDevice->Transmit)) { > + *Control |= EFI_SERIAL_OUTPUT_BUFFER_EMPTY; > + } > + > + // > + // See if the Receive FIFO is empty. > + // > + if (SerialFifoEmpty (&SerialDevice->Receive)) { > + *Control |= EFI_SERIAL_INPUT_BUFFER_EMPTY; > + } > + > + if (SerialDevice->SoftwareLoopbackEnable) { > + *Control |= EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE; > + } > + > + gBS->RestoreTPL (Tpl); > + > + return EFI_SUCCESS; > +} > + > +/** > + Write the specified number of bytes to serial device. > + > + @param This Pointer to EFI_SERIAL_IO_PROTOCOL > + @param BufferSize On input the size of Buffer, on output the > amount of > + data actually written > + @param Buffer The buffer of data to write > + > + @retval EFI_SUCCESS The data were written successfully > + @retval EFI_DEVICE_ERROR The device reported an error > + @retval EFI_TIMEOUT The write operation was stopped due to timeout > + > +**/ > +EFI_STATUS > +EFIAPI > +SerialWrite ( > + IN EFI_SERIAL_IO_PROTOCOL *This, > + IN OUT UINTN *BufferSize, > + IN VOID *Buffer > + ) > +{ > + SERIAL_DEV *SerialDevice; > + UINT8 *CharBuffer; > + UINT32 Index; > + UINTN Elapsed; > + UINTN ActualWrite; > + EFI_TPL Tpl; > + UINTN Timeout; > + UINTN BitsPerCharacter; > + > + SerialDevice = SERIAL_DEV_FROM_THIS (This); > + Elapsed = 0; > + ActualWrite = 0; > + > + if (*BufferSize == 0) { > + return EFI_SUCCESS; > + } > + > + if (Buffer == NULL) { > + REPORT_STATUS_CODE_WITH_DEVICE_PATH ( > + EFI_ERROR_CODE, > + EFI_P_EC_OUTPUT_ERROR | EFI_PERIPHERAL_SERIAL_PORT, > + SerialDevice->DevicePath > + ); > + > + return EFI_DEVICE_ERROR; > + } > + > + Tpl = gBS->RaiseTPL (TPL_NOTIFY); > + > + CharBuffer = (UINT8 *) Buffer; > + > + // > + // Compute the number of bits in a single character. This is a start bit, > + // followed by the number of data bits, followed by the number of stop > bits. > + // The number of stop bits is specified by an enumeration that includes > + // support for 1.5 stop bits. Treat 1.5 stop bits as 2 stop bits. > + // > + BitsPerCharacter = > + 1 + > + This->Mode->DataBits + > + ((This->Mode->StopBits == TwoStopBits) ? 2 : This->Mode->StopBits); > + > + // > + // Compute the timeout in microseconds to wait for a single byte to be > + // transmitted. The Mode structure contans a Timeout field that is the > + // maximum time to transmit or receive a character. However, many UARTs > + // have a FIFO for transmits, so the time required to add one new character > + // to the transmit FIFO may be the time required to flush a full FIFO. If > + // the Timeout in the Mode structure is smaller than the time required to > + // flush a full FIFO at the current baud rate, then use a timeout value > that > + // is required to flush a full transmit FIFO. > + // > + Timeout = MAX ( > + This->Mode->Timeout, > + (UINTN)DivU64x64Remainder ( > + BitsPerCharacter * (SerialDevice->TransmitFifoDepth + 1) * > 1000000, > + This->Mode->BaudRate, > + NULL > + ) > + ); > + > + for (Index = 0; Index < *BufferSize; Index++) { > + SerialFifoAdd (&SerialDevice->Transmit, CharBuffer[Index]); > + > + while (SerialReceiveTransmit (SerialDevice) != EFI_SUCCESS || > !SerialFifoEmpty (&SerialDevice->Transmit)) { > + // > + // Unsuccessful write so check if timeout has expired, if not, > + // stall for a bit, increment time elapsed, and try again > + // > + if (Elapsed >= Timeout) { > + *BufferSize = ActualWrite; > + gBS->RestoreTPL (Tpl); > + return EFI_TIMEOUT; > + } > + > + gBS->Stall (TIMEOUT_STALL_INTERVAL); > + > + Elapsed += TIMEOUT_STALL_INTERVAL; > + } > + > + ActualWrite++; > + // > + // Successful write so reset timeout > + // > + Elapsed = 0; > + } > + > + gBS->RestoreTPL (Tpl); > + > + return EFI_SUCCESS; > +} > + > +/** > + Read the specified number of bytes from serial device. > + > + @param This Pointer to EFI_SERIAL_IO_PROTOCOL > + @param BufferSize On input the size of Buffer, on output the > amount of > + data returned in buffer > + @param Buffer The buffer to return the data into > + > + @retval EFI_SUCCESS The data were read successfully > + @retval EFI_DEVICE_ERROR The device reported an error > + @retval EFI_TIMEOUT The read operation was stopped due to timeout > + > +**/ > +EFI_STATUS > +EFIAPI > +SerialRead ( > + IN EFI_SERIAL_IO_PROTOCOL *This, > + IN OUT UINTN *BufferSize, > + OUT VOID *Buffer > + ) > +{ > + SERIAL_DEV *SerialDevice; > + UINT32 Index; > + UINT8 *CharBuffer; > + UINTN Elapsed; > + EFI_STATUS Status; > + EFI_TPL Tpl; > + > + SerialDevice = SERIAL_DEV_FROM_THIS (This); > + Elapsed = 0; > + > + if (*BufferSize == 0) { > + return EFI_SUCCESS; > + } > + > + if (Buffer == NULL) { > + return EFI_DEVICE_ERROR; > + } > + > + Tpl = gBS->RaiseTPL (TPL_NOTIFY); > + > + Status = SerialReceiveTransmit (SerialDevice); > + > + if (EFI_ERROR (Status)) { > + *BufferSize = 0; > + > + REPORT_STATUS_CODE_WITH_DEVICE_PATH ( > + EFI_ERROR_CODE, > + EFI_P_EC_INPUT_ERROR | EFI_PERIPHERAL_SERIAL_PORT, > + SerialDevice->DevicePath > + ); > + > + gBS->RestoreTPL (Tpl); > + > + return EFI_DEVICE_ERROR; > + } > + > + CharBuffer = (UINT8 *) Buffer; > + for (Index = 0; Index < *BufferSize; Index++) { > + while (SerialFifoRemove (&SerialDevice->Receive, &(CharBuffer[Index])) > != EFI_SUCCESS) { > + // > + // Unsuccessful read so check if timeout has expired, if not, > + // stall for a bit, increment time elapsed, and try again > + // Need this time out to get conspliter to work. > + // > + if (Elapsed >= This->Mode->Timeout) { > + *BufferSize = Index; > + gBS->RestoreTPL (Tpl); > + return EFI_TIMEOUT; > + } > + > + gBS->Stall (TIMEOUT_STALL_INTERVAL); > + Elapsed += TIMEOUT_STALL_INTERVAL; > + > + Status = SerialReceiveTransmit (SerialDevice); > + if (Status == EFI_DEVICE_ERROR) { > + *BufferSize = Index; > + gBS->RestoreTPL (Tpl); > + return EFI_DEVICE_ERROR; > + } > + } > + // > + // Successful read so reset timeout > + // > + Elapsed = 0; > + } > + > + SerialReceiveTransmit (SerialDevice); > + > + gBS->RestoreTPL (Tpl); > + > + return EFI_SUCCESS; > +} > + > +/** > + Use scratchpad register to test if this serial port is present. > + > + @param SerialDevice Pointer to serial device structure > + > + @return if this serial port is present > +**/ > +BOOLEAN > +SerialPresent ( > + IN SERIAL_DEV *SerialDevice > + ) > + > +{ > + UINT8 Temp; > + BOOLEAN Status; > + > + Status = TRUE; > + > + // > + // Save SCR reg > + // > + Temp = READ_SCR (SerialDevice); > + WRITE_SCR (SerialDevice, 0xAA); > + > + if (READ_SCR (SerialDevice) != 0xAA) { > + Status = FALSE; > + } > + > + WRITE_SCR (SerialDevice, 0x55); > + > + if (READ_SCR (SerialDevice) != 0x55) { > + Status = FALSE; > + } > + // > + // Restore SCR > + // > + WRITE_SCR (SerialDevice, Temp); > + return Status; > +} > + > +/** > + Read serial port. > + > + @param SerialDev Pointer to serial device > + @param Offset Offset in register group > + > + @return Data read from serial port > + > +**/ > +UINT8 > +SerialReadRegister ( > + IN SERIAL_DEV *SerialDev, > + IN UINT32 Offset > + ) > +{ > + UINT8 Data; > + EFI_STATUS Status; > + > + if (SerialDev->PciDeviceInfo == NULL) { > + return IoRead8 ((UINTN) SerialDev->BaseAddress + Offset * > SerialDev->RegisterStride); > + } else { > + if (SerialDev->MmioAccess) { > + Status = SerialDev->PciDeviceInfo->PciIo->Mem.Read > (SerialDev->PciDeviceInfo->PciIo, EfiPciIoWidthUint8, > EFI_PCI_IO_PASS_THROUGH_BAR, > + > SerialDev->BaseAddress + Offset * SerialDev->RegisterStride, 1, &Data); > + } else { > + Status = SerialDev->PciDeviceInfo->PciIo->Io.Read > (SerialDev->PciDeviceInfo->PciIo, EfiPciIoWidthUint8, > EFI_PCI_IO_PASS_THROUGH_BAR, > + > SerialDev->BaseAddress + Offset * SerialDev->RegisterStride, 1, &Data); > + } > + ASSERT_EFI_ERROR (Status); > + return Data; > + } > +} > + > +/** > + Write serial port. > + > + @param SerialDev Pointer to serial device > + @param Offset Offset in register group > + @param Data data which is to be written to some serial port > register > +**/ > +VOID > +SerialWriteRegister ( > + IN SERIAL_DEV *SerialDev, > + IN UINT32 Offset, > + IN UINT8 Data > + ) > +{ > + EFI_STATUS Status; > + > + if (SerialDev->PciDeviceInfo == NULL) { > + IoWrite8 ((UINTN) SerialDev->BaseAddress + Offset * > SerialDev->RegisterStride, Data); > + } else { > + if (SerialDev->MmioAccess) { > + Status = SerialDev->PciDeviceInfo->PciIo->Mem.Write > (SerialDev->PciDeviceInfo->PciIo, EfiPciIoWidthUint8, > EFI_PCI_IO_PASS_THROUGH_BAR, > + > SerialDev->BaseAddress + Offset * SerialDev->RegisterStride, 1, &Data); > + } else { > + Status = SerialDev->PciDeviceInfo->PciIo->Io.Write > (SerialDev->PciDeviceInfo->PciIo, EfiPciIoWidthUint8, > EFI_PCI_IO_PASS_THROUGH_BAR, > + > SerialDev->BaseAddress + Offset * SerialDev->RegisterStride, 1, &Data); > + } > + ASSERT_EFI_ERROR (Status); > + } > +} > + > diff --git a/MdeModulePkg/MdeModulePkg.dec b/MdeModulePkg/MdeModulePkg.dec > index 270277e..5ec37c5 100644 > --- a/MdeModulePkg/MdeModulePkg.dec > +++ b/MdeModulePkg/MdeModulePkg.dec > @@ -686,6 +686,12 @@ > # @Prompt Enable S3 performance data support. > > gEfiMdeModulePkgTokenSpaceGuid.PcdFirmwarePerformanceDataTableS3Support|TRUE|BOOLEAN|0x00010064 > > + ## Indicates if Serial device uses half hand shake.<BR><BR> > + # TRUE - Serial device uses half hand shake.<BR> > + # FALSE - Serial device doesn't use half hand shake.<BR> > + # @Prompt Enable Serial device Half Hand Shake > + > gEfiMdeModulePkgTokenSpaceGuid.PcdSerialUseHalfHandshake|FALSE|BOOLEAN|0x00010073 > + > [PcdsFeatureFlag.IA32, PcdsFeatureFlag.X64] > ## Indicates if DxeIpl should switch to long mode to enter DXE phase. > # It is assumed that 64-bit DxeCore is built in firmware if it is true; > otherwise 32-bit DxeCore > @@ -971,6 +977,38 @@ > # @Prompt Pci Serial Device Info > > gEfiMdeModulePkgTokenSpaceGuid.PcdSerialPciDeviceInfo|{0xFF}|VOID*|0x00010067 > > + ## PCI Serial Parameters. It is an array of VendorID, DeviceID, ClockRate, > Offset, > + # BarIndex, RegisterStride, ReceiveFifoDepth, TransmitFifoDepth > information that > + # describes the parameters of special PCI serial devices. > + # Each array entry is 24-byte in length. The array is terminated > + # by an array entry with a PCI Vendor ID of 0xFFFF. If a platform only > contains a > + # standard 16550 PCI serial device whose class code is 7/0/2, the value > is 0xFFFF. > + # The C style structure is defined as below: > + # typedef struct { > + # UINT16 VendorId; ///< Vendor ID to match the PCI device. > The value 0xFFFF terminates the list of entries. > + # UINT16 DeviceId; ///< Device ID to match the PCI device > + # UINT32 ClockRate; ///< UART clock rate. Set to 0 for > default clock rate of 1843200 Hz > + # UINT64 Offset; ///< The byte offset into to the BAR > + # UINT8 BarIndex; ///< Which BAR to get the UART base address > + # UINT8 RegisterStride; ///< UART register stride in bytes. Set > to 0 for default register stride of 1 byte. > + # UINT16 ReceiveFifoDepth; ///< UART receive FIFO depth in bytes. Set > to 0 for a default FIFO depth of 16 bytes. > + # UINT16 TransmitFifoDepth; ///< UART transmit FIFO depth in bytes. > Set to 0 for a default FIFO depth of 16 bytes. > + # UINT8 Reserved[2]; > + # } PCI_SERIAL_PARAMETER; > + # It contains zero or more instances of the above structure. > + # For example, if a PCI device contains two UARTs, PcdPciSerialParameters > needs > + # to contain two instances of the above structure, with the VendorId and > DeviceId > + # equals to the Device ID and Vendor ID of the device; If the PCI device > uses the > + # first two BARs to support two UARTs, BarIndex of first instance equals > to 0 and > + # BarIndex of second one equals to 1; If the PCI device uses the first > BAR to > + # support both UARTs, BarIndex of both instance equals to 0, Offset of > first > + # instance equals to 0 and Offset of second one equals to a value bigger > than or > + # equal to 8. > + # For certain UART whose register needs to be accessed in DWORD aligned > address, > + # RegisterStride equals to 4. > + # @Prompt Pci Serial Parameters > + gEfiMdeModulePkgTokenSpaceGuid.PcdPciSerialParameters|{0xFF, > 0xFF}|VOID*|0x00010071 > + > ## Serial Port Extended Transmit FIFO Size. The default is 64 bytes. > # @Prompt Serial Port Extended Transmit FIFO Size in Bytes > > gEfiMdeModulePkgTokenSpaceGuid.PcdSerialExtendedTxFifoSize|64|UINT32|0x00010068 > diff --git a/MdeModulePkg/MdeModulePkg.dsc b/MdeModulePkg/MdeModulePkg.dsc > index 06e1093..b31c02e 100644 > --- a/MdeModulePkg/MdeModulePkg.dsc > +++ b/MdeModulePkg/MdeModulePkg.dsc > @@ -208,6 +208,7 @@ > MdeModulePkg/Application/HelloWorld/HelloWorld.inf > MdeModulePkg/Application/MemoryProfileInfo/MemoryProfileInfo.inf > > + MdeModulePkg/Bus/Pci/PciSioSerialDxe/PciSioSerialDxe.inf > MdeModulePkg/Bus/Pci/PciBusDxe/PciBusDxe.inf > > MdeModulePkg/Bus/Pci/IncompatiblePciDeviceSupportDxe/IncompatiblePciDeviceSupportDxe.inf > MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpressDxe.inf > -- > 1.9.5.msysgit.1 _______________________________________________ edk2-devel mailing list [email protected] https://lists.01.org/mailman/listinfo/edk2-devel

