# SerialIo

## Function Table

| Address | Name | Description |
|---------|------|-------------|
|  | **SerialIoDriverBindingSupported** |  |
|  | **SerialIoDriverBindingStart** |  |
|  | **SerialIoDriverBindingStop** |  |
|  | **SerialIoComponentNameGetDriverName** |  |
|  | **SerialIoComponentNameGetControllerName** |  |
|  | **SerialIoReset** |  |
|  | **SerialIoSetAttributes** |  |
|  | **SerialIoSetControlBits** |  |
|  | **SerialIoGetControlBits** |  |
|  | **SerialIoWrite** |  |
|  | **SerialIoRead** |  |
|  | **UartReadRegister** |  |
|  | **UartWriteRegister** |  |
|  | **UartSetFifoMode** |  |
|  | **SerialIoCreateDevicePathNode** |  |
|  | **SerialIoTransmitReadyTimer** |  |
|  | **SerialIoDetectUart** |  |
|  | **SerialIoDetectUartEnhanced** |  |
|  | **SerialIoDriverEntryPoint** |  |
|  | **HobGetAcpiDevicePathEnd** |  |
| COM | **port name strings (off_3560 at 0x3560)** |  |
| GLOBAL_REMOVE_IF_UNREFERENCED | **const CHAR16 *mComPortNames[10] = {** |  |
| Baud | **rate table (dword_35D0 at 0x35D0)** |  |
| Supported | **rates in ascending order, used to clamp requested baud rates** |  |
| to | **the nearest valid value.** |  |
| GLOBAL_REMOVE_IF_UNREFERENCED | **const UINT32 mBaudRateTable[19] = {** |  |
| PCI | **UART Device Table (at 0x3AC8)** |  |
| Terminated | **by DeviceId = 0xFFFF.** |  |
| The | **SerialIoDriverBindingStart code iterates this table to match PCI UART** |  |
| Data | **at 0x3AC8: first entry = {0xFFFF, 0x00FF, ...} (table may be empty/terminator)** |  |
| Default | **serial attributes for initial Setup** |  |
| xmmword_35B0 | **at 0x35B0 = 0x0000130E03** |  |
| Hardware | **magic constant:** |  |
| Max | **consecutive write timeouts before blocking** |  |
| Software | **flow control timeout (in 100ns units, 10 seconds)** |  |
| Transmit | **timeout loop limit** |  |
| EFI_GUID | **gEfiSerialIoProtocolGuid     = EFI_SERIAL_IO_PROTOCOL_GUID;** |  |
| Device | **path GUID for UART serial device node** |  |
| EFI_GUID | **gEfiSerialIoDevicePathGuid   = EFI_SERIAL_IO_DEVICE_PATH_GUID;** |  |
| EFI_STATUS | **EFIAPI** |  |
| Component | **Name 2 Protocol** |  |
| Serial | **I/O Protocol Functions** |  |
| UART | **Hardware Access** |  |
| UINT8 | **UartReadRegister (** |  |
| Backend | **functions (not protocol interface, internal)** |  |
| EFI_STATUS | **SerialIoCreateDevicePathNode (** |  |
| caller | **frees** |  |
| if | **(Private->AccessMethod) {** |  |
| MMIO | **access (direct memory read of register)** |  |
| switch | **(Private->RegisterWidth) {** |  |
| Legacy | **I/O port access** |  |
| return | **__inbyte(Offset + (UINT16)Private->BaseAddress);** |  |
| PCI | **I/O protocol backed access** |  |
| EFI_PCI_IO_PROTOCOL | ***PciIo;** |  |
| Use | **PCI MMIO read via PCI I/O protocol** |  |
| Use | **PCI I/O port read** |  |
| MMIO | **access** |  |
| Only | **run detection for '$SIO' magic UARTs** |  |
| if | **(Private->Magic != SERIAL_IO_MAGIC) {** |  |
| Enable | **FIFO, clear RCVR/XMIT FIFOs** |  |
| UartWriteRegister | **(Private, R_UART_FCR, FCR_FIFO_ENABLE |** |  |
| Read | **IIR to check FIFO enable status** |  |
| if | **(UartReadRegister (Private, R_UART_IIR) == 0xFF) {** |  |
| No | **UART at this address (bus pulls data high)** |  |
| UartWriteRegister | **(Private, R_UART_FCR, SavedFcr);** |  |
| Flush | **any pending data** |  |
| Perform | **8250/16550 detection by writing 0x80 then checking loopback** |  |
| UartWriteRegister | **(Private, R_UART_THR, 0x80);** |  |
| Check | **if 0x80 can be read back correctly** |  |
| if | **((UartReadRegister (Private, R_UART_LSR) & LSR_DR) != 0 &&** |  |
| No | **FIFO: standard 8250/16450** |  |
| Restore | **FCR to enabled+cleared state for further probing** |  |
| This | **is controlled by byte_3FA1 (a global flag, possibly setup-dependent)** |  |
| if | **(mSomeLoopbackEnableFlag) {** |  |
| Flush | **remaining data** |  |
| while | **((UartReadRegister (Private, R_UART_LSR) & LSR_DR) != 0) {** |  |
| Perform | **DTR/RTS loopback test:** |  |
| Toggle | **DTR bit** |  |
| if | **((NextMcr & MCR_DTR) != 0) {** |  |
| Restore | **MCR** |  |
| return | **UartWriteRegister (Private, R_UART_FCR, 0xFE);** |  |
| 16750 | **with 64-byte FIFO: enable FIFO with trigger level 14** |  |
| 16550A | **/ standard: 16-byte FIFO with trigger level 1** |  |
| Reset | **UART: clear DLAB, disable break, set LCR to default** |  |
| Lcr | **= UartReadRegister (Private, R_UART_LCR);** |  |
| Reset | **FIFOs** |  |
| Reconfigure | **FIFO with default depth (64 if 16750, else 16)** |  |
| UartSetFifoMode | **(Private, 0x40, 0);** |  |
| Clear | **MCR loopback bits** |  |
| Mcr | **= UartReadRegister (Private, R_UART_MCR);** |  |
| Reset | **scratch register** |  |
| UartWriteRegister | **(Private, R_UART_SCR, 0);** |  |
| Restore | **serial attributes** |  |
| UartCfg | **= Private->UartConfig;** |  |
| Reset | **SW FIFO and state** |  |
| Flush | **RBR (read to clear)** |  |
| UartReadRegister | **(Private, R_UART_RBR);** |  |
| Apply | **defaults for zero-valued parameters** |  |
| if | **(BaudRate == 0) {** |  |
| DefaultNoParity | **}** |  |
| DefaultStopBits | **= 1** |  |
| if | **(Private->HardwareType == HW_TYPE_16750 && DataBits < 7) {** |  |
| Clamp | **baud rate to nearest valid table entry** |  |
| for | **(BaudIndex = 0; BaudIndex < 19 - 1; BaudIndex++) {** |  |
| Validate | **all parameters against range limits** |  |
| if | **(ReceiveFifoDepth - 1 > 63 ||** |  |
| Check | **if already configured at these settings** |  |
| if | **(Private->BaudRate         == BaudRate &&** |  |
| Update | **FIFO depth in hardware if changed** |  |
| if | **(Private->UartConfig->ReceiveFifoDepth != ReceiveFifoDepth) {** |  |
| Calculate | **baud rate divisor** |  |
| Divisor | **= Clock / (16 * BaudRate);** |  |
| Set | **DLAB (Divisor Latch Access Bit) and wait for THRE+TSRE** |  |
| Lcr | **= UartReadRegister (Private, R_UART_LCR) | LCR_DLAB;** |  |
| Write | **divisor** |  |
| UartWriteRegister | **(Private, R_UART_LCR, Lcr);** |  |
| Set | **line control (parity, stop bits, data bits)** |  |
| switch | **(Parity) {** |  |
| NoParity | **NewLcr &= ~(LCR_PEN | LCR_EPS | LCR_SP);** |  |
| EvenParity | **NewLcr = (NewLcr & ~(LCR_PEN | LCR_EPS | LCR_SP)) | (LCR_PEN | LCR_EPS);** |  |
| OddParity | **NewLcr = (NewLcr & ~(LCR_EPS | LCR_SP)) | LCR_PEN;** |  |
| MarkParity | **/ SpaceParity** |  |
| SpaceParity | **(Mark=4, Space=5 in EFI)** |  |
| Set | **word length (5, 6, 7, 8 -> 0, 1, 2, 3)** |  |
| NewLcr | **= (NewLcr & ~(LCR_WLS0 | LCR_WLS1)) | (DataBits - 5);** |  |
| Update | **stored configuration** |  |
| Notify | **parent via re-propagated device path if attributes changed** |  |
| if | **(Private->BaudRate   != BaudRate ||** |  |
| Duplicate | **device path with new attributes and re-install** |  |
| VOID | ***OldDevPath;** |  |
| Free | **old if present** |  |
| if | **(Private->ParentDevicePath != NULL) {** |  |
| if | **((Control & 0xFFFF8FFC) != 0) {** |  |
| Set | **DTR (MCR bit 0)** |  |
| Mcr | **= (Mcr & ~MCR_DTR) | ((Control & SERIAL_CTRL_DTR) ? MCR_DTR : 0);** |  |
| Set | **RTS (MCR bit 1)** |  |
| Mcr | **= (Mcr & ~MCR_RTS) | ((Control & SERIAL_CTRL_RTS) ? MCR_RTS : 0);** |  |
| Set | **Loopback (MCR bit 4) -> mapped to SERIAL_CTRL_REQUEST_TO_SEND bit 12 (0x1000)** |  |
| Mcr | **= (Mcr & ~MCR_LOOP) | ((Control & 0x1000) ? MCR_LOOP : 0);** |  |
| Update | **software control bits** |  |
| Read | **Modem Status Register** |  |
| Msr | **= UartReadRegister (Private, R_UART_MSR);** |  |
| Read | **Modem Control Register** |  |
| Add | **software-controlled hardware reset bit** |  |
| if | **((Private->ControlBits & SERIAL_CTRL_HARDWARE_RESET) != 0) {** |  |
| Read | **Line Status Register for error conditions** |  |
| Lsr | **= UartReadRegister (Private, R_UART_LSR);** |  |
| Not | **exactly - indicates TX in progress** |  |
| Too | **many retries or CTS lost** | arm timer and return error |
| When | **RTS/CTS is active, limit writes to 16 bytes per call** |  |
| No | **flow control: use SW FIFO or direct write** |  |
| if | **(*BufferSize > 0) {** |  |
| Fill | **SW FIFO if space available** |  |
| while | **(Private->FifoCount < *FifoDepth) {** |  |
| Hardware | **flow control: poll for CTS before sending** |  |
| do | **{** |  |
| XOFF | **character received** |  |
| Standard | **write (no flow control or RTS)** |  |
| if | **((Private->ControlBits & SERIAL_CTRL_HARDWARE_RESET) != 0 &&** |  |
| Assert | **RTS** |  |
| SoftwareLoop | **= TRUE;** |  |
| Wait | **for CTS (MSR bit 4)** |  |
| while | **((UartReadRegister (Private, R_UART_MSR) & MSR_CTS) == 0) {** |  |
| Write | **loop** |  |
| Wait | **for THR empty (LSR bit 5)** |  |
| Write | **byte** |  |
| UartWriteRegister | **(Private, R_UART_THR** |  |
| Update | **status from partial transfer** |  |
| if | **(AutoRts && Status == EFI_TIMEOUT) {** |  |
| preserve | **EFI_TIMEOUT but with data written** |  |
| SW | **FIFO mode: read from SW FIFO buffer** |  |
| Flush | **the FIFO after an overrun** |  |
| Direct | **read from UART: poll for data** |  |
| Drain | **FIFO on overrun** |  |
| for | **( ; Index < *BufferSize; Index++) {** |  |
| No | **more data available now** |  |
| Check | **for CTS recovery** |  |
| if | **((UartReadRegister (Private, R_UART_MSR) & MSR_CTS) != 0) {** |  |
| Check | **for THRE recovery** |  |
| if | **((UartReadRegister (Private, R_UART_LSR) & LSR_THRE) != 0) {** |  |
| Global | **flag controlling extended UART detection (at 0x3FA1)** |  |
| extern | **UINT8  mExtendedUartDetection;** |  |
| Perform | **UART presence and loopback detection.** |  |
| Returns | **TRUE if UART appears absent/removed, FALSE if it seems present.** |  |
| UINT8 | **SerialIoDetectUartEnhanced (** |  |
| Enable | **FIFOs, clear them** |  |
| No | **UART: return TRUE = removed** |  |
| Flush | **RBR** |  |
| 8250 | **detection: write 0x80, then 0x08, 0x20, 0x08** |  |
| 8250 | **without FIFO** |  |
| goto | **DeviceRemoved;** |  |
| Extended | **test: toggle DTR and check MSR CTS change** |  |
| if | **(mExtendedUartDetection) {** |  |
| Toggle | **DTR in MCR** |  |
| if | **((Msr2 & MCR_DTR) != 0) {** |  |
| Restore | **//** |  |
| EFI | **Driver Binding Protocol instance (installed on image handle)** |  |
| EFI_DRIVER_BINDING_PROTOCOL | **gSerialIoDriverBinding = {** |  |
| EFI | **Component Name 2 Protocol instance** |  |
| EFI_COMPONENT_NAME2_PROTOCOL | **gSerialIoComponentName2 = {** |  |
| Supported | **languages for component name** |  |
| GLOBAL_REMOVE_IF_UNREFERENCED | **CHAR8  *mSupportedLanguages[] = {** |  |
| Add | **more languages as needed** |  |
| Install | **Driver Binding Protocol and Component Name 2 Protocol** |  |
| Status | **= EfiLibInstallDriverBindingComponentName2 (** |  |
| Case | **1: Controller has ISA I/O protocol (legacy ISA/ACPI UART)** |  |
| Status | **= gBS->OpenProtocol (** |  |
| Check | **ACPI device path for UART** |  |
| Case | **2: UART IO protocol or ACPI device path** |  |
| if | **(HobGetAcpiDevicePathEnd (This, ControllerHandle, &AcpiEnd, 16) >= 0 &&** |  |
| ACPI | **device path end found: this is an ACPI UART** |  |
| Check | **that it has type=3, subtype=14 (Serial I/O device path)** |  |
| if | **(RemainingDevicePath != NULL &&** |  |
| Case | **3: PCI UART - check for PCI I/O protocol** |  |
| if | **(mSomeLoopbackEnableFlag == 1) {** |  |
| Close | **protocol since we only need it for Supported()** |  |
| Case | **4: UART IO protocol on child UART device** |  |
| Check | **for UART mode** |  |
| Probe | **for 512 or 256 byte FIFO via UART IO protocol** |  |
| This | **is used for MMIO UART controllers** |  |
| Found | **512-byte UART** |  |
| goto | **Found512;** |  |
| Walk | **device path looking for ACPI UART node** |  |
| ParentPath | **= DevicePath;** |  |
| not | **END** |  |
| ACPI | **device path: check HID/UID** |  |
| return | **EFI_SUCCESS;** |  |
| No | **supported controller found** |  |
| if | **(Status == EFI_ALREADY_STARTED) {** |  |
| GUID | **for serial I/O device path (0x00180A03-...)** |  |
| EFI_GUID | **SerialDevicePathGuid = EFI_SERIAL_IO_DEVICE_PATH_GUID;** |  |
| GUID | **for ACPI UART HID** |  |
| EFI_GUID | **AcpiUartHid = { 0x01031804, 0x9A9D, 0x3749** |  |
| Probe | **for ISA I/O protocol first (legacy COM ports)** |  |
| ISA | **UART: get resources (I/O base, IRQ)** |  |
| Probe | **for device path + ACPI table (legacy UART enumeration)** |  |
| Get | **the UART IO protocol** |  |
| Query | **UART capabilities** |  |
| MMIO | **UART with ISA I/O** |  |
| ACPI | **enumerated UART** |  |
| Enumerate | **PCI UARTs** |  |
| if | **(UartIo->GetChildHandle != NULL) {** |  |
| Channel | **found with FIFO type 0 (512 byte)** |  |
| MMIO | **Private->InsideIo  = FALSE;** |  |
| Open | **parent channel** |  |
| 256 | **or 512 byte FIFO** |  |
| Walk | **device path to compute device path for child** |  |
| Probe | **for ACPI device path (UART IO protocol from HOB)** |  |
| if | **(HobGetAcpiDevicePathEnd (** |  |
| This | **may be an ACPI enumerated UART** |  |
| Open | **protocols** |  |
| No | **UART IO mode: try PCI I/O protocol** |  |
| actually | **DeviceId high** |  |
| Look | **up clock frequency and register width in PCI UART table** |  |
| if | **(gPciUartTableStart != (UINT16)-1) {** |  |
| UART | **IO protocol available** |  |
| If | **no protocols found, fail** |  |
| if | **(Private->PciIo == NULL && Private->BaseAddress == 0) {** |  |
| Initialize | **UART hardware** |  |
| UartWriteRegister | **(Private, R_UART_SCR, 0xAA);** |  |
| UART | **not present or not responding** |  |
| goto | **CleanupAll;** |  |
| Probe | **for FIFO type** |  |
| 16750 | **(64-byte FIFO)** |  |
| 16550A | **(16-byte FIFO, rev A)** |  |
| 16550A | **(16-byte FIFO, rev B)** |  |
| Set | **defaults for clock and register width if not yet configured** |  |
| if | **(Private->ClockFrequency == 0) {** |  |
| Standard | **PC UART clock** |  |
| Initialize | **state** |  |
| Set | **up Serial I/O Protocol function table** |  |
| Actually | **points to self** |  |
| Initialize | **default serial attributes** |  |
| Set | **default attributes on hardware** |  |
| Status | **= Private->SetAttributes (Private, 0, 0, 0, 0, 0, 0);** |  |
| Copy | **device path attributes if present** |  |
| if | **(RemainingDevicePath != NULL) {** |  |
| Build | **device path for child** |  |
| ChildDevicePath | **= HobDuplicateDevicePath (** |  |
| Install | **Serial I/O Protocol on new child handle** |  |
| Status | **= gBS->InstallMultipleProtocolInterfaces (** |  |
| Open | **protocols (child handle)** |  |
| if | **(Private->IsaAccess) {** |  |
| Create | **timer for transmit ready monitoring** |  |
| Status | **= gBS->CreateEvent (** |  |
| Close | **protocols opened by Supported()** |  |
| Status | **= gBS->CloseProtocol (** |  |
| Stop | **the child: get private context from child handle** |  |
| Determine | **which protocol was opened on the controller** |  |
| Close | **the child protocol** |  |
| Uninstall | **protocols from child handle** |  |
| Free | **the private context** |  |
| Get | **the private context from the child handle** |  |
| Private | **= NULL;** |  |
| Walk | **to the end of the device path** |  |
| while | **(PathWalk->Type != 0x7F) {  // END** |  |
| Not | **an ACPI device path** |  |
| Status | **= EFI_UNSUPPORTED;** |  |

---
*Generated by HR650X BIOS Decompilation Project*